1 /* DefaultTreeCellRenderer.java
2  Copyright (C) 2002, 2004, 2006, 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.tree;
40 
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Dimension;
44 import java.awt.Font;
45 import java.awt.Graphics;
46 import java.awt.Rectangle;
47 
48 import javax.swing.Icon;
49 import javax.swing.JLabel;
50 import javax.swing.JTree;
51 import javax.swing.LookAndFeel;
52 import javax.swing.UIManager;
53 import javax.swing.plaf.UIResource;
54 
55 /**
56  * A default implementation of the {@link TreeCellRenderer} interface.
57  *
58  * @author Andrew Selkirk
59  */
60 public class DefaultTreeCellRenderer
61   extends JLabel
62   implements TreeCellRenderer
63 {
64 
65   /**
66    * A flag indicating the current selection status.
67    */
68   protected boolean selected;
69 
70   /**
71    * A flag indicating the current focus status.
72    */
73   protected boolean hasFocus;
74 
75   /**
76    * Indicates if the focus border is also drawn around the icon.
77    */
78   private boolean drawsFocusBorderAroundIcon;
79 
80   /**
81    * The icon used to represent non-leaf nodes that are closed.
82    *
83    * @see #setClosedIcon(Icon)
84    */
85   protected transient Icon closedIcon;
86 
87   /**
88    * The icon used to represent leaf nodes.
89    *
90    * @see #setLeafIcon(Icon)
91    */
92   protected transient Icon leafIcon;
93 
94   /**
95    * The icon used to represent non-leaf nodes that are open.
96    *
97    * @see #setOpenIcon(Icon)
98    */
99   protected transient Icon openIcon;
100 
101   /**
102    * The color used for text in selected cells.
103    *
104    * @see #setTextSelectionColor(Color)
105    */
106   protected Color textSelectionColor;
107 
108   /**
109    * The color used for text in non-selected cells.
110    *
111    * @see #setTextNonSelectionColor(Color)
112    */
113   protected Color textNonSelectionColor;
114 
115   /**
116    * The background color for selected cells.
117    *
118    * @see #setBackgroundSelectionColor(Color)
119    */
120   protected Color backgroundSelectionColor;
121 
122   /**
123    * The background color for non-selected cells.
124    *
125    * @see #setBackgroundNonSelectionColor(Color)
126    */
127   protected Color backgroundNonSelectionColor;
128 
129   /**
130    * The border color for selected tree cells.
131    *
132    * @see #setBorderSelectionColor(Color)
133    */
134   protected Color borderSelectionColor;
135 
136   /**
137    * Creates a new tree cell renderer with defaults appropriate for the
138    * current {@link LookAndFeel}.
139    */
DefaultTreeCellRenderer()140   public DefaultTreeCellRenderer()
141   {
142     setLeafIcon(getDefaultLeafIcon());
143     setOpenIcon(getDefaultOpenIcon());
144     setClosedIcon(getDefaultClosedIcon());
145 
146     setTextNonSelectionColor(UIManager.getColor("Tree.textForeground"));
147     setTextSelectionColor(UIManager.getColor("Tree.selectionForeground"));
148     setBackgroundNonSelectionColor(UIManager.getColor("Tree.textBackground"));
149     setBackgroundSelectionColor(UIManager.getColor("Tree.selectionBackground"));
150     setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor"));
151     Object val = UIManager.get("Tree.drawsFocusBorderAroundIcon");
152     drawsFocusBorderAroundIcon = val != null && ((Boolean) val).booleanValue();
153   }
154 
155   /**
156    * Returns the default icon for non-leaf tree cells that are open (expanded).
157    * The icon is fetched from the defaults table for the current
158    * {@link LookAndFeel} using the key <code>Tree.openIcon</code>.
159    *
160    * @return The default icon.
161    */
getDefaultOpenIcon()162   public Icon getDefaultOpenIcon()
163   {
164     return UIManager.getIcon("Tree.openIcon");
165   }
166 
167   /**
168    * Returns the default icon for non-leaf tree cells that are closed (not
169    * expanded).  The icon is fetched from the defaults table for the current
170    * {@link LookAndFeel} using the key <code>Tree.closedIcon</code>.
171    *
172    * @return The default icon.
173    */
getDefaultClosedIcon()174   public Icon getDefaultClosedIcon()
175   {
176     return UIManager.getIcon("Tree.closedIcon");
177   }
178 
179   /**
180    * Returns the default icon for leaf tree cells.  The icon is fetched from
181    * the defaults table for the current {@link LookAndFeel} using the key
182    * <code>Tree.leafIcon</code>.
183    *
184    * @return The default icon.
185    */
getDefaultLeafIcon()186   public Icon getDefaultLeafIcon()
187   {
188     return UIManager.getIcon("Tree.leafIcon");
189   }
190 
191   /**
192    * Sets the icon to be displayed for non-leaf nodes that are open (expanded).
193    * Set this to <code>null</code> if no icon is required.
194    *
195    * @param icon  the icon (<code>null</code> permitted).
196    *
197    * @see #getOpenIcon()
198    */
setOpenIcon(Icon icon)199   public void setOpenIcon(Icon icon)
200   {
201     openIcon = icon;
202   }
203 
204   /**
205    * Returns the icon displayed for non-leaf nodes that are open (expanded).
206    * The default value is initialised from the {@link LookAndFeel}.
207    *
208    * @return The open icon (possibly <code>null</code>).
209    *
210    * @see #setOpenIcon(Icon)
211    */
getOpenIcon()212   public Icon getOpenIcon()
213   {
214     return openIcon;
215   }
216 
217   /**
218    * Sets the icon to be displayed for non-leaf nodes that are closed.  Set
219    * this to <code>null</code> if no icon is required.
220    *
221    * @param icon  the icon (<code>null</code> permitted).
222    *
223    * @see #getClosedIcon()
224    */
setClosedIcon(Icon icon)225   public void setClosedIcon(Icon icon)
226   {
227     closedIcon = icon;
228   }
229 
230   /**
231    * Returns the icon displayed for non-leaf nodes that are closed.  The
232    * default value is initialised from the {@link LookAndFeel}.
233    *
234    * @return The closed icon (possibly <code>null</code>).
235    *
236    * @see #setClosedIcon(Icon)
237    */
getClosedIcon()238   public Icon getClosedIcon()
239   {
240     return closedIcon;
241   }
242 
243   /**
244    * Sets the icon to be displayed for leaf nodes.  Set this to
245    * <code>null</code> if no icon is required.
246    *
247    * @param icon  the icon (<code>null</code> permitted).
248    *
249    * @see #getLeafIcon()
250    */
setLeafIcon(Icon icon)251   public void setLeafIcon(Icon icon)
252   {
253     leafIcon = icon;
254   }
255 
256   /**
257    * Returns the icon displayed for leaf nodes.  The default value is
258    * initialised from the {@link LookAndFeel}.
259    *
260    * @return The leaf icon (possibly <code>null</code>).
261    *
262    * @see #setLeafIcon(Icon)
263    */
getLeafIcon()264   public Icon getLeafIcon()
265   {
266     return leafIcon;
267   }
268 
269   /**
270    * Sets the text color for tree cells that are selected.
271    *
272    * @param c  the color (<code>null</code> permitted).
273    *
274    * @see #getTextSelectionColor()
275    */
setTextSelectionColor(Color c)276   public void setTextSelectionColor(Color c)
277   {
278     textSelectionColor = c;
279   }
280 
281   /**
282    * Returns the text color for tree cells that are selected.
283    * The default value is obtained from the {@link LookAndFeel} defaults
284    * table using the key <code>Tree.selectionForeground</code>.
285    *
286    * @return The text color for tree cells that are selected.
287    *
288    * @see #setTextSelectionColor(Color)
289    */
getTextSelectionColor()290   public Color getTextSelectionColor()
291   {
292     return textSelectionColor;
293   }
294 
295   /**
296    * Sets the text color for tree cells that are not selected.
297    *
298    * @param c  the color (<code>null</code> permitted).
299    *
300    * @see #getTextNonSelectionColor()
301    */
setTextNonSelectionColor(Color c)302   public void setTextNonSelectionColor(Color c)
303   {
304     textNonSelectionColor = c;
305   }
306 
307   /**
308    * Returns the text color for tree cells that are not selected.
309    * The default value is obtained from the {@link LookAndFeel} defaults
310    * table using the key <code>Tree.selectionForeground</code>.
311    *
312    * @return The background color for tree cells that are not selected.
313    *
314    * @see #setTextgroundNonSelectionColor(Color)
315    */
getTextNonSelectionColor()316   public Color getTextNonSelectionColor()
317   {
318     return textNonSelectionColor;
319   }
320 
321   /**
322    * Sets the background color for tree cells that are selected.
323    *
324    * @param c  the color (<code>null</code> permitted).
325    *
326    * @see #getBackgroundSelectionColor()
327    */
setBackgroundSelectionColor(Color c)328   public void setBackgroundSelectionColor(Color c)
329   {
330     backgroundSelectionColor = c;
331   }
332 
333   /**
334    * Returns the background color for tree cells that are selected.
335    * The default value is obtained from the {@link LookAndFeel} defaults
336    * table using the key <code>Tree.selectionBackground</code>.
337    *
338    * @return The background color for tree cells that are selected.
339    *
340    * @see #setBackgroundSelectionColor(Color)
341    */
getBackgroundSelectionColor()342   public Color getBackgroundSelectionColor()
343   {
344     return backgroundSelectionColor;
345   }
346 
347   /**
348    * Sets the background color for tree cells that are not selected.
349    *
350    * @param c  the color (<code>null</code> permitted).
351    *
352    * @see #getBackgroundNonSelectionColor()
353    */
setBackgroundNonSelectionColor(Color c)354   public void setBackgroundNonSelectionColor(Color c)
355   {
356     backgroundNonSelectionColor = c;
357   }
358 
359   /**
360    * Returns the background color for tree cells that are not selected.
361    * The default value is obtained from the {@link LookAndFeel} defaults
362    * table using the key <code>Tree.textBackground</code>.
363    *
364    * @return The background color for tree cells that are not selected.
365    *
366    * @see #setBackgroundNonSelectionColor(Color)
367    */
getBackgroundNonSelectionColor()368   public Color getBackgroundNonSelectionColor()
369   {
370     return backgroundNonSelectionColor;
371   }
372 
373   /**
374    * Sets the border color for tree cells that are selected.
375    *
376    * @param c  the color (<code>null</code> permitted).
377    *
378    * @see #getBorderSelectionColor()
379    */
setBorderSelectionColor(Color c)380   public void setBorderSelectionColor(Color c)
381   {
382     borderSelectionColor = c;
383   }
384 
385   /**
386    * Returns the border color for tree cells that are selected.
387    * The default value is obtained from the {@link LookAndFeel} defaults
388    * table using the key <code>Tree.selectionBorderColor</code>.
389    *
390    * @return The border color for tree cells that are selected.
391    *
392    * @see #setBorderSelectionColor(Color)
393    */
getBorderSelectionColor()394   public Color getBorderSelectionColor()
395   {
396     return borderSelectionColor;
397   }
398 
399   /**
400    * Sets the font.
401    *
402    * @param f the font.
403    *
404    * @see #getFont()
405    */
setFont(Font f)406   public void setFont(Font f)
407   {
408     if (f != null && f instanceof UIResource)
409       f = null;
410     super.setFont(f);
411   }
412 
413   /**
414    * Sets the background color.
415    *
416    * @param c the color.
417    */
setBackground(Color c)418   public void setBackground(Color c)
419   {
420     if (c != null && c instanceof UIResource)
421       c = null;
422     super.setBackground(c);
423   }
424 
425   /**
426    * Returns a component (in fact <code>this</code>) that can be used to
427    * render a tree cell with the specified state.
428    *
429    * @param tree  the tree that the cell belongs to.
430    * @param val  the cell value.
431    * @param selected  indicates whether or not the cell is selected.
432    * @param expanded  indicates whether or not the cell is expanded.
433    * @param leaf  indicates whether or not the cell is a leaf in the tree.
434    * @param row  the row index.
435    * @param hasFocus  indicates whether or not the cell has the focus.
436    *
437    * @return <code>this</code>.
438    */
getTreeCellRendererComponent(JTree tree, Object val, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus)439   public Component getTreeCellRendererComponent(JTree tree, Object val,
440                                                 boolean selected,
441                                                 boolean expanded, boolean leaf,
442                                                 int row, boolean hasFocus)
443   {
444     if (leaf)
445       setIcon(getLeafIcon());
446     else if (expanded)
447       setIcon(getOpenIcon());
448     else
449       setIcon(getClosedIcon());
450 
451     setText(val.toString());
452     this.selected = selected;
453     this.hasFocus = hasFocus;
454     setHorizontalAlignment(LEFT);
455     setOpaque(false);
456     setVerticalAlignment(CENTER);
457     setEnabled(true);
458     super.setFont(UIManager.getFont("Tree.font"));
459 
460     if (selected)
461       {
462         super.setBackground(getBackgroundSelectionColor());
463         setForeground(getTextSelectionColor());
464 
465         if (hasFocus)
466           setBorderSelectionColor(UIManager.getLookAndFeelDefaults().
467                                   getColor("Tree.selectionBorderColor"));
468         else
469           setBorderSelectionColor(null);
470       }
471     else
472       {
473         super.setBackground(getBackgroundNonSelectionColor());
474         setForeground(getTextNonSelectionColor());
475         setBorderSelectionColor(null);
476       }
477 
478     return this;
479   }
480 
481   /**
482    * Returns the current font.
483    *
484    * @return The current font.
485    *
486    * @see #setFont(Font)
487    */
getFont()488   public Font getFont()
489   {
490     return super.getFont();
491   }
492 
493   /**
494    * Paints the value. The background is filled based on selected.
495    *
496    * @param g the graphics device.
497    */
paint(Graphics g)498   public void paint(Graphics g)
499   {
500     // Determine background color.
501     Color bgColor;
502     if (selected)
503       bgColor = getBackgroundSelectionColor();
504     else
505       {
506         bgColor = getBackgroundNonSelectionColor();
507         if (bgColor == null)
508           bgColor = getBackground();
509       }
510     // Paint background.
511     int xOffset = -1;
512     if (bgColor != null)
513       {
514         xOffset = getXOffset();
515         g.setColor(bgColor);
516         g.fillRect(xOffset, 0, getWidth() - xOffset, getHeight());
517       }
518 
519     if (hasFocus)
520       {
521         if (drawsFocusBorderAroundIcon)
522           xOffset = 0;
523         else if (xOffset == -1)
524           xOffset = getXOffset();
525         paintFocus(g, xOffset, 0, getWidth() - xOffset, getHeight());
526       }
527     super.paint(g);
528   }
529 
530   /**
531    * Paints the focus indicator.
532    */
paintFocus(Graphics g, int x, int y, int w, int h)533   private void paintFocus(Graphics g, int x, int y, int w, int h)
534   {
535     Color col = getBorderSelectionColor();
536     if (col != null)
537       {
538         g.setColor(col);
539         g.drawRect(x, y, w - 1, h - 1);
540       }
541   }
542 
543   /**
544    * Determines the X offset of the label that is caused by
545    * the icon.
546    *
547    * @return the X offset of the label
548    */
getXOffset()549   private int getXOffset()
550   {
551     Icon i = getIcon();
552     int offs = 0;
553     if (i != null && getText() != null)
554       offs = i.getIconWidth() + Math.max(0, getIconTextGap() - 1);
555     return offs;
556   }
557 
558   /**
559    * Returns the preferred size of the cell.
560    *
561    * @return The preferred size of the cell.
562    */
getPreferredSize()563   public Dimension getPreferredSize()
564   {
565     Dimension size = super.getPreferredSize();
566     size.width += 3;
567     return size;
568   }
569 
570   /**
571    * For performance reasons, this method is overridden to do nothing.
572    */
validate()573   public void validate()
574   {
575     // Overridden for performance reasons.
576   }
577 
578   /**
579    * For performance reasons, this method is overridden to do nothing.
580    */
revalidate()581   public void revalidate()
582   {
583     // Overridden for performance reasons.
584   }
585 
586   /**
587    * For performance reasons, this method is overridden to do nothing.
588    *
589    * @param tm ignored
590    * @param x coordinate of the region to mark as dirty
591    * @param y coordinate of the region to mark as dirty
592    * @param width dimension of the region to mark as dirty
593    * @param height dimension of the region to mark as dirty
594    */
repaint(long tm, int x, int y, int width, int height)595   public void repaint(long tm, int x, int y, int width, int height)
596   {
597     // Overridden for performance reasons.
598   }
599 
600   /**
601    * For performance reasons, this method is overridden to do nothing.
602    *
603    * @param area  the area to repaint.
604    */
repaint(Rectangle area)605   public void repaint(Rectangle area)
606   {
607     // Overridden for performance reasons.
608   }
609 
610   /**
611    * For performance reasons, this method is overridden to do nothing.
612    *
613    * @param name  the property name.
614    * @param oldValue  the old value.
615    * @param newValue  the new value.
616    */
firePropertyChange(String name, Object oldValue, Object newValue)617   protected void firePropertyChange(String name, Object oldValue,
618                                     Object newValue)
619   {
620     // Overridden for performance reasons.
621   }
622 
623   /**
624    * For performance reasons, this method is overridden to do nothing.
625    *
626    * @param name  the property name.
627    * @param oldValue  the old value.
628    * @param newValue  the new value.
629    */
firePropertyChange(String name, byte oldValue, byte newValue)630   public void firePropertyChange(String name, byte oldValue, byte newValue)
631   {
632     // Overridden for performance reasons.
633   }
634 
635   /**
636    * For performance reasons, this method is overridden to do nothing.
637    *
638    * @param name  the property name.
639    * @param oldValue  the old value.
640    * @param newValue  the new value.
641    */
firePropertyChange(String name, char oldValue, char newValue)642   public void firePropertyChange(String name, char oldValue, char newValue)
643   {
644     // Overridden for performance reasons.
645   }
646 
647   /**
648    * For performance reasons, this method is overridden to do nothing.
649    *
650    * @param name  the property name.
651    * @param oldValue  the old value.
652    * @param newValue  the new value.
653    */
firePropertyChange(String name, short oldValue, short newValue)654   public void firePropertyChange(String name, short oldValue, short newValue)
655   {
656     // Overridden for performance reasons.
657   }
658 
659   /**
660    * For performance reasons, this method is overridden to do nothing.
661    *
662    * @param name  the property name.
663    * @param oldValue  the old value.
664    * @param newValue  the new value.
665    */
firePropertyChange(String name, int oldValue, int newValue)666   public void firePropertyChange(String name, int oldValue, int newValue)
667   {
668     // Overridden for performance reasons.
669   }
670 
671   /**
672    * For performance reasons, this method is overridden to do nothing.
673    *
674    * @param name  the property name.
675    * @param oldValue  the old value.
676    * @param newValue  the new value.
677    */
firePropertyChange(String name, long oldValue, long newValue)678   public void firePropertyChange(String name, long oldValue, long newValue)
679   {
680     // Overridden for performance reasons.
681   }
682 
683   /**
684    * For performance reasons, this method is overridden to do nothing.
685    *
686    * @param name  the property name.
687    * @param oldValue  the old value.
688    * @param newValue  the new value.
689    */
firePropertyChange(String name, float oldValue, float newValue)690   public void firePropertyChange(String name, float oldValue, float newValue)
691   {
692     // Overridden for performance reasons.
693   }
694 
695   /**
696    * For performance reasons, this method is overridden to do nothing.
697    *
698    * @param name  the property name.
699    * @param oldValue  the old value.
700    * @param newValue  the new value.
701    */
firePropertyChange(String name, double oldValue, double newValue)702   public void firePropertyChange(String name, double oldValue, double newValue)
703   {
704     //  Overridden for performance reasons.
705   }
706 
707   /**
708    * For performance reasons, this method is overridden to do nothing.
709    *
710    * @param name  the property name.
711    * @param oldValue  the old value.
712    * @param newValue  the new value.
713    */
firePropertyChange(String name, boolean oldValue, boolean newValue)714   public void firePropertyChange(String name, boolean oldValue,
715                                  boolean newValue)
716   {
717     //  Overridden for performance reasons.
718   }
719 
720 }
721