initial checkin draft
authorClaus Gittinger <cg@exept.de>
Mon, 08 Jul 2019 01:37:03 +0200
changeset 3676 319c68f831df
parent 3675 caafc519b235
child 3677 b2fe15814f14
initial checkin
FileVersionDiffBrowser.st
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileVersionDiffBrowser.st	Mon Jul 08 01:37:03 2019 +0200
@@ -0,0 +1,1701 @@
+"
+ COPYRIGHT (c) 2019 by eXept Software AG
+              All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+"{ Package: 'stx:libtool2' }"
+
+"{ NameSpace: Smalltalk }"
+
+ApplicationModel subclass:#FileVersionDiffBrowser
+	instanceVariableNames:'diffTextView diffTextLabelA diffTextLabelB versionAHolder
+		versionBHolder infoHolder isMultipleVersionBrowser
+		versionInfoList versionList versionEntriesList
+		selectedVersionHolder symbolicVersionList symbolicVersionNameList
+		selectedSymbolicVersionHolder selectedSymbolicVersionIndexHolder
+		symbolicToVersionMapping selectedVersionIndexHolder
+		isMultipleFilesVersionBrowser fileListHolder
+		selectedFileIndexHolder fileHolder diffTextHolder
+		versionAIfSingleFileDiff versionBIfSingleFileDiff
+		fileIfSingleFileDiff'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'Interface-Tools-File'
+!
+
+!FileVersionDiffBrowser class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 2019 by eXept Software AG
+              All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+!
+
+documentation
+"
+    A quickly hacked up browser to show differences between file versions,
+    allowing easy comparison; will also eventually add capabilities
+    to checkIn / load files into / from the repository.
+
+    [usages:]
+        FileVersionDiffBrowser openOnAllVersionsOfFile:'Make.proto'.
+        FileVersionDiffBrowser openOnAllFilesChangedSince:(Date today - 7 days) in:('../../libbasic' asFilename).
+        
+    [see also:]
+
+    [instance variables:]
+
+    [class variables:]
+"
+! !
+
+!FileVersionDiffBrowser 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:FileVersionDiffBrowser andSelector:#windowSpec
+     FileVersionDiffBrowser new openInterface:#windowSpec
+     FileVersionDiffBrowser open
+    "
+
+    <resource: #canvas>
+
+    ^ 
+    #(FullSpec
+       name: windowSpec
+       uuid: '34d3baee-a108-11e9-a652-b8f6b1108e05'
+       window: 
+      (WindowSpec
+         label: 'Version DiffBrowser'
+         name: 'Version DiffBrowser'
+         uuid: '90e45e00-7175-11e9-a23a-b8f6b1108e05'
+         min: (Point 10 10)
+         bounds: (Rectangle 0 0 865 504)
+         menu: mainMenu
+       )
+       component: 
+      (SpecCollection
+         collection: (
+          (VariableVerticalPanelSpec
+             name: 'VariableVerticalPanel1'
+             layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 -25 1.0)
+             uuid: '90e460c6-7175-11e9-a23a-b8f6b1108e05'
+             component: 
+            (SpecCollection
+               collection: (
+                (ViewSpec
+                   name: 'DiffOrSingleMethodCodeBox'
+                   uuid: '90e471a6-7175-11e9-a23a-b8f6b1108e05'
+                   component: 
+                  (SpecCollection
+                     collection: (
+                      (ViewSpec
+                         name: 'diffTextViewBox'
+                         layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+                         uuid: '90e47264-7175-11e9-a23a-b8f6b1108e05'
+                         component: 
+                        (SpecCollection
+                           collection: (
+                            (LabelSpec
+                               label: 'A'
+                               name: 'DiffTextLabelA'
+                               layout: (LayoutFrame 0 0 0 0 0 0.5 20 0)
+                               uuid: '90e47318-7175-11e9-a23a-b8f6b1108e05'
+                               translateLabel: true
+                               labelChannel: diffTextLabelA
+                             )
+                            (LabelSpec
+                               label: 'B'
+                               name: 'DiffTextLabelB'
+                               layout: (LayoutFrame 0 0.5 0 0 0 1 20 0)
+                               uuid: '90e47412-7175-11e9-a23a-b8f6b1108e05'
+                               translateLabel: true
+                               labelChannel: diffTextLabelB
+                             )
+                            (ArbitraryComponentSpec
+                               name: 'diffTextView'
+                               layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 0 1.0)
+                               uuid: '90e47502-7175-11e9-a23a-b8f6b1108e05'
+                               hasBorder: false
+                               component: diffTextView
+                             )
+                            )
+                          
+                         )
+                       )
+                      )
+                    
+                   )
+                 )
+                )
+              
+             )
+             handles: (Any 1.0)
+           )
+          (LabelSpec
+             name: 'InfoLabel'
+             layout: (LayoutFrame 0 0 -25 1 0 1 0 1)
+             uuid: '90e47868-7175-11e9-a23a-b8f6b1108e05'
+             level: -1
+             translateLabel: true
+             labelChannel: infoHolder
+             adjust: left
+           )
+          )
+        
+       )
+     )
+!
+
+windowSpecForMultipleFiles
+    "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:FileVersionDiffBrowser andSelector:#windowSpecForMultipleFiles
+     FileVersionDiffBrowser new openInterface:#windowSpecForMultipleFiles
+    "
+
+    <resource: #canvas>
+
+    ^ 
+    #(FullSpec
+       name: windowSpecForMultipleFiles
+       uuid: '3c5c60f4-a108-11e9-a652-b8f6b1108e05'
+       window: 
+      (WindowSpec
+         label: 'Version DiffBrowser'
+         name: 'Version DiffBrowser'
+         uuid: '2b3f2546-d4fd-11e7-af82-c42c033b4871'
+         min: (Point 10 10)
+         bounds: (Rectangle 0 0 865 504)
+         menu: mainMenu
+       )
+       component: 
+      (SpecCollection
+         collection: (
+          (VariableVerticalPanelSpec
+             name: 'VariableVerticalPanel1'
+             layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 -25 1.0)
+             uuid: '2b3f297e-d4fd-11e7-af82-c42c033b4871'
+             component: 
+            (SpecCollection
+               collection: (
+                (VariableHorizontalPanelSpec
+                   name: 'FileAndVersionAndTagPanel'
+                   uuid: '17c6805c-7184-11e9-a23a-b8f6b1108e05'
+                   component: 
+                  (SpecCollection
+                     collection: (
+                      (SequenceViewSpec
+                         name: 'List2'
+                         uuid: '2b3f2d20-d4fd-11e7-af82-c42c033b4871'
+                         model: selectedFileIndexHolder
+                         menu: fileListMenu
+                         hasHorizontalScrollBar: true
+                         hasVerticalScrollBar: true
+                         useIndex: true
+                         sequenceList: fileNameListHolder
+                       )
+                      (VariableHorizontalPanelSpec
+                         name: 'VersionAndTagPanel'
+                         uuid: '2b3f2c08-d4fd-11e7-af82-c42c033b4871'
+                         component: 
+                        (SpecCollection
+                           collection: (
+                            (SequenceViewSpec
+                               name: 'VersionList'
+                               uuid: '2b3f2d20-d4fd-11e7-af82-c42c033b4871'
+                               model: selectedVersionIndexHolder
+                               menu: versionsMenu
+                               hasHorizontalScrollBar: true
+                               hasVerticalScrollBar: true
+                               useIndex: true
+                               sequenceList: versionEntriesList
+                             )
+                            (SequenceViewSpec
+                               name: 'List1'
+                               uuid: '2b3f3086-d4fd-11e7-af82-c42c033b4871'
+                               model: selectedSymbolicVersionIndexHolder
+                               menu: symbolicVersionsMenu
+                               hasHorizontalScrollBar: true
+                               hasVerticalScrollBar: true
+                               useIndex: true
+                               sequenceList: symbolicVersionNameList
+                             )
+                            )
+                          
+                         )
+                         handles: (Any 0.5 1.0)
+                       )
+                      )
+                    
+                   )
+                   handles: (Any 0.5 1.0)
+                 )
+                (ViewSpec
+                   name: 'DiffBox'
+                   uuid: '2b3f408a-d4fd-11e7-af82-c42c033b4871'
+                   component: 
+                  (SpecCollection
+                     collection: (
+                      (ViewSpec
+                         name: 'diffTextViewBox'
+                         layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+                         uuid: '2b3f415c-d4fd-11e7-af82-c42c033b4871'
+                         component: 
+                        (SpecCollection
+                           collection: (
+                            (LabelSpec
+                               label: 'A'
+                               name: 'DiffTextLabelA'
+                               layout: (LayoutFrame 0 0 0 0 0 0.5 20 0)
+                               uuid: '2b3f426a-d4fd-11e7-af82-c42c033b4871'
+                               translateLabel: true
+                               labelChannel: diffTextLabelA
+                             )
+                            (LabelSpec
+                               label: 'B'
+                               name: 'DiffTextLabelB'
+                               layout: (LayoutFrame 0 0.5 0 0 0 1 20 0)
+                               uuid: '2b3f43d2-d4fd-11e7-af82-c42c033b4871'
+                               translateLabel: true
+                               labelChannel: diffTextLabelB
+                             )
+                            (ArbitraryComponentSpec
+                               name: 'diffTextView'
+                               layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 0 1.0)
+                               uuid: '2b3f4508-d4fd-11e7-af82-c42c033b4871'
+                               hasBorder: false
+                               component: diffTextView
+                             )
+                            )
+                          
+                         )
+                       )
+                      )
+                    
+                   )
+                 )
+                )
+              
+             )
+             handles: (Any 0.5 1.0)
+           )
+          (LabelSpec
+             name: 'InfoLabel'
+             layout: (LayoutFrame 0 0 -25 1 0 1 0 1)
+             uuid: '2b3f4a44-d4fd-11e7-af82-c42c033b4871'
+             level: -1
+             translateLabel: true
+             labelChannel: infoHolder
+             adjust: left
+           )
+          )
+        
+       )
+     )
+!
+
+windowSpecForMultipleVersions
+    "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:FileVersionDiffBrowser andSelector:#windowSpecForMultipleVersions
+     FileVersionDiffBrowser new openInterface:#windowSpecForMultipleVersions
+    "
+
+    <resource: #canvas>
+
+    ^ 
+    #(FullSpec
+       name: windowSpecForMultipleVersions
+       uuid: '441c0448-a108-11e9-a652-b8f6b1108e05'
+       window: 
+      (WindowSpec
+         label: 'Version DiffBrowser'
+         name: 'Version DiffBrowser'
+         uuid: '2b3f2546-d4fd-11e7-af82-c42c033b4871'
+         min: (Point 10 10)
+         bounds: (Rectangle 0 0 865 504)
+         menu: mainMenu
+       )
+       component: 
+      (SpecCollection
+         collection: (
+          (VariableVerticalPanelSpec
+             name: 'VariableVerticalPanel1'
+             layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 -25 1.0)
+             uuid: '2b3f297e-d4fd-11e7-af82-c42c033b4871'
+             component: 
+            (SpecCollection
+               collection: (
+                (VariableHorizontalPanelSpec
+                   name: 'VersionAndTagBox'
+                   uuid: '2b3f2c08-d4fd-11e7-af82-c42c033b4871'
+                   component: 
+                  (SpecCollection
+                     collection: (
+                      (SequenceViewSpec
+                         name: 'VersionList'
+                         uuid: '2b3f2d20-d4fd-11e7-af82-c42c033b4871'
+                         model: selectedVersionIndexHolder
+                         menu: versionsMenu
+                         hasHorizontalScrollBar: true
+                         hasVerticalScrollBar: true
+                         useIndex: true
+                         sequenceList: versionEntriesList
+                       )
+                      (SequenceViewSpec
+                         name: 'List1'
+                         uuid: '2b3f3086-d4fd-11e7-af82-c42c033b4871'
+                         model: selectedSymbolicVersionIndexHolder
+                         menu: symbolicVersionsMenu
+                         hasHorizontalScrollBar: true
+                         hasVerticalScrollBar: true
+                         useIndex: true
+                         sequenceList: symbolicVersionNameList
+                       )
+                      )
+                    
+                   )
+                   handles: (Any 0.5 1.0)
+                 )
+                (ViewSpec
+                   name: 'DiffBox'
+                   uuid: '2b3f408a-d4fd-11e7-af82-c42c033b4871'
+                   component: 
+                  (SpecCollection
+                     collection: (
+                      (ViewSpec
+                         name: 'diffTextViewBox'
+                         layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+                         uuid: '2b3f415c-d4fd-11e7-af82-c42c033b4871'
+                         component: 
+                        (SpecCollection
+                           collection: (
+                            (LabelSpec
+                               label: 'A'
+                               name: 'DiffTextLabelA'
+                               layout: (LayoutFrame 0 0 0 0 0 0.5 20 0)
+                               uuid: '2b3f426a-d4fd-11e7-af82-c42c033b4871'
+                               translateLabel: true
+                               labelChannel: diffTextLabelA
+                             )
+                            (LabelSpec
+                               label: 'B'
+                               name: 'DiffTextLabelB'
+                               layout: (LayoutFrame 0 0.5 0 0 0 1 20 0)
+                               uuid: '2b3f43d2-d4fd-11e7-af82-c42c033b4871'
+                               translateLabel: true
+                               labelChannel: diffTextLabelB
+                             )
+                            (ArbitraryComponentSpec
+                               name: 'diffTextView'
+                               layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 0 1.0)
+                               uuid: '2b3f4508-d4fd-11e7-af82-c42c033b4871'
+                               hasBorder: false
+                               component: diffTextView
+                             )
+                            )
+                          
+                         )
+                       )
+                      )
+                    
+                   )
+                 )
+                )
+              
+             )
+             handles: (Any 0.5 1.0)
+           )
+          (LabelSpec
+             name: 'InfoLabel'
+             layout: (LayoutFrame 0 0 -25 1 0 1 0 1)
+             uuid: '2b3f4a44-d4fd-11e7-af82-c42c033b4871'
+             level: -1
+             translateLabel: true
+             labelChannel: infoHolder
+             adjust: left
+           )
+          )
+        
+       )
+     )
+! !
+
+!FileVersionDiffBrowser class methodsFor:'menu specs'!
+
+mainMenu
+    "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:FileVersionDiffBrowser andSelector:#mainMenu
+     (Menu new fromLiteralArrayEncoding:(FileVersionDiffBrowser mainMenu)) startUp
+    "
+
+    <resource: #menu>
+
+    ^ 
+     #(Menu
+        (
+         (MenuItem
+            label: 'File'
+            submenu: 
+           (Menu
+              (
+               (MenuItem
+                  label: 'Create PatchFile...'
+                  itemValue: createPatchFile
+                )
+               (MenuItem
+                  label: '-'
+                )
+               (MenuItem
+                  label: 'Exit'
+                  itemValue: closeRequest
+                )
+               )
+              nil
+              nil
+            )
+          )
+         (MenuItem
+            label: 'View'
+            submenuChannel: viewMenu
+          )
+         (MenuItem
+            label: 'MENU_Help'
+            startGroup: conditionalRight
+            submenu: 
+           (Menu
+              (
+               (MenuItem
+                  label: 'Documentation'
+                  itemValue: openDocumentation
+                )
+               (MenuItem
+                  label: '-'
+                )
+               (MenuItem
+                  label: 'About this Application...'
+                  itemValue: openAboutThisApplication
+                )
+               )
+              nil
+              nil
+            )
+          )
+         )
+        nil
+        nil
+      )
+!
+
+versionsMenu
+    "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:VersionDiffBrowser andSelector:#mainMenu
+     (Menu new fromLiteralArrayEncoding:(VersionDiffBrowser mainMenu)) startUp
+    "
+
+    <resource: #menu>
+
+    ^ 
+     #(Menu
+              (
+               (MenuItem
+                  label: 'Compare against Previous (Older) Version'
+                  nameKey: CompareAgainstPreviousVersion
+                  itemValue: versionMenuCompareAgainstPreviousVersion
+                  enabled: hasPreviousVersionInVersionList
+                )
+               (MenuItem
+                  label: 'Compare against Next (Younger) Version'
+                  nameKey: CompareAgainstNextVersion
+                  itemValue: versionMenuCompareAgainstNextVersion
+                  enabled: hasNextVersionInVersionList
+                )
+
+               )
+              nil
+              nil
+            )
+
+    "Created: / 05-02-2017 / 11:11:30 / cg"
+    "Modified: / 06-02-2017 / 09:27:22 / cg"
+!
+
+viewMenu
+    "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:FileVersionDiffBrowser andSelector:#viewMenu
+     (Menu new fromLiteralArrayEncoding:(FileVersionDiffBrowser viewMenu)) startUp
+    "
+
+    <resource: #menu>
+
+    ^ 
+     #(Menu
+        (
+         (MenuItem
+            label: 'Show Log Messages'
+            itemValue: showLogMessages
+          )
+         )
+        nil
+        nil
+      )
+! !
+
+!FileVersionDiffBrowser class methodsFor:'startup'!
+
+openOnAllFilesChangedSince:aDateOrTimestamp in:aSetOfFilesOrADirectoryFilename
+    "create a FileVersionDiffBrowser instance and set the list of files.
+     When a file is selected, the version list is extracted,
+     and the diff list is generated from the file's current version against
+     the selected version in the top selection list"
+
+    |setOfFiles theBrowser filesChangedSince sinceTimestamp|
+
+    sinceTimestamp := aDateOrTimestamp asTimestamp.
+
+    setOfFiles := aSetOfFilesOrADirectoryFilename.
+    setOfFiles isFilename ifTrue:[
+        setOfFiles := setOfFiles directoryContentsAsFilenames.
+    ].
+    
+    filesChangedSince := setOfFiles 
+        select:[:fn | fn modificationTime > sinceTimestamp].
+    filesChangedSince sort:[:a :b | a name < b name].
+    
+    theBrowser := self new.
+    theBrowser allButOpenInterface:#windowSpecForMultipleFiles.
+    theBrowser beMultipleFilesVersionBrowser.
+    theBrowser fileList:filesChangedSince.
+    
+    "/ theBrowser classHolder:(ValueHolder with:aClass).
+    "/ theBrowser setupForClass:aClass againstVersion:nil.
+    theBrowser window label:(self resources string:'Versions of %1 files' with:setOfFiles size).
+    theBrowser openWindow.
+    ^ theBrowser.
+
+    "
+     FileVersionDiffBrowser 
+        openOnAllFilesChangedSince:(Date today - 7 days) 
+        in:('../../libbasic' asFilename files).
+    "
+
+    "Created: / 07-07-2019 / 18:58:01 / Claus Gittinger"
+    "Modified: / 08-07-2019 / 01:36:01 / Claus Gittinger"
+!
+
+openOnAllVersionsOfFile:aFilename
+    "create a VersionDiffBrowser instance and set the file. 
+     The diff is generated from aFilename's current version against
+     the selected version in the top selection list"
+
+    |theBrowser|
+
+    theBrowser := self new.
+    theBrowser allButOpenInterface:#windowSpecForMultipleVersions.
+    theBrowser beMultipleVersionBrowser.
+    theBrowser fileHolder value:aFilename.
+    theBrowser setupForAllVersionsOfFile:aFilename.
+    theBrowser window label:(self resources string:'Versions of %1' with:aFilename baseName).
+    theBrowser openWindow.
+    ^ theBrowser.
+
+    "
+     self openOnAllVersionsOfFile:'Make.proto' asFilename
+     self openOnAllVersionsOfFile:'../../libbasic/Array.st' asFilename
+    "
+
+    "Created: / 07-07-2019 / 19:26:28 / Claus Gittinger"
+    "Modified: / 07-07-2019 / 22:40:38 / Claus Gittinger"
+    "Modified (comment): / 08-07-2019 / 01:27:03 / Claus Gittinger"
+!
+
+openOnAllVersionsOfFiles:aSetOfFilenames
+    "create a VersionDiffBrowser instance and set the list of files.
+     When a file is selected, the version list is extracted,
+     and the diff set is generated from the file's current version against
+     the selected version in the top selection list"
+
+    |theBrowser|
+
+    theBrowser := self new.
+    theBrowser allButOpenInterface:#windowSpecForMultipleFiles.
+    theBrowser beMultipleFilesVersionBrowser.
+    theBrowser beMultipleVersionBrowser.
+    theBrowser fileList:(aSetOfFilenames collect:#asFilename).
+    theBrowser window label:(self resources string:'Versions of %1 files' with:aSetOfFilenames size).
+    theBrowser openWindow.
+    ^ theBrowser.
+
+    "
+     self openOnAllVersionsOfFiles:#('Make.proto' 'Make.spec')
+    "
+
+    "Created: / 07-07-2019 / 19:29:38 / Claus Gittinger"
+    "Modified: / 08-07-2019 / 00:30:31 / Claus Gittinger"
+!
+
+openOnFile:aFilename againstVersion:aVersionA
+    "create a VersionDiffBrowser instance and set the diffs of the
+     browser. The diffs are generated from aFilename's current against some version
+     via the source code manager."
+
+    |theBrowser fn|
+
+    fn := aFilename asFilename.
+    theBrowser := self new.
+    theBrowser allButOpen.
+    theBrowser setupForFile:fn againstVersion:aVersionA.
+    theBrowser window label:(self resources string:'Diffs of %1 %2 against current' with:fn baseName with:aVersionA).
+    theBrowser openWindow.
+    ^ theBrowser.
+
+    "
+     self openOnFile:'Make.proto' againstVersion:'1.2'
+     self openOnFile:'Make.proto' againstVersion:#newest        - against the newest repository version
+    "
+
+    "Created: / 07-07-2019 / 19:31:13 / Claus Gittinger"
+    "Modified: / 08-07-2019 / 00:42:22 / Claus Gittinger"
+!
+
+openOnFile:file1 andFile:file2
+    |fn1 fn2|
+    
+    fn1 := file1 asFilename.
+    fn2 := file2 asFilename.
+    ^ self 
+        openOnFile:fn1 labelA:fn1 baseName andFile:fn2 labelB:fn2 baseName 
+        title:(self resources string:'%1 vs. %2' 
+                                with:fn1 baseName with:fn2 baseName)
+        ifSame:nil
+
+    "
+     FileVersionDiffBrowser
+        openOnFile:'../../libbasic/FloatArray.st'
+        andFile:'../../libbasic/DoubleArray.st'
+    "
+
+    "Created: / 08-07-2019 / 00:52:18 / Claus Gittinger"
+!
+
+openOnFile:fileA labelA:aLabelA andFile:fileB labelB:aLabelB title:title
+    "create a VersionDiffBrowser instance and set the difflist of the
+     browser. The diffs are generated from two files."
+
+    ^ self
+        openOnFile:fileA labelA:aLabelA
+        andFile:fileB labelB:aLabelB
+        title:title ifSame:nil
+
+    "
+     self
+        openOnFile:'../../libbasic/FloatArray.st' labelA:'FloatArray'
+        andFile:'../../libbasic/DoubleArray.st' labelB:'DoubleArray'
+        title:'FloatArray vs. DoubleArray'
+    "
+
+    "Created: / 07-07-2019 / 19:32:07 / Claus Gittinger"
+    "Modified (comment): / 08-07-2019 / 00:37:50 / Claus Gittinger"
+!
+
+openOnFile:fileA labelA:aLabelA andFile:fileB labelB:aLabelB title:title ifSame:sameAction
+    "create a VersionDiffBrowser instance and set the class change set of the
+     browser. The class diff set is generated from two classes."
+
+    |theBrowser fn1 fn2|
+
+    fn1 := fileA asFilename.
+    fn2 := fileB asFilename.
+    
+    theBrowser := self new.
+    theBrowser allButOpen.
+    theBrowser setupForFile:fn1 labelA:aLabelA andFile:fn2 labelB:aLabelB.
+    theBrowser window label:title.
+    theBrowser openWindow.
+    ^ theBrowser.
+
+    "
+     FileVersionDiffBrowser
+        openOnFile:'../../libbasic/FloatArray.st' labelA:'FloatArray'
+        andFile:'../../libbasic/DoubleArray.st' labelB:'DoubleArray'
+        title:'Some diffs' ifSame:nil
+    "
+
+    "Created: / 07-07-2019 / 20:05:16 / Claus Gittinger"
+    "Modified (comment): / 08-07-2019 / 00:51:29 / Claus Gittinger"
+!
+
+openOnFile:aFilename versionA:versionA versionB:versionB
+    "create a VersionDiffBrowser instance and set the class change set of the
+     browser. The class diff set is generated from two versions of aClass via
+     the source code manager."
+
+    |theBrowser|
+
+    theBrowser := self new.
+    theBrowser allButOpen.
+    theBrowser setupForFile:aFilename versionA:versionA versionB:versionB.
+    theBrowser window label:(self resources 
+                                string:'%1 Versions %2 vs. %3' 
+                                with:aFilename baseName with:versionA with:versionB).
+    theBrowser openWindow.
+    ^ theBrowser.
+
+    "
+     self openOnFile:'Make.proto' versionA:'1.1' versionB:'1.2'
+    "
+
+    "Created: / 07-07-2019 / 20:06:15 / Claus Gittinger"
+! !
+
+!FileVersionDiffBrowser methodsFor:'accessing'!
+
+beMultipleFilesVersionBrowser
+    isMultipleFilesVersionBrowser := true
+
+    "Created: / 07-07-2019 / 18:58:49 / Claus Gittinger"
+!
+
+beMultipleVersionBrowser
+    isMultipleVersionBrowser := true
+!
+
+isMultipleFilesVersionBrowser
+    ^ isMultipleFilesVersionBrowser
+
+    "Created: / 07-07-2019 / 19:53:15 / Claus Gittinger"
+!
+
+isMultipleVersionBrowser
+    ^ isMultipleVersionBrowser
+
+    "Modified: / 08-05-2019 / 10:59:40 / Claus Gittinger"
+! !
+
+!FileVersionDiffBrowser methodsFor:'aspects'!
+
+diffTextHolder
+    diffTextHolder isNil ifTrue:[
+        diffTextHolder := '' asValue
+    ].    
+    ^ diffTextHolder
+
+    "Created: / 07-07-2019 / 20:04:23 / Claus Gittinger"
+!
+
+diffTextLabelA
+    "aspect for the label for version A"
+
+    ^ diffTextLabelA.
+
+    "Modified: / 08-05-2019 / 11:03:23 / Claus Gittinger"
+!
+
+diffTextLabelB
+    "aspect for the label for version B"
+
+    ^ diffTextLabelB.
+
+    "Modified: / 08-05-2019 / 11:03:32 / Claus Gittinger"
+!
+
+diffTextView
+    "
+    return the component for the diff text view.
+
+    <return: HVScrollableView>
+    "
+    |v|
+
+    diffTextView isNil ifTrue:[
+        v := DiffCodeView new.
+        v textViewClass:CodeView.
+        v initialize.
+        diffTextView := HVScrollableView
+                           forView:v
+                           miniScrollerH:true miniScrollerV:false.
+        diffTextView addNextPreviousButtons.
+    ].
+    ^ diffTextView
+
+    "Modified: / 06-10-2006 / 14:30:42 / cg"
+!
+
+fileHolder
+    fileHolder isNil ifTrue:[
+        fileHolder := nil asValue
+    ].    
+    ^ fileHolder
+
+    "Created: / 07-07-2019 / 20:10:47 / Claus Gittinger"
+!
+
+fileList:aList
+    self fileListHolder contents:aList
+
+    "Created: / 08-07-2019 / 00:28:32 / Claus Gittinger"
+!
+
+fileListHolder
+    "aspect for the 'list of files' list.
+     <return: List>"
+
+    fileListHolder isNil ifTrue:[
+        fileListHolder := List new
+    ].    
+    ^ fileListHolder
+
+    "Created: / 07-07-2019 / 19:46:44 / Claus Gittinger"
+!
+
+fileNameListHolder
+    "aspect for the 'list of file' list.
+     <return: List>"
+
+    ^ BlockValue
+        with:[:l | l collect:#baseName]
+        argument:(self fileListHolder)
+
+    "Created: / 07-07-2019 / 19:47:13 / Claus Gittinger"
+!
+
+infoHolder
+    ^ infoHolder.
+
+    "Modified: / 08-05-2019 / 11:05:10 / Claus Gittinger"
+!
+
+selectedFileIndexHolder
+    selectedFileIndexHolder isNil ifTrue:[
+        selectedFileIndexHolder := nil asValue. 
+        selectedFileIndexHolder onChangeSend:#selectedFileIndexHolderChanged to:self.
+    ].
+    ^ selectedFileIndexHolder
+
+    "Created: / 07-07-2019 / 19:00:13 / Claus Gittinger"
+!
+
+selectedSymbolicVersionHolder
+    ^ selectedSymbolicVersionHolder
+
+    "Modified: / 08-05-2019 / 11:08:42 / Claus Gittinger"
+!
+
+selectedSymbolicVersionIndexHolder
+    ^ selectedSymbolicVersionIndexHolder
+
+    "Created: / 28-05-2019 / 15:32:03 / Claus Gittinger"
+!
+
+selectedVersionHolder
+    ^ selectedVersionHolder
+
+    "Modified: / 08-05-2019 / 11:09:18 / Claus Gittinger"
+!
+
+selectedVersionIndex
+    ^ selectedVersionIndexHolder value ? 0
+
+    "Created: / 23-05-2018 / 11:35:50 / Claus Gittinger"
+    "Modified: / 08-05-2019 / 11:09:50 / Claus Gittinger"
+!
+
+selectedVersionIndexHolder
+    ^ selectedVersionIndexHolder
+
+    "Created: / 29-11-2017 / 13:02:49 / cg"
+    "Modified: / 08-05-2019 / 11:09:46 / Claus Gittinger"
+!
+
+symbolicVersionList
+    ^ symbolicVersionList
+
+    "Modified: / 08-05-2019 / 11:10:23 / Claus Gittinger"
+!
+
+symbolicVersionNameList
+    ^ symbolicVersionNameList
+
+    "Created: / 28-05-2019 / 15:42:12 / Claus Gittinger"
+!
+
+versionEntriesList
+    ^ versionEntriesList
+
+    "Created: / 29-11-2017 / 13:06:14 / cg"
+    "Modified: / 08-05-2019 / 11:10:38 / Claus Gittinger"
+!
+
+versionList
+    ^ versionList
+
+    "Modified: / 08-05-2019 / 11:10:53 / Claus Gittinger"
+! !
+
+!FileVersionDiffBrowser methodsFor:'aspects-menu'!
+
+hasNextVersionInVersionList
+    "versions are sorted youngest first.
+     If the current selected one is the first, there is no next version"
+     
+    ^ (self selectedVersionIndex) > 1.
+
+    "Modified: / 23-05-2018 / 11:36:33 / Claus Gittinger"
+!
+
+hasPreviousVersionInVersionList 
+    "versions are sorted youngest first.
+     If the current selected one is the last, there is no previous version"
+
+    ^ (self selectedVersionIndex) < versionList value size.
+
+    "Modified: / 23-05-2018 / 11:36:38 / Claus Gittinger"
+!
+
+versionsMenu
+    ^ [ 
+        |m item nextVersion prevVersion|
+
+        m := self class versionsMenu.
+        m := m decodeAsLiteralArray.
+        m findGuiResourcesIn:self.
+
+        self hasNextVersionInVersionList ifTrue:[
+            nextVersion := self versionList at:(self selectedVersionIndex - 1).
+            item := m atNameKey:#CompareAgainstNextVersion. 
+            item label:(resources string:(item label,' (%1)') with:nextVersion).
+        ].
+        self hasPreviousVersionInVersionList ifTrue:[
+            prevVersion := self versionList at:(self selectedVersionIndex + 1).
+            item := m atNameKey:#CompareAgainstPreviousVersion.
+            item label:(resources string:(item label,'(%1)') with:prevVersion).
+        ].
+        m
+      ]
+
+    "Modified: / 23-05-2018 / 11:36:18 / Claus Gittinger"
+! !
+
+!FileVersionDiffBrowser methodsFor:'change & update'!
+
+selectVersion:version
+    |idx numShownBefore numShownAfter|
+
+    idx := versionList indexOf:version.
+    "/ if not found, get more version infos
+    [idx == 0] whileTrue:[
+        numShownBefore := versionList size.
+        self updateVersionList.
+        numShownAfter := versionList size.
+        idx := versionList indexOf:version.
+        idx == 0 ifTrue:[
+            numShownBefore == numShownAfter ifTrue:[
+                ^ self
+            ].
+        ].
+    ].    
+    self selectedVersionIndexHolder value:idx.
+
+    "Created: / 28-05-2019 / 14:58:37 / Claus Gittinger"
+!
+
+selectedFileIndexHolderChanged
+    |fn|
+
+    fn := self fileListHolder value at:(self selectedFileIndexHolder value).
+
+    self fileHolder value:fn.
+    (self isMultipleVersionBrowser or:[self isMultipleFilesVersionBrowser]) ifTrue:[
+        self withWaitCursorDo:[
+            self updateVersionList.
+        ]
+    ]
+
+    "Created: / 07-07-2019 / 19:51:17 / Claus Gittinger"
+    "Modified: / 08-07-2019 / 00:30:51 / Claus Gittinger"
+!
+
+selectedSymbolicVersionHolderChanged
+    |symbolicTag version|
+
+    symbolicTag := self selectedSymbolicVersionHolder value.
+    version := symbolicToVersionMapping at:symbolicTag ifAbsent:nil.
+    version isNil ifTrue:[
+        symbolicTag = '-' ifFalse:[
+            Dialog warn:'No version has this tag ("%1")' with:symbolicTag.
+        ].
+        ^ self.
+    ].
+    self selectVersion:version
+
+    "Modified: / 28-05-2019 / 14:57:56 / Claus Gittinger"
+!
+
+selectedSymbolicVersionIndexHolderChanged
+    self selectedSymbolicVersionHolder value:(symbolicVersionList at:self selectedSymbolicVersionIndexHolder value)
+
+    "Created: / 28-05-2019 / 15:32:47 / Claus Gittinger"
+!
+
+selectedVersionHolderChanged
+
+    self withWaitCursorDo:[
+        |idx|
+
+        "/ possibly expand a contracted list
+        selectedVersionHolder value = '...' ifTrue:[
+            idx := self versionList size.
+            self updateVersionList.
+            selectedVersionHolder setValue:(self versionList at:idx).
+        ].
+
+        "/ update the view
+        self 
+            setupForFile:fileHolder value 
+            againstVersion:(selectedVersionHolder value).
+
+        "/ self showVersionInfoIfNothingSelected
+    ]
+
+    "Modified: / 06-02-2017 / 02:32:24 / cg"
+    "Modified: / 08-07-2019 / 00:05:30 / Claus Gittinger"
+!
+
+selectedVersionIndexHolderChanged
+    self selectedVersionHolder value:(versionList at:self selectedVersionIndexHolder value)
+
+    "Created: / 29-11-2017 / 13:04:12 / cg"
+!
+
+showActivity:someMessage
+    "some activityNotification shalt be communicated to the user."
+
+    infoHolder value:someMessage.
+
+    "Created: / 28-05-2019 / 15:26:34 / Claus Gittinger"
+!
+
+update:something with:parameter from:changedObject
+    (changedObject == fileHolder
+    or:[changedObject == versionAHolder
+    or:[changedObject == versionBHolder]]) ifTrue:[
+        self setupForFile:(fileHolder value) versionA:(versionAHolder value) versionB:(versionBHolder value).
+        ^ self
+    ].
+    super update:something with:parameter from:changedObject
+
+    "Modified: / 17-07-2012 / 17:48:58 / cg"
+    "Modified: / 08-07-2019 / 00:09:19 / Claus Gittinger"
+!
+
+updateLists
+    "walk over the changeSet(s) and setup the 3 lists:
+     onlyInA, changed, onlyInB,
+     Optionally filter extensions, categoryChanges and versionMethods,
+     changes with same semantic (variable renames)
+     and changes which have been explicitly filtered by the user."
+
+    |listOnlyInA listOnlyInB listChanged
+     printStringGenerator "sortBlockForChangeLists" filteredList
+     numIgnoredExtensions numIgnoredVersionMethods 
+     info needFilter entryIsForCommentOrFormatOnly
+     isIgnoredChange|
+
+"/    listOnlyInA := filteredList := self methodsOnlyInA.
+"/    listOnlyInA removeAll.
+"/    classChangeSet notNil ifTrue:[
+"/        "/ classChangeSet methodsOnlyInA sort:sortBlockForChangeLists.
+"/        filteredList := classChangeSet methodsOnlyInA reject:isIgnoredChange.
+"/        listOnlyInA addAll: (filteredList collect:printStringGenerator).
+"/    ].
+"/    methodsOnlyInAFiltered := filteredList.
+"/
+"/    listOnlyInB := filteredList := self methodsOnlyInB.
+"/    listOnlyInB removeAll.
+"/    classChangeSet notNil ifTrue:[
+"/        "/ classChangeSet methodsOnlyInB sort:sortBlockForChangeLists.
+"/        filteredList := classChangeSet methodsOnlyInB reject:isIgnoredChange.
+"/        listOnlyInB addAll: (filteredList collect:printStringGenerator).
+"/    ].
+"/    methodsOnlyInBFiltered := filteredList.
+
+"/    entryIsForCommentOrFormatOnly :=
+"/        [:entry |
+"/            |commentOnly changeA changeB mthdA mthdB|
+"/
+"/            commentOnly := false.
+"/            
+"/            changeA := entry first.
+"/            changeB := entry second.
+"/            changeA isMethodChange ifTrue:[
+"/                changeA isMethodCodeChange ifTrue:[
+"/                    RBCodeDuplicationRule notNil ifTrue:[
+"/                        mthdA := RBMethod forMethodChange:changeA.
+"/                        mthdB := RBMethod forMethodChange:changeB.
+"/                        commentOnly := RBCodeDuplicationRule hasMethod:mthdA sameSemanticAs:mthdB.
+"/                    ].
+"/                ] ifFalse:[
+"/                    changeA isMethodCategoryChange ifTrue:[
+"/                        commentOnly := true
+"/                    ] ifFalse:[    
+"/                        self breakPoint:#cg
+"/                    ].    
+"/                ].    
+"/            ] ifFalse:[
+"/                changeA isClassDefinitionChange ifTrue:[
+"/                    changeA source = changeB source ifTrue:[
+"/                        commentOnly := true
+"/                    ] ifFalse:[
+"/                        self breakPoint:#cg
+"/                    ].    
+"/                ] ifFalse:[    
+"/                    self breakPoint:#cg
+"/                ].
+"/            ].
+"/            commentOnly
+"/        ].
+        
+"/    listChanged := filteredList := self methodsChanged.
+"/    listChanged removeAll.
+"/    classChangeSet notNil ifTrue:[
+"/        "/ classChangeSet methodsChanged sort:[:a :b | sortBlockForChangeLists value:a first value:b first].
+"/        filteredList := classChangeSet methodsChanged reject:[:entry | isIgnoredChange value:entry first].
+"/
+"/        (self hideDiffsWithCommentOrFormattingChangeOnly) ifTrue:[
+"/            filteredList := filteredList reject:entryIsForCommentOrFormatOnly.
+"/            listChanged addAll: (filteredList collect:[:entry| printStringGenerator value:(entry first)]).
+"/        ] ifFalse:[
+"/            filteredList do:[:entry| 
+"/                |string|
+"/
+"/                string := printStringGenerator value:(entry first).
+"/                (entryIsForCommentOrFormatOnly value:entry) ifTrue:[
+"/                    string := string withColor:Color grey.
+"/                ].    
+"/                listChanged add:string
+"/            ].
+"/        ].    
+"/    ].
+"/    methodsChangedFiltered := filteredList.
+
+"/    self boxAVisible value:(listOnlyInA notEmpty).
+"/    self boxBVisible value:(listOnlyInB notEmpty).
+
+"/    self boxMVisible value:(listChanged isEmpty
+"/                            and: [(listOnlyInA notEmpty
+"/                                  or:[listOnlyInB notEmpty])]) not.
+
+    self information:info
+
+    "Modified (comment): / 06-02-2017 / 10:09:11 / cg"
+    "Modified (format): / 16-02-2017 / 11:11:49 / stefan"
+    "Modified: / 07-07-2019 / 19:08:03 / Claus Gittinger"
+!
+
+updateVersionList
+    "asks the classes source code manager for a list of revisions;
+     construct versionInfoList (containing the full info), versionList (containing version numbers only)
+     and tagList (containing symbolic names only).
+     This is only used when comparing multiple versions."
+
+    |fn sourceCodeManager numShown newNumShown numOverallRevisions
+     partialLog newestRev revisions revisionEntries symbolicNames
+     stableRevision releasedRevision tagList logMessages|
+
+    fn := fileHolder value.
+    fn isNil ifTrue:[
+        symbolicVersionList contents:#().
+        symbolicVersionNameList contents:#().
+        self versionList contents:#().
+        self versionEntriesList contents:#().
+        ^ self
+    ]. 
+ 
+    sourceCodeManager := CVSSourceCodeManager.
+
+    numShown := versionList size - 1.
+    newNumShown := (numShown + 50) max:30.
+
+    infoHolder value:'Getting version log...'.
+    partialLog := sourceCodeManager revisionLogOfFile:fn numberOfRevisions:newNumShown.
+
+    partialLog isNil ifTrue:[
+        self warn:'Could not find/access the container for ',fn name,' in the repository.
+This could be due to:
+    - invalid/wrong CVS-Root setting
+    - missing CVS access rights
+        (no access / not logged in)
+    - changed CVSRoot after compilation
+        (i.e. wrong CVS-path in classes version method)
+'.
+        ^ nil
+    ].
+
+    numOverallRevisions := partialLog at:#numberOfRevisions.
+    newestRev := partialLog at:#newestRevision.
+    revisions := partialLog at:#revisions.
+    
+    "/ fetch the symbolic (tag) version list
+    symbolicNames := partialLog at:#symbolicNames ifAbsent:[].
+    symbolicNames notNil ifTrue:[
+        stableRevision := symbolicNames at:'stable' ifAbsent:[].
+        releasedRevision := symbolicNames at:'released' ifAbsent:[].
+
+        tagList := ((symbolicNames associations 
+                        sort:[:a :b | sourceCodeManager versionString:(a value) isLessThan:(b value)])
+                            collect:[:assoc | assoc key]) reverse.
+"/        tagList := ((symbolicNames associations 
+"/                        sort:[:a :b | a key < b key])
+"/                            collect:[:assoc | assoc key]) reverse.
+
+        tagList remove:'stable' ifAbsent:[].
+        stableRevision notNil ifTrue:[
+            tagList notEmpty ifTrue:[tagList addFirst:'-'].
+            tagList addFirst:'stable'.
+        ].
+    ].
+    logMessages := Dictionary new.
+
+    versionInfoList := revisions.
+
+"/    items := versionInfoList collect:[:each | |rev date who flag|
+"/                                    rev := each at:#revision.
+"/                                    logMessages at:rev put:(each at:#logMessage).
+"/                                    date := (each at:#date ifAbsent:nil) ? '?'.
+"/                                    who := (each at:#author ifAbsent:nil) ? '?'.
+"/                                    rev = stableRevision ifTrue:[
+"/                                        flag := ' Stable' allBold.
+"/                                    ] ifFalse:[rev = releasedRevision ifTrue:[
+"/                                        flag := ' Released' allBold.
+"/                                    ] ifFalse:[
+"/                                        flag := ' '
+"/                                    ]].
+"/                                    rev allBold , flag, ' [' , date , ' by ' , who , ']'
+"/                               ].
+"/
+"/    revisions := revisions collect:[:eachItem | eachItem at:#revision].
+    revisions := OrderedCollection new.
+    revisionEntries := OrderedCollection new.
+    versionInfoList do:[:eachVersionInfo |
+        revisions add:eachVersionInfo revision.
+        revisionEntries add:(
+                    (eachVersionInfo revision)
+                    , ((' (by %2 at %3)' 
+                        bindWith:(eachVersionInfo revision)
+                        with:(eachVersionInfo user)
+                        with:(eachVersionInfo date)) withColor:Color grey)).
+    ].
+
+    revisions size < numOverallRevisions ifTrue:[
+        revisions add:'...'.
+        revisionEntries add:'...'.
+    ].          
+
+    symbolicToVersionMapping := symbolicNames.
+
+    symbolicVersionList contents:tagList.
+
+    symbolicVersionNameList 
+        contents:(
+            tagList 
+                collect:[:eachSymbolic |
+                    |versionsString|
+
+                    eachSymbolic = '-' ifTrue:[
+                        eachSymbolic.
+                    ] ifFalse:[    
+                        versionsString := symbolicToVersionMapping at:eachSymbolic ifAbsent:'<<none>>'.
+                        eachSymbolic,((' (',versionsString,')') withColor:Color grey)
+                    ]
+                ]).
+    self versionList contents:revisions.
+    self versionEntriesList contents:revisionEntries.
+    infoHolder value:'Done.'.
+
+    "Modified: / 29-11-2017 / 13:06:21 / cg"
+    "Modified: / 07-07-2019 / 23:44:42 / Claus Gittinger"
+! !
+
+!FileVersionDiffBrowser methodsFor:'initialization & release'!
+
+initialize
+    super initialize.
+    
+    isMultipleVersionBrowser := false.
+    isMultipleFilesVersionBrowser := false.
+
+    diffTextLabelA := ValueHolder new.
+    diffTextLabelB := ValueHolder new.
+    infoHolder := ValueHolder new.
+
+    selectedSymbolicVersionIndexHolder := nil asValue.
+    selectedSymbolicVersionIndexHolder onChangeSend:#selectedSymbolicVersionIndexHolderChanged to:self.
+
+    selectedSymbolicVersionHolder := nil asValue.
+    selectedSymbolicVersionHolder onChangeSend:#selectedSymbolicVersionHolderChanged to:self.
+
+    selectedVersionIndexHolder := nil asValue.
+    selectedVersionIndexHolder onChangeSend:#selectedVersionIndexHolderChanged to:self.
+
+    selectedVersionHolder := nil asValue.
+    selectedVersionHolder onChangeSend:#selectedVersionHolderChanged to:self.
+      
+    symbolicVersionList := List new.
+    symbolicVersionNameList := List new.
+    versionEntriesList := List new.
+    versionList := List new.
+
+    "Created: / 08-05-2019 / 10:59:30 / Claus Gittinger"
+    "Modified: / 08-07-2019 / 00:06:27 / Claus Gittinger"
+!
+
+postBuildWith:aBuilder
+    "
+    components which are invisible should be ignored by the panel.
+    Cannot be set via the interface builder.
+
+    <return: self>
+    "
+
+    super postBuildWith:aBuilder
+
+    "Modified: / 07-07-2019 / 23:56:48 / Claus Gittinger"
+!
+
+postOpenWith:aBuilder
+    super postOpenWith:aBuilder.
+
+    self isMultipleVersionBrowser ifTrue:[
+        self withWaitCursorDo:[
+            self updateVersionList.
+        ]
+    ]
+! !
+
+!FileVersionDiffBrowser methodsFor:'menu action'!
+
+mainMenu
+    "if this application runs as an subapplication,
+     the menu bar should not be used."
+
+    self masterApplication isNil ifTrue:[
+	^ self class mainMenu
+    ].
+    ^ nil
+
+    "Modified: / 25-07-2006 / 11:13:44 / cg"
+!
+
+menuAHolder
+    ^ [ self class menuA ]
+
+    "Created: / 05-02-2017 / 10:07:15 / cg"
+!
+
+menuBHolder
+    ^ [ self class menuB ]
+
+    "Created: / 05-02-2017 / 10:07:22 / cg"
+!
+
+menuMHolder
+    ^ [ self class menuM ]
+
+    "Created: / 05-02-2017 / 10:07:36 / cg"
+!
+
+openDocumentation
+    HTMLDocumentView openFullOnDocumentationFile:'tools/misc/TOP.html#VERSIONDIFF'
+!
+
+versionMenuCompareAgainstNextVersion
+    |fn selectedVersion nextVersion|
+
+    selectedVersion := self selectedVersionHolder value.
+    nextVersion := self versionList at:(self selectedVersionIndex - 1).
+    fn := fileHolder value.
+    
+    self class 
+        openOnFile:fn versionA:selectedVersion versionB:nextVersion
+
+    "Modified: / 08-07-2019 / 00:09:54 / Claus Gittinger"
+!
+
+versionMenuCompareAgainstPreviousVersion
+    |fn selectedVersion prevVersion|
+
+    selectedVersion := self selectedVersionHolder value.
+    selectedVersion isNil ifTrue:[
+        self selectedVersionIndexHolder value:1
+    ].    
+    prevVersion := self versionList at:(self selectedVersionIndex + 1).
+    fn := fileHolder value.
+    
+    self class 
+        openOnFile:fn versionA:prevVersion versionB:selectedVersion
+
+    "Modified: / 08-07-2019 / 00:10:12 / Claus Gittinger"
+! !
+
+!FileVersionDiffBrowser methodsFor:'private'!
+
+addAcceptToTextViewMenus
+    "add to the standard diff text view or single text views menu an accept entry.
+     The acceptAction will fetch the corresponding change and apply it
+     (not the shown text)
+
+     <return: self>
+    "
+
+    |diffTextView leftView rightView singleView|
+
+    diffTextView := self diffTextView.
+    leftView := diffTextView leftTextView.
+    rightView := diffTextView rightTextView.
+    singleView := self componentAt:#singleTextView.
+
+    (Array
+        with:leftView
+        with:rightView
+        with:singleView)
+    do:[:v |
+        |mGen|
+
+        mGen := [
+            |m|
+
+            m := v editMenu.
+
+            (m selectorAt:#accept) isNil ifTrue:[
+                m addLabels:(resources array:#('-' 'Accept'))
+                  selectors:#(nil #accept)
+                  after:#copySelection.
+            ].
+            m
+                actionAt:#accept
+                put:[
+                    v == singleView ifTrue:[
+                        self acceptInSingleView
+                    ] ifFalse:[
+                        v == leftView ifTrue:[
+                           self acceptInLeftView
+                        ] ifFalse:[
+                           self acceptInRightView
+                        ].
+                    ].
+                ].
+            m selectorAt:#accept put:nil.
+            m enable:#copySelection.
+            m setEnable:#accept to:[self canAcceptInCodeView].
+            m
+        ].
+        v menuHolder:mGen.
+        v menuMessage:#value.
+    ]
+!
+
+getFile:fileName version:version
+    |errStream errorMessages inStream contents|
+
+    errStream := '' writeStream.
+    [
+        inStream := PipeStream 
+                    readingFrom:('cvs update -p -r %1 %2' 
+                                    bindWith:(version ? '')
+                                    with:fileName baseName)
+                    errorDisposition:errStream
+                    inDirectory:fileName directory pathName.                
+        contents := inStream upToEnd.
+    ] ensure:[
+        inStream notNil ifTrue:[
+            inStream close
+        ]
+    ].
+    contents isEmptyOrNil ifTrue:[
+        errorMessages := errStream contents.
+        errorMessages notEmptyOrNil ifTrue:[
+            self halt.
+        ].    
+    ].    
+    ^ contents
+
+    "Created: / 07-07-2019 / 22:09:21 / Claus Gittinger"
+    "Modified: / 08-07-2019 / 01:24:35 / Claus Gittinger"
+!
+
+informationUntranslated:msg
+    self infoHolder value:msg
+
+    "Created: / 09-08-2018 / 15:40:52 / Claus Gittinger"
+!
+
+resetSelectionHolders
+    "
+    reset all selection holders when a new change set is given.
+    First set the selection to nil.
+
+    <return: self>
+    "
+
+    self diffTextView text1:'' text2:''.
+
+    "Modified (comment): / 08-07-2019 / 00:06:09 / Claus Gittinger"
+!
+
+showDiffTextView
+    "
+    if a method change is selected, then show the diff text view.
+    Add an accept entry to the popup menu.
+
+    <return: self>
+    "
+
+    (self componentAt:#diffTextViewBox) raise; beVisible.
+    (self componentAt:#diffTextView) realizeAllSubViews.
+
+    "/ self addAcceptToTextViewMenus.
+
+    "Modified: / 08-07-2019 / 00:02:19 / Claus Gittinger"
+!
+
+showSingleTextView
+    "
+    if a method  is selected which is only in version A or B of the class,
+    then show the text view.
+    Add an accept entry to the popup menu.
+
+    <return: self>
+    "
+
+    (self componentAt:#diffTextViewBox) beInvisible.
+    "/ self addAcceptToTextViewMenus.
+
+    "Modified: / 08-07-2019 / 00:03:10 / Claus Gittinger"
+!
+
+showVersionInfoIfNothingSelected
+    "show the revision info (author, date, time and logMessage), 
+     if no method is selected"
+
+    |revInfo infoText|
+
+    "/ self information:''.
+
+    versionInfoList notNil ifTrue:[
+        revInfo := versionInfoList detect:[:info | (info at:#revision) = selectedVersionHolder value] ifNone:nil.
+        revInfo notNil ifTrue:[
+            infoText := 'Revision: %1\Author:   %2\Date:     %3\Log:\\%4' withCRs
+                            bindWith:(revInfo at:#revision) 
+                            with:(revInfo at:#author) 
+                            with:(revInfo at:#date)
+                            with:(revInfo at:#logMessage).
+        ].
+    ].    
+    self showSingleTextView.
+
+    "Modified: / 05-02-2017 / 11:49:47 / cg"
+    "Modified (comment): / 08-07-2019 / 00:06:32 / Claus Gittinger"
+! !
+
+!FileVersionDiffBrowser methodsFor:'setup'!
+
+setupForAllVersionsOfFile:aFilename
+    self fileHolder value:aFilename.
+    self updateVersionList.
+
+    "Created: / 07-07-2019 / 22:42:40 / Claus Gittinger"
+    "Modified: / 07-07-2019 / 23:46:28 / Claus Gittinger"
+!
+
+setupForFile:aFilename againstVersion:aVersionA
+    "compute the diffs for the file's current version against the repository version A.
+     When setting the diffs, the labels, list etc. of the receiver
+     are updated."
+
+    |text1 text2|
+
+    text1 := aFilename contentsAsString.
+    text2 := self getFile:aFilename version:aVersionA.
+    
+    self diffTextView text1:text1 text2:text2.        
+    self diffTextLabelA value:('File: %1' bindWith:aFilename baseName).
+    self diffTextLabelB value:aVersionA.
+
+    "Created: / 07-07-2019 / 19:57:27 / Claus Gittinger"
+    "Modified: / 08-07-2019 / 01:13:47 / Claus Gittinger"
+!
+
+setupForFile:fileA labelA:labelA andFile:fileB labelB:labelB
+    "generate the diffs from the two files A and B.
+     When setting the diffs, the labels, list etc. of the receiver
+     are updated."
+
+    self diffTextView
+        text1:(fileA contentsAsString) 
+        text2:(fileB contentsAsString).
+
+    self diffTextLabelA value:labelA.
+    self diffTextLabelB value:labelB.
+
+    "Created: / 07-07-2019 / 19:59:03 / Claus Gittinger"
+    "Modified: / 08-07-2019 / 01:14:36 / Claus Gittinger"
+! !
+
+!FileVersionDiffBrowser class methodsFor:'documentation'!
+
+version_CVS
+    ^ '$Header$'
+! !
+