a lot more usability
authorClaus Gittinger <cg@exept.de>
Mon, 04 Feb 2008 10:28:24 +0100
changeset 2262 d40eebea4d20
parent 2261 60725fccd12d
child 2263 e3784764ba54
a lot more usability
DataSetBuilder.st
--- a/DataSetBuilder.st	Sun Jan 27 17:05:23 2008 +0100
+++ b/DataSetBuilder.st	Mon Feb 04 10:28:24 2008 +0100
@@ -13,7 +13,7 @@
 
 ResourceSpecEditor subclass:#DataSetBuilder
 	instanceVariableNames:'rowClass rowSuperClass columnView columns selectedColumnIndex
-		modalOpened listOfSpecViews'
+		modalOpened listOfSpecViews listOfItemsView'
 	classVariableNames:''
 	poolDictionaries:''
 	category:'Interface-UIPainter'
@@ -153,6 +153,9 @@
 #addColumn
 'Add a Column'
 
+#addNonSelectableColumn
+'Add a Non-Selectable Column'
+
 #fileLoad
 'Load Column Description from Method'
 
@@ -195,6 +198,9 @@
 #addColumn
 'Adds a new column.'
 
+#addNonSelectableColumn
+'Adds a new non-selectable column.'
+
 #basicsEditor
 'Default widget type or a selector returning an instance of a user defined widget opened in the cell.'
 
@@ -372,13 +378,38 @@
     "
      self newColumnIcon inspect
      ImageEditor openOnClass:self andSelector:#newColumnIcon
+     Icon flushCachedIcons
     "
 
     <resource: #image>
 
     ^Icon
-        constantNamed:#'DataSetBuilder newColumnIcon'
-        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'UT@@@@UPUTUUUXUPUTZ**,UPUTZB",UPUTX*H,UYUTX*H,UPUTZB",UPQTZ**,UPUTX*H,UPUTX*H,UPUTX*H,UPUTXB@,UPUTZ**,UPUTZ**,UPUTX"H,UYUTXB@,UPUTX"@,UPUTX"H,UPUTZ**,UPUTZ**,UPUT/??<UPUT@@@@UP') ; colorMapFromArray:#[0 0 0 255 255 255 170 170 170 127 127 127]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'A??@A??@A??@A??@A??@A??@A??@A??@A??CA??@A??@A??@A??@A??CA??AA??@A??CA??@A??CA??@A??@A??A') ; yourself); yourself]
+        constantNamed:#'DataSetBuilder class newColumnIcon'
+        ifAbsentPut:[(Depth2Image new) width: 19; height: 22; photometric:(#palette); bitsPerSample:(#[2]); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+U@@@@EQTUUUXUEQ***1TUF (+EQTX*H,UEQ"("1TUF (+EQTZ**,UEQ"("1TUFJ"KEQTX*H,UEQ HB1TUF**+EQTZ**,UEQ"H"1TUF@ KEQTX"@,UEQ"H"1T
+UF**+EQTZ**,UER???1TU@@@@EPb') ; colorMapFromArray:#[0 0 0 255 255 255 170 170 170 127 127 127]; mask:((Depth1Image new) width: 19; height: 22; photometric:(#blackIs0); bitsPerSample:(#[1]); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@') ; yourself); yourself]
+!
+
+newColumnNonSelectableIcon
+    "This resource specification was automatically generated
+     by the ImageEditor of ST/X."
+
+    "Do not manually edit this!! If it is corrupted,
+     the ImageEditor may not be able to read the specification."
+
+    "
+     self newColumnNonSelectableIcon inspect
+     ImageEditor openOnClass:self andSelector:#newColumnNonSelectableIcon
+     Icon flushCachedIcons
+    "
+
+    <resource: #image>
+
+    ^Icon
+        constantNamed:#'DataSetBuilder class newColumnNonSelectableIcon'
+        ifAbsentPut:[(Depth2Image new) width: 19; height: 22; photometric:(#palette); bitsPerSample:(#[2]); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+U@@@@EQTUUUXUEQ***1TUF**+EQTX*(,UEQ"*"1TUFB(KEQTZJ",UEQ(HJ1TUF("+EQTZ J,UEQ*@*1TUF("+EQTZBB,UEQ(*J1TUFB(KEQTX*(,UEQ"*"1T
+UF**+EQTZ**,UER???1TU@@@@EPb') ; colorMapFromArray:#[0 0 0 255 255 255 170 170 170 127 127 127]; mask:((Depth1Image new) width: 19; height: 22; photometric:(#blackIs0); bitsPerSample:(#[1]); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@G?<@') ; yourself); yourself]
 ! !
 
 !DataSetBuilder class methodsFor:'interface specs'!
