NewChangesBrowser.st
author tz
Tue, 15 Sep 1998 10:50:03 +0200
changeset 1887 332f146981fc
parent 1877 f0dbf0801e4d
child 1888 cc22faad669e
permissions -rw-r--r--
find last snapshot error fixed

ToolApplicationModel subclass:#NewChangesBrowser
	instanceVariableNames:'changes changeFileName skipSignal changeFileTimestamp
		autoUpdateBlock filterCompletionBlock editingClassSource modified'
	classVariableNames:'AutoUpdate CompressSnapshotInfo CategoryColumn DeltaInfoColumn
		TypeColumn TimeStampColumn PositionsColumn PrivateAsSeparate'
	poolDictionaries:''
	category:'Interface-Browsers'
!

Object subclass:#Change
	instanceVariableNames:'delta string type timeStamp category chunk lastPosition position
		className followUp'
	classVariableNames:''
	poolDictionaries:''
	privateIn:NewChangesBrowser
!

!NewChangesBrowser class methodsFor:'documentation'!

documentation
"
    The future Changes Browser.

    [start with:]
        NewChangesBrowser open
        NewChangesBrowser openOnFile:aFileName

    [author:]
        Thomas Zwick, eXept Software AG
"


! !

!NewChangesBrowser class methodsFor:'instance creation'!

openOnFile:aFileName
    "opens a Changes Browser with the changes of the aFileName"

    ^self new 
        changeFileName:aFileName;
        open

! !

!NewChangesBrowser class methodsFor:'accessing'!

autoSelectNext
    "returns true here, makes a Delete operation automatically
     select the next change"

    ^ true


!

label
    "returns my label"

    ^'Changes Browser'
! !

!NewChangesBrowser class methodsFor:'help specs'!

helpSpec
    "This resource specification was automatically generated
     by the UIHelpTool of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIHelpTool may not be able to read the specification."

    "
     UIHelpTool openOnClass:NewChangesBrowser    
    "

    <resource: #help>

    ^super helpSpec addPairsFrom:#(

#applyAll
'Apply all changes.'

#applyForClassToEnd
'Apply changes to the end which affect this class.'

#applyFromLastSnapshot
'Apply changes from the last snapshot to the end.'

#applyLine
'Apply the selected change.'

#applyToEnd
'Apply all changes from the selected one to the end.'

#deleteAll
'Deletes all changes.'

#deleteCompress
'Deletes all obsolete changes.'

#deleteCompressForClass
'Deletes obsolete changes for this class, leaving the last one.'

#deleteForClassToEnd
'Deletes changes for this class from the selection to the end.'

#deleteLine
'Deletes the selected change.'

#deleteToEnd
'Deletes changes from the selected one to the end.'

#fileLoad
'Opens a dialog for selecting and loading another changes file.'

#fileReload
'Reloads the changes file (undo your modifications).'

#fileSave
'Saves the list of changes into the current changes file.'

#filterField
'Matching patterns filtering the changes (separate patterns by blanks).'

#settingsAutoUpdate
'Toggle automatic update.'

#settingsColumns
'Configure which columns are shown in the list.'

#settingsColumnsCategory
'Toggle display of the changes category in the list.'

#settingsColumnsDeltaInfo
'Toggle display of the delta-info in the list.'

#settingsColumnsPosition
'Togle display of the changes file-position in the list.'

#settingsColumnsTimeStamp
'Toggle display of the changes time stamp in the list.'

#settingsColumnsType
'Toggle display of the change-type in the list.'

#settingsPrivateAsSeparate
'Toggle if changes for private private are included when applying, deleting, or compressing for a class.'

#testCompareWithCurrentVersion
'Opens a info dialog showing the difference between the changes code and the method current code.'

#testFindLastSnapshot
'Searches backward for the latest snapshot entry.'

#testFindNextSnapshot
'Searches forward for the next snapshot entry.'

)

    "Modified: / 19.5.1998 / 17:59:39 / cg"
! !

!NewChangesBrowser class methodsFor:'image specs'!

applyFromLastSnapshotIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     ImageEditor openOnClass:self andSelector:#applyFromLastSnapshotIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'NewChangesBrowser applyFromLastSnapshotIcon'
        ifAbsentPut:[(Depth4Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(4 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@QDQ<@@@@@@@@@@AH"H@@@@@@@@@@@D"H @@@@@@@@@@@RH"@@@@@@@@@@@AH"H@@@@@@@@@@@@@@@@@@@@@@@@@<@@@@@@@@@@@@@@@@@@@@@@@;.;.; @@@@@@@@C.;.;.@@@@@@@@@@@@@@8@@N@@@@C?????C @@@N@@@O????<@@@8@@@@@@@@@C0@@@@8@@O????<O@@C @@@@?????0@@@@C @@@@@@@O@@@N@@@@DQDQDP<@C @@@@@_??DQ@@@@@@@@@A????D@@@@@@@@@DQDQDP@@@@C @@@@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 255 255 255 0 0 0 255 0 0 0 255 0 255 255 255 255 0 255 0 255 127 0 0 0 127 0 0 0 127 0 127 127 127 127 0 127 0 127 127 127 127 170 170 170]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@C<@@C<@@C<@@C<@@C<@@A<@@D@@?<@@?<@@?<LC?<\C?<\C?<8O?08O?10O?10??C ??[@??_@?<^@?<_@?<_@') ; yourself); yourself]!

applyIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     ImageEditor openOnClass:self andSelector:#applyIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'NewChangesBrowser applyIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'UUUUUUUPUUUUUUUPUUUUUUU[UUUUUUUPP@@@@@@QQUUUUUTPQUUUUUTVQ**UUUTPQUUUUUTPQUUUUUTXQ***UUTPQ**UUUTPQ*****TPQ***%UTPQ****)TPQUUUUUTPQUUUUUTUP@@@@@@PUUUUUUUPUUUUUUUPUUUUUUUPUUUUUUUP') ; colorMapFromArray:#[0 0 0 255 255 255 170 170 170 255 0 0]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; yourself); yourself]!

applyToEndIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     ImageEditor openOnClass:self andSelector:#applyToEndIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'NewChangesBrowser applyToEndIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@B** H@@@B** H@@@@@@ @@@@**( @@@@**(@J@@@@@H@@@@O??H@@@@O??@@@@@@@C@H@@C??3@@ @C??0@ @@@@@0@B@@UUT0B@K@UUT@@H@@@@D@H@CEUUDB@@JG?U@@@@MG?=@@@@@EUU@@B@@@@@@@@@H') ; colorMapFromArray:#[0 0 0 255 255 255 127 127 127 170 170 170]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@C?0@C?0@C?0@O?0@O?0@O?0@??@@??@@??LC?<\C?<\C?<8O?08O?10O?10??C ??[@??_@?<^@?<_@?<_@') ; yourself); yourself]!

compressIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     ImageEditor openOnClass:self andSelector:#compressIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'NewChangesBrowser compressIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@????<@@@:***(@@@8@@@8@@@8@@@8@@@@@@@8@@@@@@@8A@@@@@@8@@:**0@8HC**+@@8@@@@@@@8H@@@@@@8@@@@@@@8@@@@@@@8@@@@@@@8@@C????8@@C****(@@@@@@@@H@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; colorMapFromArray:#[0 0 0 124 124 124 170 170 170 255 255 255]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@??0A??8A??8A??8A8A8G>A8@@A8G?98O?18_?!!8??A8@@A8G>A8@0A8C??8C??8C??8C??0@0@@D2@@G>@@D2@@') ; yourself); yourself]!

deleteIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     ImageEditor openOnClass:self andSelector:#deleteIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'NewChangesBrowser deleteIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@AUUUU@@OA??UU@@@AUUUU@@@AUUUU@B@A???U@H@A??5U@@@A???0@@@AUUUB@B@@@@@@@@@@@@@A@BK@@@@A_:@@@@@AO2G@@@@AL2@@@@@AL2C@@@@AL2@@@@@AL2@@@@@AL2H@@@@AL2@@@@@A\:@@@@@H_8 @@@@@@@H') ; colorMapFromArray:#[0 0 0 255 255 255 127 127 127 170 170 170]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'_?<@_?<@_?<P_?<P_?<X_?<X_?<H_? H_?O<_?XL@@_<@@_<@@_<@@_<@@_<@@_<@@_<@@_<@@_<@@_<@@_<@@G0') ; yourself); yourself]!

deleteToEndIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     ImageEditor openOnClass:self andSelector:#deleteToEndIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'NewChangesBrowser deleteToEndIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@B** @@O@B** @@@@@@@ @@@@??< @B@@??<@@H@@@@L@@@@EUUL@@@@G?U@B@B@G?=@@@@@EUU@A@BK@@@@A_:@@@@@AO2G@@@@AL2@@@@@AL2C@@@@AL2@@@@@AL2@@@@@AL2H@@@@AL2@@@@@A\:@@@@@H_8 @@@@@@@H') ; colorMapFromArray:#[0 0 0 255 255 255 127 127 127 170 170 170]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'C?0@C?0@C?0PO?0PO?0XO?0X??@H??@H??O<?<XL?<_<?<_<@@_<@@_<@@_<@@_<@@_<@@_<@@_<@@_<@@_<@@G0') ; yourself); yourself]!

findLastSnapshotIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     ImageEditor openOnClass:self andSelector:#findLastSnapshotIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'NewChangesBrowser findLastSnapshotIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@EUUUW@A@F***(@@@F***(@@@F***(@@@F***(@@@F***(@@@F***(@@@F***(@A@F***(@M@F***(@H@F***(@@@F***(@@@F***(@I@L@@@@@@@@@@@@@A@P@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; colorMapFromArray:#[0 0 0 255 255 255 255 0 0 170 170 170]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'C??@C??@C??@C??@C??@C??@C??@C??@C??@C??@C??@C??@C??@C??B@@@B@C@B@G B@O0@@_8@@G @@G @@G @') ; yourself); yourself]!

findNextSnapshotIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the ImageEditor may not be able to read the specification."

    "
     ImageEditor openOnClass:self andSelector:#findNextSnapshotIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'NewChangesBrowser findNextSnapshotIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@DA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@D@B@@@@@@@@@@@@@@@E@@@@@@@@@EUUUW@N@F***(@@@F***(@@@F***(@@@F***(@@@F***(@@@F***(@@@V***(@H@F***(@@@F***(@@@F***(@@@F***(@@@F***(@@@L@@@@@@') ; colorMapFromArray:#[0 0 0 255 255 255 255 0 0 170 170 170]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@G @@G @@G @@_8@@O0@@G @@C@@@@@@C??@C??@C??@C??@C??@C??BC??BC??BC??BC??@C??@C??@C??@C??@') ; yourself); yourself]! !

!NewChangesBrowser class methodsFor:'interface specs'!

windowSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

    "
     UIPainter new openOnClass:NewChangesBrowser andSelector:#windowSpec
     NewChangesBrowser new openInterface:#windowSpec
     NewChangesBrowser open
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #window: 
           #(#WindowSpec
              #name: 'Changes Browser'
              #layout: #(#LayoutFrame 53 0 92 0 687 0 583 0)
              #label: 'Changes Browser'
              #min: #(#Point 10 10)
              #max: #(#Point 1152 900)
              #bounds: #(#Rectangle 53 92 688 584)
              #menu: #menu
              #usePreferredExtent: false
          )
          #component: 
           #(#SpecCollection
              #collection: 
               #(
                 #(#MenuPanelSpec
                    #name: 'menuToolbarView'
                    #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
                    #menu: #menuToolbar
                    #style: #(#FontDescription #helvetica #medium #roman 10)
                    #showSeparatingLines: true
                )
                 #(#VariableVerticalPanelSpec
                    #name: 'variableVerticalPanel1'
                    #layout: #(#LayoutFrame 0 0.0 34 0 0 1.0 -26 1.0)
                    #component: 
                     #(#SpecCollection
                        #collection: 
                         #(
                           #(#ViewSpec
                              #name: 'Box1'
                              #component: 
                               #(#SpecCollection
                                  #collection: 
                                   #(
                                     #(#DataSetSpec
                                        #name: 'changesDataSetView'
                                        #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 -28 1.0)
                                        #model: #selectionOfChange
                                        #menu: #menuTable
                                        #hasHorizontalScrollBar: true
                                        #hasVerticalScrollBar: true
                                        #miniScrollerHorizontal: true
                                        #dataList: #listOfChanges
                                        #useIndex: false
                                        #has3Dsepartors: true
                                        #doubleClickSelector: #doBrowseClass
                                        #columnHolder: #listOfChangeColumns
                                        #valueChangeSelector: #changeSelected:
                                    )
                                     #(#ViewSpec
                                        #name: 'Box2'
                                        #layout: #(#LayoutFrame 0 0.0 -28 1 0 1.0 0 1.0)
                                        #component: 
                                         #(#SpecCollection
                                            #collection: 
                                             #(
                                               #(#LabelSpec
                                                  #name: 'filterLabel'
                                                  #layout: #(#AlignmentOrigin 37 0 13 0.0 1 0.5)
                                                  #label: 'Filter:'
                                                  #style: #(#FontDescription #helvetica #medium #roman 10)
                                                  #adjust: #left
                                              )
                                               #(#InputFieldSpec
                                                  #name: 'filterField'
                                                  #layout: #(#LayoutFrame 41 0.0 3 0 250 0 25 0)
                                                  #activeHelpKey: #filterField
                                                  #model: #valueOfFilter
                                                  #immediateAccept: false
                                              )
                                               #(#ProgressIndicatorSpec
                                                  #name: 'readProgressIndicator'
                                                  #layout: #(#LayoutFrame 41 0 3 0 250 0 25 0)
                                                  #model: #valueOfReadProgress
                                                  #foregroundColor: #(#Color 0.0 60.0 60.0)
                                              )
                                               #(#ActionButtonSpec
                                                  #name: 'allButton'
                                                  #layout: #(#LayoutFrame 258 0.0 2 0.0 268 0 13 0)
                                                  #label: ' '
                                                  #model: #doFilter:
                                                  #actionValue: ''
                                              )
                                               #(#LabelSpec
                                                  #name: 'allLabel'
                                                  #layout: #(#LayoutFrame 273 0 0 0.0 310 0 14 0)
                                                  #label: '= all'
                                                  #translateLabel: true
                                                  #style: #(#FontDescription #helvetica #medium #roman 10)
                                                  #adjust: #left
                                              )
                                               #(#ActionButtonSpec
                                                  #name: 'methodChangesButton'
                                                  #layout: #(#LayoutFrame 359 0.0 2 0.0 369 0 13 0)
                                                  #label: ' '
                                                  #backgroundColor: #(#Color 100.0 100.0 100.0)
                                                  #model: #doFilterType:
                                                  #actionValue: 'method'
                                              )
                                               #(#LabelSpec
                                                  #name: 'methodChangesLabel'
                                                  #layout: #(#LayoutFrame 373 0 0 0.0 458 0 14 0)
                                                  #label: '= method'
                                                  #translateLabel: true
                                                  #style: #(#FontDescription #helvetica #medium #roman 10)
                                                  #adjust: #left
                                              )
                                               #(#ActionButtonSpec
                                                  #name: 'classChangesButton'
                                                  #layout: #(#LayoutFrame 455 0.0 2 0.0 465 0 13 0)
                                                  #label: ' '
                                                  #backgroundColor: #(#Color 50.0008 50.0008 50.0008)
                                                  #model: #doFilterType:
                                                  #actionValue: 'class'
                                              )
                                               #(#LabelSpec
                                                  #name: 'classChangesLabel'
                                                  #layout: #(#LayoutFrame 470 0 0 0.0 580 0 14 0)
                                                  #label: '= class change'
                                                  #translateLabel: true
                                                  #style: #(#FontDescription #helvetica #medium #roman 10)
                                                  #adjust: #left
                                              )
                                               #(#ActionButtonSpec
                                                  #name: 'snapshotButton'
                                                  #layout: #(#LayoutFrame 258 0.0 16 0.0 268 0 27 0)
                                                  #label: ' '
                                                  #backgroundColor: #(#Color 100.0 0.0 0.0)
                                                  #model: #doFilterType:
                                                  #actionValue: 'image'
                                              )
                                               #(#LabelSpec
                                                  #name: 'snapshotLabel'
                                                  #layout: #(#LayoutFrame 273 0 14 0.0 355 0 28 0)
                                                  #label: '= snapshot'
                                                  #translateLabel: true
                                                  #style: #(#FontDescription #helvetica #medium #roman 10)
                                                  #adjust: #left
                                              )
                                               #(#ActionButtonSpec
                                                  #name: 'fileInButton'
                                                  #layout: #(#LayoutFrame 359 0.0 16 0.0 369 0 27 0)
                                                  #label: ' '
                                                  #backgroundColor: #(#Color 0.0 80.0 80.0)
                                                  #model: #doFilterSourceType:
                                                  #actionValue: '* file*'
                                              )
                                               #(#LabelSpec
                                                  #name: 'fileInLabel'
                                                  #layout: #(#LayoutFrame 374 0 14 0.0 440 0 28 0)
                                                  #label: '= fileIn'
                                                  #translateLabel: true
                                                  #style: #(#FontDescription #helvetica #medium #roman 10)
                                                  #adjust: #left
                                              )
                                               #(#ActionButtonSpec
                                                  #name: 'checkInButton'
                                                  #layout: #(#LayoutFrame 455 0.0 16 0.0 465 0 27 0)
                                                  #label: ' '
                                                  #backgroundColor: #(#Color 0.0 0.0 100.0)
                                                  #model: #doFilterSourceType:
                                                  #actionValue: '* checkin*'
                                              )
                                               #(#LabelSpec
                                                  #name: 'checkInLabel'
                                                  #layout: #(#LayoutFrame 470 0 14 0.0 550 0 28 0)
                                                  #label: '= checkIn'
                                                  #translateLabel: true
                                                  #style: #(#FontDescription #helvetica #medium #roman 10)
                                                  #adjust: #left
                                              )
                                            )
                                        )
                                    )
                                  )
                              )
                          )
                           #(#WorkspaceSpec
                              #name: 'changeTextEditor'
                              #model: #valueOfChangeText
                              #hasHorizontalScrollBar: true
                              #hasVerticalScrollBar: true
                              #miniScrollerHorizontal: true
                              #isReadOnly: true
                          )
                        )
                    )
                    #handles: #(#Any 0.5 1.0)
                )
                 #(#UISubSpecification
                    #name: 'windowSpecForInfoBar'
                    #layout: #(#LayoutFrame 0 0.0 -24 1 0 1.0 0 1.0)
                    #majorKey: #ToolApplicationModel
                    #minorKey: #windowSpecForInfoBar
                )
              )
          )
      )

    "Modified: / 19.5.1998 / 18:58:47 / cg"
