SelectionInTree.st
changeset 857 d8e14b853cb7
parent 849 f7d8363fc24f
child 860 64d52b8e3dbd
--- a/SelectionInTree.st	Tue Apr 14 13:31:49 1998 +0200
+++ b/SelectionInTree.st	Tue Apr 14 13:32:54 1998 +0200
@@ -86,9 +86,9 @@
     (root := aRoot) notNil ifTrue:[
         root parent:nil.
         root tree: self.
-    ]. 
-    self recomputeList.
-
+    ].
+    self listFromRoot.
+    self changed:#list.
 ! !
 
 !SelectionInTree methodsFor:'accessing behavior'!
@@ -103,9 +103,6 @@
     "set children action block
     "
     childrenAction := aBlock.
-
-    self changed:#list.
-    
 !
 
 contentsAction
@@ -118,9 +115,6 @@
     "set contents action block
     "
     contentsAction := aBlock.
-
-    self changed:#list.
-    
 !
 
 iconAction
@@ -133,9 +127,6 @@
     "set icon action block
     "
     iconAction := aBlock.
-
-    self changed:#list.
-    
 !
 
 labelAction
@@ -148,9 +139,6 @@
     "set label action block
     "
     labelAction := aBlock.
-
-    self changed:#list.
-    
 !
 
 showRoot
@@ -166,10 +154,13 @@
         showRoot := aState.
 
         root notNil ifTrue:[
-            aState ifTrue:[list addFirst:root]
-                  ifFalse:[list removeFirst].
-
-            self changed:#list.
+            aState ifTrue:[
+                list addFirst:root.
+                self changed:#insertCollection: with:(Array with:1 with:1 with:nil).
+            ] ifFalse:[
+                list removeFirst.
+                self changed:#removeFrom: with:(Array with:1 with:1 with:nil).
+            ].
         ].
     ].
 ! !
@@ -179,15 +170,21 @@
 collapse:something 
     "collapse a node or collection of nodes
     "
-    |invalidate|
+    |listChanged|
+
+    listChanged := false.
 
     self each:something do:[:aNode|
         aNode isCollapsable ifTrue:[
             aNode collapse.
-            invalidate := true
+            listChanged := true
         ]
     ].
-    invalidate == true ifTrue:[self recomputeList]
+    listChanged ifTrue:[
+        self listFromRoot.
+        self changed:#list.
+    ]
+
 !
 
 expand
@@ -199,15 +196,79 @@
 expand:something 
     "expand a node or collection of nodes
     "
-    |invalidate|
+    |listChanged|
+
+    listChanged := false.
 
     self each:something do:[:aNode|
         aNode isExpandable ifTrue:[
             aNode expand.
-            invalidate := true
+            listChanged := true
         ]
     ].
-    invalidate == true ifTrue:[self recomputeList]
+    listChanged ifTrue:[
+        self listFromRoot.
+        self changed:#list.
+    ]
+! !
+
+!SelectionInTree methodsFor:'accessing hierarchy new'!
+
+doCollapse:something
+    "collapse all children under an item or a sequence of items;
+     if the list changed, notifications are raised
+    "
+    self each:something do:[:anItem|
+        self collapseItem:anItem do:[ anItem collapse ]
+    ]
+!
+
+doCollapseAll:something
+    "collapse all children and subChildren under an item or sequence of items;
+     if the list changed, notifications are raised
+    "
+    self each:something do:[:anItem|
+        self collapseItem:anItem do:[ anItem collapseAll ]
+    ]
+!
+
+doExpand:something
+    "expand all children under an item or collection of items;
+     if the list changed, notifications are raised
+    "
+    self each:something do:[:anItem|
+        self expandItem:anItem do:[anItem expand]
+    ]
+!
+
+doExpandAll:something
+    "expand all children and subChildren under an item or sequence of items;
+     if the list changed, notifications are raised
+    "
+    self each:something do:[:anItem|
+        self expandItem:anItem do:[anItem expandAll]
+    ]
+!
+
+doMakeVisible:something
+    "make an item or list of items to become visible
+    "
+    |anchor parent|
+
+    self each:something do:[:anItem|
+        parent := anItem.
+        anchor := nil.
+
+        [(parent := parent parent) notNil] whileTrue:[
+            parent hidden ifTrue:[
+                anchor notNil ifTrue:[ anchor expand ].
+                anchor := parent.
+            ]
+        ].
+        anchor notNil ifTrue:[
+            self expandItem:anchor do:[anchor expand]
+        ]
+    ]
 ! !
 
 !SelectionInTree methodsFor:'adding & removing'!
@@ -217,93 +278,188 @@
     "
     "add a node or collection of nodes to after a child
     "