@@ -1012,7 +1043,7 @@
               name: 'framedBox1'
               layout: (LayoutFrame 0 0.0 3 0 0 1.0 149 0)
               labelPosition: topLeft
-                    translateLabel: true
+              translateLabel: true
               component: 
              (SpecCollection
                 collection: (
@@ -1029,11 +1060,7 @@
                     activeHelpKey: formatInputType
                     tabable: true
                     model: type
-                    comboList: 
-                   (Array string
-                      password number
-                      numberOrNil symbolOrNil
-                    )
+                    comboList: possiblePrintConverterTypes
                     useIndex: false
                     hidePullDownMenuButton: false
                   )
@@ -1090,7 +1117,6 @@
                     tabable: true
                     model: formatSelector
                     group: inputGroup
-                    formatString: ''
                     acceptOnLostFocus: false
                     acceptChannel: acceptChannel
                     modifiedChannel: modifiedChannel
@@ -1845,7 +1871,7 @@
                       collection: (
                        (DataSetSpec
                           name: 'columnView'
-                          layout: (LayoutFrame 2 0.0 6 0.0 2 1.0 6 1.0)
+                          layout: (LayoutFrame 0 0.0 6 0.0 0 1.0 2 1.0)
                           hasHorizontalScrollBar: true
                           hasVerticalScrollBar: false
                           miniScrollerHorizontal: true
@@ -1876,12 +1902,14 @@
                                 hasHorizontalScrollBar: true
                                 hasVerticalScrollBar: true
                                 miniScrollerHorizontal: true
+                                isMultiSelect: true
                                 useIndex: true
                                 sequenceList: seqList
                               )
                              )
                            
                           )
+                          postBuildCallback: postBuildListOfItemsView:
                         )
                        (ViewSpec
                           name: 'specView'
@@ -1908,6 +1936,7 @@
                              )
                            
                           )
+                          postBuildCallback: postBuildSpecView:
                         )
                        )
                      
@@ -2025,7 +2054,7 @@
          (MenuItem
             label: 'Edit'
             translateLabel: true
-            submenuChannel: menuEdit
+            submenuChannel: menuEditWithoutAccelerators
           )
          (MenuItem
             label: 'Add'
@@ -2041,6 +2070,14 @@
                   translateLabel: true
                   labelImage: (ResourceRetriever nil newColumnIcon 'Column')
                 )
+               (MenuItem
+                  activeHelpKey: addNonSelectableColumn
+                  enabled: columnIsNotEditing
+                  label: 'Column (Non-Selectable)'
+                  itemValue: doCreateNonSelectableColumn
+                  translateLabel: true
+                  labelImage: (ResourceRetriever DataSetBuilder newColumnNonSelectableIcon 'Column (Non-Selectable)')
+                )
                )
               nil
               nil
