HierarchicalListEditor.st
author tz
Tue, 03 Feb 1998 17:13:23 +0100
changeset 566 58b18ffe959c
parent 562 f16b2ca2be5b
child 581 399646a86258
permissions -rw-r--r--
info bar layout changed

"
 COPYRIGHT (c) 1997 by eXept Software AG / Claus Gittinger
              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.
"




ToolApplicationModel subclass:#HierarchicalListEditor
	instanceVariableNames:'isModified didInstall treeView specClass specSelector'
	classVariableNames:'CopyBuffer'
	poolDictionaries:''
	category:'Interface-UIPainter'
!

!HierarchicalListEditor class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1997 by eXept Software AG / Claus Gittinger
              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
"
    HierarchicalListEditor is used by the UIPainter to
    create or maintain a hierarchical list.

    [start with:]
        HierarchicalListEditor open

    [see also:]
        UIPainter

    [author:]
        Claus Atzkern, eXept Software AG
"



! !

!HierarchicalListEditor class methodsFor:'help specs'!

helpSpec
    "return a dictionary filled with helpKey -> helptext associations.
     These are used by the activeHelp tool."

    "
    UIHelpTool openOnClass:HierarchicalListEditor    
    "

  ^ super helpSpec addPairsFrom:#(

#addChild
'Adds a new child item.'

#addSister
'Adds a new sister item.'

#fileNew
'Creates a new hierarchical list.'

#fileReload
'Reload hierarchical list from current class and selector.'

#fileSave
'Saves current hierarchical list.'

)
! !

!HierarchicalListEditor class methodsFor:'interface specs'!

classAndMethodSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:HierarchicalListEditor andSelector:#classAndMethodSpec
     HierarchicalListEditor new openInterface:#classAndMethodSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'Hierarchical List Editor'
              #'layout:' #(#LayoutFrame 213 0 373 0 513 0 501 0)
              #'label:' 'Hierarchical List Editor'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1160 870)
              #'bounds:' #(#Rectangle 213 373 514 502)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#FramedBoxSpec
                    #'name:' 'framedBox1'
                    #'layout:' #(#LayoutFrame 0 0.0 3 0.0 0 1.0 -33 1.0)
                    #'label:' 'Class and selector for code'
                    #'labelPosition:' #topLeft
                )
                 #(#LabelSpec
                    #'name:' 'classLabel'
                    #'layout:' #(#AlignmentOrigin 53 0.11 39 0 1 0.5)
                    #'label:' 'Class:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'classField'
                    #'layout:' #(#LayoutFrame 57 0.11 27 0 -19 1.0 49 0)
                    #'enableChannel:' #canChangeClassName
                    #'tabable:' true
                    #'model:' #specClassChannel
                )
                 #(#LabelSpec
                    #'name:' 'methodLabel'
                    #'layout:' #(#AlignmentOrigin 53 0.11 64 0 1 0.5)
                    #'label:' 'Selector:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'methodField'
                    #'layout:' #(#LayoutFrame 57 0.11 52 0 -19 1.0 74 0)
                    #'tabable:' true
                    #'model:' #specSelectorChannel
                    #'type:' #string
                )
                 #(#UISubSpecification
                    #'name:' 'SubSpecification'
                    #'layout:' #(#LayoutFrame 0 0.0 -29 1 0 1.0 -5 1.0)
                    #'majorKey:' #ToolApplicationModel
                    #'minorKey:' #windowSpecForCommitWithoutChannels
                )
              )
          )
      )
!

