Tools__TextDiff3Tool.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Wed, 21 Mar 2012 01:52:35 +0000
branchjv
changeset 12202 eaa1f6cb6ce8
parent 12201 283826cb8bcc
child 12203 bcfd4488d8a2
permissions -rw-r--r--
Improvements in merge tool

"
 COPYRIGHT (c) 2006 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: Tools }"

TextDiffTool subclass:#TextDiff3Tool
	instanceVariableNames:'labelMergedHolder textMergedHolder mergeHolder mergeDataHolder
		mergeView'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-Diff'
!

CodeViewService subclass:#MergeService
	instanceVariableNames:'dataHolder data'
	classVariableNames:''
	poolDictionaries:''
	privateIn:TextDiff3Tool
!

!TextDiff3Tool class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 2006 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
"
    documentation to be added.

    [author:]
        Jan Vrany <jan.vrany@fit.cvut.cz>

    [instance variables:]

    [class variables:]

    [see also:]

"
!

examples
"
  Starting the application:
                                                                [exBegin]
    Tools::TextDiff3Tool open

                                                                [exEnd]

  more examples to be added:
                                                                [exBegin]
    ... add code fragment for 
    ... executable example here ...
                                                                [exEnd]
"
! !

!TextDiff3Tool class methodsFor:'defaults - colors'!

colorA

    ^(Color red:54.1176470588235 green:75.2941176470588 blue:28.6274509803922) lighter

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

colorB

    ^(Color red:96.078431372549 green:73.7254901960784 blue:0.0) lighter

    "Created: / 19-03-2012 / 13:11:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

colorBase

    ^(Color red:5.88235294117647 green:58.8235294117647 blue:80.3921568627451) lighter

    "Created: / 19-03-2012 / 13:12:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

colorConflict

    ^Color red

    "Created: / 19-03-2012 / 13:12:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

colorMerged

    ^(Color red:83.921568627451 green:17.2549019607843 blue:85.0980392156863) lighter

    "Created: / 19-03-2012 / 13:11:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool class methodsFor:'interface specs'!

diff3Spec
    "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::TextDiff3Tool andSelector:#diff3Spec
     Tools::TextDiff3Tool new openInterface:#diff3Spec
    "

    <resource: #canvas>

    ^ 
     #(FullSpec
        name: diff3Spec
        window: 
       (WindowSpec
          label: 'Text Diff Tool (for embedding)'
          name: 'Text Diff Tool (for embedding)'
          min: (Point 10 10)
          bounds: (Rectangle 0 0 782 506)
        )
        component: 
       (SpecCollection
          collection: (
           (ViewSpec
              name: '3Labels'
              layout: (LayoutFrame 0 0 0 0 -16 1 30 0)
              component: 
             (SpecCollection
                collection: (
                 (UISubSpecification
                    name: 'VersionC'
                    layout: (LayoutFrame 0 0 0 0 0 0.33333 30 0)
                    minorKey: versionCLabelSpec
                  )
                 (UISubSpecification
                    name: 'VersionA'
                    layout: (LayoutFrame 5 0.3333 0 0 0 0.67 30 0)
                    minorKey: versionALabelSpec
                  )
                 (UISubSpecification
                    name: 'VersionB'
                    layout: (LayoutFrame 5 0.67 0 0 0 1 30 0)
                    minorKey: versionBLabelSpec
                  )
                 )
               
              )
            )
           (ArbitraryComponentSpec
              name: 'Diff3TextView'
              layout: (LayoutFrame 0 0 30 0 0 1 0 1)
              hasHorizontalScrollBar: false
              hasVerticalScrollBar: false
              autoHideScrollBars: false
              hasBorder: false
              component: #'Tools::Diff3CodeView2'
              postBuildCallback: postBuildDiffView:
            )
           )
         
        )
      )
!

