1. /*
  2. * @(#)DefaultTreeCellRenderer.java 1.47 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.tree;
  8. import javax.swing.*;
  9. import javax.swing.plaf.ColorUIResource;
  10. import javax.swing.plaf.FontUIResource;
  11. import java.awt.*;
  12. import java.awt.event.*;
  13. import java.beans.*;
  14. import java.io.*;
  15. import java.util.*;
  16. /**
  17. * Displays an entry in a tree.
  18. * See <a
  19. href="http://java.sun.com/docs/books/tutorial/uiswing/components/tree.html">How to Use Trees</a>
  20. * in <em>The Java Tutorial</em>
  21. * for examples of customizing node display using this class.
  22. * <p>
  23. *
  24. * <strong><a name="override">Implementation Note:</a></strong>
  25. * This class overrides
  26. * <code>validate</code>,
  27. * <code>revalidate</code>,
  28. * <code>repaint</code>,
  29. * and
  30. * <code>firePropertyChange</code>
  31. * solely to improve performance.
  32. * If not overridden, these frequently called methods would execute code paths
  33. * that are unnecessary for the default tree cell renderer.
  34. * If you write your own renderer,
  35. * take care to weigh the benefits and
  36. * drawbacks of overriding these methods.
  37. *
  38. * <p>
  39. * <strong>Warning:</strong>
  40. * Serialized objects of this class will not be compatible with
  41. * future Swing releases. The current serialization support is
  42. * appropriate for short term storage or RMI between applications running
  43. * the same version of Swing. As of 1.4, support for long term storage
  44. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  45. * has been added to the <code>java.beans</code> package.
  46. * Please see {@link java.beans.XMLEncoder}.
  47. *
  48. * @version 1.47 01/23/03
  49. * @author Rob Davis
  50. * @author Ray Ryan
  51. * @author Scott Violet
  52. */
  53. public class DefaultTreeCellRenderer extends JLabel implements TreeCellRenderer
  54. {
  55. /** Last tree the renderer was painted in. */
  56. private JTree tree;
  57. /** Is the value currently selected. */
  58. protected boolean selected;
  59. /** True if has focus. */
  60. protected boolean hasFocus;
  61. /** True if draws focus border around icon as well. */
  62. private boolean drawsFocusBorderAroundIcon;
  63. // Icons
  64. /** Icon used to show non-leaf nodes that aren't expanded. */
  65. transient protected Icon closedIcon;
  66. /** Icon used to show leaf nodes. */
  67. transient protected Icon leafIcon;
  68. /** Icon used to show non-leaf nodes that are expanded. */
  69. transient protected Icon openIcon;
  70. // Colors
  71. /** Color to use for the foreground for selected nodes. */
  72. protected Color textSelectionColor;
  73. /** Color to use for the foreground for non-selected nodes. */
  74. protected Color textNonSelectionColor;
  75. /** Color to use for the background when a node is selected. */
  76. protected Color backgroundSelectionColor;
  77. /** Color to use for the background when the node isn't selected. */
  78. protected Color backgroundNonSelectionColor;
  79. /** Color to use for the focus indicator when the node has focus. */
  80. protected Color borderSelectionColor;
  81. /**
  82. * Returns a new instance of DefaultTreeCellRenderer. Alignment is
  83. * set to left aligned. Icons and text color are determined from the
  84. * UIManager.
  85. */
  86. public DefaultTreeCellRenderer() {
  87. setHorizontalAlignment(JLabel.LEFT);
  88. setLeafIcon(UIManager.getIcon("Tree.leafIcon"));
  89. setClosedIcon(UIManager.getIcon("Tree.closedIcon"));
  90. setOpenIcon(UIManager.getIcon("Tree.openIcon"));
  91. setTextSelectionColor(UIManager.getColor("Tree.selectionForeground"));
  92. setTextNonSelectionColor(UIManager.getColor("Tree.textForeground"));
  93. setBackgroundSelectionColor(UIManager.getColor("Tree.selectionBackground"));
  94. setBackgroundNonSelectionColor(UIManager.getColor("Tree.textBackground"));
  95. setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor"));
  96. Object value = UIManager.get("Tree.drawsFocusBorderAroundIcon");
  97. drawsFocusBorderAroundIcon = (value != null && ((Boolean)value).
  98. booleanValue());
  99. }
  100. /**
  101. * Returns the default icon, for the current laf, that is used to
  102. * represent non-leaf nodes that are expanded.
  103. */
  104. public Icon getDefaultOpenIcon() {
  105. return UIManager.getIcon("Tree.openIcon");
  106. }
  107. /**
  108. * Returns the default icon, for the current laf, that is used to
  109. * represent non-leaf nodes that are not expanded.
  110. */
  111. public Icon getDefaultClosedIcon() {
  112. return UIManager.getIcon("Tree.closedIcon");
  113. }
  114. /**
  115. * Returns the default icon, for the current laf, that is used to
  116. * represent leaf nodes.
  117. */
  118. public Icon getDefaultLeafIcon() {
  119. return UIManager.getIcon("Tree.leafIcon");
  120. }
  121. /**
  122. * Sets the icon used to represent non-leaf nodes that are expanded.
  123. */
  124. public void setOpenIcon(Icon newIcon) {
  125. openIcon = newIcon;
  126. }
  127. /**
  128. * Returns the icon used to represent non-leaf nodes that are expanded.
  129. */
  130. public Icon getOpenIcon() {
  131. return openIcon;
  132. }
  133. /**
  134. * Sets the icon used to represent non-leaf nodes that are not expanded.
  135. */
  136. public void setClosedIcon(Icon newIcon) {
  137. closedIcon = newIcon;
  138. }
  139. /**
  140. * Returns the icon used to represent non-leaf nodes that are not
  141. * expanded.
  142. */
  143. public Icon getClosedIcon() {
  144. return closedIcon;
  145. }
  146. /**
  147. * Sets the icon used to represent leaf nodes.
  148. */
  149. public void setLeafIcon(Icon newIcon) {
  150. leafIcon = newIcon;
  151. }
  152. /**
  153. * Returns the icon used to represent leaf nodes.
  154. */
  155. public Icon getLeafIcon() {
  156. return leafIcon;
  157. }
  158. /**
  159. * Sets the color the text is drawn with when the node is selected.
  160. */
  161. public void setTextSelectionColor(Color newColor) {
  162. textSelectionColor = newColor;
  163. }
  164. /**
  165. * Returns the color the text is drawn with when the node is selected.
  166. */
  167. public Color getTextSelectionColor() {
  168. return textSelectionColor;
  169. }
  170. /**
  171. * Sets the color the text is drawn with when the node isn't selected.
  172. */
  173. public void setTextNonSelectionColor(Color newColor) {
  174. textNonSelectionColor = newColor;
  175. }
  176. /**
  177. * Returns the color the text is drawn with when the node isn't selected.
  178. */
  179. public Color getTextNonSelectionColor() {
  180. return textNonSelectionColor;
  181. }
  182. /**
  183. * Sets the color to use for the background if node is selected.
  184. */
  185. public void setBackgroundSelectionColor(Color newColor) {
  186. backgroundSelectionColor = newColor;
  187. }
  188. /**
  189. * Returns the color to use for the background if node is selected.
  190. */
  191. public Color getBackgroundSelectionColor() {
  192. return backgroundSelectionColor;
  193. }
  194. /**
  195. * Sets the background color to be used for non selected nodes.
  196. */
  197. public void setBackgroundNonSelectionColor(Color newColor) {
  198. backgroundNonSelectionColor = newColor;
  199. }
  200. /**
  201. * Returns the background color to be used for non selected nodes.
  202. */
  203. public Color getBackgroundNonSelectionColor() {
  204. return backgroundNonSelectionColor;
  205. }
  206. /**
  207. * Sets the color to use for the border.
  208. */
  209. public void setBorderSelectionColor(Color newColor) {
  210. borderSelectionColor = newColor;
  211. }
  212. /**
  213. * Returns the color the border is drawn.
  214. */
  215. public Color getBorderSelectionColor() {
  216. return borderSelectionColor;
  217. }
  218. /**
  219. * Subclassed to map <code>FontUIResource</code>s to null. If
  220. * <code>font</code> is null, or a <code>FontUIResource</code>, this
  221. * has the effect of letting the font of the JTree show
  222. * through. On the other hand, if <code>font</code> is non-null, and not
  223. * a <code>FontUIResource</code>, the font becomes <code>font</code>.
  224. */
  225. public void setFont(Font font) {
  226. if(font instanceof FontUIResource)
  227. font = null;
  228. super.setFont(font);
  229. }
  230. /**
  231. * Gets the font of this component.
  232. * @return this component's font; if a font has not been set
  233. * for this component, the font of its parent is returned
  234. */
  235. public Font getFont() {
  236. Font font = super.getFont();
  237. if (font == null && tree != null) {
  238. // Strive to return a non-null value, otherwise the html support
  239. // will typically pick up the wrong font in certain situations.
  240. font = tree.getFont();
  241. }
  242. return font;
  243. }
  244. /**
  245. * Subclassed to map <code>ColorUIResource</code>s to null. If
  246. * <code>color</code> is null, or a <code>ColorUIResource</code>, this
  247. * has the effect of letting the background color of the JTree show
  248. * through. On the other hand, if <code>color</code> is non-null, and not
  249. * a <code>ColorUIResource</code>, the background becomes
  250. * <code>color</code>.
  251. */
  252. public void setBackground(Color color) {
  253. if(color instanceof ColorUIResource)
  254. color = null;
  255. super.setBackground(color);
  256. }
  257. /**
  258. * Configures the renderer based on the passed in components.
  259. * The value is set from messaging the tree with
  260. * <code>convertValueToText</code>, which ultimately invokes
  261. * <code>toString</code> on <code>value</code>.
  262. * The foreground color is set based on the selection and the icon
  263. * is set based on on leaf and expanded.
  264. */
  265. public Component getTreeCellRendererComponent(JTree tree, Object value,
  266. boolean sel,
  267. boolean expanded,
  268. boolean leaf, int row,
  269. boolean hasFocus) {
  270. String stringValue = tree.convertValueToText(value, sel,
  271. expanded, leaf, row, hasFocus);
  272. this.tree = tree;
  273. this.hasFocus = hasFocus;
  274. setText(stringValue);
  275. if(sel)
  276. setForeground(getTextSelectionColor());
  277. else
  278. setForeground(getTextNonSelectionColor());
  279. // There needs to be a way to specify disabled icons.
  280. if (!tree.isEnabled()) {
  281. setEnabled(false);
  282. if (leaf) {
  283. setDisabledIcon(getLeafIcon());
  284. } else if (expanded) {
  285. setDisabledIcon(getOpenIcon());
  286. } else {
  287. setDisabledIcon(getClosedIcon());
  288. }
  289. }
  290. else {
  291. setEnabled(true);
  292. if (leaf) {
  293. setIcon(getLeafIcon());
  294. } else if (expanded) {
  295. setIcon(getOpenIcon());
  296. } else {
  297. setIcon(getClosedIcon());
  298. }
  299. }
  300. setComponentOrientation(tree.getComponentOrientation());
  301. selected = sel;
  302. return this;
  303. }
  304. /**
  305. * Paints the value. The background is filled based on selected.
  306. */
  307. public void paint(Graphics g) {
  308. Color bColor;
  309. if(selected) {
  310. bColor = getBackgroundSelectionColor();
  311. } else {
  312. bColor = getBackgroundNonSelectionColor();
  313. if(bColor == null)
  314. bColor = getBackground();
  315. }
  316. int imageOffset = -1;
  317. if(bColor != null) {
  318. Icon currentI = getIcon();
  319. imageOffset = getLabelStart();
  320. g.setColor(bColor);
  321. if(getComponentOrientation().isLeftToRight()) {
  322. g.fillRect(imageOffset, 0, getWidth() - 1 - imageOffset,
  323. getHeight());
  324. } else {
  325. g.fillRect(0, 0, getWidth() - 1 - imageOffset,
  326. getHeight());
  327. }
  328. }
  329. if (hasFocus) {
  330. if (drawsFocusBorderAroundIcon) {
  331. imageOffset = 0;
  332. }
  333. else if (imageOffset == -1) {
  334. imageOffset = getLabelStart();
  335. }
  336. Color bsColor = getBorderSelectionColor();
  337. if (bsColor != null) {
  338. g.setColor(bsColor);
  339. if(getComponentOrientation().isLeftToRight()) {
  340. g.drawRect(imageOffset, 0, getWidth() - 1 - imageOffset,
  341. getHeight() - 1);
  342. } else {
  343. g.drawRect(0, 0, getWidth() - 1 - imageOffset,
  344. getHeight() - 1);
  345. }
  346. }
  347. }
  348. super.paint(g);
  349. }
  350. private int getLabelStart() {
  351. Icon currentI = getIcon();
  352. if(currentI != null && getText() != null) {
  353. return currentI.getIconWidth() + Math.max(0, getIconTextGap() - 1);
  354. }
  355. return 0;
  356. }
  357. /**
  358. * Overrides <code>JComponent.getPreferredSize</code> to
  359. * return slightly wider preferred size value.
  360. */
  361. public Dimension getPreferredSize() {
  362. Dimension retDimension = super.getPreferredSize();
  363. if(retDimension != null)
  364. retDimension = new Dimension(retDimension.width + 3,
  365. retDimension.height);
  366. return retDimension;
  367. }
  368. /**
  369. * Overridden for performance reasons.
  370. * See the <a href="#override">Implementation Note</a>
  371. * for more information.
  372. */
  373. public void validate() {}
  374. /**
  375. * Overridden for performance reasons.
  376. * See the <a href="#override">Implementation Note</a>
  377. * for more information.
  378. */
  379. public void revalidate() {}
  380. /**
  381. * Overridden for performance reasons.
  382. * See the <a href="#override">Implementation Note</a>
  383. * for more information.
  384. */
  385. public void repaint(long tm, int x, int y, int width, int height) {}
  386. /**
  387. * Overridden for performance reasons.
  388. * See the <a href="#override">Implementation Note</a>
  389. * for more information.
  390. */
  391. public void repaint(Rectangle r) {}
  392. /**
  393. * Overridden for performance reasons.
  394. * See the <a href="#override">Implementation Note</a>
  395. * for more information.
  396. */
  397. protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
  398. // Strings get interned...
  399. if (propertyName=="text")
  400. super.firePropertyChange(propertyName, oldValue, newValue);
  401. }
  402. /**
  403. * Overridden for performance reasons.
  404. * See the <a href="#override">Implementation Note</a>
  405. * for more information.
  406. */
  407. public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {}
  408. /**
  409. * Overridden for performance reasons.
  410. * See the <a href="#override">Implementation Note</a>
  411. * for more information.
  412. */
  413. public void firePropertyChange(String propertyName, char oldValue, char newValue) {}
  414. /**
  415. * Overridden for performance reasons.
  416. * See the <a href="#override">Implementation Note</a>
  417. * for more information.
  418. */
  419. public void firePropertyChange(String propertyName, short oldValue, short newValue) {}
  420. /**
  421. * Overridden for performance reasons.
  422. * See the <a href="#override">Implementation Note</a>
  423. * for more information.
  424. */
  425. public void firePropertyChange(String propertyName, int oldValue, int newValue) {}
  426. /**
  427. * Overridden for performance reasons.
  428. * See the <a href="#override">Implementation Note</a>
  429. * for more information.
  430. */
  431. public void firePropertyChange(String propertyName, long oldValue, long newValue) {}
  432. /**
  433. * Overridden for performance reasons.
  434. * See the <a href="#override">Implementation Note</a>
  435. * for more information.
  436. */
  437. public void firePropertyChange(String propertyName, float oldValue, float newValue) {}
  438. /**
  439. * Overridden for performance reasons.
  440. * See the <a href="#override">Implementation Note</a>
  441. * for more information.
  442. */
  443. public void firePropertyChange(String propertyName, double oldValue, double newValue) {}
  444. /**
  445. * Overridden for performance reasons.
  446. * See the <a href="#override">Implementation Note</a>
  447. * for more information.
  448. */
  449. public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {}
  450. }