Frames | No Frames |
1: /* MetalTreeUI.java 2: Copyright (C) 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.plaf.metal; 40: 41: import java.awt.Graphics; 42: import java.awt.Insets; 43: import java.awt.Rectangle; 44: import java.beans.PropertyChangeEvent; 45: import java.beans.PropertyChangeListener; 46: 47: import javax.swing.JComponent; 48: import javax.swing.JTree; 49: import javax.swing.UIManager; 50: import javax.swing.tree.TreePath; 51: import javax.swing.plaf.ComponentUI; 52: import javax.swing.plaf.basic.BasicTreeUI; 53: 54: /** 55: * A UI delegate for the {@link JTree} component. 56: */ 57: public class MetalTreeUI extends BasicTreeUI 58: { 59: /** 60: * Listens for property changes of the line style and updates the 61: * internal setting. 62: */ 63: private class LineStyleListener 64: implements PropertyChangeListener 65: { 66: 67: public void propertyChange(PropertyChangeEvent e) 68: { 69: if (e.getPropertyName().equals(LINE_STYLE_PROPERTY)) 70: decodeLineStyle(e.getNewValue()); 71: } 72: 73: } 74: 75: /** 76: * The key to the lineStyle client property. 77: */ 78: private static final String LINE_STYLE_PROPERTY = "JTree.lineStyle"; 79: 80: /** 81: * The property value indicating no line style. 82: */ 83: private static final String LINE_STYLE_VALUE_NONE = "None"; 84: 85: /** 86: * The property value indicating angled line style. 87: */ 88: private static final String LINE_STYLE_VALUE_ANGLED = "Angled"; 89: 90: /** 91: * The property value indicating horizontal line style. 92: */ 93: private static final String LINE_STYLE_VALUE_HORIZONTAL = "Horizontal"; 94: 95: /** 96: * The line style for None. 97: */ 98: private static final int LINE_STYLE_NONE = 0; 99: 100: /** 101: * The line style for Angled. 102: */ 103: private static final int LINE_STYLE_ANGLED = 1; 104: 105: /** 106: * The line style for Horizontal. 107: */ 108: private static final int LINE_STYLE_HORIZONTAL = 2; 109: 110: /** 111: * The current line style. 112: */ 113: private int lineStyle; 114: 115: /** 116: * Listens for changes on the line style property and updates the 117: * internal settings. 118: */ 119: private PropertyChangeListener lineStyleListener; 120: 121: /** 122: * Constructs a new instance of <code>MetalTreeUI</code>. 123: */ 124: public MetalTreeUI() 125: { 126: super(); 127: } 128: 129: /** 130: * Returns a new instance of <code>MetalTreeUI</code>. 131: * 132: * @param component the component for which we return an UI instance 133: * 134: * @return A new instance of <code>MetalTreeUI</code>. 135: */ 136: public static ComponentUI createUI(JComponent component) 137: { 138: return new MetalTreeUI(); 139: } 140: 141: /** 142: * The horizontal element of legs between nodes starts at the right of the 143: * left-hand side of the child node by default. This method makes the 144: * leg end before that. 145: */ 146: protected int getHorizontalLegBuffer() 147: { 148: return super.getHorizontalLegBuffer(); 149: } 150: 151: /** 152: * Configures the specified component appropriate for the look and feel. 153: * This method is invoked when the ComponentUI instance is being installed 154: * as the UI delegate on the specified component. This method should completely 155: * configure the component for the look and feel, including the following: 156: * 1. Install any default property values for color, fonts, borders, icons, 157: * opacity, etc. on the component. Whenever possible, property values 158: * initialized by the client program should not be overridden. 159: * 2. Install a LayoutManager on the component if necessary. 160: * 3. Create/add any required sub-components to the component. 161: * 4. Create/install event listeners on the component. 162: * 5. Create/install a PropertyChangeListener on the component in order 163: * to detect and respond to component property changes appropriately. 164: * 6. Install keyboard UI (mnemonics, traversal, etc.) on the component. 165: * 7. Initialize any appropriate instance data. 166: */ 167: public void installUI(JComponent c) 168: { 169: super.installUI(c); 170: 171: Object lineStyleProp = c.getClientProperty(LINE_STYLE_PROPERTY); 172: decodeLineStyle(lineStyleProp); 173: if (lineStyleListener == null) 174: lineStyleListener = new LineStyleListener(); 175: c.addPropertyChangeListener(lineStyleListener); 176: } 177: 178: /** 179: * Reverses configuration which was done on the specified component during 180: * installUI. This method is invoked when this UIComponent instance is being 181: * removed as the UI delegate for the specified component. This method should 182: * undo the configuration performed in installUI, being careful to leave the 183: * JComponent instance in a clean state (no extraneous listeners, 184: * look-and-feel-specific property objects, etc.). This should include 185: * the following: 186: * 1. Remove any UI-set borders from the component. 187: * 2. Remove any UI-set layout managers on the component. 188: * 3. Remove any UI-added sub-components from the component. 189: * 4. Remove any UI-added event/property listeners from the component. 190: * 5. Remove any UI-installed keyboard UI from the component. 191: * 6. Nullify any allocated instance data objects to allow for GC. 192: */ 193: public void uninstallUI(JComponent c) 194: { 195: super.uninstallUI(c); 196: if (lineStyleListener != null) 197: c.removePropertyChangeListener(lineStyleListener); 198: lineStyleListener = null; 199: } 200: 201: /** 202: * This function converts between the string passed into the client 203: * property and the internal representation (currently an int). 204: * 205: * @param lineStyleFlag - String representation 206: */ 207: protected void decodeLineStyle(Object lineStyleFlag) 208: { 209: if (lineStyleFlag == null || lineStyleFlag.equals(LINE_STYLE_VALUE_ANGLED)) 210: lineStyle = LINE_STYLE_ANGLED; 211: else if (lineStyleFlag.equals(LINE_STYLE_VALUE_HORIZONTAL)) 212: lineStyle = LINE_STYLE_HORIZONTAL; 213: else if (lineStyleFlag.equals(LINE_STYLE_VALUE_NONE)) 214: lineStyle = LINE_STYLE_NONE; 215: else 216: lineStyle = LINE_STYLE_ANGLED; 217: } 218: 219: /** 220: * Checks if the location is in expand control. 221: * 222: * @param row - current row 223: * @param rowLevel - current level 224: * @param mouseX - current x location of the mouse click 225: * @param mouseY - current y location of the mouse click 226: */ 227: protected boolean isLocationInExpandControl(int row, int rowLevel, 228: int mouseX, int mouseY) 229: { 230: return super.isLocationInExpandControl(tree.getPathForRow(row), 231: mouseX, mouseY); 232: } 233: 234: /** 235: * Paints the specified component appropriate for the look and feel. 236: * This method is invoked from the ComponentUI.update method when the 237: * specified component is being painted. Subclasses should override this 238: * method and use the specified Graphics object to render the content of 239: * the component. 240: * 241: * @param g - the current graphics configuration. 242: * @param c - the current component to draw 243: */ 244: public void paint(Graphics g, JComponent c) 245: { 246: // Calls BasicTreeUI's paint since it takes care of painting all 247: // types of icons. 248: super.paint(g, c); 249: 250: if (lineStyle == LINE_STYLE_HORIZONTAL) 251: paintHorizontalSeparators(g, c); 252: } 253: 254: /** 255: * Paints the horizontal separators. 256: * 257: * @param g - the current graphics configuration. 258: * @param c - the current component to draw 259: */ 260: protected void paintHorizontalSeparators(Graphics g, JComponent c) 261: { 262: g.setColor(UIManager.getColor("Tree.line")); 263: Rectangle clip = g.getClipBounds(); 264: int row0 = getRowForPath(tree, getClosestPathForLocation(tree, 0, clip.y)); 265: int row1 = 266: getRowForPath(tree, getClosestPathForLocation(tree, 0, 267: clip.y + clip.height - 1)); 268: if (row0 >= 0 && row1 >= 0) 269: { 270: for (int i = row0; i <= row1; i++) 271: { 272: TreePath p = getPathForRow(tree, i); 273: if (p != null && p.getPathCount() == 2) 274: { 275: Rectangle r = getPathBounds(tree, getPathForRow(tree, i)); 276: if (r != null) 277: { 278: g.drawLine(clip.x, r.y, clip.x + clip.width, r.y); 279: } 280: } 281: } 282: } 283: } 284: 285: 286: /** 287: * Paints the vertical part of the leg. The receiver should NOT modify 288: * clipBounds, insets. 289: * 290: * @param g - the current graphics configuration. 291: * @param clipBounds - 292: * @param insets - 293: * @param path - the current path 294: */ 295: protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, 296: Insets insets, TreePath path) 297: { 298: if (lineStyle == LINE_STYLE_ANGLED) 299: super.paintVerticalPartOfLeg(g, clipBounds, insets, path); 300: } 301: 302: /** 303: * Paints the horizontal part of the leg. The receiver should NOT \ 304: * modify clipBounds, or insets. 305: * NOTE: parentRow can be -1 if the root is not visible. 306: */ 307: protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds, 308: Insets insets, Rectangle bounds, 309: TreePath path, int row, 310: boolean isExpanded, boolean hasBeenExpanded, 311: boolean isLeaf) 312: { 313: if (lineStyle == LINE_STYLE_ANGLED) 314: super.paintHorizontalPartOfLeg(g, clipBounds, insets, bounds, path, row, 315: isExpanded, hasBeenExpanded, isLeaf); 316: } 317: }