windowSpec
    "this window spec was automatically generated by the ST/X UIPainter"

    "do not manually edit this - the painter/builder may not be able to
     handle the specification if its corrupted."

    "
     UIPainter new openOnClass:HierarchicalListEditor andSelector:#windowSpec
     HierarchicalListEditor new openInterface:#windowSpec
    "
    "HierarchicalListEditor open"

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'Hierarchical List Editor'
              #'layout:' #(#LayoutFrame 366 0 355 0 840 0 667 0)
              #'label:' 'Hierarchical List Editor'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1160 870)
              #'bounds:' #(#Rectangle 366 355 841 668)
              #'menu:' #menu
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#MenuPanelSpec
                    #'name:' 'menuToolbarView'
                    #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 32 0)
                    #'menu:' #menuToolbar
                )
                 #(#VariableHorizontalPanelSpec
                    #'name:' 'variableHorizontalPanel'
                    #'layout:' #(#LayoutFrame 0 0.0 34 0.0 0 1.0 -26 1.0)
                    #'component:' 
                     #(#SpecCollection
                        #'collection:' 
                         #(
                           #(#ArbitraryComponentSpec
                              #'name:' 'treeView'
                              #'menu:' #menuEdit
                              #'hasHorizontalScrollBar:' true
                              #'hasVerticalScrollBar:' true
                              #'miniScrollerHorizontal:' true
                              #'miniScrollerVertical:' true
                              #'component:' #treeView
                              #'hasBorder:' false
                          )
                           #(#ViewSpec
                              #'name:' 'specView'
                              #'component:' 
                               #(#SpecCollection
                                  #'collection:' 
                                   #(
                                     #(#LabelSpec
                                        #'name:' 'nameLabel'
                                        #'layout:' #(#AlignmentOrigin 107 0 25 0 1 0.5)
                                        #'label:' 'Name:'
                                        #'resizeForLabel:' true
                                    )
                                     #(#InputFieldSpec
                                        #'name:' 'nameInputField'
                                        #'layout:' #(#LayoutFrame 110 0 15 0 -5 1.0 37 0)
                                        #'tabable:' true
                                        #'model:' #itemName
                                    )
                                     #(#LabelSpec
                                        #'name:' 'valueLabel'
                                        #'layout:' #(#AlignmentOrigin 107 0 51 0 1 0.5)
                                        #'label:' 'Value:'
                                        #'resizeForLabel:' true
                                    )
                                     #(#InputFieldSpec
                                        #'name:' 'valueInputField'
                                        #'layout:' #(#LayoutFrame 110 0 41 0 -5 1.0 63 0)
                                        #'tabable:' true
                                        #'model:' #itemValue
                                        #'type:' #symbolOrNil
                                    )
                                     #(#UISubSpecification
                                        #'name:' 'SubSpecification'
                                        #'layout:' #(#LayoutFrame 2 0.0 -26 1.0 -2 1.0 -2 1.0)
                                        #'majorKey:' #ToolApplicationModel
                                        #'minorKey:' #windowSpecForCommit
                                    )
                                  )
                              )
                              #'level:' -1
                          )
                        )
                    )
                    #'handles:' #(#Any 0.368421 1.0)
                )
                 #(#UISubSpecification
                    #'name:' 'infoBarSubSpec'
                    #'layout:' #(#LayoutFrame 0 0.0 -24 1 0 1.0 0 1.0)
                    #'majorKey:' #ToolApplicationModel
                    #'minorKey:' #windowSpecForInfoBar
                )
              )
          )
      )
! !

!HierarchicalListEditor class methodsFor:'menu specs'!

