|
Class: AbstractHierarchicalItem
Object
|
+--AbstractHierarchicalItem
|
+--AbstractHierarchicalItemWithModel
- Package:
- stx:libwidg2
- Category:
- Views-Support
- Version:
- rev:
1.56
date: 2019/07/24 06:00:48
- user: cg
- file: AbstractHierarchicalItem.st directory: libwidg2
- module: stx stc-classLibrary: libwidg2
- Author:
- Claus Atzkern
- Claus Gittinger (redesign and refactoring)
Hierarchical Items are mostly like Models, but the list of
dependencies are kept by its HierarchicalList.
The class is used to build up hierarchical trees.
2015 update:
the original HierarchicalItem has been refactored into this abstract class,
which provides all the mechanisms, but leaves the concrete representation
of some slots open.
These are:
- if and how the geometry information (width + height) are cached,
- if and how the expanded-state is remembered.
- if and how the underlying model is fetched
The old class used private slots for the first three (width-height-isExpanded),
but did not keep a reference to the model. This leads to a very poor performance,
as many algorithms degenerated to O(n log(n)) or even O(n^2) time behavior,
as the model was fetched by walking along the parent chain - sometimes for every item
in a long list.
The old class is still around and may be used for small trees,
but we recommend rewriting applications to use the new CompactHierarchicalItem
class, which behaves the same on the outside, but uses clever tricks to be both more
space efficient (saving 2 slots) and time efficient (caching the model).
For this, make sure that the subclass does not access the instvars isExpanded, width and height
directly, but uses the getters isExpanded, width and height and the setters setExpanded:, width: and height:
[Instance variables:]
parent <Item, List or nil> parent or my HierarchicalList.
children <Collection or nil> list of children
HierarchicalItem
(the
old
item
class)
HierarchicalList
(typical
model)
HierarchicalListView
(typical
user
of
me)
instance creation
-
new
-
-
parent: aParent
-
protocol
-
doResetExtentOnChange
-
true: the extent of the item is reset if a change
notification is raised from the item. the default is true
queries
-
isAbstract
-
Return if this class is an abstract class.
True is returned here for myself only; false for subclasses.
Abstract subclasses must redefine this again.
accessing
-
getChildren
-
returns the children as they are present (or not);
not going to the model, and especially not creating autocreated children...
-
level
-
returns the level starting with 0 for the root
-
nextSibling
-
returns the next child of my parent or nil
-
parent
-
returns the parent or nil
-
parent: aParent
-
set the parent (or the model if the item is the root item)
-
previousSibling
-
returns the previous child of my parent or nil
-
rootItem
-
returns the root item
accessing-children
-
at: anIndex
-
return the child at anIndex if valid;
if the index is invalid, nil is returned
-
at: anIndex ifAbsent: exceptionBlock
-
return the child at anIndex if valid; if the index is
invalid, the result of evaluating the exceptionBlock is returned.
-
at: anIndex put: anItem
-
replace a child by a new item. return anItem (sigh)
-
children: aListOfChildren
-
set a new list of children
-
first
-
returns the first child
-
last
-
returns the last child
-
second
-
returns the second child
accessing-hierarchy
-
collapse
-
hide all my subitems
-
enforcedExpand
-
expand children - even if there are no children,
the item is initially expanded (but this might be undone later,
when we know that no children are there
-
expand
-
expand children - but only if there are children
(i.e. this cannot be used before the childInfo is valid;
aka not before the updateTask came along this item)
-
expand: enforced
-
expand children
-
expandLevels: numLevels
-
expand children numLevels down
-
expandLevels: numLevels max: maxNumExpandedHolder
-
expand children numLevels down
-
expandWithoutUpdate
-
in case expand is redefined to do any update
(as in guiBrowser's applicationTreeItem),
this can be used to expand without updating
-
labelPath
-
return my label-path as an ordered collection of individual labels
-
makeVisible
-
expand all my parents
-
recursiveCollapse
-
collapse item and recursively all sub items
-
recursiveExpand
-
expand children and sub-children;
WARNING: refetches children.
Precondition: must be collapsed
-
recursiveToggleExpand
-
if the item is collapsed, the item and all its sub-items
are expanded otherwise collapsed
-
toggleExpand
-
if the item is collapsed, the item is expanded otherwise collapsed
accessing-mvc
-
application
-
returns the responsible application or nil
-
applicationsDo: aOneArgBlock
-
evaluate the block for each dependent application
-
fetchModel
-
returns the hierachicalList model or nil.
This is a stupid implementation here, in that the top-item's parent is assumed to
be the model of the tree, and that is returned.
This saves a slot in every node, but makes some algorithms O(n*log n) or even O(n^2).
So be aware of the performance penalty
-
model
-
returns the hierachicalList model or nil.
This uses fetchModel, which has a stupid implementation here,
in that the top-item's parent is assumed to be the model of the tree, and that is returned.
This saves a slot in every node, but makes some algorithms O(n*log n) or even O(n^2).
So be aware of the performance penalty or redefined fetchModel
adding & removing
-
add: aChildItem
-
add a child at end
-
add: aChildItem after: aChild
-
add an item after an existing item
-
add: aChildItem afterIndex: anIndex
-
add an item after an index
-
add: aChildItem before: aChild
-
add an item before an existing item
-
add: aChildItem beforeIndex: anIndex
-
add an item before an index
-
add: aChild sortBlock: aBlock
-
add a child sorted
-
addAll: aList
-
add children at the end
-
addAll: aList before: aChild
-
add an item before an existing item
-
addAll: aList beforeIndex: anIndex
-
add children before an index
-
addAll: aList sortBlock: aBlock
-
add children sorted
-
addAllFirst: aCollectionOfItems
-
add children at the beginning
-
addAllLast: aCollectionOfItems
-
add children at the end
-
addFirst: aChildItem
-
add a child at the beginning
-
addLast: anItem
-
add a child at the end
-
remove
-
remove the item
-
remove: aChild
-
remove a child
-
removeAll
-
remove all children.
Returns the receiver.
-
removeAll: aList
-
remove all items in aList from my children.
Returns the receiver.
-
removeAllIdentical: aList
-
remove all children in the collection
-
removeFromIndex: startIndex
-
remove the children from startIndex up to end of children.
Returns the receiver.
-
removeFromIndex: startIndex toIndex: stopIndex
-
remove the children from startIndex up to and including
the child under stopIndex.
Returns the receiver.
-
removeIndex: anIndex
-
remove the child at an index.
Returns the receiver
basic adding & removing
-
basicAdd: aChild sortBlock: aBlockOrNil
-
add a child sorted.
Not synchronized - should only be called internally
within a synchronized region.
-
basicAddAll: aList beforeIndex: anIndex
-
add children before an index.
Not synchronized - should only be called internally
within a synchronized region.
-
basicRemoveFromIndex: startIndex toIndex: stopIndex
-
remove the children from startIndex up to and including
the child under stopIndex.
Not synchronized - should only be called internally
within a synchronized region.
change & update
-
changed: what with: anArgument
-
the item changed; raise change notification
#icon icon is modified; height and width are unchanged
#hierarchy collapsed/expanded; height and width are unchanged
#redraw redraw but height and width are unchanged
....... all others: the height and width are reset
-
childrenOrderChanged
-
called if the order of the children changed by a user
operation. Update the model and raise a change notification for
each item which has changed its position
triggered by the user operation !
-
fontChanged
-
called if the font has changed.
Clear the precomputed width and height
-
hierarchyChanged
-
hierarchy changed; optimize redrawing
-
iconChanged
-
icon changed; optimize redrawing
-
invalidate
-
force redrawing of me
-
labelChanged
-
called if the label has changed.
Clear the precomputed width and height, and invalidate
enumerating
-
allExpandedItemsDo: aBlock
-
recursively enumerate all expanded nodes
(depth first; parent before children)
-
collect: aBlock
-
for each child in the receiver (non recursive), evaluate the argument, aBlock
and return a new collection with the results
-
contains: aBlock
-
evaluate aOneArgBlock for each of the receiver's children (non recursive).
Return true and skip remaining elements, if aBlock ever returns true,
otherwise return false
-
do: aOneArgBlock
-
evaluate a block for each child (non recursive)
-
from: startIndex do: aOneArgBlock
-
evaluate a block on each child starting with the
child at startIndex to the end.
-
from: startIndex reverseDo: aOneArgBlock
-
evaluate a block on each child (non recursive) starting at end to the startIndex
-
from: startIndex to: endIndex do: aOneArgBlock
-
WARNING: may fetch lazy children
evaluate a block on each child (non recursive),
starting with the child at startIndex to the endIndex (last index if nil).
Answer the value of the block executed on the last element.
-
from: startIndex to: endIndex reverseDo: aOneArgBlock
-
WARNING: may fetch lazy children
evaluate a block on each child (non recursive),
starting with the child at endIndex to the startIndex.
-
keysAndValuesDo: aTwoArgBlock
-
evaluate the argument, aBlock for every child (non recursive),
passing both index and element as arguments.
-
keysAndValuesReverseDo: aTwoArgBlock
-
WARNING: may fetch lazy children
evaluate the argument, aBlock in reverse order for every child (non recursive),
passing both index and element as arguments.
-
recursiveCollect: aBlock
-
for each child in the receiver, evaluate the argument, aBlock
and return a new collection with the results.
Warning: this only enumerates already visible child elements
i.e. any collapsed items are not visited.
-
recursiveDo: aOneArgBlock
-
WARNING: may fetch lazy children
evaluate a block on each item and all the sub-items.
Warning: this only enumerates already visible child elements
i.e. any collapsed items are not visited.
-
recursiveDo: aOneArgBlock skipIf: elementCheck skipChildrenIf: childrenCheck
-
WARNING: may fetch lazy children
evaluate a block on each item and all the sub-items.
Warning: this only enumerates already visible child elements
i.e. any collapsed items are not visited.
-
recursiveReverseDo: aOneArgBlock
-
WARNING: may fetch lazy children
evaluate a block on each item and all the sub-items;
proccesing children in reverse direction.
Warning: this only enumerates already visible child elements
i.e. any collapsed items are not visited.
-
recursiveSelect: aBlock
-
return a new collection with all children and subChildren from the receiver,
for which the argument aBlock evaluates to true.
Warning: this only enumerates already visible child elements
i.e. any collapsed items are not visited.
-
reverseDo: aOneArgBlock
-
evaluate a block on each child (non recursive) in reverse direction
-
select: aBlock
-
return a new collection with all items from the receiver (non recursive),
for which the argument aBlock evaluates to true.
-
withAllDo: aOneArgBlock
-
WARNING: may fetch lazy children
recursively evaluate aOneArgBlock on each item and subitem including self
enumerating parents
-
allParents
-
return a collection of all parents (bottom to top, ie. in parent, grandparent, ... order)
-
parentsDetect: aBlock
-
find the first parent (bottom to top), for which evaluation of the block returns
true; if none does so, report an error
-
parentsDetect: aBlock ifNone: anExceptionBlock
-
find the first parent (bottom to top), for which evaluation of the block returns
true; if none does so, return the evaluation of anExceptionBlock
-
parentsDo: aBlock
-
evaluate a block for each parent (bottom to top)
initialization
-
initialize
-
private
-
addVisibleChildrenTo: aList
-
add all visible children and sub-children to the list
-
checkConsistency
-
-
clearExpandedWhenLastChildWasRemoved
-
https://expeccoalm.exept.de/D227397
Do not set #isExpanded to false just because #children is empty (may children appear 'again' later).
Do modify #isExpanded ONLY when a user presses the expand/collapse toggle, otherwise #isExpanded should be persistent.
The user's preference if the item is expanded or collapsed should be kept,
regardless if there are chilren or not (even regardless anything else).
All other related things, like the drawing in case for #isExpanded is true and children is empty,
has to be solved within the drawing (or within any feature requesting this information)
-
criticalDo: aBlock
-
** This is an obsolete interface - do not use it (it may vanish in future versions) **
-
listIndex
-
returns the index in the full list or nil;
for a non-visible root, 0 is returned
-
numberOfVisibleChildren
-
returns the number of all visible children including subchildren,
but excluding myself.
PseudoRecursive to avoid recursionError for very deep hierarchies.
-
parentOrModel
-
returns the parent without checking for item or model
-
setChildren: aCollectionOfChildrenOrNil
-
-
synchronized: aBlock
-
evaluate aBlock synchronized, i.e. use a monitor for this object;
return the value from aBlock
private-displaying
-
displayLabel: aLabel h: lH on: aGC x: x y: y h: h
-
display the label at x@y
** This is an obsolete interface - do not use it (it may vanish in future versions) **
-
displayLabel: aLabel h: lH on: aGC x: x y: y h: h isHighlightedAsSelected: isHighlightedAsSelected
-
display the label at x@y
-
heightOf: aLabel on: aGC
-
returns the height of the label or 0
-
widthOf: aLabel on: aGC
-
returns the height of the label or 0
private-enumerating
-
nonCriticalDo: aOneArgBlock
-
WARNING: may fetch lazy children (i.e. calls #children)
evaluate a block noncritical for each child.
Not synchronized - should only be called internally
within a synchronized region.
-
nonCriticalFrom: startIndex to: endIndex do: aOneArgBlock
-
WARNING: may fetch lazy children (i.e. calls #children)
evaluate a block noncritical for each child starting with the
child at startIndex to the endIndex (if nil: to end of list).
Returns the value of the last block's evaluation.
Not synchronized - should only be called internally
within a synchronized region.
Answer the value of the block executed on the last element.
-
nonCriticalFrom: startIndex to: endIndexArg reverseDo: aOneArgBlock
-
WARNING: may fetch lazy children (i.e. calls #children)
evaluate a block non critical for each child starting with the
child at endIndex (if nil: from the end of list) down to to startIndex.
Returns the value of the last block's evaluation.
Not synchronized - should only be called internally
within a synchronized region.
-
nonCriticalKeysAndValuesReverseDo: aOneArgBlock
-
WARNING: may fetch lazy children (i.e. calls #children)
evaluate the argument, aBlock in reverse order for every
child, passing both index and element as arguments.
Not synchronized - should only be called internally
within a synchronized region.
-
nonCriticalRecursiveDo: aOneArgBlock
-
WARNING: may fetch lazy children (i.e. calls #children)
evaluate the block non critical for each item and all the sub-items.
Not synchronized - should only be called internally
within a synchronized region.
-
nonCriticalRecursiveReverseDo: aOneArgBlock
-
WARNING: may fetch lazy children (i.e. calls #children)
evaluate the block non critical for each item and all the sub-items;
proccesing children in reverse direction.
Not synchronized - should only be called internally
within a synchronized region.
-
nonCriticalRecursiveSort: aSortBlock
-
recursively sort children using aSortBlock.
Does NOT fetch children (via #children), but sort the ones which are already present.
Not synchronized - should only be called internally
within a synchronized region.
private-hierarchy
-
recursiveSetCollapsed
-
collapse all children and sub-children without notifications
** This is an obsolete interface - do not use it (it may vanish in future versions) **
-
recursiveSetCollapsedHelper
-
private helper.
collapse all children and sub-children without notifications.
Helper; not synchronized - should only be called internally
within a synchronized region.
PseudoRecursive to avoid recursionError with deep hierarchies.
-
recursiveSetExpandedAndAddToList: aList
-
expand all children and sub-children without notifications;
add children to list
** This is an obsolete interface - do not use it (it may vanish in future versions) **
-
recursiveSetExpandedAndAddToListHelper: aList
-
private helper.
expand all children and sub-children without notifications; adds children to aList
Helper; not synchronized - should only be called internally
within a synchronized region.
private-to be redefined
-
fetchChildren
-
should return the list of children via the model.
The default here is to return nil (no children).
*** redefine in subClass
-
heightOn: aGC
-
return the height of the receiver, if it is to be displayed on aGC
** This method raises an error - it must be redefined in concrete classes **
-
isExpanded
-
returns true if the item is expanded
** This method raises an error - it must be redefined in concrete classes **
-
makeWidthAndHeightUnknown
-
invalidate any cached with/height information
** This method raises an error - it must be redefined in concrete classes **
-
setExpanded: aBoolean
-
set expanded flag without any computation or notification.
It is left to the subclasses responsibility, where this expanded state is stored;
could be in the model (as a list of expanded items), in the item itself (as boolean flag),
or somewhere else.
For huge trees, it may make sense to not store the expanded flag in a slot
(in order to save space). See CompactHierarchicalItem as a clever example of how it can be
stored without ANY additional space requirements.
** This method raises an error - it must be redefined in concrete classes **
-
widthOn: aGC
-
return the width of the receiver, if it is to be displayed on aGC
** This method raises an error - it must be redefined in concrete classes **
protocol-accessing
-
children
-
returns a list of children. When first asked, the list is fetched, if it was
built lazily.
*** to optimize: either redefine this or fetchChildren by subClass
-
icon
-
returns the icon or nil;
*** to optimize:redefine by subClass
-
label
-
returns the label displayed on aGC;
*** to optimize:redefine by subClass
-
middleButtonMenu
-
returns the items middleButtonMenu or nil if no menu is defined.
If nil is returned, the view is asked for a menu.
-
recursiveSortChildren: aSortBlock
-
-
sortChildren: aSortBlock
-
sort the children inplace using the 2-arg block sortBlock for comparison
** This is an obsolete interface - do not use it (it may vanish in future versions) **
protocol-displaying
-
displayIcon: anIcon atX: x y: y on: aGC
-
called to draw the icon - can be redefined to manipulate the icon
-
displayOn: aGC x: x y: y h: h
-
draw the receiver in the graphicsContext, aGC
** This is an obsolete interface - do not use it (it may vanish in future versions) **
-
displayOn: aGC x: x y: y h: h isHighlightedAsSelected: isHighlightedAsSelected
-
draw the receiver in the graphicsContext, aGC
protocol-event processing
-
processButtonPress: button visibleX: visX visibleY: visY on: view
-
A mouse button was pressed on myself. The visX/visY coordinates
are relative to the viewOrigin.
If this method returns TRUE, the other method
#processButtonPress:x:y:on: IS NOT CALLED !!!
-
processButtonPress: button x: x y: y
-
a mouse button was pressed in my label.
Return true, if the event is eaten (ignored by the gc).
By default, false is returned (should be handled by the gc).
-
processButtonPress: button x: x y: y on: aGC
-
a mouse button was pressed in my label.
Return true, if the event is eaten (ignored by the gc).
By default, false is returned (should be handled by the gc).
-
processButtonPressOnIcon: button on: aGC
-
a mouse button was pressed in my icon.
Return true, if the event is eaten (ignored by the gc).
By default, false is returned (should be handled by the gc).
protocol-monitoring
-
monitoringCycle
-
called every 'n' seconds by the model, if the monitoring
cycle is enabled. The item can perform some checks, ..
**** can be redefined by subclass to perform some actions
protocol-queries
-
canCollapse
-
called before collapsing the item; can be redefined
by subclass to omit the collapse operation
-
canExpand
-
called before expanding the item; can be redefined
by subclass to omit the expand operation
-
canRecursiveCollapse
-
called before collapsing the item; can be redefined
by subclass to omit the collapse operation.
Q: why is there an extra canRecursiveCollapse (i.e. not always using canCollapse)?
-
canRecursiveExpand
-
called before recursive expanding the item;
can be redefined by subclass to omit the expand operation
-
drawHorizontalLineUpToText
-
draw the horizontal line for the selected item up to the text
or (by default) to the start of the vertical line;
only used by the hierarchical view
-
hasChildren
-
checks whether the item has children;
here the children are fetched, and thus this may take some time.
*** to optimize: redefine in subClass (example: FileDirectory)
-
hasIndicator
-
on default the indicator is drawn if the item has children
-
isSelectable
-
returns true if the item is selectable. Can be redefined in subclasses
-
string
-
access the printable string used for stepping through a list
searching for an entry starting with a character.
*** to optimize:redefine by subClass
queries
-
isChildOf: anItem
-
returns true if the item is a child (or grandchild or ...) of anItem
-
isCollapsed
-
returns true if the item is collapsed
-
isDirectoryItem
-
-
isHierarchicalItem
-
used to decide if the parent is a hierarchical item or the model
-
isRealChildOf: anItem
-
returns true if the item is a child of anItem
-
isRootItem
-
returns true if the item is the root item
-
size
-
return the number of children
searching
-
detect: aOneArgBlock
-
find the first child (not recursive), for which evaluation of the block returns
true; if none does so, report an error
-
detect: aOneArgBlock ifNone: exceptionValue
-
find the first child (not recursive), for which evaluation of the block returns
true; if none does so, return the value of anExceptionValue
-
detectLast: aOneArgBlock
-
find the last child (not recursive), for which evaluation of the block returns
true; if none does so, an exception is raised
-
detectLast: aOneArgBlock ifNone: anExceptionValue
-
find the last child (not recursive), for which evaluation of the block returns
true; if none does so, return the value of anExceptionValue
-
findChildByLabelPath: aLabelPath
-
recursivly find the child by its label path.
A label path is an ordered collection (or array) of strings,
which are the labels of items (i.e. as retrived by labelPath).
-
findFirst: aOneArgBlock
-
find the first child (not recursive), for which evaluation of the argument, aOneArgBlock
returns true; return its index or 0 if none detected.
-
findLast: aOneArgBlock
-
find the last child (not recursive), for which evaluation of the argument, aOneArgBlock
returns true; return its index or 0 if none detected.
-
findNextInTreeForWhich: aBlock
-
does a breadth-first search in the tree starting at the receiver
i.e. first goes down recursively, then up to the next child of the parent
(doing a recursive search there),
up until all of the top item's children have been visited.
Returns the found item or nil.
-
findPreviousInTreeForWhich: aBlock
-
does a breadth-first search in the tree starting at the receiver
i.e. first goes down recursively, then up to the next child of the parent
(doing a recursive search there),
up until all of the top item's children have been visited.
Returns the found item or nil.
-
identityIndexOf: aChild
-
return the index of aChild or 0 if not found. Compare using ==
-
identityIndexOf: aChild startingAt: startIndex
-
return the index of aChild, starting search at startIndex.
Compare using ==; return 0 if not found
-
recursiveDetect: aOneArgBlock
-
recursive find the first child, for which evaluation
of the block returns true; if none, nil is returned.
Warning: this only searches in already visible child elements
i.e. any collapsed items are not searched.
-
recursiveDetect: aOneArgBlock skipIf: elementCheck skipChildrenIf: childrenCheck
-
recursive find the first child, for which evaluation
of the block returns true; if none, nil is returned.
Warning: this only searches in already visible child elements
i.e. any collapsed items are not searched.
-
recursiveDetectLast: aBlock
-
recursive find the last child, for which evaluation of the block returns true;
if none does so, nil is returned.
Warning: this only searches in already visible child elements
i.e. any collapsed items are not searched.
-
withAllDetect: aOneArgBlock
-
recursive find the first item including self,
for which evaluation of the block returns true; if none nil is returned.
Warning: this only searches in already visible child elements
i.e. any collapsed items are not searched.
sorting & reordering
-
recursiveSort: aSortBlock
-
recursive sort the children inplace using the 2-arg block sortBlock for comparison
-
sort: aSortBlock
-
sort the children inplace using the 2-arg block sortBlock for comparison
|