-    aChild notNil ifTrue:[
-        aChild parent add:something after:aChild.
-        self recomputeList
+    |p|
+
+    (aChild notNil and:[(p := aChild parent) notNil]) ifTrue:[
+        self add:something afterIndex:(p indexOfChild:aChild) below:p
     ]
+
 !
 
 add:something afterIndex:anIndex below:aParent
     "add a node or collection of nodes to parent after an index
     "
-    aParent add:something afterIndex:anIndex.
-    self recomputeList
-
+    self add:something beforeIndex:(anIndex + 1) below:aParent
 !
 
 add:something before:aChild
     "add a node or collection of nodes to before a child
     "
-    aChild notNil ifTrue:[
-        aChild parent add:something before:aChild.
-        self recomputeList
+    |p|
+
+    (aChild notNil and:[(p := aChild parent) notNil]) ifTrue:[
+        self add:something beforeIndex:(p indexOfChild:aChild) below:p
     ]
 !
 
 add:something beforeIndex:anIndex below:aParent
     "add a node or collection of nodes to parent before an index
     "
-    aParent add:something beforeIndex:anIndex.
-    self recomputeList
+    |children start index size pList|
+
+    (    aParent isNil
+     or:[something isNil
+     or:[(something isCollection and:[something isEmpty])]]
+    ) ifTrue:[
+        ^ self
+    ].
+
+    (start := self indexOf:aParent) == 0 ifTrue:[
+        "/
+        "/ parent not visible; list not changed
+        "/
+        aParent add:something beforeIndex:anIndex.
+        ^ self
+    ].
+
+    aParent shown ifFalse:[
+        aParent add:something beforeIndex:anIndex.
+        self changed:#at: with:start.
+        ^ self
+    ].
+    children := aParent children.
+
+    (children isEmpty or:[anIndex <= 1]) ifTrue:[
+        index := 1.
+    ] ifFalse:[
+        size  := children size.
+
+        anIndex > size ifTrue:[
+            index := size + 1.
+            start := aParent numberOfAllVisibleChildren + start.
+        ] ifFalse:[
+            index := anIndex.
+            start := (self indexOf:(children at:index)) - 1.
+        ]
+    ].
+    aParent add:something beforeIndex:index.
+
+    (start := start + 1) == 0 ifTrue:[
+        "/
+        "/ not visible
+        "/
+        ^ self
+    ].
+    pList := OrderedCollection new:2048.
+
+    self each:something do:[:aNode|
+        pList add:aNode.
+        aNode addVisibleChildrenTo:pList
+    ].
+    pList isEmpty ifTrue:[
+        ^ self
+    ].
+    list addAll:pList beforeIndex:start.
+
+    self changed:#insertCollection:
+            with:(Array with:start with:pList size with:aParent).
 
 !
 
 add:something below:aParent
     "add a node or collection of nodes to parent
     "
-    aParent add:something.
-    self recomputeList
-
+    aParent notNil ifTrue:[
+        self add:something beforeIndex:(aParent numberOfChildren + 1) below:aParent
+    ]
 !
 
 remove:something
     "remove a node or collection of nodes
     "
-    |invalidate|
+    |node coll index loNums loItem start size parent|
+
+    something isNil ifTrue:[
+        ^ something
+    ].
+    loNums := SortedCollection new.
+
+    self each:something do:[:el|
+        node := el isNumber ifTrue:[list at:el ifAbsent:nil]
+                           ifFalse:[el].
+
+        node notNil ifTrue:[
+            self stopIndicatorValidationFor:node.
 
-    self each:something do:[:aNode|
-        self stopIndicatorValidationFor:aNode.
+            node parent isNil ifTrue:[
+                "/ remove all including root
+                node == root ifTrue:[ self root:nil ].
+              ^ something
+            ].
+            index := self indexOf:node.
 
-        aNode parent notNil ifTrue:[
-            aNode parent remove:aNode.
-            invalidate := true
+            index == 0 ifTrue:[
+                "/ not visible
+                node parent removeChild:node
+            ] ifFalse:[
+                loNums add:index
+            ].
         ]
     ].
-    invalidate == true ifTrue:[self recomputeList].
-  ^ something
+
+    loNums isEmpty ifTrue:[
+        "/ nothing visible changed
+        ^ something
+    ].
+    loItem := OrderedCollection new.
+    loNums do:[:i| loItem add:(list at:i)].
+
+    loItem do:[:aNode|
+        start := self indexOf:aNode.
+
+        start ~~ 0 ifTrue:[
+            parent := aNode parent.
+            size   := 1 + aNode numberOfAllVisibleChildren.
+            parent remove:aNode.
+            list removeFromIndex:start toIndex:(start + size - 1).
 
+            self changed:#removeFrom:
+                    with:(Array with:start with:size with:parent).
+        ]
+    ].
+    ^ something
+!
+
+removeAllOtherThanRoot
+    "remove all other than the root
+    "
+    |listChanged|
+
+    root notNil ifTrue:[
+        listChanged := root isCollapsable.
+        root children:(OrderedCollection new).
+
+        listChanged ifTrue:[
+            self listFromRoot.
+            self changed:#list
+        ]
+    ]
 !
 
 removeIndex:something
     "remove a node at index or collection of indexed nodes
     "
-    |invalidate node|
-
-    something isCollection ifFalse:[
-        (something isNil or:[something == 0]) ifFalse:[
-            ^ self remove:(list at:something)
-        ].
-      ^ nil
-    ].
-
-    (SortedCollection withAll:something) reverseDo:[:anIndex|
-        node := list at:anIndex.
-        self stopIndicatorValidationFor:node.
-
-        node parent notNil ifTrue:[
-            node parent remove:node.
-            invalidate := true
-        ]
-    ].
-    invalidate == true ifTrue:[self recomputeList].
-
+    self remove:something
 !
 
 removeSelection
     "remove selected nodes
     "
-    self removeIndex:(self selectionIndex).
-    self selectionIndex:nil
+    |sel|
+
+    sel := self selectionIndex.
+    self selectionIndex:nil.
+    self remove:sel.
 ! !
 
 !SelectionInTree methodsFor:'change & update'!
@@ -356,15 +512,91 @@
 recomputeList
     "Travers the tree and build a new list."
 
+    self listFromRoot.
+    self changed:#list.
+! !
+
+!SelectionInTree methodsFor:'private hierarchy'!
+
+collapseItem:anItem do:collapseBlock
+    "collapse all children under an item; raise a notification if
+     the list changed
+    "
+    |start stop size|
+
+    anItem isCollapsable ifFalse:[
+        ^ self
+    ].
+
+    (start := self indexOf:anItem) == 0 ifTrue:[
+        "/
+        "/ item not visible
+        "/
+        collapseBlock value.
+    ] ifFalse:[
+        size := anItem numberOfAllVisibleChildren.
+        collapseBlock value.
+
+        size == 0 ifTrue:[
+            "/
+            "/ no children before; list not changed 
+            "/
+            self changed:#at: with:start
+        ] ifFalse:[        
+            stop  := start + size.
+            start := start + 1.
+            list removeFromIndex:start toIndex:stop.
+            self changed:#removeFrom: with:(Array with:start with:size with:anItem).
+        ]
+    ]
+!
+
+expandItem:anItem do:expandBlock
+    "expand all children under an item; raise a notification if
+     the list changed
+    "
+    |start size pList|
+
+    anItem isExpandable ifFalse:[
+        ^ self
+    ].
+    expandBlock value.
+
+    (start := self indexOf:anItem) ~~ 0 ifTrue:[
+        anItem addVisibleChildrenTo:(pList := OrderedCollection new:2048).
+
+        (size := pList size) ~~ 0 ifTrue:[
+            start := 1 + start.
+            list addAll:pList beforeIndex:start.
+
+            self changed:#insertCollection:
+                    with:(Array with:start with:size with:anItem).
+        ] ifFalse:[
+            self changed:#at: with:start
+        ]
+    ]
+!
+
+listFromRoot
+    "Travers the tree and build a new list;
+     no change notification is raised
+    "
     list clearContents.
 
     root notNil ifTrue:[
-        showRoot ifTrue:[   
-            list add:root
-        ].
-        root recomputeList:list.
-    ].
-    self changed:#list.
+        showRoot ifTrue:[ list add:root ].
+        root addVisibleChildrenTo:list
+    ]
+
+! !
+
+!SelectionInTree methodsFor:'queries'!
+
+indexOf:anItem
+    "returns the index of an item or 0
+    "
+    ^ anItem notNil ifTrue:[list identityIndexOf:anItem]
+                   ifFalse:[0]
 ! !
 
 !SelectionInTree methodsFor:'searching'!
@@ -396,6 +628,35 @@
 
 !SelectionInTree methodsFor:'selection'!
 
+selectedNodes
+    "returns list of selected nodes or nil
+    "
+    |node coll|
+
+    selection isNil ifTrue:[
+        ^ nil
+    ].
+
+    selection isCollection ifFalse:[
+        node := list at:selection ifAbsent:nil.
+      ^ node notNil ifTrue:[Array with:node] ifFalse:[nil]
+    ].
+
+    selection isEmpty ifTrue:[
+        ^ nil
+    ].
+
+    coll := OrderedCollection new:(selection size).
+
+    selection do:[:idx|
+        (node := list at:idx ifAbsent:nil) notNil ifTrue:[
+            coll add:node
+        ]
+    ].
+    ^ coll notEmpty ifTrue:[coll] ifFalse:[nil]
+        
+!
+
 selection
     "get the selection or nil
     "
@@ -522,5 +783,5 @@
 !SelectionInTree class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libwidg2/SelectionInTree.st,v 1.12 1998-04-09 11:37:54 ca Exp $'
+    ^ '$Header: /cvs/stx/stx/libwidg2/SelectionInTree.st,v 1.13 1998-04-14 11:32:54 ca Exp $'
 ! !