Source code: com/flexstor/common/awt/tree/FlexTreeNode.java
1 /*
2 * FlexTreeNode.java
3 *
4 * Copyright $Date: 2003/08/11 02:22:36 $ FLEXSTOR.net Inc.
5 *
6 * This work is licensed for use and distribution under license terms found at
7 * http://www.flexstor.org/license.html
8 *
9 */
10
11 package com.flexstor.common.awt.tree;
12
13 import java.awt.Color;
14 import java.awt.FontMetrics;
15 import java.awt.Graphics;
16 import java.awt.Image;
17 import java.util.ArrayList;
18 import java.util.Iterator;
19
20 /**
21 * The FlexTreeNode is a support class for the Tree.
22 * It is used to represent a single line item in the Tree.
23 * This class is based on the Proto View TreeViewJ version 2.0
24 *
25 * @version 2.1
26 * @author Don Preuninger (Proto View)
27 * @author Viktor Snezhko (Proto View)
28 * @author Dan Schroeder (Rorke Data)
29 */
30 public class FlexTreeNode
31 {
32 public static final int FIRST = -100; // First child -- used in addChild()
33 public static final int LAST = -200; // Last child -- used in addChild()
34
35 private static Image iDefExp = null; // Default expanded image.
36 private static Image iDefCol = null; // Default collapsed image.
37 private Image iExpanded = null; // Expanded image.
38 private Image iCollapsed = null; // Collapsed image.
39
40 private String sLabel = null; // Label
41 private Color cFg = Color.black; // Foreground color
42 private Color cBgSel = new Color ( 0, 0, 119 ); // Selected background color
43 private Color cFgSel = Color.white; // Selected foreground color
44 private Color cLine = Color.gray; // Line color
45 private Color cDotBorder = Color.yellow; // The dotted border color for the current node.
46
47 private boolean bTrueRoot = false; // True if this is a "true" root node. This is a node that is
48 // not visible on the tree and is the parent of all other root nodes.
49 private boolean bSubRoot = false; // True if this is a root node.
50 private int nTreeID = -1; // ID of this node's tree (used by root only)
51 private int nLevel = -1; // Node level - calculated by getLevel()
52 private boolean bRemoved = false; // ???
53 private boolean bExpanded = true; // True if this node is currently expanded.
54
55 public FlexTreeNode nNext = null; // The next sibling node.
56 protected FlexTreeNode nPrev = null; // The previous sibling node.
57 protected FlexTreeNode nFirstChild = null; // First child of this node.
58 protected FlexTreeNode nLastChild = null; // Last child of this node.
59 protected FlexTreeNode nParent = null; // The parent of this node.
60
61 private boolean bAlwaysShowPlusMinus = false;
62 private boolean bSelected = false;
63
64 public FlexTreeNode ( )
65 {
66 this ( "", null, null );
67 }
68
69 public FlexTreeNode ( String sLabel )
70 {
71 this ( sLabel, null, null );
72 }
73
74
75 public FlexTreeNode ( String sLabel, Image expanded, Image collapsed )
76 {
77 this.sLabel = sLabel;
78 setDefaultImages();
79 setImages ( expanded, collapsed );
80 }
81
82
83 public int getTreeID ( )
84 {
85 FlexTreeNode n = this;
86
87 // Find a root node.
88 while ( n != null && !n.isTrueRoot() )
89 n = n.getParent();
90
91 return (n == null) ? -1 : n.nTreeID;
92 }
93
94
95 public void forceRepaint ( )
96 {
97 TreeNotifier.notify ( getTreeID(), TreeNotifier.REPAINT );
98 }
99
100
101 public void forceLayout ( )
102 {
103 TreeNotifier.notify ( getTreeID(), TreeNotifier.REPAINT );
104 }
105
106
107 public void setRedraw ( boolean bState )
108 {
109 if ( bState )
110 TreeNotifier.notify ( getTreeID(), TreeNotifier.REDRAW_ON );
111 else
112 TreeNotifier.notify ( getTreeID(), TreeNotifier.REDRAW_OFF );
113 }
114
115 public void setAlwaysShowPlusMinus ( boolean bAlwaysShowPlusMinus )
116 {
117 this.bAlwaysShowPlusMinus = bAlwaysShowPlusMinus;
118 }
119
120 public boolean getAlwaysShowPlusMinus ( )
121 {
122 return bAlwaysShowPlusMinus;
123 }
124
125 protected void setAsTrueRoot ( int id )
126 {
127 bTrueRoot = true;
128 nTreeID = id;
129 }
130
131 protected void setAsRoot ( )
132 {
133 bSubRoot = true;
134 }
135
136 public boolean isTrueRoot ( )
137 {
138 return bTrueRoot;
139 }
140
141 public boolean isRoot ( )
142 {
143 return bSubRoot;
144 }
145
146 public void addChild ( FlexTreeNode n, int nPosition )
147 {
148 FlexTreeNode c1; // Child that will be before the new node.
149 FlexTreeNode c2; // Child that will be after the new node.
150
151 // ...--> c1 <--> n <--> c2 <--...
152
153 switch ( nPosition )
154 {
155 case FIRST:
156 case 0:
157 {
158 c1 = null;
159 c2 = nFirstChild;
160 break;
161 }
162
163 case LAST:
164 {
165 c1 = getLastChild();
166 c2 = null;
167 break;
168 }
169
170 default:
171 {
172 c1 = getChild ( nPosition-1 );
173 c2 = getChild ( nPosition );
174
175 if ( c1 == c2 )
176 c2 = null;
177
178 break;
179 }
180 }
181
182 /*
183 System.out.println ( "" );
184
185 if ( nPosition == FIRST )
186 System.out.println ( "FIRST" );
187 else if ( nPosition == LAST )
188 System.out.println ( "LAST" );
189 else
190 System.out.println ( nPosition );
191
192 System.out.println ( "n = " + n + " - " + n.getLabel() );
193
194 if ( c1 == null )
195 System.out.println ( "c1 = " + c1 );
196 else
197 System.out.println ( "c1 = " + c1 + " - " + c1.getLabel());
198
199 if ( c2 == null )
200 System.out.println ( "c2 = " + c2 );
201 else
202 System.out.println ( "c2 = " + c2 + " - " + c2.getLabel());
203 */
204
205 // Link n to this node (parent).
206 n.nParent = this;
207
208 // Link nodes c1 and n
209 if ( c1 == null )
210 {
211 nFirstChild = n;
212 n.nPrev = null;
213 }
214 else
215 {
216 c1.nNext = n;
217 n.nPrev = c1;
218 }
219
220 // Link nodes n and c2;
221 if ( c2 == null )
222 {
223 nLastChild = n;
224 n.nNext = null;
225 }
226 else
227 {
228 n.nNext = c2;
229 c2.nPrev = n;
230 }
231 }
232
233
234 public ArrayList getChildren ( )
235 {
236 ArrayList l = new ArrayList();
237 FlexTreeNode node = nFirstChild;
238
239 while ( node != null )
240 {
241 l.add ( node );
242 node = node.nNext;
243 }
244
245 return l;
246 }
247
248
249 public FlexTreeNode getFirstChild ( )
250 {
251 return nFirstChild;
252 }
253
254
255 public ArrayList getAllChildren ( )
256 {
257 FlexTreeNode node = nFirstChild;
258 ArrayList l = new ArrayList();
259
260 while ( node != null )
261 {
262 l.add ( node );
263 l.addAll ( node.getAllChildren() );
264 node = node.nNext;
265 }
266
267 return l;
268 }
269
270
271 /**
272 * Returns the Nth child of this node.
273 * If there are less than N children, then the last child is returned.
274 * If there are no childen, then null is returned.
275 * @param n the child to return.
276 * @return the child node.
277 */
278 public FlexTreeNode getChild ( int n )
279 {
280 int nCount = 1;
281 FlexTreeNode node = nFirstChild;
282
283 while ( node != null && node.nNext != null && nCount <= n )
284 {
285 node = node.nNext;
286 nCount++;
287 }
288
289 return node;
290 }
291
292
293 private FlexTreeNode getLastChild ( )
294 {
295 FlexTreeNode n = nFirstChild;
296
297 while ( n != null && n.nNext != null )
298 {
299 n = n.nNext;
300 }
301
302 return n;
303 }
304
305
306 /**
307 * Set the foreground color for this node
308 * @param color the new background color
309 */
310 public void setForeground(Color color)
311 {
312 cFg = color;
313 }
314
315
316 /**
317 * Get the foreground color for this node. If no foreground color has been set,
318 * then the return value is null.
319 */
320 public Color getForeground()
321 {
322 return cFg;
323 }
324
325 /**
326 * Set the foreground color for this node when selected
327 * @param color the new selected background color
328 */
329 public void setSelectedForeground(Color color)
330 {
331 cFgSel = color;
332 }
333
334
335 /**
336 * Get the selected foreground color for this node.
337 */
338 public Color getSelectedForeground()
339 {
340 return cFgSel;
341 }
342
343
344 /**
345 * Check if the "node" is a child of this node.
346 * @param node node to test as a child.
347 * @return True - node is a child, false node is not a child
348 * @see #isDescendant
349 */
350 public boolean isChild(FlexTreeNode node)
351 {
352 FlexTreeNode n = nFirstChild;
353 if(node == null || n == null) return false;
354 if(n == node) return true;
355 while(n != null)
356 {
357 n = n.nNext;
358 if(n == node)
359 return true;
360 }
361 return false;
362 }
363
364
365 /**
366 * Check if the "node" is a descendant of this node.
367 * @param node node to test as a descendant.
368 * @return True - node is a descendant, false - node is not a descendant
369 * @see #isChild
370 */
371 public boolean isDescendant(FlexTreeNode node)
372 {
373 FlexTreeNode n = nFirstChild;
374 if(node == null || n == null) return false;
375 if(isChild(node))
376 return true;
377 while(!n.isDescendant(node))
378 {
379 n = n.nNext;
380 if(n == null)
381 return false;
382 }
383 return true;
384 }
385
386
387 public void remove()
388 {
389 int nID = getTreeID();
390
391 // Remove children
392 FlexTreeNode c = nFirstChild;
393 nLastChild = null;
394 nFirstChild = null;
395 while ( c != null )
396 {
397 c.remove();
398 c = c.nNext;
399 }
400
401 // Node is in the middle of other nodes
402 if ( nNext != null && nPrev != null )
403 {
404 nNext.nPrev = nPrev;
405 nPrev.nNext = nNext;
406 }
407
408 // Node is the first child of several
409 else if ( nNext != null )
410 {
411 nNext.nPrev = null;
412 if ( nParent != null && nParent.nFirstChild == this )
413 nParent.nFirstChild = nNext;
414 }
415
416 // Node is the last child of several
417 else if(nPrev != null)
418 {
419 nPrev.nNext = null;
420 if ( nParent != null && nParent.nLastChild == this )
421 nParent.nLastChild = nPrev;
422 }
423 // The only child
424 else if(nParent != null)
425 {
426 if(nParent.nFirstChild == this)
427 nParent.nFirstChild = null;
428
429 if(nParent.nLastChild == this)
430 nParent.nLastChild = null;
431 }
432
433 nPrev = null;
434 nParent = null;
435 bRemoved = true;
436
437 // Need to test if this deleted item is the first visible item in the tree (bug #6565)
438 TreeNotifier.notify ( nID, TreeNotifier.CHECK_FIRST_VISIBLE_NODE );
439 }
440
441 public void removeChildren()
442 {
443 for ( Iterator i = getChildren().iterator(); i.hasNext(); )
444 ((FlexTreeNode)i.next()).remove();
445 }
446
447 protected int _paint ( Tree Tree, Graphics g, int count )
448 {
449 if ( bRemoved )
450 return 0;
451
452 int nHOffset = 3 + ( getLevel() * Tree.m_iIndent ) - Tree.m_iHScroll;
453 int nVOffset = ( count - 1 ) * Tree.m_iLineHeight;
454 int nHStart = -( 2 + Tree.m_iHScroll ) + Tree.m_imMinus.getHeight( Tree );
455
456 if ( Tree.getLines() )
457 {
458 int nHalfLineHeight = Tree.m_iLineHeight / 2;
459
460 // set lines color
461 g.setColor( cLine );
462
463 int nHLineOffset = 0;
464
465 // draw vertical lines
466 for ( int nCurrentLevel = 0; nCurrentLevel <= getLevel(); nCurrentLevel++ )
467 {
468 FlexTreeNode parent = this;
469
470 int nL = getLevel();
471 while ( nL > nCurrentLevel )
472 {
473 parent = parent.nParent;
474
475 nL--;
476 }
477
478 nHLineOffset = ( nCurrentLevel * Tree.m_iIndent ) + nHStart;
479
480 // line down from "+"
481 if ( ( getLevel() == 0 ) && ( nPrev == null ) )
482 {
483 if ( nNext != null )
484 {
485 g.drawLine( nHStart, nVOffset + nHalfLineHeight, nHStart, nVOffset + Tree.m_iLineHeight );
486 }
487 }
488 // line up from last sibling node
489 else if ( ( parent.nNext == null ) && ( nCurrentLevel == getLevel() ) )
490 {
491 // "vOffset - 1" - connect to node image on the top
492 g.drawLine( nHLineOffset, nVOffset - 1, nHLineOffset, nVOffset + nHalfLineHeight );
493 }
494 // line up/down from previous to next sibling
495 else if ( parent.nNext != null )
496 {
497 g.drawLine( nHLineOffset, nVOffset - 1, nHLineOffset, nVOffset + Tree.m_iLineHeight );
498 }
499 }
500
501 // draw horizontal line ( 7 pixels )
502 g.drawLine( nHLineOffset, nVOffset + nHalfLineHeight, nHLineOffset + 7, nVOffset + nHalfLineHeight );
503 }
504
505 // paint the plus and minus buttons
506 if ( bAlwaysShowPlusMinus || nFirstChild != null )
507 {
508 g.drawImage( bExpanded ? Tree.m_imMinus : Tree.m_imPlus,
509 nHOffset, nVOffset + ( Tree.m_iLineHeight - Tree.m_imMinus.getHeight( Tree ) ) / 2, Tree );
510 }
511 nHOffset += Tree.m_imMinus.getWidth( Tree ) + 5;
512
513 // paint the image
514 Image image = bExpanded ? getExpandedImage() : getCollapsedImage();
515 if( image != null )
516 {
517 g.drawImage( image, nHOffset, nVOffset + ( Tree.m_iLineHeight - image.getHeight( Tree ) ) / 2, Tree );
518
519 nHOffset += image.getWidth( Tree );
520 }
521 else if ( Tree.getLines() )
522 {
523 nHOffset += 4;
524 }
525
526 // gap between image and text
527 nHOffset += 5;
528
529 FontMetrics fm = g.getFontMetrics();
530
531 // text vertical offset
532 int vTextVOffset = nVOffset + fm.getAscent() + ( Tree.m_iLineHeight - ( fm.getAscent() + fm.getDescent() ) ) / 2;
533
534 // focus rectangle
535 if ( Tree.selection.isSelected( this ) )
536 {
537 int nTextWidth = fm.stringWidth( getLabel() ) + 5;
538
539 // set selection rectangle
540 g.setColor( cBgSel );
541 g.fillRect( nHOffset - 2, nVOffset, nTextWidth, Tree.m_iLineHeight );
542
543 // draw text string
544 g.setColor( getSelectedForeground() );
545 g.drawString( getLabel(), nHOffset, vTextVOffset );
546
547 // if focus is in current node, draw focus border around selection rectangle
548 if ( Tree.getCurrentNode() == this )
549 drawSelectedBorder( g, nHOffset - 2, nVOffset, nTextWidth - 1, Tree.m_iLineHeight - 1 );
550 }
551 else
552 {
553 // draw text string
554 g.setColor( getForeground() );
555 g.drawString( getLabel(), nHOffset, vTextVOffset );
556 }
557
558 return count;
559 }
560
561 public void drawSelectedBorder ( Graphics g, int l, int t, int w, int h )
562 {
563 int d = w & 1;
564 w += l;
565 int i = t - 1;
566
567 g.setColor ( cDotBorder );
568
569 // left/right lines
570 while((i += 2) <= h + t)
571 {
572 g.drawLine(l, i, l, i);
573 g.drawLine(w, i + d, w, i + d);
574 }
575
576 // top/bottom lines
577 d = h & 1;
578 h += t;
579 i = l - 1;
580 while((i += 2) <= w)
581 {
582 g.drawLine(i, t, i, t);
583 g.drawLine(i + d, h, i + d, h);
584 }
585 }
586
587
588 protected FlexTreeNode nodeAtLine(int Line)
589 {
590 FlexTreeNode oldNode = null;
591 FlexTreeNode next = this;
592 int x = 1;
593 while((next != null) && x < Line)
594 {
595 oldNode = next;
596 next = next.getNextVisible();
597 x++;
598 }
599 return (next == null) ? oldNode : next;
600 }
601
602
603 protected int lineFromNode(Tree tree)
604 {
605 int x = 1;
606 FlexTreeNode next = tree.firstVisNode;
607 while((next != null) && x <= tree.m_iLinesPerPage + 1)
608 {
609 if(next == this)
610 return x;
611 next = next.getNextVisible();
612 x++;
613 }
614 return -1;
615 }
616
617
618 /**
619 * Return the parent node of this node
620 */
621 public FlexTreeNode getParent()
622 {
623 return nParent;
624 }
625
626
627 /**
628 * Return the next node that is visible. The visible nodes are the nodes
629 * whose ancestors are all expanded. Even if a node is scrolled out of view,
630 * it can still be considered visible.
631 */
632 public FlexTreeNode getNextVisible()
633 {
634 if((nFirstChild != null) && bExpanded)
635 return nFirstChild;
636 else if(nNext != null)
637 return nNext;
638 return (nParent == null) ? null : nParent.getNextParent();
639 }
640
641
642 /**
643 * Return the next node following this node. The next node may not be visible
644 * and it may not be either a child nor a sibling of this node. This method is used for
645 * enumerating all nodes
646 */
647 public FlexTreeNode getNext()
648 {
649 if(nFirstChild != null)
650 return nFirstChild;
651 else if(nNext != null)
652 return nNext;
653 return (nParent == null) ? null : nParent.getNextParent();
654 }
655
656
657 /**
658 * Return the previous node following this node. The previous node may not
659 * be visible and it may not be either a child nor a sibling of this node.
660 * This method is used for enumerating all nodes in reverse
661 */
662 public FlexTreeNode getPrev()
663 {
664 return (nPrev == null) ? (nParent.isTrueRoot() ? null : nParent) :
665 nPrev.getPrevLast(this);
666 }
667
668
669 protected FlexTreeNode getPrevLast(FlexTreeNode node)
670 {
671 if(nLastChild == null)
672 return this;
673 else
674 return (nLastChild == node) ? null : nLastChild.getPrevLast(node);
675 }
676
677
678 protected FlexTreeNode getNextParent()
679 {
680 if(nNext != null)
681 return nNext;
682 return (nParent == null) ? null : nParent.getNextParent();
683 }
684
685
686 /**
687 * Return the previous node that is visible. The visible nodes are the nodes
688 * whose ancestors are all expanded. Even if a node is scrolled out of view,
689 * it can still be considered visible.
690 */
691 public FlexTreeNode getPrevVisible()
692 {
693 if ( nPrev != null )
694 return nPrev.lastVisible(this);
695 else if ( nParent == null )
696 return null;
697 else
698 return nParent.isTrueRoot() ? null : nParent;
699 }
700
701
702 protected FlexTreeNode lastVisible(FlexTreeNode node)
703 {
704 if(!bExpanded || nLastChild == null)
705 return this;
706 return (nLastChild == node) ? null : nLastChild.lastVisible(node);
707 }
708
709 public FlexTreeNode getLastVisible()
710 {
711 if ( !bExpanded || nLastChild == null )
712 return this;
713 return nLastChild.getLastVisible();
714 }
715
716
717 /**
718 * Return a boolean value indicating whether or not the node has
719 * any child nodes associated with it.
720 */
721 public boolean hasChildren()
722 {
723 return nFirstChild != null;
724 }
725
726
727 /**
728 * Get the level of this node within the tree hierarchy.
729 */
730 public int getLevel()
731 {
732 // If nLevel is -1, then need to calculate it.
733 if ( nLevel == -1 )
734 {
735 FlexTreeNode currentNode = this;
736
737 while ( !currentNode.isTrueRoot() )
738 {
739 nLevel++;
740
741 currentNode = currentNode.getParent();
742
743 // If this occurs, then this node (or one of it's parents) is not properly
744 // attached to the "true" root node of this tree.
745 if ( currentNode == null )
746 break;
747 }
748 }
749
750 return nLevel;
751 }
752
753
754 /**
755 * Return the next sibling node for this node. The
756 * value will be null if there is no next sibling.
757 */
758 public FlexTreeNode getNextSibling()
759 {
760 return nNext;
761 }
762
763
764 /**
765 * Return the previous sibling node for this node. The
766 * value will be null if there is no previous sibling.
767 */
768 public FlexTreeNode getPrevSibling()
769 {
770 return nPrev;
771 }
772
773
774 /**
775 * Return the text label of the this node.
776 */
777 public String getLabel()
778 {
779 return sLabel;
780 }
781
782
783 /**
784 * Set the text label of the this node.
785 * Note: this method does not update tree painting.
786 */
787 public void setLabel ( String sLabel )
788 {
789 this.sLabel = sLabel;
790 }
791
792
793 public void setExpanded ( boolean expanded, boolean bChild )
794 {
795 bExpanded = expanded;
796
797 if ( bChild )
798 {
799 FlexTreeNode next = nFirstChild;
800 while(next != null)
801 {
802 next.setExpanded ( expanded, bChild );
803 next = next.nNext;
804 }
805 }
806 }
807
808
809 /**
810 * Return the expanded state of the node. If true, the node is expanded.
811 * If false the node is not expanded.
812 */
813 public boolean isExpanded()
814 {
815 return bExpanded;
816 }
817
818
819 boolean sortChildren( boolean bRecursive, boolean bCase)
820 {
821 FlexTreeNode oldFirst;
822 FlexTreeNode oldLast;
823 FlexTreeNode current;
824 FlexTreeNode next;
825 boolean didSwitch = true;
826 int result;
827
828 if(nFirstChild == null)
829 return false;
830
831 if(nFirstChild.nPrev != null)
832 return false;
833
834 oldLast = nLastChild;
835
836 while(didSwitch) {
837 while(nFirstChild.nPrev != null)
838 nFirstChild = nFirstChild.nPrev;
839 current = nFirstChild;
840
841 next = current.nNext;
842 didSwitch = false;
843 while(next != null) {
844 if(bCase)
845 result = current.getLabel().compareTo(next.getLabel());
846 else {
847 String one = current.getLabel().toUpperCase();
848 String two = next.getLabel().toUpperCase();
849 result = one.compareTo(two);
850 }
851 if(result > 0) {
852 // switch the nodes
853 switchNodes(current, next);
854 next = current;
855 didSwitch = true;
856 }
857 current = next;
858 next = next.nNext;
859 }
860 }
861
862 // recursively sort the children of this node
863 if(bRecursive) {
864 current = nFirstChild;
865 while(current != null) {
866 current.sortChildren(bRecursive, bCase);
867 current = current.nNext;
868 }
869 }
870
871 // reset the first and last child nodes of this node correctly
872 while(oldLast != null) {
873 nLastChild = oldLast;
874 oldLast = oldLast.nNext;
875 }
876
877 return true;
878 }
879
880
881 void switchNodes(FlexTreeNode one, FlexTreeNode two)
882 {
883 FlexTreeNode tmpNext;
884 FlexTreeNode tmpPrev;
885
886 tmpNext = two.nNext;
887 tmpPrev = one.nPrev;
888
889 two.nNext = one;
890 two.nPrev = tmpPrev;
891 one.nPrev = two;
892 one.nNext = tmpNext;
893
894 // switch the neighbor links
895 if(tmpNext != null)
896 tmpNext.nPrev = one;
897 if(tmpPrev != null)
898 tmpPrev.nNext = two;
899 }
900
901
902 public boolean getRemoved ( )
903 {
904 return bRemoved;
905 }
906
907
908 public void setImages ( Image expanded, Image collapsed )
909 {
910 iExpanded = (expanded == null) ? iDefExp : expanded;
911 iCollapsed = (collapsed == null) ? iDefCol : collapsed;
912 }
913
914
915 public Image getExpandedImage ( )
916 {
917 return iExpanded;
918 }
919
920
921 public Image getCollapsedImage ( )
922 {
923 return iCollapsed;
924 }
925
926
927 public void setDefaultImages ( )
928 {
929 if ( iDefExp == null )
930 iDefExp = (new DefaultTreeImages()).getExpandedImage();
931
932 if ( iDefCol == null )
933 iDefCol = (new DefaultTreeImages()).getCollapsedImage();
934 }
935
936
937 /**
938 * Gets the position of this node in its parent container.
939 */
940 public int getPosition ( )
941 {
942 if ( getParent() == null )
943 return -1;
944
945 int nPos = 0;
946 FlexTreeNode node = getParent().nFirstChild;
947
948 while ( node != this )
949 {
950 node = node.nNext;
951 nPos++;
952 }
953
954 return nPos;
955 }
956
957 /**
958 * Returns all the leaf nodes of this node and all sub nodes.
959 * @return list of the leaf nodes.
960 */
961 public ArrayList getLeafNodes ( )
962 {
963 ArrayList l = new ArrayList();
964 ArrayList c = getChildren();
965
966 // If this is a leaf node, add it...
967 if ( !hasChildren() )
968 l.add ( this );
969
970 for ( int i = 0; i < c.size(); i++ )
971 l.addAll ( ((FlexTreeNode)c.get(i)).getLeafNodes() );
972
973 return l;
974 }
975
976 protected boolean isSelected ( )
977 {
978 return bSelected;
979 }
980
981 protected void setSelected ( boolean b )
982 {
983 bSelected = b;
984 }
985 }