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