1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53:
54:
55:
61: public class DefaultMutableTreeNode
62: implements Cloneable, MutableTreeNode, Serializable
63: {
64: private static final long serialVersionUID = -4298474751201349152L;
65:
66:
70: public static final Enumeration<TreeNode> EMPTY_ENUMERATION =
71: new EmptyEnumeration<TreeNode>();
72:
73:
76: protected MutableTreeNode parent;
77:
78:
81: protected Vector<MutableTreeNode> children = new Vector<MutableTreeNode>();
82:
83:
86: protected transient Object userObject;
87:
88:
91: protected boolean allowsChildren;
92:
93:
97: public DefaultMutableTreeNode()
98: {
99: this(null, true);
100: }
101:
102:
109: public DefaultMutableTreeNode(Object userObject)
110: {
111: this(userObject, true);
112: }
113:
114:
122: public DefaultMutableTreeNode(Object userObject, boolean allowsChildren)
123: {
124: this.userObject = userObject;
125: this.allowsChildren = allowsChildren;
126: }
127:
128:
134: public Object clone()
135: {
136: return new DefaultMutableTreeNode(this.userObject, this.allowsChildren);
137: }
138:
139:
146: public String toString()
147: {
148: if (userObject == null)
149: return null;
150:
151: return userObject.toString();
152: }
153:
154:
169: public void add(MutableTreeNode child)
170: {
171: if (! allowsChildren)
172: throw new IllegalStateException();
173:
174: if (child == null)
175: throw new IllegalArgumentException();
176:
177: if (isNodeAncestor(child))
178: throw new IllegalArgumentException("Cannot add ancestor node.");
179:
180: children.add(child);
181: child.setParent(this);
182: }
183:
184:
189: public TreeNode getParent()
190: {
191: return parent;
192: }
193:
194:
203: public void remove(int index)
204: {
205: MutableTreeNode child = children.remove(index);
206: child.setParent(null);
207: }
208:
209:
219: public void remove(MutableTreeNode node)
220: {
221: if (node == null)
222: throw new IllegalArgumentException("Null 'node' argument.");
223: if (node.getParent() != this)
224: throw new IllegalArgumentException(
225: "The given 'node' is not a child of this node.");
226: children.remove(node);
227: node.setParent(null);
228: }
229:
230:
237: private void writeObject(ObjectOutputStream stream)
238: throws IOException
239: {
240:
241: }
242:
243:
251: private void readObject(ObjectInputStream stream)
252: throws IOException, ClassNotFoundException
253: {
254:
255: }
256:
257:
266: public void insert(MutableTreeNode node, int index)
267: {
268: if (! allowsChildren)
269: throw new IllegalStateException();
270:
271: if (node == null)
272: throw new IllegalArgumentException("Null 'node' argument.");
273:
274: if (isNodeAncestor(node))
275: throw new IllegalArgumentException("Cannot insert ancestor node.");
276:
277: children.insertElementAt(node, index);
278: }
279:
280:
285: public TreeNode[] getPath()
286: {
287: return getPathToRoot(this, 0);
288: }
289:
290:
296: @SuppressWarnings("rawtypes")
297: public Enumeration children()
298: {
299: if (children.size() == 0)
300: return EMPTY_ENUMERATION;
301:
302: return children.elements();
303: }
304:
305:
310: public void setParent(MutableTreeNode node)
311: {
312: parent = node;
313: }
314:
315:
322: public TreeNode getChildAt(int index)
323: {
324: return children.elementAt(index);
325: }
326:
327:
332: public int getChildCount()
333: {
334: return children.size();
335: }
336:
337:
347: public int getIndex(TreeNode node)
348: {
349: if (node == null)
350: throw new IllegalArgumentException("Null 'node' argument.");
351: return children.indexOf(node);
352: }
353:
354:
361: public void setAllowsChildren(boolean allowsChildren)
362: {
363: if (!allowsChildren)
364: removeAllChildren();
365: this.allowsChildren = allowsChildren;
366: }
367:
368:
373: public boolean getAllowsChildren()
374: {
375: return allowsChildren;
376: }
377:
378:
383: public void setUserObject(Object userObject)
384: {
385: this.userObject = userObject;
386: }
387:
388:
394: public Object getUserObject()
395: {
396: return userObject;
397: }
398:
399:
402: public void removeFromParent()
403: {
404: parent.remove(this);
405: parent = null;
406: }
407:
408:
411: public void removeAllChildren()
412: {
413: for (int i = getChildCount() - 1; i >= 0; i--)
414: remove(i);
415: }
416:
417:
432: public boolean isNodeAncestor(TreeNode node)
433: {
434: if (node == null)
435: return false;
436:
437: TreeNode current = this;
438:
439: while (current != null && current != node)
440: current = current.getParent();
441:
442: return current == node;
443: }
444:
445:
460: public boolean isNodeDescendant(DefaultMutableTreeNode node)
461: {
462: if (node == null)
463: return false;
464:
465: TreeNode current = node;
466:
467: while (current != null
468: && current != this)
469: current = current.getParent();
470:
471: return current == this;
472: }
473:
474:
481: public TreeNode getSharedAncestor(DefaultMutableTreeNode node)
482: {
483: TreeNode current = this;
484: ArrayList<TreeNode> list = new ArrayList<TreeNode>();
485:
486: while (current != null)
487: {
488: list.add(current);
489: current = current.getParent();
490: }
491:
492: current = node;
493:
494: while (current != null)
495: {
496: if (list.contains(current))
497: return current;
498:
499: current = current.getParent();
500: }
501:
502: return null;
503: }
504:
505:
512: public boolean isNodeRelated(DefaultMutableTreeNode node)
513: {
514: if (node == null)
515: return false;
516:
517: return node.getRoot() == getRoot();
518: }
519:
520:
525: public int getDepth()
526: {
527: if ((! allowsChildren)
528: || children.size() == 0)
529: return 0;
530:
531: Stack<Integer> stack = new Stack<Integer>();
532: stack.push(new Integer(0));
533: TreeNode node = getChildAt(0);
534: int depth = 0;
535: int current = 1;
536:
537: while (! stack.empty())
538: {
539: if (node.getChildCount() != 0)
540: {
541: node = node.getChildAt(0);
542: stack.push(new Integer(0));
543: current++;
544: }
545: else
546: {
547: if (current > depth)
548: depth = current;
549:
550: int size;
551: int index;
552:
553: do
554: {
555: node = node.getParent();
556: size = node.getChildCount();
557: index = stack.pop().intValue() + 1;
558: current--;
559: }
560: while (index >= size
561: && node != this);
562:
563: if (index < size)
564: {
565: node = node.getChildAt(index);
566: stack.push(new Integer(index));
567: current++;
568: }
569: }
570: }
571:
572: return depth;
573: }
574:
575:
580: public int getLevel()
581: {
582: int count = -1;
583: TreeNode current = this;
584:
585: do
586: {
587: current = current.getParent();
588: count++;
589: }
590: while (current != null);
591:
592: return count;
593: }
594:
595:
603: protected TreeNode[] getPathToRoot(TreeNode node, int depth)
604: {
605: if (node == null)
606: {
607: if (depth == 0)
608: return null;
609:
610: return new TreeNode[depth];
611: }
612:
613: TreeNode[] path = getPathToRoot(node.getParent(), depth + 1);
614: path[path.length - depth - 1] = node;
615: return path;
616: }
617:
618:
623: public Object[] getUserObjectPath()
624: {
625: TreeNode[] path = getPathToRoot(this, 0);
626: Object[] object = new Object[path.length];
627:
628: for (int index = 0; index < path.length; ++index)
629: object[index] = ((DefaultMutableTreeNode) path[index]).getUserObject();
630:
631: return object;
632: }
633:
634:
639: public TreeNode getRoot()
640: {
641: TreeNode current = this;
642: TreeNode check = current.getParent();
643:
644: while (check != null)
645: {
646: current = check;
647: check = current.getParent();
648: }
649:
650: return current;
651: }
652:
653:
659: public boolean isRoot()
660: {
661: return parent == null;
662: }
663:
664:
669: public DefaultMutableTreeNode getNextNode()
670: {
671:
672: if (getChildCount() != 0)
673: return (DefaultMutableTreeNode) getChildAt(0);
674:
675:
676: DefaultMutableTreeNode node = this;
677: DefaultMutableTreeNode sibling;
678:
679: do
680: {
681: sibling = node.getNextSibling();
682: node = (DefaultMutableTreeNode) node.getParent();
683: }
684: while (sibling == null &&
685: node != null);
686:
687:
688: return sibling;
689: }
690:
691:
696: public DefaultMutableTreeNode getPreviousNode()
697: {
698:
699: if (parent == null)
700: return null;
701:
702: DefaultMutableTreeNode sibling = getPreviousSibling();
703:
704:
705: if (sibling == null)
706: return (DefaultMutableTreeNode) parent;
707:
708:
709: if (sibling.getChildCount() != 0)
710: return sibling.getLastLeaf();
711:
712:
713: return sibling;
714: }
715:
716:
721: @SuppressWarnings("rawtypes")
722: public Enumeration preorderEnumeration()
723: {
724: return new PreorderEnumeration(this);
725: }
726:
727:
732: @SuppressWarnings("rawtypes")
733: public Enumeration postorderEnumeration()
734: {
735: return new PostorderEnumeration(this);
736: }
737:
738:
743: @SuppressWarnings("rawtypes")
744: public Enumeration breadthFirstEnumeration()
745: {
746: return new BreadthFirstEnumeration(this);
747: }
748:
749:
754: @SuppressWarnings("rawtypes")
755: public Enumeration depthFirstEnumeration()
756: {
757: return postorderEnumeration();
758: }
759:
760:
767: @SuppressWarnings("rawtypes")
768: public Enumeration pathFromAncestorEnumeration(TreeNode node)
769: {
770: if (node == null)
771: throw new IllegalArgumentException();
772:
773: TreeNode parent = this;
774: Vector<TreeNode> nodes = new Vector<TreeNode>();
775: nodes.add(this);
776:
777: while (parent != node && parent != null)
778: {
779: parent = parent.getParent();
780: nodes.add(0, parent);
781: }
782:
783: if (parent != node)
784: throw new IllegalArgumentException();
785:
786: return nodes.elements();
787: }
788:
789:
798: public boolean isNodeChild(TreeNode node)
799: {
800: if (node == null)
801: return false;
802:
803: return node.getParent() == this;
804: }
805:
806:
813: public TreeNode getFirstChild()
814: {
815: return children.firstElement();
816: }
817:
818:
825: public TreeNode getLastChild()
826: {
827: return children.lastElement();
828: }
829:
830:
842: public TreeNode getChildAfter(TreeNode node)
843: {
844: if (node == null || node.getParent() != this)
845: throw new IllegalArgumentException();
846:
847: int index = getIndex(node) + 1;
848:
849: if (index == getChildCount())
850: return null;
851:
852: return getChildAt(index);
853: }
854:
855:
867: public TreeNode getChildBefore(TreeNode node)
868: {
869: if (node == null || node.getParent() != this)
870: throw new IllegalArgumentException();
871:
872: int index = getIndex(node) - 1;
873:
874: if (index < 0)
875: return null;
876:
877: return getChildAt(index);
878: }
879:
880:
890: public boolean isNodeSibling(TreeNode node)
891: {
892: if (node == null)
893: return false;
894: if (node == this)
895: return true;
896: return node.getParent() == getParent() && getParent() != null;
897: }
898:
899:
906: public int getSiblingCount()
907: {
908: if (parent == null)
909: return 1;
910:
911: return parent.getChildCount();
912: }
913:
914:
921: public DefaultMutableTreeNode getNextSibling()
922: {
923: if (parent == null)
924: return null;
925:
926: int index = parent.getIndex(this) + 1;
927:
928: if (index == parent.getChildCount())
929: return null;
930:
931: return (DefaultMutableTreeNode) parent.getChildAt(index);
932: }
933:
934:
941: public DefaultMutableTreeNode getPreviousSibling()
942: {
943: if (parent == null)
944: return null;
945:
946: int index = parent.getIndex(this) - 1;
947:
948: if (index < 0)
949: return null;
950:
951: return (DefaultMutableTreeNode) parent.getChildAt(index);
952: }
953:
954:
960: public boolean isLeaf()
961: {
962: return children.size() == 0;
963: }
964:
965:
972: public DefaultMutableTreeNode getFirstLeaf()
973: {
974: TreeNode current = this;
975:
976: while (current.getChildCount() > 0)
977: current = current.getChildAt(0);
978:
979: return (DefaultMutableTreeNode) current;
980: }
981:
982:
989: public DefaultMutableTreeNode getLastLeaf()
990: {
991: TreeNode current = this;
992: int size = current.getChildCount();
993:
994: while (size > 0)
995: {
996: current = current.getChildAt(size - 1);
997: size = current.getChildCount();
998: }
999:
1000: return (DefaultMutableTreeNode) current;
1001: }
1002:
1003:
1008: public DefaultMutableTreeNode getNextLeaf()
1009: {
1010:
1011: DefaultMutableTreeNode sibling = getNextSibling();
1012: if (sibling != null)
1013: return sibling.getFirstLeaf();
1014:
1015: if (parent != null)
1016: return ((DefaultMutableTreeNode) parent).getNextLeaf();
1017: return null;
1018: }
1019:
1020:
1025: public DefaultMutableTreeNode getPreviousLeaf()
1026: {
1027:
1028: DefaultMutableTreeNode sibling = getPreviousSibling();
1029: if (sibling != null)
1030: return sibling.getLastLeaf();
1031:
1032: if (parent != null)
1033: return ((DefaultMutableTreeNode) parent).getPreviousLeaf();
1034: return null;
1035: }
1036:
1037:
1042: public int getLeafCount()
1043: {
1044: int count = 0;
1045: Enumeration<?> e = depthFirstEnumeration();
1046:
1047: while (e.hasMoreElements())
1048: {
1049: TreeNode current = (TreeNode) e.nextElement();
1050:
1051: if (current.isLeaf())
1052: count++;
1053: }
1054:
1055: return count;
1056: }
1057:
1058:
1061: static class BreadthFirstEnumeration implements Enumeration<TreeNode>
1062: {
1063:
1064: LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
1065:
1066: BreadthFirstEnumeration(TreeNode node)
1067: {
1068: queue.add(node);
1069: }
1070:
1071: public boolean hasMoreElements()
1072: {
1073: return !queue.isEmpty();
1074: }
1075:
1076: public TreeNode nextElement()
1077: {
1078: if (queue.isEmpty())
1079: throw new NoSuchElementException("No more elements left.");
1080:
1081: TreeNode node = queue.removeFirst();
1082:
1083: @SuppressWarnings("unchecked")
1084: Enumeration<TreeNode> children =
1085: (Enumeration<TreeNode>) node.children();
1086: while (children.hasMoreElements())
1087: queue.add(children.nextElement());
1088:
1089: return node;
1090: }
1091: }
1092:
1093:
1096: static class PreorderEnumeration implements Enumeration<TreeNode>
1097: {
1098: TreeNode next;
1099:
1100: Stack<Enumeration<TreeNode>> childrenEnums =
1101: new Stack<Enumeration<TreeNode>>();
1102:
1103: PreorderEnumeration(TreeNode node)
1104: {
1105: next = node;
1106: @SuppressWarnings("unchecked")
1107: Enumeration<TreeNode> children =
1108: (Enumeration<TreeNode>) node.children();
1109: childrenEnums.push(children);
1110: }
1111:
1112: public boolean hasMoreElements()
1113: {
1114: return next != null;
1115: }
1116:
1117: public TreeNode nextElement()
1118: {
1119: if (next == null)
1120: throw new NoSuchElementException("No more elements left.");
1121:
1122: TreeNode current = next;
1123:
1124: Enumeration<TreeNode> children = childrenEnums.peek();
1125:
1126:
1127: next = traverse(children);
1128:
1129: return current;
1130: }
1131:
1132: private TreeNode traverse(Enumeration<TreeNode> children)
1133: {
1134:
1135: if (children.hasMoreElements())
1136: {
1137: TreeNode child = children.nextElement();
1138: @SuppressWarnings("unchecked")
1139: Enumeration<TreeNode> grandchildren =
1140: (Enumeration<TreeNode>) child.children();
1141: childrenEnums.push(grandchildren);
1142:
1143: return child;
1144: }
1145:
1146:
1147: childrenEnums.pop();
1148:
1149:
1150:
1151: if (childrenEnums.isEmpty())
1152: return null;
1153: else
1154: {
1155: return traverse(childrenEnums.peek());
1156: }
1157: }
1158: }
1159:
1160:
1163: static class PostorderEnumeration implements Enumeration<TreeNode>
1164: {
1165:
1166: Stack<TreeNode> nodes = new Stack<TreeNode>();
1167: Stack<Enumeration<TreeNode>> childrenEnums =
1168: new Stack<Enumeration<TreeNode>>();
1169:
1170: PostorderEnumeration(TreeNode node)
1171: {
1172: nodes.push(node);
1173: @SuppressWarnings("unchecked")
1174: Enumeration<TreeNode> children =
1175: (Enumeration<TreeNode>) node.children();
1176: childrenEnums.push(children);
1177: }
1178:
1179: public boolean hasMoreElements()
1180: {
1181: return !nodes.isEmpty();
1182: }
1183:
1184: public TreeNode nextElement()
1185: {
1186: if (nodes.isEmpty())
1187: throw new NoSuchElementException("No more elements left!");
1188:
1189: Enumeration<TreeNode> children = childrenEnums.peek();
1190:
1191: return traverse(children);
1192: }
1193:
1194: private TreeNode traverse(Enumeration<TreeNode> children)
1195: {
1196: if (children.hasMoreElements())
1197: {
1198: TreeNode node = children.nextElement();
1199: nodes.push(node);
1200:
1201: @SuppressWarnings("unchecked")
1202: Enumeration<TreeNode> newChildren =
1203: (Enumeration<TreeNode>) node.children();
1204: childrenEnums.push(newChildren);
1205:
1206: return traverse(newChildren);
1207: }
1208: else
1209: {
1210: childrenEnums.pop();
1211:
1212:
1213:
1214: TreeNode next = nodes.peek();
1215: nodes.pop();
1216:
1217: return next;
1218: }
1219: }
1220:
1221: }
1222:
1223: }