eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'AbstractHierarchicalItem':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: AbstractHierarchicalItem


Inheritance:

   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)

Description:


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


Related information:

    HierarchicalItem
    (the
    old
    item
    class)
    HierarchicalList
    (typical
    model)
    HierarchicalListView
    (typical
    user
    of
    me)

Class protocol:

instance creation
o  new

o  parent: aParent

protocol
o  doResetExtentOnChange
true: the extent of the item is reset if a change
notification is raised from the item. the default is true

queries
o  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.


Instance protocol:

accessing
o  getChildren
returns the children as they are present (or not);
not going to the model, and especially not creating autocreated children...

o  level
returns the level starting with 0 for the root

o  nextSibling
returns the next child of my parent or nil

o  parent
returns the parent or nil

o  parent: aParent
set the parent (or the model if the item is the root item)

o  previousSibling
returns the previous child of my parent or nil

o  rootItem
returns the root item

accessing-children
o  at: anIndex
return the child at anIndex if valid;
if the index is invalid, nil is returned

o  at: anIndex ifAbsent: exceptionBlock
return the child at anIndex if valid; if the index is
invalid, the result of evaluating the exceptionBlock is returned.

o  at: anIndex put: anItem
replace a child by a new item. return anItem (sigh)

o  children: aListOfChildren
set a new list of children

o  first
returns the first child

o  last
returns the last child

o  second
returns the second child

accessing-hierarchy
o  collapse
hide all my subitems

o  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

o  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)

o  expand: enforced
expand children

o  expandLevels: numLevels
expand children numLevels down

o  expandLevels: numLevels max: maxNumExpandedHolder
expand children numLevels down

o  expandWithoutUpdate
in case expand is redefined to do any update
(as in guiBrowser's applicationTreeItem),
this can be used to expand without updating

o  labelPath
return my label-path as an ordered collection of individual labels

o  makeVisible
expand all my parents

o  recursiveCollapse
collapse item and recursively all sub items

o  recursiveExpand
expand children and sub-children;
WARNING: refetches children.
Precondition: must be collapsed

o  recursiveToggleExpand
if the item is collapsed, the item and all its sub-items
are expanded otherwise collapsed

o  toggleExpand
if the item is collapsed, the item is expanded otherwise collapsed

accessing-mvc
o  application
returns the responsible application or nil

o  applicationsDo: aOneArgBlock
evaluate the block for each dependent application

o  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

o  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
o  add: aChildItem
add a child at end

o  add: aChildItem after: aChild
add an item after an existing item

o  add: aChildItem afterIndex: anIndex
add an item after an index

o  add: aChildItem before: aChild
add an item before an existing item

o  add: aChildItem beforeIndex: anIndex
add an item before an index

o  add: aChild sortBlock: aBlock
add a child sorted

o  addAll: aList
add children at the end

o  addAll: aList before: aChild
add an item before an existing item

o  addAll: aList beforeIndex: anIndex
add children before an index

o  addAll: aList sortBlock: aBlock
add children sorted

o  addAllFirst: aCollectionOfItems
add children at the beginning

o  addAllLast: aCollectionOfItems
add children at the end

o  addFirst: aChildItem
add a child at the beginning

o  addLast: anItem
add a child at the end

o  remove
remove the item

o  remove: aChild
remove a child

o  removeAll
remove all children.
Returns the receiver.

o  removeAll: aList
remove all items in aList from my children.
Returns the receiver.

o  removeAllIdentical: aList
remove all children in the collection

o  removeFromIndex: startIndex
remove the children from startIndex up to end of children.
Returns the receiver.

o  removeFromIndex: startIndex toIndex: stopIndex
remove the children from startIndex up to and including
the child under stopIndex.
Returns the receiver.

o  removeIndex: anIndex
remove the child at an index.
Returns the receiver

basic adding & removing
o  basicAdd: aChild sortBlock: aBlockOrNil
add a child sorted.
Not synchronized - should only be called internally
within a synchronized region.

o  basicAddAll: aList beforeIndex: anIndex
add children before an index.
Not synchronized - should only be called internally
within a synchronized region.

o  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
o  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

o  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 !

o  fontChanged
called if the font has changed.
Clear the precomputed width and height

o  hierarchyChanged
hierarchy changed; optimize redrawing

o  iconChanged
icon changed; optimize redrawing

o  invalidate
force redrawing of me

o  labelChanged
called if the label has changed.
Clear the precomputed width and height, and invalidate

enumerating
o  allExpandedItemsDo: aBlock
recursively enumerate all expanded nodes
(depth first; parent before children)

o  collect: aBlock
for each child in the receiver (non recursive), evaluate the argument, aBlock
and return a new collection with the results

o  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

o  do: aOneArgBlock
evaluate a block for each child (non recursive)

o  from: startIndex do: aOneArgBlock
evaluate a block on each child starting with the
child at startIndex to the end.

o  from: startIndex reverseDo: aOneArgBlock
evaluate a block on each child (non recursive) starting at end to the startIndex

o  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.

o  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.

o  keysAndValuesDo: aTwoArgBlock
evaluate the argument, aBlock for every child (non recursive),
passing both index and element as arguments.

o  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.

o  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.

o  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.

o  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.

o  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.

o  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.

o  reverseDo: aOneArgBlock
evaluate a block on each child (non recursive) in reverse direction

o  select: aBlock
return a new collection with all items from the receiver (non recursive),
for which the argument aBlock evaluates to true.

o  withAllDo: aOneArgBlock
WARNING: may fetch lazy children
recursively evaluate aOneArgBlock on each item and subitem including self

enumerating parents
o  allParents
return a collection of all parents (bottom to top, ie. in parent, grandparent, ... order)

o  parentsDetect: aBlock
find the first parent (bottom to top), for which evaluation of the block returns
true; if none does so, report an error

o  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

o  parentsDo: aBlock
evaluate a block for each parent (bottom to top)

initialization
o  initialize

private
o  addVisibleChildrenTo: aList
add all visible children and sub-children to the list

o  checkConsistency

o  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)