! !

!NewChangesBrowser class methodsFor:'list specs'!

tableColumnsForChangeAttributes
    "This resource specification was automatically generated
     by the DataSetBuilder of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the DataSetBuilder may not be able to read the specification."

    "
     DataSetBuilder new openOnClass:NewChangesBrowser andSelector:#tableColumnsForChangeAttributes
    "

    <resource: #tableColumns>


    ^ #(
        #(#DataSetColumnSpec
           #rendererType: #rowSelector
           #backgroundSelector: #listColor
       )
        #(#DataSetColumnSpec
           #id: #change
           #label: 'Change'
           #translateLabel: true
           #labelAlignment: #left
           #model: #string
           #canSelect: false
       )
        #(#DataSetColumnSpec
           #id: #category
           #label: 'Category'
           #translateLabel: true
           #labelAlignment: #left
           #model: #category
           #canSelect: false
       )
        #(#DataSetColumnSpec
           #id: #deltaInfo
           #label: 'Delta Info'
           #translateLabel: true
           #labelAlignment: #left
           #model: #delta
           #canSelect: false
       )
        #(#DataSetColumnSpec
           #id: #timeStamp
           #label: 'Time Stamp'
           #translateLabel: true
           #labelAlignment: #left
           #model: #timeStamp
           #canSelect: false
       )
        #(#DataSetColumnSpec
           #id: #type
           #label: 'Type'
           #translateLabel: true
           #labelAlignment: #left
           #model: #type
           #canSelect: false
       )
        #(#DataSetColumnSpec
           #id: #position
           #label: 'Position'
           #translateLabel: true
           #labelAlignment: #left
           #model: #positions
           #canSelect: false
       )
     )

    "Modified: / 19.5.1998 / 20:34:14 / cg"
! !

!NewChangesBrowser class methodsFor:'menu specs'!

menu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

    "
     MenuEditor new openOnClass:NewChangesBrowser andSelector:#menu
     (Menu new fromLiteralArrayEncoding:(NewChangesBrowser menu)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #label: 'About'
                #translateLabel: true
                #activeHelpKey: #about
                #labelImage: #(#ResourceRetriever nil #menuIcon)
                #submenuChannel: #menuAbout
            )
             #(#MenuItem
                #label: 'File'
                #translateLabel: true
                #activeHelpKey: #file
                #submenu: 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #label: 'Reload'
                          #translateLabel: true
                          #value: #doReload
                          #activeHelpKey: #fileReload
                          #enabled: #valueOfNotReading
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'Load...'
                          #translateLabel: true
                          #value: #doLoad
                          #activeHelpKey: #fileLoad
                          #enabled: #valueOfNotSaving
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'Save'
                          #translateLabel: true
                          #value: #doSave
                          #activeHelpKey: #fileSave
                          #enabled: #valueOfNotReading
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'Browse Class'
                          #translateLabel: true
                          #value: #doBrowseClass
                          #activeHelpKey: #fileBrowseClass
                          #enabled: #valueOfHavingChangeSelection
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'Exit'
                          #translateLabel: true
                          #value: #closeRequest
                          #activeHelpKey: #fileExit
                          #enabled: #valueOfNotSaving
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #label: 'Apply'
                #translateLabel: true
                #submenu: 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #label: 'Change'
                          #translateLabel: true
                          #value: #doApply
                          #activeHelpKey: #applyLine
                          #enabled: #valueOfHavingChangeSelection
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'All'
                          #translateLabel: true
                          #value: #doApplyAll
                          #activeHelpKey: #applyAll
                          #enabled: #valueOfNotReading
                      )
                       #(#MenuItem
                          #label: 'To End'
                          #translateLabel: true
                          #value: #doApplyToEnd
                          #activeHelpKey: #applyToEnd
                          #enabled: #valueOfHavingSelection
                      )
                       #(#MenuItem
                          #label: 'All for Class'
                          #translateLabel: true
                          #value: #doApplyAllForClass
                          #activeHelpKey: #applyForClassToEnd
                          #enabled: #valueOfHavingChangeSelection
                      )
                       #(#MenuItem
                          #label: 'For Class to End'
                          #translateLabel: true
                          #value: #doApplyForClassToEnd
                          #activeHelpKey: #applyForClassToEnd
                          #enabled: #valueOfHavingChangeSelection
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'From last Snapshot'
                          #translateLabel: true
                          #value: #doApplyFromLastSnapshot
                          #activeHelpKey: #applyFromLastSnapshot
                          #enabled: #valueOfNotReading
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #label: 'Delete'
                #translateLabel: true
                #activeHelpKey: #edit
                #submenu: 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #label: 'Change'
                          #translateLabel: true
                          #value: #doDelete
                          #activeHelpKey: #deleteLine
                          #enabled: #valueOfHavingSelection
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'All'
                          #translateLabel: true
                          #value: #doDeleteAll
                          #activeHelpKey: #deleteAll
                          #enabled: #valueOfNotReading
                      )
                       #(#MenuItem
                          #label: 'To End'
                          #translateLabel: true
                          #value: #doDeleteToEnd
                          #activeHelpKey: #deleteToEnd
                          #enabled: #valueOfHavingSelection
                      )
                       #(#MenuItem
                          #label: 'All for Class'
                          #translateLabel: true
                          #value: #doDeleteAllForClass
                          #activeHelpKey: #applyForClassToEnd
                          #enabled: #valueOfHavingChangeSelection
                      )
                       #(#MenuItem
                          #label: 'For Class to End'
                          #translateLabel: true
                          #value: #doDeleteForClassToEnd
                          #activeHelpKey: #deleteForClassToEnd
                          #enabled: #valueOfHavingChangeSelection
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'Compress'
                          #translateLabel: true
                          #value: #doCompress
                          #activeHelpKey: #deleteCompress
                          #enabled: #valueOfNotReading
                      )
                       #(#MenuItem
                          #label: 'Compress for Class'
                          #translateLabel: true
                          #value: #doCompressForClass
                          #activeHelpKey: #deleteCompressForClass
                          #enabled: #valueOfHavingChangeSelection
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #label: 'Test'
                #translateLabel: true
                #activeHelpKey: #test
                #submenu: 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #label: 'Find last Snapshot'
                          #translateLabel: true
                          #value: #doFindSnapshot:
                          #activeHelpKey: #testFindLastSnapshot
                          #enabled: #valueOfHavingSelection
                          #argument: 'last'
                      )
                       #(#MenuItem
                          #label: 'Find next Snapshot'
                          #translateLabel: true
                          #value: #doFindSnapshot:
                          #activeHelpKey: #testFindNextSnapshot
                          #enabled: #valueOfHavingSelection
                          #argument: 'next'
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'Compare with Current Version'
                          #translateLabel: true
                          #value: #doCompare
                          #activeHelpKey: #testCompareWithCurrentVersion
                          #enabled: #valueOfHavingChangeSelection
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #label: 'Settings'
                #translateLabel: true
                #activeHelpKey: #settings
                #submenu: 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #label: 'Auto Update'
                          #translateLabel: true
                          #activeHelpKey: #settingsAutoUpdate
                          #enabled: #valueOfNotReading
                          #indication: #autoUpdateMode:
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'Private Classes as Separate'
                          #translateLabel: true
                          #activeHelpKey: #settingsPrivateAsSeparate
                          #enabled: #valueOfNotReading
                          #indication: #privateAsSeparate:
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'Columns'
                          #translateLabel: true
                          #activeHelpKey: #settingsColumns
                          #submenu: 
                           #(#Menu
                              
                               #(
                                 #(#MenuItem
                                    #label: 'Category'
                                    #activeHelpKey: #settingsColumnsCategory
                                    #indication: #categoryColumn:
                                )
                                 #(#MenuItem
                                    #label: 'Delta Info'
                                    #activeHelpKey: #settingsColumnsDeltaInfo
                                    #indication: #deltaInfoColumn:
                                )
                                 #(#MenuItem
                                    #label: 'Type'
                                    #activeHelpKey: #settingsColumnsType
                                    #indication: #typeColumn:
                                )
                                 #(#MenuItem
                                    #label: 'Time Stamp'
                                    #activeHelpKey: #settingsColumnsTimeStamp
                                    #indication: #timeStampColumn:
                                )
                                 #(#MenuItem
                                    #label: 'Positions'
                                    #activeHelpKey: #settingsColumnsPosition
                                    #indication: #positionsColumn:
                                )
                              ) nil
                              nil
                          )
                      )
                       #(#MenuItem
                          #label: '-'
                      )
                       #(#MenuItem
                          #label: 'Fonts'
                          #translateLabel: true
                          #enabled: #valueOfNotReading
                          #submenuChannel: #menuFont
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #label: 'History'
                #translateLabel: true
                #submenuChannel: #menuHistory
            )
             #(#MenuItem
                #label: 'Help'
                #translateLabel: true
                #startGroup: #right
                #activeHelpKey: #help
                #submenuChannel: #menuHelp
            )
          ) nil
          nil
      )

    "Modified: / 19.5.1998 / 18:17:27 / cg"