@@ -2085,7 +2122,7 @@
             submenuChannel: menuHistory
           )
          (MenuItem
-            label: 'Help'
+            label: 'MENU_Help'
             translateLabel: true
             startGroup: conditionalRight
             submenuChannel: menuHelp
@@ -2110,65 +2147,264 @@
 
     <resource: #menu>
 
-    ^
-     
-       #(#Menu
-          
-           #(
-             #(#MenuItem
-                #label: 'Cut'
-                #translateLabel: true
-                #value: #doCut
-                #activeHelpKey: #editCut
-                #enabled: #isColumnSelected
-            )
-             #(#MenuItem
-                #label: 'Copy'
-                #translateLabel: true
-                #value: #doCopy
-                #activeHelpKey: #editCopy
-                #enabled: #isColumnSelected
-            )
-             #(#MenuItem
-                #label: 'Paste'
-                #translateLabel: true
-                #value: #doPaste
-                #activeHelpKey: #editPaste
-                #enabled: #valueOfHavingClipboard
+    ^ 
+     #(Menu
+        (
+         (MenuItem
+            activeHelpKey: editCut
+            enabled: isColumnSelected
+            label: 'Cut'
+            itemValue: doCut
+            translateLabel: true
+            shortcutKey: Cut
+          )
+         (MenuItem
+            activeHelpKey: editCopy
+            enabled: isColumnSelected
+            label: 'Copy'
+            itemValue: doCopy
+            translateLabel: true
+            shortcutKey: Copy
+          )
+         (MenuItem
+            activeHelpKey: editPaste
+            enabled: valueOfHavingClipboard
+            label: 'Paste'
+            itemValue: doPaste
+            translateLabel: true
+            shortcutKey: Paste
+          )
+         (MenuItem
+            label: '-'
+          )
+         (MenuItem
+            activeHelpKey: editMoveUp
+            enabled: isColumnSelected
+            label: 'Move Up'
+            itemValue: doMoveColumn:
+            translateLabel: true
+            shortcutKey: CtrlCursorUp
+            labelImage: (ResourceRetriever Icon upIcon 'Move Up')
+            argument: up
+          )
+         (MenuItem
+            activeHelpKey: editMoveDown
+            enabled: isColumnSelected
+            label: 'Move Down'
+            itemValue: doMoveColumn:
+            translateLabel: true
+            shortcutKey: CtrlCursorDown
+            labelImage: (ResourceRetriever Icon downIcon 'Move Down')
+            argument: down
+          )
+         (MenuItem
+            label: '-'
+          )
+         (MenuItem
+            label: 'Separators'
+            translateLabel: true
+            submenu: 
+           (Menu
+              (
+               (MenuItem
+                  label: 'Label Columns'
+                  translateLabel: true
+                  submenu: 
+                 (Menu
+                    (
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Add Separators'
+                        itemValue: addLabelColumnSeparators
+                        translateLabel: true
+                      )
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Remove Separators'
+                        itemValue: removeLabelColumnSeparators
+                        translateLabel: true
+                      )
+                     )
+                    nil
+                    nil
+                  )
+                )
+               (MenuItem
+                  label: 'Label Row && Columns'
+                  translateLabel: true
+                  submenu: 
+                 (Menu
+                    (
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Add Separators'
+                        itemValue: addLabelSeparators
+                        translateLabel: true
+                      )
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Remove Separators'
+                        itemValue: removeLabelSeparators
+                        translateLabel: true
+                      )
+                     )
+                    nil
+                    nil
+                  )
+                )
+               (MenuItem
+                  label: '-'
+                )
+               (MenuItem
+                  label: 'Cell Rows'
+                  translateLabel: true
+                  submenu: 
+                 (Menu
+                    (
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Add Separators'
+                        itemValue: addRowSeparators
+                        translateLabel: true
+                      )
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Remove Separators'
+                        itemValue: removeRowSeparators
+                        translateLabel: true
+                      )
+                     )
+                    nil
+                    nil
+                  )
+                )
+               (MenuItem
+                  label: 'Cell Columns'
+                  translateLabel: true
+                  submenu: 
+                 (Menu
+                    (
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Add Separators'
+                        itemValue: addLabelColumnSeparators
+                        translateLabel: true
+                      )
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Remove'
+                        itemValue: removeLabelColumnSeparators
+                        translateLabel: true
+                      )
+                     )
+                    nil
+                    nil
+                  )
+                )
+               (MenuItem
+                  label: 'Cell Rows && Columns'
+                  translateLabel: true
+                  submenu: 
+                 (Menu
+                    (
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Add Separators'
+                        itemValue: addCellSeparators
+                        translateLabel: true
+                      )
+                     (MenuItem
+                        enabled: hasSelection
+                        label: 'Remove Separators'
+                        itemValue: removeCellSeparators
+                        translateLabel: true
+                      )
+                     )
+                    nil
+                    nil
+                  )
+                )
+               )
+              nil
+              nil
             )
