Tools__ChangeList.st
author Claus Gittinger <cg@exept.de>
Wed, 05 Feb 2014 19:58:09 +0100
changeset 13835 7dfb57f5f5e7
parent 13513 97b651d76972
child 13927 78883c6c8297
permissions -rw-r--r--
merged in jv's chenges

"
 COPYRIGHT (c) 2010 by Jan Vrany, SWING Research Group. CTU in Prague
              All Rights Reserved

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the 'Software'), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
"
"{ Package: 'stx:libtool' }"

"{ NameSpace: Tools }"

BrowserListWithFilter subclass:#ChangeList
	instanceVariableNames:'listHolder showRemovedHolder showSameHolder showTimestampHolder
		allowRemoveHolder allowAcceptHolder scrollToBottom applyAction
		showConflictsOnlyHolder'
	classVariableNames:'LastSelectionConditionString'
	poolDictionaries:''
	category:'Interface-Browsers-ChangeSet'
!

HierarchicalItem subclass:#ListEntry
	instanceVariableNames:'change application x'
	classVariableNames:''
	poolDictionaries:''
	privateIn:ChangeList
!

!ChangeList class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 2010 by Jan Vrany, SWING Research Group. CTU in Prague
              All Rights Reserved

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the 'Software'), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
"
! !

!ChangeList class methodsFor:'image specs'!

iconEqual
    ^ ToolbarIconLibrary iconEqual12x12

    "Modified: / 31-08-2011 / 10:52:34 / cg"
!

iconEqualGrayed
    ^ ToolbarIconLibrary iconEqualGray12x12

    "Modified: / 31-08-2011 / 10:54:00 / cg"
!

iconExcla
    ^ ToolbarIconLibrary iconExclaRed12x12
!

iconMinus
    ^ ToolbarIconLibrary iconMinusRed12x12

    "Modified: / 24-07-2012 / 16:43:36 / cg"
!

iconMinusGrayed
    ^ ToolbarIconLibrary iconMinusGray12x12

    "Modified: / 31-08-2011 / 10:54:40 / cg"
!

iconPlus
    ^ ToolbarIconLibrary iconPlusBlue12x12

    "Modified: / 24-07-2012 / 16:43:31 / cg"
!

iconPlusGrayed
    ^ ToolbarIconLibrary iconPlusGray12x12

    "Modified: / 31-08-2011 / 10:54:46 / cg"
! !

!ChangeList 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:Tools::ChangeList andSelector:#windowSpec
     Tools::ChangeList new openInterface:#windowSpec
     Tools::ChangeList open
    "

    <resource: #canvas>

    ^
     #(FullSpec
	name: windowSpec
	window:
       (WindowSpec
	  label: 'Change List'
	  name: 'Change List'
	  min: (Point 10 10)
	  bounds: (Rectangle 0 0 300 300)
	)
	component:
       (SpecCollection
	  collection: (
	   (InputFieldSpec
	      name: 'Filter'
	      layout: (LayoutFrame 0 0 0 0 0 1 25 0)
	      initiallyInvisible: true
	      model: filterPatternHolder
	      immediateAccept: true
	      acceptOnLeave: false
	      acceptOnReturn: false
	      acceptOnTab: false
	      acceptOnPointerLeave: false
	      emptyFieldReplacementText: 'Search Filter...'
	      postBuildCallback: postBuildFilterView:
	    )
	   (DataSetSpec
	      name: 'List'
	      layout: (LayoutFrame 0 0 0 0 0 1 0 1)
	      model: selectionHolder
	      menu: menuHolderWithShowFilter
	      hasHorizontalScrollBar: true
	      hasVerticalScrollBar: true
	      dataList: listHolder
	      useIndex: false
	      doubleClickSelector: selectionDoubleclicked
	      columnHolder: listColumns
	      showLabels: false
	      multipleSelectOk: true
	      postBuildCallback: postBuildListView:
	      properties:
	     (PropertyListDictionary
		startDragSelector: nil
		dropObjectSelector: dragObjects:
		canDropSelector: canDrop:
		dropSelector: dropObjects:
	      )
	    )
	   )

	)
      )
! !