!

menuTable
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

    "
     MenuEditor new openOnClass:NewChangesBrowser andSelector:#menuTable
     (Menu new fromLiteralArrayEncoding:(NewChangesBrowser menuTable)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #label: 'Apply'
                #translateLabel: true
                #value: #doApply
                #activeHelpKey: #applyLine
                #enabled: #valueOfHavingChangeSelection
            )
             #(#MenuItem
                #label: 'Apply To End'
                #translateLabel: true
                #value: #doApplyToEnd
                #activeHelpKey: #applyToEnd
                #enabled: #valueOfHavingSelection
            )
             #(#MenuItem
                #label: 'Apply All For Class'
                #translateLabel: true
                #value: #doApplyAllForClass
                #activeHelpKey: #applyForClassToEnd
                #enabled: #valueOfHavingChangeSelection
            )
             #(#MenuItem
                #label: 'Apply For Class To End'
                #translateLabel: true
                #value: #doApplyForClassToEnd
                #activeHelpKey: #applyForClassToEnd
                #enabled: #valueOfHavingChangeSelection
            )
             #(#MenuItem
                #label: '-'
            )
             #(#MenuItem
                #label: 'Delete'
                #translateLabel: true
                #value: #doDelete
                #activeHelpKey: #deleteLine
                #enabled: #valueOfHavingSelection
            )
             #(#MenuItem
                #label: 'Delete To End'
                #translateLabel: true
                #value: #doDeleteToEnd
                #activeHelpKey: #deleteToEnd
                #enabled: #valueOfHavingSelection
            )
             #(#MenuItem
                #label: 'Delete All For Class'
                #translateLabel: true
                #value: #doDeleteAllForClass
                #activeHelpKey: #applyForClassToEnd
                #enabled: #valueOfHavingChangeSelection
            )
             #(#MenuItem
                #label: 'Delete For Class To End'
                #translateLabel: true
                #value: #doDeleteForClassToEnd
                #activeHelpKey: #deleteForClassToEnd
                #enabled: #valueOfHavingChangeSelection
            )
             #(#MenuItem
                #label: '-'
            )
             #(#MenuItem
                #label: 'Browse Class'
                #translateLabel: true
                #value: #doBrowseClass
                #activeHelpKey: #fileBrowseClass
                #enabled: #valueOfHavingChangeSelection
            )
             #(#MenuItem
                #label: '-'
            )
             #(#MenuItem
                #label: 'Compress For Class'
                #translateLabel: true
                #value: #doCompressForClass
                #activeHelpKey: #deleteCompressForClass
                #enabled: #valueOfHavingChangeSelection
            )
          ) nil
          nil
      )

    "Modified: / 19.5.1998 / 18:03:59 / cg"
!

menuToolbar
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

    "
     MenuEditor new openOnClass:NewChangesBrowser andSelector:#menuToolbar
     (Menu new fromLiteralArrayEncoding:(NewChangesBrowser menuToolbar)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #label: 'Load'
                #isButton: true
                #value: #doLoad
                #activeHelpKey: #fileLoad
                #enabled: #valueOfNotReading
                #labelImage: #(#ResourceRetriever #Icon #loadIcon)
            )
             #(#MenuItem
                #label: 'Save'
                #isButton: true
                #value: #doSave
                #activeHelpKey: #fileSave
                #enabled: #valueOfNotSaving
                #labelImage: #(#ResourceRetriever #Icon #saveIcon)
            )
             #(#MenuItem
                #label: ''
            )
             #(#MenuItem
                #label: 'Compress'
                #isButton: true
                #value: #doCompress
                #activeHelpKey: #deleteCompress
                #enabled: #valueOfNotReading
                #labelImage: #(#ResourceRetriever nil #compressIcon)
            )
             #(#MenuItem
                #label: ''
            )
             #(#MenuItem
                #label: 'Apply'
                #isButton: true
                #value: #doApply
                #activeHelpKey: #applyLine
                #enabled: #valueOfHavingChangeSelection
                #labelImage: #(#ResourceRetriever nil #applyIcon)
            )
             #(#MenuItem
                #label: 'Apply To End'
                #isButton: true
                #value: #doApplyToEnd
                #activeHelpKey: #applyToEnd
                #enabled: #valueOfHavingSelection
                #labelImage: #(#ResourceRetriever nil #applyToEndIcon)
            )
             #(#MenuItem
                #label: 'Apply From Last Snapshot'
                #isButton: true
                #value: #doApplyFromLastSnapshot
                #activeHelpKey: #applyFromLastSnapshot
                #enabled: #valueOfNotReading
                #labelImage: #(#ResourceRetriever nil #applyFromLastSnapshotIcon)
            )
             #(#MenuItem
                #label: ''
            )
             #(#MenuItem
                #label: 'Delete'
                #isButton: true
                #value: #doDelete
                #activeHelpKey: #deleteLine
                #enabled: #valueOfHavingSelection
                #labelImage: #(#ResourceRetriever nil #deleteIcon)
            )
             #(#MenuItem
                #label: 'Delete To End'
                #isButton: true
                #value: #doDeleteToEnd
                #activeHelpKey: #deleteToEnd
                #enabled: #valueOfHavingSelection
                #labelImage: #(#ResourceRetriever nil #deleteToEndIcon)
            )
             #(#MenuItem
                #label: ''
            )
             #(#MenuItem
                #label: 'Find Last Snapshot'
                #isButton: true
                #value: #doFindSnapshot:
                #activeHelpKey: #testFindLastSnapshot
                #enabled: #valueOfHavingSelection
                #argument: 'last'
                #labelImage: #(#ResourceRetriever nil #findLastSnapshotIcon)
            )
             #(#MenuItem
                #label: 'Find Next Snapshot'
                #isButton: true
                #value: #doFindSnapshot:
                #activeHelpKey: #testFindNextSnapshot
                #enabled: #valueOfHavingSelection
                #argument: 'next'
                #labelImage: #(#ResourceRetriever nil #findNextSnapshotIcon)
            )
          ) nil
          nil
      )
! !

!NewChangesBrowser methodsFor:'accesssing - columns'!

categoryColumn
    "returns whether the column for the category attribute of the changes is shown"

    ^CategoryColumn ? (CategoryColumn := false)
!

categoryColumn: aBoolean
    "sets whether the column for the category attribute of the changes is shown"

    self changeColumn: #category add: (CategoryColumn := aBoolean)

    "Modified: / 19.5.1998 / 20:30:13 / cg"
!

deltaInfoColumn
    "returns whether the column for the delta info attribute of the changes is shown"

    ^DeltaInfoColumn ? (DeltaInfoColumn := false)
!

deltaInfoColumn: aBoolean
    "sets whether the column for the delta info attribute of the changes is shown; and updates"

    self changeColumn: #deltaInfo add: (DeltaInfoColumn := aBoolean).
    (self window notNil and: [DeltaInfoColumn]) ifTrue: [self doReload]

    "Modified: / 19.5.1998 / 20:30:21 / cg"
!

positionsColumn
    "returns whether the column for the position attribute of the changes is shown"

    ^PositionsColumn ? (PositionsColumn := false)
!

positionsColumn: aBoolean
    "sets whether the column for the positions attribute of the changes is shown"

    self changeColumn: #position add: (PositionsColumn := aBoolean)

    "Modified: / 19.5.1998 / 20:30:37 / cg"
!

timeStampColumn
    "returns whether the column for the time stamp attribute of the changes is shown"

    ^TimeStampColumn ? (TimeStampColumn := false)
!

timeStampColumn: aBoolean
    "sets whether the column for the time stamp attribute of the changes is shown"

    self changeColumn: #timeStamp add: (TimeStampColumn := aBoolean)

    "Modified: / 19.5.1998 / 20:30:42 / cg"
!

typeColumn
    "returns whether the column for the type attribute of the changes is shown"

    ^TypeColumn ? (TypeColumn := false)
!

typeColumn: aBoolean
    "sets whether the column for the type attribute of the changes is shown"

    self changeColumn: #type add: (TypeColumn := aBoolean)

    "Modified: / 19.5.1998 / 20:30:46 / cg"
! !

!NewChangesBrowser methodsFor:'accesssing - views'!

changeTextEditor
    "returns the view of the changeTextEditor"

    ^builder componentAt: #changeTextEditor



!

filterField
    "returns the view of the filterField"

    ^builder componentAt: #filterField



!

filterLabel
    "returns the view of the filterLabel"

    ^builder componentAt: #filterLabel



!

readProgressIndicator
    "returns the view of the readProgressIndicator"

    ^builder componentAt: #readProgressIndicator



! !

!NewChangesBrowser methodsFor:'aspects'!

listOfChangeColumns
    "initializes (during the startup) and returns the value holder for the columns"

    |holder|
    (holder := builder bindingAt:#listOfChangeColumns) isNil ifTrue:[
        builder aspectAt:#listOfChangeColumns put:(holder := List new).
        self changeColumn: nil add: true.
        self changeColumn: #change add: true.
        self categoryColumn: self categoryColumn.
        self timeStampColumn: self timeStampColumn.
        self typeColumn: self typeColumn.
        self deltaInfoColumn: self deltaInfoColumn.
        self positionsColumn: self positionsColumn.
    ].
    ^ holder

    "Modified: / 19.5.1998 / 20:30:31 / cg"
!

listOfChanges
    "returns the value holder for the changes"

    |holder| 
    (holder := builder bindingAt:#listOfChanges) isNil ifTrue:[
        builder aspectAt:#listOfChanges put:(holder := List new)
    ].   
    ^ holder