mergeSpec
    "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::TextDiff3Tool andSelector:#mergeSpec
     Tools::TextDiff3Tool new openInterface:#mergeSpec
    "

    <resource: #canvas>

    ^ 
     #(FullSpec
        name: mergeSpec
        window: 
       (WindowSpec
          label: 'Merge view'
          name: 'Merge view'
          min: (Point 10 10)
          bounds: (Rectangle 0 0 782 506)
        )
        component: 
       (SpecCollection
          collection: (
           (VariableVerticalPanelSpec
              name: 'DiffAndMergePanel'
              layout: (LayoutFrame 0 0 0 0 0 1 0 1)
              component: 
             (SpecCollection
                collection: (
                 (UISubSpecification
                    name: 'DiffView'
                    minorKey: diff3Spec
                  )
                 (TransparentBoxSpec
                    name: 'MergeView'
                    component: 
                   (SpecCollection
                      collection: (
                       (UISubSpecification
                          name: 'MergeLabel'
                          layout: (LayoutFrame 0 0 0 0 0 1 30 0)
                          minorKey: versionMergedLabelSpec
                        )
                       (TextEditorSpec
                          name: 'MergeCode'
                          layout: (LayoutFrame 0 0 30 0 0 1 0 1)
                          model: textMergedHolder
                          hasHorizontalScrollBar: true
                          hasVerticalScrollBar: true
                          hasKeyboardFocusInitially: false
                          viewClassName: 'Tools::CodeView2'
                          postBuildCallback: postBuildMergeView:
                        )
                       )
                     
                    )
                  )
                 )
               
              )
              handles: (Any 0.5 1.0)
            )
           )
         
        )
      )
! !

!TextDiff3Tool class methodsFor:'interface specs - labels'!

versionMergedLabelSpec
    "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::TextDiff3Tool andSelector:#versionMergedLabelSpec
     Tools::TextDiff3Tool new openInterface:#versionMergedLabelSpec
    "

    <resource: #canvas>

    ^ 
     #(FullSpec
        name: versionMergedLabelSpec
        window: 
       (WindowSpec
          label: 'Merge'
          name: 'Merge'
          min: (Point 10 10)
          bounds: (Rectangle 0 0 774 30)
        )
        component: 
       (SpecCollection
          collection: (
           (LabelSpec
              label: 'versionMerged24x24'
              name: 'VersionMergedIcon'
              layout: (LayoutFrame 0 0 -12 0.5 27 0 12 0.5)
              hasCharacterOrientedLabel: false
              translateLabel: true
            )
           (LabelSpec
              label: 'Merge'
              name: 'VersionMergeLabel'
              layout: (LayoutFrame 30 0 5 0 -350 1 0 1)
              translateLabel: true
              labelChannel: labelMergedHolder
              resizeForLabel: true
              adjust: left
              useDynamicPreferredWidth: true
              usePreferredWidth: true
            )
           (HorizontalPanelViewSpec
              name: 'HorizontalPanel1'
              layout: (LayoutFrame -350 1 0 0 0 1 0 1)
              horizontalLayout: center
              verticalLayout: center
              horizontalSpace: 3
              verticalSpace: 3
              component: 
             (SpecCollection
                collection: (
                 (ActionButtonSpec
                    label: 'Merge'
                    name: 'MergeAuto'
                    translateLabel: true
                    model: doMergeAuto
                    extent: (Point 80 22)
                  )
                 (ActionButtonSpec
                    label: 'Use Base'
                    name: 'MergeBase'
                    translateLabel: true
                    model: doMergeUsingBase
                    extent: (Point 80 22)
                  )
                 (ActionButtonSpec
                    label: 'Use A'
                    name: 'MergeUsingA'
                    translateLabel: true
                    model: doMergeUsingA
                    extent: (Point 80 22)
                  )
                 (ActionButtonSpec
                    label: 'Use B'
                    name: 'MergeUsingB'
                    translateLabel: true
                    model: doMergeUsingB
                    extent: (Point 80 22)
                  )
                 )
               
              )
            )
           )
         
        )
      )
! !

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

    ^ #(
        #codeAspectHolder
        #labelAHolder
        #labelBHolde
        #labelCHolder
        #labelHolder
        #languageHolder
        #textAHolder
        #textBHolder
        #textCHolder

        #mergeHolder
        #mergeDataHolder
      ).

    "Modified: / 19-03-2012 / 11:54:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool methodsFor:'accessing'!

