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. |
Free forum by Nabble | Edit this page |