001/* DefaultTreeCellRenderer.java
002 Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING.  If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library.  Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module.  An independent module is a module which is not derived from
033 or based on this library.  If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so.  If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039package javax.swing.tree;
040
041import java.awt.Color;
042import java.awt.Component;
043import java.awt.Dimension;
044import java.awt.Font;
045import java.awt.Graphics;
046import java.awt.Rectangle;
047
048import javax.swing.Icon;
049import javax.swing.JLabel;
050import javax.swing.JTree;
051import javax.swing.LookAndFeel;
052import javax.swing.UIManager;
053import javax.swing.plaf.UIResource;
054
055/**
056 * A default implementation of the {@link TreeCellRenderer} interface.
057 *
058 * @author Andrew Selkirk
059 */
060public class DefaultTreeCellRenderer
061  extends JLabel
062  implements TreeCellRenderer
063{
064
065  /**
066   * A flag indicating the current selection status.
067   */
068  protected boolean selected;
069
070  /**
071   * A flag indicating the current focus status.
072   */
073  protected boolean hasFocus;
074
075  /**
076   * Indicates if the focus border is also drawn around the icon.
077   */
078  private boolean drawsFocusBorderAroundIcon;
079
080  /**
081   * The icon used to represent non-leaf nodes that are closed.
082   *
083   * @see #setClosedIcon(Icon)
084   */
085  protected transient Icon closedIcon;
086
087  /**
088   * The icon used to represent leaf nodes.
089   *
090   * @see #setLeafIcon(Icon)
091   */
092  protected transient Icon leafIcon;
093
094  /**
095   * The icon used to represent non-leaf nodes that are open.
096   *
097   * @see #setOpenIcon(Icon)
098   */
099  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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
714  public void firePropertyChange(String name, boolean oldValue,
715                                 boolean newValue)
716  {
717    //  Overridden for performance reasons.
718  }
719
720}