menu
    "this window spec was automatically generated by the ST/X MenuEditor"

    "do not manually edit this - the builder may not be able to
     handle the specification if its corrupted."

    "
     MenuEditor new openOnClass:HierarchicalListEditor andSelector:#menu
     (Menu new fromLiteralArrayEncoding:(HierarchicalListEditor menu)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #'label:' 'About'
                #'labelImage:' #(#ResourceRetriever nil #menuIcon)
                #'submenuChannel:' #menuAbout
            )
             #(#MenuItem
                #'label:' 'File'
                #'submenu:' 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #'label:' 'New'
                          #'value:' #doNew
                          #'activeHelpKey:' #fileNew
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Reload'
                          #'value:' #doReload
                          #'activeHelpKey:' #fileReload
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Save'
                          #'value:' #doInstall
                          #'activeHelpKey:' #fileSave
                          #'enabled:' #hasValidClass
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Define Class And Selector...'
                          #'value:' #doDefineClass
                          #'activeHelpKey:' #fileDefineClassAndSelector
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Exit'
                          #'value:' #closeRequest
                          #'activeHelpKey:' #fileExit
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #'label:' 'Edit'
                #'submenuChannel:' #menuEdit
            )
             #(#MenuItem
                #'label:' 'Add'
                #'submenu:' 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #'label:' 'Child'
                          #'value:' #doCreateChild
                          #'activeHelpKey:' #addChild
                          #'enabled:' #canCreateChildChannel
                          #'labelImage:' #(#ResourceRetriever #HierarchicalListEditor #createChildIcon 'Child')
                      )
                       #(#MenuItem
                          #'label:' 'Sister'
                          #'value:' #doCreateSister
                          #'activeHelpKey:' #addSister
                          #'enabled:' #canCreateSisterChannel
                          #'labelImage:' #(#ResourceRetriever #HierarchicalListEditor #createSisterIcon 'Sister')
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #'label:' 'Browse'
                #'enabled:' #hasValidClass
                #'submenu:' 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #'label:' 'Class'
                          #'value:' #'doBrowse:'
                          #'argument:' #class
                      )
                       #(#MenuItem
                          #'label:' 'Method'
                          #'value:' #'doBrowse:'
                          #'enabled:' #hasValidMethodSelector
                          #'argument:' #method
                      )
                       #(#MenuItem
                          #'label:' 'Specification'
                          #'value:' #'doBrowse:'
                          #'enabled:' #hasValidSpecSelector
                          #'argument:' #spec
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #'label:' 'Help'
                #'startGroup:' #right
                #'submenuChannel:' #menuHelp
            )
          ) nil
          nil
      )
!

menuEdit
    "this window spec was automatically generated by the ST/X MenuEditor"

    "do not manually edit this - the builder may not be able to
     handle the specification if its corrupted."

    "
     MenuEditor new openOnClass:HierarchicalListEditor andSelector:#menuEdit
     (Menu new fromLiteralArrayEncoding:(HierarchicalListEditor menuEdit)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #'label:' 'Cut'
                #'value:' #doCut
                #'activeHelpKey:' #editCut
                #'enabled:' #canCut
            )
             #(#MenuItem
                #'label:' 'Copy'
                #'value:' #doCopy
                #'activeHelpKey:' #editCopy
                #'enabled:' #canCopy
            )
             #(#MenuItem
                #'label:' 'Paste'
                #'value:' #doPaste
                #'activeHelpKey:' #editPaste
                #'enabled:' #canPaste
            )
             #(#MenuItem
                #'label:' '-'
            )
             #(#MenuItem
                #'label:' 'Move Up'
                #'value:' #doStepUp
                #'activeHelpKey:' #editMoveUp
                #'enabled:' #canStepOverChannel
                #'labelImage:' #(#ResourceRetriever #ToolApplicationModel #upIcon 'Move Up')
            )
             #(#MenuItem
                #'label:' 'Move Down'
                #'value:' #doStepDown
                #'activeHelpKey:' #editMoveDown
                #'enabled:' #canStepOverChannel
                #'labelImage:' #(#ResourceRetriever #ToolApplicationModel #downIcon 'Move Down')
            )
             #(#MenuItem
                #'label:' 'Move In'
                #'value:' #doStepIn
                #'activeHelpKey:' #editMoveIn
                #'enabled:' #canStepInChannel
                #'labelImage:' #(#ResourceRetriever #ToolApplicationModel #downRightIcon 'Move In')
            )
             #(#MenuItem
                #'label:' 'Move Out'
                #'value:' #doStepOut
                #'activeHelpKey:' #editMoveOut
                #'enabled:' #canStepOutChannel
                #'labelImage:' #(#ResourceRetriever #ToolApplicationModel #leftDownIcon 'Move Out')
            )
          ) nil
          nil
      )
!

