📄 treebrowser.java
字号:
// TreeBrowser.java// $Id: TreeBrowser.java,v 1.14 2000/08/16 21:37:57 ylafon Exp $ */// Authors: Jean-Michel.Leon@sophia.inria.fr, // Yves.Lafon@w3.org : // - Lines, insert/remove, awt 1.1 version// Thierry.Kormann@sophia.inria.fr// - Insert debug, horizontal scrollbar, javadoc, // selection graphic customization, scrollbar policy, // lightweight version.package org.w3c.tools.widgets ;import java.awt.Canvas;import java.awt.Color;import java.awt.Component;import java.awt.Dimension;import java.awt.FontMetrics;import java.awt.Graphics;import java.awt.Image;import java.awt.Rectangle;import java.awt.Scrollbar;import java.awt.event.AdjustmentEvent;import java.awt.event.AdjustmentListener;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.util.Enumeration;import java.util.EventObject;import java.util.Stack;import java.util.Vector;/** * The TreeBrowser class. * * This class is a generic framework to browser any hierachical structure. * * <p>Genericity is obtained through the use of 'handlers': the TreeBrowser * itself does not perform any action in response to user events, but simply * forward them as <b>notifications</b> to <b>handlers</b>. Each item inserted * may have its own handler, but handlers may also (this is the most common * case) be shared between handlers. * * <p>Any item added in the Tree is displayed with an icon and a label. When a * handler receive a notification on a node, it may change this node, to modify * or update its appearance. * * @author Jean-Michel.Leon@sophia.inria.fr * @author Yves.Lafon@w3.org * @author Thierry.Kormann@sophia.inria.fr */public class TreeBrowser extends Canvas implements AdjustmentListener { /** * Specifies that the horizontal/vertical scrollbars should always be shown * regardless of the respective sizes of the TreeBrowser. */ public static final int SCROLLBARS_ALWAYS = 0; /** * Specifies that horizontal/vertical scrollbars should be shown only when * the size of the nodes exceeds the size of the TreeBrowser in the * horizontal/vertical dimension. */ public static final int SCROLLBARS_ASNEEDED = 1; /** * This policy that lets just one node selected at the same time. */ public static final int SINGLE = 0; /** * The policy that enables a multiple selection of nodes. */ public static final int MULTIPLE = 1; static final int HMARGIN = 5; static final int VMARGIN = 5; static final int HGAP = 10; static final int DXLEVEL = HGAP*2; /** * The inner mouse listener in charge of all the node expansion * selection and execution */ private class BrowserMouseListener extends MouseAdapter { private void clickAt(TreeNode node, MouseEvent me) { if(node == null) return; int x = me.getX() - HMARGIN; if(node.handler == null) return; // node.handler.notifyExpand(this, node); if((x >= node.level*DXLEVEL) && (x <= node.level*DXLEVEL + DXLEVEL)) { // click on expand/collapse button if(node.children != TreeNode.NOCHILD) { node.handler.notifyCollapse(TreeBrowser.this, node); } else { node.handler.notifyExpand(TreeBrowser.this, node); } } else if(x > node.level*DXLEVEL + HGAP) { // item selection node.handler.notifySelect(TreeBrowser.this, node); } } /** * Handles events and send notifications ot handlers. * is sent, depending on the node's current state.<br> * on MOUSE_DOWN on a label, a <b>Select</b> notificaiton is sent.<br> * on DOUBLE_CLICK on a label, an <b>Execute</b> notification is sent. */ public void mousePressed(MouseEvent me) { int y = me.getY() - VMARGIN; if(me.getClickCount() == 1) { clickAt(itemAt(y), me); } } public void mouseClicked(MouseEvent me) { if(me.getClickCount() > 1) { int y = me.getY() - VMARGIN; TreeNode node = itemAt(y); if((node != null) && (node.handler != null)) { node.handler.notifyExecute(TreeBrowser.this, node); } } } } private Scrollbar vscroll; private Scrollbar hscroll; private int maxwidth = 0; private int startx = 0; private Color selectColor = new Color(0, 0, 128); private Color selectFontColor = Color.white; private int scrollbarDisplayPolicy = SCROLLBARS_ASNEEDED; private boolean hierarchyChanged = true; protected Vector items; protected Vector selection; protected int topItem = 0; protected int visibleItemCount = 20; protected int selectionPolicy = SINGLE; protected int fontHeight; /** * Builds a new browser instance * * @param root the root node for this hierarchy * @param label the label that should be displayed for this item * @param handler the handler for this node * @param icon the icon that must be displayed for this item */ public TreeBrowser(Object root, String label, NodeHandler handler, Image icon) { this(); initialize(root, label, handler, icon); } protected TreeBrowser() { selection = new Vector(1, 1); items = new Vector(); topItem = 0; addMouseListener(new BrowserMouseListener()); } protected void initialize(Object item,String label, NodeHandler handler, Image icon) { items.addElement(new TreeNode(item,label, handler, icon, 0)); } public Dimension getPreferredSize() { return new Dimension(200, 400); } /** * Sets the color of a selected node to the specified color. * @param color the color used to paint a selected node */ public void setSelectionFontColor(Color color) { this.selectFontColor = color; } /** * Sets the background color of a selected node to the specified color. * @param color the color used to paint the background of a selected node */ public void setSelectionBackgroudColor(Color color) { this.selectColor = color; } /** * Sets the scrollbars display policy to the specified policy. The default * is SCROLLBARS_ALWAYS * @param scrollbarDisplayPolicy SCROLLBARS_NEVER | SCROLLBARS_ASNEEDED | * SCROLLBARS_ALWAYS */ public void setScrollbarDisplayPolicy(int scrollbarDisplayPolicy) { this.scrollbarDisplayPolicy = scrollbarDisplayPolicy; hierarchyChanged = false; } /** * repaints the View. */ public void paint(Graphics g) { fontHeight = g.getFontMetrics().getHeight(); int fontAscent = g.getFontMetrics().getAscent(); int itemCount = items.size(); Dimension dim = getSize(); int myHeight = dim.height-VMARGIN*2; int myWidth = dim.width-HMARGIN*2; g.clipRect(HMARGIN, VMARGIN, myWidth, myHeight); g.translate(HMARGIN, VMARGIN); int y = 0; int dx, fatherIndex; int level; Stack indexStack = new Stack(); Graphics bg = g.create(); bg.setColor(selectColor); g.setFont(getFont()); visibleItemCount = 0; TreeNode node; level = -1; int labelwidth; if (hierarchyChanged) { maxwidth = 0; } // we push the indexes of the inner levels to speed up things for(int i = 0; i < topItem; i++) { node = (TreeNode) items.elementAt(i); // hscroll if (hierarchyChanged) { dx = node.level * DXLEVEL; labelwidth = g.getFontMetrics().stringWidth(node.label); maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth); } if(node.level > level) { indexStack.push(new Integer(i-1)); level = node.level; } if(node.level < level) { for(int j=node.level; j<level; j++) indexStack.pop(); level = node.level; } } int nitems = myHeight/fontHeight; int ditems = itemCount - topItem; if (ditems < nitems) { topItem = Math.max(0, topItem-(nitems-ditems)); } if (myWidth >= maxwidth) { startx = 0; } else if (startx+myWidth > maxwidth) { startx = (maxwidth - myWidth); } for(int i = topItem; i < itemCount ; i++) { node = (TreeNode) items.elementAt(i); if(node.level > level) { indexStack.push(new Integer(i-1)); level = node.level; } if(node.level < level) { for(int j=node.level; j<level; j++) indexStack.pop(); level = node.level; } dx = (node.level * DXLEVEL)-startx; if(y <= myHeight) { if(node.selected) { bg.fillRect(dx, y-1, Math.max(myWidth-1, maxwidth-1), fontHeight); g.setColor(selectFontColor); g.drawImage(node.icon, dx, y, this); g.drawString(node.label, dx + DXLEVEL, y+fontAscent); g.setColor(getForeground()); } else { g.setColor(getForeground()); g.drawImage(node.icon, dx, y, this); g.drawString(node.label, dx + DXLEVEL, y+fontAscent); } fatherIndex = ((Integer) indexStack.peek()).intValue(); if( fatherIndex != -1) { // draw fancy lines int fi = fatherIndex - topItem; g.drawLine(dx - HGAP/2 , y + fontHeight/2, dx - DXLEVEL + HGAP/2, y + fontHeight/2); if(node.handler.isDirectory(this, node)) { g.drawRect(dx - DXLEVEL + HGAP/2 -2, y + fontHeight/2 - 2, 4, 4); } g.drawLine(dx-DXLEVEL + HGAP/2, y + fontHeight/2, dx-DXLEVEL + HGAP/2, (fi+1)*fontHeight - 1); } visibleItemCount++; } else { // draw the lines for invisible nodes. fatherIndex = ((Integer)indexStack.peek()).intValue(); if(fatherIndex != -1) { int fi = fatherIndex - topItem; if((fi+1)*fontHeight -1 < myHeight) g.drawLine(dx - DXLEVEL + HGAP/2, myHeight-1, dx - DXLEVEL + HGAP/2, (fi+1)*fontHeight-1); } } // hscroll if (hierarchyChanged) { dx = (node.level * DXLEVEL); labelwidth = g.getFontMetrics().stringWidth(node.label); maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth); } y += fontHeight; } // hscroll if (hierarchyChanged) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -