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