menuToolbar
    "this window spec was automatically generated by the ST/X MenuEditor"

    "do not manually edit this - the builder may not be able to
     handle the specification if its corrupted."

    "
     MenuEditor new openOnClass:HierarchicalListEditor andSelector:#menuToolbar
     (Menu new fromLiteralArrayEncoding:(HierarchicalListEditor menuToolbar)) startUp
    "

    <resource: #menu>

    ^
     
       #(#Menu
          
           #(
             #(#MenuItem
                #'label:' 'New'
                #'isButton:' true
                #'value:' #doNew
                #'activeHelpKey:' #fileNew
                #'labelImage:' #(#ResourceRetriever nil #newIcon)
            )
             #(#MenuItem
                #'label:' 'Save'
                #'isButton:' true
                #'value:' #doInstall
                #'activeHelpKey:' #fileSave
                #'enabled:' #hasValidClass
                #'labelImage:' #(#ResourceRetriever nil #saveIcon)
            )
             #(#MenuItem
                #'label:' ''
            )
             #(#MenuItem
                #'label:' 'Add Child'
                #'isButton:' true
                #'value:' #doCreateChild
                #'activeHelpKey:' #addChild
                #'enabled:' #canCreateChildChannel
                #'labelImage:' #(#ResourceRetriever nil #createChildIcon)
            )
             #(#MenuItem
                #'label:' 'Add Sister'
                #'isButton:' true
                #'value:' #doCreateSister
                #'activeHelpKey:' #addSister
                #'enabled:' #canCreateSisterChannel
                #'labelImage:' #(#ResourceRetriever nil #createSisterIcon)
            )
             #(#MenuItem
                #'label:' ''
            )
             #(#MenuItem
                #'label:' 'Move Up'
                #'isButton:' true
                #'value:' #doStepUp
                #'activeHelpKey:' #editMoveUp
                #'enabled:' #canStepOverChannel
                #'labelImage:' #(#ResourceRetriever nil #upIcon)
            )
             #(#MenuItem
                #'label:' 'Move Down'
                #'isButton:' true
                #'value:' #doStepDown
                #'activeHelpKey:' #editMoveDown
                #'enabled:' #canStepOverChannel
                #'labelImage:' #(#ResourceRetriever nil #downIcon)
            )
             #(#MenuItem
                #'label:' 'Move In'
                #'isButton:' true
                #'value:' #doStepIn
                #'activeHelpKey:' #editMoveIn
                #'enabled:' #canStepInChannel
                #'labelImage:' #(#ResourceRetriever nil #downRightIcon)
            )
             #(#MenuItem
                #'label:' 'Move Out'
                #'isButton:' true
                #'value:' #doStepOut
                #'activeHelpKey:' #editMoveOut
                #'enabled:' #canStepOutChannel
                #'labelImage:' #(#ResourceRetriever nil #leftDownIcon)
            )
          ) nil
          nil
      )
! !

!HierarchicalListEditor class methodsFor:'printing'!

prettyPrintArray:anArray on:aStream indent:anIndent
    "print a literal array in a nice format
    "
    |arg sol|

    sol := aStream position.
    aStream spaces:anIndent.
    aStream nextPutAll:'#('.

    anArray first isSymbol ifTrue:[
        arg := anArray first.
        aStream nextPut:$#.
        aStream nextPutAll:anArray first.
        aStream cr.
        anArray size == 2 ifTrue:[
            self prettyPrintArray:(anArray last)
                               on:aStream
                           indent:(anIndent + 4).
        ].
        aStream spaces:anIndent.
        aStream nextPut:$).
      ^ self  
    ].

    aStream nextPut:$'.
    aStream nextPutAll:(anArray at:1).
    aStream nextPut:$'.
    arg := anArray at:2 ifAbsent:nil.

    arg isString ifTrue:[
        aStream spaces:((50 - (aStream position - sol)) max:4).

        arg isSymbol ifTrue:[
            aStream nextPut:$#.
        ].
        aStream nextPut:$'.
        aStream nextPutAll:arg.
        aStream nextPut:$'.
        arg := anArray at:3 ifAbsent:nil.
    ].
    arg isArray ifTrue:[
        aStream nextPutAll:' #('.
        aStream cr.
        arg do:[:e|self prettyPrintArray:e on:aStream indent:(anIndent + 4)].
        aStream spaces:anIndent.
        aStream nextPut:$).
    ].
    aStream nextPut:$).
    aStream cr.
! !

!HierarchicalListEditor class methodsFor:'resources'!