o  criticalDo: aBlock

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  listIndex
returns the index in the full list or nil;
for a non-visible root, 0 is returned

o  numberOfVisibleChildren
returns the number of all visible children including subchildren,
but excluding myself.
PseudoRecursive to avoid recursionError for very deep hierarchies.

o  parentOrModel
returns the parent without checking for item or model

o  setChildren: aCollectionOfChildrenOrNil

o  synchronized: aBlock
evaluate aBlock synchronized, i.e. use a monitor for this object;
return the value from aBlock

private-displaying
o  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) **

o  displayLabel: aLabel h: lH on: aGC x: x y: y h: h isHighlightedAsSelected: isHighlightedAsSelected
display the label at x@y

o  heightOf: aLabel on: aGC
returns the height of the label or 0

o  widthOf: aLabel on: aGC
returns the height of the label or 0

private-enumerating
o  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.

o  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.

o  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.

o  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.

o  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.

o  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.

o  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
o  recursiveSetCollapsed
collapse all children and sub-children without notifications

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  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.

o  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) **

o  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
o  fetchChildren
should return the list of children via the model.
The default here is to return nil (no children).
*** redefine in subClass

o  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 **

o  isExpanded
returns true if the item is expanded

** This method raises an error - it must be redefined in concrete classes **

o  makeWidthAndHeightUnknown
invalidate any cached with/height information

** This method raises an error - it must be redefined in concrete classes **

o  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 **

o  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
o  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

o  icon
returns the icon or nil;
*** to optimize:redefine by subClass

o  label
returns the label displayed on aGC;
*** to optimize:redefine by subClass

o  middleButtonMenu
returns the items middleButtonMenu or nil if no menu is defined.
If nil is returned, the view is asked for a menu.

o  recursiveSortChildren: aSortBlock

o  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
o  displayIcon: anIcon atX: x y: y on: aGC
called to draw the icon - can be redefined to manipulate the icon

o  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) **

o  displayOn: aGC x: x y: y h: h isHighlightedAsSelected: isHighlightedAsSelected
draw the receiver in the graphicsContext, aGC

protocol-event processing
o  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 !!!

o  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).

o  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).

o  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
o  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
o  canCollapse
called before collapsing the item; can be redefined
by subclass to omit the collapse operation

o  canExpand
called before expanding the item; can be redefined
by subclass to omit the expand operation

o  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)?

o  canRecursiveExpand
called before recursive expanding the item;
can be redefined by subclass to omit the expand operation

o  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

o  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)

o  hasIndicator
on default the indicator is drawn if the item has children

o  isSelectable
returns true if the item is selectable. Can be redefined in subclasses

o  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
o  isChildOf: anItem
returns true if the item is a child (or grandchild or ...) of anItem

o  isCollapsed
returns true if the item is collapsed

o  isDirectoryItem

o  isHierarchicalItem
used to decide if the parent is a hierarchical item or the model

o  isRealChildOf: anItem
returns true if the item is a child of anItem

o  isRootItem
returns true if the item is the root item

o  size
return the number of children

searching
o  detect: aOneArgBlock
find the first child (not recursive), for which evaluation of the block returns
true; if none does so, report an error

o  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

o  detectLast: aOneArgBlock
find the last child (not recursive), for which evaluation of the block returns
true; if none does so, an exception is raised

o  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

o  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).

o  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.

o  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.

o  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.

o  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.

o  identityIndexOf: aChild
return the index of aChild or 0 if not found. Compare using ==

o  identityIndexOf: aChild startingAt: startIndex
return the index of aChild, starting search at startIndex.
Compare using ==; return 0 if not found

o  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.

o  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.

o  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.

o  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
o  recursiveSort: aSortBlock
recursive sort the children inplace using the 2-arg block sortBlock for comparison

o  sort: aSortBlock
sort the children inplace using the 2-arg block sortBlock for comparison



ST/X 7.2.0.0; WebServer 1.670 at bd0aa1f87cdd.unknown:8081; Fri, 19 Apr 2024 13:32:07 GMT