-             #(#MenuItem
-                #label: 'Delete'
-                #translateLabel: true
-                #value: #doDelete
-                #activeHelpKey: #editDelete
-                #enabled: #valueOfHavingClipboard
-            )
-             #(#MenuItem
-                #label: '-'
+          )
+         (MenuItem
+            label: 'Alignment'
+            translateLabel: true
+            submenu: 
+           (Menu
+              (
+               (MenuItem
+                  enabled: hasSelection
+                  label: 'Make Labels Left Aligned'
+                  itemValue: alignLabelsLeft
+                  translateLabel: true
+                )
+               (MenuItem
+                  enabled: hasSelection
+                  label: 'Make Labels Centered'
+                  itemValue: alignLabelsCentered
+                  translateLabel: true
+                )
+               (MenuItem
+                  enabled: hasSelection
+                  label: 'Make Labels Right Aligned'
+                  itemValue: alignLabelsRight
+                  translateLabel: true
+                )
+               (MenuItem
+                  label: '-'
+                )
+               (MenuItem
+                  enabled: hasSelection
+                  label: 'Make Cell Left Aligned'
+                  itemValue: alignColumnsLeft
+                  translateLabel: true
+                )
+               (MenuItem
+                  enabled: hasSelection
+                  label: 'Make Cell Centered'
+                  itemValue: alignColumnsCentered
+                  translateLabel: true
+                )
+               (MenuItem
+                  enabled: hasSelection
+                  label: 'Make Cell Right Aligned'
+                  itemValue: alignColumnsRight
+                  translateLabel: true
+                )
+               )
+              nil
+              nil
             )
-             #(#MenuItem
-                #label: 'Move Up'
-                #translateLabel: true
-                #value: #doMoveColumn:
-                #activeHelpKey: #editMoveUp
-                #enabled: #isColumnSelected
-                #argument: #up
-                #labelImage: #(#ResourceRetriever #Icon #upIcon 'Move Up')
-            )
-             #(#MenuItem
-                #label: 'Move Down'
-                #translateLabel: true
-                #value: #doMoveColumn:
-                #activeHelpKey: #editMoveDown
-                #enabled: #isColumnSelected
-                #argument: #down
-                #labelImage: #(#ResourceRetriever #Icon #downIcon 'Move Down')
-            )
-          ) nil
-          nil
+          )
+         (MenuItem
+            label: '-'
+          )
+         (MenuItem
+            enabled: hasSelection
+            label: 'Make Selectable'
+            itemValue: makeColumnsSelectable
+            translateLabel: true
+          )
+         (MenuItem
+            enabled: hasSelection
+            label: 'Make Unselectable'
+            itemValue: makeColumnsUnselectable
+            translateLabel: true
+          )
+         )
+        nil
+        nil
       )
 !
 
+menuEditWithoutAccelerators
+    ^ self menuEdit decodeAsLiteralArray
+        allItemsDo:[:i | i shortcutKey:nil]
+!
+
 menuToolbar
     "This resource specification was automatically generated
      by the MenuEditor of ST/X."
@@ -2195,6 +2431,9 @@
             labelImage: (ResourceRetriever ToolbarIconLibrary newDataSetIcon)
           )
          (MenuItem
+            label: '-'
+          )
+         (MenuItem
             activeHelpKey: fileLoad
             label: 'Load'
             itemValue: doLoad
@@ -2264,7 +2503,16 @@
             labelImage: (ResourceRetriever nil newColumnIcon)
           )
          (MenuItem
-            label: '-'
+            activeHelpKey: addNonSelectableColumn
+            enabled: columnIsNotEditing
+            label: 'Add Column (Non Selectable)'
+            itemValue: doCreateNonSelectableColumn
+            translateLabel: true
+            isButton: true
+            labelImage: (ResourceRetriever DataSetBuilder newColumnNonSelectableIcon)
+          )
+         (MenuItem
+            label: ''
           )
          (MenuItem
             activeHelpKey: editMoveUp
@@ -2273,6 +2521,7 @@
             itemValue: doMoveColumn:
             translateLabel: true
             isButton: true
+            startGroup: right
             labelImage: (ResourceRetriever Icon upIcon)
             argument: up
           )