createChildIcon
    "Generated by the Image Editor"
    "
    ImageEditor openOnClass:self andSelector:#createChildIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'HierarchicalListEditor createChildIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@AUUUUP@@A????2@@A????2 @A????0@@A?????8@A?????8@A?????8@A?????8@A?????8@A?????8@A?????8@A?????8@A?????8@A<3L308@A33L33H@A30L33H@A33L33H@A<3L008@A?????8@C*****(@@@@@@@@@'); colorMap:(((Array new:4) at:1 put:((Color black)); at:2 put:((Color white)); at:3 put:((Color grey:49.9962)); at:4 put:((Color grey:66.9978)); yourself)); mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'_?>@_??@_?? _??0_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8'); yourself); yourself]!

createSisterIcon
    "Generated by the Image Editor"
    "
    ImageEditor openOnClass:self andSelector:#createSisterIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'HierarchicalListEditor createSisterIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@AUUUUP@@A????2@@A????2 @A????0@@A?????8@A?????8@A?????8@A<L<O?8@A3<3??8@A<<<<C8@A?L?O?8@A0<0??8@A?????8@A0LCC?8@A<<?L?8@A<<CC?8@A<<?L?8@A<<CL?8@A?????8@C*****(@@@@@@@@@'); colorMap:(((Array new:4) at:1 put:((Color black)); at:2 put:((Color white)); at:3 put:((Color grey:49.9962)); at:4 put:((Color grey:66.9978)); yourself)); mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'_?>@_??@_?? _??0_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8_??8'); yourself); yourself]! !

!HierarchicalListEditor methodsFor:'accessing'!

didInstall
    "returns true if spec was installed by operator"

    ^didInstall ? false
!

selectorName
    "returns current spec. selector"

    ^specSelector
! !

!HierarchicalListEditor methodsFor:'aspects'!

canCreateChildChannel
    "automatically generated by UIPainter ..."

    ^builder booleanValueAspectFor:#canCreateChildChannel

!

canCreateSisterChannel
    "automatically generated by UIPainter ..."

    ^builder booleanValueAspectFor:#canCreateSisterChannel

!

canStepInChannel
    "automatically generated by UIPainter ..."

    ^builder booleanValueAspectFor:#canStepInChannel

!

canStepOutChannel
    "automatically generated by UIPainter ..."

    ^builder booleanValueAspectFor:#canStepOutChannel

!

canStepOverChannel
    "automatically generated by UIPainter ..."

    ^builder booleanValueAspectFor:#canStepOverChannel

!

hasValidClass
    "automatically generated by UIPainter ..."

    ^builder booleanValueAspectFor:#hasValidClass

!

itemName
    "automatically generated by UIPainter ..."

    |holder|

    (holder := builder bindingAt:#itemName) isNil ifTrue:[
        builder aspectAt:#itemName put:(holder :=  ValueHolder new).
        holder addDependent:self.
    ].
    ^ holder
!

itemValue
    "automatically generated by UIPainter ..."

    |holder|

    (holder := builder bindingAt:#itemValue) isNil ifTrue:[
        builder aspectAt:#itemValue put:(holder :=  ValueHolder new).
        holder addDependent:self.
    ].
    ^ holder
!

treeView
    "automatically generated by UIPainter ..."

    ^treeView
! !

!HierarchicalListEditor methodsFor:'change & update'!

update:something with:aParameter from:someObject
    "one of my models changed"

    self valueOfEnablingCommitButtons value: true
! !

!HierarchicalListEditor methodsFor:'private'!