beDiff3Tool

    self mergeHolder value: false

    "Created: / 17-03-2012 / 12:23:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

beMergeTool

    self mergeHolder value: true

    "Created: / 17-03-2012 / 12:23:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

mergeData

    ^self mergeDataHolder value

    "Created: / 20-03-2012 / 14:17:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool methodsFor:'actions'!

doMergeAuto

    self mergeDataHolder value 
        text1: self textC text2: self textA text3: self textB.

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

doMergeUsingA

    self mergeData mergeUsingA

    "Created: / 17-03-2012 / 12:55:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

doMergeUsingB

    self mergeData mergeUsingB

    "Created: / 17-03-2012 / 12:55:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

doMergeUsingBase

    self mergeData mergeUsingBase

    "Created: / 17-03-2012 / 12:55:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool methodsFor:'aspects'!

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

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

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

    |oldValue newValue|

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

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

    mergeHolder isNil ifTrue:[
        mergeHolder := ValueHolder with: false.
        mergeHolder addDependent:self.
    ].
    ^ mergeHolder

    "Modified: / 16-03-2012 / 13:24:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

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

    |oldValue newValue|

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

!TextDiff3Tool methodsFor:'aspects-versions'!

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

    labelMergedHolder isNil ifTrue:[
        labelMergedHolder := ValueHolder with:'Merge'.
    ].
    ^ labelMergedHolder

    "Modified: / 17-03-2012 / 12:36:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

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

    labelMergedHolder := something.
!

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

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

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

    textMergedHolder := something.
! !

!TextDiff3Tool methodsFor:'change & update'!

update:something with:aParameter from:changedObject
    "Invoked when an object that I depend upon sends a change notification."

    "stub code automatically generated - please change as required"

    changedObject == mergeHolder ifTrue:[
        self updateViews.
        self updateMergeData.
        self updateCodeViewSynchronization.
         ^ self.
    ].
    super update:something with:aParameter from:changedObject

    "Modified: / 19-03-2012 / 14:29:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

updateAfterAorBorCChanged

    (textAChanged & textBChanged & textCChanged) ifTrue:[
        textAChanged := textBChanged := textCChanged := false.
        self updateViews.
        self isMerge ifTrue:[
            self updateMergeData.
        ].
    ].

    "Created: / 16-03-2012 / 15:26:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

updateCodeViewSynchronization

    diffView isNil ifTrue:[ ^ self ].
    mergeView isNil ifTrue:[ ^ self ].
    self isMerge ifTrue:[
        diffView synchronizeWith: mergeView. 
        diffView textViews do:[:e|
            mergeView synchronizeWith: e.
        ]
    ] ifFalse:[
        diffView unsynchronizeWith: mergeView.
        diffView textViews do:[:e|
            mergeView unsynchronizeWith: e.
        ]

    ]

    "Created: / 19-03-2012 / 14:24:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

updateMergeData
    | data |

    (data := self mergeDataHolder value) isNil ifTrue:[
        data := TextMergeInfo new.
        data text1: self textC text2: self textA text3: self textB.
        self mergeDataHolder value: data.
    ].

    "Created: / 19-03-2012 / 11:52:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

updateViews

    self mergeHolder value ifTrue:[
        self contentSpecHolder value: #mergeSpec
    ] ifFalse:[
        self contentSpecHolder value: #diff3Spec
    ].

    diffView notNil ifTrue:[
        diffView
            text1: self textCHolder value
            text2: self textAHolder value
            text3: self textBHolder value.
    ]

    "Created: / 16-03-2012 / 13:24:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool methodsFor:'hooks'!

commonPostBuild
    self updateViews

    "Created: / 16-03-2012 / 13:25:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

postBuildDiffView:aScrollableView

    super postBuildDiffView:aScrollableView.
    diffView notNil ifTrue:[
       (self textAHolder value notNil and:[self textBHolder value notNil and:[self textCHolder value notNil]]) ifTrue:[
            diffView scrolledView
                text1: self textCHolder value
                text2: self textAHolder value
                text3: self textBHolder value

        ].
        self updateCodeViewSynchronization.
    ].

    "Created: / 16-03-2012 / 13:31:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