@@ -2283,6 +2532,7 @@
             itemValue: doMoveColumn:
             translateLabel: true
             isButton: true
+            startGroup: right
             labelImage: (ResourceRetriever Icon downIcon)
             argument: down
           )
@@ -2365,7 +2615,8 @@
 !
 
 columnIsNotEditing
-    "returns a boolean value holder which is set to true if column is not editing"
+    "returns a boolean value holder which returns true if a columns attributes have not
+     been modified (notebook fields)"
 
     |holder|
 
@@ -2374,7 +2625,6 @@
         builder aspectAt:#columnIsNotEditing put:holder.
     ].
     ^ holder
-
 !
 
 editorTypeList
@@ -2390,14 +2640,23 @@
     ^list
 !
 
+hasColumns
+    "returns a boolean value holder which is set to true if there are any columns"
+
+    ^ BlockValue
+        with:[:m | m notEmptyOrNil]
+        argument:(self seqList)
+!
+
+hasSelection
+    ^ (selectedColumnIndex isCollection not and:[ selectedColumnIndex ~~ 0 ])
+    or:[ selectedColumnIndex size > 0 ]
+!
+
 isColumnSelected
-    "returns a boolean value holder which is set to true if something is modified
-     and not accepted"
+    "returns a boolean value holder which is set to true if some col is selected"
 
     ^builder valueAspectFor:#isColumnSelected initialValue: false
-
-
-
 !
 
 menuEdit
@@ -2406,6 +2665,10 @@
     ^ self class menuEdit
 !
 
+possiblePrintConverterTypes
+    ^ UISpecification possiblePrintConverterTypes
+!
+
 rendererTypeList
     "generate list of supported renderer types"
 
@@ -2843,6 +3106,48 @@
     ]
 ! !
 
+!DataSetBuilder methodsFor:'event handling'!
+
+processEvent:anEvent
+    "filter keyboard edit-events typed into the listOfItemsView.
+     Return true, if I have eaten the event"
+
+    |evView inView rawKey key|
+
+    anEvent isKeyPressEvent ifFalse:[^ false].
+
+    evView := anEvent targetView.
+    evView isNil ifTrue:[ ^ false ].
+
+    inView := evView isSameOrComponentOf:listOfItemsView.
+    inView ifTrue:[^ false].
+
+    key    := anEvent key.
+    rawKey := anEvent rawKey.
+
+    (    key == #Delete
+     or:[key == #BackSpace
+     or:[key == #Cut]]
+    ) ifTrue:[
+        self doCut.
+        ^ true.
+    ].
+
+    key == #Copy  ifTrue:[ self doCopy.  ^ true ].
+    key == #Paste ifTrue:[ self doPaste. ^ true ].
+
+    (rawKey == #CtrlCursorUp) ifTrue:[
+        self doMoveUp.
+        ^ true.
+    ].
+    (rawKey == #CtrlCursorDown) ifTrue:[
+        self doMoveDown.
+        ^ true.
+    ].
+
+    ^ false.
+! !
+
 !DataSetBuilder methodsFor:'initialization'!
 
 initialize
@@ -2866,6 +3171,145 @@
 "/    aDataSetColumnSpec editorType: #InputField.
 ! !
 
+!DataSetBuilder methodsFor:'operations'!
+
+addCellSeparators
+    self addRowSeparators.
+    self addColumnSeparators.
+!
+
+addColumnSeparators
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr showColSeparator:true
+    ].
+    self updateAfterOperation.
+!
+
+addLabelColumnSeparators
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr labelButtonType:#Button
+    ].
+    self updateAfterOperation.
+!
+
+addLabelSeparators
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr labelButtonType:#Button
+    ].
+    self updateAfterOperation.
+!
+
+addRowSeparators
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr showRowSeparator:true
+    ].
+    self updateAfterOperation.
+!
+
+alignColumns:how
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr columnAlignment:how
+    ].
+    self updateAfterOperation.
+!
+
+alignColumnsCentered
+    self alignColumns:#centered
+!
+
+alignColumnsLeft
+    self alignColumns:#left
+!
+
+alignColumnsRight
+    self alignColumns:#right
+!
+
+alignLabels:how
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr labelAlignment:how
+    ].
+    self updateAfterOperation.
+!
+
+alignLabelsCentered
+    self alignLabels:#centered
+!
+
+alignLabelsLeft
+    self alignLabels:#left
+!
+
+alignLabelsRight
+    self alignLabels:#right
+!
+
+makeColumnsSelectable
+    self makeColumnsSelectable:true
+!
+
+makeColumnsSelectable:aBoolean
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr canSelect:aBoolean
+    ].
+    self updateAfterOperation.
+!
+
+makeColumnsUnselectable
+    self makeColumnsSelectable:false
+!
+
+removeCellSeparators
+    self removeRowSeparators.
+    self removeColumnSeparators.
+!
+
+removeColumnSeparators
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr showColSeparator:false
+    ].
+    self updateAfterOperation.
+!
+
+removeLabelColumnSeparators
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr labelButtonType:#Group
+    ].
+    self updateAfterOperation.
+!
+
+removeLabelSeparators
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr labelButtonType:#None
+    ].
+    self updateAfterOperation.
+!
+
+removeRowSeparators
+    self selectedColumnsDo:[:eachColDescr |
+        eachColDescr showRowSeparator:false
+    ].
+    self updateAfterOperation.
+!
+
+selectedColumnsDo:aBlock
+    selectedColumnIndex isCollection ifTrue:[
+        selectedColumnIndex do:[:idx | aBlock value:(columns at:idx)].
+    ] ifFalse:[
+        selectedColumnIndex ~~ 0 ifTrue:[
+            selectedColumnIndex notNil ifTrue:[
+                aBlock value:(columns at:selectedColumnIndex)
+            ]
+        ].  
+    ].
+!
+
+updateAfterOperation
+    self updateColumnView.
+    self updateInputFields.
+    self setModified.
+! !
+
 !DataSetBuilder methodsFor:'private'!
 
 labelFromColumn:aColumn
