HierarchicalListEditor.st
author tz
Fri, 23 Jan 1998 18:53:14 +0100
changeset 473 396ab247a5af
parent 469 28bcb1982ef9
child 484 ab3d54531432
permissions -rw-r--r--
be sure that file is selected

"
 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
"



! !

!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:' 'Painter'
              #'layout:' #(#LayoutFrame 233 0 430 0 533 0 558 0)
              #'label:' 'Painter'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1160 870)
              #'bounds:' #(#Rectangle 233 430 534 559)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'boxLabel'
                    #'layout:' #(#Point 5 10)
                    #'label:' 'Class and selector for code:'
                    #'adjust:' #left
                    #'resizeForLabel:' true
                )
                 #(#LabelSpec
                    #'name:' 'classLabel'
                    #'layout:' #(#AlignmentOrigin 45 0.11 51 0 1 0.5)
                    #'label:' 'Class:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'classField'
                    #'layout:' #(#LayoutFrame 47 0.11 39 0 -2 1.0 61 0)
                    #'tabable:' true
                    #'model:' #specClassChannel
                )
                 #(#LabelSpec
                    #'name:' 'methodLabel'
                    #'layout:' #(#AlignmentOrigin 45 0.11 74 0 1 0.5)
                    #'label:' 'Selector:'
                    #'adjust:' #right
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'methodField'
                    #'layout:' #(#LayoutFrame 47 0.11 64 0 -2 1.0 86 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
                )
              )
          )
      )
!

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 #icon)
                #'submenuChannel:' #menuAbout
            )
             #(#MenuItem
                #'label:' 'File'
                #'submenu:' 
                 #(#Menu
                    
                     #(
                       #(#MenuItem
                          #'label:' 'New'
                          #'value:' #doNew
                      )
                       #(#MenuItem
                          #'label:' 'Reload'
                          #'value:' #doReload
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Save'
                          #'value:' #doInstall
                          #'enabled:' #hasValidClass
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Define Selector...'
                          #'value:' #doDefineSelector
                          #'enabled:' #hasValidClass
                      )
                       #(#MenuItem
                          #'label:' 'Define Class...'
                          #'value:' #doDefineClass
                          #'enabled:' #canChangeClassName
                      )
                       #(#MenuItem
                          #'label:' '-'
                      )
                       #(#MenuItem
                          #'label:' 'Exit'
                          #'value:' #closeRequest
                      )
                    ) nil
                    nil
                )
            )
             #(#MenuItem
                #'label:' 'Edit'
                #'submenuChannel:' #menuEdit
            )
             #(#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
                )
            )
          ) 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
                #'enabled:' #canCut
            )
             #(#MenuItem
                #'label:' 'Copy'
                #'value:' #doCopy
                #'enabled:' #canCopy
            )
             #(#MenuItem
                #'label:' 'Paste'
                #'value:' #doPaste
                #'enabled:' #canPaste
            )
             #(#MenuItem
                #'label:' '-'
            )
             #(#MenuItem
                #'label:' 'Create Child'
                #'value:' #doCreateChild
                #'enabled:' #canCreateChildChannel
                #'labelImage:' #(#ResourceRetriever #HierarchicalListEditor #iconCreateChild)
            )
             #(#MenuItem
                #'label:' 'Create Sister'
                #'value:' #doCreateSister
                #'enabled:' #canCreateSisterChannel
                #'labelImage:' #(#ResourceRetriever #HierarchicalListEditor #iconCreateSister)
            )
          ) 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
                #'enabled:' #canCreateChildChannel
                #'labelImage:' #(#ResourceRetriever nil #newIcon)
            )
             #(#MenuItem
                #'label:' 'Save'
                #'isButton:' true
                #'value:' #doInstall
                #'enabled:' #canCreateChildChannel
                #'labelImage:' #(#ResourceRetriever nil #saveIcon)
            )
             #(#MenuItem
                #'label:' ''
            )
             #(#MenuItem
                #'label:' 'Create Child'
                #'isButton:' true
                #'value:' #doCreateChild
                #'enabled:' #canCreateChildChannel
                #'labelImage:' #(#ResourceRetriever nil #createChildIcon)
            )
             #(#MenuItem
                #'label:' 'Create Sister'
                #'isButton:' true
                #'value:' #doCreateSister
                #'enabled:' #canCreateSisterChannel
                #'labelImage:' #(#ResourceRetriever nil #createSisterIcon)
            )
             #(#MenuItem
                #'label:' ''
            )
             #(#MenuItem
                #'label:' 'Step Up'
                #'isButton:' true
                #'value:' #doStepUp
                #'enabled:' #canStepOverChannel
                #'labelImage:' #(#ResourceRetriever nil #upIcon)
            )
             #(#MenuItem
                #'label:' 'Step Down'
                #'isButton:' true
                #'value:' #doStepDown
                #'enabled:' #canStepOverChannel
                #'labelImage:' #(#ResourceRetriever nil #downIcon)
            )
             #(#MenuItem
                #'label:' 'Step In'
                #'isButton:' true
                #'value:' #doStepIn
                #'enabled:' #canStepInChannel
                #'labelImage:' #(#ResourceRetriever nil #downRightIcon)
            )
             #(#MenuItem
                #'label:' 'Step Out'
                #'isButton:' true
                #'value:' #doStepOut
                #'enabled:' #canStepOutChannel
                #'labelImage:' #(#ResourceRetriever nil #leftDownIcon)
            )
          ) nil
          nil
      )
!

