1 /* 2 * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.plaf.synth; 26 27 import java.awt.Color; 28 import java.awt.Component; 29 import java.awt.Graphics; 30 import java.awt.Insets; 31 import java.awt.Rectangle; 32 import java.beans.PropertyChangeEvent; 33 import java.beans.PropertyChangeListener; 34 import java.util.Enumeration; 35 import javax.swing.DefaultCellEditor; 36 import javax.swing.Icon; 37 import javax.swing.JComponent; 38 import javax.swing.JTextField; 39 import javax.swing.JTree; 40 import javax.swing.LookAndFeel; 41 import javax.swing.plaf.ComponentUI; 42 import javax.swing.plaf.UIResource; 43 import javax.swing.plaf.basic.BasicTreeUI; 44 import javax.swing.tree.DefaultTreeCellEditor; 45 import javax.swing.tree.DefaultTreeCellRenderer; 46 import javax.swing.tree.TreeCellEditor; 47 import javax.swing.tree.TreeCellRenderer; 48 import javax.swing.tree.TreeModel; 49 import javax.swing.tree.TreePath; 50 import sun.swing.plaf.synth.SynthIcon; 51 52 /** 53 * Provides the Synth L&F UI delegate for 54 * {@link javax.swing.JTree}. 55 * 56 * @author Scott Violet 57 * @since 1.7 58 */ 59 public class SynthTreeUI extends BasicTreeUI 60 implements PropertyChangeListener, SynthUI { 61 private SynthStyle style; 62 private SynthStyle cellStyle; 63 64 private SynthContext paintContext; 65 66 private boolean drawHorizontalLines; 67 private boolean drawVerticalLines; 68 69 private Object linesStyle; 70 71 private int padding; 72 73 private boolean useTreeColors; 74 75 private Icon expandedIconWrapper = new ExpandedIconWrapper(); 76 77 /** 78 * Creates a new UI object for the given component. 79 * 80 * @param x component to create UI object for 81 * @return the UI object 82 */ 83 public static ComponentUI createUI(JComponent x) { 84 return new SynthTreeUI(); 85 } 86 87 /** 88 * {@inheritDoc} 89 */ 90 @Override 91 public Icon getExpandedIcon() { 92 return expandedIconWrapper; 93 } 94 95 /** 96 * {@inheritDoc} 97 */ 98 @Override 99 protected void installDefaults() { 100 updateStyle(tree); 101 } 102 103 private void updateStyle(JTree tree) { 104 SynthContext context = getContext(tree, ENABLED); 105 SynthStyle oldStyle = style; 106 107 style = SynthLookAndFeel.updateStyle(context, this); 108 if (style != oldStyle) { 109 Object value; 110 111 setExpandedIcon(style.getIcon(context, "Tree.expandedIcon")); 112 setCollapsedIcon(style.getIcon(context, "Tree.collapsedIcon")); 113 114 setLeftChildIndent(style.getInt(context, "Tree.leftChildIndent", 115 0)); 116 setRightChildIndent(style.getInt(context, "Tree.rightChildIndent", 117 0)); 118 119 drawHorizontalLines = style.getBoolean( 120 context, "Tree.drawHorizontalLines",true); 121 drawVerticalLines = style.getBoolean( 122 context, "Tree.drawVerticalLines", true); 123 linesStyle = style.get(context, "Tree.linesStyle"); 124 125 value = style.get(context, "Tree.rowHeight"); 126 if (value != null) { 127 LookAndFeel.installProperty(tree, "rowHeight", value); 128 } 129 130 value = style.get(context, "Tree.scrollsOnExpand"); 131 LookAndFeel.installProperty(tree, "scrollsOnExpand", 132 value != null? value : Boolean.TRUE); 133 134 padding = style.getInt(context, "Tree.padding", 0); 135 136 largeModel = (tree.isLargeModel() && tree.getRowHeight() > 0); 137 138 useTreeColors = style.getBoolean(context, 139 "Tree.rendererUseTreeColors", true); 140 141 Boolean showsRootHandles = style.getBoolean( 142 context, "Tree.showsRootHandles", Boolean.TRUE); 143 LookAndFeel.installProperty( 144 tree, JTree.SHOWS_ROOT_HANDLES_PROPERTY, showsRootHandles); 145 146 if (oldStyle != null) { 147 uninstallKeyboardActions(); 148 installKeyboardActions(); 149 } 150 } 151 context.dispose(); 152 153 context = getContext(tree, Region.TREE_CELL, ENABLED); 154 cellStyle = SynthLookAndFeel.updateStyle(context, this); 155 context.dispose(); 156 } 157 158 /** 159 * {@inheritDoc} 160 */ 161 @Override 162 protected void installListeners() { 163 super.installListeners(); 164 tree.addPropertyChangeListener(this); 165 } 166 167 /** 168 * {@inheritDoc} 169 */ 170 @Override 171 public SynthContext getContext(JComponent c) { 172 return getContext(c, SynthLookAndFeel.getComponentState(c)); 173 } 174 175 private SynthContext getContext(JComponent c, int state) { 176 return SynthContext.getContext(c, style, state); 177 } 178 179 private SynthContext getContext(JComponent c, Region region) { 180 return getContext(c, region, getComponentState(c, region)); 181 } 182 183 private SynthContext getContext(JComponent c, Region region, int state) { 184 return SynthContext.getContext(c, region, cellStyle, state); 185 } 186 187 private int getComponentState(JComponent c, Region region) { 188 // Always treat the cell as selected, will be adjusted appropriately 189 // when painted. 190 return ENABLED | SELECTED; 191 } 192 193 /** 194 * {@inheritDoc} 195 */ 196 @Override 197 protected TreeCellEditor createDefaultCellEditor() { 198 TreeCellRenderer renderer = tree.getCellRenderer(); 199 DefaultTreeCellEditor editor; 200 201 if(renderer != null && (renderer instanceof DefaultTreeCellRenderer)) { 202 editor = new SynthTreeCellEditor(tree, (DefaultTreeCellRenderer) 203 renderer); 204 } 205 else { 206 editor = new SynthTreeCellEditor(tree, null); 207 } 208 return editor; 209 } 210 211 /** 212 * {@inheritDoc} 213 */ 214 @Override 215 protected TreeCellRenderer createDefaultCellRenderer() { 216 return new SynthTreeCellRenderer(); 217 } 218 219 /** 220 * {@inheritDoc} 221 */ 222 @Override 223 protected void uninstallDefaults() { 224 SynthContext context = getContext(tree, ENABLED); 225 226 style.uninstallDefaults(context); 227 context.dispose(); 228 style = null; 229 230 context = getContext(tree, Region.TREE_CELL, ENABLED); 231 cellStyle.uninstallDefaults(context); 232 context.dispose(); 233 cellStyle = null; 234 235 236 if (tree.getTransferHandler() instanceof UIResource) { 237 tree.setTransferHandler(null); 238 } 239 } 240 241 /** 242 * {@inheritDoc} 243 */ 244 @Override 245 protected void uninstallListeners() { 246 super.uninstallListeners(); 247 tree.removePropertyChangeListener(this); 248 } 249 250 /** 251 * Notifies this UI delegate to repaint the specified component. 252 * This method paints the component background, then calls 253 * the {@link #paint(SynthContext,Graphics)} method. 254 * 255 * <p>In general, this method does not need to be overridden by subclasses. 256 * All Look and Feel rendering code should reside in the {@code paint} method. 257 * 258 * @param g the {@code Graphics} object used for painting 259 * @param c the component being painted 260 * @see #paint(SynthContext,Graphics) 261 */ 262 @Override 263 public void update(Graphics g, JComponent c) { 264 SynthContext context = getContext(c); 265 266 SynthLookAndFeel.update(context, g); 267 context.getPainter().paintTreeBackground(context, 268 g, 0, 0, c.getWidth(), c.getHeight()); 269 paint(context, g); 270 context.dispose(); 271 } 272 273 /** 274 * {@inheritDoc} 275 */ 276 @Override 277 public void paintBorder(SynthContext context, Graphics g, int x, 278 int y, int w, int h) { 279 context.getPainter().paintTreeBorder(context, g, x, y, w, h); 280 } 281 282 /** 283 * Paints the specified component according to the Look and Feel. 284 * <p>This method is not used by Synth Look and Feel. 285 * Painting is handled by the {@link #paint(SynthContext,Graphics)} method. 286 * 287 * @param g the {@code Graphics} object used for painting 288 * @param c the component being painted 289 * @see #paint(SynthContext,Graphics) 290 */ 291 @Override 292 public void paint(Graphics g, JComponent c) { 293 SynthContext context = getContext(c); 294 295 paint(context, g); 296 context.dispose(); 297 } 298 299 /** 300 * Paints the specified component. 301 * 302 * @param context context for the component being painted 303 * @param g the {@code Graphics} object used for painting 304 * @see #update(Graphics,JComponent) 305 */ 306 protected void paint(SynthContext context, Graphics g) { 307 paintContext = context; 308 309 updateLeadSelectionRow(); 310 311 Rectangle paintBounds = g.getClipBounds(); 312 Insets insets = tree.getInsets(); 313 TreePath initialPath = getClosestPathForLocation(tree, 0, 314 paintBounds.y); 315 Enumeration paintingEnumerator = treeState.getVisiblePathsFrom 316 (initialPath); 317 int row = treeState.getRowForPath(initialPath); 318 int endY = paintBounds.y + paintBounds.height; 319 TreeModel treeModel = tree.getModel(); 320 SynthContext cellContext = getContext(tree, Region.TREE_CELL); 321 322 drawingCache.clear(); 323 324 setHashColor(context.getStyle().getColor(context, 325 ColorType.FOREGROUND)); 326 327 if (paintingEnumerator != null) { 328 // First pass, draw the rows 329 330 boolean done = false; 331 boolean isExpanded; 332 boolean hasBeenExpanded; 333 boolean isLeaf; 334 Rectangle rowBounds = new Rectangle(0, 0, tree.getWidth(),0); 335 Rectangle bounds; 336 TreePath path; 337 TreeCellRenderer renderer = tree.getCellRenderer(); 338 DefaultTreeCellRenderer dtcr = (renderer instanceof 339 DefaultTreeCellRenderer) ? (DefaultTreeCellRenderer) 340 renderer : null; 341 342 configureRenderer(cellContext); 343 while (!done && paintingEnumerator.hasMoreElements()) { 344 path = (TreePath)paintingEnumerator.nextElement(); 345 bounds = getPathBounds(tree, path); 346 if ((path != null) && (bounds != null)) { 347 isLeaf = treeModel.isLeaf(path.getLastPathComponent()); 348 if (isLeaf) { 349 isExpanded = hasBeenExpanded = false; 350 } 351 else { 352 isExpanded = treeState.getExpandedState(path); 353 hasBeenExpanded = tree.hasBeenExpanded(path); 354 } 355 rowBounds.y = bounds.y; 356 rowBounds.height = bounds.height; 357 paintRow(renderer, dtcr, context, cellContext, g, 358 paintBounds, insets, bounds, rowBounds, path, 359 row, isExpanded, hasBeenExpanded, isLeaf); 360 if ((bounds.y + bounds.height) >= endY) { 361 done = true; 362 } 363 } 364 else { 365 done = true; 366 } 367 row++; 368 } 369 370 // Draw the connecting lines and controls. 371 // Find each parent and have them draw a line to their last child 372 boolean rootVisible = tree.isRootVisible(); 373 TreePath parentPath = initialPath; 374 parentPath = parentPath.getParentPath(); 375 while (parentPath != null) { 376 paintVerticalPartOfLeg(g, paintBounds, insets, parentPath); 377 drawingCache.put(parentPath, Boolean.TRUE); 378 parentPath = parentPath.getParentPath(); 379 } 380 done = false; 381 paintingEnumerator = treeState.getVisiblePathsFrom(initialPath); 382 while (!done && paintingEnumerator.hasMoreElements()) { 383 path = (TreePath)paintingEnumerator.nextElement(); 384 bounds = getPathBounds(tree, path); 385 if ((path != null) && (bounds != null)) { 386 isLeaf = treeModel.isLeaf(path.getLastPathComponent()); 387 if (isLeaf) { 388 isExpanded = hasBeenExpanded = false; 389 } 390 else { 391 isExpanded = treeState.getExpandedState(path); 392 hasBeenExpanded = tree.hasBeenExpanded(path); 393 } 394 // See if the vertical line to the parent has been drawn. 395 parentPath = path.getParentPath(); 396 if (parentPath != null) { 397 if (drawingCache.get(parentPath) == null) { 398 paintVerticalPartOfLeg(g, paintBounds, insets, 399 parentPath); 400 drawingCache.put(parentPath, Boolean.TRUE); 401 } 402 paintHorizontalPartOfLeg(g, 403 paintBounds, insets, bounds, 404 path, row, isExpanded, 405 hasBeenExpanded, isLeaf); 406 } 407 else if (rootVisible && row == 0) { 408 paintHorizontalPartOfLeg(g, 409 paintBounds, insets, bounds, 410 path, row, isExpanded, 411 hasBeenExpanded, isLeaf); 412 } 413 if (shouldPaintExpandControl(path, row, isExpanded, 414 hasBeenExpanded, isLeaf)) { 415 paintExpandControl(g, paintBounds, 416 insets, bounds, path, row, 417 isExpanded, hasBeenExpanded,isLeaf); 418 } 419 if ((bounds.y + bounds.height) >= endY) { 420 done = true; 421 } 422 } 423 else { 424 done = true; 425 } 426 row++; 427 } 428 } 429 cellContext.dispose(); 430 431 paintDropLine(g); 432 433 // Empty out the renderer pane, allowing renderers to be gc'ed. 434 rendererPane.removeAll(); 435 436 paintContext = null; 437 } 438 439 private void configureRenderer(SynthContext context) { 440 TreeCellRenderer renderer = tree.getCellRenderer(); 441 442 if (renderer instanceof DefaultTreeCellRenderer) { 443 DefaultTreeCellRenderer r = (DefaultTreeCellRenderer)renderer; 444 SynthStyle style = context.getStyle(); 445 446 context.setComponentState(ENABLED | SELECTED); 447 Color color = r.getTextSelectionColor(); 448 if (color == null || (color instanceof UIResource)) { 449 r.setTextSelectionColor(style.getColor( 450 context, ColorType.TEXT_FOREGROUND)); 451 } 452 color = r.getBackgroundSelectionColor(); 453 if (color == null || (color instanceof UIResource)) { 454 r.setBackgroundSelectionColor(style.getColor( 455 context, ColorType.TEXT_BACKGROUND)); 456 } 457 458 context.setComponentState(ENABLED); 459 color = r.getTextNonSelectionColor(); 460 if (color == null || color instanceof UIResource) { 461 r.setTextNonSelectionColor(style.getColorForState( 462 context, ColorType.TEXT_FOREGROUND)); 463 } 464 color = r.getBackgroundNonSelectionColor(); 465 if (color == null || color instanceof UIResource) { 466 r.setBackgroundNonSelectionColor(style.getColorForState( 467 context, ColorType.TEXT_BACKGROUND)); 468 } 469 } 470 } 471 472 /** 473 * {@inheritDoc} 474 */ 475 @Override 476 protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds, 477 Insets insets, Rectangle bounds, 478 TreePath path, int row, 479 boolean isExpanded, 480 boolean hasBeenExpanded, boolean 481 isLeaf) { 482 if (drawHorizontalLines) { 483 super.paintHorizontalPartOfLeg(g, clipBounds, insets, bounds, 484 path, row, isExpanded, 485 hasBeenExpanded, isLeaf); 486 } 487 } 488 489 /** 490 * {@inheritDoc} 491 */ 492 @Override 493 protected void paintHorizontalLine(Graphics g, JComponent c, int y, 494 int left, int right) { 495 paintContext.getStyle().getGraphicsUtils(paintContext).drawLine( 496 paintContext, "Tree.horizontalLine", g, left, y, right, y, linesStyle); 497 } 498 499 /** 500 * {@inheritDoc} 501 */ 502 @Override 503 protected void paintVerticalPartOfLeg(Graphics g, 504 Rectangle clipBounds, Insets insets, 505 TreePath path) { 506 if (drawVerticalLines) { 507 super.paintVerticalPartOfLeg(g, clipBounds, insets, path); 508 } 509 } 510 511 /** 512 * {@inheritDoc} 513 */ 514 @Override 515 protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, 516 int bottom) { 517 paintContext.getStyle().getGraphicsUtils(paintContext).drawLine( 518 paintContext, "Tree.verticalLine", g, x, top, x, bottom, linesStyle); 519 } 520 521 private void paintRow(TreeCellRenderer renderer, 522 DefaultTreeCellRenderer dtcr, SynthContext treeContext, 523 SynthContext cellContext, Graphics g, Rectangle clipBounds, 524 Insets insets, Rectangle bounds, Rectangle rowBounds, 525 TreePath path, int row, boolean isExpanded, 526 boolean hasBeenExpanded, boolean isLeaf) { 527 // Don't paint the renderer if editing this row. 528 boolean selected = tree.isRowSelected(row); 529 530 JTree.DropLocation dropLocation = tree.getDropLocation(); 531 boolean isDrop = dropLocation != null 532 && dropLocation.getChildIndex() == -1 533 && path == dropLocation.getPath(); 534 535 int state = ENABLED; 536 if (selected || isDrop) { 537 state |= SELECTED; 538 } 539 540 if (tree.isFocusOwner() && row == getLeadSelectionRow()) { 541 state |= FOCUSED; 542 } 543 544 cellContext.setComponentState(state); 545 546 if (dtcr != null && (dtcr.getBorderSelectionColor() instanceof 547 UIResource)) { 548 dtcr.setBorderSelectionColor(style.getColor( 549 cellContext, ColorType.FOCUS)); 550 } 551 SynthLookAndFeel.updateSubregion(cellContext, g, rowBounds); 552 cellContext.getPainter().paintTreeCellBackground(cellContext, g, 553 rowBounds.x, rowBounds.y, rowBounds.width, 554 rowBounds.height); 555 cellContext.getPainter().paintTreeCellBorder(cellContext, g, 556 rowBounds.x, rowBounds.y, rowBounds.width, 557 rowBounds.height); 558 if (editingComponent != null && editingRow == row) { 559 return; 560 } 561 562 int leadIndex; 563 564 if (tree.hasFocus()) { 565 leadIndex = getLeadSelectionRow(); 566 } 567 else { 568 leadIndex = -1; 569 } 570 571 Component component = renderer.getTreeCellRendererComponent( 572 tree, path.getLastPathComponent(), 573 selected, isExpanded, isLeaf, row, 574 (leadIndex == row)); 575 576 rendererPane.paintComponent(g, component, tree, bounds.x, bounds.y, 577 bounds.width, bounds.height, true); 578 } 579 580 private int findCenteredX(int x, int iconWidth) { 581 return tree.getComponentOrientation().isLeftToRight() 582 ? x - (int)Math.ceil(iconWidth / 2.0) 583 : x - (int)Math.floor(iconWidth / 2.0); 584 } 585 586 /** 587 * {@inheritDoc} 588 */ 589 @Override 590 protected void paintExpandControl(Graphics g, Rectangle clipBounds, 591 Insets insets, Rectangle bounds, TreePath path, int row, 592 boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) { 593 //modify the paintContext's state to match the state for the row 594 //this is a hack in that it requires knowledge of the subsequent 595 //method calls. The point is, the context used in drawCentered 596 //should reflect the state of the row, not of the tree. 597 boolean isSelected = tree.getSelectionModel().isPathSelected(path); 598 int state = paintContext.getComponentState(); 599 if (isSelected) { 600 paintContext.setComponentState(state | SynthConstants.SELECTED); 601 } 602 super.paintExpandControl(g, clipBounds, insets, bounds, path, row, 603 isExpanded, hasBeenExpanded, isLeaf); 604 paintContext.setComponentState(state); 605 } 606 607 /** 608 * {@inheritDoc} 609 */ 610 @Override 611 protected void drawCentered(Component c, Graphics graphics, Icon icon, 612 int x, int y) { 613 int w = SynthIcon.getIconWidth(icon, paintContext); 614 int h = SynthIcon.getIconHeight(icon, paintContext); 615 616 SynthIcon.paintIcon(icon, paintContext, graphics, 617 findCenteredX(x, w), 618 y - h/2, w, h); 619 } 620 621 /** 622 * {@inheritDoc} 623 */ 624 @Override 625 public void propertyChange(PropertyChangeEvent event) { 626 if (SynthLookAndFeel.shouldUpdateStyle(event)) { 627 updateStyle((JTree)event.getSource()); 628 } 629 630 if ("dropLocation" == event.getPropertyName()) { 631 JTree.DropLocation oldValue = (JTree.DropLocation)event.getOldValue(); 632 repaintDropLocation(oldValue); 633 repaintDropLocation(tree.getDropLocation()); 634 } 635 } 636 637 /** 638 * {@inheritDoc} 639 */ 640 @Override 641 protected void paintDropLine(Graphics g) { 642 JTree.DropLocation loc = tree.getDropLocation(); 643 if (!isDropLine(loc)) { 644 return; 645 } 646 647 Color c = (Color)style.get(paintContext, "Tree.dropLineColor"); 648 if (c != null) { 649 g.setColor(c); 650 Rectangle rect = getDropLineRect(loc); 651 g.fillRect(rect.x, rect.y, rect.width, rect.height); 652 } 653 } 654 655 private void repaintDropLocation(JTree.DropLocation loc) { 656 if (loc == null) { 657 return; 658 } 659 660 Rectangle r; 661 662 if (isDropLine(loc)) { 663 r = getDropLineRect(loc); 664 } else { 665 r = tree.getPathBounds(loc.getPath()); 666 if (r != null) { 667 r.x = 0; 668 r.width = tree.getWidth(); 669 } 670 } 671 672 if (r != null) { 673 tree.repaint(r); 674 } 675 } 676 677 /** 678 * {@inheritDoc} 679 */ 680 @Override 681 protected int getRowX(int row, int depth) { 682 return super.getRowX(row, depth) + padding; 683 } 684 685 @SuppressWarnings("serial") // Superclass is not serializable across versions 686 private class SynthTreeCellRenderer extends DefaultTreeCellRenderer 687 implements UIResource { 688 SynthTreeCellRenderer() { 689 } 690 691 @Override 692 public String getName() { 693 return "Tree.cellRenderer"; 694 } 695 696 @Override 697 public Component getTreeCellRendererComponent(JTree tree, Object value, 698 boolean sel, 699 boolean expanded, 700 boolean leaf, int row, 701 boolean hasFocus) { 702 if (!useTreeColors && (sel || hasFocus)) { 703 SynthLookAndFeel.setSelectedUI((SynthLabelUI)SynthLookAndFeel. 704 getUIOfType(getUI(), SynthLabelUI.class), 705 sel, hasFocus, tree.isEnabled(), false); 706 } 707 else { 708 SynthLookAndFeel.resetSelectedUI(); 709 } 710 return super.getTreeCellRendererComponent(tree, value, sel, 711 expanded, leaf, row, hasFocus); 712 } 713 714 @Override 715 public void paint(Graphics g) { 716 paintComponent(g); 717 if (hasFocus) { 718 SynthContext context = getContext(tree, Region.TREE_CELL); 719 720 if (context.getStyle() == null) { 721 assert false: "SynthTreeCellRenderer is being used " + 722 "outside of UI that created it"; 723 return; 724 } 725 int imageOffset = 0; 726 Icon currentI = getIcon(); 727 728 if(currentI != null && getText() != null) { 729 imageOffset = currentI.getIconWidth() + 730 Math.max(0, getIconTextGap() - 1); 731 } 732 if (selected) { 733 context.setComponentState(ENABLED | SELECTED); 734 } 735 else { 736 context.setComponentState(ENABLED); 737 } 738 if(getComponentOrientation().isLeftToRight()) { 739 context.getPainter().paintTreeCellFocus(context, g, 740 imageOffset, 0, getWidth() - imageOffset, 741 getHeight()); 742 } 743 else { 744 context.getPainter().paintTreeCellFocus(context, g, 745 0, 0, getWidth() - imageOffset, getHeight()); 746 } 747 context.dispose(); 748 } 749 SynthLookAndFeel.resetSelectedUI(); 750 } 751 } 752 753 754 private static class SynthTreeCellEditor extends DefaultTreeCellEditor { 755 public SynthTreeCellEditor(JTree tree, 756 DefaultTreeCellRenderer renderer) { 757 super(tree, renderer); 758 setBorderSelectionColor(null); 759 } 760 761 @Override 762 protected TreeCellEditor createTreeCellEditor() { 763 @SuppressWarnings("serial") // anonymous class 764 JTextField tf = new JTextField() { 765 @Override 766 public String getName() { 767 return "Tree.cellEditor"; 768 } 769 }; 770 DefaultCellEditor editor = new DefaultCellEditor(tf); 771 772 // One click to edit. 773 editor.setClickCountToStart(1); 774 return editor; 775 } 776 } 777 778 // 779 // BasicTreeUI directly uses expandIcon outside of the Synth methods. 780 // To get the correct context we return an instance of this that fetches 781 // the SynthContext as needed. 782 // 783 private class ExpandedIconWrapper extends SynthIcon { 784 public void paintIcon(SynthContext context, Graphics g, int x, 785 int y, int w, int h) { 786 if (context == null) { 787 context = getContext(tree); 788 SynthIcon.paintIcon(expandedIcon, context, g, x, y, w, h); 789 context.dispose(); 790 } 791 else { 792 SynthIcon.paintIcon(expandedIcon, context, g, x, y, w, h); 793 } 794 } 795 796 public int getIconWidth(SynthContext context) { 797 int width; 798 if (context == null) { 799 context = getContext(tree); 800 width = SynthIcon.getIconWidth(expandedIcon, context); 801 context.dispose(); 802 } 803 else { 804 width = SynthIcon.getIconWidth(expandedIcon, context); 805 } 806 return width; 807 } 808 809 public int getIconHeight(SynthContext context) { 810 int height; 811 if (context == null) { 812 context = getContext(tree); 813 height = SynthIcon.getIconHeight(expandedIcon, context); 814 context.dispose(); 815 } 816 else { 817 height = SynthIcon.getIconHeight(expandedIcon, context); 818 } 819 return height; 820 } 821 } 822 }