!ChangeList class methodsFor:'list specs'!

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

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

    "
     DataSetBuilder new openOnClass:Tools::ChangeList andSelector:#listColumnSpec
    "

    <resource: #tableColumns>

    ^#(
      (DataSetColumnSpec
	 label: 'Removed'
	 id: 'removed'
	 labelButtonType: Button
	 width: 20
	 minWidth: 20
	 editorType: CheckToggle
	 rendererType: CheckToggle
	 model: notRemoved
	 menuFromApplication: false
	 printSelector: notRemoved
	 isResizeable: false
	 showRowSeparator: false
	 showSelectionHighLighted: false
	 showColSeparator: false
       )
      (DataSetColumnSpec
	 label: 'Delta'
	 id: 'delta'
	 labelButtonType: Button
	 width: 20
	 minWidth: 20
	 menuFromApplication: false
	 printSelector: iconDelta
	 canSelect: false
	 isResizeable: false
	 showRowSeparator: false
	 showSelectionHighLighted: false
	 showColSeparator: false
       )
      (DataSetColumnSpec
	 label: 'Change'
	 id: change
	 labelAlignment: left
	 labelButtonType: Button
	 menuFromApplication: false
	 printSelector: label
	 canSelect: false
	 showRowSeparator: false
	 showColSeparator: false
       )
      (DataSetColumnSpec
	 label: 'Class'
	 id: 'className'
	 labelAlignment: left
	 activeHelpKey: ''
	 activeHelpKeyForLabel: ''
	 labelButtonType: Button
	 usePreferredWidth: true
	 model: className
	 menuFromApplication: false
	 canSelect: false
	 showRowSeparator: false
	 showColSeparator: false
       )
      (DataSetColumnSpec
	 label: 'Selector'
	 id: 'selector'
	 labelAlignment: left
	 activeHelpKey: ''
	 activeHelpKeyForLabel: ''
	 labelButtonType: Button
	 usePreferredWidth: true
	 model: selector
	 menuFromApplication: false
	 canSelect: false
	 showRowSeparator: false
	 showColSeparator: false
       )
      (DataSetColumnSpec
	 label: 'Category'
	 id: category
	 labelAlignment: left
	 labelButtonType: Button
	 usePreferredWidth: true
	 model: category
	 menuFromApplication: false
	 canSelect: false
	 showRowSeparator: false
	 showColSeparator: false
       )
      (DataSetColumnSpec
	 label: 'Time Stamp'
	 id: timeStamp
	 labelAlignment: left
	 labelButtonType: Button
	 usePreferredWidth: true
	 model: timeStamp
	 menuFromApplication: false
	 canSelect: false
	 showRowSeparator: false
	 showColSeparator: false
       )
      )

! !

!ChangeList class methodsFor:'menu specs'!

listMenu
    "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:Tools::ChangeList andSelector:#listMenu
     (Menu new fromLiteralArrayEncoding:(Tools::ChangeList listMenu)) startUp
    "

    <resource: #menu>

    ^ 
     #(Menu
        (
         (MenuItem
            enabled: hasChangeSelectedAndNotRemoved
            label: 'Apply'
            itemValue: listMenuApply
            translateLabel: true
            isVisible: allowAcceptHolder
            shortcutKey: Accept
          )
         (MenuItem
            label: 'Apply all'
            itemValue: listMenuApplyAll
            translateLabel: true
            isVisible: allowAcceptHolder
          )
         (MenuItem
            enabled: hasSingleChangeSelectedAndCanBrowse
            label: 'Browse'
            itemValue: listMenuBrowse
            translateLabel: true
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            label: 'Delete'
            itemValue: listMenuDeleteSelection
            nameKey: Delete
            translateLabel: true
            isVisible: allowRemoveHolder
            shortcutKey: Delete
          )
         (MenuItem
            label: '-'
            isVisible: allowRemoveHolder
          )
         (MenuItem
            label: 'Select...'
            translateLabel: true
            submenu: 
           (Menu
              (
               (MenuItem
                  label: 'Select same'
                  itemValue: listMenuSelectSame
                  translateLabel: true
                )
               (MenuItem
                  label: 'Select conflicts (redefined classes/methods)'
                  itemValue: listMenuSelectConflicts
                  translateLabel: true
                )
               (MenuItem
                  label: 'Select additions (new classes/methods)'
                  itemValue: listMenuSelectAdditions
                  translateLabel: true
                )
               (MenuItem
                  label: 'Select removals'
                  itemValue: listMenuSelectRemovals
                  translateLabel: true
                )
               (MenuItem
                  label: '-'
                )
               (MenuItem
                  label: 'Select all'
                  itemValue: listMenuSelectAll
                  translateLabel: true
                )
               (MenuItem
                  label: 'Select none'
                  itemValue: listMenuSelectNone
                  translateLabel: true
                )
               (MenuItem
                  label: '-'
                )
               (MenuItem
                  label: 'Select using block'
                  itemValue: listMenuSelectUsingBlock
                  translateLabel: true
                )
               )
              nil
              nil
            )
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            label: 'Show Deleted'
            translateLabel: true
            isVisible: allowRemoveHolder
            indication: showRemovedHolder
          )
         (MenuItem
            label: 'Inspect change'
            itemValue: listMenuInspect
            translateLabel: true
          )
         )
        nil
        nil
      )
! !

!ChangeList 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)."

    ^ #(
        #allowAcceptHolder
        #allowRemoveHolder
        #inGeneratorHolder
        #menuHolder
        #outGeneratorHolder
        #selectionHolder
        #showFilterHolder
        #showRemovedHolder
        #showSameHolder
        #showTimestampHolder
        #showConflictsOnlyHolder
      ).

! !

!ChangeList methodsFor:'accessing'!