!

selectionOfChange
    "returns the value holder for the selected change"

    |holder|
    (holder := builder bindingAt:#selectionOfChange) isNil ifTrue:[
        builder aspectAt:#selectionOfChange put:(holder :=  ValueHolder new).
    ].                                           
    ^ holder
!

valueOfChangeText
    "returns the value holder for the source code of the selected change"

    |holder|
    (holder := builder bindingAt:#valueOfChangeText) isNil ifTrue:[
        builder aspectAt:#valueOfChangeText put:(holder :=  ValueHolder new).
    ].
    ^ holder
!

valueOfFilter
    "returns the value holder for the string of the filter"

    |holder|
    (holder := builder bindingAt:#valueOfFilter) isNil ifTrue:[
        builder aspectAt:#valueOfFilter put:(holder :=  ValueHolder new).
        holder addDependent: self
    ].
    ^ holder
!

valueOfHavingChangeSelection
    "returns whether the selected change can be applied as value holder"

    |holder|
    (holder := builder bindingAt:#valueOfHavingChangeSelection) isNil ifTrue:[
        builder aspectAt:#valueOfHavingChangeSelection put:(holder :=  false asValue).
    ].
    ^ holder
!

valueOfHavingSelection
    "returns whether a change is selected as value holder"

    |holder|
    (holder := builder bindingAt:#valueOfHavingSelection) isNil ifTrue:[
        builder aspectAt:#valueOfHavingSelection put:(holder :=  false asValue).
    ].
    ^ holder
!

valueOfNotReading
    "returns whether it is not reading or compressing as value holder"

    |holder|
    (holder := builder bindingAt:#valueOfReading) isNil ifTrue:[
        builder aspectAt:#valueOfReading put:(holder :=  true asValue).
    ].
    ^ holder
!

valueOfNotSaving
    "returns whether it is not saving as value holder"

    |holder|
    (holder := builder bindingAt:#valueOfNotSaving) isNil ifTrue:[
        builder aspectAt:#valueOfNotSaving put:(holder :=  true asValue).
    ].
    ^ holder
!

valueOfReadProgress
    "returns the stage of reading or compressing as value holder"

    |holder|
    (holder := builder bindingAt:#valueOfReadProgress) isNil ifTrue:[
        builder aspectAt:#valueOfReadProgress put:(holder :=  ValueHolder with: 0).
    ].
    ^ holder
! !

!NewChangesBrowser methodsFor:'callbacks'!

changeSelected: lineNr
    "fetches the source code of the change and shows it in the codeView"

    |aStream sawExcla chunk selectedRow changeNr|

    lineNr == 0 ifTrue: [^nil].
    changeNr := changes indexOf: (self listOfChanges at: lineNr).
    aStream := self streamForChange: (changes at: changeNr).
    aStream isNil ifTrue:[^ self].
    sawExcla := aStream peekFor:(aStream class chunkSeparator).
    chunk := aStream nextChunk.
    sawExcla ifTrue:[
        chunk := aStream nextChunk
    ].
    aStream close.        
    self valueOfChangeText value:chunk.

    self updateChannels
! !

!NewChangesBrowser methodsFor:'change & update'!

update:something with:aParameter from:changedObject
    "evaluates the filterCompletionBlock after returning the filter string"

    super update:something with:aParameter from:changedObject.

    changedObject == self valueOfFilter 
    ifTrue: 
    [                           
        filterCompletionBlock value: changedObject value. 
        self listOfChanges size > 0 ifTrue: [self addToHistory: changedObject value -> #doFilter:] 
    ]






!

updateChannels
    "updates my channels"

    |change|           
    (change := self selectionOfChange value) notNil
    ifTrue:
    [
        self valueOfHavingSelection value: true.
        self valueOfHavingChangeSelection value: 
            ((change type = 'method') or: [(change type = 'class')])
    ]
    ifFalse:
    [
        self valueOfHavingSelection value: false.
        self valueOfHavingChangeSelection value: false
    ]






! !

!NewChangesBrowser methodsFor:'compiler interface'!

wantChangeLog
    "sent by the compiler to ask if a changeLog entry should
     be written. Return false here."

    ^ false


! !

!NewChangesBrowser methodsFor:'error handling'!

correctableError:aString position:relPos to:relEndPos from:aCompiler
    "compiler notifys us of an error - this should really not happen since
     changes ought to be correct (did someone edit the changes file ??).
     Show the bad change in the codeView and let codeView hilight the error;
     no corrections allowed here therefore return false"

    self error:aString position:relPos to:relEndPos from:aCompiler.
    ^ false
!

error:aString position:relPos to:relEndPos from:aCompiler
    "compiler notifys us of an error - this should really not happen since
     changes ought to be correct (did someone edit the changes file ??).
     Show the bad change in the codeView and let codeView hilight the error"

    |action|

    (skipSignal notNil) ifTrue:[

        self changeTextEditor highlightingErrorPosition:relPos to:relEndPos do:[
            |box|

            "
             start dialog - make certain cleanup is done
            "
            action := OptionBox 
                          request:aString
                          label:'Error'
                          form:(WarningBox iconBitmap)
                          buttonLabels:#('cancel' 'skip' 'continue')
                          values:#(#abort #skip #continue)
                          default:#continue.
        ].

        action == #abort ifTrue:[
            Object abortSignal raise.
            ^ false
        ].
        action == #skip ifTrue:[
            skipSignal raise.
            ^ false
        ].
        ^  false 
    ].
    ^self changeTextEditor error:aString position:relPos to:relEndPos from:aCompiler

!

warning:aString position:relPos to:relEndPos from:aCompiler
    "compiler notifys us of a warning - ignore it"

    ^ self

! !

!NewChangesBrowser methodsFor:'help'!

defaultInfoLabel
    "returns the default label for the info bar"

    changeFileName asFilename exists ifTrue: [^changeFileName].
    ^'No change file name defined.'



! !

!NewChangesBrowser methodsFor:'initialization'!

initialize
    "initializes the instance variables"

    super initialize.

    changes           := List new.
    self changeFileName: ObjectMemory nameForChanges. 
    AutoUpdate        := AutoUpdate ? false.                                     
    PrivateAsSeparate := PrivateAsSeparate ? false.

    ObjectMemory addDependent:self.
! !

!NewChangesBrowser methodsFor:'menu modes'!

autoUpdateMode
    "returns whether autoUpdate is on/off"

    ^AutoUpdate

!

autoUpdateMode: aMode
    "sets the autoUpdate to aMode"

    AutoUpdate := aMode

!

privateAsSeparate
    "returns whether private classes are handled as separate changes"

    ^PrivateAsSeparate

!

privateAsSeparate: aMode
    "sets the PrivateAsSeparate to aMode"

    PrivateAsSeparate := aMode

! !

!NewChangesBrowser methodsFor:'private'!

applyChange:aChange
    "applies aChange"

    |aStream nm applyAction changeNr|

    aStream := self streamForChange:aChange.
    aStream isNil ifTrue:[^ self].

    nm := self classNameOfChange:aChange.
    nm notNil ifTrue:[
        |cls|

        cls := Smalltalk at:(nm asSymbol) ifAbsent:[].
        cls notNil ifTrue:[
            cls isLoaded ifFalse:[
                cls autoload
            ]
        ]
    ].

    applyAction := [
        |sig|

        (skipSignal notNil) ifTrue:[
            sig := skipSignal
        ] ifFalse:[
            sig := Object abortSignal
        ].
        sig catch:[
            |reader doItChunk methodsForChunk|

            "/ a followup methodsFor: chunk...
            aChange followUp ifTrue:[
                methodsForChunk := aChange chunk.
            ] ifFalse:[
                doItChunk := aStream nextChunk.   "/ an empty chunk sometimes...
                doItChunk notEmpty ifTrue:[
                    Compiler evaluate:doItChunk notifying:self.
                ] ifFalse:[
                    methodsForChunk := aStream nextChunk.   "/ the real one
                ]
            ].
            methodsForChunk notNil ifTrue:[
                Class methodRedefinitionSignal handle:[:ex |
                    ex proceedWith:#keep
                ] do:[
                    reader := Compiler evaluate:methodsForChunk notifying:self.
                    reader fileInFrom:aStream notifying:self passChunk:false single:true.
                ]
            ]
        ].
    ].

    "/
    "/ if I am showing the changes file, dont update it
    "/
    changeFileName asFilename pathName = ObjectMemory nameForChanges asFilename pathName ifTrue:[
        Class withoutUpdatingChangesDo:applyAction
    ] ifFalse:[
        applyAction value
    ].
    aStream close

    "Modified: / 8.9.1998 / 12:48:01 / cg"
!

autoSelectChange:aChange
    "selects aChange"

    self class autoSelectNext ifTrue:[         
        ((self listOfChanges indexOf: aChange) <= self listOfChanges size) ifTrue:[
            self selectionOfChange value: aChange.  
            self changeSelected:(self listOfChanges indexOf: aChange).
            self updateChannels.
            ^ self
        ]
    ].         
    self updateChannels.
    self unselectChange

!

autoSelectLast
    "selects the last change"

    self autoSelectChange: (self listOfChanges at: self listOfChanges size ifAbsent: nil).
    self updateChannels.

!

autoSelectOrEnd:aChange
    "selects aChange or the last"

    |last|

    last := self listOfChanges size.
    aChange notNil ifTrue:[  
        self autoSelectChange:aChange
    ] ifFalse:[
        self selectionOfChange value: (self listOfChanges at: last ifAbsent: nil).
        self changeSelected: last
    ].
    self updateChannels
!

changeColumn: aColumnId add: addOrRemove
    "adds or removes a attribute column to the table"

    |newListOfChangeColumns|

    newListOfChangeColumns := self listOfChangeColumns asOrderedCollection.
    addOrRemove
    ifTrue:
    [    
        newListOfChangeColumns add: 
            ((self class tableColumnsForChangeAttributes 
                collect: [:i| i decodeAsLiteralArray]) 
                    detect: [:column| column id = aColumnId])
    ]
    ifFalse:
    [
        newListOfChangeColumns remove: 
            (self listOfChangeColumns detect: [:column| column id = aColumnId] ifNone: nil) ifAbsent: nil
    ].
    self listOfChangeColumns contents: newListOfChangeColumns.
    self autoSelectLast

    "Modified: / 19.5.1998 / 20:32:53 / cg"
!

changeFileName:aFileName
    "sets the name of the file with the changes"

    changeFileName := (Filename currentDirectory asAbsoluteFilename construct: aFileName) name.
!

checkClassIsLoaded:aClass
    "returns true if aClass is loaded"

    |cls|
    aClass isMeta ifTrue:[
        cls := aClass soleInstance
    ] ifFalse:[
        cls := aClass
    ].
    cls isLoaded ifFalse:[
        (self confirm:(cls name , ' is an autoloaded class.\I can only compare the methods texts if its loaded first.\\Load the class first ?') withCRs)
        ifTrue:[
            cls autoload
        ]
    ].
    ^ cls isLoaded
!

checkIfFileHasChanged
    "checks if changes file has changed"

    |f info|

    Processor removeTimedBlock:autoUpdateBlock.   
    f := changeFileName asFilename.
    (info := f info) isNil ifTrue:[
        self newLabel:'unaccessable'
    ] ifFalse:[
        (info modified) > changeFileTimestamp ifTrue:[
            self newLabel:'outdated'.
            AutoUpdate ifTrue:[
                self doReload
            ]
        ] ifFalse:[
            self newLabel:''
        ]
    ].
    Processor addTimedBlock:autoUpdateBlock afterSeconds:5.
!

classNameOfChange:aChange
    "returns the classname of aChange 
     (for classChanges (i.e. xxx class), the non-metaClassName (i.e. xxx) is returned)"

    |name|

    name := self fullClassNameOfChange:aChange.
    name isNil ifTrue:[^ nil].
    (name endsWith:' class') ifTrue:[
        ^ name copyWithoutLast:6
    ].
    ^ name
!

