0001: /*
0002: * Stingray Software Objective Blend
0003: * Copyright (C) 1997 Stingray Software, Inc.
0004: * All Rights Reserved
0005: *
0006: * This source code is only intended as a supplement to
0007: * the Stingray Objective Blend product. See the Objective
0008: * Blend html help documentation for detailed information regarding
0009: * using OB classes.
0010: *
0011: * Author : Kerry Smith
0012: * Description : ListBox.java - list box
0013: *
0014: * CHANGELOG:
0015: * 7/09/96 LFW Created
0016: * 3/12/97 JDK1.1
0017: *
0018: */
0019:
0020: package ob.tree;
0021:
0022: import java.awt.*;
0023: import com.sun.portal.log.common.PortalLogger;
0024: import java.awt.event.*;
0025: import java.util.Vector;
0026: import java.io.Serializable;
0027: import java.awt.image.*;
0028: import ob.obbase.*;
0029: import ob.listbox.*;
0030: import ob.text.*;
0031:
0032: /**
0033: * The TreeBase extends the ListBox control and provides additional functionality
0034: * and support for a tree hierarchy in the control. Since the TreeBase derives from
0035: * the ListBox control, it uses the same architecture for storing images and referencing
0036: * them by integer values rather than duplicating storage for images in every single node
0037: * of the tree. You can view the reference for ListBox to determine how to initialize
0038: * the image reference list, and use integer IDs to refer to the images when you need
0039: * to associate tree items with images.
0040: * @see ob.listbox.ListBox
0041: * @see ob.tree.Node
0042: * @see ob.tree.TreeNodeX
0043: */
0044: public class TreeBase extends ob.listbox.ListBox implements
0045: Serializable {
0046:
0047: /**
0048: * user defined event ILLEGAL for illegal action
0049: */
0050: public static final int ILLEGAL = 3000; // User defined Event ID.
0051:
0052: /**
0053: * user defined event OPENFOLDER for open folder action
0054: */
0055: public static final int OPENFOLDER = 3002; // User defined Event ID.
0056: /**
0057: * user defined event SELECTION_CHANGE for selection change action
0058: */
0059: public static final int SELECTION_CHANGE = 3003; // User defined Event ID.
0060:
0061: /**
0062: * action event generated when an item is collapsed
0063: */
0064: public static final int ITEM_COLLAPSED = 3004;
0065:
0066: /**
0067: * action event generated when an item is expanded
0068: */
0069: public static final int ITEM_EXPANDED = 3005;
0070:
0071: /**
0072: * action generated when an item is double clicked
0073: */
0074: public static final int DOUBLE_CLICK = 3006;
0075:
0076: /**
0077: * action command used for a drag and drop event
0078: */
0079: public static final String commandDragDrop = "Drag_Drop";
0080:
0081: /**
0082: * action command used for an open folder event
0083: */
0084: public static final String commandOpenFolder = "Open_Folder";
0085:
0086: /**
0087: * action command used for a selection change
0088: */
0089: public static final String commandSelectionChanged = "Selection_Changed";
0090:
0091: /**
0092: * action command used for an illegal action
0093: */
0094: public static final String commandIllegalAction = "Illegal_Action";
0095:
0096: /**
0097: * action command used for an item being collapsed
0098: */
0099: public static final String commandItemCollapsed = "Item_Collapsed";
0100:
0101: /**
0102: * action command used for an item being expanded
0103: */
0104: public static final String commandItemExpanded = "Item_Expanded";
0105:
0106: public static final int TVGN_NEXT = 0;
0107: public static final int TVGN_PREVIOUS = 1;
0108: public static final int TVGN_CHILD = 2;
0109: public static final int TVGN_PARENT = 3;
0110: public static final int TVGN_ROOT = 4;
0111: public static final int TVGN_CARET = 5;
0112: public static final int TVGN_FIRSTVISIBLE = 6;
0113: public static final int TVGN_NEXTVISIBLE = 7;
0114: public static final int TVGN_PREVIOUSVISIBLE = 8;
0115: public static final int TVGN_DROPHILITE = 9;
0116: public static final int TVGN_FIRSTSELECTED = 10;
0117: public static final int TVGN_NEXTSELECTED = 11;
0118: public static final int TVGN_PREVIOUSSELECTED = 12;
0119:
0120: public static final int TVE_COLLAPSE = 0;
0121: public static final int TVE_EXPAND = 1;
0122: public static final int TVE_TOGGLE = 2;
0123:
0124: Node m_itemEventTarget;
0125:
0126: protected Vector m_arrRoots = null;
0127: protected int m_nIndent = 18;
0128: private int m_nButtonSize = 8;
0129: protected boolean m_bHideDisabledItems = false;
0130:
0131: protected boolean m_bHierarchyLines = true;
0132: protected Color m_colHierarchyLines = SystemColor.windowBorder;
0133: protected int m_nStyleHierarchyLines = DOTTED;
0134:
0135: protected boolean m_bLinesAtRoot = true;
0136: protected boolean m_bButton = true;
0137:
0138: protected int m_nWordGap = 4;
0139:
0140: /* Color for text highlighting .... added by Bina
0141: * txtBgHighColor - is the background color of the highlighted text
0142: */
0143:
0144: String txtBgHighColor = "";
0145:
0146: // txtTxtBgColor - is the color of text in the TextComponent object.
0147:
0148: String txtTxtColor = "";
0149:
0150: // txtHiTxtColor - text color of highlighted text.
0151:
0152: String txtHiTxtColor = "";
0153:
0154: /**
0155: * m_itemDropTarget is the TreeItem used for dropping actions
0156: */
0157: Node m_itemDropTarget;
0158:
0159: Node m_nodeCurrentEdit = new Node();
0160:
0161: /**
0162: * default constructor for the tree control
0163: */
0164: public TreeBase() {
0165: super ();
0166: m_nRowSpace = 3;
0167: }
0168:
0169: /**
0170: * constructor for Treebase
0171: * @param bMultipleSelections true if multiple selections allowed, otherwise false
0172: */
0173: public TreeBase(boolean bMultipleSelections) {
0174: super (bMultipleSelections);
0175: m_nRowSpace = 3;
0176: }
0177:
0178: /**
0179: * constructor for Treebase; sets the root text, the root image used for regular nodes
0180: * the image reference for expanded nodes, and an action listener
0181: * @param rootText text used for the root node
0182: * @param imgReg integer reference when a node is in regular, unexpanded state
0183: * @param imgExp integer reference when a node is in expanded state
0184: * @param action actionListener which can be registered for the control
0185: */
0186: public TreeBase(String rootText, int imgReg, int imgExp,
0187: ActionListener action) {
0188: this (false);
0189: initRootNode(rootText, imgReg, imgExp);
0190: actionListener = action;
0191: }
0192:
0193: /**
0194: * determines whether the node is the root or not.
0195: * @param node node you are checking to see if it is the root or not
0196: * @return true if node is root, otherwise false
0197: * @see ob.tree.Node
0198: */
0199: public boolean isRoot(Node node) {
0200: return m_arrRoots.contains(node);
0201: }
0202:
0203: /**
0204: * checks whether the root index is a root item or not
0205: * @param x the root index to check
0206: * @return true if root, otherwise false
0207: */
0208: public boolean isRoot(int x) {
0209: for (int i = 0; i < m_arrRoots.size(); i++) {
0210: if (nodeIndex((Node) m_arrRoots.elementAt(i)) == x)
0211: return true;
0212: }
0213: return false;
0214: }
0215:
0216: /**
0217: * retrieves the root node from the root index passed in
0218: * @param rootIndex the root index you are checking against
0219: * @return the root value as type Node if exists, otherwise null
0220: */
0221: public Node getRoot(int rootIndex) {
0222: if (m_arrRoots.size() > rootIndex)
0223: return (Node) m_arrRoots.elementAt(rootIndex);
0224: return null;
0225: }
0226:
0227: /**
0228: * inserts a new item into the tree control. You need to specify the parent where you
0229: * want to insert the new node. If there are other children where you are inserting, you
0230: * can also specify the node which you want to place the new Node after.
0231: * @param item the Node item to insert
0232: * @param parent the Node parent you are inserting
0233: * @param insertAfter the Node you wish to insert after
0234: * @param imageID reference to the image for the regular mode
0235: * @param imageExpID reference to the iamge for the expanded state
0236: * @return the Node itself if successfully inserted
0237: */
0238: public Node insertItem(Node item, Node parent, Node insertAfter,
0239: int imageID, int imageExpID) {
0240: item.setImage(imageID);
0241: item.setExpandedImage(imageExpID);
0242: return insertItem(item, parent, insertAfter);
0243: }
0244:
0245: /**
0246: * inserts a new item into the tree control. You need to specify the parent where you
0247: * want to insert the new node. If there are other children where you are inserting, you
0248: * can also specify the node which you want to place the new Node after.
0249: * @param item the Node item to insert
0250: * @param parent the Node parent you are inserting
0251: * @param insertAfter the Node you wish to insert after
0252: * @param imageID reference to the image for the regular mode
0253: * @param imageExpID reference to the iamge for the expanded state
0254: * @return the new Node if successfully inserted
0255: * @see ob.tree.Node
0256: */
0257: public Node insertItem(Node item, Node parent, Node insertAfter,
0258: int imageID, int imageExpID, Font nodeFont) {
0259: item.setFont(nodeFont);
0260: return insertItem(item, parent, insertAfter, imageID,
0261: imageExpID);
0262: }
0263:
0264: /**
0265: * inserts a new item into the tree control. You need to specify the parent where you
0266: * want to insert the new node. If there are other children where you are inserting, you
0267: * can also specify the node which you want to place the new Node after.
0268: * @param item the Node item to insert
0269: * @param parent the Node parent you are inserting
0270: * @param insertAfter the Node you wish to insert after
0271: * @return the new Node if successfully inserted
0272: * @see ob.tree.Node
0273: */
0274: public Node insertItem(Node item, Node parent, Node insertAfter) {
0275: if (m_arrRoots == null)
0276: initRootNode();
0277: TreeNodeX pNodeParent, pNodeInsertAfter;
0278: Node pNodeNew;
0279:
0280: // insert into our internal storage of all nodes (visible or not)
0281: // find the parent
0282: pNodeParent = parent;
0283: if (parent == null) {
0284: pNodeParent = (Node) m_arrRoots.elementAt(0);
0285: }
0286: pNodeInsertAfter = insertAfter;
0287:
0288: pNodeNew = new Node();
0289:
0290: pNodeNew = item;
0291:
0292: if (!pNodeParent.addChild(pNodeNew, pNodeInsertAfter))
0293: return null;
0294:
0295: pNodeNew.collapse();
0296: if (shouldBeInListBox(pNodeNew)) {
0297:
0298: addNodeToListBox(pNodeNew);
0299: }
0300:
0301: return pNodeNew;
0302: }
0303:
0304: /**
0305: * creates a new item and inserts it into the tree control. You need to specify the parent where you
0306: * want to insert the new node. If there are other children where you are inserting, you
0307: * can also specify the node which you want to place the new Node after.
0308: * @param strItem the text for the new item to be inserted
0309: * @param parent the Node parent you are inserting
0310: * @param insertAfter the Node you wish to insert after
0311: * @param image reference to the unexpanded image
0312: * @param imageExp reference to the expanded image
0313: * @return the new Node if successfully inserted
0314: * @see ob.tree.Node
0315: */
0316: public Node insertItem(String strItem, Node parent,
0317: Node insertAfter, int image, int imageExp) {
0318: Node pNodeNew = new Node();
0319: pNodeNew.setText(strItem);
0320: return insertItem(pNodeNew, parent, insertAfter, image,
0321: imageExp);
0322: }
0323:
0324: /**
0325: * creates a new item and inserts it into the tree control. You need to specify the parent where you
0326: * want to insert the new node. If there are other children where you are inserting, you
0327: * can also specify the node which you want to place the new Node after.
0328: * @param strItem the text for the new item to be inserted
0329: * @param parent the Node parent you are inserting
0330: * @param insertAfter the Node you wish to insert after
0331: * @param image reference to the unexpanded image
0332: * @param imageExp reference to the expanded image
0333: * @param nodeFont the font to use with the new node
0334: * @return the new Node if successfully inserted
0335: * @see ob.tree.Node
0336: */
0337: public Node insertItem(String strItem, Node parent,
0338: Node insertAfter, int image, int imageExp, Font nodeFont) {
0339: Node pNodeNew = new Node();
0340: pNodeNew.setText(strItem);
0341: return insertItem(pNodeNew, parent, insertAfter, image,
0342: imageExp, nodeFont);
0343: }
0344:
0345: /**
0346: * creates a new item and inserts it into the tree control. You need to specify the parent where you
0347: * want to insert the new node. If there are other children where you are inserting, you
0348: * can also specify the node which you want to place the new Node after.
0349: * @param strItem the text for the new item to be inserted
0350: * @param parent the Node parent you are inserting
0351: * @param insertAfter the Node you wish to insert after
0352: * @return the new Node if successfully inserted
0353: * @see ob.tree.Node
0354: */
0355: public Node insertItem(String strItem, Node parent, Node insertAfter) {
0356: Node pNodeNew = new Node();
0357: pNodeNew.setText(strItem);
0358: return insertItem(pNodeNew, parent, insertAfter);
0359:
0360: }
0361:
0362: /**
0363: * sets the color for the lines drawing the tree hierarchy
0364: * @param c Color to use when drawing hierarchy
0365: */
0366: public void setHierarchyLineColor(Color c) {
0367: m_colHierarchyLines = c;
0368: }
0369:
0370: /**
0371: * sets the style of the hierarchy lines. Default is solid lines for a style
0372: * of 0; you can also set the DOTTED style to draw dotted lines
0373: * @param nStyle style to draw lines in
0374: */
0375: public void setHierarchyLineStyle(int nStyle) {
0376: m_nStyleHierarchyLines = nStyle;
0377: }
0378:
0379: /**
0380: * sets the indentation spacing
0381: * @param indent new indent
0382: * @see TreeBase#getIndent
0383: */
0384: public void setIndent(int indent) {
0385: m_nIndent = indent;
0386: reMeasureAllItems();
0387: update();
0388: }
0389:
0390: /**
0391: * retrieves the Indentation spacing
0392: * @see TreeBase#getIndent
0393: */
0394: public int getIndent() {
0395: return m_nIndent;
0396: }
0397:
0398: /**
0399: * routine used to measure the size of the current item; usually not used
0400: * by a developer
0401: * @return the size of the text in pixels as type int
0402: */
0403: protected int measureText() {
0404: Rectangle rectText = new Rectangle();
0405: rectText.y = 0;
0406: rectText.height = 0;
0407: Font font = ((Node) ((ListItem) m_arrItems
0408: .elementAt(m_lvi_iItem)).getItemData()).getFont();
0409: if (font == null) {
0410: font = defaultfont;
0411: }
0412:
0413: FontMetrics fontMetrics = getFontMetrics(font);
0414:
0415: m_lvi_pszText = ((Node) ((ListItem) m_arrItems
0416: .elementAt(m_lvi_iItem)).getItemData()).getText();
0417:
0418: if (m_bAutoWrap && m_lvi_pszText != null) {
0419: int nIndent = ((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0420: .getTextBounds().x
0421: + m_nWidthGap
0422: + (getInsideRect().width + m_nVScrollbarWidth - getBounds().width);//+getIndent();
0423: Vector wrapLines = Text.wrapText(m_lvi_pszText,
0424: ((Column) m_arrColumns.elementAt(m_lvi_iSubItem))
0425: .getWidth()
0426: - m_nWidthGap * 2 - nIndent, true,
0427: fontMetrics);
0428: rectText.height = wrapLines.size()
0429: * (fontMetrics.getHeight());
0430: } else
0431: rectText.height = fontMetrics.getHeight();
0432:
0433: return rectText.height;
0434:
0435: }
0436:
0437: /**
0438: * overridden subitem measuring; usually not used by a developer
0439: * @param g Graphics object
0440: * @return subitem size in pixels as type int
0441: * @see ob.listbox.ListBox#measureSubItem
0442: */
0443: public int measureSubItem(Graphics g) {
0444: try {
0445: if (m_lvi_iSubItem == 0) {
0446:
0447: String strText;
0448: int leftText;
0449:
0450: // Tree items will be indented according to distance down the tree
0451: int nIndent;
0452: nIndent = getIndent()
0453: * (((Node) ((ListItem) m_arrItems
0454: .elementAt(m_lvi_iItem)).getItemData())
0455: .getDistanceFromRoot() - 1);
0456: nIndent += getIndent();
0457:
0458: if (m_arrImages != null && m_arrImages.size() != 0) {
0459: int imageID = ((Node) (((ListItem) m_arrItems
0460: .elementAt(m_lvi_iItem)).getItemData()))
0461: .getImage();
0462:
0463: Image img = getImageList(imageID);
0464: int nImgHeight = img.getHeight(this );
0465: int nImgWidth = img.getWidth(this );
0466: int ImgSize = nImgWidth;
0467:
0468: ((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0469: .setImageBounds(new Rectangle(nIndent
0470: + m_nWidthGap, 0, nImgWidth,
0471: nImgHeight));
0472: Rectangle rcTemp = ((ListItem) m_arrItems
0473: .elementAt(m_lvi_iItem)).getImageBounds();
0474:
0475: //figure out where text starts
0476: //BINA CHANGES
0477: //leftText = rcTemp.width + nIndent + m_nWidthGap;
0478: //System.out.println("Left Text at 15....");
0479: leftText = rcTemp.width + nIndent + m_nWidthGap
0480: + 18;
0481: ///BINA
0482:
0483: }
0484: /* //// BINA CHANGES
0485: else
0486: //leftText = nIndent+m_nWordGap;
0487: //System.out.println("LeftText at 15");
0488: */
0489: leftText = nIndent + m_nWordGap + 18;
0490: /// BINA
0491: Font font = ((ListItem) m_arrItems
0492: .elementAt(m_lvi_iItem)).getFont();
0493: if (font == null)
0494: font = defaultfont;
0495: FontMetrics fm = getFontMetrics(font);
0496: if (m_bAutoWrap)
0497: ((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0498: .setTextBounds(
0499: leftText,
0500: 0,
0501: Math
0502: .min(
0503: ((Column) m_arrColumns
0504: .elementAt(0))
0505: .getWidth(),
0506: fm
0507: .stringWidth(((Node) ((ListItem) m_arrItems
0508: .elementAt(m_lvi_iItem))
0509: .getItemData())
0510: .getText())
0511: + leftText
0512: + m_nWidthGap),
0513: 0);
0514: else {
0515: ((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0516: .setTextBounds(
0517: leftText,
0518: 0,
0519: fm
0520: .stringWidth(((Node) ((ListItem) m_arrItems
0521: .elementAt(m_lvi_iItem))
0522: .getItemData())
0523: .getText())
0524: + leftText + m_nWidthGap, 0);
0525: }
0526: int textHeight = measureText();
0527: ((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0528: .setTextHeight(textHeight);
0529:
0530: m_recPCRect = new Rectangle((((ListItem) m_arrItems
0531: .elementAt(m_lvi_iItem)).getTextBounds()));
0532: m_recPCRect.height = Math.max(m_recPCRect.height,
0533: ((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0534: .getImageBounds().height);
0535:
0536: return m_recPCRect.height;
0537:
0538: } else
0539: return super .measureSubItem(g);
0540: } catch (Exception ex) {
0541: return 1;
0542: }
0543: }
0544:
0545: /**
0546: * virtual override of the ListBox to draw the subitem. Usually not used
0547: * directly by the developer
0548: * @param g Graphics object
0549: * @see ob.listbox.ListBox#drawSubItem
0550: */
0551: public void drawSubItem(Graphics g) {
0552:
0553: Rectangle bounds = getBounds();
0554:
0555: if (m_lvi_iSubItem == 0) {
0556: int textHeight = measureText();
0557: String strText;
0558: int iImage;
0559: Rectangle rectText;
0560: Rectangle rcIndent;
0561: boolean bSelected;
0562:
0563: bSelected = isSelected(m_lvi_iItem);
0564: Node nodeTemp = (Node) ((ListItem) m_arrItems
0565: .elementAt(m_lvi_iItem)).getItemData();
0566:
0567: strText = nodeTemp.getText();
0568:
0569: if (!nodeTemp.isExpanded()) {
0570: iImage = ((Node) ((ListItem) m_arrItems
0571: .elementAt(m_lvi_iItem)).getItemData())
0572: .getImage();
0573: } else
0574: iImage = ((Node) ((ListItem) m_arrItems
0575: .elementAt(m_lvi_iItem)).getItemData())
0576: .getExpandedImage();
0577: Rectangle rectFill;
0578: g.setColor(getBackground());
0579: rectFill = m_recPCRect;
0580: //compute the text size and position
0581: rectText = ((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0582: .getTextBounds();
0583:
0584: rectText.y = m_recPCRect.y + 2;
0585:
0586: if (m_arrColumns.size() > 1)
0587: rectText.width = Math.min(rectText.width, m_recPCRect.x
0588: + ((Column) m_arrColumns.elementAt(0))
0589: .getWidth() - m_nWidthGap);
0590:
0591: // unless we have an icon, the hierarchy lines end
0592: // where the label begins.
0593:
0594: rcIndent = m_recPCRect;
0595: rcIndent.width = 0;
0596:
0597: if (m_arrImages != null && m_arrImages.size() > 0) {
0598: //Then draw icons/bitmaps/whatever
0599:
0600: if (getImageIndex(iImage) >= m_arrImages.size()) {
0601: System.out.println("Warning: Image " + iImage
0602: + " does not exist!");
0603: iImage = 0;
0604: }
0605:
0606: ListItem pItem = ((ListItem) m_arrItems
0607: .elementAt(m_lvi_iItem));
0608: Point pt = new Point(m_recPCRect.x
0609: + pItem.getImageBounds().x, m_recPCRect.y
0610: + pItem.getImageBounds().y);
0611:
0612: pt.y += 1;
0613:
0614: Image img = getImageList(iImage); //null;
0615: /*if (iImage >= 0 && iImage < m_arrImages.size())
0616: img = (Image)m_arrImages.elementAt(iImage);*/
0617:
0618: if (img != null)
0619: g.drawImage(img, pt.x, pt.y - bounds.y, this );
0620:
0621: rcIndent.width = pt.x;
0622: }
0623:
0624: // Now erase everything to the right of the text string.
0625: // This is necessary because the last string painted here
0626: // may have been longer than the current, so we have to
0627: // erase everything to the right of the current text.
0628: rectFill.x = rectText.x + rectText.width;
0629: rectFill.width = m_recPCRect.width;
0630:
0631: g.fillRect(rectFill.x, rectFill.y - bounds.y,
0632: rectFill.width, rectFill.height);
0633: m_recPCRect.x = rectText.x;//+bounds.x;
0634:
0635: // now we can draw the lines and button since we've erased background
0636:
0637: if (m_bHierarchyLines)
0638: drawHierarchyLines(g);
0639: if (m_bButton)
0640: drawButton(g);
0641:
0642: //compute fillrect
0643: rectFill.x = rectText.x - (m_nWidthGap / 2);
0644: rectFill.width = rectText.width + (m_nWidthGap / 2);
0645: rectFill.y = m_recPCRect.y;
0646: rectFill.height = textHeight * (5 / 4);//m_recPCRect.height + m_recPCRect.height/4;
0647:
0648: g.setFont(((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0649: .getFont());
0650: FontMetrics fm = g.getFontMetrics();
0651:
0652: g.setColor(getBackground());
0653:
0654: //g.setColor(Color.red); // test to see if it works
0655: //g.fillRect(rectFill.x, rectFill.y-bounds.y, rectFill.width, rectFill.height);
0656:
0657: if (strText != null) {
0658: if (m_bAutoWrap) {
0659: String selectText = ((Node) ((ListItem) m_arrItems
0660: .elementAt(m_lvi_iItem)).getItemData())
0661: .getText();
0662:
0663: Font font = ((Node) ((ListItem) m_arrItems
0664: .elementAt(m_lvi_iItem)).getItemData())
0665: .getFont();
0666: if (font == null) {
0667:
0668: font = defaultfont;
0669: }
0670: g.setFont(font);
0671:
0672: fm = getFontMetrics(font);
0673: int nIndent = ((ListItem) m_arrItems
0674: .elementAt(m_lvi_iItem)).getTextBounds().x
0675: + m_nWidthGap;
0676:
0677: Vector nodeText = Text.wrapText(strText,
0678: ((Column) m_arrColumns
0679: .elementAt(m_lvi_iSubItem))
0680: .getWidth()
0681: - m_nWidthGap * 2 - nIndent, true,
0682: fm);
0683:
0684: int selectWidth = fm.stringWidth(selectText);
0685: if (nodeText.size() > 1)
0686: selectWidth = ((Column) m_arrColumns
0687: .elementAt(m_lvi_iSubItem)).getWidth()
0688: - m_nWidthGap * 2 - nIndent;
0689: if (selectWidth > ((Column) m_arrColumns
0690: .elementAt(0)).getWidth()
0691: - (rectText.x - 2 + m_nWidthGap))
0692: selectWidth = rectText.width;
0693:
0694: g.setColor(SystemColor.textText);
0695: //g.setColor(Color.red);
0696:
0697: if (!isSelected(m_lvi_iItem)) {
0698: g.setColor(Color.black);
0699:
0700: } else {
0701:
0702: //g.setColor(SystemColor.textHighlight);
0703: // Changed by bina to set the color instead of
0704: // getting the desktop color
0705: g.setColor(getTreeColor(txtBgHighColor,
0706: Color.black));
0707: ListItem pItem = ((ListItem) m_arrItems
0708: .elementAt(m_lvi_iItem));
0709: int cySubItem = Math.max(textHeight, pItem
0710: .getImageBounds().height);
0711:
0712: if (((ListItem) m_arrItems
0713: .elementAt(m_lvi_iItem))
0714: .getImageBounds().height <= textHeight) {
0715: g.fillRect(rectText.x - 1 + m_nWidthGap
0716: - m_ptViewportOrg.x, rectText.y
0717: - bounds.y - 1, selectWidth + 3,
0718: textHeight + textHeight / 4 - 2);
0719: if (m_bHasFocus)
0720: drawDottedRect(g, rectText.x - 2
0721: + m_nWidthGap
0722: - m_ptViewportOrg.x, rectText.y
0723: - bounds.y - 2,
0724: selectWidth + 4, textHeight
0725: + textHeight / 4 - 1);
0726: } else {
0727: g
0728: .fillRect(
0729: rectText.x + m_nWidthGap
0730: - m_ptViewportOrg.x
0731: + 1,
0732: rectText.y
0733: + ((cySubItem / 2) - textHeight / 2)
0734: - bounds.y - 2,
0735: selectWidth + 3, textHeight
0736: + textHeight / 4
0737: - 2);
0738: if (m_bHasFocus)
0739: drawDottedRect(
0740: g,
0741: rectText.x + m_nWidthGap
0742: - m_ptViewportOrg.x,
0743: rectText.y
0744: + ((cySubItem / 2) - textHeight / 2)
0745: - 1 - bounds.y - 2,
0746: selectWidth + 4, textHeight
0747: + textHeight / 4 - 1);
0748: }
0749:
0750: g.setXORMode(getBackground());
0751: g.setPaintMode();
0752: //g.setColor(SystemColor.textHighlightText);
0753: // Changed by bina to set the color instead of
0754: // getting the desktop color
0755: g.setColor(getTreeColor(txtBgHighColor,
0756: Color.black));
0757:
0758: }
0759:
0760: ListItem pItem = ((ListItem) m_arrItems
0761: .elementAt(m_lvi_iItem));
0762: int cySubItem = Math.max(textHeight, pItem
0763: .getImageBounds().height);
0764: int xPos = 0;
0765: int yPos = 0;
0766: int rowHeight = fm.getHeight();
0767: if (((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0768: .getImageBounds().height <= textHeight) {
0769: xPos = rectText.x + m_nWidthGap
0770: - m_ptViewportOrg.x;
0771: yPos = rectText.y - 2 - bounds.y + rowHeight
0772: - rowHeight / 4;
0773: } else {
0774: xPos = rectText.x + m_nWidthGap
0775: - m_ptViewportOrg.x;
0776: yPos = rectText.y + textHeight
0777: + ((cySubItem / 2) - textHeight / 2)
0778: - 1 - bounds.y - 2;
0779: }
0780:
0781: for (int i = 0; i < nodeText.size(); i++) {
0782: g.drawString((String) nodeText.elementAt(i),
0783: xPos, yPos);
0784: yPos += rowHeight;
0785: yPos += rowHeight / 4;
0786:
0787: }
0788:
0789: } else { // no wordwrap
0790: Font font = ((Node) ((ListItem) m_arrItems
0791: .elementAt(m_lvi_iItem)).getItemData())
0792: .getFont();
0793: if (font == null)
0794: font = defaultfont;
0795: g.setFont(font);
0796: fm = getFontMetrics(font);
0797: if (!isSelected(m_lvi_iItem)) {
0798: //g.setColor(SystemColor.textText);
0799: g.setColor(getTreeColor(txtTxtColor,
0800: Color.black));
0801:
0802: } else {
0803: //g.setColor(SystemColor.textHighlight);
0804: g.setColor(getTreeColor(txtBgHighColor,
0805: Color.black));
0806:
0807: ListItem pItem = ((ListItem) m_arrItems
0808: .elementAt(m_lvi_iItem));
0809: int cySubItem = Math.max(textHeight, pItem
0810: .getImageBounds().height);
0811:
0812: int selectWidth;
0813: if (fm.stringWidth(strText) + m_recPCRect.x
0814: + m_nWidthGap + getIndent() < ((Column) m_arrColumns
0815: .elementAt(0)).getWidth())
0816: selectWidth = fm.stringWidth(strText);
0817: else
0818: selectWidth = Math.min(m_recPCRect.width
0819: + 2 - m_recPCRect.x - getIndent(),
0820: fm.stringWidth(strText));
0821:
0822: if (((ListItem) m_arrItems
0823: .elementAt(m_lvi_iItem))
0824: .getImageBounds().height <= textHeight
0825: && m_arrColumns.size() == 1) {
0826: g.fillRect(rectText.x - 2 + m_nWidthGap
0827: - m_ptViewportOrg.x + 1, rectText.y
0828: - bounds.y - 1, selectWidth + 3,
0829: textHeight + textHeight / 4 - 2);
0830: if (m_bHasFocus)
0831: drawDottedRect(g, rectText.x - 2
0832: + m_nWidthGap
0833: - m_ptViewportOrg.x, rectText.y
0834: - bounds.y - 2,
0835: selectWidth + 4, textHeight
0836: + textHeight / 4 - 1);
0837: } else {
0838: g
0839: .fillRect(
0840: rectText.x + m_nWidthGap
0841: - m_ptViewportOrg.x
0842: - 1,
0843: rectText.y
0844: + ((cySubItem / 2) - textHeight / 2)
0845: - bounds.y - 2,
0846: selectWidth + 3, textHeight
0847: + textHeight / 4
0848: - 2);
0849: if (m_bHasFocus)
0850: drawDottedRect(
0851: g,
0852: rectText.x + m_nWidthGap
0853: - m_ptViewportOrg.x - 2,
0854: rectText.y
0855: + ((cySubItem / 2) - textHeight / 2)
0856: - 1 - bounds.y - 2,
0857: selectWidth + 4, textHeight
0858: + textHeight / 4 - 1);
0859: }
0860:
0861: g.setXORMode(getBackground());
0862: g.setPaintMode();
0863: //g.setColor(SystemColor.textHighlightText);
0864: g.setColor(getTreeColor(txtHiTxtColor,
0865: Color.white));
0866: }
0867:
0868: g.setFont(((Node) ((ListItem) m_arrItems
0869: .elementAt(m_lvi_iItem)).getItemData())
0870: .getFont());
0871: if (g.getFont() == null) {
0872: g.setFont(defaultfont);
0873: }
0874: ListItem pItem = ((ListItem) m_arrItems
0875: .elementAt(m_lvi_iItem));
0876: int cySubItem = Math.max(textHeight, pItem
0877: .getImageBounds().height);
0878:
0879: int xPos = 0;
0880: int yPos = 0;
0881: int rowHeight = fm.getHeight();
0882: if (((ListItem) m_arrItems.elementAt(m_lvi_iItem))
0883: .getImageBounds().height <= textHeight) {
0884: xPos = rectText.x + m_nWidthGap
0885: - m_ptViewportOrg.x;
0886: yPos = rectText.y - 2 - bounds.y + rowHeight
0887: - rowHeight / 4;
0888: } else {
0889: xPos = rectText.x + m_nWidthGap
0890: - m_ptViewportOrg.x;
0891: yPos = rectText.y + textHeight
0892: + ((cySubItem / 2) - textHeight / 2)
0893: - 1 - bounds.y - 2;
0894: }
0895:
0896: if (m_arrColumns.size() > 1) {
0897: int nTotalWidth = fm.stringWidth(strText)
0898: + ((ListItem) m_arrItems
0899: .elementAt(m_lvi_iItem))
0900: .getTextBounds().x;
0901: String str = "";
0902: int nImgWidth = 0;
0903: if (nTotalWidth > m_recPCRect.width
0904: - 2
0905: * m_nWidthGap
0906: - (bounds.width - getInsideRect().width)) {
0907: int nDotWidth = fm.stringWidth(".");
0908: if (nImgWidth + m_nWidthGap + nDotWidth > m_recPCRect.width
0909: - (bounds.width - getInsideRect().width)
0910: || ((ListItem) m_arrItems
0911: .elementAt(m_lvi_iItem))
0912: .getTextBounds().x > m_recPCRect.width
0913: - (bounds.width - getInsideRect().width)) {//-2*m_nOffset) {
0914: nTotalWidth = nImgWidth;
0915: str = " ";
0916: } else if (nImgWidth + m_nWidthGap + 2
0917: * nDotWidth > m_recPCRect.width
0918: - (bounds.width - getInsideRect().width)) {//-2*m_nOffset) {
0919: nTotalWidth = nImgWidth + m_nWidthGap
0920: + nDotWidth;
0921: str = ".";
0922: } else if (nImgWidth + m_nWidthGap + 3
0923: * nDotWidth > m_recPCRect.width
0924: - (bounds.width - getInsideRect().width)) {//-2*m_nOffset) {
0925: nTotalWidth = nImgWidth + m_nWidthGap
0926: + 2 * nDotWidth;
0927: str = "..";
0928: } else {
0929: int j = 0;
0930: for (j = 1; j < strText.length(); j++) {
0931: nTotalWidth = nImgWidth
0932: + 2
0933: * m_nWidthGap
0934: + fm
0935: .stringWidth(strText
0936: .substring(
0937: 0,
0938: j - 1))
0939: + 3
0940: * nDotWidth
0941: + ((ListItem) m_arrItems
0942: .elementAt(m_lvi_iItem))
0943: .getTextBounds().x;
0944: if (nTotalWidth > m_recPCRect.width)
0945: break;
0946: }
0947: if (j - 2 < 0)
0948: j = 2;
0949: str = strText.substring(0, j - 2)
0950: + "...";
0951: nTotalWidth = ((ListItem) m_arrItems
0952: .elementAt(m_lvi_iItem))
0953: .getTextBounds().x
0954: + nImgWidth
0955: + m_nWidthGap
0956: + fm.stringWidth(str);
0957: }
0958: }
0959:
0960: if (fm.stringWidth(strText)
0961: + ((ListItem) m_arrItems
0962: .elementAt(m_lvi_iItem))
0963: .getTextBounds().x > m_recPCRect.width
0964: - 2
0965: * m_nWidthGap
0966: - m_recPCRect.x
0967: + bounds.x)
0968: strText = str;
0969:
0970: }
0971:
0972: int xPos2 = m_recPCRect.x + m_nWidthGap
0973: - m_ptViewportOrg.x + 2;
0974: int yPos2 = m_recPCRect.y
0975: + ((ListItem) m_arrItems
0976: .elementAt(m_lvi_iItem))
0977: .getTextBounds().height
0978: - bounds.y
0979: - /*ELIMINATING m_LIPItem*/((ListItem) m_arrItems
0980: .elementAt(m_lvi_iItem))
0981: .getTextBounds().height / 4;
0982: int sLen = m_nWidthGap
0983: + fm.stringWidth(m_lvi_pszText);
0984: Column tempCol = ((Column) m_arrColumns
0985: .elementAt(m_lvi_iSubItem));
0986:
0987: g.drawString(strText, xPos2, yPos2);
0988: }
0989: }
0990: }
0991:
0992: else
0993: super .drawSubItem(g);
0994:
0995: }
0996:
0997: /**
0998: * draws the target highlight. Usually not used by the developer
0999: * @param g Graphics object
1000: */
1001: public void drawTargetHighLight(Graphics g) {
1002: Rectangle bounds = getBounds();
1003:
1004: g.setColor(SystemColor.textHighlight);
1005: int index = getTarget(m_nXMouse, m_nYMouse);
1006:
1007: if (index != m_nOldTargetIndex) {
1008: if (m_nOldTargetIndex != -1
1009: && !isSelected(m_nOldTargetIndex)) {
1010: m_lvi_iItem = m_nOldTargetIndex;
1011: ListItem tempItem = (ListItem) m_arrItems
1012: .elementAt(m_nOldTargetIndex);
1013:
1014: int selectWidth;
1015: if (((ListItem) m_arrItems.elementAt(m_lvi_iItem))
1016: .getTextBounds().width /*fm.stringWidth(strText)-rcText.x+m_nWidthGap +getIndent()*/< ((Column) m_arrColumns
1017: .elementAt(0)).getWidth()) {
1018: selectWidth = ((ListItem) m_arrItems
1019: .elementAt(m_lvi_iItem)).getTextBounds().width
1020: - ((ListItem) m_arrItems
1021: .elementAt(m_lvi_iItem))
1022: .getTextBounds().x;
1023: } else
1024: selectWidth = Math
1025: .min(
1026: /*rcText.width+2-rcText.x-getIndent()*/((ListItem) m_arrItems
1027: .elementAt(m_lvi_iItem))
1028: .getTextBounds().width
1029: - ((ListItem) m_arrItems
1030: .elementAt(m_lvi_iItem))
1031: .getTextBounds().x,
1032: ((Column) m_arrColumns.elementAt(0))
1033: .getWidth()
1034: - ((ListItem) m_arrItems
1035: .elementAt(m_lvi_iItem))
1036: .getTextBounds().x);
1037: g.fillRect(
1038: tempItem.getTextBounds().x + m_nWidthGap - 2,
1039: tempItem.getTextBounds().y - 2 - bounds.y, /*tempItem.getTextBounds().width-tempItem.getTextBounds().x*/
1040: selectWidth, tempItem.getTextBounds().height
1041: + tempItem.getTextBounds().height / 4);
1042: }
1043:
1044: m_nOldTargetIndex = index;
1045: if (index != -1 && !isSelected(index)) {
1046: m_lvi_iItem = index;
1047: ListItem pItem = (ListItem) m_arrItems.elementAt(index);
1048: g.fillRect(pItem.getTextBounds().x + m_nWidthGap - 2,
1049: pItem.getTextBounds().y - 2 - bounds.y, pItem
1050: .getTextBounds().width
1051: - pItem.getTextBounds().x, pItem
1052: .getTextBounds().height
1053: + pItem.getTextBounds().height / 4);
1054: }
1055: }
1056: }
1057:
1058: /**
1059: * draws the button indicating the node has children. Usually not used by
1060: * developers
1061: * @param g Graphics object
1062: */
1063: protected void drawButton(Graphics g) {
1064: Rectangle rectButton;
1065: rectButton = calcButtonRect();
1066: Node pNode = ((Node) (((ListItem) m_arrItems
1067: .elementAt(m_lvi_iItem)).getItemData()));
1068: if (!pNode.hasChildren())
1069: return;
1070: int w = rectButton.width / 3;
1071: Point pt = new Point(rectButton.width / 2 + rectButton.x,
1072: rectButton.height / 2 + rectButton.y);
1073: g.setColor(getBackground());
1074: g.fillRect(rectButton.x, rectButton.y, rectButton.width,
1075: rectButton.height);
1076:
1077: g.setColor(m_colHierarchyLines);
1078: g.drawRect(rectButton.x, rectButton.y, rectButton.width,
1079: rectButton.height);
1080:
1081: // put '-' sign in box
1082: g.drawLine(pt.x - w + 1, pt.y, pt.x + w, pt.y);
1083:
1084: if (!((Node) ((ListItem) m_arrItems.elementAt(m_lvi_iItem))
1085: .getItemData()).isExpanded()) {
1086: // put '+' in box
1087: g.drawLine(pt.x, pt.y - w + 1, pt.x, pt.y + w);
1088: }
1089:
1090: }
1091:
1092: /**
1093: * calculates the size of the button rectangle
1094: * @return size as type Rectangle
1095: */
1096: protected Rectangle calcButtonRect() {
1097: // this is the button the user clicks on to expand/contract
1098: // a tree node. Need to know to test for hits.
1099:
1100: Rectangle bounds = getBounds();
1101:
1102: Node pNode = getNodeAt(m_lvi_iItem);
1103:
1104: if (isRoot(pNode) || !pNode.hasChildren())
1105: return new Rectangle(0, 0, 0, 0);
1106: ListItem pItem = super .getItemAt(m_lvi_iItem);
1107:
1108: int iDist = pNode.getDistanceFromRoot();//-1;
1109: int yMid;
1110: int xMid;
1111: int w;
1112: int textHeight = measureText();
1113: yMid = m_recPCRect.y;
1114:
1115: //AAB xMid = m_recPCRect.x -3+ getIndent()*(iDist-1) - (m_bLinesAtRoot ? 0 : getIndent());
1116: xMid = m_recPCRect.x - m_nButtonSize + getIndent()
1117: * (iDist - 1) - (m_bLinesAtRoot ? 0 : getIndent());
1118: xMid += bounds.x;
1119:
1120: //AAB
1121: xMid += m_nWidthGap;
1122:
1123: yMid += pItem.getTextBounds().y + pItem.getImageBounds().height
1124: / 2 - 2;//-pItem.getTextBounds().height/4;
1125: w = m_nButtonSize;
1126:
1127: if (m_bLinesAtRoot)
1128: xMid += getIndent();
1129:
1130: Rectangle pRectButton = new Rectangle();
1131: pRectButton.x = xMid - w / 2 - bounds.x - m_recPCRect.x
1132: - m_ptViewportOrg.x;
1133: pRectButton.y = yMid - w / 2 - bounds.y - m_recPCRect.y;
1134: pRectButton.width = w;
1135: pRectButton.height = w;
1136:
1137: return pRectButton;
1138: }
1139:
1140: /**
1141:
1142:
1143: Draws lines connecting the node on this
1144: row to its parent(s) and next and
1145: previous siblings.</br>
1146:
1147:
1148: How this function works: </br>
1149:
1150: This function paints the hierarchy lines for each row
1151: individually. For example, for a node 5 levels deep
1152: in the hierarchy, it will paint: </br>
1153:
1154: | | | | '- [NODE] </br>
1155:
1156: The above diagram assumes the node on this row has
1157: no siblings below itself (i.e. no next sibling). In
1158: this case, an upward L shape is painted. If the
1159: node does have a next sibling, the drawing becomes: </br>
1160:
1161: | | | | |- [NODE]</br>
1162:
1163: The painting starts by positioning the drawing point
1164: at the far right of the picture above (i.e. the horz
1165: line that connects to the node itself. Next, it draws
1166: the upward L shape. Lastly, it enters a for loop
1167: where it draws 'n' vertical lines where 'n' is the
1168: hierarchical depth of the node. Note, a vertical line
1169: is drawn over the upward L shape iff the node has a
1170: next sibling. </br>
1171:
1172: There is only one exception to the above painting
1173: algorithm. The very first node in the tree doesn't
1174: have the vertical line segment of the upward L shape.
1175: This is because the very first node has no parent or
1176: previous sibling to connect to.
1177: * @param g Graphics object
1178: */
1179:
1180: public void drawHierarchyLines(Graphics g) {
1181:
1182: Rectangle bounds = getBounds();
1183:
1184: g.setColor(m_colHierarchyLines);
1185: Node pParent;
1186: Point pt = new Point();
1187: boolean bSelected = isSelected(m_lvi_iItem);
1188: int w;
1189: int iOrigDist = ((Node) (((ListItem) m_arrItems
1190: .elementAt(m_lvi_iItem)).getItemData()))
1191: .getDistanceFromRoot() - 1;
1192: boolean bLinesAtRoot = m_bLinesAtRoot;
1193: pt.y = m_recPCRect.y;
1194: ListItem tempItem = ((ListItem) m_arrItems
1195: .elementAt(m_lvi_iItem));
1196:
1197: if (m_arrImages != null && m_arrImages.size() > 0) {
1198: pt.x = -m_ptViewportOrg.x + m_nButtonSize + getIndent()
1199: * iOrigDist - (bLinesAtRoot ? 0 : getIndent());
1200: pt.y += tempItem.getImageBounds().y
1201: + tempItem.getImageBounds().height / 2;
1202: w = tempItem.getImageBounds().x - pt.x - 1 - m_nWidthGap
1203: - m_ptViewportOrg.x;
1204: pt.y -= bounds.y;
1205: pt.x += m_nWidthGap;
1206: } else {
1207: pt.x = -m_ptViewportOrg.x + m_nButtonSize + getIndent()
1208: * iOrigDist - (bLinesAtRoot ? 0 : getIndent());//-((Column)m_arrColumns.elementAt(0)).getWidth()+ getIndent()*iOrigDist - (bLinesAtRoot ? 0 : getIndent())-bounds.x;
1209: pt.y += tempItem.getTextBounds().y
1210: + tempItem.getTextBounds().height / 2;
1211: w = tempItem.getTextBounds().x - (pt.x) - 1;
1212:
1213: pt.y -= tempItem.getTextBounds().y;
1214: pt.y -= bounds.y;
1215:
1216: }
1217: pt.x += bounds.x;
1218:
1219: if (((pt.y - m_ptViewportOrg.y) % 2) != 0)
1220: pt.y++;
1221: pt.x++;
1222:
1223: // Draw the short horizontal line that connects to the
1224: // node icon (or text).
1225: if (!isRoot(m_lvi_iItem))
1226: //// BINA CHANGES
1227: //drawHorzHierarchyLine(g, bSelected, pt.x, pt.x+w, pt.y);
1228: drawHorzHierarchyLine(g, bSelected, pt.x, pt.x + w,
1229: pt.y + 3);
1230: //// BINA
1231:
1232: // draw the upward line segment of the upward L shape. This
1233: // is the line connecting this node to its parent or previous
1234: // sibling. (NOTE: this line segment should not be drawn for
1235: // the very first node in the tree.)
1236: if (m_lvi_iItem > 0) {
1237: int temp = tempItem.getTextBounds().y;
1238: if (!isRoot(m_lvi_iItem))
1239: //// BINA CHANGES
1240: //drawVertHierarchyLine(g, bSelected, pt.x/*-getIndent()*/, pt.y, /*m_recPCRect.y*/ temp-bounds.y-2);
1241: //System.out.println("Draw Vertical Line .... 4");
1242: drawVertHierarchyLine(g, bSelected,
1243: pt.x/*-getIndent()*/, pt.y + 4, /*m_recPCRect.y*/
1244: temp - bounds.y - 2);
1245: //// BINA
1246: }
1247:
1248: // draw the line under the icon that connects this item to
1249: // its children.
1250:
1251: // Draw the line under the icon that connects this item to
1252: // its children.
1253:
1254: if (((Node) tempItem.getItemData()).hasChildren()
1255: && ((Node) tempItem.getItemData()).isExpanded()) {
1256: int cyOff;
1257: if (m_arrImages != null && m_arrImages.size() > 0)
1258: cyOff = tempItem.getImageBounds().height / 2;
1259: else
1260: cyOff = tempItem.getTextBounds().height / 2;
1261: //// BINA
1262: //System.out.println("Nex Vert line.... + 1");
1263: drawVertHierarchyLine(g, bSelected, pt.x + getIndent(),
1264: pt.y + cyOff + 2 + 2, m_recPCRect.height
1265: + m_recPCRect.height / 4
1266: + /*m_recPCRect.y*/pt.y/*-bounds.y*/);
1267: //drawVertHierarchyLine(g,bSelected, pt.x+getIndent() , pt.y + cyOff+2, m_recPCRect.height+m_recPCRect.height/4+pt.y+1);
1268: /// END BINA
1269: }
1270: if (isRoot(m_lvi_iItem))// == nodeIndex(m_pNodeRoot))
1271: return;
1272:
1273: // Draw the vertical lines to the left of the upward L shape.
1274: // Note, if the node has a next sibling, we do not draw an
1275: // upward L shape. The hierarchy lines for the node described
1276: // above that is a five level deep but has a next child is:
1277: //
1278: // | | | | |-
1279: //
1280: pParent = (Node) (tempItem.getItemData());
1281: for (int i = iOrigDist + 1; i >= (bLinesAtRoot ? 0 : 1); i--) {
1282: if (pParent.getNextSibling() != null) {
1283: if (m_arrImages == null || m_arrImages.size() < 0)
1284: drawVertHierarchyLine(g, bSelected, pt.x, pt.y,
1285: tempItem.getTextBounds().height
1286: + tempItem.getTextBounds().y
1287: - bounds.y
1288: + tempItem.getTextBounds().height
1289: / 4);
1290: else
1291: drawVertHierarchyLine(g, bSelected, pt.x,
1292: pt.y/*+2*/, m_recPCRect.height
1293: + m_recPCRect.y - bounds.y/*+4*/
1294: + m_recPCRect.height / 4);
1295: }
1296: pParent = (Node) pParent.getParent();
1297: pt.x -= getIndent();// -3;
1298: pt.y = m_recPCRect.y - 2 - bounds.y;
1299:
1300: }
1301: }
1302:
1303: /**
1304: * draws vertical hierarchy line
1305: * @param g Graphics object
1306: * @param bSelected whether item is selected
1307: * @param x x coordinate
1308: * @param y1 starting y coordinage
1309: * @param y2 ending y coordinate
1310: */
1311: public void drawVertHierarchyLine(Graphics g, boolean bSelected,
1312: int x, int y1, int y2) {
1313: int swap;
1314: int i;
1315:
1316: if (y2 < y1) {
1317: swap = y1;
1318: y1 = y2;
1319: y2 = swap;
1320: }
1321: x -= getBounds().x;
1322: if (((y1 + m_ptViewportOrg.y) % 2) != 0
1323: && m_nStyleHierarchyLines == DOTTED)
1324: y1--;
1325: if (m_nStyleHierarchyLines == DOTTED)
1326: drawDottedLine(g, x, y1, x, y2);
1327: else
1328: g.drawLine(x, y1, x, y2);
1329: }
1330:
1331: /**
1332: * draws horizontal hierachy line
1333: * @param g Graphics object
1334: * @param bSelected whether item selected or not
1335: * @param x1 starting x position
1336: * @param x2 ending x position
1337: * @param y y position
1338: */
1339: public void drawHorzHierarchyLine(Graphics g, boolean bSelected,
1340: int x1, int x2, int y) {
1341: Rectangle bounds = getBounds();
1342:
1343: int swap;
1344: int i;
1345: x1 -= bounds.x;
1346: x2 -= bounds.x;
1347: if (x2 < x1) {
1348: swap = x1;
1349: x1 = x2;
1350: x2 = swap;
1351: }
1352: if (((x1 + m_ptViewportOrg.x) % 2) != 0)
1353: x1++;
1354: if (m_nStyleHierarchyLines == DOTTED)
1355: drawDottedLine(g, x1, y, x2, y);
1356: else
1357: g.drawLine(x1, y, x2, y);
1358: }
1359:
1360: // Tree Navigation
1361: /**
1362: * retrieves the next item based on the relation value you pass in.
1363: * Possible values are: </br>
1364: * TVGN_NEXT : next sibling </br>
1365: * TVGN_PREVIOUS : previous sibling </br>
1366: * TVGN_CHILD : child item </br>
1367: * TVGN_PARENT : parent item </br>
1368: * TVGN_ROOT : root item </br>
1369: * TVGN_FIRSTVISIBLE : first visible item </br>
1370: * TVGN_NEXTVISIBLE : next visible item </br>
1371: * TVGN_PREVIOUSVISIBLE : previous visible item </br>
1372: * TVGN_FIRSTSELECTED : first selected item</br>
1373: * TVGN_NEXTSELECTED : next selected item</br>
1374: * TVGN_PREVIOUSSELECTED : previously selected item</br>
1375: * @param item Node item to search from
1376: * @param nRelation style as defined above
1377: * @return the item searched for.
1378: * @see ob.tree.Node
1379: */
1380: public Node getNextItem(Node item, int nRelation) {
1381: switch (nRelation) {
1382: case TVGN_NEXT:
1383: return getNextSiblingItem(item);
1384: case TVGN_PREVIOUS:
1385: return getPrevSiblingItem(item);
1386: case TVGN_CHILD:
1387: return getChildItem(item);
1388: case TVGN_PARENT:
1389: return getParentItem(item);
1390: case TVGN_ROOT:
1391: return getRootItem(item);
1392: case TVGN_FIRSTVISIBLE:
1393: return getFirstVisibleItem();
1394: case TVGN_NEXTVISIBLE:
1395: return getNextVisibleItem(item);
1396: case TVGN_PREVIOUSVISIBLE:
1397: return getPrevVisibleItem(item);
1398: case TVGN_FIRSTSELECTED:
1399: return getFirstSelectedItem();
1400: case TVGN_NEXTSELECTED:
1401: return getNextSelectedItem(item);
1402: case TVGN_PREVIOUSSELECTED:
1403: return getPrevSelectedItem(item);
1404: default:
1405: return null;
1406: }
1407: }
1408:
1409: /**
1410: * retrieves the next child item from the source Node
1411: * @param hItem the source Node
1412: * @return next child as type Node
1413: * @see ob.tree.Node
1414: */
1415: public Node getChildItem(Node hItem) {
1416: TreeNodeX pNode = new TreeNodeX();
1417: if (hItem == null)
1418: pNode = (Node) m_arrRoots.elementAt(0);
1419: else
1420: pNode = hItem;
1421:
1422: return (Node) pNode.getFirstChild();
1423: }
1424:
1425: /**
1426: * retrieves the next sibling item from the source Node
1427: * @param hItem source Node item
1428: * @return next sibling as type Node
1429: * @see ob.tree.Node
1430: */
1431: public Node getNextSiblingItem(Node hItem) {
1432: TreeNodeX pNode;
1433: if (hItem == null)
1434: pNode = (Node) m_arrRoots.elementAt(0);
1435: else
1436: pNode = hItem;
1437:
1438: return (Node) pNode.getNextSibling();
1439: }
1440:
1441: /**
1442: * retrieves the previous sibling item
1443: * @param hItem source Node item
1444: * @return previous sibling as type Node
1445: * @see ob.tree.Node
1446: */
1447: public Node getPrevSiblingItem(Node hItem) {
1448: TreeNodeX pNode;
1449: if (hItem == null)
1450: pNode = (Node) m_arrRoots.elementAt(0);
1451: else
1452: pNode = hItem;
1453:
1454: return (Node) pNode.getPrevSibling();
1455: }
1456:
1457: /**
1458: * retrieves the parent item of the node
1459: * @param hItem the source node
1460: * @return the parent item as type NOde
1461: * @see ob.tree.Node
1462: */
1463: public Node getParentItem(Node hItem) {
1464: TreeNodeX pNode;
1465:
1466: // retrieves the first child item of the root item of which the specified item is a part.
1467: if (hItem == null)
1468: pNode = (Node) m_arrRoots.elementAt(0);
1469: else
1470: pNode = hItem;
1471:
1472: if (!isRoot((Node) pNode)) {
1473: while (pNode != null && !isRoot((Node) pNode.getParent()))
1474: // != m_pNodeRoot)
1475: pNode = (TreeNodeX) pNode.getParent();
1476: return (Node) pNode.getFirstChild();
1477: } else
1478: return (Node) ((Node) m_arrRoots.elementAt(0))
1479: .getFirstChild();
1480: }
1481:
1482: /**
1483: * retrieves the first visible item
1484: * @return first visible item as type Node
1485: * @see ob.tree.Node
1486: */
1487: public Node getFirstVisibleItem() {
1488: // retrieves the first visible item
1489: Node pNode = null;
1490: int nNext = m_nTopRow;
1491: if (nNext != -1)
1492: pNode = getNodeAt(nNext);
1493: return pNode;
1494: }
1495:
1496: /**
1497: * retrieves the next visible item
1498: * @param hItem source Node
1499: * @return next visible item as type Node
1500: * @see ob.tree.Node
1501: */
1502: public Node getNextVisibleItem(Node hItem) {
1503: int nItem = nodeIndex(hItem);
1504: if (nItem >= 0) {
1505: // optimize the case when the given item is visible.
1506: // in this case, the next item is simply the next item
1507: // in the list.
1508: nItem++;
1509: if (nItem < getItemCount())
1510: return getNodeAt(nItem);
1511: } else {
1512: // given item is not in the list control. So, we have
1513: // to find the nearest neighbor that is.
1514: Node pNode = hItem;
1515: if (pNode != null) {
1516: pNode = (Node) pNode.getNextInDisplayOrder();
1517: for (; pNode != null; pNode = (Node) pNode
1518: .getNextInDisplayOrder()) {
1519: if (pNode.isVisible())
1520: return pNode;
1521: }
1522: }
1523: }
1524: return null;
1525:
1526: }
1527:
1528: /**
1529: * retrieves the last visible item
1530: * @param hItem the source item to search from
1531: * @return the last visible item as type Node
1532: * @see ob.tree.Node
1533: */
1534: public Node getLastVisibleItem(Node hItem) {
1535: int iLast = getItemCount();
1536: if (iLast < 0)
1537: return null;
1538: return getNodeAt(iLast - 1);
1539: }
1540:
1541: /**
1542: * retrieves the previous visible item
1543: * @param hItem the source item to search from
1544: * @return the previously visible item as type Node
1545: * @see ob.tree.Node
1546: */
1547: public Node getPrevVisibleItem(Node hItem) {
1548: if (!(isRoot(hItem))) {
1549: int nItem = nodeIndex(hItem);
1550: if (nItem >= 0) {
1551: // optimize the case when the given item is visible.
1552: // in this case, the prev item is simply the prev item
1553: // in the list.
1554: nItem--;
1555: if (nItem != -1)
1556: return getNodeAt(nItem);
1557: } else {
1558: // given item is not in the list control. So, we have
1559: // to find the nearest neighbor that is.
1560: Node pNode = hItem;
1561: while ((pNode = (Node) pNode.getPrevInDisplayOrder()) != null) {
1562: if (nodeIndex(pNode) != -1)
1563: return pNode;
1564: }
1565: }
1566: }
1567: return null;
1568: }
1569:
1570: /**
1571: * retrieves the first selected item
1572: * @return first selected item as type Node
1573: * @see ob.tree.Node
1574: */
1575: public Node getFirstSelectedItem() {
1576: Node pNode = null;
1577:
1578: if (getSelectedItems().length == 0)
1579: return pNode;
1580: int nIndex = getSelectedIndexes()[0];
1581: pNode = getNodeAt(nIndex);
1582: return pNode;
1583: }
1584:
1585: /**
1586: * retrieves the next selected item
1587: * @param hItem the source item to search from
1588: * @return the next selected item as type Node
1589: * @see ob.tree.Node
1590: */
1591: public Node getNextSelectedItem(Node hItem) {
1592: int nItem = nodeIndex(hItem);
1593: if (nItem >= 0) {
1594: for (int i = 0; i < getSelectedIndexes().length; i++) {
1595: if (nItem == getSelectedIndexes()[i]) {
1596: if (i == getSelectedIndexes().length - 1) {
1597: nItem = -1;
1598: break;
1599: } else {
1600: nItem = i + 1;
1601: break;
1602: }
1603: }
1604: }
1605: if (nItem != -1)
1606: return getNodeAt(nItem);
1607: } else {
1608: // given item is not in the list control. So, we have
1609: // to find the nearest neighbor that is.
1610: Node pNode = hItem;
1611: while ((pNode = (Node) pNode.getPrevInDisplayOrder()) != null) {
1612: if (pNode.isVisible()) {
1613: return getNextSelectedItem(pNode);
1614:
1615: }
1616: }
1617: }
1618: return null;
1619: }
1620:
1621: /**
1622: * retrieves the previously selected item
1623: * @param hItem the source item to search from
1624: * @return the previously selected item as type Node
1625: * @see ob.tree.Node
1626: */
1627: public Node getPrevSelectedItem(Node hItem) {
1628: int nItem = nodeIndex(hItem);
1629: if (nItem >= 0) {
1630: for (int i = 0; i < getSelectedIndexes().length; i++) {
1631: if (nItem == getSelectedIndexes()[i]) {
1632:
1633: nItem = i - 1;
1634: break;
1635:
1636: }
1637: }
1638:
1639: if (nItem != -1)
1640: return getNodeAt(nItem);
1641: } else {
1642: // given item is not in the list control. So, we have
1643: // tof ind the nearest neighbor that is.
1644: Node pNode;
1645: pNode = hItem;
1646: if (pNode != null) {
1647: pNode = (Node) pNode.getNextInDisplayOrder();
1648: for (; pNode != null; pNode = (Node) pNode
1649: .getNextInDisplayOrder()) {
1650: if (pNode.isVisible()) {
1651: return getPrevSelectedItem(pNode);
1652:
1653: }
1654: }
1655: }
1656: }
1657: return null;
1658: }
1659:
1660: /**
1661: * retrieves the currently selected node
1662: * @return selected Node
1663: * @see ob.tree.Node
1664: */
1665: public Node getSelectedNode() {
1666: if (selected.length > 0
1667: && selected[selected.length - 1] < m_arrItems.size()) {
1668: return (Node) (((ListItem) m_arrItems
1669: .elementAt((selected[selected.length - 1])))
1670: .getItemData());
1671: }
1672:
1673: return null;
1674: }
1675:
1676: /**
1677: * retrieves the root item
1678: * @param hti source item to search from
1679: * @return root item as type Node
1680: * @see ob.tree.Node
1681: */
1682: public Node getRootItem(Node hti) {
1683: if (m_arrRoots == null)
1684: return null;
1685:
1686: TreeNodeX pNode;
1687:
1688: // retrieves the first child item of the root item of which the specified item is a part.
1689: if (hti == null)
1690: pNode = (Node) m_arrRoots.elementAt(0);
1691: else
1692: pNode = hti;
1693:
1694: if (!isRoot((Node) pNode)) {
1695: while (pNode != null && !isRoot((Node) pNode.getParent()))
1696: // != m_pNodeRoot)
1697: pNode = (Node) pNode.getParent();
1698: return (Node) pNode.getFirstChild();
1699: } else
1700: return (Node) ((Node) m_arrRoots.elementAt(0))
1701: .getFirstChild();
1702:
1703: }
1704:
1705: /**
1706: * retrieves first root item
1707: * @return root item as type Node
1708: * @see ob.tree.Node
1709: */
1710: public Node getRootItem() {
1711: return getRootItem(null);
1712: }
1713:
1714: /**
1715: * retrieves the next item in the display order
1716: * @param hti source item to search from
1717: * @return next item as type Node
1718: * @see ob.tree.Node
1719: */
1720: public Node getNextItemInDisplayOrder(Node hti) {
1721:
1722: Node pNode = hti;
1723: return (Node) pNode.getNextInDisplayOrder();
1724: }
1725:
1726: // end navigation member functions
1727:
1728: /**
1729: * retrieves the tree Node associated with a ListItem. A ListItem
1730: * describes an entire "row" of the multicolumn tree control.
1731: * @param pItem the source ListItem
1732: * @return the corresponding Node item
1733: * @see ob.tree.Node
1734: * @see ob.listbox.ListItem
1735: * @see ob.listbox.ListBox
1736: */
1737: public Node getNode(ListItem pItem) {
1738: if (pItem == null)
1739: return null;
1740: else
1741: return (Node) (pItem.getItemData());
1742: }
1743:
1744: /**
1745: * retrieves the tree node for a given index position
1746: * @param nIndex the position you wish to retrieve the node for
1747: * @return the tree node at the position searched for as type Node
1748: * @see ob.tree.Node
1749: */
1750: public Node getNodeAt(int nIndex) {
1751: ListItem pItem;
1752: Node pNode;
1753:
1754: pItem = super .getItemAt(nIndex);
1755:
1756: if (pItem != null)
1757: pNode = (Node) (pItem.getItemData());
1758: else
1759: pNode = null;
1760:
1761: return pNode;
1762: }
1763:
1764: /**
1765: * determines whether a Node item is currently expanded or not
1766: * @return true if expanded, otherwise false
1767: */
1768: public boolean isExpanded(Node hItem) {
1769:
1770: return hItem.isExpanded();
1771:
1772: }
1773:
1774: /**
1775: * expands a given tree node. You can specify the action based on the following codes: </br>
1776: * TVE_TOGGLE : toggles between expanded and unexpanded </br>
1777: * TVE_COLLAPSE : attempts to collapse the node; if already collapsed no action is taken. </br>
1778: * TVE_EXPAND : attempts to expand the node; if it is already expanded no action is taken. </br>
1779: * @param htiExpand node which will be expanded
1780: * @param nCode the action to take. Appropriate codes described above
1781: * @param bRedraw true if you wish to force a redraw, otherwise false
1782: * @return whether the expand action was successful as type boolean
1783: */
1784: public boolean expand(Node htiExpand, int nCode, boolean bRedraw) {
1785: Node htiSelected = getSelectedNode();
1786: Node pNodeExpand;
1787: Node pNodeFocus;
1788: int action;
1789: int nIndex;
1790:
1791: pNodeExpand = htiExpand;
1792:
1793: if (nCode == TVE_TOGGLE) {
1794: if (pNodeExpand.isExpanded())
1795: action = TVE_COLLAPSE;
1796: else
1797: action = TVE_EXPAND;
1798: } else
1799: action = nCode;
1800:
1801: nIndex = nodeIndex(pNodeExpand);
1802:
1803: switch (action) {
1804: case TVE_COLLAPSE:
1805: if (!pNodeExpand.isExpanded())
1806: return true; //already collapsed;
1807: pNodeExpand.collapse();
1808:
1809: // Actually remove items from the display
1810: // first store selected list
1811: Vector preCollapseList = new Vector();
1812: for (int i = 0; i < selected.length; i++)
1813: preCollapseList.addElement(m_arrItems
1814: .elementAt(selected[i]));
1815:
1816: deselectAll(false);
1817: removeChildrenFromListCtrl(pNodeExpand, nIndex, false);
1818:
1819: selected = new int[0];
1820:
1821: for (int j = 0; j < preCollapseList.size(); j++)
1822: select(
1823: getIndex((ListItem) preCollapseList
1824: .elementAt(j)), false);
1825: reMeasureAllItems();
1826:
1827: if (bRedraw) {
1828: update();
1829: }
1830: processActionEvent(new ActionEvent(this , ITEM_COLLAPSED,
1831: commandItemCollapsed));
1832:
1833: break;
1834:
1835: case TVE_EXPAND:
1836: if (pNodeExpand.isExpanded())
1837: return true; //already expanded;
1838:
1839: Vector preExpandList = new Vector();
1840: for (int i = 0; i < selected.length; i++)
1841: preExpandList.addElement(m_arrItems
1842: .elementAt(selected[i]));
1843: deselectAll(false);
1844: //expand this branch of the tree
1845: pNodeExpand.expand();
1846:
1847: // Add the children to the list control
1848:
1849: if (pNodeExpand.hasChildren()) {
1850: addChildrenToListCtrl(pNodeExpand, nIndex);
1851: processActionEvent(new ActionEvent(this , ITEM_EXPANDED,
1852: commandItemExpanded));
1853: } else { // pNodeExpand does not have children
1854: processActionEvent(new ActionEvent(this , OPENFOLDER,
1855: commandOpenFolder));
1856: }
1857:
1858: selected = new int[0];
1859:
1860: for (int j = 0; j < preExpandList.size(); j++)
1861: select(getIndex((ListItem) preExpandList.elementAt(j)),
1862: false);
1863: reMeasureAllItems();
1864: if (bRedraw) {
1865:
1866: update();
1867: }
1868:
1869: break;
1870:
1871: default:
1872: break;
1873: }
1874:
1875: return true;
1876: }
1877:
1878: /**
1879: * expands a given tree node. You can specify the action based on the following codes: </br>
1880: * TVE_TOGGLE : toggles between expanded and unexpanded </br>
1881: * TVE_COLLAPSE : attempts to collapse the node; if already collapsed no action is taken. </br>
1882: * TVE_EXPAND : attempts to expand the node; if it is already expanded no action is taken. </br>
1883: * @param htiExpand node which will be expanded
1884: * @param nCode the action to take. Appropriate codes described above
1885: * @return whether the expand action was successful as type boolean
1886: */
1887: public boolean expand(Node hItem, int nCode) {
1888: return expand(hItem, nCode, true);
1889: }
1890:
1891: // OPERATIONS
1892:
1893: /**
1894: * adds a node to the end of the tree
1895: * @param pNodeAdd the node to be added
1896: * @return true if successful, otherwise false
1897: */
1898: protected boolean addNodeToListBox(Node pNodeAdd) {
1899: // Make a node visible in our listbox. This happens when its
1900: // parent has the attributes of being expanded (in normal tree
1901: // view mode).
1902: int nIndex;
1903: Node pNodeAbove;
1904:
1905: if (isRoot((Node) pNodeAdd.getParent())
1906: && pNodeAdd.getPrevSibling() == null) {
1907: // then item to be shown is the first child item
1908: nIndex = 1 + nodeIndex((Node) pNodeAdd.getParent());
1909: } else {
1910:
1911: pNodeAbove = getPrevVisibleItem(pNodeAdd);
1912:
1913: if (pNodeAbove == null)
1914: return false;
1915: nIndex = nodeIndex(pNodeAbove);
1916:
1917: nIndex++;
1918: }
1919:
1920: ListItem pItem = super .createNewItem();
1921: pItem.setItemData(pNodeAdd);
1922: pItem.setHeight(LVXC_UNINITIALIZED);
1923:
1924: super .insertItem(nIndex, pItem);
1925: if (pNodeAdd.hasChildren() && pNodeAdd.isExpanded()) {
1926: Node childNode = (Node) pNodeAdd.getFirstChild();
1927: while (childNode != null) {
1928: addNodeToListBox(childNode);
1929: childNode = (Node) childNode.getNextSibling();
1930: }
1931: }
1932:
1933: return true;
1934: }
1935:
1936: /**
1937: * deletes a node from the tree
1938: * @param pNodeDel Node to delete
1939: * @return true if deleted, otherwise false
1940: * @see ob.tree.Node
1941: */
1942: protected boolean delNodeFromListBox(Node pNodeDel) {
1943: return delNodeFromListBox(pNodeDel, true);
1944: }
1945:
1946: /**
1947: * deletes a node from the tree and you specify whether to force an update or not
1948: * @param pNodeDel Node to delete
1949: * @param bUpdate true if update should occur, otherwise false
1950: * @return true if deletion occured, otherwise false
1951: */
1952: protected boolean delNodeFromListBox(Node pNodeDel, boolean bUpdate) {
1953: int nIndex;
1954: //System.out.println("in.. delNodeFromListBox");
1955: if (isRoot((Node) pNodeDel.getParent()) && pNodeDel.isVisible()) {
1956: //pNodeDel's parent is the root.
1957: // cannot delete child of root.
1958: return false;
1959: }
1960:
1961: nIndex = nodeIndex(pNodeDel);
1962:
1963: //System.out.println("IN delNodeFromListBox nIndex is ....." + nIndex);
1964:
1965: super .deleteItem(nIndex, bUpdate);
1966:
1967: return true;
1968: }
1969:
1970: /**
1971: * initialize the root node
1972: * @param label the label of the root node as type String
1973: * @param image a reference to the unexpanded image diplayed with the root node
1974: * @param imageExpanded a reference to the expanded image displayed with the root node
1975: */
1976: public void initRootNode(String label, int image, int imageExpanded) {
1977: if (m_arrRoots == null) {
1978: m_arrRoots = new Vector();
1979: m_arrRoots
1980: .addElement(new Node(label, image, imageExpanded));
1981: ((Node) m_arrRoots.elementAt(0)).expand();
1982: }
1983:
1984: ListItem root = new ListItem();
1985: root.setItemData((Node) m_arrRoots.elementAt(0));
1986: addItem(root);
1987: }
1988:
1989: /**
1990: * initializes a default root item with blank information
1991: */
1992: protected void initRootNode() {
1993: if (m_arrRoots == null) {
1994: m_arrRoots.addElement(new Node());// = new Node();
1995:
1996: ((Node) m_arrRoots.elementAt(0)).expand();
1997: }
1998:
1999: ListItem root = new ListItem();
2000: root.setItemData(m_arrItems.elementAt(0));
2001: addItem(root);
2002: }
2003:
2004: /**
2005: * initialize the root node
2006: * @param label the label of the root node as type String
2007: * @param image a reference to the unexpanded image diplayed with the root node
2008: * @param imageExpanded a reference to the expanded image displayed with the root node
2009: */
2010: public int createRootNode(String label, int image, int imageExpanded) {
2011: if (m_arrRoots == null) {
2012: initRootNode(label, image, imageExpanded);
2013: return 0;
2014: }
2015:
2016: m_arrRoots.addElement(new Node(label, image, imageExpanded));
2017: ((Node) m_arrRoots.elementAt(m_arrRoots.size() - 1)).expand();
2018: ListItem root = new ListItem();
2019: root.setItemData((Node) m_arrRoots
2020: .elementAt(m_arrRoots.size() - 1));
2021: addItem(root);
2022: return m_arrRoots.size() - 1;
2023: }
2024:
2025: /**
2026: * adds a root item
2027: * @param node the new node which is made a root item in the tree
2028: * @return the position of the root relative to other root nodes
2029: */
2030: public int addRootItem(Node node) {
2031: if (m_arrRoots == null) {
2032: m_arrRoots = new Vector();
2033: //m_arrRoots.addElement(node);
2034:
2035: //return 0;
2036: }
2037:
2038: m_arrRoots.addElement(node);
2039: ((Node) m_arrRoots.elementAt(m_arrRoots.size() - 1)).expand();
2040: ListItem root = new ListItem();
2041: root.setItemData((Node) m_arrRoots
2042: .elementAt(m_arrRoots.size() - 1));
2043: addItem(root);
2044: addChildrenToListCtrl((Node) m_arrRoots.elementAt(m_arrRoots
2045: .size() - 1), nodeIndex((Node) m_arrRoots
2046: .elementAt(m_arrRoots.size() - 1)));
2047:
2048: return m_arrRoots.size() - 1;
2049: }
2050:
2051: /**
2052: * creates a default uninitialized root node
2053: */
2054: public int createRootNode() {
2055: return createRootNode("", -1, -1);
2056: }
2057:
2058: /**
2059: * detaches and optionally deletes a tree item which does not have children nodes
2060: * @param hti the source item
2061: * @param bDelFromListBox whether you wish to delete the node from the tree entirely
2062: * @return whether the item was deleted or not
2063: */
2064: protected boolean deleteUnChildedItem(Node hti,
2065: boolean bDelFromListBox) {
2066: Node pNodeDelete = hti;
2067: if (pNodeDelete.getFirstChild() != null)
2068: return false;
2069: pNodeDelete.detachFromTree();
2070: if (bDelFromListBox && nodeInListBox(pNodeDelete))
2071: delNodeFromListBox(pNodeDelete);
2072:
2073: return true;
2074: }
2075:
2076: /**
2077: * deletes a tree item which does not have tree items
2078: * @param hti node to delete
2079: * @return true if successfully deleted, otherwise false
2080: */
2081: protected boolean deletedUnChildedItem(Node hti) {
2082: return deleteUnChildedItem(hti, true);
2083: }
2084:
2085: /**
2086: * determines whether the tree node exists in the tree or not
2087: * @param pNode the Node you are checking against
2088: * @return true if node exists, otherwise false
2089: * @see ob.tree.Node
2090: */
2091: protected boolean nodeInListBox(Node pNode) {
2092: // return true if node is visible
2093: // nb. is actually "if node is in list box"
2094: if (nodeIndex(pNode) != -1)
2095: return true;
2096: return false;
2097: }
2098:
2099: /**
2100: * expands the currently specified tree node based on the code you pass in, as described below:
2101: * TVE_TOGGLE : toggles between expanded and unexpanded </br>
2102: * TVE_COLLAPSE : attempts to collapse the node; if already collapsed no action is taken. </br>
2103: * TVE_EXPAND : attempts to expand the node; if it is already expanded no action is taken. </br>
2104: * @param nCode the code used to expand
2105: * @return the expanded tree node as type Node
2106: */
2107: protected Node expandSelectedItem(int nCode) {
2108: Node hti = getSelectedNode();
2109: if (!expand(hti, nCode))
2110: return null;
2111: return hti;
2112: }
2113:
2114: /**
2115: * adds a child node to the source node
2116: * @param pParent the source node to add children to
2117: * @param nIndex the position you wish to add the node at
2118: * @return the position where the node was inserted as type int
2119: */
2120: protected int addChildrenToListCtrl(Node pParent, int nIndex) {
2121: Node pNode;
2122:
2123: ListItem pItem = new ListItem();
2124: // if we're adding children, then the parent must already
2125: // be present in the list control. Otherwise, we don't know
2126: // which index to insert below.
2127: if (nIndex == -1)
2128: return nIndex;
2129:
2130: for (pNode = (Node) pParent.getFirstChild(); pNode != null; pNode = (Node) pNode
2131: .getNextSibling()) {
2132: pItem = createNewItem();
2133: pItem.setItemData(pNode);
2134: super .insertItem(++nIndex, pItem);
2135: if (pNode.isExpanded() && pNode.hasChildren())
2136: nIndex = addChildrenToListCtrl(pNode, nIndex++);
2137:
2138: }
2139: return nIndex;
2140: }
2141:
2142: /**
2143: * removes a child node from the list control
2144: * @param pParent the parent Node
2145: * @param nParent parent index
2146: */
2147: protected void removeChildrenFromListCtrl(Node pParent, int nParent) {
2148: removeChildrenFromListCtrl(pParent, nParent, true);
2149: }
2150:
2151: /**
2152: * removes a child node from the tree control
2153: * @param pParent the parent Node
2154: * @param nParent parent index
2155: * @param bUpdate whether the tree should be updated or not
2156: */
2157: protected void removeChildrenFromListCtrl(Node pParent,
2158: int nParent, boolean bUpdate) {
2159: Node pNode;
2160: int nIndex, cCount;
2161: int i;
2162:
2163: // if we're removing children, then the parent must
2164: // be present in the list ctrl. Otherwise, we don't know
2165: // which index to delete below
2166:
2167: if (nParent == -1)
2168: return;
2169: cCount = 0;
2170: for (nIndex = nParent + 1; nIndex < getItemCount(); nIndex++, cCount++) {
2171: pNode = getNodeAt(nIndex);
2172: if (!pParent.isDescendant(pNode))
2173: break;
2174: }
2175:
2176: //reset selection state for the nodes being collapsed.
2177: int nLast = nParent + 1 + cCount - 1; // added a -1
2178: int val;
2179: for (i = selected.length - 1; i >= 0; i--) {
2180: val = selected[i];
2181: if (val > nParent && val < nLast) {
2182: pNode = getNodeAt(val);
2183:
2184: int nTempIndex = nodeIndex(pNode);
2185: if (isSelected(nTempIndex))
2186: deselect(nTempIndex);
2187: }
2188: }
2189: //now actually remove the item from the display
2190: if (cCount > 0) {
2191: if (bUpdate)
2192: super .deleteItem(nParent + 1, cCount);
2193: else
2194: super .deleteItem(nParent + 1, cCount, false);
2195: }
2196: }
2197:
2198: /**
2199: * calculates the node index
2200: * @param pNode node to determine index for
2201: * @param nStartFrom start searching from this offset
2202: * @return the index as type int
2203: */
2204: protected int nodeIndex(Node pNode, int nStartFrom) {
2205:
2206: for (int i = nStartFrom; i < getItemCount(); i++) {
2207: if (pNode == getNodeAt(i))
2208: return i;
2209: }
2210:
2211: return -1;
2212: }
2213:
2214: /**
2215: * calculates the node index
2216: * @param pNode node to determine index for
2217: * @return the index as type int
2218: */
2219: protected int nodeIndex(Node pNode) {
2220: return nodeIndex(pNode, 0);
2221: }
2222:
2223: /**
2224: * determines whether the node should be visible or not
2225: * @param pNode node which you are checking for visiblity
2226: * @return true if it should be visible, otherwise false
2227: */
2228: protected boolean shouldBeInListBox(Node pNode) {
2229: // ie, should the node be visible.
2230: if (((Node) pNode.getParent()).isExpanded()
2231: && nodeIndex(((Node) pNode.getParent())) != -1) {
2232: return true;
2233: }
2234: return false;
2235: }
2236:
2237: public void moveItems(Object[] items, int targetIndex) {
2238: if (targetIndex == -1)
2239: return;
2240:
2241: for (int j = items.length - 1; j > -1; j--) {
2242: if (items[j] == m_arrItems.elementAt(targetIndex))
2243: return;
2244: if (((Node) ((ListItem) m_arrItems.elementAt(targetIndex))
2245: .getItemData())
2246: .isAncestor(((Node) ((ListItem) items[j])
2247: .getItemData())))
2248: return;
2249: if (((Node) ((ListItem) items[j]).getItemData())
2250: .isParent(((Node) ((ListItem) m_arrItems
2251: .elementAt(targetIndex)).getItemData())))
2252: return;
2253: if (isRoot(((Node) ((ListItem) items[j]).getItemData())))
2254: return;
2255: }
2256:
2257: deselectAll(false);
2258: int nSelect = targetIndex;
2259:
2260: for (int i = items.length - 1; i > -1; i--) {
2261: if (getIndex((ListItem) items[i]) < targetIndex)
2262: targetIndex--;
2263: Node tempNode = (Node) (((ListItem) items[i]).getItemData());
2264: if (tempNode.hasChildren())
2265: removeChildrenFromListCtrl(tempNode,
2266: nodeIndex(tempNode), false);
2267: delNodeFromListBox(tempNode, false);
2268:
2269: tempNode.detachFromTree();
2270: ((Node) ((ListItem) m_arrItems.elementAt(targetIndex))
2271: .getItemData()).addChild(tempNode);
2272:
2273: if (shouldBeInListBox(tempNode))
2274: addNodeToListBox(tempNode);
2275:
2276: }
2277: }
2278:
2279: /**
2280: * edits the currently selected item or subitem
2281: */
2282: public void editItem() {
2283: Rectangle bounds = getBounds();
2284:
2285: m_bEditModeEnabled = false;
2286: m_bDragModeEnabled = false;
2287:
2288: if (selected.length > 1) {
2289: int temp = selected[selected.length - 1];
2290: selected = new int[0];
2291: select(temp);
2292: }
2293: m_nodeCurrentEdit = getSelectedNode();
2294:
2295: ListItem item = ((ListItem) m_arrItems
2296: .elementAt(selected[selected.length - 1]));
2297: m_textEditNode = new ExpandableText(m_nodeCurrentEdit.getText());
2298: m_textEditNode.setBorderStyle(Text.NORMAL);
2299: m_textEditNode.setTextHIndent(1);
2300: m_textEditNode.setTextVIndent(Text.STANDARD + 1);
2301: m_textEditNode.selectAll();
2302: m_textEditNode.setBorderColor(Color.black);
2303: Font font = m_nodeCurrentEdit.getFont();
2304: if (font == null)
2305: font = defaultfont;
2306: m_textEditNode.setFont(font);
2307: m_textEditNode.selectAll();
2308: m_textEditNode.addActionListener(this );
2309: m_nodeCurrentEdit.setText("");
2310:
2311: add(m_textEditNode);
2312: m_textEditNode.requestFocus();
2313: m_textEditNode.setBounds(item.getTextBounds().x - 2
2314: + m_nWidthGap - m_ptViewportOrg.x,
2315: item.getTextBounds().y - bounds.y - 2, item
2316: .getTextBounds().width + 2, item
2317: .getTextBounds().height
2318: + item.getTextBounds().height / 4);
2319: m_textEditNode.update();
2320: }
2321:
2322: /**
2323: * changes an item's text
2324: */
2325: protected void changeItemText() {
2326: m_nodeCurrentEdit.setText(m_textEditNode.getText());
2327: remove(m_textEditNode);
2328: m_textEditNode = null;
2329: measureItem(nodeIndex(m_nodeCurrentEdit), getGraphics());
2330: updateScrollbar();
2331: }
2332:
2333: protected int getSelected(int x1, int y1) {
2334:
2335: if (m_textEditNode != null && m_textEditNode.isShowing())
2336: changeItemText();
2337: int hitItem = super .getSelected(x1, y1);
2338:
2339: if (hitItem > -1) {
2340: ListItem tempItem = getItemAt(hitItem);
2341: Node tempNode = (Node) tempItem.getItemData();
2342: Font font = (tempNode.getFont());
2343: if (font == null)
2344: font = defaultfont;
2345:
2346: FontMetrics fm = getGraphics().getFontMetrics(font);
2347: int textWidth = 0;
2348: if (fm.stringWidth(tempNode.getText()) < tempItem
2349: .getTextBounds().width) {
2350: textWidth = fm.stringWidth(tempNode.getText());
2351: } else
2352: textWidth = tempItem.getTextBounds().width;
2353:
2354: Rectangle hitRect = new Rectangle(
2355: tempItem.getTextBounds().x - 2 + m_nWidthGap,
2356: y1 /*- bounds.y*/- 2, textWidth, 4);
2357: if (m_arrImages != null && m_arrImages.size() > 0) {
2358: hitRect.width += (tempItem.getImageBounds().width);
2359: hitRect.width += (getIndent() / 2);
2360: hitRect.x = (tempItem.getImageBounds().x)
2361: - m_ptViewportOrg.x;
2362: }
2363:
2364: if (hitRect.contains(x1, y1)) {
2365: if (isSelected(hitItem)) {
2366: hitRect.x = tempItem.getTextBounds().x - 2
2367: + m_nWidthGap - m_ptViewportOrg.x;
2368:
2369: if (hitRect.contains(x1, y1)) {
2370: if (selected.length > 1 && m_bEditModeEnabled
2371: && !m_bDragModeEnabled) {
2372: selected = new int[0];
2373: select(hitItem, false);
2374: }
2375:
2376: if (m_bEditModeAllowed)
2377: m_bEditModeEnabled = true;
2378: }
2379: return hitItem;
2380: }
2381: return hitItem;
2382: } else {
2383: m_lvi_iItem = hitItem;
2384: m_recPCRect = new Rectangle(tempItem.getTextBounds().x
2385: - 2 + m_nWidthGap, y1 - 2, textWidth, 4);
2386: Rectangle buttonRect = calcButtonRect();
2387: if (buttonRect.contains(x1, y1)) {
2388: expand(tempNode, TVE_TOGGLE, true);
2389: m_bEditModeEnabled = false;
2390: m_bDragModeEnabled = false;
2391: return -1;
2392: }
2393: }
2394: }
2395:
2396: return -1;
2397:
2398: }
2399:
2400: protected void processActionEvent(ActionEvent e) {
2401:
2402: if (actionListener != null) {
2403: actionListener.actionPerformed(e);
2404: return;
2405: }
2406:
2407: Node tempEventTarget = getSelectedNode();
2408: Component parent = getParent();
2409: if (parent != null) {
2410: int eventID;
2411: if (e.getActionCommand().equals(commandDragDrop)) {
2412: eventID = DRAGDROP;
2413: } else if (e.getActionCommand().equals(commandOpenFolder)) {
2414: eventID = OPENFOLDER;
2415: } else if (e.getActionCommand().equals(
2416: commandSelectionChanged)) {
2417: eventID = SELECTION_CHANGE;
2418: } else if (e.getActionCommand()
2419: .equals(commandItemCollapsed)) {
2420: eventID = ITEM_COLLAPSED;
2421: tempEventTarget = (Node) m_itemEventTarget;
2422: } else if (e.getActionCommand().equals(commandItemExpanded)) {
2423: eventID = ITEM_EXPANDED;
2424: tempEventTarget = (Node) m_itemEventTarget;
2425: } else if (e.getActionCommand()
2426: .equals(commandDoubleClicked)) {
2427: eventID = DOUBLE_CLICK;
2428: } else {
2429: eventID = ILLEGAL;
2430: }
2431:
2432: ///// BINA
2433: //parent.postEvent(new Event(this, eventID, tempEventTarget));
2434:
2435: parent.dispatchEvent(e);
2436:
2437: ///// END BINA
2438: }
2439: }
2440:
2441: protected int getTarget(int x, int y) {
2442: return super .getSelected(x, y);
2443: }
2444:
2445: protected void processKeyEvent(KeyEvent e) {
2446:
2447: int key = e.getKeyCode();
2448:
2449: if (e.getID() == Event.KEY_PRESS) {
2450: switch (key) {
2451: /*case KeyEvent.VK_ENTER:
2452: expand(getSelectedNode(),TVE_TOGGLE, true);
2453: prev = nodeIndex(getSelectedNode());
2454: break;*/
2455: case KeyEvent.VK_LEFT:
2456: if (getSelectedNode() != null) {
2457: if (getSelectedNode().isExpanded()) {
2458: expand(getSelectedNode(), TVE_COLLAPSE, true);
2459: prev = nodeIndex(getSelectedNode());
2460: break;
2461: } else {
2462: /*if (getSelectedNode().getParent() != null){
2463: Node tempNode = (Node)getSelectedNode().getParent();
2464: selected = new int[0];
2465: prev = Math.max(0,nodeIndex(tempNode)-1);
2466: select(nodeIndex(tempNode),false,false);
2467: update();
2468: }*/
2469: }
2470: }
2471: return;
2472: case KeyEvent.VK_RIGHT:
2473: if (getSelectedNode() != null) {
2474: if (!getSelectedNode().isExpanded()) {
2475: expand(getSelectedNode(), TVE_EXPAND, true);
2476: prev = nodeIndex(getSelectedNode());
2477: } else {
2478: /*if (getSelectedNode().hasChildren()) {
2479: Node tempNode = (Node)getSelectedNode().getFirstChild();
2480: selected = new int[0];
2481: prev = nodeIndex(tempNode);
2482: select(prev,false,false);
2483: } else {
2484: prev = nodeIndex(getSelectedNode());
2485: }*/
2486: }
2487: reMeasureAllItems();
2488: update();
2489: }
2490: return;
2491: default:
2492: break;
2493: }
2494: }
2495:
2496: if (key != KeyEvent.VK_RIGHT && key != KeyEvent.VK_LEFT)
2497: super .processKeyEvent(e);
2498: }
2499:
2500: protected void doubleClickEvent(int itemHit) {
2501: if (itemHit == -1) {
2502: return;
2503: } else {
2504: expand(getNodeAt(itemHit), TVE_TOGGLE, true);
2505: }
2506: }
2507:
2508: ///////BINA
2509: public synchronized void delNode(Node pChild, boolean pUpdate) {
2510: TreeItem ti = (TreeItem) pChild;
2511: if (ti != null) {
2512: //System.out.println("TreeItem is : " + ti);
2513: } else {
2514: //System.out.println("TreeItem is null");
2515: return;
2516: }
2517: //System.out.println("In delNode.........");
2518: //System.out.println("pChild is : " + pChild.getText());
2519: //System.out.println("pChild index is : " + ti.getIndex());
2520: if (ti.getIndex() > -1) {
2521: //System.out.println("Using delNode from List Box...");
2522: delNodeFromListBox(pChild, pUpdate);
2523: ti.detachFromTree();
2524: } else {
2525: //System.out.println("Using Bina's deleteItem...");
2526: deleteItem(ti);
2527: }
2528:
2529: // update();
2530:
2531: return;
2532: }
2533:
2534: //////BINA
2535:
2536: public void delParentNode(Node parentNode, boolean bUpdate) {
2537: TreeItem ti = (TreeItem) parentNode;
2538: delNodeFromListBox(parentNode, bUpdate);
2539: ti.detachFromTree();
2540: //update();
2541: //updateScrollbar();
2542: return;
2543: }
2544:
2545: /**
2546: * deletes the item from the tree
2547: * @param item the TreeItem to delete
2548: * @return the item deleted as type TreeItem
2549: */
2550: public void deleteItem(TreeItem item) {
2551: if (item == null || isRoot(item))
2552: return;
2553:
2554: //recursively delete all the children.
2555: TreeItem childItem = item.getChild(0);
2556: if (childItem != null) {
2557: deleteItem(childItem);
2558: }
2559: //System.out.println("Remove Children from List Ctrl");
2560: removeChildrenFromListCtrl((Node) item, item.getIndex());
2561: ///Sept8th 1999
2562: delNodeFromListBox((Node) item, false); // cahnge to false by bina
2563: item.detachFromTree();
2564: return;
2565: }
2566:
2567: /* /public void update()
2568: {
2569: paint(getGraphics());
2570: }/ */
2571:
2572: public void setTextColor(String txtHiC, String txtHiTxtC,
2573: String txtTxtC) {
2574: /* txtBgHighColor - is the background color of the highlighted text
2575: txtHiTxtColor - text color of highlighted text.
2576: txtTxtColor - is the color of text in the TextComponent object.
2577: */
2578:
2579: txtBgHighColor = txtHiC;
2580: txtHiTxtColor = txtHiTxtC;
2581: txtTxtColor = txtTxtC;
2582: }
2583:
2584: /// return the color read from the properties file.
2585: /// check if its a valid color else default to
2586: /// whatever is passed as the default color.
2587:
2588: static Color getTreeColor(String userColor, Color defColor) {
2589:
2590: try {
2591: return Color.decode(userColor);
2592: } catch (Exception e) {
2593: return defColor;
2594: }
2595:
2596: }
2597:
2598: //// END BINA
2599:
2600: }
|