001: /*
002: * Stingray Software Objective Blend
003: * Copyright (C) 1996 Stingray Software, Inc.
004: * All Rights Reserved
005: *
006: * This source code is only intended as a supplement to
007: * the Stingray Objective Blend product. See the Objective
008: * Blend html help documentation for detailed information regarding
009: * using OB classes.
010: *
011: * Author : Kerry Smith
012: * Description : TreeNodeX.java - tree control node data structure
013: *
014: * CHANGELOG:
015: * 7/09/96 LFW Created
016: * 3/12/97 JDK1.1
017: *
018: */
019:
020: /**
021: * This class describes an individual node in the tree which can contain
022: * other children nodes. The ob.tree.Node class further extends the TreeNodeX
023: * class to provide further methods to customize the nodes.
024: * @see ob.tree.TreeBase
025: * @see ob.tree.Node
026: * @see ob.listbox.ListBox
027: */package ob.tree;
028:
029: import java.io.Serializable;
030: import com.sun.portal.log.common.PortalLogger;
031:
032: /**
033: * The TreeNode class is the lowest level class used to manipulate a tree node.
034: */
035: public class TreeNode implements Serializable {
036: protected TreeNode m_pParent = null;
037: protected TreeNode m_pNextSibling = null;
038: protected TreeNode m_pPrevSibling = null;
039: protected TreeNode m_pFirstChild = null;
040: public static final int TREENODE_FIRST = 0;
041: public static final int TREENODE_LAST = 1;
042: public static final int TREENODE_SORT = 2;
043:
044: /**
045: * currently not implemented
046: */
047: public void deleteChildren() {
048:
049: }
050:
051: /**
052: * retrieves the parent node
053: * @return parent as type TreeNode
054: */
055: public TreeNode getParent() {
056: return m_pParent;
057: }
058:
059: /**
060: * determines whether the node contains children nodes
061: * @return true if children exist, otherwise false
062: */
063: public boolean isParent(TreeNode parent) {
064: if (m_pParent == parent)
065: return true;
066: return false;
067: }
068:
069: /**
070: * retrieves the next sibling
071: * @return next sibling as type TreeNode
072: */
073: public TreeNode getNextSibling() {
074: return m_pNextSibling;
075: }
076:
077: /**
078: * retrieves the previous sibling
079: * @param previous sibling as type TreeNode
080: */
081: public TreeNode getPrevSibling() {
082: return m_pPrevSibling;
083: }
084:
085: /**
086: * retrieves the first child node
087: * @param first child node as type TreeNode
088: */
089: public TreeNode getFirstChild() {
090: return m_pFirstChild;
091: }
092:
093: /**
094: * retrieves the last child node
095: * @return last child node as type TreeNode
096: */
097: public TreeNode getLastChild() {
098: TreeNode pNode;
099: pNode = getFirstChild();
100: if (pNode == null)
101: return null;
102: return pNode.getLastSibling();
103: }
104:
105: /**
106: * retrieves the first sibling node
107: * @return first sibling as type TreeNode
108: */
109: public TreeNode getFirstSibling() {
110: TreeNode pNode;
111: pNode = this ;
112:
113: while (true) {
114: if (pNode.getPrevSibling() == null)
115: return pNode;
116: pNode = pNode.getPrevSibling();
117: }
118:
119: }
120:
121: /**
122: * retrieves the last sibling as type TreeNode
123: * @return last sibling as type TreeNode
124: */
125: public TreeNode getLastSibling() {
126: TreeNode pNode = this ;
127: while (pNode.getNextSibling() != null)
128: pNode = pNode.getNextSibling();
129:
130: return pNode;
131: }
132:
133: /**
134: * retrieves the bottom left child
135: * @return bottom left child as type TreeNode
136: */
137: public TreeNode getBottomLeftChild() {
138: TreeNode pNode = m_pFirstChild;
139: if (pNode != null) {
140: while (pNode.getFirstChild() != null)
141: pNode = pNode.getFirstChild();
142: }
143:
144: return pNode;
145: }
146:
147: /**
148: * retrieves the bottom right child
149: * @return bottom right child as type TreeNode
150: */
151: public TreeNode getBottomRightChild() {
152: TreeNode pNode = getLastChild();
153: if (pNode != null)
154: return pNode.getBottomRightChild();
155: else
156: return this ;
157: }
158:
159: /**
160: * retrieves the root node
161: * @return root as type TreeNode
162: */
163: public TreeNode getRoot() {
164: TreeNode pNode;
165:
166: for (pNode = this ; pNode.m_pParent != null; pNode = pNode.m_pParent)
167: ;
168: return pNode;
169: }
170:
171: /**
172: * retrieves next node in the display
173: * @return next in display as type TreeNode
174: */
175:
176: public TreeNode getNextInDisplayOrder() {
177: if (getFirstChild() != null)
178: return getFirstChild();
179: if (getNextSibling() != null)
180: return getNextSibling();
181:
182: TreeNode pNodeAncestor = this ;
183: while (pNodeAncestor.getParent() != null) {
184: pNodeAncestor = pNodeAncestor.getParent();
185: if (pNodeAncestor.getNextSibling() != null)
186: return pNodeAncestor.getNextSibling();
187: }
188:
189: return null;
190: }
191:
192: /**
193: * retrieves the previous node in the display
194: * @return previous node as type TreeNode
195: */
196: public TreeNode getPrevInDisplayOrder() {
197: if (getPrevSibling() != null) {
198: TreeNode pBRC = getPrevSibling().getBottomRightChild();
199: if (pBRC != null)
200: return pBRC;
201: return getPrevSibling();
202: }
203:
204: return getParent();
205: }
206:
207: // the search is ordered in a specific matnner
208: // in order of bottom left most branch
209: /**
210: * search for the id
211: * @param idSearch id to search for
212: * @return item as type TreeNode
213: */
214: public TreeNode search(int idSearch) {
215: TreeNode pNode;
216: boolean bFound;
217:
218: pNode = getBottomLeftChild();
219:
220: while (pNode != null) {
221: bFound = onNextSearchNode(idSearch, pNode);
222: if (bFound)
223: return pNode;
224:
225: if (pNode.getNextSibling() != null)
226: pNode = pNode.getNextSibling();
227: else if (pNode.getParent() != null
228: && pNode.getParent() != this )
229: pNode = pNode.getParent();
230: else
231: break;
232: }
233:
234: return null;
235: }
236:
237: // a search function for subclass to override
238: /**
239: * overridable function for searching
240: * @param idSearch id to search for
241: * @param pNode node to start search from
242: * @return true if found
243: */
244: public boolean onNextSearchNode(int idSearch, TreeNode pNode) {
245: return false;
246: }
247:
248: /**
249: * sets parent to node
250: * @param n parent node to set
251: */
252: public void setParent(TreeNode n) {
253: m_pParent = n;
254: }
255:
256: /**
257: * sets next sibling
258: * @param n next sibling
259: */
260: public void setNextSibling(TreeNode n) {
261: m_pNextSibling = n;
262: }
263:
264: /**
265: * sets previous sibling
266: * @param n previous sibling
267: */
268: public void setPrevSibling(TreeNode n) {
269: m_pPrevSibling = n;
270: }
271:
272: /**
273: * sets first child
274: * @param n first child
275: */
276: public void setFirstChild(TreeNode n) {
277: m_pFirstChild = n;
278: }
279:
280: /**
281: * adds a child
282: * @param pNewTreeNode adds a new child
283: */
284: public boolean addChild(TreeNode pNewTreeNode) {
285: return addChild(pNewTreeNode, null);
286: }
287:
288: /**
289: * add a child
290: * @param pNewTreeNode new tree node to add
291: * @param pInsAfter the node to insert after
292: * @return true if successfully added, otherwise false
293: */
294: public boolean addChild(TreeNode pNewTreeNode, int pInsAfter) {
295: //System.out.println("adding child");
296: if (pInsAfter == TREENODE_SORT) {
297: System.out
298: .println("WARNING: haven't implemented TREENODE_SORT");
299: pInsAfter = TREENODE_LAST;
300: }
301:
302: pNewTreeNode.m_pParent = this ;
303:
304: if (m_pFirstChild == null) { // node does not have any children
305: m_pFirstChild = pNewTreeNode;
306: pNewTreeNode.m_pNextSibling = null;
307: pNewTreeNode.m_pPrevSibling = null;
308: }
309:
310: else { // node does have children
311: //System.out.println("node has kids");
312: TreeNodeX pChild;
313: if (pInsAfter == TREENODE_LAST) {
314: // insert as last child.
315: pChild = (TreeNodeX) m_pFirstChild;
316: while (pChild.m_pNextSibling != null)
317: pChild = (TreeNodeX) pChild.m_pNextSibling;
318:
319: // now pChild is the last child.
320: pChild.m_pNextSibling = pNewTreeNode;
321: pNewTreeNode.m_pPrevSibling = pChild;
322: pNewTreeNode.m_pNextSibling = null;
323: } else if (pInsAfter == TREENODE_FIRST) {
324: // insert as first child
325: pNewTreeNode.m_pPrevSibling = null;
326: pNewTreeNode.m_pNextSibling = m_pFirstChild;
327: m_pFirstChild.m_pPrevSibling = pNewTreeNode;
328: m_pFirstChild = pNewTreeNode;
329: }
330: //else {
331: //insert after a specified sibling
332: // boolean bFound = false;
333: // for (pChild = m_pFirstChild; pChild!= null; pChild = pChild.m_pNextSibling) {
334: // if (pChild == pInsAfter) {
335: // bFound = true;
336: // break;
337: // }
338: // }
339: //if (!bFound)
340: // return false;
341:
342: //put in pNewTreeNode
343: // pNewTreeNode.m_pNextSibling = pInsAfter.m_pNextSibling;
344: // pNewTreeNode.m_pPrevSibling = pInsAfter;
345: //make a hole to file pNewTreeNode into
346: // if (pInsAfter.m_pNextSibling != null)
347: // pInsAfter.m_pNextSibling.m_pPrevSibling = pNewTreeNode;
348: // pInsAfter.m_pNextSibling = pNewTreeNode;
349: //}
350:
351: }
352: return true;
353:
354: }
355:
356: /**
357: * adds a child to the tree
358: * @param pNewTreeNode new item to add
359: * @param pInsAfter adds after this item
360: * @return true if successfully added, otherwise false
361: */
362: public boolean addChild(TreeNode pNewTreeNode, TreeNode pInsAfter) {
363:
364: //if (pInsAfter == TREENODE_SORT) {
365: // System.out.println("WARNING: haven't implemented TREENODE_SORT");
366: // pInsAfter = TREENODE_LAST;
367: //}
368: if (pInsAfter == null) {
369: return addChild(pNewTreeNode, TREENODE_LAST);
370: }
371: pNewTreeNode.m_pParent = this ;
372:
373: if (m_pFirstChild == null) { // node does not have any children
374: m_pFirstChild = pNewTreeNode;
375: pNewTreeNode.m_pNextSibling = null;
376: pNewTreeNode.m_pPrevSibling = null;
377: }
378:
379: else { // node does have children
380: TreeNodeX pChild;
381: boolean bFound = false;
382: for (pChild = (TreeNodeX) m_pFirstChild; pChild != null; pChild = (TreeNodeX) pChild.m_pNextSibling) {
383: if (pChild == pInsAfter) {
384: bFound = true;
385: break;
386: }
387: }
388:
389: if (!bFound)
390: return false;
391:
392: //put in pNewTreeNode
393: pNewTreeNode.m_pNextSibling = pInsAfter.m_pNextSibling;
394: pNewTreeNode.m_pPrevSibling = pInsAfter;
395: //make a hole to file pNewTreeNode into
396: if (pInsAfter.m_pNextSibling != null)
397: pInsAfter.m_pNextSibling.m_pPrevSibling = pNewTreeNode;
398: pInsAfter.m_pNextSibling = pNewTreeNode;
399: //}
400:
401: }
402: return true;
403: }
404:
405: /**
406: * detaches from the tree
407: */
408: public void detachFromTree() {
409: if (m_pNextSibling != null)
410: m_pNextSibling.m_pPrevSibling = m_pPrevSibling;
411: if (m_pPrevSibling != null)
412: m_pPrevSibling.m_pNextSibling = m_pNextSibling;
413: if (m_pParent.m_pFirstChild == this )
414: m_pParent.m_pFirstChild = m_pNextSibling;
415: m_pParent = null;
416:
417: }
418:
419: /**
420: * detaches all this nodes children from the tree
421: */
422: public void deleteAllChildren() {
423: TreeNode pChild;
424: while ((pChild = getFirstChild()) != null) {
425: pChild.detachFromTree();
426: }
427: }
428:
429: /**
430: * determines if node has children
431: * @return true if children exist, otherwise false
432: */
433: public boolean hasChildren() {
434: return (m_pFirstChild != null);
435: }
436:
437: /**
438: * determines whether this node is a descendent of the node passed in
439: * @param pNode the node to check if it is a descendant
440: * @return true if descendant, otherwise false
441: */
442: public boolean isDescendant(TreeNode pNode) {
443: if (pNode == null)
444: return false;
445: while (pNode.getParent() != null) {
446: pNode = pNode.getParent();
447: if (pNode == this )
448: return true;
449: }
450: return false;
451:
452: }
453:
454: /**
455: * determines whether this node is an ancestor of the node passed in
456: * @param possibleAncestor TreeNode to check against
457: * @return true if it is an ancestor, otherwise false
458: */
459: public boolean isAncestor(TreeNode possibleAncestor) {
460: TreeNode pNode = this ;
461: for (pNode = getParent(); pNode != null; pNode = pNode
462: .getParent()) {
463: if (pNode == possibleAncestor)
464: return true;
465: }
466:
467: return false;
468: }
469:
470: /**
471: * determines whether the node is a sibling of the TreeNode passed in
472: * @param pNodeTest TreeNode to test whether it is a sibling or not
473: * @return true if it is a sibling, otherwise false
474: */
475: public boolean isSibling(TreeNode pNodeTest) {
476: TreeNode pNode;
477:
478: for (pNode = getFirstSibling(); pNode != null; pNode = pNode
479: .getNextSibling()) {
480: if (pNodeTest == pNode)
481: return true;
482: }
483:
484: return false;
485:
486: }
487:
488: /**
489: * determines how many levels down the node is from the root
490: * @return distance from root as type int
491: */
492: public int getDistanceFromRoot() {
493: int w;
494: TreeNode pNode = getParent();
495:
496: for (w = 0; pNode != null; w++)
497: pNode = pNode.getParent();
498:
499: return w;
500: }
501:
502: /**
503: * virtual method to determine if node is expanded or not
504: */
505: public boolean isExpanded() {
506: return false;
507: }
508:
509: /**
510: * virtual method to determine if node is expanded or not
511: * @param bExpand true if you wish to expand, false to collapse
512: */
513: public void expand(boolean bExpand) {
514: }
515:
516: /**
517: * expand the node
518: */
519: public void expand() {
520: expand(true);
521: }
522:
523: /**
524: * collapse the node
525: */
526: public void collapse() {
527: //System.out.println("IN collapse :.......... Bina");
528: expand(false);
529: }
530:
531: // iterate and count all descendent nodes below this one
532: /**
533: * how many total descendents fall under this node
534: * @return number of descendents
535: */
536: public int getNumDescendents() {
537: int iCount = 0;
538:
539: for (TreeNode pNode = getFirstChild(); pNode != null; pNode = pNode
540: .getNextInDisplayOrder()) // bug?? getnextindisplayorder??
541: {
542: iCount++;
543: }
544:
545: return iCount;
546: }
547:
548: }
|