compareChange:aChange
    "compares aChange with the current version"

    |aStream chunk sawExcla parseTree thisClass cat oldSource newSource
     parser sel oldMethod outcome showDiff d t1 t2 selector isLoaded
     method beep|

    aStream := self streamForChange:aChange.
    aStream isNil ifTrue:[^ self].

    showDiff := false.

    aChange followUp ifFalse:[
        sawExcla := aStream peekFor:(aStream class chunkSeparator).
        chunk := aStream nextChunk.
    ] ifTrue:[
        chunk := aChange chunk.
        sawExcla := true.
    ].

    beep := false.
    sawExcla ifFalse:[
        outcome := 'Cannot compare this change\(i.e. this is not a method change)!!'.

        parseTree := Parser parseExpression:chunk.
        (parseTree notNil and:[parseTree isMessage]) ifTrue:[
            ((selector := parseTree selector) == #removeSelector:) ifTrue:[
                thisClass := (parseTree receiver evaluate).
                thisClass isBehavior ifTrue:[
                    (self checkClassIsLoaded:thisClass) ifTrue:[
                        selector := (parseTree arg1 evaluate).
                        (thisClass includesSelector:selector) ifTrue:[
                            outcome := 'Change removes the #' , selector , ' method from ' , thisClass name.
                        ] ifFalse:[
                            outcome := 'Change has no effect\(there is no method for #' , selector , ' in ' , thisClass name , ')'
                        ]
                    ] ifFalse:[
                        beep := true.
                        outcome := 'Cannot compare this change (compare requires class to be loaded)!!'.
                    ]
                ]
            ].
            selector == #category: ifTrue:[
                parseTree receiver isMessage ifTrue:[
                    parseTree receiver selector == #compiledMethodAt: ifTrue:[
                        (method := parseTree receiver evaluate) isMethod ifTrue:[
                            method category = parseTree arg1 evaluate ifTrue:[
                                outcome := 'Change has no effect\(same category)'.
                            ] ifFalse:[
                                outcome := 'Category is different (''' , method category , ''' vs. ''' , parseTree arg1 evaluate , ''')'
                            ]
                        ] ifFalse:[
                            beep := true.
                            outcome := 'There is no such method!!'
                        ]
                    ]
                ]
            ]
        ]
    ] ifTrue:[
        parseTree := Parser parseExpression:chunk.
        (parseTree notNil 
         and:[parseTree ~~ #Error
         and:[parseTree isMessage]]) ifTrue:[
            (parseTree selector == #methodsFor:) ifTrue:[
                thisClass := (parseTree receiver evaluate).
                thisClass isBehavior ifTrue:[
                    (isLoaded := self checkClassIsLoaded:thisClass) ifFalse:[
                        outcome := 'Cannot compare this change\(compare requires class to be loaded)!!'.
                    ].

                    cat := parseTree arg1 evaluate.
                    newSource := aStream nextChunk.

                    parser := Parser parseMethod:newSource in:thisClass.
                    (parser notNil and:[parser ~~ #Error]) ifTrue:[
                        sel := parser selector.
                        oldMethod := thisClass compiledMethodAt:sel.
                        oldMethod notNil ifTrue:[
                            (oldMethod category = cat) ifFalse:[
                                Transcript showCR:'Category changed.'.
                            ].
                            oldSource := oldMethod source.
                            (oldSource = newSource) ifTrue:[
                                outcome := 'Same source.'
                            ] ifFalse:[
                                oldSource isNil ifTrue:[
                                    beep := true.
                                    outcome := 'No source for compare.'
                                ] ifFalse:[
                                    "/
                                    "/ compare for tabulator <-> space changes
                                    "/ before showing diff...
                                    "/
                                    t1 := oldSource asCollectionOfLines collect:[:s | s withTabsExpanded].
                                    t2 := newSource asCollectionOfLines collect:[:s | s withTabsExpanded].
                                    t1 = t2 ifTrue:[
                                        outcome := 'Same source.'
                                    ] ifFalse:[
                                        outcome := 'Source changed!!'.
                                        showDiff := true.

                                        "/
                                        "/ check if only historyLine diffs
                                        "/
                                        (HistoryManager notNil 
                                        and:[HistoryManager isActive]) ifTrue:[
                                            (HistoryManager withoutHistoryLines:newSource)
                                            =
                                            (HistoryManager withoutHistoryLines:oldSource)
                                            ifTrue:[
                                                outcome := 'Same source (history only).'.
                                                showDiff := false.
                                            ]
                                        ].
                                    ]
                                ]
                            ]
                        ] ifFalse:[
                            isLoaded ifTrue:[
                                beep := true.
                                outcome := 'Method does not exist!!'
                            ]
                        ]
                    ] ifFalse:[
                        outcome := 'Change unparsable!!'
                    ].
                    (showDiff and:[oldSource notNil and:[newSource notNil]]) ifTrue:[
                        d := DiffTextView 
                                openOn:oldSource label:'Current version (in image)'
                                and:newSource label:'Change version'.
                        d label:'method differences'.
                    ]
                ] ifFalse:[
                    beep := true.
                    outcome := 'Class does not exist!!'
                ]
            ] ifFalse:[
                beep := true.
                outcome := 'Not comparable!!'
            ]
        ] ifFalse:[
            beep := true.
            outcome := 'Not comparable!!'
        ]
    ].
    aStream close.
    showDiff ifFalse:[
        beep ifTrue:[
            self warn:outcome withCRs.
        ] ifFalse:[
            self information:outcome withCRs.
        ]
    ]
!

compressForClass:aClassNameOrNil
    "compresses the list of changes; 
     this replaces multiple method-changes by the last (i.e. the most recent) change.
     If the class argument is nil, compress for all classes.
     otherwise, only changes for that class are compressed."

    |aStream searchIndex anyMore deleteSet index  
     str snapshotProto snapshotPrefix snapshotNameIndex fileName|

    aStream := FileStream readonlyFileNamed:changeFileName.
    aStream isNil ifTrue:[^ self].

    aClassNameOrNil isNil ifTrue:[
        self newLabel:'compressing...'.
    ] ifFalse:[
        self newLabel:'compressing for ' , aClassNameOrNil.
    ].

    CompressSnapshotInfo == true ifTrue:[
        "
         get a prototype snapshot record (to be independent of
         the actual format ..
        "
        str := WriteStream on:String new.
        Class addChangeRecordForSnapshot:'foo' to:str.
        snapshotProto := str contents.
        snapshotPrefix := snapshotProto copyTo:10.
        snapshotNameIndex := snapshotProto findString:'foo'.
    ].

    self valueOfNotReading value: false.
    self valueOfHavingSelection value: false.
    self valueOfHavingChangeSelection value: false.
    self valueOfReadProgress value: 0.
    self readProgressIndicator raise.
    self filterLabel label: 'Comp:'; redraw.

    self withExecuteCursorDo:[
        |numChanges classes selectors types excla sawExcla
         changeNr chunk aParseTree parseTreeChunk
         thisClass thisSelector codeChunk codeParser
         compressThis oldValue|

        numChanges := changes size.
        classes := Array new:numChanges.
        selectors := Array new:numChanges.
        types := Array new:numChanges.

        "starting at the end, get the change class and change selector;
         collect all in classes / selectors"

        changeNr := numChanges.
        excla := aStream class chunkSeparator.

        [changeNr >= 1] whileTrue:[
            oldValue := self valueOfReadProgress value.
                self valueOfReadProgress value: (100 - ((aStream position/aStream size) * 100) rounded).
                oldValue ~~ self valueOfReadProgress value
                    ifTrue: [self readProgressIndicator redrawEdges;redraw].
            aStream position:(changes at: changeNr) position.
            sawExcla := aStream peekFor:excla.
            chunk := aStream nextChunk.
            sawExcla ifTrue:[
                "optimize a bit if multiple methods for same category arrive"
                (chunk = parseTreeChunk) ifFalse:[
                    aParseTree := Parser parseExpression:chunk.
                    parseTreeChunk := chunk
                ].
                (aParseTree notNil 
                and:[(aParseTree ~~ #Error) 
                and:[aParseTree isMessage]]) ifTrue:[
                    (aParseTree selector == #methodsFor:) ifTrue:[
                        thisClass := (aParseTree receiver evaluate).
                        codeChunk := aStream nextChunk.
                        codeParser := Parser 
                                          parseMethodSpecification:codeChunk
                                          in:thisClass
                                          ignoreErrors:true
                                          ignoreWarnings:true.
                        (codeParser notNil and:[codeParser ~~ #Error]) ifTrue:[
                            selectors at:changeNr put:(codeParser selector).
                            classes at:changeNr put:thisClass.
                            types at:changeNr put:#methodsFor
                        ]
                    ]
                ]
            ] ifFalse:[
                aParseTree := Parser parseExpression:chunk.
                parseTreeChunk := chunk.
                (aParseTree notNil 
                and:[(aParseTree ~~ #Error) 
                and:[aParseTree isMessage]]) ifTrue:[
                    (aParseTree selector == #removeSelector:) ifTrue:[
                        selectors at:changeNr put:(aParseTree arg1 value ).
                        classes at:changeNr put:(aParseTree receiver evaluate).
                        types at:changeNr put:#removeSelector
                    ]
                ] ifFalse:[
                    CompressSnapshotInfo == true ifTrue:[
                        (chunk startsWith:snapshotPrefix) ifTrue:[
                            str := chunk readStream position:snapshotNameIndex.
                            fileName := str upTo:(Character space).
                            "
                             kludge to allow use of match-check below
                            "
                            selectors at:changeNr put:snapshotPrefix.
                            classes at:changeNr put:fileName.
                        ]
                    ]
                ]
            ].
            changeNr := changeNr - 1
        ].
        aStream close.

        "for all changes, look for another class/selector occurence later
         in the list and, if there is one, add change number to the delete set"

        deleteSet := OrderedCollection new.
        changeNr := 1.
        [changeNr < changes size] whileTrue:[
            thisClass := classes at:changeNr.

            compressThis := false.
            aClassNameOrNil isNil ifTrue:[
                compressThis := true
            ] ifFalse:[
                "/ skipping unloaded/unknown classes
                thisClass isBehavior ifTrue:[
                    thisClass isMeta ifTrue:[
                        compressThis := aClassNameOrNil = thisClass soleInstance name. 
                    ] ifFalse:[
                        compressThis := aClassNameOrNil = thisClass name.
                        (PrivateAsSeparate not and: [thisClass isPrivate])
                            ifTrue:[compressThis := aClassNameOrNil = thisClass owningClass name]
                    ]
                 ]
            ].

            compressThis ifTrue:[
                thisSelector := selectors at:changeNr.
                searchIndex := changeNr.
                anyMore := true.
                [anyMore] whileTrue:[
                    searchIndex := classes indexOf:thisClass
                                        startingAt:(searchIndex + 1).
                    (searchIndex ~~ 0) ifTrue:[
                        ((selectors at:searchIndex) == thisSelector) ifTrue:[
                            thisClass notNil ifTrue:[
                                deleteSet add:changeNr.
                                anyMore := false
                            ]
                        ]
                    ] ifFalse:[
                        anyMore := false      
                    ]
                ].
            ].

            changeNr := changeNr + 1
        ].

        "finally delete what has been found"

        (deleteSet size > 0) ifTrue:[
            index := deleteSet size.
            [index > 0] whileTrue:[
                self silentDeleteChange: (changes at: (deleteSet at:index)).
                index := index - 1
            ].
            self setChangeList
        ].
    ].
    self valueOfNotReading value: true.
    self filterField raise.
    self filterLabel label: 'Filter:'.
    self newLabel: ''
!

contractClass:className selector:selector to:maxLen
    |s l|

    s := className , ' ', selector.
    s size > maxLen ifTrue:[
        l := maxLen - 1 - selector size max:20.
        s := (className contractTo:l) , ' ' , selector.

        s size > maxLen ifTrue:[
            l := maxLen - 1 - className size max:20.
            s := className , ' ', (selector contractTo:l).

            s size > maxLen ifTrue:[
                s := (className contractTo:(maxLen // 2 - 1)) , ' ' , (selector contractTo:maxLen // 2)
            ]
        ]
    ].
    ^ s

!

deleteChangesFrom:start to:stop
    "deletes a range of changes"

    self unselectChange.     
    stop to:start by:-1 do:[:changeNr|
        self silentDeleteChange:(self listOfChanges at: changeNr)
    ].
    self setChangeList
!

fullClassNameOfChange:aChange
    "returns the full classname of aChange 
     (for classChanges (i.e. xxx class), a string ending in ' class' is returned.
     - since parsing ascii methods is slow, keep result cached in 
       changeClassNames for the next query"

    |chunk aParseTree recTree sel name arg1Tree isMeta prevMethodDefNr
     words changeStream fullParseTree ownerTree ownerName oldDollarSetting|

    aChange isNil ifTrue:[^ nil].

    "
     first look, if not already known
    "
    name := aChange className.
    name notNil ifTrue:[^ name].

    prevMethodDefNr := changes indexOf: aChange.
    [(changes at:prevMethodDefNr) followUp] whileTrue:[
        prevMethodDefNr := prevMethodDefNr - 1.
    ].

    "
     get the chunk
    "
    chunk := (changes at:prevMethodDefNr) chunk.
    chunk isNil ifTrue:[^ nil].       "mhmh - empty"

    (chunk startsWith:'''---') ifTrue:[
        words := chunk asCollectionOfWords.
        words size > 2 ifTrue:[
            (words at:2) = 'checkin' ifTrue:[
                name := words at:3.
                aChange className: name.
                ^ name
            ]
        ].
    ].

    "/ fix it - otherwise, it cannot be parsed
    (chunk endsWith:'primitiveDefinitions:') ifTrue:[
        chunk := chunk , ''''''
    ].
    (chunk endsWith:'primitiveFunctions:') ifTrue:[
        chunk := chunk , ''''''
    ].
    (chunk endsWith:'primitiveVariables:') ifTrue:[
        chunk := chunk , ''''''
    ].

    "
     use parser to construct a parseTree
    "
    oldDollarSetting := Parser allowDollarInIdentifier.
    [
        Parser allowDollarInIdentifier:true.
        aParseTree := Parser parseExpression:chunk.
    ] valueNowOrOnUnwindDo:[
        Parser allowDollarInIdentifier:oldDollarSetting
    ].

    (aParseTree isNil or:[aParseTree == #Error]) ifTrue:[
        ^ nil        "seems strange... (could be a comment)"
    ].
    aParseTree isMessage ifFalse:[
        ^ nil        "very strange... (whats that ?)"
    ].

    "
     ask parser for selector
    "
    sel := aParseTree selector.
    recTree := aParseTree receiver.

    "
     is it a method-change, methodRemove or comment-change ?
    "
    (#(#'methodsFor:' 
       #'privateMethodsFor:' 
       #'protectedMethodsFor:' 
       #'publicMethodsFor:' 
       #'removeSelector:' 
       #'comment:'
       #'primitiveDefinitions:'
       #'primitiveFunctions:'
       #'primitiveVariables:'
       #'renameCategory:to:'
       #'instanceVariableNames:'
    ) includes:sel) ifTrue:[
        "
         yes, the className is the receiver
        "
        (recTree notNil and:[recTree ~~ #Error]) ifTrue:[
            isMeta := false.
            recTree isUnaryMessage ifTrue:[
                (recTree selector ~~ #class) ifTrue:[^ nil].
                "id class methodsFor:..."
                recTree := recTree receiver.
                isMeta := true.
            ].
            recTree isPrimary ifTrue:[
                name := recTree name.
                isMeta ifTrue:[
                    name := name , ' class'.
                ].
                aChange className: name.
                ^ name
            ]
        ].
        "more strange things"
        ^ nil
    ].

    "
     is it a change in a class-description ?
    "
    (('subclass:*' match:sel) 
    or:[('variable*subclass:*' match:sel)]) ifTrue:[
        "/ must parse the full changes text, to get
        "/ privacy information.

        changeStream := self streamForChange:aChange.
        changeStream notNil ifTrue:[
            chunk := changeStream nextChunk.
            changeStream close.
            fullParseTree := Parser parseExpression:chunk.
            (fullParseTree isNil or:[fullParseTree == #Error]) ifTrue:[
                fullParseTree := nil
            ].
            fullParseTree isMessage ifFalse:[
                fullParseTree := nil
            ].
            "/ actually, the nil case cannot happen
            fullParseTree notNil ifTrue:[
                aParseTree := fullParseTree.
                sel := aParseTree selector.
            ].
        ].

        arg1Tree := aParseTree arg1.
        (arg1Tree notNil and:[arg1Tree isConstant]) ifTrue:[
            name := arg1Tree value asString.

            "/ is it a private-class ?
            ('*privateIn:' match:sel) ifTrue:[
                ownerTree := aParseTree args last.
                ownerName := ownerTree name asString.
                name := ownerName , '::' , name
            ].
            aChange className: name.
            ^ name
        ].
        "very strange"
        ^ nil
    ].

    "
     is it a class remove ?
    "
    (sel == #removeClass:) ifTrue:[
        (recTree notNil 
        and:[recTree ~~ #Error
        and:[recTree isPrimary
        and:[recTree name = 'Smalltalk']]]) ifTrue:[
            arg1Tree := aParseTree arg1.
            (arg1Tree notNil and:[arg1Tree isPrimary]) ifTrue:[
                name := arg1Tree name.
                aChange className: name.
                ^ name
            ].
        ]
    ].

    "
     is it a method category change ?
    "
    ((sel == #category:)
    or:[sel == #privacy:]) ifTrue:[
        (recTree notNil 
        and:[recTree ~~ #Error
        and:[recTree isMessage
        and:[recTree selector == #compiledMethodAt:]]]) ifTrue:[
            isMeta := false.
            recTree := recTree receiver.
            recTree isUnaryMessage ifTrue:[
                (recTree selector ~~ #class) ifTrue:[^ nil].
                "id class "
                recTree := recTree receiver
            ].
            recTree isPrimary ifTrue:[
                isMeta ifTrue:[
                    name := name , ' class'.
                ].
                name := recTree name.
                aChange className: name.
                ^ name
            ]
        ]
    ].
    ^ nil
!

newLabel:how
    "sets the label"

    how size = 0 ifTrue: [^self window label:self class label].
    self window label:self class label, ' (', how, ')'
!

readChangesFileInBackground:inBackground
    "reads the changes file, creates a list of header-lines (changeChunks)
     and a list of chunk-positions (changePositions).
     Starting with 2.10.3, the entries are multi-col entries;
     the cols are:
        1   delta (only if comparing)
                '+' -> new method (w.r.t. current state)
                '-' -> removed method (w.r.t. current state)
                '?' -> class does not exist currently
                '=' -> change is same as current methods source
        2   class/selector
        3   type of change
                doit
                method
                category change
        4   timestamp

     since comparing slows down startup time, it is now disabled by
     default and can be enabled via a toggle."

    |aStream maxLen i f|

    self valueOfNotReading value: false.
    self valueOfHavingSelection value: false.
    self valueOfHavingChangeSelection value: false.

    editingClassSource := false.

    maxLen := 60.

    f := changeFileName asFilename.
    aStream :=  f readStream.
    aStream isNil ifTrue:[^ nil].

    self newLabel:(resources string:'updating...').

    i := f info.
    changeFileTimestamp := i modified.

    self valueOfReadProgress value: 0.
    self readProgressIndicator raise.
    self filterLabel label: 'Read:'; redraw.

    self withReadCursorDo:[
        |myProcess myPriority|

        "
         this is a time consuming operation (especially, if reading an
         NFS-mounted directory; therefore lower my priority...
        "
        inBackground ifTrue:[
            myProcess := Processor activeProcess.
            myPriority := myProcess priority.
            myProcess priority:(Processor userBackgroundPriority).
        ].

        [
            |excla timeStampInfo lastChange|

            excla := aStream class chunkSeparator.

            [aStream atEnd] whileFalse:[
                |change changeDelta changeString changeType changeCategory
                 line s l changeClass sawExcla category 
                 chunkText chunkPos sel oldValue|

                change := Change new.
                "
                 get a chunk (separated by excla)
                "
                oldValue := self valueOfReadProgress value.
                self valueOfReadProgress value: (((aStream position/aStream size) * 100) rounded).
                oldValue ~~ self valueOfReadProgress value
                    ifTrue: [self readProgressIndicator redrawEdges;redraw].

                aStream skipSeparators.
                chunkPos := aStream position.

                sawExcla := aStream peekFor:excla.
                chunkText := aStream nextChunk.
                chunkText notNil ifTrue:[
                    |index headerLine cls|

                    (chunkText startsWith:'''---- timestamp ') ifTrue:[
                        timeStampInfo := (chunkText copyFrom:16 to:(chunkText size - 6)) withoutSpaces.
                    ] ifFalse:[

                        "
                         only first line is saved in changeChunks...
                        "
                        index := chunkText indexOf:(Character cr).
                        (index ~~ 0) ifTrue:[
                            chunkText := chunkText copyTo:(index - 1).

                            "take care for comment changes - must still be a
                             valid expression for classNameOfChange: to work"

                            (chunkText endsWith:'comment:''') ifTrue:[
                                chunkText := chunkText , '...'''
                            ].
                            (chunkText endsWith:'primitiveDefinitions:''') ifTrue:[
                                sel := 'primitiveDefinitions:'.
                                chunkText := chunkText copyWithoutLast:1
                            ].
                            (chunkText endsWith:'primitiveVariables:''') ifTrue:[
                                sel := 'primitiveVariables:'.
                                chunkText := chunkText copyWithoutLast:1
                            ].
                            (chunkText endsWith:'primitiveFunctions:''') ifTrue:[
                                sel := 'primitiveFunctions:'.
                                chunkText := chunkText copyWithoutLast:1
                            ].
                        ].

                        change chunk: chunkText.
                        change position: chunkPos. 
                        lastChange notNil ifTrue: [lastChange lastPosition: chunkPos - 1].
                        lastChange := change.
                        change timeStamp: timeStampInfo.
                        change followUp: false.
                        headerLine := nil.
                        changeDelta := ' '.

                        sawExcla ifFalse:[
                            (chunkText startsWith:'''---- snap') ifTrue:[
                                changeType := ''.
                                headerLine := chunkText.
                                changeString := (chunkText contractTo:maxLen).
                                timeStampInfo := nil.
                            ] ifFalse:[

                                |p cls|

                                headerLine := chunkText , ' (doIt)'.

                                "
                                 first, assume doIt - then lets have a more detailed look...
                                "
                                ((chunkText startsWith:'''---- file')
                                or:[(chunkText startsWith:'''---- check')]) ifTrue:[
                                    changeType := ''.
                                    timeStampInfo := nil.
                                ] ifFalse:[
                                    changeType := 'doIt'.
                                ].    
                                changeString := (chunkText contractTo:maxLen).

                                p := Parser parseExpression:chunkText inNameSpace:Smalltalk.
                                (p notNil 
                                 and:[p ~~ #Error
                                 and:[p isMessage]]) ifTrue:[
                                    sel := p selector.
                                ].
                                (sel == #removeSelector:) ifTrue:[
                                    p receiver isUnaryMessage ifTrue:[
                                        cls := p receiver receiver name.
                                        changeClass := (Smalltalk classNamed:cls) class.
                                        cls := cls , ' class'.
                                    ] ifFalse:[
                                        cls := p receiver name.
                                        changeClass := (Smalltalk classNamed:cls)
                                    ].
                                    sel := (p args at:1) evaluate.

                                    DeltaInfoColumn ifTrue:[
                                        (changeClass isNil or:[changeClass isLoaded not]) ifTrue:[
                                            changeDelta := '?'
                                        ] ifFalse:[
                                            (changeClass implements:sel asSymbol) ifTrue:[
                                                changeDelta := '-'.
                                            ]
                                        ]
                                    ].
                                    changeType := 'remove'.
                                    changeString := self contractClass:cls selector:sel to:maxLen.
                                ].
                                (p ~~ #Error
                                and:[p isMessage 
                                and:[p receiver isMessage
                                and:[p receiver selector == #compiledMethodAt:]]]) ifTrue:[
                                    p receiver receiver isUnaryMessage ifTrue:[
                                        cls := p receiver receiver receiver name.
                                        changeClass := (Smalltalk classNamed:cls) class.
                                        cls := cls , ' class'.
                                    ] ifFalse:[
                                        cls := p receiver receiver name.
                                        changeClass := (Smalltalk classNamed:cls)
                                    ].
                                    (sel == #category:) ifTrue:[
                                        sel := (p receiver args at:1) evaluate.
                                        changeType := '(category change)'.
                                        changeString := self contractClass:cls selector:sel to:maxLen.
                                    ].
                                    (sel == #privacy:) ifTrue:[
                                        sel := (p receiver args at:1) evaluate.
                                        changeType := 'privacy change'.
                                        changeString := self contractClass:cls selector:sel to:maxLen.
                                    ].
                                ].
                                (#(#'subclass:'
                                  #'variableSubclass:'
                                  #'variableByteSubclass:'
                                  #'variableWordSubclass:'
                                  #'variableLongSubclass:'
                                  #'variableFloatSubclass:'
                                  #'variableDoubleSubclass:'
                                  #'primitiveDefinitions:'
                                  #'primitiveFunctions:'
                                  #'primitiveVariables:'
                                 ) includes:sel) ifTrue:[
                                    changeType := 'class definition'.
                                ].
                            ]
                        ] ifTrue:[
                            |done first p className cls text methodPos|

                            "
                             method definitions actually consist of
                             two (or more) chunks; skip next chunk(s)
                             up to an empty one.
                             The system only writes one chunk,
                             and we cannot handle more in this ChangesBrowser....
                            "
                            className := nil.
                            p := Parser parseExpression:chunkText inNameSpace:Smalltalk.

                            (p notNil and:[p ~~ #Error]) ifTrue:[
                                sel := p selector.
                                (sel == #methodsFor:) ifTrue:[
                                    p receiver isUnaryMessage ifTrue:[
                                        className := p receiver receiver name.
                                        changeClass := (Smalltalk classNamed:className) class.
                                        className := className , ' class'.
                                    ] ifFalse:[
                                        className := p receiver name.
                                        changeClass := Smalltalk classNamed:className
                                    ].
                                    category := (p args at:1) evaluate.
                                ].
                            ].

                            done := false.
                            first := true.
                            [done] whileFalse:[

                                changeDelta := ' '.
                                methodPos := aStream position.

                                text := aStream nextChunk.
                                text isNil ifTrue:[
                                    done := true
                                ] ifFalse:[
                                    done := text isEmpty
                                ].
                                done ifFalse:[
                                    first ifFalse:[
                                        change := Change new.
                                        change chunk: chunkText.
                                        change string:changeString.
                                        change position: methodPos. 
                                        change className: className. 
                                        lastChange notNil ifTrue: [lastChange lastPosition: methodPos - 1].
                                        lastChange := change.
                                        change timeStamp: timeStampInfo.
                                        change followUp: true.
                                        editingClassSource := true.
                                    ].

                                    first := false.
                                    "
                                     try to find the selector
                                    "
                                    sel := nil.
                                    className notNil ifTrue:[
                                        p := Parser 
                                                 parseMethodSpecification:text
                                                 in:nil
                                                 ignoreErrors:true
                                                 ignoreWarnings:true.
                                        (p notNil and:[p ~~ #Error]) ifTrue:[
                                            sel := p selector.
                                        ]
                                    ].

                                    sel isNil ifTrue:[
                                        changeString := (chunkText contractTo:maxLen).
                                        changeType := 'change'.
                                        headerLine := chunkText , ' (change)'.
                                    ] ifFalse:[
                                        changeString :=  self contractClass:className selector:sel to:maxLen.
                                        changeType := 'method definition'.
                                        changeCategory := category.
                                        headerLine := className , ' ' , sel , ' ' , '(change category: ''' , category , ''')'.
                                    ].

                                    DeltaInfoColumn ifTrue:[ 
                                        changeClass isNil ifFalse:[
                                            changeClass isMeta ifTrue:[
                                                cls := changeClass soleInstance
                                            ] ifFalse:[
                                                cls := changeClass
                                            ].
                                        ].

                                        (changeClass isNil or:[cls isLoaded not]) ifTrue:[
                                            changeDelta := '?'
                                        ] ifFalse:[
                                            (changeClass implements:sel asSymbol) ifFalse:[
                                                changeDelta := '+'.
                                            ] ifTrue:[
                                                |m currentText t1 t2|

                                                m := changeClass compiledMethodAt:sel asSymbol.
                                                currentText := m source.
                                                currentText notNil ifTrue:[
                                                    text asString = currentText asString ifTrue:[
                                                        changeDelta := '='
                                                    ] ifFalse:[
                                                        t1 := currentText asCollectionOfLines collect:[:s | s withTabsExpanded].
                                                        t2 := text asCollectionOfLines collect:[:s | s withTabsExpanded].
                                                        t1 = t2 ifTrue:[
                                                            changeDelta := '='
                                                        ]
                                                    ]
                                                ]
                                            ]
                                        ]
                                    ].
                                    change delta:changeDelta.
                                    change string:changeString.
                                    change type:changeType.
                                    change category: changeCategory.
                                    change timeStamp:timeStampInfo.
                                    changes add:change.
                                ].
                                changeString := nil.
                                headerLine := nil.

                            ]
                        ].
                        changeString notNil ifTrue:[
                            change delta:changeDelta.
                            change string:changeString.
                            change type:changeType.
                            change timeStamp:timeStampInfo.
                            changes add:change.

                        ] ifFalse:[
                            headerLine notNil ifTrue:[     
                                changes add: change.
                            ]
                        ]
                    ]
                ]. 
                change lastPosition: aStream position.
            ].
            modified := false.

        ] valueNowOrOnUnwindDo:[ 
            aStream close.
            inBackground ifTrue:[myProcess priority:myPriority].
        ].
    ].
    self setChangeList.
    self valueOfNotReading value: true.
    self filterField raise.
    self filterLabel label: 'Filter:'.

    self checkIfFileHasChanged.

    "Modified: / 30.7.1998 / 11:39:58 / cg"
!

selectorOfMethodChange:aChange
    "returns the selector of the method change, or nil if it is not a method change"

    |source parser sel|

    source := self sourceOfMethodChange:aChange.
    source isNil ifTrue:[^ nil].

    parser := Parser 
                parseMethod:source 
                in:nil 
                ignoreErrors:true 
                ignoreWarnings:true.

    (parser notNil and:[parser ~~ #Error]) ifTrue:[
        sel := parser selector.
    ].
    ^ sel
!

setChangeList
    "sets the list of changes into the list for the table by evaluating filterCompletionBlock"

    self unselectChange.
    filterCompletionBlock value: self valueOfFilter value.
!

silentDeleteChange:aChange
    "delete aChange do not update changeListView"

    modified := true.      

    changes remove:aChange
!

silentDeleteChangesFor:aClassName from:start to:stop
    "deletes changes for aChange in the range [start,stop]
     and returns the number of the deleted changes"

    |index numDeleted clsName|

    numDeleted := 0.
    index := stop.          
    [index >= start] whileTrue:
    [                                         
        ((clsName := self classNameOfChange:(self listOfChanges at: index)) notNil and:
        [(clsName = aClassName or: [PrivateAsSeparate not and: [(clsName upTo: $:) = aClassName]])])
        ifTrue:
        [     
            self silentDeleteChange:(self listOfChanges at: index).
            numDeleted := numDeleted + 1.
        ].
        index := index - 1
    ].
    ^ numDeleted
!

sourceOfMethodChange:aChange
    "returns the source code of the method change, or nil if it is not a method change."

    |aStream chunk sawExcla parseTree sourceChunk|

    aStream := self streamForChange:aChange. 
    aStream isNil ifTrue:[^ nil].

    aChange followUp ifFalse:[
        sawExcla := aStream peekFor:(aStream class chunkSeparator).
        chunk := aStream nextChunk.
    ] ifTrue:[
        chunk := aChange chunk.
        sawExcla := true.
    ].

    sawExcla ifTrue:[
        parseTree := Parser parseExpression:chunk.
        (parseTree notNil and:[parseTree isMessage]) ifTrue:[
            (parseTree selector == #methodsFor:) ifTrue:[
                sourceChunk := aStream nextChunk.
            ]
        ].
    ].
    aStream close.
    ^ sourceChunk
!

streamForChange:aChange
    "returns the stream for aChange"

    |aStream|

    aStream := FileStream readonlyFileNamed:changeFileName.
    aStream isNil ifTrue:[^ nil].
    aStream position:aChange position.
    ^ aStream

!

unselectChange
    "unselects the current change"

    self selectionOfChange value: nil.
    self valueOfChangeText value: nil

!

withSelectedChangeDo:aBlock
    "just a helper, check for a selected change and evaluate aBlock
     with busy cursor"

    |change|

    (change := self selectionOfChange value) notNil 
    ifTrue:[
        self withExecuteCursorDo:[aBlock value:change]
    ]
! !

!NewChangesBrowser methodsFor:'startup / release'!

closeRequest
    "asks for saving before closing"

    self valueOfNotSaving value ifFalse: [^nil].

    modified ifTrue:[
        (OptionBox 
              request:(resources string:'Changes list was modified !!') withCRs
              label:'Changes Browser'
              form:(WarningBox iconBitmap)
              buttonLabels:(resources array:#('Cancel' 'Forget it and proceed'))
              values:#(#abort #ignore)
              default:#save
        ) == #abort ifTrue:[^self].
    ].
    super closeRequest

    "Modified: / 20.5.1998 / 03:53:47 / cg"
!

postOpenWith:aBuilder
    "starts reading the changes from the file and
     builds entryCompletionBlock for the filterField before opening"

    super postOpenWith:aBuilder.

    builder namedComponents do: 
    [:aView|    
        aView allSubViewsDo: 
        [:v|
            v redraw
        ] 
    ].

    autoUpdateBlock := [self checkIfFileHasChanged].
    Processor addTimedBlock:autoUpdateBlock afterSeconds:5.  
    self updateInfoLabel.

    self filterField entryCompletionBlock:
    (filterCompletionBlock := [:value|
        |filter filters i changesCopy|
        self unselectChange.
        filter := self filterField contents.
        (filters := filter asArrayOfSubstrings) size > 0 ifTrue: 
        [
            i := 0.
            changesCopy := changes copy.
            filters do: 
            [:filter|
                i := i + 1.
                changesCopy contents: 
                    (changesCopy select: [:row| 
                        filter match: (row string asArrayOfSubstrings at: i ifAbsent: [''''])])
            ].            
            self listOfChanges contents: changesCopy
        ] 
        ifFalse: 
        [
            self listOfChanges contents: changes
        ].
        self autoSelectLast.
    ]).

    Object errorSignal handle: [:ex |
        ex parameter signal == HaltSignal ifTrue:[
            ex reject
        ].
        ex parameter signal == MessageTracer breakpointSignal ifTrue:[
            ex reject
        ].
        self warn:'Error while reading changes file:\\' , ex errorString.
    ] do: [
        self readChangesFileInBackground:true
    ].

    "Modified: / 30.7.1998 / 11:37:51 / cg"
!

uninitialize
    "removes the autoUpdateBlock from the Processor and myself from the ObjectMemory"

    Processor removeTimedBlock:autoUpdateBlock.
    ObjectMemory removeDependent:self
! !

!NewChangesBrowser methodsFor:'user actions'!

doApply
    "applies the selected change"

    self withSelectedChangeDo:[:change|
        skipSignal := nil.
        self applyChange:change.
        self autoSelectChange: (self listOfChanges at: (self listOfChanges indexOf: change) + 1 ifAbsent: [^self autoSelectLast])
    ]
!

doApplyAll
    "applies all changes"

    self withExecuteCursorDo:[
        |change|
        self unselectChange.
        skipSignal isNil ifTrue:[skipSignal := Signal new].
        1 to:self listOfChanges size do:[:changeNr |
            self selectionOfChange value:(change := self listOfChanges at: changeNr).
            self applyChange:change
        ].
        self autoSelectLast
    ]

!

doApplyAllForClass
    "applies all changes having the same class like the selected one"

    self doApplyForClassToEndFrom: 1


!

doApplyForClassToEnd
    "applies all changes having the same class like the selected one from the selected to the end"

    self doApplyForClassToEndFrom: (self listOfChanges indexOf: self selectionOfChange value)
!

doApplyForClassToEndFrom: start
    "applies changes with same class like the selected one from start to end"

    self withSelectedChangeDo:[:change|
        |classNameToApply thisClassName lastChange change2|
        (classNameToApply := self classNameOfChange:change) notNil 
        ifTrue:
        [             
            self unselectChange.
            skipSignal isNil ifTrue:[skipSignal := Signal new].
            start to:self listOfChanges size do:
            [:changeNr|
                change2 := self listOfChanges at: changeNr.
                ((thisClassName := self classNameOfChange:change2) notNil and:
                [thisClassName = classNameToApply or:
                [PrivateAsSeparate not and: [(thisClassName upTo: $:) = classNameToApply]]])
                ifTrue:
                [                           
                    self selectionOfChange value: change2.
                    self applyChange:change2.
                    lastChange := change2
                ]
            ].
            self autoSelectChange:lastChange.
        ]
    ]

!

doApplyFromLastSnapshot
    "applies all changes made since the last snapshot"

    self autoSelectLast.
    (self doFindSnapshot: 'last') ifTrue: [self doApplyToEnd]
!

doApplyToEnd
    "applies all changes from selected one to be end"

    self withSelectedChangeDo:[:change|
        self unselectChange.
        skipSignal isNil ifTrue:[skipSignal := Signal new].
        (self listOfChanges indexOf: change) to: self listOfChanges size do:[:changeNr|
            self selectionOfChange value:(self listOfChanges at: changeNr).
            self applyChange:(self listOfChanges at: changeNr)
        ].
        self autoSelectChange:self listOfChanges last
    ]

!

doBrowseClass
    "opens a System Browser on the class of a change (and selector)"

    |className cls isMeta|

    className := self fullClassNameOfChange:self selectionOfChange value.
    className notNil ifTrue:[
        isMeta := false.
        (className endsWith:' class') ifTrue:[
            className := className copyWithoutLast:6.
            isMeta := true.
        ].
        (cls := Smalltalk classNamed:className) notNil ifTrue:[
            isMeta ifTrue:[cls := cls class].
            SystemBrowser 
                openInClass:cls 
                selector:(self selectorOfMethodChange:self selectionOfChange value)
        ]
    ]



!

doCompare
    "compares a change with the current system version"

    |change|

    (change := self selectionOfChange value) notNil ifTrue:[
        self withExecuteCursorDo:[self compareChange:change]
    ].
    self newLabel:''
!

doCompress
    "compresses the changes, i.e. replaces multiple changes by the last change"

    |changesSizeBefore|
    (changesSizeBefore := changes size) == 0 ifTrue: [^self warn: 'Nothing to compress!!'].
    self setChangeList.
    self unselectChange.
    self compressForClass:nil.
    self setChangeList.    
    self updateInfoLabel.

    self information: 
        'Compression Rate:   ', (((changesSizeBefore - changes size)/changesSizeBefore) * 100) rounded printString, '%\' withCRs,
        'Obsolete Changes: ', (changesSizeBefore - changes size) printString, ' from ', changesSizeBefore printString




!

doCompressForClass
    "compresses changes for the selected class.
     this replaces multiple method-changes by the last (i.e. the most recent) change."

    self withSelectedChangeDo:[:change|
        | classNameToCompress |

        (classNameToCompress := self classNameOfChange:change) notNil ifTrue:[
            self compressForClass:classNameToCompress.
            filterCompletionBlock value: self valueOfFilter value.
            self autoSelectLast
        ]
    ]

!

doDelete
    "deletes the selected change"

    |change selectionIndex|

    (change := self selectionOfChange value) notNil ifTrue:[
        selectionIndex := self listOfChanges indexOf: change.
        self unselectChange.
        self silentDeleteChange:change.
        self listOfChanges remove:change.
        self autoSelectOrEnd: (self listOfChanges at: selectionIndex ifAbsent: [nil]).
    ]
!

doDeleteAll
    "deletes all changes"

    self deleteChangesFrom:1 to: self listOfChanges size.
    self autoSelectOrEnd: nil

!

doDeleteAllForClass
    "deletes all changes having the same class like the selected one"

    self doDeleteForClassToEndFrom: 1

!

doDeleteForClassToEnd
    "deletes all changes having the same class like the selected one from the selected to the end"

    self withSelectedChangeDo:[:change|
        self doDeleteForClassToEndFrom: (self listOfChanges indexOf: change)
    ]


!

doDeleteForClassToEndFrom: start
    "deletes changes with same class like the selected one from start to end"

    self withSelectedChangeDo:[:change|
        |classNameToDelete|
        (classNameToDelete := self classNameOfChange:change) notNil ifTrue:[
            self unselectChange.
            self silentDeleteChangesFor:classNameToDelete 
                                   from:start
                                     to:self listOfChanges size.
            self setChangeList.
            self autoSelectOrEnd: nil
        ]
    ].



!

doDeleteToEnd
    "deletes all changes from selected one to be end"

    |changeNr|

    changeNr := (self listOfChanges indexOf: self selectionOfChange value).
    changeNr ~~ 0 ifTrue:[
        self deleteChangesFrom:changeNr to: self listOfChanges size.
        self unselectChange.
        self autoSelectOrEnd: nil
    ]

!

doFilter: aFilterString
    "filter the changes with aFilterString"

    self selectionOfChange value: nil.
    self valueOfFilter value: aFilterString withoutNotifying: self.
    self valueOfFilter changed.
    self autoSelectLast
!

doFilterSourceType: aFilterStringTypeString
    "filter the source changes with aFilterStringTypeString"

    self selectionOfChange value: nil.
    self listOfChanges contents: #().
    self valueOfFilter value: '' withoutNotifying: self.
    self listOfChanges contents: (changes select: [:change| change type = 'source' and: [aFilterStringTypeString match: change string]]).
    self autoSelectLast

!

doFilterType: aFilterTypeString
    "filter the changes with aFilterTypeString"

    self selectionOfChange value: nil.
    self valueOfFilter value: '' withoutNotifying: self.
    self listOfChanges contents: (changes select: [:change| change type = aFilterTypeString]).
    self autoSelectLast

!

doFindSnapshot: what
    "finds the last made snapshot and selects it"

    |snapshotNr snapshotFound|

    self listOfChanges detect: [:change| change type = 'image'] ifNone: [^self warn: 'No snapshot found!!'].

    self withSelectedChangeDo:[:change|
        snapshotNr := self listOfChanges indexOf: change.
        snapshotFound := false.
        [snapshotNr > 0 and: [snapshotFound not]] 
        whileTrue: 
        [
            what = 'last'
            ifTrue:
            [
                snapshotNr := snapshotNr - 1.
                snapshotNr == 0 ifTrue: [snapshotNr := self listOfChanges size].   
            ]
            ifFalse:
            [
                snapshotNr := snapshotNr + 1.
                snapshotNr > self listOfChanges size ifTrue: [snapshotNr := 1].
            ].
            (self listOfChanges at: snapshotNr ifAbsent: [^self autoSelectChange: (what = 'last' ifTrue: [self listOfChanges last] ifFalse: [self listOfChanges first])]) type = 'image'
            ifTrue: 
            [
                snapshotFound := true.
                self autoSelectChange:(self listOfChanges at: snapshotNr)
            ]
        ]
    ].

    ^snapshotFound
!

doLoad
    "opens a dialog for loading changes from a file"

    |fileName|
    (fileName :=
        (FileSelectionBrowser
            request: 'Load Changes List'
            fileName: changeFileName
            withFileFilters: #('c*'))) notNil
    ifTrue:
    [
        changeFileName := fileName.
        changes removeAll.
        self readChangesFileInBackground:true.
        self unselectChange.
        Processor addTimedBlock:autoUpdateBlock afterSeconds:5.
        self updateInfoLabel.
        self autoSelectLast
    ]
!

doReload
    "reloads the changes from the file"

    changes removeAll.
    self unselectChange.
    self readChangesFileInBackground:true.
    self autoSelectLast

!

doSave
    "write back the changes file. To avoid problems when the disk is full
     or a crash occurs while writing (well, or someone kills us), 
     first write the stuff to a new temporary file. If this works ok,
     rename the old change-file to a .bak file and finally rename the
     tempfile back to the change-file. 
     That way, if anything happens, either the original file is left unchanged,
     or we have at least a backup of the previous change file."

    |inStream outStream tempfile stamp f| 

    self valueOfNotReading value ifFalse: [^nil].

    editingClassSource ifTrue:[
        (self confirm:'You are editing a classes sourceFile (not a changeFile) !!\Are you certain, you want to overwrite it ?' withCRs)
        ifFalse:[
            ^ false
        ]
    ].

    tempfile := Filename newTemporaryIn:nil.
    tempfile exists ifTrue:[tempfile remove].

    outStream := tempfile writeStream.
    outStream isNil ifTrue:[
        self warn:'Cannot create temporary file in current directory.'.
        ^ false
    ].

    inStream := FileStream readonlyFileNamed:changeFileName.
    inStream isNil ifTrue:[^ false].

    self withCursor:(Cursor write) do:[
        |excla sawExcla done first chunk
         nChanges "{Class:SmallInteger}" |

        Stream writeErrorSignal handle:[:ex |
            self warn:('Could not update the changes file.\\' , ex errorString) withCRs.
            ^ false
        ] do:[

            self valueOfNotSaving value: false.

            excla := inStream class chunkSeparator.
            nChanges := changes size.

            1 to:nChanges do:[:index |     
                inStream position: (changes at: index) position.
                sawExcla := inStream peekFor:excla.
                chunk := inStream nextChunk.

                (chunk notNil
                and:[(chunk startsWith:'''---- snap') not]) ifTrue:[
                    (stamp := (changes at:index) timeStamp) notNil ifTrue:[
                        outStream nextPutAll:'''---- timestamp ' , stamp , ' ----'''.
                        outStream nextPut:excla; cr.
                    ].
                ].

                sawExcla ifTrue:[     
                    outStream nextPut:excla.   
                    outStream nextChunkPut:chunk.
                    outStream cr; cr.

                    "
                     a method-definition chunk - skip followups
                    "
                    done := false.
                    first := true.
                    [done] whileFalse:[
                        chunk := inStream nextChunk.
                        chunk isNil ifTrue:[
                            outStream cr; cr.
                            done := true
                        ] ifFalse:[
                            chunk isEmpty ifTrue:[
                                outStream space; nextChunkPut:chunk; cr; cr.
                                done := true.
                            ] ifFalse:[
                                first ifFalse:[
                                    outStream cr; cr.
                                ].
                                outStream nextChunkPut:chunk.
                            ].
                        ].
                        first := false.
                    ].
                ] ifFalse:[
                    outStream nextChunkPut:chunk.
                    outStream cr
                ]
            ].
            outStream close.
            inStream close.
        ].

        f := changeFileName asFilename.
        f renameTo:(f withSuffix:'bak').
        tempfile renameTo:changeFileName.
        self doReload.
        modified := false.
        self valueOfNotSaving value: true.
    ].
    ^ true


! !

!NewChangesBrowser::Change methodsFor:'accessing'!

category

    ^category
!

category: aValue

    category := aValue
!

chunk

    ^chunk
!

chunk: aValue

    chunk := aValue
!

className

    ^className
!

className: aValue

    className := aValue
!

delta
    |cls|

    delta size = 0 ifTrue: [^''].
    delta = '='    ifTrue: [^'Current'].
    delta = '?'    ifTrue: [
        (className notNil and:[className knownAsSymbol]) ifTrue:[
            (cls := Smalltalk at:className asSymbol ifAbsent:nil) notNil ifTrue:[
                cls isBehavior ifTrue:[
                    cls isLoaded ifFalse:[
                        ^ 'Not loaded'
                    ]
                ]
            ]
        ].
        ^'No class'
    ].
    delta = '-'    ifTrue: [^'Remove'].
    delta = '+'    ifTrue: [^'New'].
    ^delta

    "Modified: / 29.7.1998 / 23:08:10 / cg"
!

delta: aValue

    delta := aValue
!

followUp

    ^followUp
!

followUp: aValue

    followUp := aValue
!

lastPosition: aValue

    lastPosition := aValue
!

listColor

    (string at: 3) ~~ $- ifTrue: 
    [
        (self type = 'class') ifTrue: [^Color gray].
        ^Color white
    ].

    (string includesMatchString: '---- s') ifTrue: [^Color red].
    (string includesMatchString: '---- f') ifTrue: [^Color cyan: 100 magenta: 20 yellow: 20].
    (string includesMatchString: '---- c') ifTrue: [^Color blue].

    ^Color white
!

position

    ^position
!

position: aValue

    position := aValue
!

positions

    ^position printString, ' - ', lastPosition printString
!

string

    ^string
!

string: aValue

    string := aValue
!

timeStamp

    ^timeStamp
!

timeStamp: aValue

    timeStamp := aValue
!

type

    (type = 'doIt' or: [type = 'remove']) ifTrue: [^'class'].
    (type size = 0) ifTrue: [(string includesMatchString: '---- s') ifTrue: [^'image'] ifFalse: [^'source']].
    (self category = nil) ifTrue: [^'class'].
    ^'method'
!

type: aValue

    type := aValue
! !

!NewChangesBrowser class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libtool/NewChangesBrowser.st,v 1.21 1998-09-15 08:50:03 tz Exp $'
! !