0001: /**
0002: * Caption: Zaval Java Resource Editor
0003: * $Revision: 0.37 $
0004: * $Date: 2002/03/28 9:24:42 $
0005: *
0006: * @author: Victor Krapivin
0007: * @version: 1.3
0008: *
0009: * Zaval JRC Editor is a visual editor which allows you to manipulate
0010: * localization strings for all Java based software with appropriate
0011: * support embedded.
0012: *
0013: * For more info on this product read Zaval Java Resource Editor User's Guide
0014: * (It comes within this package).
0015: * The latest product version is always available from the product's homepage:
0016: * http://www.zaval.org/products/jrc-editor/
0017: * and from the SourceForge:
0018: * http://sourceforge.net/projects/zaval0002/
0019: *
0020: * Contacts:
0021: * Support : support@zaval.org
0022: * Change Requests : change-request@zaval.org
0023: * Feedback : feedback@zaval.org
0024: * Other : info@zaval.org
0025: *
0026: * Copyright (C) 2001-2002 Zaval Creative Engineering Group (http://www.zaval.org)
0027: *
0028: * This program is free software; you can redistribute it and/or
0029: * modify it under the terms of the GNU General Public License
0030: * (version 2) as published by the Free Software Foundation.
0031: *
0032: * This program is distributed in the hope that it will be useful,
0033: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0034: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0035: * GNU General Public License for more details.
0036: *
0037: * You should have received a copy of the GNU General Public License
0038: * along with this program; if not, write to the Free Software
0039: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0040: *
0041: */package org.zaval.awt;
0042:
0043: import org.zaval.awt.peer.*;
0044:
0045: import java.awt.*;
0046: import java.awt.image.*;
0047: import java.util.*;
0048:
0049: public class SymTree extends Panel implements ScrollArea, ScrollObject {
0050: public static final int SEL_CHANGED = 1006; //selection changed event
0051:
0052: private TreeNode selectedNode; // highlighted node
0053:
0054: private Scrollbar sbV; // vertical scrollbar
0055: private Scrollbar sbH; // vertical scrollbar
0056:
0057: private Color bgHighlightColor = Color.gray; // selection bg color
0058: private Color fgHighlightColor = Color.white; // selection fg color
0059: private int viewHeight = 300;
0060: private int viewWidth = 300; // pixel size of tree display
0061:
0062: private final int cellSize = 16; // size of node image
0063: private int clickSize = 8; // size of mouse toggle (plus or minus)
0064: private int textInset = 6; // left margin for text
0065: private int textBaseLine = 3; // position of font baseline from bottom of cell
0066: private FontMetrics fm; // current font metrics
0067: private ScrollController sm;
0068:
0069: protected Image im1; // offscreen image
0070: protected Graphics g1 = null; // offscreen graphics context
0071: protected boolean noChoice = false;
0072:
0073: private int posx = 0, posy = 0;
0074: private Dimension scrollInsets = new Dimension(10, 0);
0075: private LevelTree ltree = null;
0076: private ScrollLayout sl = new ScrollLayout();
0077:
0078: private static final int DELETE = 127;
0079: private static final int INSERT = 1025;
0080:
0081: public SymTree() {
0082: super .setLayout(sl);
0083:
0084: add("East", sbV = new Scrollbar(Scrollbar.VERTICAL));
0085: add("South", sbH = new Scrollbar(Scrollbar.HORIZONTAL));
0086: add("Stubb", new StubbComponent());
0087:
0088: sbV.hide();
0089: sbH.hide();
0090: sbV.setBackground(Color.lightGray);
0091: sbH.setBackground(Color.lightGray);
0092: sm = new ScrollController(this , this );
0093: ltree = new LevelTree();
0094: }
0095:
0096: public SymTree(TreeNode head) {
0097: this ();
0098: selectedNode = ltree.getRootNode();
0099: }
0100:
0101: public void setBackground(Color c) {
0102: super .setBackground(c);
0103: invalidate();
0104: }
0105:
0106: public void setForeground(Color c) {
0107: super .setForeground(c);
0108: invalidate();
0109: }
0110:
0111: // Insert a new node relative to a node in the tree.
0112: // position = CHILD inserts the new node as a child of the node
0113: // position = NEXT inserts the new node as the next sibling
0114: // position = PREVIOUS inserts the new node as the previous sibling
0115: public void insert(TreeNode newNode, TreeNode relativeNode,
0116: int position) {
0117: ltree.insert(newNode, relativeNode, position);
0118: }
0119:
0120: public TreeNode getRootNode() {
0121: return ltree.getRootNode();
0122: }
0123:
0124: public int getCount() {
0125: return ltree.getCount();
0126: }
0127:
0128: public boolean exists(TreeNode node) {
0129: return ltree.exists(node);
0130: }
0131:
0132: public boolean exists(String s) {
0133: return ltree.exists(s);
0134: }
0135:
0136: private void resetVector() {
0137: ltree.resetVector();
0138: }
0139:
0140: // ========================================================================
0141: // This functions will be added on caf
0142: // ========================================================================
0143:
0144: public TreeNode getNode(String name) {
0145: return ltree.getNode(name);
0146: }
0147:
0148: // ========================================================================
0149:
0150: public boolean insertChild(String name, String addname) {
0151: boolean b = insertChild(name, addname, null, null);
0152: validate2();
0153: return b;
0154: }
0155:
0156: // ========================================================================
0157:
0158: public boolean insertChild(String name, String addname, String im1,
0159: String im2) {
0160: boolean b = ltree.insertChild(name, addname, im1, im2);
0161: validate2();
0162: return b;
0163: }
0164:
0165: // ========================================================================
0166:
0167: public boolean insertNext(String name, String addname) {
0168: boolean b = insertNext(name, addname, null, null);
0169: validate2();
0170: return b;
0171: }
0172:
0173: // ========================================================================
0174:
0175: public boolean insertNext(String name, String addname, String im1,
0176: String im2) {
0177: boolean b = ltree.insertNext(name, addname, im1, im2);
0178: validate2();
0179: return b;
0180: }
0181:
0182: // ========================================================================
0183:
0184: public boolean insertRoot(String addname) {
0185: boolean b = insertRoot(addname, null, null);
0186: validate2();
0187: return b;
0188: }
0189:
0190: // ========================================================================
0191:
0192: public boolean insertRoot(String addname, String im1, String im2) {
0193: boolean b = ltree.insertRoot(addname, im1, im2);
0194: validate2();
0195: return b;
0196: }
0197:
0198: // ========================================================================
0199:
0200: public boolean setImages(String name, String img1, String img2) {
0201: return setImageOpen(name, img1) && setImageClose(name, img2);
0202: }
0203:
0204: // ========================================================================
0205:
0206: public boolean setImageOpen(String name, String img) {
0207: return ltree.setImageOpen(name, img);
0208: }
0209:
0210: // ========================================================================
0211:
0212: public boolean setImageClose(String name, String img) {
0213: return ltree.setImageClose(name, img);
0214: }
0215:
0216: // ========================================================================
0217:
0218: public boolean changeText(String name, String newname) {
0219: return ltree.changeText(name, newname);
0220: }
0221:
0222: // ========================================================================
0223:
0224: public boolean selectNode(String name) {
0225: if (getNode(name) == null)
0226: return false;
0227: TreeNode f = getNode(name);
0228: if (isHidden(name))
0229: return false;
0230: return selectNode(f);
0231: }
0232:
0233: public boolean selectNode(TreeNode tn) {
0234: selectedNode = tn;
0235: int viewCount = getViewCount();
0236: int index = getIndex(selectedNode);
0237: if (index == -1)
0238: index = ltree.e.indexOf(selectedNode);
0239: if (index > viewCount - 1)
0240: index = viewCount - 1;
0241: checkSelection(index);
0242: return true;
0243: }
0244:
0245: public boolean selectNodeAndOpen(String name) {
0246: if (!selectNode(name))
0247: return false;
0248: TreeNode x = selectedNode.parent;
0249: while (x != null) {
0250: x.expand();
0251: x = x.parent;
0252: }
0253: validate2();
0254: return true;
0255: }
0256:
0257: public void setNamesDelim(String delim) {
0258: ltree.setNamesDelim(delim);
0259: }
0260:
0261: public TreeNode findNode(String name, String d) {
0262: return ltree.findNode(name, d);
0263: }
0264:
0265: // ========================================================================
0266: // end add
0267: // ========================================================================
0268:
0269: // add new node to level 0
0270: public void append(TreeNode newNode) {
0271: ltree.append(newNode);
0272: if (getRootNode() == null)
0273: selectedNode = getRootNode();
0274: }
0275:
0276: public void remove(String s) {
0277: remove(getNode(s));
0278: }
0279:
0280: public void removeSelected() {
0281: if (selectedNode != null) {
0282: remove(selectedNode);
0283: }
0284: }
0285:
0286: public void remove(TreeNode node) {
0287: int viewCount = getViewCount();
0288: if (node == selectedNode) {
0289: int index = getIndex(selectedNode);
0290:
0291: if (index == -1)
0292: index = ltree.e.indexOf(selectedNode);
0293:
0294: if (index > viewCount - 1)
0295: index = viewCount - 1;
0296:
0297: if (index > 0) {
0298: changeSelection(
0299: (TreeNode) ltree.v.elementAt(index - 1),
0300: index - 1);
0301: } else if (viewCount > 0) {
0302: try {
0303: changeSelection((TreeNode) ltree.v.elementAt(1), 1);
0304: } catch (Exception e) {
0305: changeSelection((TreeNode) ltree.v.elementAt(0), 0);
0306: }
0307: }
0308: }
0309: ltree.remove(node);
0310: }
0311:
0312: // -----------------------------------------
0313: // --------- event related methods ---------
0314: // -----------------------------------------
0315:
0316: protected boolean checkScrolls() {
0317: if (!isVisible())
0318: return false;
0319:
0320: int viewCount = getViewCount(); //getViewCount2();
0321: Dimension d = getSASize(); //size();
0322: boolean b = false;
0323:
0324: int hh = sm.getMaxHorScroll();
0325: int hv = sm.getMaxVerScroll();
0326:
0327: int w = d.width - (hv > 0 ? ScrollController.SCROLL_SIZE : 0);
0328: int h = d.height - (hh > 0 ? ScrollController.SCROLL_SIZE : 0);
0329:
0330: if (hv > 0) {
0331: int hl = viewCount - h / cellSize
0332: + ((h % cellSize > 0) ? 1 : 0);
0333: hl += scrollInsets.height;
0334: if (hl <= 1)
0335: hl = 2;
0336: int v = sbV.getValue();
0337: sbV.setValues(v, 0, 0, hl);
0338: if (!sbV.isVisible())
0339: b = true;
0340: sbV.show();
0341: } else {
0342: if (sbV.isVisible()) {
0343: sbV.hide();
0344: sbV.setValue(0);
0345: posy = 0;
0346: b = true;
0347: }
0348: }
0349:
0350: if (sm.getMaxHorScroll() > 0) {
0351: int h1 = getMaxWidth() - w + scrollInsets.width;
0352: int v = sbH.getValue();
0353:
0354: if (h1 <= 1)
0355: h1 = 2;
0356: sbH.setValues(v, 0, 0, h1);
0357: if (!sbH.isVisible())
0358: b = true;
0359: sbH.show();
0360: } else {
0361: if (sbH.isVisible()) {
0362: sbH.setValue(0);
0363: sbH.hide();
0364: posx = 0;
0365: b = true;
0366: }
0367: }
0368: return b;
0369: }
0370:
0371: public void reshape(int x, int y, int w, int h) {
0372: super .reshape(x, y, w, h);
0373: validate2();
0374: }
0375:
0376: public boolean handleEvent(Event event) {
0377: if (scroll(event))
0378: return true;
0379:
0380: if (event.key > 0 && selectedNode != null) {
0381: if ((event.key == 45) && (selectedNode.isExpanded())) {
0382: toggleEvent(selectedNode, 0);
0383: return true;
0384: }
0385:
0386: if ((event.key == 43) && isExpandable(selectedNode)
0387: && (!selectedNode.isExpanded())) {
0388: toggleEvent(selectedNode, 1);
0389: return true;
0390: }
0391: }
0392: return (super .handleEvent(event));
0393: }
0394:
0395: public String getCaption(String name) {
0396: TreeNode t = getNode(name);
0397: if (t == null)
0398: return null;
0399: return t.getCaption();
0400: }
0401:
0402: int mouse_down = 0;
0403: long time = 0;
0404:
0405: public boolean mouseUp(Event event, int x, int y) {
0406: if (time == 0)
0407: time = System.currentTimeMillis();
0408: long tt = System.currentTimeMillis();
0409: long dt = tt - time;
0410: time = tt;
0411: if (event.clickCount == 0 && dt < 300)
0412: event.clickCount = 2;
0413:
0414: if (event.modifiers == 4)
0415: return super .mouseUp(event, x, y);
0416: requestFocus();
0417:
0418: mouse_down = 1;
0419: boolean[] flags = new boolean[1];
0420: boolean b = changeSelection(event, x, y, true, flags);
0421: if (!flags[0])
0422: time -= 400;
0423:
0424: if (flags[0] && event.clickCount == 2) {
0425: Event e = new Event(event.target, 9999, event.arg);
0426: getParent().postEvent(e);
0427: }
0428: return super .mouseUp(event, x, y);
0429: }
0430:
0431: public boolean keyDown(Event event, int key) {
0432: requestFocus();
0433: if (selectedNode == null)
0434: return super .keyDown(event, key);
0435: int index = getIndex(selectedNode);
0436: int viewCount = getViewCount();
0437: TreeNode f = null;
0438: mouse_down = 0;
0439: switch (key) {
0440: case 10:
0441: sendActionEvent(event);
0442: break;
0443: case Event.UP:
0444: if (index > 0) {
0445: index--;
0446: changeSelection((TreeNode) ltree.v.elementAt(index),
0447: index);
0448: sendActionEvent(event);
0449: }
0450: break;
0451: case Event.DOWN:
0452: if (index < viewCount - 1) {
0453: index++;
0454: changeSelection((TreeNode) ltree.v.elementAt(index),
0455: index);
0456: sendActionEvent(event);
0457: }
0458: break;
0459: case Event.RIGHT: {
0460: if (!selectedNode.isExpanded()) {
0461: toggleEvent(selectedNode, 1);
0462: } else if (selectedNode.child != null) {
0463: f = selectedNode.child;
0464: while (f != null && f.hidden)
0465: f = f.sibling;
0466: if (f != null) {
0467: changeSelection(f, index);
0468: sendActionEvent(event);
0469: }
0470: }
0471: }
0472: break;
0473: case Event.LEFT: {
0474: if (selectedNode.isExpanded())
0475: toggleEvent(selectedNode, 0);
0476: else if (selectedNode.parent != null
0477: && selectedNode.parent != getRootNode()
0478: && !selectedNode.parent.hidden) {
0479: changeSelection(selectedNode.parent, index);
0480: sendActionEvent(event);
0481: }
0482: }
0483: break;
0484: case Event.PGUP: {
0485: scrollPages(-1);
0486: sendActionEvent(event);
0487: }
0488: break;
0489: case Event.PGDN: {
0490: scrollPages(1);
0491: sendActionEvent(event);
0492: }
0493: break;
0494: case Event.HOME: {
0495: f = (TreeNode) ltree.v.elementAt(0);
0496: changeSelection(f, 0);
0497: sendActionEvent(event);
0498: }
0499: break;
0500: case Event.END: {
0501: f = (TreeNode) ltree.v.elementAt(ltree.v.size() - 1);
0502: changeSelection(f, ltree.v.size() - 1);
0503: sendActionEvent(event);
0504: }
0505: break;
0506: case INSERT: {
0507: Event e = new Event(event.target, 9999, event.arg);
0508: getParent().postEvent(e);
0509: }
0510: break;
0511: case DELETE: {
0512: Event e = new Event(event.target, 9991, event.arg);
0513: getParent().postEvent(e);
0514: }
0515: break;
0516: }
0517: return super .keyDown(event, key); //false;
0518: }
0519:
0520: private void sendActionEvent(Event event) {
0521: int id = event.id;
0522: Object arg = event.arg;
0523: event.id = Event.ACTION_EVENT;
0524: event.arg = new String(selectedNode.getText());
0525: postEvent(event);
0526: event.id = id;
0527: event.arg = arg;
0528: repaint();
0529: }
0530:
0531: public TreeNode getSelectedNode() {
0532: return selectedNode;
0533: }
0534:
0535: public String getSelectedText() {
0536: if (selectedNode == null)
0537: return null;
0538: return selectedNode.getText();
0539: }
0540:
0541: public TreeNode getNode(int x, int y) {
0542: int index = ((Math.abs(posy) + y) / cellSize);
0543: for (int i = 0; i <= index && i < ltree.v.size(); ++i) {
0544: TreeNode tmpNode = (TreeNode) ltree.v.elementAt(i);
0545: if (tmpNode.getHide())
0546: ++index;
0547: }
0548: if (index >= ltree.v.size())
0549: return null;
0550: return (TreeNode) ltree.v.elementAt(index);
0551: }
0552:
0553: public boolean changeSelection(Event evt, int x, int y,
0554: boolean isToggle, boolean[] flags) {
0555: requestFocus();
0556:
0557: Dimension d = size();
0558: flags[0] = false;
0559:
0560: int viewCount = d.height / cellSize;
0561: int index = ((Math.abs(posy) + y) / cellSize);
0562: noChoice = false;
0563:
0564: int index2 = y / cellSize;
0565: if (index2 > viewCount - 1) {
0566: noChoice = true;
0567: return false; //clicked below the last node
0568: }
0569:
0570: for (int i = 0; i <= index && i < ltree.v.size(); ++i) {
0571: TreeNode tmpNode = (TreeNode) ltree.v.elementAt(i);
0572: if (tmpNode.getHide())
0573: ++index;
0574: }
0575:
0576: if (index >= ltree.v.size())
0577: return false;
0578:
0579: TreeNode oldNode = selectedNode;
0580: TreeNode newNode = (TreeNode) ltree.v.elementAt(index);
0581: int newDepth = newNode.getDepth();
0582:
0583: // check click in place plus/minus
0584:
0585: if (isExpandable(newNode)) {
0586: Rectangle rec = new Rectangle(posx + cellSize
0587: * (newDepth - 1) + cellSize / 4, posy
0588: + getIndex(newNode) * cellSize + clickSize / 2,
0589: clickSize, clickSize);
0590:
0591: if ((rec.inside(x, y)) && (isToggle)) {
0592: toggleEvent(newNode, newNode.isExpanded() ? 1 : 0);
0593: return false;
0594: }
0595: }
0596:
0597: // check max right position
0598:
0599: String text = (newNode.caption == null) ? newNode.text
0600: : newNode.caption;
0601: int x1 = posx + ((newDepth - 1) * (cellSize)) + cellSize
0602: + textInset;
0603: int x2 = x1 + fm.stringWidth(text) + 4;
0604: FontMetrics fm = g1.getFontMetrics();
0605: if (newNode.getImage() != null) {
0606: x2 = x2 + fm.getHeight();
0607: // x1 = x1 - fm.getHeight();
0608: }
0609:
0610: if (newNode.getIndicator() != null)
0611: x2 = x2 + fm.getHeight();
0612:
0613: if ((x > x2) || (x < x1)) {
0614: noChoice = true;
0615: return false;
0616: }
0617:
0618: if (newNode == oldNode)
0619: flags[0] = true;
0620: changeSelection(newNode, index);
0621:
0622: // check for toggle box click
0623: // todo: make it a bit bigger
0624: Rectangle toggleBox = new Rectangle(posx + cellSize * newDepth
0625: + cellSize / 4,
0626: posy + index * cellSize + clickSize / 2, clickSize,
0627: clickSize);
0628:
0629: if ((evt.modifiers != 4) && (isToggle) && (newNode == oldNode)) {
0630: toggleEvent(newNode, newNode.isExpanded() ? 0 : 1);
0631: return false;
0632: }
0633:
0634: if (newNode.getImage() != null)
0635: toggleBox.x -= fm.getHeight();
0636: if (newNode.getIndicator() != null)
0637: toggleBox.x -= fm.getHeight();
0638:
0639: if (!toggleBox.inside(x, y))
0640: sendActionEvent(evt);
0641:
0642: return false;
0643: }
0644:
0645: private void validate2() {
0646: resetVector();
0647: if (checkScrolls())
0648: invalidate();
0649: validate();
0650: repaint();
0651: }
0652:
0653: private int getIndex(TreeNode node) {
0654: return ltree.v.indexOf(node);
0655: }
0656:
0657: private void changeSelection(TreeNode node, int index) {
0658: if (selectedNode == null) {
0659: if (node != null)
0660: selectedNode = node;
0661: else
0662: return;
0663: }
0664:
0665: TreeNode oldNode = selectedNode;
0666: selectedNode = node;
0667:
0668: int y = index * cellSize;
0669: drawNodeText(oldNode, y, true);
0670: drawNodeText(node, y, true);
0671:
0672: checkSelection(index);
0673: }
0674:
0675: protected void checkSelection(int index) {
0676: if (!sbV.isVisible() || index < 0)
0677: return;
0678: int y = index * cellSize;
0679:
0680: if (posy != 0 && y < Math.abs(posy)) {
0681: int maxIndex = Math.abs(posy) / cellSize;
0682: int decIndex = maxIndex - index;
0683: int dy = decIndex * cellSize;
0684: vscroll(-decIndex);
0685: return;
0686: }
0687:
0688: y += (posy + cellSize);
0689: int k = viewHeight;
0690: if (sbH.isVisible())
0691: k -= ScrollController.SCROLL_SIZE;
0692: if (y > k) {
0693: int dy = (y - k);
0694: int incIndex = dy / cellSize;
0695: if (dy % cellSize > 0)
0696: incIndex++;
0697: vscroll(incIndex);
0698: return;
0699: }
0700: }
0701:
0702: public void paint(Graphics g) {
0703: redraw();
0704: if (im1 != null)
0705: g.drawImage(im1, 0, 0, this );
0706:
0707: g.setColor(Color.gray);
0708: Dimension d = size();
0709: g.drawRect(0, 0, d.width - 1, d.height - 1);
0710: }
0711:
0712: public void redraw() {
0713: resetVector();
0714: drawTree();
0715: }
0716:
0717: public void drawTree() {
0718: Dimension d = size();
0719: if ((d.width != viewWidth) || (d.height != viewHeight)
0720: || g1 == null) {
0721: if (d.width * d.height <= 0)
0722: return;
0723:
0724: im1 = createImage(d.width, d.height);
0725: if (g1 != null) {
0726: g1.dispose();
0727: g1 = null;
0728: }
0729: g1 = im1.getGraphics();
0730: viewWidth = d.width;
0731: viewHeight = d.height;
0732: }
0733:
0734: Font f = getFont(); // unix version might not provide a default font
0735:
0736: //Make certain there is a font
0737: if (f == null) {
0738: f = new Font("TimesRoman", Font.PLAIN, 14);
0739: g1.setFont(f);
0740: setFont(f);
0741: }
0742:
0743: //Make certain the graphics object has a font (Mac doesn't seem to)
0744: if (f != null)
0745: if (g1.getFont() == null)
0746: g1.setFont(f);
0747:
0748: int ww = viewWidth
0749: - ((sbV.isVisible()) ? ScrollController.SCROLL_SIZE : 0);
0750: int hh = viewHeight
0751: - ((sbH.isVisible()) ? ScrollController.SCROLL_SIZE : 0);
0752:
0753: fm = g1.getFontMetrics();
0754: g1.setColor(getBackground());
0755: g1.fillRect(0, 0, viewWidth, viewHeight); // clear image
0756:
0757: int lastOne = ltree.v.size();
0758: int skipCount = 0;
0759: int viewCount = getViewCount();//getViewCount2();
0760: for (int i = 0; i < lastOne; ++i) {
0761: TreeNode node = null;
0762: // This block is better than synchronization for every call to LevelTree
0763: try {
0764: node = (TreeNode) ltree.v.elementAt(i);
0765: } catch (Exception e) {
0766: }
0767:
0768: if (node == null) {
0769: g1.dispose();
0770: g1 = null;
0771: break;
0772: }
0773:
0774: int x = posx + cellSize * (node.depth - 1);
0775: int y = posy + (i - skipCount) * cellSize;
0776:
0777: // draw lines
0778: g1.setColor(getForeground());
0779:
0780: // draw vertical sibling line
0781: TreeNode sb = getSibling(node);
0782: if (sb != null) {
0783: int k = getIndex(sb) - getIndex(node);
0784: //if (k > lastOne) k = lastOne;
0785: drawDotLine(x + cellSize / 2, y + cellSize / 2, x
0786: + cellSize / 2, y + cellSize / 2 + k * cellSize);
0787: }
0788:
0789: // draw vertical child lines
0790: if (node.isExpanded()) {
0791: int xx = x + cellSize + cellSize / 2;
0792: drawDotLine(xx, y + cellSize - 2, xx, y + cellSize
0793: + cellSize / 2);
0794: }
0795:
0796: // draw node horizontal line
0797: g1.setColor(getForeground());
0798: int xxx = x + cellSize / 2;
0799: drawDotLine(xxx, y + cellSize / 2, xxx + cellSize / 2 + 10,
0800: y + cellSize / 2);
0801:
0802: // draw toggle box
0803: if (isExpandable(node)) {
0804: //int xx = cellSize*(node.depth) + cellSize/4;
0805: int xx = x + clickSize / 2;
0806:
0807: g1.setColor(getBackground());
0808: g1
0809: .fillRect(xx, y + clickSize / 2, clickSize,
0810: clickSize);
0811: g1.setColor(getForeground());
0812: g1
0813: .drawRect(xx, y + clickSize / 2, clickSize,
0814: clickSize);
0815: // cross hair
0816: g1.drawLine(xx + 2, y + cellSize / 2, xx + clickSize
0817: - 2, y + cellSize / 2);
0818:
0819: if (!(isExpanded(node))) {
0820: g1.drawLine(xx + clickSize / 2, y + clickSize / 2
0821: + 2, xx + clickSize / 2, y + clickSize / 2
0822: + clickSize - 2);
0823: }
0824: }
0825:
0826: // draw node image
0827: Image nodeImage = isExpanded(node) ? node
0828: .getExpandedImage() : node.getCollapsedImage();
0829: if (nodeImage != null) {
0830: g1.drawImage(nodeImage, x + cellSize, y, this );
0831: }
0832:
0833: // draw node indicator
0834: Image nodeInd = node.getIndicator();
0835: if (nodeInd != null) {
0836: int dx = ((nodeImage == null) ? cellSize : 2 * cellSize) + 2;
0837: int dy = (cellSize - nodeInd.getHeight(this )) / 2 + 1;
0838:
0839: g1.drawImage(nodeInd, x + dx, y + dy, this );
0840: }
0841:
0842: // draw node text
0843: if (node.text != null)
0844: drawNodeText(node, y, node == selectedNode);
0845: }
0846: }
0847:
0848: private TreeNode getSibling(TreeNode node) {
0849: TreeNode tn = node.sibling;
0850: while (tn != null && tn.hidden)
0851: tn = tn.sibling;
0852: return tn;
0853: }
0854:
0855: private int getMaxWidth() {
0856: int max = 0;
0857: for (int i = 0; i < ltree.v.size(); i++) {
0858: TreeNode node = (TreeNode) ltree.v.elementAt(i);
0859: if (node.getHide())
0860: continue;
0861: String text = node.caption == null ? node.text
0862: : node.caption;
0863: int depth = node.depth;
0864:
0865: int stringWidth = ((depth - 1) * cellSize) + cellSize
0866: + textInset - 1
0867: + ((fm == null) ? 0 : fm.stringWidth(text));
0868: if (node.getImage() != null && fm != null)
0869: stringWidth += fm.getHeight();
0870: if (node.getIndicator() != null && fm != null)
0871: stringWidth += fm.getHeight();
0872: if (stringWidth > max)
0873: max = stringWidth;
0874: }
0875: return max;
0876: }
0877:
0878: private void drawNodeText(TreeNode node, int yPosition,
0879: boolean eraseBackground) {
0880: String text = node.caption == null ? node.text : node.caption;
0881: Color fg = null;
0882: Color bg = null;
0883: int textOffset = getTextPos(node);
0884:
0885: if (node == selectedNode) {
0886: fg = fgHighlightColor;
0887: bg = bgHighlightColor;
0888: } else {
0889: fg = getForeground();
0890: bg = getBackground();
0891: }
0892:
0893: int stringWidth = textOffset - 1 + fm.stringWidth(text) - posx;
0894: if (eraseBackground) {
0895: g1.setColor(bg);
0896: if (styleMark != RECT_MARK) {
0897: g1.fillRect(textOffset - 1, yPosition + 1, fm
0898: .stringWidth(text) + 4, cellSize - 1);
0899: g1.setColor(fg);
0900: } else {
0901: g1.setColor(Color.black);
0902: g1.drawRect(textOffset - 1, yPosition + 1, fm
0903: .stringWidth(text) + 4, cellSize - 2);
0904: }
0905: } else {
0906: g1.setColor(fg);
0907: }
0908:
0909: g1.drawString(text, textOffset, yPosition + cellSize
0910: - textBaseLine);
0911: }
0912:
0913: private void drawDotLine(int x0, int y0, int x1, int y1) {
0914: if (y0 == y1) {
0915: for (int i = x0; i < x1; i += 2)
0916: g1.drawLine(i, y0, i, y1);
0917: } else {
0918: for (int i = y0; i < y1; i += 2)
0919: g1.drawLine(x0, i, x1, i);
0920: }
0921: }
0922:
0923: public void setTreeStructure(String s[]) {
0924: ltree.setTreeStructure(s);
0925: selectedNode = null;
0926: invalidate();
0927: }
0928:
0929: public String[] getTreeStructure() {
0930: return ltree.getTreeStructure();
0931: }
0932:
0933: public Dimension preferredSize() {
0934: FontMetrics fm = getFontMetrics(getFont());
0935: return new Dimension(175, Math.min(ltree.v.size()
0936: * fm.getHeight(), 500));
0937: }
0938:
0939: public Dimension minimumSize() {
0940: return preferredSize();
0941: }
0942:
0943: public void setLayout(LayoutManager lm) {
0944: }
0945:
0946: public void setResolver(ImageResolver imgres) {
0947: ltree.setResolver(imgres);
0948: }
0949:
0950: public void show(String name) {
0951: TreeNode t = getNode(name);
0952: if (t != null)
0953: t.setHide(false);
0954: }
0955:
0956: public void hide(String name) {
0957: TreeNode t = getNode(name);
0958: if (t != null)
0959: t.setHide(true);
0960: else
0961: return;
0962:
0963: if (t == selectedNode && fm != null) {
0964: correctSelect(t.parent);
0965: return;
0966: }
0967:
0968: if (!isExpandable(t.parent)) {
0969: t.parent.collapse();
0970: if (fm != null)
0971: correctSelect(t.parent);
0972: }
0973:
0974: validate2();
0975: }
0976:
0977: private void correctSelect(TreeNode n) {
0978: resetVector();
0979: if (selectedNode != null && ltree.v.indexOf(selectedNode) < 0) {
0980: changeSelection(n, ltree.v.indexOf(n));
0981: Event event = new Event(this , 0, null);
0982: sendActionEvent(event);
0983: }
0984: }
0985:
0986: public void setCaption(String name, String caption) {
0987: TreeNode t = getNode(name);
0988: if (t == null)
0989: return;
0990: t.setCaption(caption);
0991: validate2();
0992: }
0993:
0994: private boolean isExpandable(TreeNode node) {
0995: int jjk;
0996:
0997: if (!node.isExpandable())
0998: return false;
0999: if (node.child == null)
1000: return false;
1001: node = node.child;
1002:
1003: if (!node.getHide())
1004: return true;
1005: while (node.sibling != null) {
1006: node = node.sibling;
1007: if (!node.getHide())
1008: return true;
1009: }
1010: return false;
1011: }
1012:
1013: public void openToNode(String name) {
1014: TreeNode t = getNode(name);
1015: for (; t != null; t = t.parent)
1016: if (t.isExpandable() && !t.isExpanded())
1017: t.toggle();
1018: validate2();
1019: }
1020:
1021: public void openNode(String name) {
1022: TreeNode t = getNode(name);
1023: if (t == null || t.isExpanded())
1024: return;
1025: if (t.isExpandable() && !t.isExpanded())
1026: t.toggle();
1027: validate2();
1028: }
1029:
1030: public void closeNode(String name) {
1031: TreeNode t = getNode(name);
1032: if (t == null)
1033: return;
1034: if (t.isExpandable() && t.isExpanded()) {
1035: t.toggle();
1036: correctSelect(t);
1037: }
1038: validate2();
1039: }
1040:
1041: public boolean isHidden(String name) {
1042: TreeNode t = getNode(name);
1043: if (t == null)
1044: return false;
1045: while (t.parent != null)
1046: if (t.getHide())
1047: return true;
1048: else
1049: t = t.parent;
1050: return false;
1051: }
1052:
1053: public void expandAll() {
1054: ltree.expandAll();
1055: validate2();
1056: }
1057:
1058: public void collapseAll() {
1059: ltree.collapseAll();
1060: validate2();
1061: }
1062:
1063: // ========================================================================
1064:
1065: public TreeNode getNode2(String name) {
1066: return ltree.getNode2(name);
1067: }
1068:
1069: // ========================================================================
1070:
1071: protected int getNumChild(TreeNode parent) {
1072: return ltree.getNumChild(parent);
1073: }
1074:
1075: // ========================================================================
1076:
1077: protected TreeNode getChild(TreeNode parent, String nameChild) {
1078: return ltree.getChild(parent, nameChild);
1079: }
1080:
1081: // ========================================================================
1082:
1083: public TreeNode[] enumChild(String name) {
1084: return ltree.enumChild(name);
1085: }
1086:
1087: // ========================================================================
1088:
1089: public TreeNode[] enumChild(TreeNode tn) {
1090: return ltree.enumChild(tn);
1091: }
1092:
1093: // ========================================================================
1094:
1095: public static int NONE_FRAME = 0;
1096: public static int LINE_FRAME = 1;
1097: private int styleFrame = 1;
1098:
1099: public void styleFrame(int style) {
1100: styleFrame = style;
1101: repaint();
1102: }
1103:
1104: public static int RECT_MARK = 0;
1105: public static int FILLRECT_MARK = 1;
1106: private int styleMark = 1;
1107:
1108: public void styleMark(int style) {
1109: styleMark = style;
1110: repaint();
1111: }
1112:
1113: public void insertNode(String top, String news, String before) {
1114: ltree.insertNode(top, news, before);
1115: repaint();
1116: }
1117:
1118: private boolean isExpanded(TreeNode node) {
1119: if (!node.isExpanded())
1120: return false;
1121: TreeNode c = node.child;
1122: while (c != null) {
1123: if (!c.getHide())
1124: return true;
1125: c = c.sibling;
1126: }
1127: return false;
1128: }
1129:
1130: public int getViewCount() {
1131: return ltree.getViewCount();
1132: }
1133:
1134: public Dimension getSASize() {
1135: return sl.getAreaSize(this );
1136: }
1137:
1138: public Scrollbar getVBar() {
1139: return sbV;
1140: }
1141:
1142: public Scrollbar getHBar() {
1143: return sbH;
1144: }
1145:
1146: public Point getSOLocation() {
1147: return null;
1148: }
1149:
1150: public void setSOLocation(int x, int y) {
1151: }
1152:
1153: public Dimension getSOSize() {
1154: int v = getViewCount();//getViewCount2();
1155: Dimension r = new Dimension(getMaxWidth(), 0);
1156: r.height = v * cellSize;
1157: return r;
1158: }
1159:
1160: public Component getScrollComponent() {
1161: return null;
1162: }
1163:
1164: public Rectangle getVisibleArea(Container c) {
1165: Rectangle r = new Rectangle();
1166: return r;
1167: }
1168:
1169: public boolean gotFocus(Event e, Object o) {
1170: bgHighlightColor = Color.blue;
1171: repaint();
1172: return true;
1173: //return super.gotFocus(e, o);
1174: }
1175:
1176: public void setIndicator(String name, String image) {
1177: TreeNode t = getNode(name);
1178: if (t == null)
1179: return;
1180: t.setIndicator(image);
1181: }
1182:
1183: public boolean lostFocus(Event e, Object o) {
1184: bgHighlightColor = Color.gray;
1185: repaint();
1186: return super .lostFocus(e, o);
1187: }
1188:
1189: private void toggleEvent(TreeNode n, int i) {
1190: if (!isExpandable(n))
1191: return;
1192: getParent().postEvent(
1193: new Event(this , 0, 8888, 0, 0, i, 0, n.getText()));
1194: n.toggle();
1195: correctSelect(n);
1196: validate2();
1197: }
1198:
1199: protected boolean scrollPages(int pages) {
1200: int index = getIndex(selectedNode);
1201: int height = viewHeight
1202: - ((sbH.isVisible()) ? ScrollController.SCROLL_SIZE : 0);
1203: int lines = height / cellSize;
1204: if (pages < 0)
1205: lines = -lines;
1206:
1207: int pg = lines + index;
1208: int max = ltree.v.size();
1209: if (pg >= max)
1210: pg = max - 1;
1211: if (pg < 0)
1212: pg = 0;
1213: changeSelection((TreeNode) ltree.v.elementAt(pg), pg);
1214: repaint();
1215: return vscroll(lines);
1216: }
1217:
1218: protected boolean vscroll(int lines) {
1219: sbV.setValue(sbV.getValue() + lines);
1220: int id = (lines < 0) ? Event.SCROLL_LINE_DOWN
1221: : Event.SCROLL_LINE_UP;
1222: Event e = new Event(sbV, id, null);
1223: return scroll(e);
1224: }
1225:
1226: protected boolean scroll(Event e) {
1227: boolean b = false;
1228: if (e.target == sbV) {
1229: if (sbV.isVisible()) {
1230: posy = (-sbV.getValue() * cellSize);
1231: b = true;
1232: }
1233: }
1234:
1235: if (e.target == sbH) {
1236: if (sbH.isVisible()) {
1237: posx = -sbH.getValue();
1238: b = true;
1239: }
1240: }
1241:
1242: if (b)
1243: validate2();
1244: return b;
1245: }
1246:
1247: protected int getTextPos(TreeNode node) {
1248: int depth = node.depth;
1249: int textOffset = ((depth - 1) * (cellSize)) + cellSize
1250: + textInset + posx;
1251: if (node.getImage() != null)
1252: textOffset = textOffset + fm.getHeight();
1253: if (node.getIndicator() != null)
1254: textOffset += cellSize;
1255: return textOffset;
1256: }
1257: }
|