@@ -2965,6 +3409,12 @@
 selectedColumn
     "returns selected column or nil"
 
+    selectedColumnIndex isCollection ifTrue:[
+        ^ selectedColumnIndex size == 1 
+            ifTrue:[ columns at:selectedColumnIndex first ]
+            ifFalse:[ nil ] 
+    ].
+
     ^selectedColumnIndex == 0 
         ifFalse:[columns at:selectedColumnIndex ifAbsent: nil]
         ifTrue: [nil]
@@ -2977,7 +3427,7 @@
 !
 
 selectedColumnIndex:something
-    "changes selected column and update specifications"
+    "changes selected column and updates specifications"
 
     something == selectedColumnIndex ifFalse:[
         selectedColumnIndex := something ? 0.
@@ -2985,6 +3435,34 @@
     ].
 !
 
+selectedColumnIndices
+    "returns selected column indices or #()"
+
+    selectedColumnIndex == 0 ifTrue:[ ^ #() ].
+    selectedColumnIndex isNumber ifTrue:[ ^ Array with:selectedColumnIndex ].
+    ^selectedColumnIndex
+!
+
+selectedColumns
+    selectedColumnIndex isCollection ifTrue:[
+        ^ selectedColumnIndex collect:[:idx | columns at:idx] 
+    ].
+
+    ^ selectedColumnIndex == 0 
+        ifFalse:[ Array with:(columns at:selectedColumnIndex) ]
+        ifTrue: [ #() ]
+!
+
+singleSelectedColumnIndex
+    selectedColumnIndex isCollection ifTrue:[
+        ^ selectedColumnIndex size == 1 
+            ifTrue:[ selectedColumnIndex first ]
+            ifFalse:[ 0 ] 
+    ].
+
+    ^ selectedColumnIndex
+!
+
 tabSelection:something
     "changes selected tab and set corresponding specification"
 
@@ -3051,10 +3529,7 @@
      there is no need to ask for saving into a class"
 
     modalOpened := true.
-
     super openModal
-
-
 !
 
 openModalOnResourceSpec: aListSpec
@@ -3067,11 +3542,20 @@
 
 !
 
+postBuildListOfItemsView:aView
+    listOfItemsView := aView
+!
+
+postBuildSpecView:aView
+    listOfItemsView := aView
+!
+
 postOpenWith:aBuilder
     "reset keyboardProcessor for menuBar"
 
-    super postOpenWith: aBuilder.
+    super postOpenWith:aBuilder.
     aBuilder keyboardProcessor menuBar:nil.
+    self windowGroup addPreEventHook:self.
 ! !
 
 !DataSetBuilder methodsFor:'user actions'!
@@ -3100,7 +3584,7 @@
     aspects keysAndValuesDo:[:aKey :aModel| 
         column perform:(aKey , ':') asSymbol with: aModel value
     ].
-    self seqList at:selectedColumnIndex put:(self labelFromColumn:column).
+    self seqList at:self singleSelectedColumnIndex put:(self labelFromColumn:column).
     self updateColumnView.
     self cancel.
     self clearModified.
@@ -3120,23 +3604,26 @@
 cutOrDelete:isCut
     "remove selected column and optionally put it to the clipboard"
 
-    |idx model|
-
-    ((idx := selectedColumnIndex) ~~ 0 and:[self askForItemModification]) ifFalse:[
+    |indices selectionModel|
+
+    ((indices := self selectedColumnIndices) notEmpty and:[self askForItemModification]) ifFalse:[
         ^ self
     ].
-    model := self selectedColumnModel.
-    model value:0.
-
     isCut ifTrue:[
-        self clipboard: (columns at: idx)
+        self clipboard: (self selectedColumns)
     ].
-    columns removeIndex:idx.
-
-    self  seqList removeIndex:idx.
-    model value:(idx min:(columns size)).
-    self  updateColumnView.
-    self  updateInputFields.
+
+    selectionModel := self selectedColumnModel.
+    selectionModel value:0.
+
+    indices sort reverseDo:[:idx |
+        columns removeIndex:idx.
+        self seqList removeIndex:idx.
+    ].
+
+    selectionModel value:((indices max) min:(columns size)).
+    self updateColumnView.
+    self updateInputFields.
 
     columns isEmpty ifTrue:[
         self isColumnSelected value: false
@@ -3145,6 +3632,20 @@
     self setModified.
 !
 
+doAddColumn:descr
+    "adds a new column after the selected column or at the left (if nothing is selected)"
+
+    columns add:descr afterIndex:self singleSelectedColumnIndex.
+    self setDefaultValuesInNewColumn:descr.
+    self seqList add:(descr label) afterIndex:self singleSelectedColumnIndex.
+    self enablingCommitButtonsHolder value ifFalse:[
+        self selectedColumnModel value:self singleSelectedColumnIndex + 1
+    ].
+    self cancel.
+    self updateColumnView.
+    self setModified.
+!
+
 doBrowseRowClass
     "browse class of columns spec"
 
@@ -3158,33 +3659,61 @@
 !
 
 doCopy
-    "copy selected column to the clipboard"
-
-    |idx|
-
-    (idx := selectedColumnIndex) ~~ 0 
-    ifTrue:
-    [
-        self clipboard: (columns at: idx) deepCopy
+    "copy selected columns to the clipboard"
+
+    |cols|
+
+    cols := self selectedColumns.
+    cols notEmptyOrNil ifTrue:[
+        self clipboard:(cols deepCopy)
     ]
 !
 
 doCreateColumn
     "create a new column after selected column or at left (nothing selected)"
 
-    |label list dscs |
-
-    list := self seqList.
-    label := 'Column ', (list size + 1) printString.
-    columns add:(dscs := DataSetColumnSpec label:label selector:nil) afterIndex:selectedColumnIndex.
-    self setDefaultValuesInNewColumn:dscs.
-    self seqList add:label afterIndex:selectedColumnIndex.
-    self enablingCommitButtonsHolder value ifFalse:[
-        self selectedColumnModel value:selectedColumnIndex + 1
-    ].
-    self cancel.
-    self updateColumnView.
-    self setModified.
+    |label list dscs descr|
+
+"/    list := self seqList.
+"/    label := 'Column ', (list size + 1) printString.
+"/    columns add:(dscs := DataSetColumnSpec label:label selector:nil) afterIndex:selectedColumnIndex.
+"/    self setDefaultValuesInNewColumn:dscs.
+"/    self seqList add:label afterIndex:selectedColumnIndex.
+"/    self enablingCommitButtonsHolder value ifFalse:[
+"/        self selectedColumnModel value:selectedColumnIndex + 1
+"/    ].
+"/    self cancel.
+"/    self updateColumnView.
+"/    self setModified.
+"/
+
+    label := 'Column ', (self seqList size + 1) printString.
+    descr := DataSetColumnSpec label:label selector:nil.
+    self doAddColumn:descr
+!
+
+doCreateNonSelectableColumn
+    "create a new column after selected column or at left (nothing selected)"
+
+    |label list dscs descr|
+
+"/    list := self seqList.
+"/    label := 'Column ', (list size + 1) printString.
+"/    columns add:(dscs := DataSetColumnSpec label:label selector:nil) afterIndex:selectedColumnIndex.
+"/    self setDefaultValuesInNewColumn:dscs.
+"/    self seqList add:label afterIndex:selectedColumnIndex.
+"/    self enablingCommitButtonsHolder value ifFalse:[
+"/        self selectedColumnModel value:selectedColumnIndex + 1
+"/    ].
+"/    self cancel.
+"/    self updateColumnView.
+"/    self setModified.
+"/
+
+    label := 'Column ', (self seqList size + 1) printString.
+    descr := DataSetColumnSpec label:label selector:nil.
+    descr canSelect:false.
+    self doAddColumn:descr
 !
 
 doCut
@@ -3315,7 +3844,7 @@
 
     |idx list label col size|
 
-    (idx := selectedColumnIndex) == 0 ifTrue:[^self].
+    (idx := self singleSelectedColumnIndex) == 0 ifTrue:[^self].
     list := self seqList.
     size := list size.
 
@@ -3326,14 +3855,10 @@
     list    removeIndex:idx.
     columns removeIndex:idx.
 
-    upOrDown == #up 
-    ifTrue:
-    [
+    upOrDown == #up ifTrue:[
         idx == 1 ifTrue:[idx := size]
                 ifFalse:[idx := idx - 1]
-    ] 
-    ifFalse:
-    [
+    ] ifFalse:[
         idx == size ifTrue:[idx := 1]
                    ifFalse:[idx := idx + 1]
     ].
@@ -3344,20 +3869,42 @@
     self setModified.
 !
 
+doMoveDown
+    self doMoveColumn:#down
+!
+
+doMoveUp
+    self doMoveColumn:#up
+!
+
 doPaste
     "paste clipboard copy column after selected column or at left (nothing selected)"
 
-    |col lbl|
-
-    self askForItemModification ifFalse: [^nil].
-    col := self class clipboard deepCopy.
-    lbl := self labelFromColumn:col.
-
-    columns add:col afterIndex:selectedColumnIndex.
-    self seqList add:lbl afterIndex:selectedColumnIndex.
+    |cols idx newSel|
+
+    self askForItemModification ifFalse: [^ self].
+
+    cols := self class clipboard.
+    cols isEmptyOrNil ifTrue:[^ self].
+
+    idx := (self selectedColumnIndices) isEmpty 
+                ifTrue:[ columns size ]
+                ifFalse:[ self selectedColumnIndices max ].
+
+    newSel := OrderedCollection new.
+    cols do:[:col |
+        | lbl|
+
+        lbl := self labelFromColumn:col.
+
+        columns add:(col deepCopy) afterIndex:idx.
+        self seqList add:lbl afterIndex:idx.
+        idx := idx + 1.
+        newSel add:idx.
+    ].
 
     self enablingCommitButtonsHolder value ifFalse:[
-        self selectedColumnModel value:selectedColumnIndex + 1
+        self selectedColumnModel value:newSel "/idx
     ].
     self updateColumnView.
     self updateInputFields.