TabItemEditor.st
changeset 500 c18c7621f8e9
child 514 5ac07e96e448
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TabItemEditor.st	Wed Jan 28 15:05:27 1998 +0100
@@ -0,0 +1,1068 @@
+"
+ COPYRIGHT (c) 1997 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.
+"
+
+
+
+ToolApplicationModel subclass:#TabItemEditor
+	instanceVariableNames:'rebuildMode className selector aspects listOfTabs hasChanged
+		selectedIndex'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'Interface-UIPainter'
+!
+
+!TabItemEditor class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 1997 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
+"
+    create and modify or inspect a list of tabs
+
+    [start with:]
+        TabItemEditor open
+
+    [see also:]
+        TabItem
+        TabView
+        NoteBookView
+        UIPainter
+
+    [author:]
+        Claus Atzkern
+"
+
+
+! !
+
+!TabItemEditor class methodsFor:'interface specs'!
+
+nameAndSelectorSpec
+    "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:TabItemEditor andSelector:#nameAndSelectorSpec
+     TabItemEditor new openInterface:#nameAndSelectorSpec
+    "
+
+    <resource: #canvas>
+
+    ^
+     
+       #(#FullSpec
+          #'window:' 
+           #(#WindowSpec
+              #'name:' 'Class & Selector'
+              #'layout:' #(#LayoutFrame 219 0 193 0 584 0 319 0)
+              #'label:' 'Class & Selector'
+              #'min:' #(#Point 10 10)
+              #'max:' #(#Point 1152 900)
+              #'bounds:' #(#Rectangle 219 193 585 320)
+              #'usePreferredExtent:' false
+          )
+          #'component:' 
+           #(#SpecCollection
+              #'collection:' 
+               #(
+                 #(#LabelSpec
+                    #'name:' 'DefineClassAndSelector'
+                    #'layout:' #(#Point 2 10)
+                    #'label:' 'Define Class And Selector'
+                    #'adjust:' #left
+                    #'resizeForLabel:' true
+                )
+                 #(#LabelSpec
+                    #'name:' 'ClassLabel'
+                    #'layout:' #(#AlignmentOrigin 50 0.11 51 0 1 0.5)
+                    #'label:' 'Class:'
+                    #'adjust:' #right
+                    #'resizeForLabel:' true
+                )
+                 #(#InputFieldSpec
+                    #'name:' 'ClassField'
+                    #'layout:' #(#LayoutFrame 51 0.11 39 0 -2 1.0 61 0)
+                    #'tabable:' true
+                    #'model:' #className
+                )
+                 #(#LabelSpec
+                    #'name:' 'SelectorLabel'
+                    #'layout:' #(#AlignmentOrigin 50 0.11 74 0 1 0.5)
+                    #'label:' 'Selector:'
+                    #'adjust:' #right
+                    #'resizeForLabel:' true
+                )
+                 #(#InputFieldSpec
+                    #'name:' 'SelectorField'
+                    #'layout:' #(#LayoutFrame 51 0.11 64 0 -2 1.0 86 0)
+                    #'tabable:' true
+                    #'model:' #selector
+                )
+                 #(#UISubSpecification
+                    #'name:' 'CommitPanel'
+                    #'layout:' #(#LayoutFrame 0 0.0 -29 1 0 1.0 -5 1)
+                    #'majorKey:' #ToolApplicationModel
+                    #'minorKey:' #windowSpecForCommitWithoutChannels
+                )
+              )
+          )
+      )
+!
+
+tabSpec
+    "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:TabItemEditor andSelector:#tabSpec
+     TabItemEditor new openInterface:#tabSpec
+    "
+
+    <resource: #canvas>
+
+    ^
+     
+       #(#FullSpec
+          #'window:' 
+           #(#WindowSpec
+              #'name:' 'Tab Basic'
+              #'layout:' #(#LayoutFrame 219 0 193 0 506 0 397 0)
+              #'label:' 'Tab Basic'
+              #'min:' #(#Point 10 10)
+              #'max:' #(#Point 1280 1024)
+              #'bounds:' #(#Rectangle 219 193 507 398)
+              #'usePreferredExtent:' false
+          )
+          #'component:' 
+           #(#SpecCollection
+              #'collection:' 
+               #(
+                 #(#LabelSpec
+                    #'name:' 'Label'
+                    #'layout:' #(#AlignmentOrigin 63 0 34 0 1 0.5)
+                    #'label:' 'Label:'
+                    #'resizeForLabel:' true
+                )
+                 #(#InputFieldSpec
+                    #'name:' 'LabelField'
+                    #'layout:' #(#LayoutFrame 66 0 24 0 -4 1.0 46 0)
+                    #'activeHelpKey:' #label
+                    #'model:' #label
+                )
+                 #(#CheckBoxSpec
+                    #'name:' 'TranslateLabel'
+                    #'layout:' #(#LayoutOrigin 63 0 49 0)
+                    #'activeHelpKey:' #translateLabel
+                    #'model:' #translateLabel
+                    #'label:' 'Label derives from Application'
+                )
+                 #(#ColorMenuSpec
+                    #'name:' 'ForegroundColorMenu'
+                    #'layout:' #(#LayoutFrame 94 0 104 0 -4 1.0 126 0)
+                    #'activeHelpKey:' #foregroundColor
+                    #'model:' #labelForegroundColor
+                    #'labelsAreColored:' false
+                )
+                 #(#LabelSpec
+                    #'name:' 'ForegroundLabel'
+                    #'layout:' #(#AlignmentOrigin 92 0 116 0 1 0.5)
+                    #'label:' 'Foreground:'
+                    #'adjust:' #right
+                    #'resizeForLabel:' true
+                )
+                 #(#CheckBoxSpec
+                    #'name:' 'CanSelect'
+                    #'layout:' #(#LayoutFrame 15 0 171 0 134 0 193 0)
+                    #'model:' #enabled
+                    #'label:' 'Can Select'
+                )
+              )
+          )
+      )
+!
+
+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:TabItemEditor andSelector:#windowSpec
+     TabItemEditor new openInterface:#windowSpec
+    "
+    "TabItemEditor open"
+
+    <resource: #canvas>
+
+    ^
+     
+       #(#FullSpec
+          #'window:' 
+           #(#WindowSpec
+              #'name:' 'TabItem Editor'
+              #'layout:' #(#LayoutFrame 219 0 193 0 687 0 521 0)
+              #'label:' 'TabItem Editor'
+              #'min:' #(#Point 10 10)
+              #'max:' #(#Point 1152 900)
+              #'bounds:' #(#Rectangle 219 193 688 522)
+              #'menu:' #menu
+              #'usePreferredExtent:' false
+          )
+          #'component:' 
+           #(#SpecCollection
+              #'collection:' 
+               #(
+                 #(#MenuPanelSpec
+                    #'name:' 'menuToolbarView'
+                    #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 34 0)
+                    #'menu:' #menuToolbar
+                )
+                 #(#VariableHorizontalPanelSpec
+                    #'name:' 'VariablePanel'
+                    #'layout:' #(#LayoutFrame 0 0.0 36 0.0 0 1.0 -22 1.0)
+                    #'component:' 
+                     #(#SpecCollection
+                        #'collection:' 
+                         #(
+                           #(#SequenceViewSpec
+                              #'name:' 'columnView'
+                              #'enableChannel:' #isNotModified
+                              #'model:' #selectionHolder
+                              #'menu:' #menuEdit
+                              #'hasHorizontalScrollBar:' true
+                              #'hasVerticalScrollBar:' true
+                              #'miniScrollerHorizontal:' true
+                              #'useIndex:' true
+                              #'sequenceList:' #listOfLabels
+                          )
+                           #(#ViewSpec
+                              #'name:' 'specView'
+                              #'component:' 
+                               #(#SpecCollection
+                                  #'collection:' 
+                                   #(
+                                     #(#SubCanvasSpec
+                                        #'name:' 'specCanvas'
+                                        #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 -30 1.0)
+                                        #'specHolder:' #specChannel
+                                    )
+                                     #(#HorizontalPanelViewSpec
+                                        #'name:' 'modifyPanel'
+                                        #'layout:' #(#LayoutFrame 0 0.0 -30 1.0 0 1.0 0 1.0)
+                                        #'component:' 
+                                         #(#SpecCollection
+                                            #'collection:' 
+                                             #(
+                                               #(#ActionButtonSpec
+                                                  #'name:' 'cancelButton'
+                                                  #'label:' 'Cancel'
+                                                  #'model:' #cancel
+                                                  #'enableChannel:' #modifiedChannel
+                                                  #'extent:' #(#Point 168 24)
+                                              )
+                                               #(#ActionButtonSpec
+                                                  #'name:' 'acceptButton'
+                                                  #'label:' 'OK'
+                                                  #'model:' #accept
+                                                  #'enableChannel:' #modifiedChannel
+                                                  #'extent:' #(#Point 168 24)
+                                              )
+                                            )
+                                        )
+                                        #'horizontalLayout:' #fitSpace
+                                        #'verticalLayout:' #fitSpace
+                                        #'horizontalSpace:' 3
+                                        #'verticalSpace:' 3
+                                    )
+                                  )
+                              )
+                              #'borderWidth:' 1
+                          )
+                        )
+                    )
+                    #'handles:' #(#Any 0.259875 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
+                )
+              )
+          )
+      )
+! !
+
+!TabItemEditor class methodsFor:'menus'!
+
+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:TabItemEditor andSelector:#menu
+     (Menu new fromLiteralArrayEncoding:(TabItemEditor menu)) startUp
+    "
+
+    <resource: #menu>
+
+    ^
+     
+       #(#Menu
+          
+           #(
+             #(#MenuItem
+                #'label:' 'File'
+                #'submenu:' 
+                 #(#Menu
+                    
+                     #(
+                       #(#MenuItem
+                          #'label:' 'New'
+                          #'value:' #doNew
+                      )
+                       #(#MenuItem
+                          #'label:' 'Reload'
+                          #'value:' #doReload
+                          #'enabled:' #hasClassAndSelector
+                      )
+                       #(#MenuItem
+                          #'label:' '-'
+                      )
+                       #(#MenuItem
+                          #'label:' 'Define Class And Selector...'
+                          #'value:' #doDefineClassAndSelector
+                      )
+                       #(#MenuItem
+                          #'label:' '-'
+                      )
+                       #(#MenuItem
+                          #'label:' 'Create Aspect Method'
+                          #'value:' #doInstallAspect
+                          #'enabled:' #hasClassAndSelector
+                      )
+                       #(#MenuItem
+                          #'label:' '-'
+                      )
+                       #(#MenuItem
+                          #'label:' 'Exit'
+                          #'value:' #closeRequest
+                          #'enabled:' #isNotModified
+                      )
+                    ) 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:self andSelector:#menuEdit
+     (Menu new fromLiteralArrayEncoding:(self menuEdit)) startUp
+    "
+
+    <resource: #menu>
+
+    ^
+
+       #(#Menu
+
+           #(
+             #(#MenuItem
+                #'label:' 'Cut'
+                #'value:' #doCutTab
+                #'enabled:' #isColumnSelected
+                #'shortcutKeyCharacter:' #Cut
+            )
+             #(#MenuItem
+                #'label:' 'Copy'
+                #'value:' #doCopyTab
+                #'enabled:' #isColumnSelected
+                #'shortcutKeyCharacter:' #Copy
+            )
+             #(#MenuItem
+                #'label:' 'Paste'
+                #'value:' #doPasteTab
+                #'enabled:' #valueOfHavingClipboard
+                #'shortcutKeyCharacter:' #Paste
+            )
+          ) 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:TabItemEditor andSelector:#menuToolbar
+     (Menu new fromLiteralArrayEncoding:(TabItemEditor menuToolbar)) startUp
+    "
+
+    <resource: #menu>
+
+    ^
+     
+       #(#Menu
+          
+           #(
+             #(#MenuItem
+                #'label:' 'Save'
+                #'isButton:' true
+                #'value:' #doInstallSpec
+                #'enabled:' #isNotModified
+                #'labelImage:' #(#ResourceRetriever nil #saveIcon)
+            )
+             #(#MenuItem
+                #'label:' ''
+            )
+             #(#MenuItem
+                #'label:' 'createLabel'
+                #'isButton:' true
+                #'value:' #doCreateTab
+                #'enabled:' #isNotModified
+                #'labelImage:' #(#ResourceRetriever #MenuEditor #menuItemImage)
+            )
+             #(#MenuItem
+                #'label:' ''
+            )
+             #(#MenuItem
+                #'label:' 'Move Tab Up'
+                #'isButton:' true
+                #'value:' #'doMoveTabUpOrDown:'
+                #'enabled:' #canMoveTabUpOrDown
+                #'argument:' #up
+                #'labelImage:' #(#ResourceRetriever nil #upIcon)
+            )
+             #(#MenuItem
+                #'label:' 'Move Tab Down'
+                #'isButton:' true
+                #'value:' #'doMoveTabUpOrDown:'
+                #'enabled:' #canMoveTabUpOrDown
+                #'argument:' #down
+                #'labelImage:' #(#ResourceRetriever nil #downIcon)
+            )
+          ) nil
+          nil
+      )
+! !
+
+!TabItemEditor class methodsFor:'resources'!
+
+newLabelIcon
+    "ImageEditor openOnClass:self andSelector:#newLabelIcon"
+
+    <resource: #image>
+    ^(Depth4Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(4 )); samplesPerPixel:(1); bits:(#[17 17 16 0 0 0 0 0 0 17 17 17 17 16 17 17 17 17 17 32 17 17 17 17 16 18 34 34 34 34 48 17 17 17 17 16 18 32 2 32 34 48 17 17 17 17 16 18 2 34 2 2 48 17 17 17 17 16 18 2 34 2 2 48 17 17 17 17 16 18 32 2 32 34 48 17 17 16 17 16 18 34 34 34 34 48 17 17 17 17 16 18 2 34 2 2 48 17 17 17 17 16 18 2 34 2 2 48 17 17 17 17 16 18 2 34 2 2 48 17 17 17 17 16 18 0 2 0 2 48 17 17 17 17 16 18 34 34 34 34 48 17 17 17 17 16 18 34 34 34 34 48 17 17 17 17 16 18 2 2 2 2 48 17 17 17 17 16 18 0 2 0 2 48 17 17 17 17 16 18 2 2 0 2 48 17 17 17 17 16 18 2 2 2 2 48 17 17 17 17 16 18 34 34 34 34 48 17 17 17 17 16 18 34 34 34 34 48 17 17 17 17 16 35 51 51 51 51 48 17 17 17 17 16 0 0 0 0 0 0 17 17]) ; colorMap:((OrderedCollection new add:(Color black); add:(Color white); add:(Color grey:66.9978); add:(Color grey:49.9962); add:(Color red:100.0 green:0.0 blue:0.0); add:(Color red:0.0 green:100.0 blue:0.0); add:(Color red:0.0 green:0.0 blue:100.0); add:(Color red:0.0 green:100.0 blue:100.0); add:(Color red:100.0 green:100.0 blue:0.0); add:(Color red:100.0 green:0.0 blue:100.0); add:(Color red:49.9992 green:0.0 blue:0.0); add:(Color red:0.0 green:49.9992 blue:0.0); add:(Color red:0.0 green:0.0 blue:49.9992); add:(Color red:0.0 green:49.9992 blue:49.9992); add:(Color red:49.9992 green:49.9992 blue:0.0); add:(Color red:49.9992 green:0.0 blue:49.9992); yourself)); mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(#[7 255 192 7 255 192 7 255 192 7 255 192 7 255 192 7 255 192 7 255 192 7 255 192 7 255 195 7 255 192 7 255 192 7 255 192 7 255 192 7 255 195 7 255 193 7 255 192 7 255 195 7 255 192 7 255 195 7 255 192 7 255 192 7 255 193]) ; yourself); yourself
+
+
+! !
+
+!TabItemEditor methodsFor:'accessing'!
+
+className
+    ^ className
+!
+
+selector
+    ^ selector
+! !
+
+!TabItemEditor methodsFor:'actions'!
+
+accept
+    "accept changes
+    "
+    |label|
+
+    self modified ifTrue:[
+        selectedIndex ~~ 0 ifTrue:[
+            rebuildMode := true.
+            label := listOfTabs at:selectedIndex.
+            hasChanged := true.
+
+            aspects keysAndValuesDo:[:aKey :aModel|
+                label perform:(aKey , ':') asSymbol with:(aModel value).
+            ].
+            self listOfLabels at:selectedIndex put:(label label).
+
+            rebuildMode := false.
+        ].
+        self cancel
+    ]
+!
+
+cancel
+    "cancel all changes
+    "
+    |tab|
+
+    rebuildMode ifFalse:[
+        selectedIndex ~~ 0 ifTrue:[
+            tab := listOfTabs at:selectedIndex.
+
+            rebuildMode := true.
+
+            aspects keysAndValuesDo:[:aKey :aModel|
+                aModel value:(tab perform:aKey)    
+            ].
+
+            rebuildMode := false.
+        ].
+        self modified:false.
+    ].
+    self canMoveTabUpOrDown value:(selectedIndex ~~ 0 and:[listOfTabs size > 1])
+
+
+
+
+!
+
+modified
+    "returns true if current tab is modified
+    "
+    ^ self modifiedChannel value
+!
+
+modified:aState
+    "change modification state
+    "
+    rebuildMode ifFalse:[
+        self modifiedChannel value:aState.
+        self isNotModified   value:(aState not).
+    ]
+! !
+
+!TabItemEditor methodsFor:'aspects'!
+
+aspectFor:aKey
+    "returns aspect for a key or nil
+    "
+    ^ aspects at:aKey ifAbsent:[ super aspectFor:aKey ]
+
+
+!
+
+canMoveTabUpOrDown
+
+    |holder|
+
+    (holder := builder bindingAt:#canMoveTabUpOrDown) isNil ifTrue:[
+        builder aspectAt:#canMoveTabUpOrDown put:(holder := false asValue).
+    ].
+    ^ holder
+
+!
+
+hasClassAndSelector
+
+    |holder|
+
+    (holder := builder bindingAt:#hasClassAndSelector) isNil ifTrue:[
+        builder aspectAt:#hasClassAndSelector put:(holder := false asValue).
+    ].
+    ^ holder
+
+!
+
+isNotModified
+    "returns true if current tab spec is not modified
+    "
+    |holder|
+
+    (holder := builder bindingAt:#isNotModified) isNil ifTrue:[
+        builder aspectAt:#isNotModified put:(holder :=  true asValue).
+    ].
+    ^ holder
+!
+
+listOfLabels
+    "returns a holder which keeps the list of tab labels
+    "
+    |list|
+
+    (list := builder bindingAt:#listOfLabels) isNil ifTrue:[
+        builder aspectAt:#listOfLabels put:(list :=  List new).
+    ].
+    ^ list
+!
+
+modifiedChannel
+    "channel which is true if the current tab specification is modified
+    "
+    |holder|
+
+    (holder := builder bindingAt:#modifiedChannel) isNil ifTrue:[
+        builder aspectAt:#modifiedChannel put:(holder :=  false asValue).
+    ].
+    ^ holder
+!
+
+selectionHolder
+    "holder which keeps the current selection
+    "
+    |holder|
+
+    (holder := builder bindingAt:#selectionHolder) isNil ifTrue:[
+        holder := AspectAdaptor new subject:self; forAspect:#selectedIndex.
+        builder aspectAt:#selectionHolder put:holder.
+    ].
+    ^ holder
+!
+
+specChannel
+    "holder which keeps the current tab specification
+    "
+    |holder|
+
+    (holder := builder bindingAt:#specChannel) isNil ifTrue:[
+        builder aspectAt:#specChannel put:(holder :=  ValueHolder new).
+    ].
+    ^ holder
+! !
+
+!TabItemEditor methodsFor:'change & update'!
+
+update:something with:aParameter from:someObject
+    "one of my aspects has changed; update modified channel
+    "
+    self modified:true.
+
+
+! !
+
+!TabItemEditor methodsFor:'selection'!
+
+selectedIndex
+    ^ selectedIndex
+!
+
+selectedIndex:anIndex
+    |s oldSel|
+
+    oldSel := selectedIndex.
+    selectedIndex := anIndex ? 0.
+
+    selectedIndex == oldSel ifTrue:[^ self].
+
+    oldSel == 0 ifTrue:[
+        self specChannel value:(self class tabSpec)
+    ] ifFalse:[
+        selectedIndex == 0 ifTrue:[
+            self specChannel value:nil
+        ]
+    ].
+    self cancel.
+! !
+
+!TabItemEditor methodsFor:'startup / release'!
+
+buildFrom:aClass andSelector:aSelector
+    "build from class and selector
+    "
+    |spec list validClSl|
+
+    self doNew.
+
+    selector  := nil.
+    className := self resolveName:aClass.
+    validClSl := false.
+
+    className notNil ifTrue:[
+        aSelector notNil ifTrue:[
+            validClSl := true.
+            selector  := aSelector asSymbol.
+
+            (className respondsTo:selector) ifTrue:[
+                spec := className perform:selector.
+                list := self listOfLabels.
+
+                spec size ~~ 0 ifTrue:[
+
+                    rebuildMode := true.
+
+                    spec do:[:aTab|
+                        list add:aTab label.
+                        listOfTabs add:aTab.
+                    ].
+                    rebuildMode := false.
+                ]
+            ]
+        ]
+    ].
+
+    self hasClassAndSelector value:validClSl.
+    self modified:false.
+    hasChanged := false.
+
+    listOfTabs notEmpty ifTrue:[
+        self selectionHolder value:1
+    ].
+!
+
+closeRequest
+
+    hasChanged ifTrue:[
+        ( YesNoBox title:'tab description was modified!!'
+                 yesText:'waste it and proceed'
+                  noText:'cancel'
+        ) confirm ifFalse:[
+            ^ self
+        ].
+        hasChanged := false.
+    ].
+    super closeRequest.
+!
+
+initialize
+    "setup aspects used by column description specifications
+    "
+    |holder|
+
+    super initialize.
+
+    aspects       := IdentityDictionary new.
+    listOfTabs    := OrderedCollection new.
+    hasChanged    := false.
+    selectedIndex := 0.
+    rebuildMode   := false.
+
+   #(
+        label
+        translateLabel
+        labelForegroundColor
+        enabled
+
+    ) do:[:aKey|
+        aspects at:aKey put:(holder := ValueHolder new).
+        holder addDependent:self.
+    ].
+
+
+!
+
+openModalOnClass:aClass andSelector:aSelector
+
+    className := aClass.
+    selector  := aSelector.
+
+    super openInterfaceModal.
+
+
+!
+
+openOnClass:aClass andSelector:aSelector
+
+    className := aClass.
+    selector  := aSelector.
+
+    super openInterface.
+
+
+!
+
+postBuildWith:builder
+    self buildFrom:className andSelector:selector.
+! !
+
+!TabItemEditor methodsFor:'user interactions'!
+
+doCopyTab
+    "copy selected tab
+    "
+    selectedIndex ~~ 0 ifTrue:[
+        self clipboard:(listOfTabs at:selectedIndex) deepCopy
+    ]
+!
+
+doCreateTab
+    |tab|
+
+    tab := TabItem label:'label'.
+
+    listOfTabs add:tab afterIndex:selectedIndex.
+    self listOfLabels add:(tab label) afterIndex:selectedIndex.
+    hasChanged := true.
+
+    selectedIndex == 0 ifTrue:[
+        self selectionHolder value:1
+    ] ifFalse:[
+        self cancel.
+    ]
+!
+
+doCutTab
+    "cut selected tab
+    "
+    |list index|
+
+    (index := selectedIndex) ~~ 0 ifTrue:[
+        list := self listOfLabels.
+        self clipboard:(listOfTabs at:index) deepCopy.
+        self selectionHolder value:0.
+        listOfTabs removeIndex:index.
+        list removeIndex:index.
+        hasChanged := true.
+
+        index > list size ifTrue:[
+            index := index - 1
+        ].
+        self selectionHolder value:index
+    ]
+
+!
+
+doDefineClassAndSelector
+    "launch a dialog to define class and selector
+    "
+    |cls sel bindings|
+
+    bindings := IdentityDictionary new.
+
+    [true] whileTrue:[
+        cls := className notNil ifTrue:[className name] ifFalse:['NewApplication'].
+        sel := selector  ? 'tabItemList'.
+
+        bindings at:#className put:cls asValue.
+        bindings at:#selector  put:sel asValue.
+
+        (self openDialogInterface:#nameAndSelectorSpec withBindings:bindings)
+        ifFalse:[ ^ self ].
+
+        cls := (bindings at:#className) value withoutSeparators.
+        sel := (bindings at:#selector)  value withoutSeparators.
+
+        (cls := self resolveName:cls) notNil ifTrue:[
+            className := cls.
+
+            sel notNil ifTrue:[
+                selector := sel asSymbol.
+              ^ self hasClassAndSelector value:true.
+            ]
+        ]
+    ]
+!
+
+doInstallAspect
+    "generate aspect method
+    "
+    |code|
+
+    className isNil ifTrue:[ ^ self information:'No valid class defined!!'].
+    selector isNil  ifTrue:[ ^ self information:'No selector defined!!'   ].
+
+    (className canUnderstand:selector) ifTrue:[
+        "/ method already exists, do not overwrite the method automaticaly
+
+        ( YesNoBox title:'method '
+                         , (Text string:('#', selector) emphasis:#bold)
+                         , ' already exists'
+                 yesText:'overwrite'
+                  noText:'cancel'
+        ) confirm ifFalse:[
+            ^ self
+        ]
+    ].
+
+    code := '!!' , className name , ' methodsFor:''aspects''!!\\' ,
+            selector , '\' ,
+            '    "automatically generated by TabItem Editor ..."\' ,
+            '\' ,
+            '    |list|\' ,
+            '\' ,
+            '    (list := builder bindingAt:#' , selector , ') isNil ifTrue:[\' ,
+            '        builder aspectAt:#' , selector, ' put:(list := self class ', selector, ').\' ,
+            '    ].\' ,
+            '    ^ list\' ,
+            '!! !!\\'.
+
+    (ReadStream on:(code withCRs)) fileIn
+
+
+!
+
+doInstallSpec
+    "generate code for class and instance
+    "
+    |code spec category mthd|
+
+    (className isNil or:[selector isNil]) ifTrue:[
+        self doDefineClassAndSelector
+    ].
+    className isNil ifTrue:[ ^ self information:'No valid class defined!!'].
+    selector isNil  ifTrue:[ ^ self information:'No selector defined!!'   ].
+    listOfTabs isEmpty ifTrue:[ ^ self information:'No valid tabs defined!!' ].
+
+    spec  := WriteStream on:String new.
+    UISpecification prettyPrintSpecArray:(listOfTabs literalArrayEncoding) on:spec indent:5.
+    spec := spec contents.
+
+    "/ if that method already exists, do not overwrite the category
+
+    category := 'interface specs'.
+
+    (mthd := className class compiledMethodAt:selector) notNil ifTrue:[
+        category := mthd category.
+    ].
+
+    code := Character excla asString 
+            , className name , ' class methodsFor:' , category storeString
+            , Character excla asString , '\\'
+
+            , selector , '\'
+            , '    "this window spec was automatically generated by the ST/X TabItemEditor"\\'
+            , '    "do not manually edit this - the builder may not be able to\'
+            , '     handle the specification if its corrupted."\\'
+            , '    "\'
+            , '     TabItemEditor new openOnClass:' , className name , ' andSelector:#' , selector , '\'
+            , '    "\'.
+
+    code := code 
+            , '\'
+            , '    <resource: #tabItem>\\'
+            , '    ^\' 
+            , '     ', spec, '\'
+            , '      collect:[:aTab| TabItem new fromLiteralArrayEncoding:aTab ]'
+            , '\'
+            , Character excla asString
+            , ' '
+            , Character excla asString
+            , '\\'.
+
+    code := code withCRs.
+    (ReadStream on:code) fileIn.
+    hasChanged := false.
+
+    (className canUnderstand:selector) ifFalse:[
+        (YesNoBox confirm:'install aspect method') ifTrue:[
+            self doInstallAspect
+        ]
+    ]
+
+
+!
+
+doMoveTabUpOrDown:what
+    "step up or down
+    "
+    |tab list index|
+
+    (selectedIndex ~~ 0 and:[listOfTabs size > 1]) ifFalse:[
+        ^ self
+    ].
+
+    list := self listOfLabels.
+    tab  := listOfTabs at:selectedIndex.
+
+    list removeIndex:selectedIndex.
+    listOfTabs removeIndex:selectedIndex.
+
+    what == #down ifTrue:[
+        index := selectedIndex > list size ifTrue:[1]
+                                          ifFalse:[selectedIndex + 1]
+    ] ifFalse:[
+        index := selectedIndex == 1 ifTrue:[list size + 1]
+                                   ifFalse:[selectedIndex - 1]
+    ].
+
+    list add:(tab label) beforeIndex:index.
+    listOfTabs add:tab beforeIndex:index.
+    hasChanged  := true.
+
+    rebuildMode := true.
+    self selectionHolder value:index.
+    rebuildMode := false.
+
+
+!
+
+doNew
+
+    self modified:false.
+
+    rebuildMode := true.
+
+    self selectionHolder value:0.
+    self listOfLabels removeAll.
+    listOfTabs removeAll.
+
+    hasChanged  := true.
+    rebuildMode := false.
+!
+
+doPasteTab
+    "paste a tab
+    "
+    |tab|
+
+    tab := self class clipboard deepCopy.
+    listOfTabs add:tab afterIndex:selectedIndex.
+    self listOfLabels add:(tab label) afterIndex:selectedIndex.
+    hasChanged := true.
+
+    selectedIndex == 0 ifTrue:[
+        self selectionHolder value:1
+    ]
+!
+
+doReload
+    "reload from class and selector
+    "
+    self buildFrom:className andSelector:selector
+! !
+
+!TabItemEditor class methodsFor:'documentation'!
+
+version
+    ^ '$Header$'
+! !