checkMenuItemModified
    "check item modification"

    self valueOfEnablingCommitButtons value
    ifTrue:
    [
        ((YesNoBox title:'Item was modified!!\Save it?\' withCRs)        
            noText:'No';
            yesText:'Yes';
            showAtPointer;
            accepted) ifFalse: [self valueOfEnablingCommitButtons value: false. ^true].
        self accept
    ].
    ^true
!

checkModified
    "check menu modification
    "
    isModified
    ifTrue:
    [
        ((YesNoBox title:'Hierarchical list was modified!!')        
            noText:'Cancel';
            yesText:'Waste it and proceed';
            showAtPointer;
            accepted) ifFalse: [^false].
        isModified := false
    ].
    ^true
!

newItem
    "creates and returns a new default item"

    ^TreeItem name: 'Item' contents: nil
!

updateChannels
    "update channels"

    |node parent chnStepIn chnStepOut chnStepOvr chnChild chnSister|

    chnStepIn := chnStepOut := chnStepOvr := chnChild := chnSister := false.

    (node := treeView selectedNode) notNil 
    ifTrue:
    [
        (builder componentAt: #specView) beVisible.
        chnChild := true.
        (parent := node parent) notNil 
        ifTrue:
        [
            chnSister  := true.
            chnStepOvr := parent numberOfChildren > 1.
            chnStepOut := parent parent notNil.
            chnStepIn  := node ~~ parent lastChild
        ]
    ]
    ifFalse:
    [
        (builder componentAt: #specView) beInvisible
    ].
    self canCreateChildChannel  value:chnChild.
    self canCreateSisterChannel value:chnSister.
    self canStepOverChannel     value:chnStepOvr.
    self canStepOutChannel      value:chnStepOut.
    self canStepInChannel       value:chnStepIn.


!

updateInputFields
    "reload item value into input fields"

    |node|

    (node := treeView selectedNode) notNil 
    ifTrue:
    [
        self itemName  value:node name.
        self itemValue value:node contents
    ] 
    ifFalse:
    [
        self itemName  value:''.
        self itemValue value:nil
    ].
    self valueOfEnablingCommitButtons value: false
! !

!HierarchicalListEditor methodsFor:'queries'!

canChangeClassName
    "returns true if current class could be changed which is dependent on
     the mode: standalone or started by UIPainter"

    ^masterApplication isNil
!

canCopy
    "returns true if any selection exists"

    ^treeView selection notNil
!

canCut
    "returns true if any selection exists and not includes
     the anchor (first element into list)."

    treeView selection notNil ifTrue:[^(treeView isInSelection:1) not].
    ^false
!

canPaste
    "returns true if something to be paste exists and a
     single selection exists"

    ^CopyBuffer notNil and:[treeView selectedNode notNil]
!

hasValidMethodSelector
    "returns true if the class and the instance selector defined
     allready exists."

    (specSelector notNil and:[self hasValidClass]) 
    ifTrue:
    [
        ^(specClass compiledMethodAt:specSelector) notNil
    ].    
    ^false
!

hasValidSpecSelector
    "returns true if the class and the class selector defined
     allready exists."

    (specSelector notNil and:[self hasValidClass])
    ifTrue:
    [
        ^(specClass class compiledMethodAt:specSelector) notNil
    ].
    ^false
! !

!HierarchicalListEditor methodsFor:'startup / release'!

buildFrom:aClass andSelector:aSelector
    "rebuild window from a class and selector"

    |sel anchor|

    specClass := self resolveName:aClass.
    specSelector := nil.

    aSelector size ~~ 0 
    ifTrue:
    [
        sel := aSelector asString withoutSeparators.
        sel size ~~ 0 ifTrue:[specSelector := sel asSymbol]
    ].
    treeView selection:nil.

    (specSelector notNil and:[specClass notNil]) 
    ifTrue:
    [
        (specClass respondsTo:specSelector) 
        ifTrue:
        [
            anchor := specClass perform:specSelector.
            anchor isArray ifTrue:[anchor := anchor decodeAsLiteralArray]
        ].
        self hasValidClass value: true
    ].
    anchor notNil 
        ifTrue: [anchor expand. treeView root:anchor] 
        ifFalse:[self doNew]
!

closeRequest
    "close request"

    (self checkMenuItemModified and: [self checkModified]) ifTrue: [super closeRequest]


!

initialize
    "setup default values"

    super initialize.

    treeView := SelectionInTreeView new.
    treeView multipleSelectOk: true.
    treeView showDirectoryIndicator: true.
    treeView showDirectoryIndicatorForRoot: false.
    treeView action:[:aNr| self updateChannels. self updateInputFields].
    treeView selectConditionBlock: [:i|self checkMenuItemModified].
    treeView validateDoubleClickBlock: [:node| node ~~ treeView model list first].
!

openModalOnClass:aClass andSelector:aSelector
    "open modal on class and selector"

    specClass := Association key:aClass value:aSelector.
    super openInterfaceModal.


!

openOnClass:aClass andSelector:aSelector
    "open on class and selector"

    specClass := Association key:aClass value:aSelector.
    super openInterface.

!

postBuildWith:builder
    "setup view"

    |cls sel|

    specClass isAssociation ifTrue:[
        cls := specClass key.
        sel := specClass value.
    ].
    self buildFrom:cls andSelector:sel.

    isModified := false

! !

!HierarchicalListEditor methodsFor:'user actions'!

accept
    "invoked by button 'OK'"

    |node index|

    (index := treeView selectedIndex) ~~ 0 
    ifTrue:
    [
        node := treeView nodeAtIndex:index.
        node name: self itemName value.
        node contents: self itemValue value.
        treeView redrawLine:index.
    ].
    isModified := true.
    self valueOfEnablingCommitButtons value: false
!

cancel
    "invoked by button 'Cancel'"

    self updateInputFields.

    isModified := false.
    self valueOfEnablingCommitButtons value: false
!

doBrowse:what
    "open a system browser"

    |cls sel|

    (cls := specClass) notNil 
    ifTrue:
    [
        what == #class 
        ifFalse:
        [
            (sel := specSelector) isNil ifTrue:[^self].
            what == #spec ifTrue:[cls := cls class]
        ].
        SystemBrowser openInClass:cls selector:sel
    ]
!

doCopy
    "copy current selected nodes into copy buffer"

    CopyBuffer := OrderedCollection new.
    treeView selectedNodesDo:[:aNode| CopyBuffer add: aNode copy]

!

doCreateChild
    "create a child within selected parent"

    |node newItem|

    (node := treeView selectedNode) notNil 
    ifTrue:
    [
        treeView model add: (newItem := self newItem) afterIndex: node children size below:node.
        newItem name: 'Child ', (self getDepthAndSistersNumberOfNode: newItem onParentNode: node).
        treeView selectedNodeExpand:true.
        treeView selectNode: newItem.
        self updateChannels.
        isModified := true
    ]
!

doCreateSister
    "create a sister next to selected item
    "
    |node newItem|

    (node := treeView selectedNode) notNil 
    ifTrue:
    [
        newItem := self newItem.
        node parent notNil 
            ifTrue: [treeView model add: newItem after:node] 
            ifFalse:[treeView model add: newItem beforeIndex:1 below:node].

        newItem name: 'Child ', (self getDepthAndSistersNumberOfNode: newItem onParentNode: node parent).
        treeView selectNode: newItem.
        self updateChannels.
        isModified := true
    ]
!

doCut
    "cut current selected nodes"

    |selection|
    treeView hasSelection 
    ifTrue:
    [
        self doCopy.
        selection := treeView selection asSortedCollection.
        treeView selectedNodesRemove.
        treeView selection: selection first - 1.
        self updateChannels.
        isModified := true
    ]
!

doDefineClass
    "define class and selector"

    |sel cls bindings accepted|

    accepted := true.
    bindings := IdentityDictionary new.

    specClass    notNil ifTrue:[cls := specClass name asString]
                       ifFalse:[cls := ''].

    specSelector notNil ifTrue:[sel := specSelector asString]
                       ifFalse:[sel := ''].

    bindings at:#specSelectorChannel put: sel asValue.
    bindings at:#specClassChannel    put: cls asValue.

    [accepted] 
    whileTrue:
    [
        (accepted := self openDialogInterface:#classAndMethodSpec withBindings:bindings)
        ifTrue:
        [
            (cls := self resolveName:(bindings at:#specClassChannel) value) notNil 
            ifTrue:
            [
                (sel := (bindings at:#specSelectorChannel) value withoutSeparators) size ~~ 0 
                ifTrue:
                [
                    specClass    := cls.
                    specSelector := sel asSymbol.
                    self hasValidClass value: true.
                    isModified := true.
                    ^self
                ]
            ]
        ]
    ]

!

doInstall
    "install code"

    |code spec category mthd stream|

    (specClass notNil and:[specSelector notNil])
    ifFalse:
    [
        ^self information:'No valid class and method defined!!'
    ].

    spec   := (treeView nodeAtIndex:1) literalArrayEncoding.
    stream := WriteStream on:String new.
    self class prettyPrintArray:spec on:stream indent:4.
    spec       := stream contents.
    category   := 'interface specs'.
    didInstall := true.
    isModified := false.

    (mthd := specClass class compiledMethodAt:specSelector) notNil 
    ifTrue:
    [
        category := mthd category
    ].

    code := Character excla asString 
            , specClass name , ' class methodsFor:' , category storeString
            , Character excla asString , '\\'

            , specSelector , '\'
            , '    "this window spec was automatically generated by the ST/X HierarchicalListEditor"\\'
            , '    "do not manually edit this - the builder may not be able to\'
            , '     handle the specification if its corrupted."\\'
            , '    "\'
            , '     HierarchicalListEditor new openOnClass:' , specClass name , ' andSelector:#' , specSelector , '\'
            , '    "\'.

    code := code 
            , '\'
            , '    <resource: #hierarchicalList>\\'
            , '    ^\' 
            , spec
            , ' decodeAsLiteralArray\'
            , Character excla asString
            , ' '
            , Character excla asString
            , '\\'.

    code := code withCRs.
    (ReadStream on:code) fileIn.

    (specClass compiledMethodAt:specSelector) isNil 
    ifTrue:
    [
        category := 'aspects'.

        code := Character excla asString 
                , specClass name , ' methodsFor:' , category storeString
                , Character excla asString , '\\'

                , specSelector , '\'
                , '    "this window spec was automatically generated by the ST/X HierarchicalListEditor"\\'
                , '    ^ self class ', specSelector
                , '\'
                , Character excla asString
                , ' '
                , Character excla asString
                , '\\'.

        code := code withCRs.
        (ReadStream on:code) fileIn
    ]


!

doNew
    "remove all items; restart"

    treeView root:(TreeItem name:'Root' contents:#anchor).
    treeView selection:1.
    isModified := true




!

doPaste
    "paste after current selected item"

    treeView selectedNodeAdd:CopyBuffer.
    CopyBuffer isCollection ifFalse: [treeView selectNode: CopyBuffer] ifTrue: [treeView selection: (CopyBuffer collect: [:node| treeView indexOfNode: node])].
    self updateChannels.
    isModified := true

!

doReload
    "reload spec from current class and selector"

    self buildFrom:specClass andSelector:specSelector

!

doStepDown
    "move selected item after next item"

    treeView selectedNodeChangeSequenceOrder:1.
    self updateChannels.
    isModified := true

!

doStepIn
    "lets become the selected item a child of its next sister"

    treeView selectedNodeBecomeChildOfNext.
    self updateChannels.
    isModified := true



!

doStepOut
    "let selected node become a sister of its current parent"

    treeView selectedNodeBecomeSisterOfParent.
    self updateChannels.
    isModified := true



!

doStepUp
    "move selected item before previous item"

    treeView selectedNodeChangeSequenceOrder:-1.
    self updateChannels.
    isModified := true



!

getDepthAndSistersNumberOfNode: aNode onParentNode: aParentNode
    "return depth of selected node"

    |parent childNode depthAndSistersNumbers str|

    depthAndSistersNumbers := OrderedCollection new.
    childNode := aNode.
    parent := aParentNode.
    [parent notNil] 
    whileTrue: 
    [
        depthAndSistersNumbers add: (parent children indexOf: childNode). 
        childNode := parent. 
        parent := parent parent. 
    ].
    depthAndSistersNumbers removeFirst; addFirst: aParentNode children size.
    str := ''.
    depthAndSistersNumbers reverseDo: [:n| str := str, n printString, '.'].
    ^str copyFrom: 1 to: str size - 1
! !

!HierarchicalListEditor class methodsFor:'documentation'!

version
    ^ '$Header$'
! !