#REFACTORING by stefan
Sanitize BlockValues
class: Tools::Inspector2
changed: #toolbarBackgroundHolder
"{ Encoding: utf8 }"
"
COPYRIGHT (c) 2000 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:libtool' }"
"{ NameSpace: Smalltalk }"
ApplicationModel subclass:#VersionDiffBrowser
instanceVariableNames:'classChangeSet diffTextView boxAVisible boxBVisible boxMVisible
classIfSingleClassDiff versionAIfSingleClassDiff
versionBIfSingleClassDiff changedLabelHolder diffTextLabelA
diffTextLabelB methodText methodsChanged methodsChangedFiltered
methodsChangedSelection methodsOnlyInA methodsOnlyInAFiltered
methodsOnlyInASelection methodsOnlyInB methodsOnlyInBFiltered
methodsOnlyInBSelection onlyInALabelHolder onlyInBLabelHolder
classHolder versionAHolder versionBHolder infoHolder
includeExtensionsHolder canIncludeExtensionsHolder
includeCategoryChangesHolder includeVersionMethodsHolder
isMultipleVersionBrowser versionInfoList versionList
versionEntriesList selectedVersionHolder symbolicVersionList
selectedSymbolicVersionHolder symbolicToVersionMapping
filteredClasses filteredMethods filteredSelectors
classPatternFilters selectorPatternFilters
selectedVersionIndexHolder isMultipleClassesVersionBrowser
classListHolder filterChangedBefore filterChangedAfter
selectedClassIndexHolder'
classVariableNames:'RememberedFilters LastSearchString'
poolDictionaries:''
category:'Interface-Browsers'
!
HierarchicalItem subclass:#ClassChangeSet
instanceVariableNames:'class1BeingCompared class2BeingCompared labelA labelB diffSet
versionA versionB'
classVariableNames:''
poolDictionaries:''
privateIn:VersionDiffBrowser
!
Object subclass:#FilterParameters
instanceVariableNames:'filteredMethodNames filteredClassNames filteredSelectors
filteredClassNameMatchPattern filteredSelectorMatchPattern
filterChangedBefore filterChangedAfter'
classVariableNames:''
poolDictionaries:''
privateIn:VersionDiffBrowser
!
!VersionDiffBrowser class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 2000 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
"
This is not yet finished (work in progress).
A quickly hacked up browser to show differences between class versions,
allowing easy comparison; will also eventually add capabilities
to checkIn / load classes into / from the repository.
[usages:]
VersionDiffBrowser openOnAllVersionsOfClass:Array.
VersionDiffBrowser openOnAllClassesChangedSince:(Date today - 2 days) in:(Smalltalk allClasses).
VersionDiffBrowser openOnAllClassesChangedSince:(Date today - 2 days) in:(Smalltalk allClassesMatchingPackage:'exept:bridgeFramework*').
[see also:]
[instance variables:]
[class variables:]
"
! !
!VersionDiffBrowser class methodsFor:'accessing'!
rememberedFilters
RememberedFilters isNil ifTrue:[
RememberedFilters := Dictionary new.
].
^ RememberedFilters
"Created: / 08-05-2019 / 11:52:27 / Claus Gittinger"
! !
!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
uuid: '90e45ab8-7175-11e9-a23a-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: (
(HorizontalPanelViewSpec
name: 'MethodListsPanel'
uuid: '90e462a6-7175-11e9-a23a-b8f6b1108e05'
horizontalLayout: fit
verticalLayout: fit
horizontalSpace: 3
verticalSpace: 3
component:
(SpecCollection
collection: (
(ViewSpec
name: 'BoxA'
uuid: '90e46472-7175-11e9-a23a-b8f6b1108e05'
level: 0
visibilityChannel: boxAVisible
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Only in A'
name: 'OnlyInALabel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
uuid: '90e46580-7175-11e9-a23a-b8f6b1108e05'
translateLabel: true
labelChannel: onlyInALabelHolder
)
(SequenceViewSpec
name: 'ListA'
layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
uuid: '90e4672e-7175-11e9-a23a-b8f6b1108e05'
model: methodsOnlyInASelection
menu: menuAHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
doubleClickSelector: methodInADoubleClicked:
valueChangeSelector: methodsOnlyInASelectionChanged
useIndex: true
sequenceList: methodsOnlyInA
)
)
)
extent: (Point 287 197)
)
(ViewSpec
name: 'BoxM'
uuid: '90e4699a-7175-11e9-a23a-b8f6b1108e05'
visibilityChannel: boxMVisible
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Changed'
name: 'ChangedLabel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
uuid: '90e46a9e-7175-11e9-a23a-b8f6b1108e05'
translateLabel: true
labelChannel: changedLabelHolder
)
(SequenceViewSpec
name: 'ListM'
layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
uuid: '90e46bca-7175-11e9-a23a-b8f6b1108e05'
model: methodsChangedSelection
menu: menuMHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
doubleClickSelector: methodInChangedDoubleClicked:
valueChangeSelector: methodsChangedSelectionChanged
useIndex: true
sequenceList: methodsChanged
)
)
)
extent: (Point 287 197)
)
(ViewSpec
name: 'BoxB'
uuid: '90e46d6e-7175-11e9-a23a-b8f6b1108e05'
visibilityChannel: boxBVisible
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Only in B'
name: 'OnlyInBLabel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
uuid: '90e46e54-7175-11e9-a23a-b8f6b1108e05'
translateLabel: true
labelChannel: onlyInBLabelHolder
)
(SequenceViewSpec
name: 'ListB'
layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
uuid: '90e46fc6-7175-11e9-a23a-b8f6b1108e05'
model: methodsOnlyInBSelection
menu: menuBHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
doubleClickSelector: methodInBDoubleClicked:
valueChangeSelector: methodsOnlyInBSelectionChanged
useIndex: true
sequenceList: methodsOnlyInB
)
)
)
extent: (Point 288 197)
)
)
)
)
(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'
initiallyInvisible: true
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
)
)
)
)
(CodeViewSpec
name: 'singleTextView'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
uuid: '90e47674-7175-11e9-a23a-b8f6b1108e05'
model: methodText
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
isReadOnly: true
hasKeyboardFocusInitially: false
)
)
)
)
)
)
handles: (Any 0.41999999999999998 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
)
)
)
)
!
windowSpecForMultipleClasses
"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:#windowSpecForMultipleClasses
VersionDiffBrowser new openInterface:#windowSpecForMultipleClasses
"
<resource: #canvas>
^
#(FullSpec
name: windowSpecForMultipleClasses
uuid: '6c8b645e-7184-11e9-a23a-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: 'ClassAndversionAndTagPanel'
uuid: '17c6805c-7184-11e9-a23a-b8f6b1108e05'
component:
(SpecCollection
collection: (
(SequenceViewSpec
name: 'List2'
uuid: '2b3f2d20-d4fd-11e7-af82-c42c033b4871'
model: selectedClassIndexHolder
menu: classListMenu
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
useIndex: true
sequenceList: classNameListHolder
)
(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: selectedSymbolicVersionHolder
menu: symbolicVersionsMenu
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
useIndex: false
sequenceList: symbolicVersionList
)
)
)
handles: (Any 0.5 1.0)
)
)
)
handles: (Any 0.5 1.0)
)
(HorizontalPanelViewSpec
name: 'MethodListsPanel'
uuid: '2b3f3234-d4fd-11e7-af82-c42c033b4871'
horizontalLayout: fit
verticalLayout: fit
horizontalSpace: 3
verticalSpace: 3
component:
(SpecCollection
collection: (
(ViewSpec
name: 'OnlyInABox'
uuid: '2b3f3464-d4fd-11e7-af82-c42c033b4871'
level: 0
visibilityChannel: boxAVisible
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Only in A'
name: 'OnlyInALabel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
uuid: '2b3f3568-d4fd-11e7-af82-c42c033b4871'
translateLabel: true
labelChannel: onlyInALabelHolder
)
(SequenceViewSpec
name: 'ListA'
layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
uuid: '2b3f37c0-d4fd-11e7-af82-c42c033b4871'
model: methodsOnlyInASelection
menu: menuAHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
doubleClickSelector: methodInADoubleClicked:
valueChangeSelector: methodsOnlyInASelectionChanged
useIndex: true
sequenceList: methodsOnlyInA
)
)
)
extent: (Point 287 154)
)
(ViewSpec
name: 'ChangedBox'
uuid: '2b3f39a0-d4fd-11e7-af82-c42c033b4871'
visibilityChannel: boxMVisible
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Changed'
name: 'ChangedLabel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
uuid: '2b3f3a86-d4fd-11e7-af82-c42c033b4871'
translateLabel: true
labelChannel: changedLabelHolder
)
(SequenceViewSpec
name: 'ListM'
layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
uuid: '2b3f3b94-d4fd-11e7-af82-c42c033b4871'
model: methodsChangedSelection
menu: menuMHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
doubleClickSelector: methodInChangedDoubleClicked:
valueChangeSelector: methodsChangedSelectionChanged
useIndex: true
sequenceList: methodsChanged
)
)
)
extent: (Point 287 154)
)
(ViewSpec
name: 'OnlyInBBox'
uuid: '2b3f3d1a-d4fd-11e7-af82-c42c033b4871'
visibilityChannel: boxBVisible
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Only in B'
name: 'OnlyInBLabel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
uuid: '2b3f3dec-d4fd-11e7-af82-c42c033b4871'
translateLabel: true
labelChannel: onlyInBLabelHolder
)
(SequenceViewSpec
name: 'ListB'
layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
uuid: '2b3f3f04-d4fd-11e7-af82-c42c033b4871'
model: methodsOnlyInBSelection
menu: menuBHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
doubleClickSelector: methodInBDoubleClicked:
valueChangeSelector: methodsOnlyInBSelectionChanged
useIndex: true
sequenceList: methodsOnlyInB
)
)
)
extent: (Point 288 154)
)
)
)
)
(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'
initiallyInvisible: true
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
)
)
)
)
(CodeViewSpec
name: 'singleTextView'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
uuid: '2b3f4738-d4fd-11e7-af82-c42c033b4871'
model: methodText
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
isReadOnly: true
hasKeyboardFocusInitially: false
)
)
)
)
)
)
handles: (Any 0.33000000000000002 0.67000000000000004 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:VersionDiffBrowser andSelector:#windowSpecForMultipleVersions
VersionDiffBrowser new openInterface:#windowSpecForMultipleVersions
"
<resource: #canvas>
^
#(FullSpec
name: windowSpecForMultipleVersions
uuid: '70c66d08-7174-11e9-a23a-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: selectedSymbolicVersionHolder
menu: symbolicVersionsMenu
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
useIndex: false
sequenceList: symbolicVersionList
)
)
)
handles: (Any 0.5 1.0)
)
(HorizontalPanelViewSpec
name: 'MethodListsPanel'
uuid: '2b3f3234-d4fd-11e7-af82-c42c033b4871'
horizontalLayout: fit
verticalLayout: fit
horizontalSpace: 3
verticalSpace: 3
component:
(SpecCollection
collection: (
(ViewSpec
name: 'OnlyInABox'
uuid: '2b3f3464-d4fd-11e7-af82-c42c033b4871'
level: 0
visibilityChannel: boxAVisible
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Only in A'
name: 'OnlyInALabel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
uuid: '2b3f3568-d4fd-11e7-af82-c42c033b4871'
translateLabel: true
labelChannel: onlyInALabelHolder
)
(SequenceViewSpec
name: 'ListA'
layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
uuid: '2b3f37c0-d4fd-11e7-af82-c42c033b4871'
model: methodsOnlyInASelection
menu: menuAHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
doubleClickSelector: methodInADoubleClicked:
valueChangeSelector: methodsOnlyInASelectionChanged
useIndex: true
sequenceList: methodsOnlyInA
)
)
)
extent: (Point 287 152)
)
(ViewSpec
name: 'ChangedBox'
uuid: '2b3f39a0-d4fd-11e7-af82-c42c033b4871'
visibilityChannel: boxMVisible
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Changed'
name: 'ChangedLabel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
uuid: '2b3f3a86-d4fd-11e7-af82-c42c033b4871'
translateLabel: true
labelChannel: changedLabelHolder
)
(SequenceViewSpec
name: 'ListM'
layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
uuid: '2b3f3b94-d4fd-11e7-af82-c42c033b4871'
model: methodsChangedSelection
menu: menuMHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
doubleClickSelector: methodInChangedDoubleClicked:
valueChangeSelector: methodsChangedSelectionChanged
useIndex: true
sequenceList: methodsChanged
)
)
)
extent: (Point 287 152)
)
(ViewSpec
name: 'OnlyInBBox'
uuid: '2b3f3d1a-d4fd-11e7-af82-c42c033b4871'
visibilityChannel: boxBVisible
component:
(SpecCollection
collection: (
(LabelSpec
label: 'Only in B'
name: 'OnlyInBLabel'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 20 0)
uuid: '2b3f3dec-d4fd-11e7-af82-c42c033b4871'
translateLabel: true
labelChannel: onlyInBLabelHolder
)
(SequenceViewSpec
name: 'ListB'
layout: (LayoutFrame 0 0.0 20 0.0 0 1.0 -3 1.0)
uuid: '2b3f3f04-d4fd-11e7-af82-c42c033b4871'
model: methodsOnlyInBSelection
menu: menuBHolder
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
doubleClickSelector: methodInBDoubleClicked:
valueChangeSelector: methodsOnlyInBSelectionChanged
useIndex: true
sequenceList: methodsOnlyInB
)
)
)
extent: (Point 288 152)
)
)
)
)
(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'
initiallyInvisible: true
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
)
)
)
)
(CodeViewSpec
name: 'singleTextView'
layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
uuid: '2b3f4738-d4fd-11e7-af82-c42c033b4871'
model: methodText
hasHorizontalScrollBar: true
hasVerticalScrollBar: true
miniScrollerHorizontal: true
isReadOnly: true
hasKeyboardFocusInitially: false
)
)
)
)
)
)
handles: (Any 0.33000000000000002 0.67000000000000004 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
)
)
)
)
! !
!VersionDiffBrowser class methodsFor:'menu specs'!
filterMenu
"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:#filterMenu
(Menu new fromLiteralArrayEncoding:(VersionDiffBrowser filterMenu)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
label: 'Filter Classes Matching...'
itemValue: filterClassesMatching
)
(MenuItem
label: 'Filter Selectors Matching...'
itemValue: filterSelectorsMatching
)
(MenuItem
enabled: hasClassFilter
label: 'Remove Class Filter'
itemValue: removeClassFilter
)
(MenuItem
enabled: hasSelectorFilter
label: 'Remove Selector Filter'
itemValue: removeSelectorFilter
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Remember Filter As...'
itemValue: rememberFilterAs
)
(MenuItem
enabled: hasRememberedFilters
label: 'Load Filter Named...'
itemValue: loadFilterNamed
)
(MenuItem
label: '-'
)
(MenuItem
enabled: hasRememberedFilters
label: 'Export Filter Settings'
itemValue: exportFilterParameters
)
(MenuItem
label: 'Import Filter Settings From...'
itemValue: importFilterParameters
)
(MenuItem
label: '-'
)
(MenuItem
enabled: hasRememberedFilters
label: 'Forget Filter Named...'
itemValue: forgetFilterNamed
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Inspect Current Filter Settings'
itemValue: inspectFilterParameters
)
)
nil
nil
)
!
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'
submenu:
(Menu
(
(MenuItem
label: 'Create PatchFile...'
itemValue: createPatchFile
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Exit'
itemValue: closeRequest
)
)
nil
nil
)
)
(MenuItem
label: 'Class'
submenu:
(Menu
(
(MenuItem
label: 'Select Class...'
itemValue: menuSelectClass
enabled: hasNoClass
isVisible: false
)
(MenuItem
label: 'Remove from Changeset'
itemValue: menuRemoveClassFromChangeSet
enabled: showingClassChangeSet
)
)
nil
nil
)
)
(MenuItem
label: 'View'
submenuChannel: viewMenu
)
(MenuItem
label: 'Filter'
submenuChannel: filterMenu
)
(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
)
"Modified: / 05-02-2017 / 11:09:50 / cg"
"Modified: / 08-05-2019 / 11:48:05 / Claus Gittinger"
!
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: 'Apply'
#translateLabel: true
#value: #applySelectedChangeInA
#enabled: #hasChangeSelectedInA
)
#(#MenuItem
#label: 'Browse'
#translateLabel: true
#value: #browseClassInA
#enabled: #hasChangeSelectedInA
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Filter this Change'
#translateLabel: true
#value: #filterMethodInA
#enabled: #hasChangeSelectedInA
)
#(#MenuItem
#label: 'Filter Class'
#translateLabel: true
#value: #filterClassInA
#enabled: #hasChangeSelectedInA
)
#(#MenuItem
#label: 'Filter Selector'
#translateLabel: true
#value: #filterSelectorFromA
#enabled: #hasChangeSelectedInA
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Find Next Change with String...'
#translateLabel: true
#value: #findNextChangeWithStringInA
#enabled: #hasChangeSelectedInA
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Inspect'
#translateLabel: true
#value: #inspectSelectedChangeInA
#choiceValue: 'nil "UndefinedObject" '
#enabled: #hasChangeSelectedInA
)
)
nil
nil
)
"Modified: / 05-02-2017 / 11:21:54 / cg"
!
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: 'Apply'
#translateLabel: true
#value: #applySelectedChangeInB
#enabled: #hasChangeSelectedInB
)
#(#MenuItem
#label: 'Browse'
#translateLabel: true
#value: #browseClassInB
#enabled: #hasChangeSelectedInB
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Remove in Image'
#translateLabel: true
#value: #removeSelectedChangeInBFromImage
#enabled: #hasChangeSelectedInB
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Filter this Change'
#translateLabel: true
#value: #filterMethodInB
#enabled: #hasChangeSelectedInB
)
#(#MenuItem
#label: 'Filter Class'
#translateLabel: true
#value: #filterClassInB
#enabled: #hasChangeSelectedInB
)
#(#MenuItem
#label: 'Filter Selector '
#translateLabel: true
#value: #filterSelectorFromB
#enabled: #hasChangeSelectedInB
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Find Next Change with String...'
#translateLabel: true
#value: #findNextChangeWithStringInB
#enabled: #hasChangeSelectedInB
)
#(#MenuItem
#label: 'Inspect'
#translateLabel: true
#value: #inspectSelectedChangeInB
#choiceValue: 'nil "UndefinedObject" '
#enabled: #hasChangeSelectedInB
)
)
nil
nil
)
"Modified: / 05-02-2017 / 11:22:10 / cg"
"Modified: / 08-05-2019 / 13:27:06 / Claus Gittinger"
!
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: 'Browse'
#translateLabel: true
#value: #browseClassInM
#enabled: #hasChangeSelectedInM
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Apply Left Version'
#translateLabel: true
#value: #acceptInLeftView
#enabled: #hasChangeSelectedInM
)
#(#MenuItem
#label: 'Apply Right Version'
#translateLabel: true
#value: #acceptInRightView
#enabled: #hasChangeSelectedInM
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Filter this Change'
#translateLabel: true
#value: #filterMethodInM
#enabled: #hasChangeSelectedInM
)
#(#MenuItem
#label: 'Filter Class'
#translateLabel: true
#value: #filterClassInM
#enabled: #hasChangeSelectedInM
)
#(#MenuItem
#label: 'Filter Selector '
#translateLabel: true
#value: #filterSelectorFromM
#enabled: #hasChangeSelectedInM
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Find Next Change with String...'
#translateLabel: true
#value: #findNextChangeWithStringInM
#enabled: #hasChangeSelectedInM
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Inspect both'
#translateLabel: true
#value: #inspectSelectedChangeInM
#choiceValue: 'nil "UndefinedObject" '
#enabled: #hasChangeSelectedInM
)
)
nil
nil
)
"Modified: / 05-02-2017 / 11:21:44 / cg"
!
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:VersionDiffBrowser andSelector:#mainMenu
(Menu new fromLiteralArrayEncoding:(VersionDiffBrowser mainMenu)) startUp
"
<resource: #menu>
^
#(Menu
(
(MenuItem
enabled: canIncludeExtensionsHolder
label: 'Include Extensions'
itemValue: includeExtensions:
indication: includeExtensionsHolder
)
(MenuItem
enabled: canIncludeExtensionsHolder
label: 'Include Version Methods'
itemValue: includeVersionMethods:
indication: includeVersionMethodsHolder
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Include Category Changes'
itemValue: includeCategoryChanges:
indication: includeCategoryChangesHolder
)
(MenuItem
label: 'Hide Comment- and Formatting-Only Changes'
itemValue: hideDiffsWithCommentOrFormattingChangeOnlyHolder:
indication: hideDiffsWithCommentOrFormattingChangeOnlyHolder
)
(MenuItem
label: '-'
)
(MenuItem
label: 'Show Log Messages'
itemValue: showLogMessages
)
)
nil
nil
)
"Created: / 05-02-2017 / 11:06:24 / cg"
! !
!VersionDiffBrowser class methodsFor:'plugIn spec'!
aspectSelectors
"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."
"Return a description of exported aspects;
these can be connected to aspects of an embedding application
(if this app is embedded in a subCanvas)."
^ #(
#changedLabelHolder
#onlyInALabelHolder
#onlyInBLabelHolder
).
! !
!VersionDiffBrowser class methodsFor:'startup'!
openOnAllClassesChangedSince:aDateOrTimestamp in:aSetOfClasses
"create a VersionDiffBrowser instance and set the list of classes.
When a class is selected, the version list is extracted,
and the class diff set is generated from aClasses current version against
the selected version in the top selection list"
|theBrowser classesChangedSince sinceTimestamp|
sinceTimestamp := aDateOrTimestamp asTimestamp.
classesChangedSince := aSetOfClasses
select:[:cls |
cls isLoaded
and:[cls isPrivate not
and:[cls isNameSpace not
and:[cls revisionTimestamp > sinceTimestamp]]]
].
classesChangedSince sort:[:a :b | a name < b name].
theBrowser := self new.
theBrowser allButOpenInterface:#windowSpecForMultipleClasses.
theBrowser beMultipleClassesVersionBrowser.
theBrowser classList:classesChangedSince.
theBrowser setFilterChangedAfter:sinceTimestamp.
"/ theBrowser classHolder:(ValueHolder with:aClass).
"/ theBrowser setupForClass:aClass againstVersion:nil.
theBrowser window label:(self resources string:'Versions of %1 classes' with:aSetOfClasses size).
theBrowser openWindow.
^ theBrowser.
"
VersionDiffBrowser
openOnAllClassesChangedSince:(Date today - 2 days)
in:(Smalltalk allClassesMatchingPackage:'exept:bridgeFramework*').
"
"Created: / 08-05-2019 / 12:07:11 / Claus Gittinger"
"Modified: / 08-05-2019 / 13:38:22 / Claus Gittinger"
!
openOnAllVersionsOfClass:aClass
"create a VersionDiffBrowser instance and set the class change set of the
browser. The class diff set is generated from aClasses current version against
the selected version in the top selection list"
|theBrowser|
theBrowser := self new.
theBrowser allButOpenInterface:#windowSpecForMultipleVersions.
theBrowser beMultipleVersionBrowser.
theBrowser classHolder:(ValueHolder with:aClass).
theBrowser setupForClass:aClass againstVersion:nil.
theBrowser window label:(self resources string:'Versions of %1' with:aClass name).
theBrowser openWindow.
^ theBrowser.
"
self openOnAllVersionsOfClass:Object
"
"Modified: / 04-02-2017 / 19:52:33 / cg"
!
openOnAllVersionsOfClasses:aSetOfClasses
"create a VersionDiffBrowser instance and set the list of classes.
When a class is selected, the version list is extracted,
and the class diff set is generated from aClasses current version against
the selected version in the top selection list"
|theBrowser|
theBrowser := self new.
theBrowser allButOpenInterface:#windowSpecForMultipleClasses.
theBrowser beMultipleClassesVersionBrowser.
theBrowser beMultipleVersionBrowser.
theBrowser classList:aSetOfClasses.
"/ theBrowser classHolder:(ValueHolder with:aClass).
"/ theBrowser setupForClass:aClass againstVersion:nil.
theBrowser window label:(self resources string:'Versions of %1 classes' with:aSetOfClasses size).
theBrowser openWindow.
^ theBrowser.
"
self openOnAllVersionsOfClasses:(Collection withAllSubclasses)
self openOnAllVersionsOfClasses:(Smalltalk allClassesInPackage:'exept:bridgeFramework')
self openOnAllVersionsOfClasses:(Smalltalk allClassesMatchingPackage:'exept:bridgeFramework*')
"
"Created: / 08-05-2019 / 10:58:15 / Claus Gittinger"
!
openOnClass:aClass againstVersion:aVersionA
"create a VersionDiffBrowser instance and set the class change set of the
browser. The class diff set is generated from aClasses current against some version
via the source code manager."
|theBrowser|
theBrowser := self new.
theBrowser allButOpen.
theBrowser setupForClass:aClass againstVersion:aVersionA.
theBrowser window label:(self resources string:'Diffs of %1 %2 against current' with:aClass name with:aVersionA).
theBrowser openWindow.
^ theBrowser.
"
self openOnClass:Array againstVersion:'1.116'
self openOnClass:Array againstVersion:nil - against the version on which Array is based upon
self openOnClass:Array againstVersion:#newest - against the newest repository version
self openOnClass:VersionDiffBrowser againstVersion:nil
self openOnClass:VersionDiffBrowser againstVersion:#newest
(self openOnClass:ByteArray againstVersion:'1.116') includeExtensionsHolder value:true
"
"Modified: / 04-02-2017 / 19:58:16 / cg"
!
openOnClass:classA labelA:aLabelA andClass:classB labelB:aLabelB title:title
"create a VersionDiffBrowser instance and set the class change set of the
browser. The class diff set is generated from two classes."
^ self
openOnClass:classA labelA:aLabelA
andClass:classB labelB:aLabelB
title:title ifSame:nil
"
self
openOnClass:Array labelA:'Array'
andClass:Collection labelB:'Collection'
title:'Array vs. Collection'
"
"Modified (comment): / 04-02-2017 / 20:02:38 / cg"
!
openOnClass:classA labelA:aLabelA andClass:classB 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."
|classChangeSet|
classChangeSet := ClassChangeSet newForClass:classA labelA:aLabelA andClass:classB labelB:aLabelB.
classChangeSet removeAllVersionMethods.
sameAction notNil ifTrue:[
"/ check if same ...
(classChangeSet methodsOnlyInA isEmpty
and:[classChangeSet methodsOnlyInB isEmpty
and:[classChangeSet diffSet isEmpty]]) ifTrue:[
sameAction value.
^ self "/ do not open
]
].
^ self openOnClassChangeSet:classChangeSet title:title
"Modified (format): / 04-02-2017 / 19:59:16 / cg"
!
openOnClass:aClass labelA:aLabelA sourceA:aSourceA labelB:aLabelB sourceB:aSourceB
"create a VersionDiffBrowser instance and set the class change set of the
browser. The class diff set is generated from two source files."
^ self
openOnClass:aClass labelA:aLabelA sourceA:aSourceA labelB:aLabelB sourceB:aSourceB
title:nil
!
openOnClass:aClass labelA:aLabelA sourceA:aSourceA labelB:aLabelB sourceB:aSourceB title:ignoredTitle
"create a VersionDiffBrowser instance and set the class change set of the
browser. The class diff set is generated from two source files."
^ self
openOnClass:aClass labelA:aLabelA sourceA:aSourceA
labelB:aLabelB sourceB:aSourceB
title:ignoredTitle ifSame:nil
!
openOnClass:aClass labelA:aLabelA sourceA:aSourceA labelB:aLabelB sourceB:aSourceB title:ignoredTitle ifSame:sameAction
"create a VersionDiffBrowser instance and set the class change set of the
browser. The class diff set is generated from two source files."
|diffs hasChangedMethods classChangeSet versionMethodChanges|
classChangeSet := ClassChangeSet newForClass:aClass labelA:aLabelA sourceA:aSourceA labelB:aLabelB sourceB:aSourceB.
classChangeSet removeAllVersionMethods.
sameAction notNil ifTrue:[
"/ check if same ...
(classChangeSet methodsOnlyInA isEmpty
and:[classChangeSet methodsOnlyInB isEmpty]) ifTrue:[
diffs := classChangeSet diffSet.
hasChangedMethods := diffs changed notEmpty.
hasChangedMethods ifTrue:[
versionMethodChanges := diffs changed select:[:eachDifference |
|eachChange|
eachChange := eachDifference first.
(eachChange isMethodChange
and:[ (AbstractSourceCodeManager isVersionMethodSelector:eachChange changeSelector)
and:[ eachChange changeClass isMeta ]]).
].
diffs changed size == versionMethodChanges size ifTrue: [
hasChangedMethods := false.
].
"/ diffs changed size == 1 ifTrue:[
"/ theOnlyDifference := diffs changed first.
"/ theOnlyChange := theOnlyDifference first.
"/ (theOnlyChange isMethodChange
"/ and:[ ((theOnlyChange selector == #version) or:[theOnlyChange selector startsWith:'version_'])
"/ and:[ theOnlyChange changeClass isMeta ]]) ifTrue:[
"/ hasChangedMethods := false
"/ ]
"/ ]
].
(hasChangedMethods not
and:[diffs onlyInArg isEmpty
and:[diffs onlyInReceiver isEmpty]]) ifTrue:[
sameAction value.
^ self "/ do not open
].
]
].
^ self openOnClassChangeSet:classChangeSet title:ignoredTitle
"Modified: / 06-02-2017 / 02:31:51 / cg"
!
openOnClass:aClass 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 setupForClass:aClass versionA:versionA versionB:versionB.
theBrowser window label:(self resources
string:'%1 Versions %2 vs. %3'
with:aClass name with:versionA with:versionB).
theBrowser openWindow.
^ theBrowser.
"
self openOnClass:Array versionA:'1.116' versionB:'1.113'
self openOnClass:Array versionA:'1.113' versionB:'1.116'
"
!
openOnClassChangeSet:classChangeSet title:title
"create a VersionDiffBrowser instance and set the class change set of the
browser. The class diff set is generated from two classes."
|theBrowser|
theBrowser := self new.
theBrowser allButOpen.
theBrowser classChangeSet:classChangeSet.
theBrowser openWindow.
theBrowser window label:title.
^ theBrowser.
"Modified: / 04-02-2017 / 19:59:06 / cg"
!
openOnDiffSet:diffSet labelA:aLabelA labelB:aLabelB title:ignoredTitle
^ self
openOnDiffSet:diffSet
labelA:aLabelA labelB:aLabelB
title:ignoredTitle
ignoreExtensions:false
ignoreVersionMethods:false
"Modified: / 12-09-2011 / 11:52:44 / cg"
!
openOnDiffSet:diffSet labelA:aLabelA labelB:aLabelB title:ignoredTitle ignoreExtensions:ignoreExtensionsBoolean
^ self
openOnDiffSet:diffSet
labelA:aLabelA labelB:aLabelB
title:ignoredTitle
ignoreExtensions:ignoreExtensionsBoolean
ignoreVersionMethods:false
!
openOnDiffSet:diffSet labelA:aLabelA labelB:aLabelB title:ignoredTitle ignoreExtensions:ignoreExtensionsBoolean ignoreVersionMethods:ignoreVersionMethodsBoolean
|theBrowser|
theBrowser := self new.
theBrowser ignoreExtensions:ignoreExtensionsBoolean.
theBrowser ignoreVersionMethods:ignoreVersionMethodsBoolean.
theBrowser allButOpen.
theBrowser setupForDiffSet:diffSet labelA:aLabelA labelB:aLabelB.
theBrowser window label:ignoredTitle.
theBrowser openWindow.
^ theBrowser.
"Created: / 12-09-2011 / 11:50:18 / cg"
!
openOnDiffsBetweenFile:file1 and:file2
|set1 set2 diffset theBrowser|
set1 := ChangeSet fromFile:file1.
set2 := ChangeSet fromFile:file2.
diffset := set1 diffSetsAgainst:set2.
theBrowser := self new.
theBrowser allButOpen.
theBrowser setupForDiffSet:diffset labelA:file1 asFilename baseName labelB:file2 asFilename baseName.
theBrowser window label:('%1 vs. %2' bindWith:file1 asFilename baseName with:file2 asFilename baseName).
theBrowser openWindow.
^ theBrowser.
"
VersionDiffBrowser
openOnDiffsBetweenFile:'/phys/exept/tmp/ws/Workflow::BlockDescription.st'
and:'/phys/exept/tmp/workflowClasses/Workflow::BlockDescription.st'
"
! !
!VersionDiffBrowser methodsFor:'accessing'!
beMultipleClassesVersionBrowser
isMultipleClassesVersionBrowser := true
"Created: / 08-05-2019 / 10:58:32 / Claus Gittinger"
!
beMultipleVersionBrowser
isMultipleVersionBrowser := true
!
canIncludeExtensions:aBoolean
canIncludeExtensionsHolder value:aBoolean.
"Modified (format): / 08-05-2019 / 11:14:30 / Claus Gittinger"
!
changeSetA
"gets the change set which contains only the new methods
in versionA of the class
<return: ChangeSet>
"
^ self classChangeSet methodsOnlyInA
"Modified (comment): / 08-05-2019 / 11:13:50 / Claus Gittinger"
!
changeSetB
"gets the change set which contains only the new methods
in versionB of the class
<return: ChangeSet>
"
^ self classChangeSet methodsOnlyInB
"Modified (comment): / 08-05-2019 / 11:13:44 / Claus Gittinger"
!
class:aClass versionA:revA versionB:revB
classIfSingleClassDiff := aClass.
versionAIfSingleClassDiff := revA.
versionBIfSingleClassDiff := revB.
!
classBeingCompared
"returns the class from the change set which is compared.
<return: Class>
"
^ self classChangeSet classBeingCompared
"Modified (comment): / 08-05-2019 / 11:13:31 / Claus Gittinger"
!
classChangeSet
"returns the class change set which is the model of the version diff browser."
^ classChangeSet
!
classChangeSet:aClassChangeSet
"sets the class change set which is the model of the version diff browser.
The labels, the lists, the visibility and the selection of the lists must be reseted
when a new change set is given."
classChangeSet := aClassChangeSet.
self updateLabels.
self updateLists.
self resetSelectionHolders.
!
classList:aCollectionOfClasses
^ self classListHolder contents:aCollectionOfClasses
"Created: / 08-05-2019 / 11:17:13 / Claus Gittinger"
!
ignoreExtensions
"if true, extension methods are suppressed.
Ignoring is useful when comparing for baseClass checkin,
as opposed to extension-checking, where extensions should not be ignored.
the default is false"
^ self includeExtensions not
"Created: / 12-09-2011 / 11:54:11 / cg"
!
ignoreExtensions:aBoolean
"if true, extension methods are suppressed.
Ignoring is useful when comparing for baseClass checkin,
as opposed to extension-checking, where extensions should not be ignored.
the default is false"
self includeExtensions:aBoolean not
"Modified: / 06-03-2012 / 15:37:32 / cg"
!
ignoreVersionMethods:aBoolean
"if true, version methods (version and version_XXX) are suppressed.
Ignoring is useful when comparing for real code changes.
the default is false"
self includeVersionMethods:aBoolean not
"Modified: / 06-03-2012 / 15:37:32 / cg"
!
isMultipleClassesVersionBrowser
^ isMultipleClassesVersionBrowser
"Created: / 08-05-2019 / 10:58:53 / Claus Gittinger"
!
isMultipleVersionBrowser
^ isMultipleVersionBrowser
"Modified: / 08-05-2019 / 10:59:40 / Claus Gittinger"
!
selectedChangeInA
"gets the selected method change for the 'method only in version A'.
<return: MethodChange | nil>
"
|selIndex change|
selIndex := self methodsOnlyInASelection value.
selIndex notNil ifTrue:[
change := methodsOnlyInAFiltered "self changeSetA" at:selIndex.
].
^ change
"Modified (comment): / 08-05-2019 / 11:12:38 / Claus Gittinger"
!
selectedChangeInB
"gets the selected method change for the 'method only in version B'.
<return: MethodChange | nil>
"
|selIndex change|
selIndex := self methodsOnlyInBSelection value.
selIndex notNil ifTrue:[
change := methodsOnlyInBFiltered "self changeSetB" at:selIndex.
].
^ change
"Modified (comment): / 08-05-2019 / 11:12:51 / Claus Gittinger"
!
selectedChangesInM
"get the two method changes for the selected 'changed method'.
<return: <Array with:MethodChange with:MethodChange | nil>>
"
|selIndex theTwoChanges|
selIndex := self methodsChangedSelection value.
selIndex notNil ifTrue:[
theTwoChanges := methodsChangedFiltered "self classChangeSet methodsChanged" at:selIndex.
^ theTwoChanges.
].
^ #(nil nil)
"Modified (comment): / 08-05-2019 / 11:12:58 / Claus Gittinger"
!
versionA
"gets the first class version to be compared
<return: String>
"
classChangeSet isNil ifTrue:[^ 'A'].
^ classChangeSet labelA
"Modified (comment): / 08-05-2019 / 11:13:07 / Claus Gittinger"
!
versionB
"gets the second class version to be compared
<return: String>
"
classChangeSet isNil ifTrue:[^ 'B'].
^ classChangeSet labelB
"Modified (comment): / 08-05-2019 / 11:14:00 / Claus Gittinger"
! !
!VersionDiffBrowser methodsFor:'actions'!
acceptInLeftView
|change|
change := self selectedChangesInM first.
self applyChange:change
!
acceptInRightView
|change|
change := self selectedChangesInM second.
self applyChange:change
!
acceptInSingleView
|change|
change := self selectedChangeInA.
change isNil ifTrue:[
change := self selectedChangeInB
].
self applyChange:change
!
applyChange:change
change notNil ifTrue:[
change apply
]
!
applySelectedChangeInA
self applyChange:(self selectedChangeInA)
!
applySelectedChangeInB
self applyChange:(self selectedChangeInB)
!
methodInADoubleClicked:index
"/ |change|
"/
"/ change := self changeSetA at:index.
"/ self browseChange:change
self browseClassInA
!
methodInBDoubleClicked:index
"/ |change|
"/
"/ change := self changeSetB at:index.
"/ self browseChange:change
self browseClassInB
!
methodInChangedDoubleClicked:index
self browseClassInM.
!
removeSelectedChangeInBFromImage
|change cls sel op|
change := self selectedChangeInB.
change isMethodChange ifTrue:[
(cls := change changeClass) notNil ifTrue:[
(sel := change changeSelector) notNil ifTrue:[
RefactoryChangeManager notNil ifTrue:[
op := RemoveMethodChange remove:sel from:cls.
RefactoryChangeManager performChange: op.
] ifFalse:[
cls removeSelector:sel
]
]
]
]
"Modified: / 06-02-2017 / 02:31:40 / cg"
!
showLogMessages
"the UI shows code-diffs if any change is selected, and version log entries otherwise.
But there is no way to deselect any of the method-change-lists, to go back to log-messages,
once a method has been looked at.
This view-menu entry helps."
methodsOnlyInASelection value:nil.
methodsOnlyInBSelection value:nil.
methodsChangedSelection value:nil.
! !
!VersionDiffBrowser methodsFor:'aspects'!
boxAVisible
^ boxAVisible.
"Modified: / 08-05-2019 / 11:01:23 / Claus Gittinger"
!
boxBVisible
^ boxBVisible.
"Modified: / 08-05-2019 / 11:01:38 / Claus Gittinger"
!
boxMVisible
^ boxMVisible.
"Modified: / 08-05-2019 / 11:01:51 / Claus Gittinger"
!
canIncludeExtensionsHolder
"can include extensions ? (menu item enabler)"
^ canIncludeExtensionsHolder.
"Modified: / 08-05-2019 / 11:02:15 / Claus Gittinger"
!
changedLabelHolder
" aspect for the label of the changed method box"
^ changedLabelHolder.
"Modified: / 08-05-2019 / 11:02:51 / Claus Gittinger"
!
classListHolder
"aspect for the 'list of classes' list.
<return: List>"
classListHolder isNil ifTrue:[
classListHolder := List new
].
^ classListHolder
"Created: / 08-05-2019 / 11:15:52 / Claus Gittinger"
!
classNameListHolder
"aspect for the 'list of classes' list.
<return: List>"
^ BlockValue
with:[:l | l collect:#name]
argument:(self classListHolder)
"Created: / 08-05-2019 / 13:28:24 / 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"
!
hideDiffsWithCommentOrFormattingChangeOnly
^ self hideDiffsWithCommentOrFormattingChangeOnlyHolder value
"Created: / 04-02-2017 / 22:54:07 / cg"
!
hideDiffsWithCommentOrFormattingChangeOnlyHolder
"hide changes which have no semantic effect?"
^ self builder booleanValueAspectFor:#hideDiffsWithCommentOrFormattingChangeOnlyHolder
"Created: / 04-02-2017 / 16:55:12 / cg"
!
includeCategoryChanges
^ includeCategoryChangesHolder value
"Created: / 17-07-2012 / 18:22:34 / cg"
"Modified: / 08-05-2019 / 11:00:58 / Claus Gittinger"
!
includeCategoryChanges:aBoolean
includeCategoryChangesHolder value:aBoolean
"Created: / 17-07-2012 / 17:50:41 / cg"
"Modified: / 08-05-2019 / 11:01:03 / Claus Gittinger"
!
includeCategoryChangesHolder
^ includeCategoryChangesHolder.
"Modified: / 06-03-2012 / 15:36:52 / cg"
"Created: / 17-07-2012 / 16:47:58 / cg"
"Modified: / 08-05-2019 / 11:00:43 / Claus Gittinger"
!
includeExtensions
^ includeExtensionsHolder value
"Created: / 13-09-2011 / 11:48:51 / cg"
"Modified: / 08-05-2019 / 11:04:14 / Claus Gittinger"
!
includeExtensions:aBoolean
includeExtensionsHolder value:aBoolean
"Created: / 13-09-2011 / 11:48:41 / cg"
"Modified: / 08-05-2019 / 11:04:17 / Claus Gittinger"
!
includeExtensionsHolder
"only compare base-methods or include extensions ?"
^ includeExtensionsHolder.
"Modified: / 06-03-2012 / 15:36:52 / cg"
"Modified: / 08-05-2019 / 11:04:21 / Claus Gittinger"
!
includeVersionMethods
^ includeVersionMethodsHolder value
"Created: / 13-09-2011 / 11:48:51 / cg"
"Modified: / 08-05-2019 / 11:04:44 / Claus Gittinger"
!
includeVersionMethods:aBoolean
includeVersionMethodsHolder value:aBoolean
"Created: / 13-09-2011 / 11:48:41 / cg"
"Modified: / 08-05-2019 / 11:04:46 / Claus Gittinger"
!
includeVersionMethodsHolder
^ includeVersionMethodsHolder.
"Modified: / 06-03-2012 / 15:36:52 / cg"
"Created: / 17-07-2012 / 16:47:58 / cg"
"Modified: / 08-05-2019 / 11:04:50 / Claus Gittinger"
!
infoHolder
^ infoHolder.
"Modified: / 08-05-2019 / 11:05:10 / Claus Gittinger"
!
methodText
"aspect for the text in the method text view"
^ methodText.
"Modified: / 08-05-2019 / 11:05:35 / Claus Gittinger"
!
methodsChanged
"aspect for the 'changed method' list.
<return: List>"
^ methodsChanged.
"Modified: / 08-05-2019 / 11:06:09 / Claus Gittinger"
!
methodsChangedSelection
"aspect for the selection holder of 'changed method'-list.
<return: ValueHolder>"
^ methodsChangedSelection.
"Modified (comment): / 08-05-2019 / 11:06:43 / Claus Gittinger"
!
methodsOnlyInA
"aspect for the 'method only in version A' list."
^ methodsOnlyInA.
"Modified: / 25-07-2006 / 11:14:43 / cg"
"Modified: / 08-05-2019 / 11:07:12 / Claus Gittinger"
!
methodsOnlyInASelection
"aspect for the selection holder of 'method only in version A'-list."
^ methodsOnlyInASelection.
"Modified: / 25-07-2006 / 11:14:53 / cg"
"Modified: / 08-05-2019 / 11:07:36 / Claus Gittinger"
!
methodsOnlyInB
"aspect for the 'method only in version B' list"
^ methodsOnlyInB.
"Modified: / 25-07-2006 / 11:14:48 / cg"
"Modified: / 08-05-2019 / 11:07:16 / Claus Gittinger"
!
methodsOnlyInBSelection
"aspect for the selection holder of 'method only in version B'-list."
^ methodsOnlyInBSelection.
"Modified: / 25-07-2006 / 11:15:00 / cg"
"Modified: / 08-05-2019 / 11:07:40 / Claus Gittinger"
!
onlyInALabelHolder
"aspect for the label for 'method only in version A'."
^ onlyInALabelHolder.
"Modified: / 25-07-2006 / 11:15:12 / cg"
"Modified: / 08-05-2019 / 11:08:08 / Claus Gittinger"
!
onlyInBLabelHolder
"aspect for the label for 'method only in version B'."
^ onlyInBLabelHolder.
"Modified: / 25-07-2006 / 11:15:07 / cg"
"Modified: / 08-05-2019 / 11:08:12 / Claus Gittinger"
!
selectedClassIndexHolder
selectedClassIndexHolder isNil ifTrue:[
selectedClassIndexHolder := nil asValue.
selectedClassIndexHolder onChangeSend:#selectedClassIndexHolderChanged to:self.
].
^ selectedClassIndexHolder
"Created: / 08-05-2019 / 13:30:37 / Claus Gittinger"
!
selectedSymbolicVersionHolder
^ selectedSymbolicVersionHolder
"Modified: / 08-05-2019 / 11:08:42 / 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"
!
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"
! !
!VersionDiffBrowser methodsFor:'aspects-exported'!
changedLabelHolder:aValueHolder
builder aspectAt:#changedLabelHolder put:aValueHolder.
!
classHolder
classHolder isNil ifTrue:[
classHolder := ValueHolder new.
classHolder addDependent:self
].
^ classHolder
"Created: / 08-05-2019 / 13:36:50 / Claus Gittinger"
!
classHolder:aValueHolder
classHolder notNil ifTrue:[
classHolder removeDependent:self
].
classHolder := aValueHolder.
classHolder notNil ifTrue:[
classHolder addDependent:self
]
!
onlyInALabelHolder:aValueHolder
builder aspectAt:#onlyInALabelHolder put:aValueHolder.
!
onlyInBLabelHolder:aValueHolder
builder aspectAt:#onlyInBLabelHolder put:aValueHolder.
!
versionAHolder:aValueHolder
versionAHolder notNil ifTrue:[
versionAHolder removeDependent:self
].
versionAHolder := aValueHolder.
versionAHolder notNil ifTrue:[
versionAHolder addDependent:self
]
!
versionBHolder:aValueHolder
versionBHolder notNil ifTrue:[
versionBHolder removeDependent:self
].
versionBHolder := aValueHolder.
versionBHolder notNil ifTrue:[
versionBHolder addDependent:self
]
! !
!VersionDiffBrowser methodsFor:'aspects-menu'!
canAcceptInCodeView
^ self hasChangeSelectedInA
or:[self hasChangeSelectedInB
or:[self hasChangeSelectedInM]]
!
hasChangeSelectedInA
^ self selectedChangeInA notNil
!
hasChangeSelectedInB
^ self selectedChangeInB notNil
!
hasChangeSelectedInM
^ self methodsChangedSelection value notNil
!
hasClassFilter
^ classPatternFilters notEmptyOrNil
"Created: / 08-05-2019 / 11:50:12 / Claus Gittinger"
!
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"
!
hasRememberedFilters
^ RememberedFilters notEmptyOrNil
"Created: / 08-05-2019 / 11:54:31 / Claus Gittinger"
!
hasSelectorFilter
^ selectorPatternFilters notEmptyOrNil
"Created: / 08-05-2019 / 11:50:46 / Claus Gittinger"
!
showingClassChangeSet
^ classChangeSet notNil
"Created: / 05-02-2017 / 11:09:18 / cg"
!
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"
! !
!VersionDiffBrowser methodsFor:'change & update'!
filterChanged
self withExecuteCursorDo:[
|listA listB listM selA selB selM posA posB posM|
"/ remember selection and scroll positions
listA := (self componentAt:'ListA') scrolledView.
listB := (self componentAt:'ListB') scrolledView.
listM := (self componentAt:'ListM') scrolledView.
selA := listA selection.
selB := listB selection.
selM := listM selection.
posA := listA firstLineShown.
posB := listB firstLineShown.
posM := listM firstLineShown.
self updateLists.
self enqueueDelayedAction:
[
selA notNil ifTrue:[
listA selection:selA
] ifFalse:[
listA scrollToLine:posA
].
selB notNil ifTrue:[
listB selection:selB
] ifFalse:[
listB scrollToLine:posB
].
selM notNil ifTrue:[
listM selection:selM
] ifFalse:[
listM scrollToLine:posM
].
].
].
"Created: / 05-02-2017 / 10:19:41 / cg"
"Modified (format): / 14-03-2017 / 16:30:58 / cg"
!
methodsChangedSelectionChanged
"the selection in the list of the 'changed methods' changed.
Reset the selection of the two other lists and calc the method change.
<return: self>"
|sel changeA changeB methodsChanged|
"/ self information:''.
sel := self methodsChangedSelection value.
sel notNil ifTrue:[
self methodsOnlyInASelection value:nil.
self methodsOnlyInBSelection value:nil.
methodsChanged := self classChangeSet methodsChanged.
changeA := (methodsChangedFiltered at:sel) first.
changeB := (methodsChangedFiltered at:sel) second.
self withReadCursorDo:[
|info|
info := self shortChangeInfoFor:changeA and:changeB.
info notNil ifTrue:[
self infoHolder value:info
].
self diffTextView
text1:(changeA prettyPrintedSource)
text2:(changeB prettyPrintedSource)
].
self showDiffTextView.
self diffTextView moveToNextChangedAfter:1
] ifFalse:[
self showVersionInfoIfNothingSelected
]
"Modified: / 03-09-1999 / 15:01:30 / ps"
"Modified: / 29-11-2017 / 12:56:28 / cg"
"Modified: / 23-07-2018 / 09:51:12 / Claus Gittinger"
"Modified (format): / 13-03-2019 / 10:39:33 / Claus Gittinger"
!
methodsOnlyInASelectionChanged
"the selection in the list of the 'method only in version A' changed.
Reset the selection of the two other lists and show the method in
the text view.
<return: self>"
|change sel versionA|
"/ self information:''.
sel := self methodsOnlyInASelection value.
sel notNil ifTrue:[
self methodsOnlyInBSelection value:nil.
self methodsChangedSelection value:nil.
change := methodsOnlyInAFiltered "self changeSetA" at:sel.
self methodText value:(change prettyPrintedSource).
self showSingleTextView.
(versionA := diffTextLabelA value) notEmptyOrNil ifTrue:[
self infoHolder value:('Method removed from version: ',versionA).
].
] ifFalse:[
self showVersionInfoIfNothingSelected
].
"Modified: / 05-02-2017 / 12:08:07 / cg"
"Modified: / 13-03-2019 / 10:48:17 / Claus Gittinger"
!
methodsOnlyInBSelectionChanged
"the selection in the list of the 'method only in version B' changed.
Reset the selection of the two other lists and show the method in
the text view.
<return: self>"
|change sel versionA|
"/ self information:''.
sel := self methodsOnlyInBSelection value.
sel notNil ifTrue:[
self methodsOnlyInASelection value:nil.
self methodsChangedSelection value:nil.
change := methodsOnlyInBFiltered "self changeSetB" at:sel.
self methodText value:(change prettyPrintedSource).
self showSingleTextView.
(versionA := diffTextLabelA value) notEmptyOrNil ifTrue:[
self infoHolder value:('Method added to version: ',versionA).
].
] ifFalse:[
self showVersionInfoIfNothingSelected
].
"Modified: / 05-02-2017 / 11:49:22 / cg"
"Modified: / 13-03-2019 / 10:48:23 / Claus Gittinger"
!
selectedClassIndexHolderChanged
|cls|
cls := self classListHolder value at:(self selectedClassIndexHolder value).
self classHolder value:cls.
(self isMultipleVersionBrowser or:[self isMultipleClassesVersionBrowser]) ifTrue:[
self withWaitCursorDo:[
self updateVersionList.
]
]
"Created: / 08-05-2019 / 13:33:07 / Claus Gittinger"
!
selectedSymbolicVersionHolderChanged
|symbolicTag version|
symbolicTag := self selectedSymbolicVersionHolder value.
version := symbolicToVersionMapping at:symbolicTag ifAbsent:nil.
version isNil ifTrue:[
Dialog warn:'no version has this tag'.
^ self.
].
self selectedVersionHolder value:version
"Modified: / 08-05-2019 / 14:38:53 / Claus Gittinger"
!
selectedVersionHolderChanged
self withWaitCursorDo:[
|idx prevSelectionIndexA prevSelectionIndexB prevSelectionIndexDifferent
previousChange previousClass previousSelector|
"/ remember the previous selected method
(prevSelectionIndexA := methodsOnlyInASelection value) notNil ifTrue:[
previousChange := methodsOnlyInAFiltered at:prevSelectionIndexA.
].
(prevSelectionIndexB := methodsOnlyInBSelection value) notNil ifTrue:[
previousChange := methodsOnlyInBFiltered at:prevSelectionIndexB.
].
(prevSelectionIndexDifferent := methodsChangedSelection value) notNil ifTrue:[
previousChange := (methodsChangedFiltered at:prevSelectionIndexDifferent) first.
].
previousChange notNil ifTrue:[
previousClass := previousChange className.
previousSelector := previousChange changeSelector.
].
"/ possibly expand a contracted list
selectedVersionHolder value = '...' ifTrue:[
idx := self versionList size.
self updateVersionList.
selectedVersionHolder setValue:(self versionList at:idx).
].
"/ update the view
self
setupForClass:classHolder value
againstVersion:(selectedVersionHolder value).
"/ try to reselect the same method again.
previousChange notNil ifTrue:[
"/ search a change for that in the three lists
(idx := methodsChangedFiltered findFirst:[:entry | entry first className = previousClass
and:[ entry first changeSelector = previousSelector]]) ~= 0
ifTrue:[
methodsChangedSelection value:idx. self methodsChangedSelectionChanged.
] ifFalse:[
(idx := methodsOnlyInAFiltered findFirst:[:chg | chg className = previousClass
and:[ chg changeSelector = previousSelector]]) ~= 0
ifTrue:[
methodsOnlyInASelection value:idx. self methodsOnlyInASelectionChanged
] ifFalse:[
(idx := methodsOnlyInBFiltered findFirst:[:chg | chg className = previousClass
and:[ chg changeSelector = previousSelector]]) ~= 0
ifTrue:[
methodsOnlyInBSelection value:idx. self methodsOnlyInBSelectionChanged.
]
]
].
].
self showVersionInfoIfNothingSelected
]
"Modified: / 06-02-2017 / 02:32:24 / cg"
!
selectedVersionIndexHolderChanged
self selectedVersionHolder value:(versionList at:self selectedVersionIndexHolder value)
"Created: / 29-11-2017 / 13:04:12 / cg"
!
shortChangeInfoFor:changeA and:changeB
|parseError treeA treeB sameSuperClass sameClassName sameInstVars sameClassVars samePools sameCategory append info|
"/ see if the semantics have changed (or only prettyPrinted)
RBParser notNil ifTrue:[
(classChangeSet notNil
and:[ classChangeSet classBeingCompared notNil ]) ifTrue:[
parseError := false.
changeA isMethodChange ifTrue:[
changeB isMethodChange ifFalse:[^ 'Different change types'].
treeA := RBParser parseMethod:(changeA source) onError: [:str :pos | parseError := true].
treeB := RBParser parseMethod:(changeB source) onError: [:str :pos | parseError := true].
parseError ifFalse:[
(treeA equalTo:treeB withMapping:(Dictionary new)) ifTrue:[
^ 'Methods only differ in formatting / comments'.
].
(treeA semanticallyEqualTo:treeB withMapping:(Dictionary new)) ifTrue:[
^ 'Methods seem to do the same'.
].
^ 'Methods are different'.
].
self infoHolder value:'ParseError while comparing - please check the code'.
^ nil
].
changeA isClassDefinitionChange ifTrue:[
changeB isClassDefinitionChange ifFalse:[^ 'Different change types'].
treeA := RBParser parseExpression:(changeA source) onError: [:str :pos | parseError := true].
treeB := RBParser parseExpression:(changeB source) onError: [:str :pos | parseError := true].
(treeA semanticallyEqualTo:treeB withMapping:(Dictionary new)) ifTrue:[
^ 'Class definitions seem to do the same'.
].
sameSuperClass := treeA receiver = treeB receiver.
sameClassName := treeA arg1 = treeB arg1.
sameInstVars := treeA arg2 = treeB arg2.
sameClassVars := treeA arg3 = treeB arg3.
samePools := (treeA arg:4) = (treeB arg:4).
sameCategory := (treeA arg:5) = (treeB arg:5).
info := ''.
append := [:s | info := info isEmpty ifTrue:[s] ifFalse:[info,', ',s]].
sameSuperClass ifFalse:[
append value:'Superclass'.
].
sameClassName ifFalse:[
append value:'Name'.
].
sameInstVars ifFalse:[
append value:'Instvars'.
].
sameClassVars ifFalse:[
append value:'Classvars'.
].
samePools ifFalse:[
append value:'SharedPools'.
].
sameCategory ifFalse:[
append value:'Category'.
].
info notEmpty ifTrue:[ ^ 'different ',info ].
^ 'Class definitions are different.'.
].
changeA isClassCommentChange ifTrue:[
changeB isClassCommentChange ifFalse:[^ 'Different change types'].
changeA comment = changeB comment ifFalse:[^ 'Different class comment'].
^ 'Same comment'.
].
changeA isPrimitiveChange ifTrue:[
changeB isPrimitiveChange ifFalse:[^ 'Different change types'].
(changeA sameAs:changeB) ifFalse:[^ 'Different class primitive'].
^ 'Same primitive'.
].
].
].
^ nil
"Modified: / 09-04-2018 / 12:21:27 / stefan"
!
update:something with:parameter from:changedObject
((changedObject == includeExtensionsHolder)
or:[ changedObject == includeCategoryChangesHolder
or:[ changedObject == includeVersionMethodsHolder ]]) ifTrue:[
self updateLists.
^ self
].
(changedObject == classHolder
or:[changedObject == versionAHolder
or:[changedObject == versionBHolder]]) ifTrue:[
self setupForClass:(classHolder value) versionA:(versionAHolder value) versionB:(versionBHolder value).
^ self
].
super update:something with:parameter from:changedObject
"Modified: / 17-07-2012 / 17:48:58 / cg"
!
updateLabels
"update the labels of the diff text view. Show the version numbers
of the class."
|theVersionA theVersionB builder makeLabel|
makeLabel :=
[:theVersion |
|label date author revInfo|
label := theVersion.
versionInfoList notNil ifTrue:[
revInfo := versionInfoList detect:[:info | (info at:#revision) = theVersion] ifNone:nil.
revInfo notNil ifTrue:[
date := (Timestamp readGeneralizedFrom:(revInfo at:#date)) asDate.
author := (revInfo at:#author) ? '?'.
label := theVersion , ' [',date printString,' by ',author,']'.
].
].
label
].
builder := self builder.
(theVersionA := self versionA) notNil ifTrue:[
self diffTextLabelA value:(makeLabel value:theVersionA).
self onlyInALabelHolder value:('Only in ' , theVersionA).
(self componentAt:#OnlyInALabel)
foregroundColor:Color white;
backgroundColor:Color darkGreen.
].
(theVersionB :=self versionB) notNil ifTrue:[
self diffTextLabelB value:(makeLabel value:theVersionB).
self onlyInBLabelHolder value:('Only in ' , theVersionB).
(self componentAt:#OnlyInBLabel)
foregroundColor:Color white;
backgroundColor:Color darkRed.
].
self changedLabelHolder value:('Different').
"Modified: / 13-10-2006 / 01:07:08 / cg"
"Modified: / 13-03-2019 / 21:19:13 / 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 isIgnored1 isIgnored2 isIgnored3 isIgnored4 isIgnored5|
printStringGenerator := [:aChange | self printStringForChange:aChange].
"/ sortBlockForChangeLists := [:a :b | (printStringGenerator value:a) < (printStringGenerator value:b)].
numIgnoredExtensions := numIgnoredVersionMethods := 0.
needFilter := self includeExtensions not
or:[self includeCategoryChanges not
or:[self includeVersionMethods not]].
needFilter ifTrue:[
isIgnoredChange :=
[:change |
|packageOfMethodInChange packageOfMethodInImage changeMethod ignored|
ignored := false.
change isMethodCodeChange ifTrue:[
self includeExtensions ifFalse:[
packageOfMethodInChange := change package.
(packageOfMethodInChange notNil
and:[ packageOfMethodInChange ~= PackageId noProjectID
and:[ change changeClass notNil
and:[ packageOfMethodInChange ~= change changeClass package ]]]) ifTrue:[
ignored := true
].
changeMethod := change changeMethod.
changeMethod notNil ifTrue:[
packageOfMethodInImage := changeMethod package.
(true "packageOfMethodInImage notNil"
and:[ packageOfMethodInImage ~= PackageId noProjectID
and:[ packageOfMethodInImage ~= changeMethod mclass package ]]) ifTrue:[
ignored := true
].
].
numIgnoredExtensions := numIgnoredExtensions + (ignored ifTrue:[1] ifFalse:[0]).
].
self includeVersionMethods ifFalse:[
(change isMethodChangeForVersionMethod
or:[ change isMethodChangeForExtensionsVersionMethod ]) ifTrue:[
ignored := true.
numIgnoredVersionMethods := numIgnoredVersionMethods + 1
].
].
] ifFalse:[
change isMethodCategoryChange ifTrue:[
self includeCategoryChanges ifFalse:[
ignored := true
]
].
].
ignored.
].
] ifFalse:[
isIgnoredChange := [:change | false].
].
filteredClasses notEmptyOrNil ifTrue:[
isIgnored1 := isIgnoredChange.
isIgnoredChange :=
[:change |
(isIgnored1 value:change)
or:[
filteredClasses includes:change nonMetaClassName
]
].
].
filteredSelectors notEmptyOrNil ifTrue:[
isIgnored2 := isIgnoredChange.
isIgnoredChange :=
[:change |
(isIgnored2 value:change)
or:[ filteredSelectors includes:change changeSelector ]
].
].
filteredMethods notEmptyOrNil ifTrue:[
isIgnored3 := isIgnoredChange.
isIgnoredChange :=
[:change |
(isIgnored3 value:change)
or:[
filteredMethods contains:[:filter |
|filterSelector filterClassName|
"/ migration - will be always an assoc
filter isAssociation ifTrue:[
filterClassName := filter key.
filterSelector := filter value.
] ifFalse:[
filterClassName := filter className.
filterSelector := filter changeSelector.
].
((change className = filterClassName)
and:[change changeSelector = filterSelector])
]
]
].
].
classPatternFilters notEmptyOrNil ifTrue:[
isIgnored4 := isIgnoredChange.
isIgnoredChange :=
[:change |
(isIgnored4 value:change)
or:[
classPatternFilters contains:[:pattern | pattern match:change nonMetaClassName]
]
].
].
selectorPatternFilters notEmptyOrNil ifTrue:[
isIgnored5 := isIgnoredChange.
isIgnoredChange :=
[:change |
(isIgnored5 value:change)
or:[
selectorPatternFilters contains:[:pattern | pattern match:change changeSelector]
]
].
].
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.
info := '%1 changed, %2 added, %3 removed%4'
bindWith:methodsChangedFiltered size
with:methodsOnlyInB size
with:methodsOnlyInA size
with:(isIgnoredChange isNil
ifTrue:['']
ifFalse:[' (filtered)']).
numIgnoredExtensions ~~ 0 ifTrue:[
info := info , ('; %1 extension methods ignored. ' bindWith:numIgnoredExtensions).
].
numIgnoredVersionMethods ~~ 0 ifTrue:[
info := info , ('; %1 version methods ignored.' bindWith:numIgnoredVersionMethods).
].
self information:info
"Modified (comment): / 06-02-2017 / 10:09:11 / cg"
"Modified (format): / 16-02-2017 / 11:11:49 / stefan"
!
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."
|cls sourceCodeManager numShown newNumShown numOverallRevisions
partialLog newestRev revisions revisionEntries symbolicNames
stableRevision releasedRevision tagList logMessages|
cls := classHolder value.
cls isNil ifTrue:[
self symbolicVersionList contents:#().
self versionList contents:#().
self versionEntriesList contents:#().
^ self
].
sourceCodeManager := cls sourceCodeManager.
numShown := versionList size - 1.
newNumShown := (numShown + 50) max:30.
partialLog := sourceCodeManager revisionLogOf:cls numberOfRevisions:newNumShown.
partialLog isNil ifTrue:[
self warn:'Could not find/access the container for class ',cls 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 | a key < b key "self versionString:(a value) isLessThan:(b value)"])
collect:[:assoc | assoc key]) reverse.
tagList remove:'stable' ifAbsent:[].
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:(
'%1 (by %2 at %3)'
bindWith:(eachVersionInfo revision)
with:(eachVersionInfo user)
with:(eachVersionInfo date)).
].
revisions size < numOverallRevisions ifTrue:[
revisions add:'...'.
revisionEntries add:'...'.
].
symbolicToVersionMapping := symbolicNames.
self symbolicVersionList contents:tagList.
self versionList contents:revisions.
self versionEntriesList contents:revisionEntries.
"Modified: / 29-11-2017 / 13:06:21 / cg"
"Modified: / 08-05-2019 / 11:18:30 / Claus Gittinger"
! !
!VersionDiffBrowser methodsFor:'initialization & release'!
initialize
super initialize.
isMultipleVersionBrowser := false.
isMultipleClassesVersionBrowser := false.
onlyInALabelHolder := ValueHolder new.
onlyInBLabelHolder := ValueHolder new.
changedLabelHolder := ValueHolder new.
diffTextLabelA := ValueHolder new.
diffTextLabelB := ValueHolder new.
infoHolder := ValueHolder new.
methodText := ValueHolder new.
methodsChanged := List new.
methodsOnlyInA := List new.
methodsOnlyInB := List new.
methodsChangedSelection := ValueHolder new.
methodsOnlyInASelection := ValueHolder new.
methodsOnlyInBSelection := ValueHolder new.
boxAVisible := true asValue.
boxBVisible := true asValue.
boxMVisible := true asValue.
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.
versionEntriesList := List new.
versionList := List new.
canIncludeExtensionsHolder := true asValue.
includeCategoryChangesHolder := true asValue.
includeCategoryChangesHolder addDependent:self.
includeExtensionsHolder := false asValue.
includeExtensionsHolder addDependent:self.
includeVersionMethodsHolder := true asValue.
includeVersionMethodsHolder addDependent:self.
"Created: / 08-05-2019 / 10:59:30 / Claus Gittinger"
"Modified: / 08-05-2019 / 13:31:36 / Claus Gittinger"
!
postBuildWith:aBuilder
"
components which are invisible should be ignored by the panel.
Cannot be set via the interface builder.
<return: self>
"
(self componentAt:#MethodListsPanel) ignoreInvisibleComponents:true.
super postBuildWith:aBuilder
"Modified: / 08-05-2019 / 11:38:34 / Claus Gittinger"
!
postOpenWith:aBuilder
super postOpenWith:aBuilder.
self isMultipleVersionBrowser ifTrue:[
self withWaitCursorDo:[
self updateVersionList.
]
]
! !
!VersionDiffBrowser methodsFor:'menu action'!
browseChange:aChange
"browse the change in aChange"
|cls sel|
aChange isNil ifTrue:[^ self].
cls := aChange changeClass.
cls isNil ifTrue:[
Dialog information:'The class is not present in the image'.
^ self
].
aChange isMethodChange ifTrue:[
sel := aChange changeSelector.
"/ (cls compiledMethodAt:sel) isNil ifTrue:[
"/ (self confirm:'Method does not exist.\\Browse Class ?' withCRs) ifTrue:[
"/ browserClass openInClass:cls
"/ ].
"/ sel := nil.
"/ ]
].
self withWaitCursorDo:[
SystemBrowser default openInClass:cls selector:sel.
]
"Modified (format): / 01-09-2017 / 14:23:56 / cg"
!
browseClassInA
"browse the selected method."
self browseChange:(self selectedChangeInA).
"Modified: / 25-07-2006 / 11:14:02 / cg"
!
browseClassInB
"browse the selected method."
self browseChange:(self selectedChangeInB).
"Modified: / 25-07-2006 / 11:13:58 / cg"
!
browseClassInM
"browse the selected method."
self browseChange:(self selectedChangesInM first).
"Modified: / 25-07-2006 / 11:13:54 / cg"
!
createPatchFile
"create a patchFile, to patch the old version (versionA) into the new version (versionB).
I.e. a little changeFile to transport those changes."
|defaultName diffSet f oldVersion newVersion vsnMthdA vsnMthdB vsnA vsnB info classBeingCompared|
classChangeSet isNil ifTrue:[
self warn:'No changes'.
^ self
].
self warn:'Sorry: This function is not yet implemented'.
defaultName := 'patchFile.chg'.
classBeingCompared := classChangeSet classBeingCompared.
defaultName := '%1-%2-to-%3.chg'
bindWith:(classBeingCompared isNil ifTrue:['unknown'] ifFalse:[classBeingCompared nameWithoutPrefix])
with:(classChangeSet versionA ? 'old')
with:(classChangeSet versionB ? 'new').
f := Dialog
requestFileNameForSave:'Name of patchFile:'
default:defaultName.
self halt.
diffSet := classChangeSet diffSet.
^ self.
"/ vsnMthdA := self changeSetA
"/ detect:[:ch | ch isMethodChange
"/ and:[ch changeClass isMeta
"/ and:[ch changeSelector = #version]]]
"/ ifNone:nil.
"/ vsnMthdB := self changeSetA
"/ detect:[:ch | ch isMethodChange
"/ and:[ch changeClass isMeta
"/ and:[ch changeSelector = #version]]]
"/ ifNone:nil.
"/
"/ vsnMthdA notNil ifTrue:[
"/ "/ extract the version
"/ vsnA := Class revisionStringFromSource:vsnMthdA source.
"/ vsnA notNil ifTrue:[
"/ info := Class revisionInfoFromString:vsnA.
"/ info notNil ifTrue:[
"/ vsnA := info at:#revision ifAbsent:nil.
"/ ] ifFalse:[
"/ vsnA := nil.
"/ ].
"/ ].
"/ ].
"/ vsnMthdB notNil ifTrue:[
"/ "/ extract the version
"/ vsnB := Class revisionStringFromSource:vsnMthdB source.
"/ vsnB notNil ifTrue:[
"/ info := Class revisionInfoFromString:vsnB.
"/ info notNil ifTrue:[
"/ vsnB := info at:#revision ifAbsent:nil.
"/ ] ifFalse:[
"/ vsnB := nil.
"/ ].
"/ ].
"/ ].
"/
"/ (vsnA isNil or:[vsnB isNil or:[vsnA = vsnB]]) ifTrue:[
"/ self warn:'The generated patch file will not be able to validate/update the class version'.
"/ ].
"/
"/self halt:'not yet finished'.
"Modified: / 27-10-2010 / 11:34:58 / cg"
"Modified (format): / 08-05-2019 / 11:48:57 / Claus Gittinger"
!
hideDiffsWithCommentOrFormattingChangeOnlyHolder:newValue
"state of hide changes which have no semantic effect has changed"
self updateLists.
"Created: / 04-02-2017 / 19:50:51 / cg"
"Modified: / 04-02-2017 / 23:14:45 / cg"
!
inspectSelectedChangeInA
"inspect the selected method change for the 'method only in version A'."
self selectedChangeInA inspect.
"Modified: / 25-07-2006 / 11:13:30 / cg"
!
inspectSelectedChangeInB
"inspect the selected method change for the 'method only in version B'."
self selectedChangeInB inspect.
"Modified: / 25-07-2006 / 11:13:22 / cg"
!
inspectSelectedChangeInM
"inspect the two method changes for the selected 'changed method'."
|changes|
changes := self selectedChangesInM.
changes do:[:change |
change inspect
].
"Modified: / 25-07-2006 / 11:13:13 / cg"
!
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"
!
menuRemoveClassFromChangeSet
|cls ok changedClasses|
classChangeSet notNil ifTrue:[
"/ only do if we compare a single class
(cls := classChangeSet classBeingCompared) notNil ifTrue:[
ok := classChangeSet diffSet isEmptyOrNil.
ok ifFalse:[
changedClasses := classChangeSet diffSet changedClasses.
(changedClasses size == 1
and:[ changedClasses anElement theNonMetaclass == cls theNonMetaclass]) ifTrue:[
(methodsChangedFiltered isEmptyOrNil
and:[ methodsOnlyInAFiltered isEmptyOrNil
and:[ methodsOnlyInBFiltered isEmptyOrNil ]]) ifTrue:[
ok := true.
]
]
].
ok ifTrue:[
ChangeSet current condenseChangesForClass:cls
].
].
].
"Created: / 08-05-2019 / 11:35:37 / Claus Gittinger"
!
menuSelectClass
"let user choose a class to be shown"
|cls|
cls := Dialog requestClass:'Class to show versions'.
cls isNil ifTrue:[^ self].
self classHolder:(cls asValue).
classHolder changed.
"Created: / 08-05-2019 / 11:44:00 / Claus Gittinger"
!
openDocumentation
HTMLDocumentView openFullOnDocumentationFile:'tools/misc/TOP.html#VERSIONDIFF'
!
versionMenuCompareAgainstNextVersion
|cls selectedVersion nextVersion|
selectedVersion := self selectedVersionHolder value.
nextVersion := self versionList at:(self selectedVersionIndex - 1).
cls := classHolder value.
self class openOnClass:cls versionA:selectedVersion versionB:nextVersion
"Modified: / 23-05-2018 / 11:37:18 / Claus Gittinger"
!
versionMenuCompareAgainstPreviousVersion
|cls selectedVersion prevVersion|
selectedVersion := self selectedVersionHolder value.
selectedVersion isNil ifTrue:[
self selectedVersionIndexHolder value:1
].
prevVersion := self versionList at:(self selectedVersionIndex + 1).
cls := classHolder value.
self class openOnClass:cls versionA:prevVersion versionB:selectedVersion
"Modified: / 23-05-2018 / 11:38:13 / Claus Gittinger"
! !
!VersionDiffBrowser methodsFor:'menu action - filters'!
currentFilterParameters
"get the current settings"
|filterParameters|
"/ migration - will be removed
filteredMethods notEmptyOrNil ifTrue:[
filteredMethods := filteredMethods
collect:[:filter |
filter isAssociation ifTrue:[
filter.
] ifFalse:[
filter className ->filter changeSelector.
].
].
].
filterParameters := FilterParameters new.
filterParameters filteredClassNameMatchPattern:classPatternFilters.
filterParameters filteredSelectorMatchPattern:selectorPatternFilters.
filterParameters filteredClassNames:filteredClasses.
filterParameters filteredMethodNames:filteredMethods.
filterParameters filteredSelectors:filteredSelectors.
filterParameters filterChangedBefore:filterChangedBefore.
filterParameters filterChangedAfter:filterChangedAfter.
^ filterParameters.
"Created: / 06-02-2017 / 09:20:07 / cg"
"Modified: / 08-05-2019 / 13:19:46 / Claus Gittinger"
!
exportFilterParameters
"generate XML with the current settings
(to be pasted into Jabber for interchange)"
|filterParameters|
XMLStandardCoder isNil ifTrue:[
Smalltalk loadPackage:'stx:goodies/xml/stx'.
].
filterParameters := self currentFilterParameters.
Workspace
openWith:(XMLStandardCoder encode:filterParameters)
title:'Current Filter'
"Created: / 06-02-2017 / 09:19:52 / cg"
"Modified: / 08-05-2019 / 11:56:31 / Claus Gittinger"
!
filterClassInA
"filter all changes for the selected change's class (don't show it)."
filteredClasses isNil ifTrue:[
filteredClasses := Set new.
].
filteredClasses add:(self selectedChangeInA nonMetaClassName).
self filterChanged.
"Created: / 05-02-2017 / 10:17:22 / cg"
"Modified: / 05-02-2017 / 11:19:05 / cg"
"Modified (comment): / 06-02-2017 / 09:13:23 / cg"
!
filterClassInB
"filter all changes for the selected change's class (don't show it)."
filteredClasses isNil ifTrue:[
filteredClasses := Set new.
].
filteredClasses add:(self selectedChangeInB nonMetaClassName).
self filterChanged.
"Created: / 05-02-2017 / 10:16:45 / cg"
"Modified: / 05-02-2017 / 11:19:02 / cg"
"Modified (comment): / 06-02-2017 / 09:13:29 / cg"
!
filterClassInM
"filter all changes for the selected change's class (don't show it)."
filteredClasses isNil ifTrue:[
filteredClasses := Set new.
].
filteredClasses add:(self selectedChangesInM first nonMetaClassName).
self filterChanged.
"Created: / 05-02-2017 / 10:38:06 / cg"
"Modified (comment): / 06-02-2017 / 09:13:33 / cg"
!
filterClassesMatching
"ask for a GLOB pattern;
filter all changes with matching classnames ."
|pattern|
pattern := Dialog request:'Matchpattern for Classname Filter (will hide changes with matching classes):'.
pattern isEmptyOrNil ifTrue:[^ self].
classPatternFilters isNil ifTrue:[
classPatternFilters := OrderedCollection new.
].
classPatternFilters add:pattern.
self filterChanged
"Created: / 05-02-2017 / 11:11:42 / cg"
"Modified: / 06-02-2017 / 09:18:15 / cg"
!
filterMethod:aChange
"filter this change (don't show it)."
filteredMethods isNil ifTrue:[
filteredMethods := Set new.
].
aChange isMethodChange ifTrue:[
filteredMethods add:(aChange className -> aChange changeSelector).
] ifFalse:[
].
self filterChanged.
"Created: / 06-02-2017 / 08:58:17 / cg"
!
filterMethodInA
"filter this entry (don't show it)."
self filterMethod:(self selectedChangeInA)
"Created: / 05-02-2017 / 10:11:48 / cg"
"Modified: / 06-02-2017 / 08:58:38 / cg"
!
filterMethodInB
"filter this entry (don't show it)."
self filterMethod:(self selectedChangeInB)
"Created: / 05-02-2017 / 10:15:57 / cg"
"Modified: / 06-02-2017 / 08:58:46 / cg"
!
filterMethodInM
"filter this entry (don't show it)."
self filterMethod:(self selectedChangesInM first)
"Created: / 05-02-2017 / 10:39:10 / cg"
"Modified: / 06-02-2017 / 08:58:59 / cg"
!
filterSelectorFromA
"filter all changes for the selected change's selector(don't show it)."
self filterSelectorFromSet:{self selectedChangeInA}
"Created: / 05-02-2017 / 10:36:08 / cg"
"Modified (comment): / 06-02-2017 / 09:13:48 / cg"
!
filterSelectorFromB
"filter all changes for the selected change's selector(don't show it)."
self filterSelectorFromSet:{self selectedChangeInB}
"Created: / 05-02-2017 / 10:36:14 / cg"
"Modified (comment): / 06-02-2017 / 09:13:52 / cg"
!
filterSelectorFromChange:aChange
"common to set a filter;
gets the change as argument,
takes its selector and adds it to the filters"
filteredSelectors isNil ifTrue:[
filteredSelectors := Set new.
].
filteredSelectors add:(aChange changeSelector).
self filterChanged.
"Created: / 05-02-2017 / 10:39:28 / cg"
"Modified (comment): / 06-02-2017 / 09:13:55 / cg"
!
filterSelectorFromM
"filter all changes for the selected change's selector(don't show it)."
self filterSelectorFromSet:{self selectedChangesInM}
"Created: / 05-02-2017 / 10:39:28 / cg"
"Modified (comment): / 06-02-2017 / 09:13:55 / cg"
!
filterSelectorFromSet:setOfChanges
"common to set a filter;
get the sub-set (A,B,M as argument),
takes its first selection and adds it to the filters"
filteredSelectors isNil ifTrue:[
filteredSelectors := Set new.
].
filteredSelectors add:(setOfChanges first changeSelector).
self filterChanged.
"Created: / 05-02-2017 / 10:39:28 / cg"
"Modified (comment): / 06-02-2017 / 09:13:55 / cg"
!
filterSelectorsMatching
"ask for a GLOB pattern;
filter all changes with matching selectors."
|pattern|
pattern := Dialog request:'Matchpattern for Selector Filter (will hide changes with matching selectors):'.
pattern isEmptyOrNil ifTrue:[^ self].
selectorPatternFilters isNil ifTrue:[
selectorPatternFilters := OrderedCollection new.
].
selectorPatternFilters add:pattern.
self filterChanged
"Created: / 06-02-2017 / 02:29:07 / cg"
"Modified: / 06-02-2017 / 09:18:20 / cg"
!
forgetFilterNamed
"forget a remembered named filter"
|filterName filters|
RememberedFilters isEmptyOrNil ifTrue:[
Dialog warn:'No filter was defined'.
^ self
].
filters := self class rememberedFilters.
filterName := Dialog
request:'Forget Filter Named:'
list:(filters keys asNewOrderedCollection sort).
filterName isEmptyOrNil ifTrue:[^ self].
(Dialog confirm:'Shure to Forget the Filter Named: ',filterName) ifFalse:[^ self].
filters removeKey:filterName.
"Created: / 05-02-2017 / 11:12:08 / cg"
"Modified: / 06-02-2017 / 02:17:47 / cg"
"Modified: / 08-05-2019 / 11:53:06 / Claus Gittinger"
!
importFilterParameters
"ask for XML representation as exported previously.
(to be pasted from Jabber for interchange)"
|xml filterParameters|
xml := Dialog requestText:'Paste XML Exported Filter Here and Accept'.
xml isEmptyOrNil ifTrue:[^ self].
filterParameters := XMLStandardCoder decode:xml.
(filterParameters isKindOf:FilterParameters) ifTrue:[
self setFilterParameters:filterParameters
].
"Created: / 06-02-2017 / 09:51:11 / cg"
!
inspectFilterParameters
"inspect the current settings"
self currentFilterParameters inspect.
"Created: / 06-02-2017 / 02:00:55 / cg"
"Modified: / 06-02-2017 / 09:20:15 / cg"
!
loadFilterNamed
"load a remembered named filter"
|filterName filterParameters filters|
RememberedFilters isEmptyOrNil ifTrue:[
Dialog warn:'No filters defined'.
^ self.
].
filters := self class rememberedFilters.
filterName := Dialog
request:'Load Filter Named:'
list:(filters keys asNewOrderedCollection sort).
filterName isEmptyOrNil ifTrue:[^ self].
filterParameters := filters at:filterName.
self setFilterParameters:filterParameters.
"Created: / 06-02-2017 / 01:57:48 / cg"
"Modified: / 06-02-2017 / 09:51:47 / cg"
"Modified: / 08-05-2019 / 11:53:49 / Claus Gittinger"
!
rememberFilterAs
"remember the current settings under a named filter"
|filterName filterParameters filters|
filters := self class rememberedFilters.
filterName := Dialog
request:'Name of Filter:'
list:(filters keys asNewOrderedCollection sort).
filterName isEmptyOrNil ifTrue:[^ self].
filterParameters := self currentFilterParameters.
filters at:filterName put:filterParameters.
"Modified: / 06-02-2017 / 09:20:35 / cg"
"Modified: / 08-05-2019 / 11:54:08 / Claus Gittinger"
!
removeClassFilter
"clear the current class filter (but not named ones)"
classPatternFilters := nil.
self filterChanged
!
removeSelectorFilter
"clear the current selector filter (but not named ones)"
selectorPatternFilters := nil.
self filterChanged
"Created: / 06-02-2017 / 02:29:07 / cg"
"Modified: / 06-02-2017 / 09:18:20 / cg"
!
setFilterChangedAfter:aTimestamp
filterChangedAfter := aTimestamp.
"Created: / 08-05-2019 / 13:24:11 / Claus Gittinger"
!
setFilterChangedBefore:aTimestamp
filterChangedBefore := aTimestamp.
"Created: / 08-05-2019 / 13:24:07 / Claus Gittinger"
!
setFilterParameters:filter
"setup from a remembered filter"
selectorPatternFilters := filter filteredSelectorMatchPattern.
classPatternFilters := filter filteredClassNameMatchPattern.
filteredClasses := filter filteredClassNames.
filteredMethods := filter filteredMethodNames.
filteredSelectors := filter filteredSelectors.
filterChangedBefore := filter filterChangedBefore.
filterChangedAfter := filter filterChangedAfter.
self filterChanged.
"Created: / 06-02-2017 / 09:51:37 / cg"
"Modified: / 08-05-2019 / 13:20:25 / Claus Gittinger"
! !
!VersionDiffBrowser methodsFor:'menu action - searching'!
findNextChangeWithStringIn:listOfchanges selectionHolder:whichMethodSelectionHolder
"common code to select the next change which contains some string"
|string startIdx|
string := Dialog request:'Search for:' initialAnswer:LastSearchString.
string isEmptyOrNil ifTrue:[^ false].
LastSearchString := string.
startIdx := whichMethodSelectionHolder value.
listOfchanges from:startIdx+1 keysAndValuesDo:[:index :eachChange |
(eachChange source includesString:string caseSensitive:false) ifTrue:[
whichMethodSelectionHolder value:index.
^ true.
]
].
^ false
!
findNextChangeWithStringInA
"select the next change which contains some string"
(self findNextChangeWithStringIn:methodsOnlyInAFiltered selectionHolder:methodsOnlyInASelection) ifTrue:[
self methodsOnlyInASelectionChanged
] ifFalse:[
self beepInEditor
].
!
findNextChangeWithStringInB
"select the next change which contains some string"
(self findNextChangeWithStringIn:methodsOnlyInBFiltered selectionHolder:methodsOnlyInBSelection) ifTrue:[
self methodsOnlyInASelectionChanged
]
!
findNextChangeWithStringInM
"select the next change which contains some string"
(self findNextChangeWithStringInPairs:methodsChangedFiltered selectionHolder:methodsChangedSelection) ifTrue:[
self methodsChangedSelectionChanged
]
!
findNextChangeWithStringInPairs:listOfchangePairs selectionHolder:whichMethodSelectionHolder
"select the next change which contains some string"
|string startIdx|
string := Dialog request:'Search for:' initialAnswer:LastSearchString.
string isEmptyOrNil ifTrue:[^ false].
LastSearchString := string.
startIdx := whichMethodSelectionHolder value.
listOfchangePairs from:startIdx+1 keysAndValuesDo:[:index :eachChangePair |
(eachChangePair first source includesString:string caseSensitive:false) ifTrue:[
whichMethodSelectionHolder value:index.
^ true.
].
(eachChangePair second source includesString:string caseSensitive:false) ifTrue:[
whichMethodSelectionHolder value:index.
^ true.
]
].
^ false.
! !
!VersionDiffBrowser 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.
]
!
informationUntranslated:msg
self infoHolder value:msg
"Created: / 09-08-2018 / 15:40:52 / Claus Gittinger"
!
printStringForChange:aChange
"generate a print string for a change."
|m changeClassName classOrMetaString useChangesString selectorString
singleComparedClass singleComparedClassesName singleComparedMetaclassesName
printString class1 class2|
class1 := self classChangeSet class1BeingCompared.
class2 := self classChangeSet class2BeingCompared.
(singleComparedClass := self classBeingCompared) notNil ifTrue:[
singleComparedClassesName := singleComparedClass name.
singleComparedMetaclassesName := singleComparedClass theMetaclass name.
].
aChange isClassDefinitionChange ifTrue:[
^ aChange printStringWithoutClassName
].
aChange isDoIt ifTrue:[
^ aChange source , ' (doIt)'
].
aChange isNameSpaceCreationChange ifTrue:[
^ aChange source
].
changeClassName := aChange className.
changeClassName isNil ifTrue:[
^ aChange source
].
useChangesString := false.
classOrMetaString := ''.
(class1 notNil
and:[ class2 notNil
and:[ class1 ~= class2 ]]) ifTrue:[
changeClassName := ''.
] ifFalse:[
(changeClassName = singleComparedClassesName) ifTrue:[
"/ changeClassName := ''.
useChangesString := true.
] ifFalse:[
(changeClassName = singleComparedMetaclassesName) ifTrue:[
"/ classOrMetaString := ' class'.
useChangesString := true.
] ifFalse:[
((changeClassName includes:$:) and:[ changeClassName startsWith:((singleComparedClassesName ? ''),'::') ]) ifTrue:[
changeClassName := changeClassName copyFrom:(singleComparedClassesName,'::') size+1.
].
].
].
].
selectorString := ''.
(aChange isMethodChange) ifTrue:[
selectorString := aChange changeSelector.
aChange changeClass notNil ifTrue:[
m := aChange changeMethod.
m notNil ifTrue:[
m := m originalMethodIfWrapped.
selectorString := m printStringForBrowserWithSelector:aChange changeSelector inClass:aChange changeClass.
].
].
changeClassName notEmptyOrNil ifTrue:[
selectorString := ' ยป ',selectorString
]
].
printString := changeClassName,classOrMetaString,selectorString.
aChange isMethodCategoryChange ifTrue:[
^ printString, ' (category)'
].
^ printString
"Modified: / 06-02-2017 / 02:32:08 / cg"
!
resetSelectionHolders
"
reset all selection holders when a new change set is given.
First set the selection to nil.
<return: self>
"
self methodsChangedSelection value:nil.
self methodsOnlyInASelection value:nil.
self methodsOnlyInBSelection value:nil.
self diffTextView text1:'' text2:''.
self methodText value:''.
"/ self methodsChangedSelectionChanged.
"/ self methodsOnlyInASelectionChanged.
"/ self methodsOnlyInBSelectionChanged.
!
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:#singleTextView) beInvisible.
(self componentAt:#diffTextView) realizeAllSubViews.
self addAcceptToTextViewMenus.
!
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:#singleTextView) raise; beVisible.
(self componentAt:#diffTextViewBox) beInvisible.
self addAcceptToTextViewMenus.
!
showVersionInfoIfNothingSelected
"show the revision info (author, date, time and logMessage),
if no method is selected"
|revInfo infoText|
"/ self information:''.
(methodsOnlyInASelection value isNil
and:[ methodsOnlyInBSelection value isNil
and:[ methodsChangedSelection value isNil]]
) ifTrue:[
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 methodText value:infoText.
self showSingleTextView.
].
"Modified: / 05-02-2017 / 11:49:47 / cg"
"Modified (comment): / 13-03-2019 / 10:41:01 / Claus Gittinger"
! !
!VersionDiffBrowser methodsFor:'setup'!
setupForClass:aClass againstVersion:aVersionA
"compute the class change set for the class aClass of its current version against the repository version A.
When setting the class change set, the labels, list etc. of the receiver
are updated."
|changeSet|
aClass isNil ifTrue:[
changeSet := nil
] ifFalse:[
(aClass isRealNameSpace) ifFalse:[
aClass isLoaded ifTrue:[
changeSet := (ClassChangeSet newForClass:aClass againstVersion:aVersionA).
]
].
].
self classChangeSet:changeSet.
aVersionA isNil ifTrue:[
self class:aClass versionA:'Repository' versionB:'Current'.
] ifFalse:[
self class:aClass versionA:aVersionA versionB:(aVersionA , 'm').
]
!
setupForClass:classA labelA:aLabelA andClass:classB labelB:aLabelB
"generate the class change set from the two classes A and B.
When setting the class change set, the labels, list etc. of the receiver
are updated."
|changeSet|
changeSet := (ClassChangeSet newForClass:classA labelA:aLabelA andClass:classB labelB:aLabelB).
self classChangeSet:changeSet
!
setupForClass:aClass labelA:aLabelA sourceA:aSourceA labelB:aLabelB sourceB:aSourceB
"generate the class change set from the two source files A and B.
When setting the class change set, the labels, list etc. of the receiver
are updated."
|changeSet|
aClass isRealNameSpace ifFalse:[
aClass isLoaded ifTrue:[
changeSet := (ClassChangeSet newForClass:aClass labelA:aLabelA sourceA:aSourceA labelB:aLabelB sourceB:aSourceB).
]
].
self classChangeSet:changeSet
"Modified: / 10-11-2006 / 17:15:26 / cg"
!
setupForClass:aClass versionA:aVersionA versionB:aVersionB
"compute the class change set for the class aClass and the versions A and B.
When setting the class change set, the labels, list etc. of the receiver
are updated."
|changeSet|
aClass isNameSpace ifFalse:[
aClass isLoaded ifTrue:[
changeSet := (ClassChangeSet newForClass:aClass versionA:aVersionA versionB:aVersionB).
]
].
self classChangeSet:changeSet.
self class:aClass versionA:aVersionA versionB:aVersionB.
!
setupForDiffSet:diffSet labelA:aLabelA labelB:aLabelB
|changeSet|
changeSet := (ClassChangeSet new diffSet:diffSet; labelA:aLabelA; labelB:aLabelB).
self classChangeSet:changeSet
! !
!VersionDiffBrowser::ClassChangeSet class methodsFor:'instance creation'!
changeSetForClass:aClass
"return a ChangeSet for the class aClass and its current source.
The source is generated into a stream and then the change set is generated
from the source stream."
^ ChangeSet forExistingClass:aClass.
!
changeSetForClass:aClass andRevision:aVersion
"return a ChangeSet for the class aClass and version aVersion.
The version from the class source stream is checked out from the repositiory
into a source stream. Then the change set is generated from the source stream."
|theSourceCodeManager theSourceStream theChangeSet|
theSourceCodeManager := SourceCodeManagerUtilities sourceCodeManagerFor:aClass.
[
theSourceStream := theSourceCodeManager getSourceStreamFor:aClass revision:aVersion.
theSourceStream notNil ifTrue:[
theChangeSet := ChangeSet fromStream:theSourceStream
]
] ensure:[
theSourceStream notNil ifTrue:[theSourceStream close]
].
theChangeSet isNil ifTrue:[
self error:'Could not read source of class ',aClass name mayProceed:true.
^ nil
].
self sortChangeSet:theChangeSet.
^ theChangeSet
"Modified: / 12-09-2006 / 14:24:51 / cg"
!
changeSetForClass:aClass andSource:aSource
"return a ChangeSet for the class aClass and source aSource.
The source is converted to a stream and then the change set is generated
from the source stream.
Raise an error if the source stream cannot be opened."
|theChangeSet theSourceStream|
[
theSourceStream := aSource readStream.
theChangeSet := ChangeSet fromStream:theSourceStream.
] ensure:[
theSourceStream notNil ifTrue:[
theSourceStream close
]
].
theChangeSet isNil ifTrue:[
self error:'Could not read source of class ',aClass name mayProceed:true.
^ nil
].
self sortChangeSet:theChangeSet.
^ theChangeSet
"Modified: / 02-01-2018 / 20:41:55 / stefan"
!
newForClass:aClass againstVersion:aVersionA
"return a ClassChangeSet for the class aClass against some verson in the repository.
A new instance of ClassChangeSet is generated containing
the correspondenting changes."
|theClassChangeSet|
theClassChangeSet := self new.
theClassChangeSet setupForClass:aClass againstVersion:aVersionA.
^ theClassChangeSet
!
newForClass:classA labelA:aLabelA andClass:classB labelB:aLabelB
"return a ClassChangeSet for two classes.
A new instance of ClassChangeSet is generated containing the correspondenting changes."
|aStream sourceA sourceB theChangeSetA theChangeSetB theClassChangeSet|
theClassChangeSet := self new.
theClassChangeSet class1BeingCompared:classA class2BeingCompared:classB.
theClassChangeSet labelA:aLabelA.
theClassChangeSet labelB:aLabelB.
theChangeSetA := ChangeSet forExistingClass:classA withExtensions:true withLooseMethods:true.
theChangeSetB := ChangeSet forExistingClass:classB withExtensions:true withLooseMethods:true.
"/ aStream := '' writeStream.
"/ Method flushSourceStreamCache.
"/ classA fileOutOn:aStream withTimeStamp:false.
"/ sourceA := aStream contents asString.
"/ aStream := '' writeStream.
"/ Method flushSourceStreamCache.
"/ classB fileOutOn:aStream withTimeStamp:false.
"/ sourceB := aStream contents asString.
"/ theChangeSetA:=self changeSetForClass:classA andSource:sourceA.
"/ theChangeSetB:=self changeSetForClass:classB andSource:sourceB.
"/ theChangeSetA isNil ifTrue: [theChangeSetA := ChangeSet new].
"/ theChangeSetB isNil ifTrue: [theChangeSetB := ChangeSet new].
"/ just in case (if comparing a class against another),
"/ unify the classes of the changes (to avoid that all changes are detected as different)
"/ theChangeSetB do:[:eachChange |
"/ eachChange isMethodChange ifTrue:[
"/ eachChange changeClass isMeta ifTrue:[
"/ eachChange changeClass ~~ classA theMetaclass ifTrue:[
"/ eachChange changeClass:classA theMetaclass.
"/ ]
"/ ] ifFalse:[
"/ eachChange changeClass ~~ classA theNonMetaclass ifTrue:[
"/ eachChange changeClass:classA theNonMetaclass.
"/ ]
"/ ].
"/ ].
"/ ].
"/ remove all #initialize doIts
theChangeSetA := theChangeSetA reject:[:eachChange | eachChange isDoIt and:[eachChange isInitialize]].
theChangeSetB := theChangeSetB reject:[:eachChange | eachChange isDoIt and:[eachChange isInitialize]].
theClassChangeSet diffSet:(theChangeSetA diffSetsAgainst:theChangeSetB comparingDifferentClasses:true).
^ theClassChangeSet
!
newForClass:aClass labelA:aLabelA sourceA:aSourceA labelB:aLabelB sourceB:aSourceB
"return a ClassChangeSet for the class aClass and the two sources.
The two classes are compared via the source files. A new instance of
ClassChangeSet is generated containing the correspondenting changes."
|theChangeSetA theChangeSetB theClassChangeSet className metaClassName|
theClassChangeSet := self new.
theClassChangeSet classBeingCompared:aClass.
theClassChangeSet labelA:aLabelA.
theClassChangeSet labelB:aLabelB.
theChangeSetA:=self changeSetForClass:aClass andSource:aSourceA.
theChangeSetB:=self changeSetForClass:aClass andSource:aSourceB.
className := aClass name.
metaClassName := aClass class name.
aClass isPrivate ifTrue:[
theChangeSetA := theChangeSetA select:[:change | change isMethodChange not
or:[change className = className or:[change className = metaClassName]]].
theChangeSetA := theChangeSetA select:[:change | change isClassDefinitionChange not
or:[change className = className or:[change className = metaClassName]]].
theChangeSetA := theChangeSetA select:[:change | change isDoIt not
or:[change receiverClassName = className or:[change receiverClassName = metaClassName]]].
theChangeSetB := theChangeSetB select:[:change | change isMethodChange not
or:[change className = className or:[change className = metaClassName]]].
theChangeSetB := theChangeSetB select:[:change | change isClassDefinitionChange not
or:[change className = className or:[change className = metaClassName]]].
theChangeSetB := theChangeSetB select:[:change | change isDoIt not
or:[change receiverClassName = className or:[change receiverClassName = metaClassName]]].
"/ there might be more needed...
].
theChangeSetA isNil
ifTrue: [theChangeSetA := ChangeSet new].
theChangeSetB isNil
ifTrue: [theChangeSetB := ChangeSet new].
theClassChangeSet diffSet:(theChangeSetA diffSetsAgainst:theChangeSetB).
^ theClassChangeSet
!
newForClass:aClass versionA:aVersionA versionB:aVersionB
"return a ClassChangeSet for the class aClass and the two versions.
The two class version are checked out from the repository and then being
compared. A new instance of ClassChangeSet is generated containing
the correspondenting changes."
|theChangeSetA theChangeSetB theClassChangeSet|
theClassChangeSet := self new.
theClassChangeSet classBeingCompared:aClass.
theClassChangeSet versionA:aVersionA.
theClassChangeSet versionB:aVersionB.
theClassChangeSet labelA:aVersionA.
theClassChangeSet labelB:aVersionB.
theChangeSetA := self changeSetForClass: aClass andRevision: aVersionA.
theChangeSetB := self changeSetForClass: aClass andRevision: aVersionB.
theChangeSetA isNil ifTrue: [theChangeSetA := ChangeSet new].
theChangeSetB isNil ifTrue: [theChangeSetB := ChangeSet new].
theClassChangeSet diffSet:(theChangeSetA diffSetsAgainst:theChangeSetB).
^ theClassChangeSet
!
sortChangeSet:aChangeSet
"/ sort by meta and selector
aChangeSet
sort:[:a :b |
a == b ifTrue:[
false
] ifFalse:[
a isClassDefinitionChange == b isClassDefinitionChange ifTrue:[
a isClassChange == b isClassChange ifTrue:[
a isClassChange ifTrue:[
a isForMeta == b isForMeta ifTrue:[
(a isMethodChange and:[b isMethodChange]) ifTrue:[
a className < b className
or:[ a className = b className
and:[ a isPrimitiveChange not
and:[ b isPrimitiveChange not
and:[ a changeSelector < b changeSelector ]]]]
] ifFalse:[
a isMethodChange not
].
] ifFalse:[
a isForMeta
].
] ifFalse:[
a printString < b printString
].
] ifFalse:[
a isClassChange
].
] ifFalse:[
a isClassDefinitionChange
].
]
].
"Modified: / 06-02-2017 / 02:31:57 / cg"
! !
!VersionDiffBrowser::ClassChangeSet methodsFor:'accessing'!
class1BeingCompared
"returns the class which is compared"
^ class1BeingCompared
!
class1BeingCompared:class1 class2BeingCompared:class2
"returns the class which is compared"
class1BeingCompared := class1.
class2BeingCompared := class2
!
class2BeingCompared
"returns the class which is compared"
^ class2BeingCompared
!
classBeingCompared
"returns the class which is compared"
^ class1BeingCompared
!
classBeingCompared:something
"set the value of the class which is compared"
class1BeingCompared := class2BeingCompared := something.
!
diffSet
"returns a diffSet containing the different changes.
it responds to:
changed OrderedCollection of arrays containing ChangeSets for methods
which are changed and exists in the class versionA and versionB
onlyInArg ChangeSet for the methods which exists only in the class versionB
onlyInReceiver ChangeSet for the methods which exists only in the class versionA
"
^ diffSet
!
diffSet:something
"sets the diffSet containing the different changes.
it responds to:
changed OrderedCollection of arrays containing ChangeSets for methods
which are changed and exists in the class versionA and versionB
onlyInArg ChangeSet for the methods which exists only in the class versionB
onlyInReceiver ChangeSet for the methods which exists only in the class versionA
"
diffSet := something.
!
labelA
"returns the label for the class versionA"
^ labelA
!
labelA:something
"sets the label for the class versionA"
labelA := something.
!
labelB
"returns the label for the class versionB"
^ labelB
!
labelB:something
"sets the label for the class versionB"
labelB := something.
!
methodsChanged
"returns an OrderedCollection of arrays containing ChangeSets for methods
which are changed and exists in the class versionA and versionB
<return: OrderedCollection of Array(2)>
"
^ self diffSet changed
!
methodsOnlyInA
"returns a ChangeSet for the methods which exists only in the class versionA"
^ self diffSet onlyInReceiver
!
methodsOnlyInB
"returns a ChangeSet for the methods which exists only in the class versionB"
^ self diffSet onlyInArg
!
versionA
^ versionA
!
versionA:something
versionA := something.
!
versionB
^ versionB
!
versionB:something
versionB := something.
! !
!VersionDiffBrowser::ClassChangeSet methodsFor:'misc'!
removeAllVersionMethods
diffSet removeAllVersionMethods.
! !
!VersionDiffBrowser::ClassChangeSet methodsFor:'setup'!
setupForClass:aClass againstVersion:aVersionA
"return a ClassChangeSet for the class aClass against some verison in the repository.
A new instance of ClassChangeSet is generated containing
the correspondenting changes."
|theChangeSetA theChangeSetB versionCompared|
self classBeingCompared:aClass.
versionCompared := aVersionA.
aVersionA isNil ifTrue:[
self labelA:(versionCompared := aClass revision).
self versionA:versionCompared.
] ifFalse:[
aVersionA == #newest ifTrue:[
self labelA:(VersionDiffBrowser resources string:'Newest').
] ifFalse:[
self labelA:versionCompared.
self versionA:versionCompared.
]
].
self labelB:(VersionDiffBrowser resources string:'Current').
theChangeSetA := self class changeSetForClass: aClass andRevision: versionCompared.
theChangeSetB := self class changeSetForClass: aClass.
theChangeSetA isNil ifTrue: [theChangeSetA := ChangeSet new].
theChangeSetB isNil ifTrue: [theChangeSetB := ChangeSet new].
"/ if we are comparing a private class, prune out other changes
aClass isPrivate ifTrue:[
theChangeSetA removeAllSuchThat:[:aChange | aChange className ~= aClass name ].
theChangeSetB removeAllSuchThat:[:aChange | aChange className ~= aClass name ].
].
self activityNotification:'Generating diff-set...'.
self diffSet:(theChangeSetA diffSetsAgainst:theChangeSetB).
self activityNotification:nil.
^ diffSet
! !
!VersionDiffBrowser::FilterParameters class methodsFor:'documentation'!
documentation
"
documentation to be added.
[author:]
Claus Gittinger
[instance variables:]
[class variables:]
[see also:]
"
! !
!VersionDiffBrowser::FilterParameters methodsFor:'accessing'!
filterChangedAfter
^ filterChangedAfter
"Created: / 08-05-2019 / 13:15:11 / Claus Gittinger"
!
filterChangedAfter:aTimestamp
filterChangedAfter := aTimestamp
"Created: / 08-05-2019 / 13:15:07 / Claus Gittinger"
!
filterChangedBefore
^ filterChangedBefore
"Created: / 08-05-2019 / 13:14:55 / Claus Gittinger"
!
filterChangedBefore:aTimestamp
filterChangedBefore := aTimestamp
"Created: / 08-05-2019 / 13:15:04 / Claus Gittinger"
!
filteredClassNameMatchPattern
^ filteredClassNameMatchPattern
!
filteredClassNameMatchPattern:something
filteredClassNameMatchPattern := something.
!
filteredClassNames
^ filteredClassNames
!
filteredClassNames:something
filteredClassNames := something.
!
filteredMethodNames
^ filteredMethodNames
!
filteredMethodNames:something
filteredMethodNames := something.
!
filteredSelectorMatchPattern
^ filteredSelectorMatchPattern
!
filteredSelectorMatchPattern:something
filteredSelectorMatchPattern := something.
!
filteredSelectors
^ filteredSelectors
!
filteredSelectors:something
filteredSelectors := something.
! !
!VersionDiffBrowser class methodsFor:'documentation'!
version
^ '$Header$'
!
version_CVS
^ '$Header$'
! !