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 039 package javax.swing.tree; 040 041 import java.awt.Color; 042 import java.awt.Component; 043 import java.awt.Dimension; 044 import java.awt.Font; 045 import java.awt.FontMetrics; 046 import java.awt.Graphics; 047 import java.awt.Insets; 048 import java.awt.Rectangle; 049 050 import javax.swing.Icon; 051 import javax.swing.JLabel; 052 import javax.swing.JTree; 053 import javax.swing.LookAndFeel; 054 import javax.swing.SwingUtilities; 055 import javax.swing.UIManager; 056 import javax.swing.border.Border; 057 import javax.swing.plaf.UIResource; 058 059 /** 060 * A default implementation of the {@link TreeCellRenderer} interface. 061 * 062 * @author Andrew Selkirk 063 */ 064 public class DefaultTreeCellRenderer 065 extends JLabel 066 implements TreeCellRenderer 067 { 068 069 /** 070 * A flag indicating the current selection status. 071 */ 072 protected boolean selected; 073 074 /** 075 * A flag indicating the current focus status. 076 */ 077 protected boolean hasFocus; 078 079 /** 080 * Indicates if the focus border is also drawn around the icon. 081 */ 082 private boolean drawsFocusBorderAroundIcon; 083 084 /** 085 * The icon used to represent non-leaf nodes that are closed. 086 * 087 * @see #setClosedIcon(Icon) 088 */ 089 protected transient Icon closedIcon; 090 091 /** 092 * The icon used to represent leaf nodes. 093 * 094 * @see #setLeafIcon(Icon) 095 */ 096 protected transient Icon leafIcon; 097 098 /** 099 * 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 }