Active Trees: Beta, Third Iteration

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Active Trees: Beta, Third Iteration

Eric Taylor
Hello Forum!

After much unit- and field-testing, I have finally completed the third
iteration of Active Trees.  The reason for the delay is that I had to
learn SUnit, and then develop the tests (over 100 of them!).  The files
should be available in a few days.

HOW ARE ACTIVE TREES DIFFERENT FROM TREES?

ActiveTreeModel, a subclass of TreeModel, is the centerpiece of the
implementation of active trees.  This class can benefit the developer in
at least two ways: first, by providing cursor-based manipulation of
trees, and second, by extending TreeModel's features with an extensive
set of node- and level-manipulation features.  A sample from this set:

#allOnLevel:
#levelOf:
#depth
#addAll:asChildrenOf: and #addAllFirst:asChildrenOf:
#addFirst:asChildOf:
#add:after:, #add:afterCursor:, and #addAfterCursor:
#moveAll:asChildOf:
#moveDown:
#move:upBy:
#moveToTop: and #moveToBottom:
#moveUpOneLevel:
#move:toBefore:, #move:toBeforeCursor:, and #moveToBeforeCursor:
#grandparentOf:
#beRoots:

The cursor in ActiveTreeModel has a behavior defined by
ActiveTreeCursor, and includes methods such as:

#goBack, #goForward, #goUp, #goDown
#goTo:, #goToFirst, #goToLast
#goToFirstInLevel: and #goToLastInLevel:
#goToFirstWithChildren and #goToLastWithChildren

Aside from being able to request an unlimited number of
ActiveTreeCursors on an ActiveTreeModel, ActiveTreeModel's global cursor
is directly accessible and available for manipulation:

myTreeModel := ActiveTreeModel new.
myTreeModel cursor goTo: someObject

Since cursors must, by definition, be nondestructive, this breaking of
encapsulation is quite expedient...and harmless.

Once the files are available, I'll let the forum know.  Feedback and
criticism would be much appreciated.

Cheers,

Eric

========================================================================
==

This iteration includes the following developments:

1) The full "active" class hierarchy now consists of ActiveTreeModel,
ActiveTreeCursor, ActiveTreeNode, and ActiveTreeView;
2) Full implementation of cursors.  ActiveTreeModel now employs a global
cursor to carry out its operations.  The global cursor is stored in the
instance variable <cursor>;
3) One can instantiate an unlimited number of ActiveTreeCursors on an
ActiveTreeModel.  Each cursor can be manipulated in isolation, without
any effect on ActiveTreeModel's global cursor;
4) All cursors, including ActiveTreeModel's global cursor, respond to
two events: #invalidateCursors and #invalidateCursorsAndGoTo:.  If an
object is removed from a tree, all cursors affected by the removal will
update themselves according to the cursor-updating policy defined in
ActiveTreeCursor>>#updateByPolicy;
5) ActiveTreeModels (and ActiveTreeNodes) are now level-aware, and
ActiveTreeModel includes a number of level-oriented methods;
6) Addressed efficiency concerns with respect to cursor-updating.
Eliminated the need to update numerous state variables (and,
consequently, eliminated those state variables).  Only a cursor's
underlying object is updated.  All collateral state information about,
and around, the cursor is supplied only upon request;
7) Added a development method that allows trees to be built quickly from
"bracket notation";
8) Three unit tests now come with the implementation:
ActiveTreeModelTest, ActiveTreeCursorTest, and ActiveTreeNodeTest.

Aside from the unit tests, we have been rigorously field-testing the
implementation with our XtremeCommandBarsPresenter, among other things.
We have also tested, through use cases, rather large trees of 1000,
10000, 100000, and 1000000 nodes.

WHAT REMAINS TO BE DONE

1) Still must address the need to refresh the entire tree whenever its
roots are manipulated (the cause has been identified, but solving it is
not trivial);
2) Refine the unit tests (the current tests are a little awkward as this
is my first time out with SUnit);
3) Need to abstract ActiveTreeCursor.  Actually, I already have, but I
have not tested all of the classes and, therefore, have not included the
abstraction in this iteration.  The full hierarchy is

DataCursor
        SequenceCursor
                LinkedCursor
                        TreeCursor
                                ActiveTreeCursor

While it is possible to request a cursor on a collection, such as
OrderedCollection, it would seem that Smalltalk's [wonderful]
stream-based classes render cursors on sequenceable collections
superfluous (well, almost ;)).  There is one advantage, however:
behavioral normalization.  Normalization would eliminate the disparity
between streams and nonlinear data structures, such as trees and graphs
(somehow TreeStream and GraphStream just don't sit well).  Further, one
could implement behavior such as #swapCursor:withCursor, where
normalized cursor behavior would allow two entirely different types of
data structure to communicate with, and operate upon, each other in just
such a manner.