1. /*
  2. * @(#)MetalTreeUI.java 1.22 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.metal;
  8. import javax.swing.*;
  9. import javax.swing.event.*;
  10. import java.awt.*;
  11. import java.awt.event.*;
  12. import java.beans.*;
  13. import java.io.*;
  14. import java.util.*;
  15. import javax.swing.plaf.*;
  16. import javax.swing.tree.*;
  17. import javax.swing.plaf.basic.*;
  18. /**
  19. * The metal look and feel implementation of <code>TreeUI</code>.
  20. * <p>
  21. * <code>MetalTreeUI</code> allows for configuring how to
  22. * visually render the spacing and delineation between nodes. The following
  23. * hints are supported:
  24. *
  25. * <table summary="Descriptions of supported hints: Angled, Horizontal, and None">
  26. * <tr>
  27. * <th><p align="left">Angled</p></th>
  28. * <td>A line is drawn connecting the child to the parent. For handling
  29. * of the root node refer to
  30. * {@link javax.swing.JTree#setRootVisible} and
  31. * {@link javax.swing.JTree#setShowsRootHandles}.
  32. * </td>
  33. * </tr>
  34. * <tr>
  35. * <th><p align="left">Horizontal</p></th>
  36. * <td>A horizontal line is drawn dividing the children of the root node.</td>
  37. * </tr>
  38. * <tr>
  39. * <th><p align="left">None</p></th>
  40. * <td>Do not draw any visual indication between nodes.</td>
  41. * </tr>
  42. * </table>
  43. *
  44. * <p>
  45. * As it is typically impratical to obtain the <code>TreeUI</code> from
  46. * the <code>JTree</code> and cast to an instance of <code>MetalTreeUI</code>
  47. * you enable this property via the client property
  48. * <code>JTree.lineStyle</code>. For example, to switch to
  49. * <code>Horizontal</code> style you would do:
  50. * <code>tree.putClientProperty("JTree.lineStyle", "Horizontal");</code>
  51. * <p>
  52. * The default is <code>Angled</code>.
  53. *
  54. * @version 1.22 01/23/03
  55. * @author Tom Santos
  56. * @author Steve Wilson (value add stuff)
  57. */
  58. public class MetalTreeUI extends BasicTreeUI {
  59. private static Color lineColor;
  60. private static final String LINE_STYLE = "JTree.lineStyle";
  61. private static final String LEG_LINE_STYLE_STRING = "Angled";
  62. private static final String HORIZ_STYLE_STRING = "Horizontal";
  63. private static final String NO_STYLE_STRING = "None";
  64. private static final int LEG_LINE_STYLE = 2;
  65. private static final int HORIZ_LINE_STYLE = 1;
  66. private static final int NO_LINE_STYLE = 0;
  67. private int lineStyle = LEG_LINE_STYLE;
  68. private PropertyChangeListener lineStyleListener = new LineListener();
  69. // Boilerplate
  70. public static ComponentUI createUI(JComponent x) {
  71. return new MetalTreeUI();
  72. }
  73. public MetalTreeUI()
  74. {
  75. super();
  76. }
  77. protected int getHorizontalLegBuffer()
  78. {
  79. return 4;
  80. }
  81. public void installUI( JComponent c ) {
  82. super.installUI( c );
  83. lineColor = UIManager.getColor( "Tree.line" );
  84. Object lineStyleFlag = c.getClientProperty( LINE_STYLE );
  85. decodeLineStyle(lineStyleFlag);
  86. c.addPropertyChangeListener(lineStyleListener);
  87. }
  88. public void uninstallUI( JComponent c) {
  89. c.removePropertyChangeListener(lineStyleListener);
  90. super.uninstallUI(c);
  91. }
  92. /** this function converts between the string passed into the client property
  93. * and the internal representation (currently and int)
  94. *
  95. */
  96. protected void decodeLineStyle(Object lineStyleFlag) {
  97. if ( lineStyleFlag == null ||
  98. lineStyleFlag.equals(LEG_LINE_STYLE_STRING)){
  99. lineStyle = LEG_LINE_STYLE; // default case
  100. } else {
  101. if ( lineStyleFlag.equals(NO_STYLE_STRING) ) {
  102. lineStyle = NO_LINE_STYLE;
  103. } else if ( lineStyleFlag.equals(HORIZ_STYLE_STRING) ) {
  104. lineStyle = HORIZ_LINE_STYLE;
  105. }
  106. }
  107. }
  108. protected boolean isLocationInExpandControl(int row, int rowLevel,
  109. int mouseX, int mouseY) {
  110. if(tree != null && !isLeaf(row)) {
  111. int boxWidth;
  112. if(getExpandedIcon() != null)
  113. boxWidth = getExpandedIcon().getIconWidth() + 6;
  114. else
  115. boxWidth = 8;
  116. Insets i = tree.getInsets();
  117. int boxLeftX = (i != null) ? i.left : 0;
  118. boxLeftX += (((rowLevel + depthOffset - 1) * totalChildIndent) +
  119. getLeftChildIndent()) - boxWidth2;
  120. int boxRightX = boxLeftX + boxWidth;
  121. return mouseX >= boxLeftX && mouseX <= boxRightX;
  122. }
  123. return false;
  124. }
  125. public void paint(Graphics g, JComponent c) {
  126. super.paint( g, c );
  127. // Paint the lines
  128. if (lineStyle == HORIZ_LINE_STYLE && !largeModel) {
  129. paintHorizontalSeparators(g,c);
  130. }
  131. }
  132. protected void paintHorizontalSeparators(Graphics g, JComponent c) {
  133. g.setColor( lineColor );
  134. Rectangle clipBounds = g.getClipBounds();
  135. int beginRow = getRowForPath(tree, getClosestPathForLocation
  136. (tree, 0, clipBounds.y));
  137. int endRow = getRowForPath(tree, getClosestPathForLocation
  138. (tree, 0, clipBounds.y + clipBounds.height - 1));
  139. if ( beginRow <= -1 || endRow <= -1 ) {
  140. return;
  141. }
  142. for ( int i = beginRow; i <= endRow; ++i ) {
  143. TreePath path = getPathForRow(tree, i);
  144. if(path != null && path.getPathCount() == 2) {
  145. Rectangle rowBounds = getPathBounds(tree,getPathForRow
  146. (tree, i));
  147. // Draw a line at the top
  148. if(rowBounds != null)
  149. g.drawLine(clipBounds.x, rowBounds.y,
  150. clipBounds.x + clipBounds.width, rowBounds.y);
  151. }
  152. }
  153. }
  154. protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
  155. Insets insets, TreePath path) {
  156. if (lineStyle == LEG_LINE_STYLE) {
  157. super.paintVerticalPartOfLeg(g, clipBounds, insets, path);
  158. }
  159. }
  160. protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
  161. Insets insets, Rectangle bounds,
  162. TreePath path, int row,
  163. boolean isExpanded,
  164. boolean hasBeenExpanded, boolean
  165. isLeaf) {
  166. if (lineStyle == LEG_LINE_STYLE) {
  167. super.paintHorizontalPartOfLeg(g, clipBounds, insets, bounds,
  168. path, row, isExpanded,
  169. hasBeenExpanded, isLeaf);
  170. }
  171. }
  172. /** This class listens for changes in line style */
  173. class LineListener implements PropertyChangeListener {
  174. public void propertyChange(PropertyChangeEvent e) {
  175. String name = e.getPropertyName();
  176. if ( name.equals( LINE_STYLE ) ) {
  177. decodeLineStyle(e.getNewValue());
  178. }
  179. }
  180. } // end class PaletteListener
  181. }