|
Class: AbstractHierarchicalItem
Object
|
+--AbstractHierarchicalItem
|
+--CompactHierarchicalItem
|
+--HierarchicalItem
- Package:
- stx:libwidg2
- Category:
- Views-Support
- Version:
- rev:
1.20
date: 2018/04/29 15:08:12
- 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...
-
level
-
returns the level starting with 0 for the root
-
parent
-
returns the parent or nil
-
parent: aParent
-
set the parent (or the model if the item is the root item)
-
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
-
labelPath
-
return my label-path as an ordered collection of individual labels
-
makeVisible
-
expand all my parents
-
recursiveCollapse
-
collapse all item and sub items
**** must be expanded
-
recursiveExpand
-
expand children and sub-children
**** 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
-
model
-
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
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
-
removeAll: aList
-
remove all children in the collection
-
removeAllIdentical: aList
-
remove all children in the collection
-
removeFromIndex: startIndex
-
remove the children from startIndex up to end of children
-
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
basic adding & removing
-
basicAdd: aChild sortBlock: aBlock
-
add a child sorted
-
basicAddAll: aList beforeIndex: anIndex
-
add children before an index
-
basicRemoveFromIndex: startIndex toIndex: stopIndex
-
remove the children from startIndex up to and including
the child under stopIndex.
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
-
labelChanged
-
called if the label has changed.
Clear the precomputed width and height
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
-
evaluate a block on each child (non recursive),
starting with the child at startIndex to the endIndex.
-
from: startIndex to: endIndex reverseDo: aOneArgBlock
-
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
-
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
-
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
-
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
-
recursively evaluate aOneArgBlock on each item and subitem including self
enumerating parents
-
allParents
-
return a collection of all parents (in parent, grandparent, ... order)
-
parentsDetect: aBlock
-
find the first parent, for which evaluation of the block returns
true; if none does so, report an error
-
parentsDetect: aBlock ifNone: anExceptionBlock
-
find the first parent, 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
initialization
-
initialize
-
private
-
addVisibleChildrenTo: aList
-
add all visible children and sub-children to the list
-
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
-
-
listIndex
-
returns the visible index or nil; for a non-visible root, 0 is returned
-
numberOfVisibleChildren
-
returns number of all visible children including subchildren
-
parentOrModel
-
returns the parent without checking for item or model
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
-
evaluate a block noncritical for each child.
-
nonCriticalFrom: startIndex to: endIndex do: aOneArgBlock
-
evaluate a block noncritical for each child starting with the
child at startIndex to the endIndex (if nil to end of list).
-
nonCriticalFrom: startIndex to: endIndex reverseDo: aOneArgBlock
-
evaluate a block non critical for each child starting with the
child at endIndex (if nil to end of list) to startIndex.
-
nonCriticalKeysAndValuesReverseDo: aOneArgBlock
-
evaluate the argument, aBlock in reverse order for every
child, passing both index and element as arguments.
-
nonCriticalRecursiveDo: aOneArgBlock
-
evaluate the block non critical for each item and all the sub-items
-
nonCriticalRecursiveReverseDo: aOneArgBlock
-
evaluate the block non critical for each item and all the sub-items;
proccesing children in reverse direction
-
nonCriticalRecursiveSort: aSortBlock
-
evaluate a block noncritical for each child.
private-hierarchy
-
recursiveSetCollapsed
-
collapse all children and sub-children without notifications
-
recursiveSetCollapsedHelper
-
private helper.
collapse all children and sub-children without notifications.
Helper only - does not lock
-
recursiveSetExpandedAndAddToList: aList
-
expand all children and sub-children without notifications;
add children to list
-
recursiveSetExpandedAndAddToListHelper: aList
-
private helper.
expand all children and sub-children without notifications; adds children to aList
Helper only - does not lock
private-to be redefined
-
fetchChildren
-
-
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
-
canRecursiveExpand
-
called before expanding the item; can be redefined
by subclass to omit the collapse operation
-
drawHorizontalLineUpToText
-
draw the horizizontal line for the selected item up to the text
or on default to the start of the the vertical line; only used by
the hierarchical view
-
hasChildren
-
checks whether the item has children;
the list needs not to be loaded yet( example. FileDirectory ).
*** to optimize: redefine in subClass
-
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 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.
-
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.
-
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
|