initial checkin
authorClaus Gittinger <cg@exept.de>
Mon, 05 Jul 1999 17:28:17 +0200
changeset 2221 f536ebd184ef
parent 2220 1ec72aa513c8
child 2222 cd9ee5d35461
initial checkin
VersionDiffBrowser.st
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VersionDiffBrowser.st	Mon Jul 05 17:28:17 1999 +0200
@@ -0,0 +1,955 @@
+ApplicationModel subclass:#VersionDiffBrowser
+	instanceVariableNames:'classBeingCompared versionA versionB changeSetA changeSetB
+		indexFromChangedToA indexFromChangedToB diffTextView'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'Interface-Browsers'
+!
+
+
+!VersionDiffBrowser 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:VersionDiffBrowser andSelector:#windowSpec
+     VersionDiffBrowser new openInterface:#windowSpec
+     VersionDiffBrowser open
+    "
+
+    <resource: #canvas>
+
+    ^ 
+     #(#FullSpec
+        #name: #windowSpec
+        #window: 
+       #(#WindowSpec
+          #label: 'Version DiffBrowser'
+          #name: 'Version DiffBrowser'
+          #layout: #(#LayoutFrame 220 0 200 0 1084 0 703 0)
+          #level: 0
+          #min: #(#Point 10 10)
+          #max: #(#Point nil nil)
+          #bounds: #(#Rectangle 220 200 1085 704)
+          #menu: #mainMenu
+          #usePreferredExtent: false
+          #returnIsOKInDialog: true
+          #escapeIsCancelInDialog: true
+        )
+        #component: 
+       #(#SpecCollection
+          #collection: #(
+           #(#VariableVerticalPanelSpec
+              #name: 'VariableVerticalPanel1'
+              #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+              #handles: #(#Any 0.319444 1.0)
+              #component: 
+             #(#SpecCollection
+                #collection: #(
+                 #(#HorizontalPanelViewSpec
+                    #name: 'TopHorizontalPanel'
+                    #horizontalLayout: #fit
+                    #verticalLayout: #fit
+                    #horizontalSpace: 3
+                    #verticalSpace: 3
+                    #component: 
+                   #(#SpecCollection
+                      #collection: #(
+                       #(#ViewSpec
+                          #name: 'BoxA'
+                          #level: 0
+                          #component: 
+                         #(#SpecCollection
+                            #collection: #(
+                             #(#LabelSpec
+                                #label: 'Only in A'
+                                #name: 'Label1'
+                                #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
+                                #translateLabel: true
+                                #labelChannel: #onlyInALabelHolder
+                              )
+                             #(#SequenceViewSpec
+                                #name: 'ListA'
+                                #layout: #(#LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
+                                #model: #methodsOnlyInASelection
+                                #menu: #menuA
+                                #hasHorizontalScrollBar: true
+                                #hasVerticalScrollBar: true
+                                #miniScrollerHorizontal: true
+                                #valueChangeSelector: #methodsOnlyInASelectionChanged
+                                #useIndex: true
+                                #sequenceList: #methodsOnlyInA
+                              )
+                             )
+                           
+                          )
+                          #extent: #(#Point 286 160)
+                        )
+                       #(#ViewSpec
+                          #name: 'BoxM'
+                          #component: 
+                         #(#SpecCollection
+                            #collection: #(
+                             #(#LabelSpec
+                                #label: 'Changed'
+                                #name: 'Label2'
+                                #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
+                                #translateLabel: true
+                                #labelChannel: #changedLabelHolder
+                              )
+                             #(#SequenceViewSpec
+                                #name: 'ListM'
+                                #layout: #(#LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
+                                #model: #methodsChangedSelection
+                                #menu: #menuM
+                                #hasHorizontalScrollBar: true
+                                #hasVerticalScrollBar: true
+                                #miniScrollerHorizontal: true
+                                #valueChangeSelector: #methodsChangedSelectionChanged
+                                #useIndex: true
+                                #sequenceList: #methodsChanged
+                              )
+                             )
+                           
+                          )
+                          #extent: #(#Point 286 160)
+                        )
+                       #(#ViewSpec
+                          #name: 'BoxB'
+                          #component: 
+                         #(#SpecCollection
+                            #collection: #(
+                             #(#LabelSpec
+                                #label: 'Only in B'
+                                #name: 'Label3'
+                                #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
+                                #translateLabel: true
+                                #labelChannel: #onlyInBLabelHolder
+                              )
+                             #(#SequenceViewSpec
+                                #name: 'ListB'
+                                #layout: #(#LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
+                                #model: #methodsOnlyInBSelection
+                                #menu: #menuB
+                                #hasHorizontalScrollBar: true
+                                #hasVerticalScrollBar: true
+                                #miniScrollerHorizontal: true
+                                #valueChangeSelector: #methodsOnlyInBSelectionChanged
+                                #useIndex: true
+                                #sequenceList: #methodsOnlyInB
+                              )
+                             )
+                           
+                          )
+                          #extent: #(#Point 287 160)
+                        )
+                       )
+                     
+                    )
+                  )
+                 #(#ViewSpec
+                    #name: 'Box4'
+                    #component: 
+                   #(#SpecCollection
+                      #collection: #(
+                       #(#ViewSpec
+                          #name: 'diffTextViewBox'
+                          #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+                          #initiallyInvisible: true
+                          #component: 
+                         #(#SpecCollection
+                            #collection: #(
+                             #(#LabelSpec
+                                #label: 'A'
+                                #name: 'DiffTextLabelA'
+                                #layout: #(#LayoutFrame 0 0 0 0 0 0.5 20 0)
+                                #translateLabel: true
+                                #labelChannel: #diffTextLabelA
+                              )
+                             #(#LabelSpec
+                                #label: 'B'
+                                #name: 'DiffTextLabelB'
+                                #layout: #(#LayoutFrame 0 0.5 0 0 0 1 20 0)
+                                #translateLabel: true
+                                #labelChannel: #diffTextLabelB
+                              )
+                             #(#ArbitraryComponentSpec
+                                #name: 'diffTextView'
+                                #layout: #(#LayoutFrame 0 0.0 20 0.0 0 1.0 0 1.0)
+                                #hasBorder: false
+                                #component: #diffTextView
+                              )
+                             )
+                           
+                          )
+                        )
+                       #(#TextEditorSpec
+                          #name: 'singleTextView'
+                          #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+                          #initiallyInvisible: true
+                          #model: #methodText
+                          #hasHorizontalScrollBar: true
+                          #hasVerticalScrollBar: true
+                          #miniScrollerHorizontal: true
+                        )
+                       )
+                     
+                    )
+                  )
+                 )
+               
+              )
+            )
+           )
+         
+        )
+      )
+! !
+
+!VersionDiffBrowser 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:VersionDiffBrowser andSelector:#mainMenu
+     (Menu new fromLiteralArrayEncoding:(VersionDiffBrowser mainMenu)) startUp
+    "
+
+    <resource: #menu>
+
+    ^ 
+     #(#Menu
+        #(
+         #(#MenuItem
+            #label: 'File'
+            #translateLabel: true
+            #submenu: 
+           #(#Menu
+              #(
+               #(#MenuItem
+                  #label: 'Exit'
+                  #translateLabel: true
+                  #value: #closeRequest
+                )
+               )
+              nil
+              nil
+            )
+          )
+         #(#MenuItem
+            #label: 'Help'
+            #translateLabel: true
+            #startGroup: #right
+            #submenu: 
+           #(#Menu
+              #(
+               #(#MenuItem
+                  #label: 'Documentation'
+                  #translateLabel: true
+                  #value: #openDocumentation
+                )
+               #(#MenuItem
+                  #label: '-'
+                )
+               #(#MenuItem
+                  #label: 'About this Application'
+                  #translateLabel: true
+                  #value: #openAboutThisApplication
+                )
+               )
+              nil
+              nil
+            )
+          )
+         )
+        nil
+        nil
+      )
+!
+
+menuA
+    "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:#menu1
+     (Menu new fromLiteralArrayEncoding:(VersionDiffBrowser menu1)) startUp
+    "
+
+    <resource: #menu>
+
+    ^ 
+     #(#Menu
+        #(
+         #(#MenuItem
+            #label: 'Inspect'
+            #translateLabel: true
+            #value: #inspectSelectedChangeInA
+            #choiceValue: 'nil "UndefinedObject" '
+          )
+         )
+        nil
+        nil
+      )
+!
+
+menuB
+    "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:#menuB
+     (Menu new fromLiteralArrayEncoding:(VersionDiffBrowser menuB)) startUp
+    "
+
+    <resource: #menu>
+
+    ^ 
+     #(#Menu
+        #(
+         #(#MenuItem
+            #label: 'Inspect'
+            #translateLabel: true
+            #value: #inspectSelectedChangeInB
+            #choiceValue: 'nil "UndefinedObject" '
+          )
+         )
+        nil
+        nil
+      )
+!
+
+menuM
+    "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:#menu1
+     (Menu new fromLiteralArrayEncoding:(VersionDiffBrowser menu1)) startUp
+    "
+
+    <resource: #menu>
+
+    ^ 
+     #(#Menu
+        #(
+         #(#MenuItem
+            #label: 'Inspect'
+            #translateLabel: true
+            #value: #inspectSelectedChangeInM
+            #choiceValue: 'nil "UndefinedObject" '
+          )
+         )
+        nil
+        nil
+      )
+! !
+
+!VersionDiffBrowser class methodsFor:'startup'!
+
+openOnClass:aClass versionA:vsnA versionB:vsnB
+    |browser|
+
+    browser := self new.
+    browser allButOpen.
+
+    browser classBeingCompared:aClass.
+    browser versionA:vsnA.
+    browser versionB:vsnB.
+
+    browser openWindow.
+
+    ^ browser.
+
+    "
+     self openOnClass:Array versionA:'1.116' versionB:'1.113'
+    "
+! !
+
+!VersionDiffBrowser methodsFor:'accessing'!
+
+classBeingCompared
+    "return the value of the instance variable 'classBeingCompared' (automatically generated)"
+
+    ^ classBeingCompared!
+
+classBeingCompared:something
+    "set the value of the instance variable 'classBeingCompared' (automatically generated)"
+
+    classBeingCompared := something.
+    self updateViewsIfPossible.
+!
+
+versionA
+    "return the value of the instance variable 'versionA' (automatically generated)"
+
+    ^ versionA!
+
+versionA:something
+    "set the value of the instance variable 'versionA' (automatically generated)"
+
+    versionA := something.
+    self updateViewsIfPossible.
+
+!
+
+versionB
+    "return the value of the instance variable 'versionB' (automatically generated)"
+
+    ^ versionB!
+
+versionB:something
+    "set the value of the instance variable 'versionB' (automatically generated)"
+
+    versionB := something.
+    self updateViewsIfPossible.
+
+! !
+
+!VersionDiffBrowser methodsFor:'actions'!
+
+methodsChangedSelectionChanged
+    |sel idxA idxB changeA changeB|
+
+    sel := self methodsChangedSelection value.
+    sel notNil ifTrue:[
+        self methodsOnlyInASelection value:nil.
+        self methodsOnlyInBSelection value:nil.
+
+        idxA := indexFromChangedToA at:sel ifAbsent:nil.
+        idxB := indexFromChangedToB at:sel ifAbsent:nil.
+
+        changeA := changeSetA at:idxA.
+        changeB := changeSetB at:idxB.
+
+        self diffTextView text1:changeA source text2:changeB source.
+        self diffTextView moveToNextChanged.
+
+        self showDiffTextView.
+
+    ]
+!
+
+methodsOnlyInASelectionChanged
+    |change sel|
+
+    sel := self methodsOnlyInASelection value.
+    sel notNil ifTrue:[
+        self methodsOnlyInBSelection value:nil.
+        self methodsChangedSelection value:nil.
+
+        change := changeSetA at:sel.
+        self methodText value:(change source).    
+        self showSingleTextView.
+    ]
+!
+
+methodsOnlyInBSelectionChanged
+    |change sel|
+
+    sel := self methodsOnlyInBSelection value.
+    sel notNil ifTrue:[
+        self methodsOnlyInASelection value:nil.
+        self methodsChangedSelection value:nil.
+
+        change := changeSetB at:sel.
+        self methodText value:(change source).    
+        self showSingleTextView.
+    ]
+! !
+
+!VersionDiffBrowser methodsFor:'aspects'!
+
+changedLabelHolder
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#changedLabelHolder) isNil ifTrue:[
+        builder aspectAt:#changedLabelHolder put:(holder :=  ValueHolder new).
+    ].
+    ^ holder.
+!
+
+diffTextLabelA
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#diffTextLabelA) isNil ifTrue:[
+        builder aspectAt:#diffTextLabelA put:(holder :=  ValueHolder new).
+    ].
+    ^ holder.
+!
+
+diffTextLabelB
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#diffTextLabelB) isNil ifTrue:[
+        builder aspectAt:#diffTextLabelB put:(holder :=  ValueHolder new).
+    ].
+    ^ holder.
+!
+
+methodText
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#methodText) isNil ifTrue:[
+        builder aspectAt:#methodText put:(holder :=  ValueHolder new).
+    ].
+    ^ holder.
+!
+
+methodsChanged
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#methodsChanged) isNil ifTrue:[
+        builder aspectAt:#methodsChanged put:(holder :=  List new).
+    ].
+    ^ holder.
+!
+
+methodsChangedSelection
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#methodsChangedSelection) isNil ifTrue:[
+        builder aspectAt:#methodsChangedSelection put:(holder :=  ValueHolder new).
+    ].
+    ^ holder.
+!
+
+methodsOnlyInA
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#methodsOnlyInA) isNil ifTrue:[
+        builder aspectAt:#methodsOnlyInA put:(holder :=  List new).
+    ].
+    ^ holder.
+!
+
+methodsOnlyInASelection
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#methodsOnlyInASelection) isNil ifTrue:[
+        builder aspectAt:#methodsOnlyInASelection put:(holder :=  ValueHolder new).
+    ].
+    ^ holder.
+!
+
+methodsOnlyInB
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#methodsOnlyInB) isNil ifTrue:[
+        builder aspectAt:#methodsOnlyInB put:(holder :=  List new).
+    ].
+    ^ holder.
+!
+
+methodsOnlyInBSelection
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#methodsOnlyInBSelection) isNil ifTrue:[
+        builder aspectAt:#methodsOnlyInBSelection put:(holder :=  ValueHolder new).
+    ].
+    ^ holder.
+!
+
+onlyInALabelHolder
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#onlyInALabelHolder) isNil ifTrue:[
+        builder aspectAt:#onlyInALabelHolder put:(holder :=  ValueHolder new).
+    ].
+    ^ holder.
+!
+
+onlyInBLabelHolder
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept in the browser."
+
+    |holder|
+
+    (holder := builder bindingAt:#onlyInBLabelHolder) isNil ifTrue:[
+        builder aspectAt:#onlyInBLabelHolder put:(holder :=  ValueHolder new).
+    ].
+    ^ holder.
+! !
+
+!VersionDiffBrowser methodsFor:'initialization & release'!
+
+closeDownViews
+    "This is a hook method generated by the Browser.
+     It will be invoked when your app/dialog-window is really closed."
+
+    "/ change the code below as required ...
+    "/ This should cleanup any leftover resources
+    "/ (for example, temporary files)
+    "/ super closeRequest will initiate the closeDown
+
+    "/ add your code here
+
+    "/ do not remove the one below ...
+    ^ super closeDownViews
+!
+
+closeRequest
+    "This is a hook method generated by the Browser.
+     It will be invoked when your app/dialog-window is about to be
+     closed (and has a chance to suppress the close)."
+
+    "/ change the code below as required ...
+    "/ Closing can be suppressed, by returning.
+    "/ super closeRequest will initiate the closeDown
+
+    ^ super closeRequest
+!
+
+postBuildWith:aBuilder
+    "This is a hook method generated by the Browser.
+     It will be invoked during the initialization of your app/dialog,
+     after all of the visual components have been built, 
+     but BEFORE the top window is made visible.
+     Add any app-specific actions here (reading files, setting up
+     values etc.)"
+
+    "/ add any code here ...
+
+    (aBuilder componentAt:#TopHorizontalPanel) ignoreInvisibleComponents:true.
+
+    ^ super postBuildWith:aBuilder
+! !
+
+!VersionDiffBrowser methodsFor:'menu action'!
+
+inspectSelectedChangeInA
+    |sel|
+
+    sel := self methodsOnlyInASelection value.
+    sel notNil ifTrue:[
+        (changeSetA at:sel) inspect
+    ]
+!
+
+inspectSelectedChangeInB
+    |sel|
+
+    sel := self methodsOnlyInBSelection value.
+    sel notNil ifTrue:[
+        (changeSetB at:sel) inspect
+    ]
+!
+
+inspectSelectedChangeInM
+    |sel idxA idxB|
+
+    sel := self methodsChangedSelection value.
+    sel notNil ifTrue:[
+        idxA := indexFromChangedToA at:sel ifAbsent:nil.
+        idxB := indexFromChangedToB at:sel ifAbsent:nil.
+
+        (changeSetA at:idxA) inspect.
+        (changeSetB at:idxB) inspect.
+    ]
+! !
+
+!VersionDiffBrowser methodsFor:'private'!
+
+change:changeA isForSameMethodAs:changeB
+    "return true, if the two given changes are for the same method.
+     Ought to go to changeSet class"
+
+    changeA isMethodChange ifFalse:[^ false].   "/ for now
+    changeB isMethodChange ifFalse:[^ false].   "/ for now
+
+    changeA className ~= changeB className ifTrue:[^ false].
+    changeA selector ~= changeB selector ifTrue:[^ false].
+    ^ true.
+!
+
+change:changeA isSameAs:changeB
+    "return true, if the two given changes are the same.
+     Ought to go to changeSet class"
+
+    |sourceA sourceB|
+
+    changeA isMethodChange ifFalse:[
+        "/ A is not a methodChange - B must not be as well.
+        changeB isMethodChange ifTrue:[^ false].   
+
+        changeA isClassDefinitionChange ifTrue:[
+            changeB isClassDefinitionChange ifFalse:[^ false].  
+
+            changeA className ~= changeB className ifTrue:[^ false].
+            changeA source = changeB source ifTrue:[^ true].
+            self halt.
+        ].
+
+        ^ false   "/ for now
+    ].   
+
+    "/ A is a methodChange - B must be as well.
+    changeB isMethodChange ifFalse:[^ false].   
+
+    changeA className ~= changeB className ifTrue:[^ false].
+    changeA selector ~= changeB selector ifTrue:[^ false].
+
+    (sourceA := changeA source) = (sourceB := changeB source) ifTrue:[^ true].
+
+    sourceA := sourceA asCollectionOfLines.
+    sourceB := sourceB asCollectionOfLines.
+    sourceA size ~~ sourceB size ifTrue:[^ false].
+    sourceA := sourceA collect:[:line | line withTabsExpanded withoutTrailingSeparators].
+    sourceB := sourceB collect:[:line | line withTabsExpanded withoutTrailingSeparators].
+    sourceA = sourceB ifFalse:[^ false].
+    ^ true.
+!
+
+showDiffTextView
+    (self builder componentAt:#diffTextViewBox) raise; beVisible.
+    (self builder componentAt:#singleTextView) beInvisible.
+    (self builder componentAt:#diffTextView) realizeAllSubViews.
+!
+
+showSingleTextView
+    (self builder componentAt:#singleTextView) raise; beVisible.
+    (self builder componentAt:#diffTextViewBox) beInvisible.
+
+!
+
+updateViews
+    |mgr versionAStream versionBStream versionAChangeSet versionBChangeSet
+     allFromA filteredChangeSetA filteredChangeSetB changedMethodsChangeSet
+     listA listB listM|
+
+    mgr := classBeingCompared sourceCodeManager.
+
+    versionAStream := mgr getSourceStreamFor:classBeingCompared revision:versionA.
+    changeSetA := ChangeSet fromStream:versionAStream.
+    versionAStream close.
+
+    versionBStream := mgr getSourceStreamFor:classBeingCompared revision:versionB.
+    changeSetB := ChangeSet fromStream:versionBStream.
+    versionBStream close.
+
+    filteredChangeSetA := ChangeSet new.
+    filteredChangeSetB := ChangeSet new.
+    changedMethodsChangeSet := ChangeSet new.
+
+    indexFromChangedToA := OrderedCollection new.
+    indexFromChangedToB := OrderedCollection new.
+
+    changeSetA keysAndValuesDo:[:idxA :aChangeInA |
+        |anyFound|
+
+        anyFound := false.
+
+        changeSetB do:[:aChangeInB |
+            (self change:aChangeInA isForSameMethodAs:aChangeInB) ifTrue:[
+                anyFound := true.
+
+                "/ also in B - is it different ?
+                (self change:aChangeInA isSameAs:aChangeInB) ifFalse:[
+                    changedMethodsChangeSet add:aChangeInA.
+                    indexFromChangedToA add:idxA.
+                    indexFromChangedToB add:nil.
+                ]
+            ] ifFalse:[
+                (self change:aChangeInA isSameAs:aChangeInB) ifTrue:[
+                    anyFound := true.
+                ]
+            ]
+        ].
+
+        anyFound ifFalse:[
+            filteredChangeSetA add:aChangeInA.
+        ]
+    ].
+
+    changeSetB keysAndValuesDo:[:idxB :aChangeInB |
+        |anyFound|
+
+        anyFound := false.
+
+        changeSetA do:[:aChangeInA |
+            |idxM|
+
+            (self change:aChangeInA isForSameMethodAs:aChangeInB) ifTrue:[
+                anyFound := true.
+
+                "/ also in B - is it different ?
+                (self change:aChangeInA isSameAs:aChangeInB) ifFalse:[
+                    "/ already there ?
+                    idxM := changedMethodsChangeSet findFirst:[:c | self change:c isForSameMethodAs:aChangeInB].
+                    idxM == 0 ifTrue:[
+                        changedMethodsChangeSet add:aChangeInB.
+                        indexFromChangedToB add:idxB.
+                    ] ifFalse:[
+                        indexFromChangedToB at:idxM put:idxB
+                    ]
+                ]
+            ] ifFalse:[
+                (self change:aChangeInA isSameAs:aChangeInB) ifTrue:[
+                    anyFound := true.
+                ]
+            ]
+        ].
+        anyFound ifFalse:[
+            filteredChangeSetB add:aChangeInB.
+        ]
+    ].
+
+    listA := self methodsOnlyInA.
+    listA removeAll.
+    listA addAll:(filteredChangeSetA collect:[:c | c printString]).
+
+    listB := self methodsOnlyInB.
+    listB removeAll.
+    listB addAll:(filteredChangeSetB collect:[:c | c printString]).
+
+    listM := self methodsChanged.
+    listM removeAll.
+    listM addAll:(changedMethodsChangeSet collect:[:c | c printString]).
+
+
+    listA isEmpty ifTrue:[
+        (self builder componentAt:#BoxA) beInvisible.
+    ] ifFalse:[
+        (self builder componentAt:#BoxA) beVisible.
+    ].
+
+    listB isEmpty ifTrue:[
+        (self builder componentAt:#BoxB) beInvisible.
+    ] ifFalse:[
+        (self builder componentAt:#BoxB) beVisible.
+    ].
+
+    listM isEmpty ifTrue:[
+        (listA notEmpty or:[listB notEmpty]) ifTrue:[
+            (self builder componentAt:#BoxM) beInvisible.
+        ]
+    ] ifFalse:[
+        (self builder componentAt:#BoxM) beVisible.
+    ]
+
+!
+
+updateViewsIfPossible
+    classBeingCompared notNil ifTrue:[
+        self window label:'Version Diff Browser on ' , classBeingCompared name.
+        versionA notNil ifTrue:[
+            self diffTextLabelA value:versionA.
+            self onlyInALabelHolder value:'Only in ' , versionA.
+            versionB notNil ifTrue:[
+                self diffTextLabelB value:versionB.
+                self onlyInBLabelHolder value:'Only in ' , versionB.
+                self updateViews
+            ]
+        ]
+    ]
+
+
+! !
+
+!VersionDiffBrowser methodsFor:'values'!
+
+diffTextView
+    "automatically generated by UIPainter ..."
+
+    diffTextView isNil ifTrue:[
+        diffTextView := HVScrollableView
+                           for:DiffTextView
+                           miniScrollerH:true miniScrollerV:false.
+        diffTextView addNextPreviousButtons.
+    ].
+    ^ diffTextView
+! !
+
+!VersionDiffBrowser class methodsFor:'documentation'!
+
+version
+    ^ '$Header: /cvs/stx/stx/libtool/VersionDiffBrowser.st,v 1.1 1999-07-05 15:28:17 cg Exp $'
+! !