postBuildMergeView:aCodeView2

    mergeView := aCodeView2.
    mergeView registerService: 
                (MergeService new
                    dataHolder: self mergeDataHolder;
                    yourself).
    self updateCodeViewSynchronization.

    "Created: / 19-03-2012 / 11:47:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool methodsFor:'testing'!

isDiff3
    ^true

    "Created: / 16-03-2012 / 15:21:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

isMerge

    ^self mergeHolder value

    "Created: / 19-03-2012 / 11:53:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool::MergeService class methodsFor:'accessing'!

label
    "Answers short label - for UI"

    ^'Merge Support Service'

    "Created: / 19-03-2012 / 11:48:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool::MergeService class methodsFor:'testing'!

isAvailable

    ^false "/Should be installed explicitly"

    "Created: / 19-03-2012 / 11:45:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool::MergeService methodsFor:'accessing'!

infoAtLine: lineNr

    ^(lineNr between: 1 and: data listInfos size) ifTrue:[
        data listInfos at: lineNr
    ] ifFalse:[
        nil
    ]

    "Created: / 19-03-2012 / 13:15:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool::MergeService methodsFor:'aspects'!

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

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

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

    |oldValue newValue|

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

!TextDiff3Tool::MergeService methodsFor:'change & update'!

dataChanged
    "Merge data has changes, update text view"
    | changed |

    textView isNil ifTrue:[ 
        ^ self  "/not yet registered
    ]. 
    data isNil ifTrue:[
        textView list: #().
        ^self.
    ].

    "/Collect conflicted lines"
    changed := data listInfos 
                select:[:info|info isConflict]
                thenCollect:[:info|info line].

    textView changedLines: changed.
    textView diffMode: true.
    textView list: data list.
    textView invalidate.
    gutterView invalidate.

    "Created: / 19-03-2012 / 12:41:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

dataHolderChanged

    data notNil ifTrue:[
        data removeDependent: self.
    ].
    data := dataHolder value.
    data notNil ifTrue:[
        data addDependent: self.
    ].
    self dataChanged

    "Created: / 19-03-2012 / 11:56:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

update:something with:aParameter from:changedObject
    "Invoked when an object that I depend upon sends a change notification."

    "stub code automatically generated - please change as required"

    changedObject == dataHolder ifTrue:[
         self dataHolderChanged.
         ^ self.
    ].
    changedObject == data ifTrue:[
         self dataChanged.
         ^ self.
    ].
    super update:something with:aParameter from:changedObject

    "Modified: / 19-03-2012 / 12:41:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool::MergeService methodsFor:'drawing'!

drawLine:lineNo in:view atX:x y:y width:w height:h from:startCol to:endColOrNil with:fg and:bg 
    "Called by both gutterView and textView (well, not yet) to
     allow services to draw custom things on text view.
     Ask JV what the args means if unsure (I'm lazy to document
     them, now it is just an experiment...)"

    | info |

    view == gutterView ifFalse:[ ^ self ].
    info := self infoAtLine: lineNo.
    info isNil ifTrue:[ ^self ].

    view fillRectangleX:x y:y - h 
            width:6 height:h + textView lineSpacing + 3"Magic constant to make it look nicer"
            color: info color.

    "Created: / 19-03-2012 / 13:15:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool::MergeService methodsFor:'event handling'!

linesModifiedFrom: start to: end

    start to: end do:[:i|
        (data listInfos at:i) resolution: #Merged.
    ].
    gutterView invalidate.

    "Created: / 06-07-2011 / 17:14:36 / jv"
    "Created: / 20-03-2012 / 22:57:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool::MergeService methodsFor:'registering'!

registerIn: aCodeView

    "Installs myself in aCodeView"

    super registerIn: aCodeView.
    self dataChanged.

    "Modified: / 17-06-2011 / 13:07:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Created: / 19-03-2012 / 12:52:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TextDiff3Tool class methodsFor:'documentation'!

version_SVN
    ^ '$Id: Tools__TextDiff3Tool.st 7948 2012-03-21 01:52:35Z vranyj1 $'
! !