methodSpec
    "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:#methodSpec
     HierarchicalListEditor new openInterface:#methodSpec
    "

    <resource: #canvas>

    ^
     
       #(#FullSpec
          #'window:' 
           #(#WindowSpec
              #'name:' 'Painter'
              #'layout:' #(#LayoutFrame 151 0 377 0 431 0 455 0)
              #'label:' 'Painter'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1160 870)
              #'bounds:' #(#Rectangle 151 377 432 456)
              #'usePreferredExtent:' false
          )
          #'component:' 
           #(#SpecCollection
              #'collection:' 
               #(
                 #(#LabelSpec
                    #'name:' 'boxLabel'
                    #'layout:' #(#LayoutFrame 0 0.0 3 0 0 1.0 20 0)
                    #'label:' 'Selector for code:'
                    #'adjust:' #left
                    #'resizeForLabel:' true
                )
                 #(#InputFieldSpec
                    #'name:' 'methodField'
                    #'layout:' #(#LayoutFrame 0 0.0 22 0 0 1.0 44 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 195 0 319 0 669 0 631 0)
              #'label:' 'Hierarchical List Editor'
              #'min:' #(#Point 10 10)
              #'max:' #(#Point 1160 870)
              #'bounds:' #(#Rectangle 195 319 670 632)
              #'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 -22 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)
                )
                 #(#LabelSpec
                    #'name:' 'infoLabel'
                    #'layout:' #(#LayoutFrame 0 0.0 -22 1 -80 1.0 0 1.0)
                    #'labelChannel:' #valueOfInfoLabel
                    #'level:' 1
                    #'adjust:' #left
                )
                 #(#LabelSpec
                    #'name:' 'timeLabel'
                    #'layout:' #(#LayoutFrame -80 1 -22 1 0 1.0 0 1.0)
                    #'labelChannel:' #valueOfTimeLabel
                    #'level:' 1
                    #'adjust:' #right
                )
              )
          )
      )
! !

!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
    "ImageEditor openOnClass:self andSelector:#createChildIcon"

    <resource: #image>
    ^(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(#[0 0 0 0 0 0 5 85 85 85 0 0 7 255 255 255 32 0 7 255 255 255 40 0 7 255 255 255 0 0 7 255 255 255 254 0 7 255 255 255 254 0 7 255 255 255 254 0 7 255 255 255 254 0 7 255 255 255 254 0 7 255 255 255 254 0 7 255 255 255 254 0 7 255 255 255 254 0 7 255 255 255 254 0 7 204 204 207 14 0 7 60 204 207 50 0 7 60 12 207 50 0 7 60 204 207 50 0 7 204 204 195 14 0 7 255 255 255 254 0 14 170 170 170 170 0 0 0 0 0 0 0]) ; 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:(#[127 255 128 127 255 192 127 255 224 127 255 240 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248]) ; yourself); yourself!

createSisterIcon
    "ImageEditor openOnClass:self andSelector:#createSisterIcon"

    <resource: #image>
    ^(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(#[0 0 0 0 0 0 5 85 85 85 0 0 7 255 255 255 32 0 7 255 255 255 40 0 7 255 255 255 0 0 7 255 255 255 254 0 7 255 255 255 254 0 7 255 255 255 254 0 7 195 60 63 254 0 7 63 51 255 254 0 7 207 60 240 62 0 7 243 63 63 254 0 7 15 48 255 254 0 7 255 255 255 254 0 7 3 3 15 254 0 7 207 63 51 254 0 7 207 3 15 254 0 7 207 63 51 254 0 7 207 3 51 254 0 7 255 255 255 254 0 14 170 170 170 170 0 0 0 0 0 0 0]) ; 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:(#[127 255 128 127 255 192 127 255 224 127 255 240 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248 127 255 248]) ; 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

!

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
!

newItem
    "creates and returns a new default item"

    ^TreeItem name: 'Undefined' 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]
!

hasValidClass
    "returns true if the class defined allready exists"

    ^specClass isBehavior
!

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]
        ]
    ].
    anchor notNil 
        ifTrue: [anchor expand. treeView root:anchor] 
        ifFalse:[self doNew]
!

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].
    self doNew.
!

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.

! !

!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.
    ].
    self valueOfEnablingCommitButtons value: false
!

cancel
    "invoked by button 'Cancel'"

    self updateInputFields.

    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|

    (node := treeView selectedNode) notNil 
    ifTrue:
    [
        treeView model add: self newItem beforeIndex:1 below:node.
        treeView selectedNodeExpand:true.
        self updateChannels.
    ]
!

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

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

doCut
    "cut current selected nodes"

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

doDefineClass
    "define class and selector"

    |sel cls bindings accepted|

    masterApplication notNil ifTrue:[^self information:'Only selector can be changed.'].
    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
                ]
            ]
        ]
    ]

!

doDefineSelector
    "define selector only"

    |sel bindings accepted|

    accepted := true.
    bindings := IdentityDictionary new.

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

    bindings at:#specSelectorChannel put:(sel asValue).

    [accepted] 
    whileTrue:
    [
        (accepted := self openDialogInterface:#methodSpec withBindings:bindings)
        ifTrue:
        [
            (sel := (bindings at:#specSelectorChannel) value withoutSeparators) size ~~ 0 
            ifTrue:
            [
                specSelector := sel asSymbol.
                ^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.

    (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:'Anchor' contents:#anchor).
    treeView selection:0

!

doPaste
    "paste after current selected item"

    treeView selectedNodeAdd:CopyBuffer.
    self updateChannels
!

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
!

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

    treeView selectedNodeBecomeChildOfNext.
    self updateChannels
!

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

    treeView selectedNodeBecomeSisterOfParent.
    self updateChannels
!

doStepUp
    "move selected item before previous item"

    treeView selectedNodeChangeSequenceOrder:-1.
    self updateChannels
! !

!HierarchicalListEditor class methodsFor:'documentation'!

version
    ^ '$Header$'
! !