Source for javax.swing.tree.DefaultTreeCellRenderer

   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:    */
 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: }