acceptEnabled
    ^ self allowAccept

    "Created: / 08-02-2012 / 14:45:12 / cg"
!

allowAccept
    ^ self allowAcceptHolder value

    "Created: / 24-01-2012 / 19:52:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

allowAccept: aBoolean
    ^ self allowAcceptHolder value: aBoolean

    "Created: / 24-01-2012 / 19:52:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

allowRemoved
    ^ self allowRemoveHolder value ? true

    "Created: / 05-12-2009 / 14:28:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

applyAction:aBlock
    applyAction := aBlock.

    "Modified (format): / 10-09-2012 / 14:15:30 / cg"
!

list
    ^ listHolder value

    "Created: / 05-12-2009 / 14:48:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Created: / 27-12-2011 / 14:18:25 / cg"
!

scrollToBottom:aBoolean
    "If set to true, list will automaticallu scroll to bottom
     ehen the list is updated and clears this flag.

     This is required as the list is updated asynchronously"

    scrollToBottom := aBoolean.

    "Modified (comment): / 30-03-2012 / 17:05:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

selection

    ^(self selectionHolder value ? #()) reject:[:e|e isNil].

    "Created: / 05-12-2009 / 14:48:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

selection: selection

    self selectionHolder value: selection

    "Created: / 30-03-2012 / 12:29:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

selectionIndices
    |sel|

    (sel := self selectionHolder value) isEmptyOrNil ifTrue:[^ #()].
    ^ sel collect:[:each | self list identityIndexOf:each].

    "Created: / 05-12-2009 / 14:48:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Created: / 27-12-2011 / 10:56:20 / cg"
!

showRemoved

    ^self showRemovedHolder value ? true

    "Created: / 05-12-2009 / 14:28:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!ChangeList methodsFor:'actions'!

selectionDoubleclicked

    self listMenuBrowse
"/    | app |
"/
"/    self selection do:
"/        [:e|e removed: e removed not].
"/    ((app := self masterApplication) respondsTo: #redrawChangeListViews)
"/        ifTrue:[app redrawChangeListViews].

    "Modified: / 24-01-2012 / 22:01:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!ChangeList methodsFor:'aspects'!

allowAcceptHolder
    "return/create the valueHolder 'acceptEnabledHolder'"

    allowAcceptHolder isNil ifTrue:[
        allowAcceptHolder := ValueHolder with:nil "defaultValue here".
    ].
    ^ allowAcceptHolder

    "Created: / 24-01-2012 / 19:53:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

allowAcceptHolder:something
    "set the 'allowAcceptHolder' value holder (automatically generated)"

    allowAcceptHolder := something.
!

allowRemoveHolder
    "return/create the 'allowRemoveHolder' value holder (automatically generated)"
    
    allowRemoveHolder isNil ifTrue:[
        allowRemoveHolder := ValueHolder with:true.
        allowRemoveHolder addDependent:self.
    ].
    ^ allowRemoveHolder

    "Modified (comment): / 24-01-2012 / 19:44:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

allowRemoveHolder:something 
    "set the 'showRemovedHolder' value holder (automatically generated)"
    
    |oldValue newValue|

    allowRemoveHolder notNil ifTrue:[
        oldValue := allowRemoveHolder value.
        allowRemoveHolder removeDependent:self.
    ].
    allowRemoveHolder := something.
    allowRemoveHolder notNil ifTrue:[
        allowRemoveHolder addDependent:self.
    ].
    newValue := allowRemoveHolder value.
    oldValue ~~ newValue ifTrue:[
        self 
            update:#value
            with:newValue
            from:allowRemoveHolder.
    ].
!

listColumns

    |holder|
    (holder := builder bindingAt:#listColumns) isNil ifTrue:[
	builder aspectAt:#listColumns put:(holder := List new).
	self listColumnShow: #delta.
	self listColumnShow: #change.
    ].
    ^ holder

    "Created: / 26-07-2012 / 18:03:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

listHolder
    listHolder isNil ifTrue:[
        listHolder := ValueHolder new.
    ].
    ^ listHolder
!

showConflictsOnlyHolder
    "return/create the 'showConflictsOnlyHolder' value holder (automatically generated)"

    showConflictsOnlyHolder isNil ifTrue:[
        showConflictsOnlyHolder := ValueHolder with: true.
        showConflictsOnlyHolder addDependent: self.
    ].
    ^ showConflictsOnlyHolder
!

showConflictsOnlyHolder:something
    "set the 'showConflictsOnlyHolder' value holder (automatically generated)"

    |oldValue newValue|

    showConflictsOnlyHolder notNil ifTrue:[
        oldValue := showConflictsOnlyHolder value.
        showConflictsOnlyHolder removeDependent:self.
    ].
    showConflictsOnlyHolder := something.
    showConflictsOnlyHolder notNil ifTrue:[
        showConflictsOnlyHolder addDependent:self.
    ].
    newValue := showConflictsOnlyHolder value.
    oldValue ~~ newValue ifTrue:[
        self update:#value with:newValue from:showConflictsOnlyHolder.
    ].
!

showRemovedHolder
    "return/create the 'showRemovedHolder' value holder (automatically generated)"

    showRemovedHolder isNil ifTrue:[
        showRemovedHolder := ValueHolder with: true.
        showRemovedHolder addDependent: self.
    ].
    ^ showRemovedHolder
!

showRemovedHolder:something
    "set the 'showRemovedHolder' value holder (automatically generated)"

    |oldValue newValue|

    showRemovedHolder notNil ifTrue:[
        oldValue := showRemovedHolder value.
        showRemovedHolder removeDependent:self.
    ].
    showRemovedHolder := something.
    showRemovedHolder notNil ifTrue:[
        showRemovedHolder addDependent:self.
    ].
    newValue := showRemovedHolder value.
    oldValue ~~ newValue ifTrue:[
        self update:#value with:newValue from:showRemovedHolder.
    ].
!

showSameHolder
    "return/create the 'showSameHolder' value holder (automatically generated)"

    showSameHolder isNil ifTrue:[
        showSameHolder := ValueHolder with: true.
        showSameHolder addDependent:self.
    ].
    ^ showSameHolder

    "Modified: / 04-08-2011 / 18:39:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

showSameHolder:something
    "set the 'showSameHolder' value holder (automatically generated)"

    |oldValue newValue|

    showSameHolder notNil ifTrue:[
        oldValue := showSameHolder value.
        showSameHolder removeDependent:self.
    ].
    showSameHolder := something.
    showSameHolder notNil ifTrue:[
        showSameHolder addDependent:self.
    ].
    newValue := showSameHolder value.
    oldValue ~~ newValue ifTrue:[
        self update:#value with:newValue from:showSameHolder.
    ].
!

showTimestampHolder
    "return/create the 'showTimestampHolder' value holder (automatically generated)"

    showTimestampHolder isNil ifTrue:[
	showTimestampHolder := ValueHolder new.
	showTimestampHolder addDependent:self.
    ].
    ^ showTimestampHolder
!

showTimestampHolder:something
    "set the 'showTimestampHolder' value holder (automatically generated)"

    |oldValue newValue|

    showTimestampHolder notNil ifTrue:[
	oldValue := showTimestampHolder value.
	showTimestampHolder removeDependent:self.
    ].
    showTimestampHolder := something.
    showTimestampHolder notNil ifTrue:[
	showTimestampHolder addDependent:self.
    ].
    newValue := showTimestampHolder value.
    oldValue ~~ newValue ifTrue:[
	self update:#value with:newValue from:showTimestampHolder.
    ].
! !

!ChangeList methodsFor:'change & update'!

selectionChanged
   super selectionChanged
!

update: aspect with: param from: sender

    sender == allowRemoveHolder ifTrue:[
        self listColumn: #removed visible: allowRemoveHolder value.
        ^self.
    ].

    sender == showTimestampHolder ifTrue:[
        self listColumn: #timeStamp visible: showTimestampHolder value.
        ^self.
    ].


    sender == selectionHolder ifTrue:[
        self selectionChanged.
        ^ self
    ].
    sender == showSameHolder ifTrue:[
        self updateList.
        ^self.
    ].
    sender == showRemovedHolder ifTrue:[
        self updateList
    ].
    sender == showConflictsOnlyHolder ifTrue:[
        self updateList
    ].

    ^super update: aspect with: param from: sender

    "Created: / 24-10-2009 / 19:47:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (format): / 27-12-2011 / 14:20:30 / cg"
    "Modified: / 26-07-2012 / 18:44:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!ChangeList methodsFor:'drag & drop'!

canDrop: aDropContext

    ^(self inGeneratorHolder value isKindOf: Iterator) not
	and:[aDropContext dropObjects allSatisfy:[:obj|(obj theObject isKindOf: Change)]].

    "Created: / 01-08-2012 / 17:53:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

dragObjects: aDropSource

    ^self selection collect:[:item|(DropObject new: item change) displayObject: (item labelAndIcon)]

    "Created: / 01-08-2012 / 17:50:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

dropObjects:aDropContext
    "drop manager wants to drop.
     This is ony sent, if #canDrop: returned true.
     Must be redefined in order for drop to work."

    | changes |

    changes := self inGeneratorHolder value.
    aDropContext dropObjects do:[:obj|changes add: obj theObject].
    self inGeneratorHolder changed: #value

    "Modified: / 01-08-2012 / 18:15:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!ChangeList methodsFor:'event processing'!

buttonPress:button x:x y:y view:aView

    | itemIndex item |

    button ~= 1 ifTrue:[^aView buttonPress:button x:x y:y].

    itemIndex := aView yVisibleToLineNr:y.
    itemIndex isNil ifTrue:[^self].
    itemIndex == 0 ifTrue:[^self].
    itemIndex > aView list size ifTrue:[^self].
    item := aView list at: itemIndex.

    ((aView left + x) between: (item x) and: (item x + 16))
        ifFalse:[^aView buttonPress:button x:x y:y].

    item removed: item removed not.
    aView invalidate

    "Created: / 08-12-2009 / 14:12:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-11-2011 / 14:55:41 / cg"
!

handlesButtonPress:button inView:aView

    ^listView scrolledView == aView

    "Created: / 08-12-2009 / 14:08:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

handlesKeyPress:key inView:aView
    <resource: #keyboard (#Accept #Ctrls)>

    ^(key == #Accept or:[ key == #Ctrls]) 
        and:[ listView scrolledView == aView ]

    "Created: / 08-02-2012 / 14:43:11 / cg"
!

keyPress:key x:x y:y view:aView
    (key == #Accept or:[ key == #Ctrls]) ifTrue:[
	self listMenuApply.
	^ self
    ].

    "Created: / 08-02-2012 / 14:42:18 / cg"
! !

!ChangeList methodsFor:'generators'!

makeGenerator
    "Superclass Tools::BrowserList says that I am responsible to implement this method"

    ^Iterator on:
        [:whatToDo|

        selectionHolder value do:
            [:changeListItem| | change |
            change := changeListItem change.
            change isCompositeChange ifTrue:
                [change changes do: whatToDo]]].

    "Modified: / 24-07-2009 / 23:00:41 / Jan Vrany <vranyj1@fel.cvut.cz>"
    "Modified: / 24-10-2009 / 20:00:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!ChangeList methodsFor:'hooks'!

postBuildListView: aView

    super postBuildListView: aView.
    listView scrolledView delegate: self.

    "Created: / 29-11-2011 / 14:56:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!ChangeList methodsFor:'initialization'!

initialize

    super initialize.
    menuHolder := [self menuFor: #listMenu].
    scrollToBottom := false.
    applyAction isNil ifTrue:[
	applyAction := [:change | change apply ].
    ].

    "Created: / 29-10-2010 / 12:50:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!ChangeList methodsFor:'menu actions'!

listMenuApply
    |sel list idx selectionHolder|

    self acceptEnabled ifFalse:[^self].
    selectionHolder := self selectionHolder.

    (sel := selectionHolder value) do:[:e| applyAction value:e change].
    sel size == 1 ifTrue:[
        list := self listHolder value. 
        idx := list indexOf:(sel first). 
        idx < list size ifTrue:[
            selectionHolder value:(Array with:(list at:idx+1))
        ] ifFalse:[
            selectionHolder value:#()
        ].
    ].

    "Modified: / 24-10-2009 / 22:02:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 10-09-2012 / 13:57:46 / cg"
!

listMenuApplyAll

    self acceptEnabled ifFalse:[^self].

    self selection value do:
        [:e|e removed ifFalse:[applyAction value:e change]].

    "Created: / 05-12-2009 / 14:53:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 10-09-2012 / 13:57:58 / cg"
!

listMenuBrowse

    self listMenuBrowseChanges:
        ((self selectionHolder value ? #()) collect:[:e|e change])

    "Modified: / 24-01-2012 / 22:00:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

listMenuBrowseChanges: changes
    | classes methods methodsOnly browserClass|

    classes := Set new.
    methods := Set new.
    methodsOnly := true.
    changes do: [:each |
        each isClassChange ifTrue:[
            each changeClass ifNotNil:[
                classes add: each  changeClass.
                each isMethodCodeChange 
                    ifTrue:
                        [each changeMethod ifNotNil:
                            [methods add:each changeMethod]]
                    ifFalse:
                        [methodsOnly := false]
            ]
        ]
    ].

    browserClass := environment browserClass.
    methodsOnly 
        ifTrue:
            [methods size = 1 
                ifTrue:[ browserClass openInMethod: methods anyOne]
                ifFalse:[ browserClass browseMethods: methods asArray title: 'Selected methods from changeset' sort: true]]
        ifFalse:
            [classes size = 1
                ifTrue:[ browserClass browseClass: classes anyOne]
                ifFalse:[ browserClass browseClasses: classes]]

    "Modified: / 24-10-2009 / 22:02:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Created: / 24-01-2012 / 22:00:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

listMenuDeleteSelection

    self selectionHolder value do:
        [:each|each removed: true].
    self updateList
!

listMenuInspect

    | selection |

    selection := self selectionHolder value collect:[:e|e change].
    selection size = 1
        ifTrue:[selection anyOne inspect]
        ifFalse:[selection inspect].

    "Modified: / 24-10-2009 / 22:02:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

listMenuSelectAdditions

    self listMenuSelectAllSuchThat:[:change|change delta = #+]
!

listMenuSelectAll

    self listMenuSelectAllSuchThat:[:change|true]
!

listMenuSelectAllSuchThat:conditionBlock 
    |newSelection|

    newSelection := self listHolder value 
                select:[:entry | conditionBlock value:entry change ].
    self selectionHolder value:newSelection
!

listMenuSelectNone

    self listMenuSelectAllSuchThat:[:change|false]
!

listMenuSelectRemovals

    self listMenuSelectAllSuchThat:[:change|change delta = #-]
!

listMenuSelectSame

    self listMenuSelectAllSuchThat:[:change|change delta = #=]
!

listMenuSelectUsingBlock

    |conditionBlockString conditionBlock dialog textHolder template|

    template :=
'[:change|
     "/ Define condition for selection below:
     "/ change is an instance of Change
     "/ change will be selected if and only if block returns true

    
     true"/always select the change
]
'.

    LastSelectionConditionString isNil ifTrue:[
        LastSelectionConditionString := template.
    ].


    textHolder := ValueHolder new.
    dialog := Dialog
                 forRequestText:(resources string:'Enter condition for selection')
                 lines:20
                 columns:70
                 initialAnswer:LastSelectionConditionString
                 model:textHolder.
    dialog addButton:(Button label:'Template' action:[textHolder value:template. textHolder changed:#value.]).
    dialog open.
    dialog accepted ifFalse:[^ self].

    conditionBlockString := textHolder value.
    LastSelectionConditionString := conditionBlockString.

    conditionBlock := Parser evaluate:conditionBlockString.
    conditionBlock isBlock ifFalse:[
        self error:'Bad selection block (syntax error?)'.
        ^ self
    ].

    self listMenuSelectAllSuchThat: conditionBlock
!

listMenuUndeleteSelection

    self selectionHolder value do:
        [:each|each removed: false].
    self updateList
! !

!ChangeList methodsFor:'private'!

application

    ^self

    "Created: / 05-12-2009 / 14:10:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

browserNameList

    ^'Change list'

    "Modified: / 24-07-2009 / 22:06:53 / Jan Vrany <vranyj1@fel.cvut.cz>"
!

iconSelectorForChange:change
    | delta sym selectorOrNil |

    masterApplication notNil ifTrue:[
        selectorOrNil := masterApplication iconSelectorForChange:change.
        selectorOrNil notNil ifTrue:[ ^ selectorOrNil ].
    ].
    delta := change deltaDetail.
    sym := delta shortDeltaSymbol.
    sym = #+ ifTrue:[^#iconPlus].
    sym = #- ifTrue:[^#iconMinus].
    sym = #= ifTrue:[^#iconEqual].
    "/ different.
    ^ nil.
!

listColumn: columnId visible: visible
    visible ifTrue:[
        self listColumnShow: columnId
    ] ifFalse:[
        self listColumnHide: columnId
    ]

    "Created: / 26-07-2012 / 18:20:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

listColumnHide: columnId
    self listColumns do:[:spec|
	spec id = columnId ifTrue:[
	    self listColumns remove: spec.
	    listView notNil ifTrue:[
		listView invalidate.
	    ].
	    ^self
	].
    ]

    "Created: / 26-07-2012 / 18:19:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

listColumnShow: columnId

    | columns |
    columns := self listColumns.

    columns do:[:spec|
	spec id = columnId ifTrue:[
	    ^self.
	]
    ].

    self class listColumnSpec do:[:specArray|
	| spec |

	spec := specArray decodeAsLiteralArray.
	spec id = columnId ifTrue:[
	    columnId == #removed ifTrue:[
		columns addFirst: spec.
	    ] ifFalse:[
		columns add: spec.
	    ].
	    listView notNil ifTrue:[
		listView invalidate.
	    ].
	    ^self.
	]

    ].

    "Created: / 26-07-2012 / 17:56:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

listEntryFor:chg 
    ^ListEntry change:chg application: self

    "Modified: / 05-12-2009 / 14:39:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

makeDependent

    "Modified: / 24-07-2009 / 22:06:32 / Jan Vrany <vranyj1@fel.cvut.cz>"
!

makeIndependent

    "Modified: / 24-07-2009 / 22:06:37 / Jan Vrany <vranyj1@fel.cvut.cz>"
!

parentOrModel

    ^self

    "Created: / 05-12-2009 / 14:14:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

updateList
    |inGenerator changeset firstLineShown oldSel newList newSel |
    self withWaitCursorDo:[
        inGenerator := self inGeneratorHolder value.
        listView notNil ifTrue:[
            ((listView isKindOf: ScrollableView) not or:[listView scrolledView notNil]) ifTrue:[
                firstLineShown := listView firstLineShown
            ].
        ].
        oldSel := self selection.

        changeset := inGenerator isNil ifTrue:[ #() ] ifFalse:[ inGenerator ].
        newList := changeset
                    select:
                        [:chg |
                        (self showRemovedHolder value or:[ chg removed not ])
                            and:[self showSameHolder value or:[chg delta ~~ #=]]
                        ].
        newList := self filterList: newList.
        newList := newList collect:[:chg | self listEntryFor:chg ].
        self listHolder value ~= newList ifTrue:[
            self listHolder value: newList.
            ((newList size ~~ 0) and:[scrollToBottom]) ifTrue:[
                self selection: { newList last }
            ] ifFalse:[
                oldSel notEmptyOrNil ifTrue:[
                    newSel := OrderedCollection new: oldSel size.
                    oldSel := oldSel reject:[:e|e isNil].
                    oldSel := oldSel collect:[:e|e change].
                    newList do:[:e|(oldSel includes:e change) ifTrue:[newSel add:e]].
                    self selection: newSel.
                ].
                (listView notNil and:[firstLineShown notNil]) ifTrue:[
                    listView scrollToLine: (newList size min: firstLineShown).
                ].
            ].
            scrollToBottom := false.

        ]
    ]
    "Modified: / 28-12-2011 / 15:46:15 / cg"
    "Modified: / 01-08-2012 / 18:10:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!ChangeList methodsFor:'queries'!

hasChangeSelected

    ^self selectionHolder value size > 0
!

hasChangeSelectedAndNotRemoved
    | selection |

    selection := self selectionHolder value ? #().
    ^selection size > 0 and: [selection conform:[:e|e removed not]].
!

hasSingleChangeSelected

    ^self selectionHolder value size = 1
!

hasSingleChangeSelectedAndCanBrowse
    self selectionHolder value ? #() do: [:each |
        |chg|

        chg := each change.
        chg isClassChange ifTrue:[
            (chg isMethodChange not or:[chg isMethodCodeChange]) ifFalse:[^ false]
        ].
    ].
    ^ true
!

showColumn: columnSymbol

    ^self showColumnSpecHolder value includes: columnSymbol.

    "Created: / 03-04-2012 / 11:28:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!ChangeList::ListEntry class methodsFor:'instance creation'!

change: aChange

    ^self new change: aChange

    "Created: / 24-07-2009 / 22:43:41 / Jan Vrany <vranyj1@fel.cvut.cz>"
!

change: aChange application: anApplicationModel

    ^self new change: aChange; application: anApplicationModel

    "Created: / 05-12-2009 / 14:16:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

change: aChange parent: aChangeList

    ^self new change: aChange; parent: aChangeList

    "Created: / 25-07-2009 / 23:33:00 / Jan Vrany <vranyj1@fel.cvut.cz>"
! !

!ChangeList::ListEntry methodsFor:'accessing'!

application
    ^ application ifNil:[super application]

    "Modified: / 05-12-2009 / 14:16:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

application:anApplicationModel
    application := anApplicationModel.

    "Modified: / 05-12-2009 / 14:15:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

change
    ^ change
!

change:aChange
    self assert: ((aChange isKindOf: Change) or:[aChange isKindOf: RefactoryChange]).
    change := aChange.

    "Modified: / 25-07-2009 / 23:40:38 / Jan Vrany <vranyj1@fel.cvut.cz>"
    "Modified (format): / 04-12-2011 / 14:58:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

changeClass

    ^change changeClass
!

changeSource
    "the changes source"

    "/ Hack to make sure code is displayed in similar way
    "/ (i.e., with no namespace pragma)
    ^ (change isClassDefinitionChange and:[change isPrivateClassDefinitionChange]) ifTrue:[
        change definitionStringInNamespace: nil.
    ] ifFalse:[
        change changeSource.
    ].

    "Created: / 19-07-2011 / 12:03:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (comment): / 25-07-2012 / 17:39:39 / cg"
    "Modified: / 14-11-2013 / 14:55:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

children

    children isNil ifTrue:[
        change isCompositeChange ifTrue:[
            children := OrderedCollection new: change changes size.
            self application showConflictsOnlyHolder value ifTrue:[
                change changes do:[:chg|
                    (chg isConflict) ifTrue:[
                        children add: ((self application listEntryFor: chg) parent: self)
                    ]
                ].
            ] ifFalse:[
                |showRemoved showSame|

                showRemoved := self application showRemovedHolder value.
                showSame := self application showSameHolder value.

                change changes do:[:chg|
                    ((showRemoved or:[ chg removed not ])
                        and:[showSame or:[chg delta ~~ #=]]) 
                            ifTrue:[
                                children add: ((self application listEntryFor: chg) parent: self)
                            ]
                ].
            ]
        ] ifFalse:[
            children :=  #()
        ]
    ].
    ^children

    "Created: / 25-07-2009 / 23:32:39 / Jan Vrany <vranyj1@fel.cvut.cz>"
    "Modified (format): / 18-11-2011 / 14:56:25 / cg"
    "Modified: / 04-12-2011 / 15:08:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

delta
    "/ obsolete: please use deltaDetail

    ^change delta

    "Created: / 29-10-2010 / 14:32:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (comment): / 31-08-2011 / 10:30:02 / cg"
!

deltaDetail

    ^change deltaDetail

    "Created: / 29-10-2010 / 14:32:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Created: / 31-08-2011 / 10:29:21 / cg"
!

imageSource
    "return the source for the in-image version of the change"

    ^ change imageSource

    "Created: / 19-07-2011 / 12:03:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (comment): / 25-07-2012 / 17:38:57 / cg"
!

label
    | label |

    label := change displayString.

    "Hack: if the printString contains multiple lines, then
     if there are just 2 lines, then merge them, otherwise add
     ... to the first line"
    (label includes: Character cr) ifTrue:[
        | firstCR secondCR |
        firstCR := label indexOf: Character cr.
        firstCR ~~ label size ifTrue:[
            secondCR := label indexOf: Character cr startingAt: firstCR + 1.
        ].
        secondCR isNil ifTrue:[
            "/2 lines only
            label := label copy at: firstCR put: Character space.
        ] ifFalse:[
            label := (label copyTo: firstCR - 1) , '...'
        ].
    ].
    self removed ifTrue:[label := label asText colorizeAllWith: Color gray].
    ^label

    "Created: / 05-11-2008 / 08:20:02 / Jan Vrany <vranyj1@fel.cvut.cz>"
    "Modified: / 25-07-2009 / 23:43:23 / Jan Vrany <vranyj1@fel.cvut.cz>"
    "Modified: / 05-12-2009 / 14:46:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (format): / 27-07-2012 / 21:26:34 / cg"
!

labelAndIcon
    ^(LabelAndIcon label: self label icon: self iconDelta)

    "Created: / 01-08-2012 / 18:14:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

notRemoved
    ^ self removed not

    "Created: / 26-07-2012 / 18:31:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

notRemoved: aBoolean
    ^ self removed: aBoolean not

    "Created: / 26-07-2012 / 18:31:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

removed
    ^ change removed == true

    "Modified: / 26-07-2012 / 18:30:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

removed:aBoolean
    change removed: aBoolean.
!

source

    ^change source
!

timeStamp
    ^change timeOfChangeIfKnown

    "Created: / 26-07-2012 / 18:38:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

x
    ^ x
! !

!ChangeList::ListEntry methodsFor:'displaying'!

displayLabel:aLabel h:lH on:aGC x:newX y:y h:h

    | list cx icon colW colS |
    list := self application.
    cx := x := newX.
    (list allowRemoveHolder value and:[list showRemovedHolder value]) ifTrue: [
	(icon := self iconRemoved) notNil ifTrue:[
	    icon displayOn: aGC x: cx y: y + (h / 2) - (icon height / 2)
	].
	cx := cx + 22."experimental value - this looks good"
    ].
    (icon := self iconDelta) notNil ifTrue:[
	icon displayOn: aGC x: cx y: y + (h / 2) - (icon height / 2)
    ].
    cx := cx + 16."12 + 2px gap"

    super displayLabel:aLabel h:lH on:aGC x:cx y:y h:h.

"/    "Now, display additional columns..."
"/    (list showColumn: #timestamp) ifTrue:[
"/        cx := cx + (aLabel widthOn: aGC) + 5."px - padding"
"/        colS := change timeOfChangeIfKnown notNil
"/                    ifTrue:[change timeOfChangeIfKnown printString]
"/                    ifFalse:['???'].
"/        [ (colW := colS widthOn: aGC) > (aGC width - cx - 5) ] whileTrue:[
"/            colS = '...' ifTrue:[ ^ self ].
"/            colS := '...' , (colS copyFrom: 6).
"/        ].
"/        super displayLabel:colS h:lH on:aGC x: (aGC width - 5 - colW) y:y h:h.
"/    ].

    "Modified: / 27-07-2012 / 17:13:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

iconDelta
    | iconSelector |

    iconSelector := self iconSelector.
    iconSelector isNil ifTrue:[^nil].
    self removed ifTrue:[iconSelector := iconSelector , #Grayed].
    ^self application class perform: iconSelector asSymbol.

    "Created: / 05-12-2009 / 14:11:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-11-2011 / 14:56:33 / cg"
!

iconRemoved
    |appClass|

    appClass := self application class.
    ^self removed 
        ifTrue: [appClass uncheckedIcon ]
        ifFalse:[appClass checkedIcon ]

    "Created: / 05-12-2009 / 14:11:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

iconSelector
    ^ application iconSelectorForChange:change
! !

!ChangeList::ListEntry methodsFor:'protocol-queries'!

hasChildren
    ^ change isCompositeChange and:[change changes notEmptyOrNil ].

    "Created: / 04-12-2011 / 14:45:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (format): / 27-07-2012 / 21:25:34 / cg"
! !

!ChangeList class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libtool/Tools__ChangeList.st,v 1.27 2014-02-05 18:58:09 cg Exp $'
!

version_CVS
    ^ '$Header: /cvs/stx/stx/libtool/Tools__ChangeList.st,v 1.27 2014-02-05 18:58:09 cg Exp $'
!

version_SVN
    ^ '$Id: Tools__ChangeList.st,v 1.27 2014-02-05 18:58:09 cg Exp $'
! !