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