/* * @(#)DefaultTreeCellRenderer.java 1.51 04/01/23 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.swing.tree; import javax.swing.*; import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.FontUIResource; import javax.swing.plaf.basic.BasicGraphicsUtils; import java.awt.*; import java.awt.event.*; import java.beans.*; import java.io.*; import java.util.*; /** * Displays an entry in a tree. * DefaultTreeCellRenderer is not opaque and * unless you subclass paint you should not change this. * See How to Use Trees * in The Java Tutorial * for examples of customizing node display using this class. *

* * Implementation Note: * This class overrides * invalidate, * validate, * revalidate, * repaint, * and * firePropertyChange * solely to improve performance. * If not overridden, these frequently called methods would execute code paths * that are unnecessary for the default tree cell renderer. * If you write your own renderer, * take care to weigh the benefits and * drawbacks of overriding these methods. * *

* Warning: * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeansTM * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. * * @version 1.51 01/23/04 * @author Rob Davis * @author Ray Ryan * @author Scott Violet */ public class DefaultTreeCellRenderer extends JLabel implements TreeCellRenderer { /** Last tree the renderer was painted in. */ private JTree tree; /** Is the value currently selected. */ protected boolean selected; /** True if has focus. */ protected boolean hasFocus; /** True if draws focus border around icon as well. */ private boolean drawsFocusBorderAroundIcon; /** If true, a dashed line is drawn as the focus indicator. */ private boolean drawDashedFocusIndicator; // If drawDashedFocusIndicator is true, the following are used. /** * Background color of the tree. */ private Color treeBGColor; /** * Color to draw the focus indicator in, determined from the background. * color. */ private Color focusBGColor; // Icons /** Icon used to show non-leaf nodes that aren't expanded. */ transient protected Icon closedIcon; /** Icon used to show leaf nodes. */ transient protected Icon leafIcon; /** Icon used to show non-leaf nodes that are expanded. */ transient protected Icon openIcon; // Colors /** Color to use for the foreground for selected nodes. */ protected Color textSelectionColor; /** Color to use for the foreground for non-selected nodes. */ protected Color textNonSelectionColor; /** Color to use for the background when a node is selected. */ protected Color backgroundSelectionColor; /** Color to use for the background when the node isn't selected. */ protected Color backgroundNonSelectionColor; /** Color to use for the focus indicator when the node has focus. */ protected Color borderSelectionColor; /** * Returns a new instance of DefaultTreeCellRenderer. Alignment is * set to left aligned. Icons and text color are determined from the * UIManager. */ public DefaultTreeCellRenderer() { setHorizontalAlignment(JLabel.LEFT); setLeafIcon(UIManager.getIcon("Tree.leafIcon")); setClosedIcon(UIManager.getIcon("Tree.closedIcon")); setOpenIcon(UIManager.getIcon("Tree.openIcon")); setTextSelectionColor(UIManager.getColor("Tree.selectionForeground")); setTextNonSelectionColor(UIManager.getColor("Tree.textForeground")); setBackgroundSelectionColor(UIManager.getColor("Tree.selectionBackground")); setBackgroundNonSelectionColor(UIManager.getColor("Tree.textBackground")); setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor")); Object value = UIManager.get("Tree.drawsFocusBorderAroundIcon"); drawsFocusBorderAroundIcon = (value != null && ((Boolean)value). booleanValue()); value = UIManager.get("Tree.drawDashedFocusIndicator"); drawDashedFocusIndicator = (value != null && ((Boolean)value). booleanValue()); } /** * Returns the default icon, for the current laf, that is used to * represent non-leaf nodes that are expanded. */ public Icon getDefaultOpenIcon() { return UIManager.getIcon("Tree.openIcon"); } /** * Returns the default icon, for the current laf, that is used to * represent non-leaf nodes that are not expanded. */ public Icon getDefaultClosedIcon() { return UIManager.getIcon("Tree.closedIcon"); } /** * Returns the default icon, for the current laf, that is used to * represent leaf nodes. */ public Icon getDefaultLeafIcon() { return UIManager.getIcon("Tree.leafIcon"); } /** * Sets the icon used to represent non-leaf nodes that are expanded. */ public void setOpenIcon(Icon newIcon) { openIcon = newIcon; } /** * Returns the icon used to represent non-leaf nodes that are expanded. */ public Icon getOpenIcon() { return openIcon; } /** * Sets the icon used to represent non-leaf nodes that are not expanded. */ public void setClosedIcon(Icon newIcon) { closedIcon = newIcon; } /** * Returns the icon used to represent non-leaf nodes that are not * expanded. */ public Icon getClosedIcon() { return closedIcon; } /** * Sets the icon used to represent leaf nodes. */ public void setLeafIcon(Icon newIcon) { leafIcon = newIcon; } /** * Returns the icon used to represent leaf nodes. */ public Icon getLeafIcon() { return leafIcon; } /** * Sets the color the text is drawn with when the node is selected. */ public void setTextSelectionColor(Color newColor) { textSelectionColor = newColor; } /** * Returns the color the text is drawn with when the node is selected. */ public Color getTextSelectionColor() { return textSelectionColor; } /** * Sets the color the text is drawn with when the node isn't selected. */ public void setTextNonSelectionColor(Color newColor) { textNonSelectionColor = newColor; } /** * Returns the color the text is drawn with when the node isn't selected. */ public Color getTextNonSelectionColor() { return textNonSelectionColor; } /** * Sets the color to use for the background if node is selected. */ public void setBackgroundSelectionColor(Color newColor) { backgroundSelectionColor = newColor; } /** * Returns the color to use for the background if node is selected. */ public Color getBackgroundSelectionColor() { return backgroundSelectionColor; } /** * Sets the background color to be used for non selected nodes. */ public void setBackgroundNonSelectionColor(Color newColor) { backgroundNonSelectionColor = newColor; } /** * Returns the background color to be used for non selected nodes. */ public Color getBackgroundNonSelectionColor() { return backgroundNonSelectionColor; } /** * Sets the color to use for the border. */ public void setBorderSelectionColor(Color newColor) { borderSelectionColor = newColor; } /** * Returns the color the border is drawn. */ public Color getBorderSelectionColor() { return borderSelectionColor; } /** * Subclassed to map FontUIResources to null. If * font is null, or a FontUIResource, this * has the effect of letting the font of the JTree show * through. On the other hand, if font is non-null, and not * a FontUIResource, the font becomes font. */ public void setFont(Font font) { if(font instanceof FontUIResource) font = null; super.setFont(font); } /** * Gets the font of this component. * @return this component's font; if a font has not been set * for this component, the font of its parent is returned */ public Font getFont() { Font font = super.getFont(); if (font == null && tree != null) { // Strive to return a non-null value, otherwise the html support // will typically pick up the wrong font in certain situations. font = tree.getFont(); } return font; } /** * Subclassed to map ColorUIResources to null. If * color is null, or a ColorUIResource, this * has the effect of letting the background color of the JTree show * through. On the other hand, if color is non-null, and not * a ColorUIResource, the background becomes * color. */ public void setBackground(Color color) { if(color instanceof ColorUIResource) color = null; super.setBackground(color); } /** * Configures the renderer based on the passed in components. * The value is set from messaging the tree with * convertValueToText, which ultimately invokes * toString on value. * The foreground color is set based on the selection and the icon * is set based on on leaf and expanded. */ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { String stringValue = tree.convertValueToText(value, sel, expanded, leaf, row, hasFocus); this.tree = tree; this.hasFocus = hasFocus; setText(stringValue); if(sel) setForeground(getTextSelectionColor()); else setForeground(getTextNonSelectionColor()); // There needs to be a way to specify disabled icons. if (!tree.isEnabled()) { setEnabled(false); if (leaf) { setDisabledIcon(getLeafIcon()); } else if (expanded) { setDisabledIcon(getOpenIcon()); } else { setDisabledIcon(getClosedIcon()); } } else { setEnabled(true); if (leaf) { setIcon(getLeafIcon()); } else if (expanded) { setIcon(getOpenIcon()); } else { setIcon(getClosedIcon()); } } setComponentOrientation(tree.getComponentOrientation()); selected = sel; return this; } /** * Paints the value. The background is filled based on selected. */ public void paint(Graphics g) { Color bColor; if(selected) { bColor = getBackgroundSelectionColor(); } else { bColor = getBackgroundNonSelectionColor(); if(bColor == null) bColor = getBackground(); } int imageOffset = -1; if(bColor != null) { Icon currentI = getIcon(); imageOffset = getLabelStart(); g.setColor(bColor); if(getComponentOrientation().isLeftToRight()) { g.fillRect(imageOffset, 0, getWidth() - imageOffset, getHeight()); } else { g.fillRect(0, 0, getWidth() - imageOffset, getHeight()); } } if (hasFocus) { if (drawsFocusBorderAroundIcon) { imageOffset = 0; } else if (imageOffset == -1) { imageOffset = getLabelStart(); } if(getComponentOrientation().isLeftToRight()) { paintFocus(g, imageOffset, 0, getWidth() - imageOffset, getHeight()); } else { paintFocus(g, 0, 0, getWidth() - imageOffset, getHeight()); } } super.paint(g); } private void paintFocus(Graphics g, int x, int y, int w, int h) { Color bsColor = getBorderSelectionColor(); if (bsColor != null && (selected || !drawDashedFocusIndicator)) { g.setColor(bsColor); g.drawRect(x, y, w - 1, h - 1); } if (drawDashedFocusIndicator) { Color color; if (selected) { color = getBackgroundSelectionColor(); } else { color = getBackgroundNonSelectionColor(); if(color == null) { color = getBackground(); } } if (treeBGColor != color) { treeBGColor = color; focusBGColor = new Color(~color.getRGB()); } g.setColor(focusBGColor); BasicGraphicsUtils.drawDashedRect(g, x, y, w, h); } } private int getLabelStart() { Icon currentI = getIcon(); if(currentI != null && getText() != null) { return currentI.getIconWidth() + Math.max(0, getIconTextGap() - 1); } return 0; } /** * Overrides JComponent.getPreferredSize to * return slightly wider preferred size value. */ public Dimension getPreferredSize() { Dimension retDimension = super.getPreferredSize(); if(retDimension != null) retDimension = new Dimension(retDimension.width + 3, retDimension.height); return retDimension; } /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void validate() {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. * * @since 1.5 */ public void invalidate() {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void revalidate() {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void repaint(long tm, int x, int y, int width, int height) {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void repaint(Rectangle r) {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. * * @since 1.5 */ public void repaint() {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { // Strings get interned... if (propertyName=="text") super.firePropertyChange(propertyName, oldValue, newValue); } /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void firePropertyChange(String propertyName, char oldValue, char newValue) {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void firePropertyChange(String propertyName, short oldValue, short newValue) {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void firePropertyChange(String propertyName, int oldValue, int newValue) {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void firePropertyChange(String propertyName, long oldValue, long newValue) {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void firePropertyChange(String propertyName, float oldValue, float newValue) {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void firePropertyChange(String propertyName, double oldValue, double newValue) {} /** * Overridden for performance reasons. * See the Implementation Note * for more information. */ public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {} }