1 /* 2 * Copyright (c) 2002, 2008, 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(SynthContext.class, c, 177 SynthLookAndFeel.getRegion(c), style, state); 178 } 179 180 private SynthContext getContext(JComponent c, Region region) { 181 return getContext(c, region, getComponentState(c, region)); 182 } 183 184 private SynthContext getContext(JComponent c, Region region, int state) { 185 return SynthContext.getContext(SynthContext.class, c, 186 region, cellStyle, state); 187 } 188 189 private int getComponentState(JComponent c, Region region) { 190 // Always treat the cell as selected, will be adjusted appropriately 191 // when painted. 192 return ENABLED | SELECTED; 193 } 194 195 /** 196 * @inheritDoc 197 */ 198 @Override 199 protected TreeCellEditor createDefaultCellEditor() { 200 TreeCellRenderer renderer = tree.getCellRenderer(); 201 DefaultTreeCellEditor editor; 202 203 if(renderer != null && (renderer instanceof DefaultTreeCellRenderer)) { 204 editor = new SynthTreeCellEditor(tree, (DefaultTreeCellRenderer) 205 renderer); 206 } 207 else { 208 editor = new SynthTreeCellEditor(tree, null); 209 } 210 return editor; 211 } 212 213 /** 214 * @inheritDoc 215 */ 216 @Override 217 protected TreeCellRenderer createDefaultCellRenderer() { 218 return new SynthTreeCellRenderer(); 219 } 220 221 /** 222 * @inheritDoc 223 */ 224 @Override 225 protected void uninstallDefaults() { 226 SynthContext context = getContext(tree, ENABLED); 227 228 style.uninstallDefaults(context); 229 context.dispose(); 230 style = null; 231 232 context = getContext(tree, Region.TREE_CELL, ENABLED); 233 cellStyle.uninstallDefaults(context); 234 context.dispose(); 235 cellStyle = null; 236 237 238 if (tree.getTransferHandler() instanceof UIResource) { 239 tree.setTransferHandler(null); 240 } 241 } 242 243 /** 244 * @inheritDoc 245 */ 246 @Override 247 protected void uninstallListeners() { 248 super.uninstallListeners(); 249 tree.removePropertyChangeListener(this); 250 } 251 252 /** 253 * Notifies this UI delegate to repaint the specified component. 254 * This method paints the component background, then calls 255 * the {@link #paint(SynthContext,Graphics)} method. 256 * 257 * <p>In general, this method does not need to be overridden by subclasses. 258 * All Look and Feel rendering code should reside in the {@code paint} method. 259 * 260 * @param g the {@code Graphics} object used for painting 261 * @param c the component being painted 262 * @see #paint(SynthContext,Graphics) 263 */ 264 @Override 265 public void update(Graphics g, JComponent c) { 266 SynthContext context = getContext(c); 267 268 SynthLookAndFeel.update(context, g); 269 context.getPainter().paintTreeBackground(context, 270 g, 0, 0, c.getWidth(), c.getHeight()); 271 paint(context, g); 272 context.dispose(); 273 } 274 275 /** 276 * @inheritDoc 277 */ 278 @Override 279 public void paintBorder(SynthContext context, Graphics g, int x, 280 int y, int w, int h) { 281 context.getPainter().paintTreeBorder(context, g, x, y, w, h); 282 } 283 284 /** 285 * Paints the specified component according to the Look and Feel. 286 * <p>This method is not used by Synth Look and Feel. 287 * Painting is handled by the {@link #paint(SynthContext,Graphics)} method. 288 * 289 * @param g the {@code Graphics} object used for painting 290 * @param c the component being painted 291 * @see #paint(SynthContext,Graphics) 292 */ 293 @Override 294 public void paint(Graphics g, JComponent c) { 295 SynthContext context = getContext(c); 296 297 paint(context, g); 298 context.dispose(); 299 } 300 301 /** 302 * Paints the specified component. 303 * 304 * @param context context for the component being painted 305 * @param g the {@code Graphics} object used for painting 306 * @see #update(Graphics,JComponent) 307 */ 308 protected void paint(SynthContext context, Graphics g) { 309 paintContext = context; 310 311 updateLeadSelectionRow(); 312 313 Rectangle paintBounds = g.getClipBounds(); 314 Insets insets = tree.getInsets(); 315 TreePath initialPath = getClosestPathForLocation(tree, 0, 316 paintBounds.y); 317 Enumeration paintingEnumerator = treeState.getVisiblePathsFrom 318 (initialPath); 319 int row = treeState.getRowForPath(initialPath); 320 int endY = paintBounds.y + paintBounds.height; 321 TreeModel treeModel = tree.getModel(); 322 SynthContext cellContext = getContext(tree, Region.TREE_CELL); 323 324 drawingCache.clear(); 325 326 setHashColor(context.getStyle().getColor(context, 327 ColorType.FOREGROUND)); 328 329 if (paintingEnumerator != null) { 330 // First pass, draw the rows 331 332 boolean done = false; 333 boolean isExpanded; 334 boolean hasBeenExpanded; 335 boolean isLeaf; 336 Rectangle rowBounds = new Rectangle(0, 0, tree.getWidth(),0); 337 Rectangle bounds; 338 TreePath path; 339 TreeCellRenderer renderer = tree.getCellRenderer(); 340 DefaultTreeCellRenderer dtcr = (renderer instanceof 341 DefaultTreeCellRenderer) ? (DefaultTreeCellRenderer) 342 renderer : null; 343 344 configureRenderer(cellContext); 345 while (!done && paintingEnumerator.hasMoreElements()) { 346 path = (TreePath)paintingEnumerator.nextElement(); 347 if (path != null) { 348 isLeaf = treeModel.isLeaf(path.getLastPathComponent()); 349 if (isLeaf) { 350 isExpanded = hasBeenExpanded = false; 351 } 352 else { 353 isExpanded = treeState.getExpandedState(path); 354 hasBeenExpanded = tree.hasBeenExpanded(path); 355 } 356 bounds = getPathBounds(tree, path); 357 rowBounds.y = bounds.y; 358 rowBounds.height = bounds.height; 359 paintRow(renderer, dtcr, context, cellContext, g, 360 paintBounds, insets, bounds, rowBounds, path, 361 row, isExpanded, hasBeenExpanded, isLeaf); 362 if ((bounds.y + bounds.height) >= endY) { 363 done = true; 364 } 365 } 366 else { 367 done = true; 368 } 369 row++; 370 } 371 372 // Draw the connecting lines and controls. 373 // Find each parent and have them draw a line to their last child 374 boolean rootVisible = tree.isRootVisible(); 375 TreePath parentPath = initialPath; 376 parentPath = parentPath.getParentPath(); 377 while (parentPath != null) { 378 paintVerticalPartOfLeg(g, paintBounds, insets, parentPath); 379 drawingCache.put(parentPath, Boolean.TRUE); 380 parentPath = parentPath.getParentPath(); 381 } 382 done = false; 383 paintingEnumerator = treeState.getVisiblePathsFrom(initialPath); 384 while (!done && paintingEnumerator.hasMoreElements()) { 385 path = (TreePath)paintingEnumerator.nextElement(); 386 if (path != null) { 387 isLeaf = treeModel.isLeaf(path.getLastPathComponent()); 388 if (isLeaf) { 389 isExpanded = hasBeenExpanded = false; 390 } 391 else { 392 isExpanded = treeState.getExpandedState(path); 393 hasBeenExpanded = tree.hasBeenExpanded(path); 394 } 395 bounds = getPathBounds(tree, path); 396 // See if the vertical line to the parent has been drawn. 397 parentPath = path.getParentPath(); 398 if (parentPath != null) { 399 if (drawingCache.get(parentPath) == null) { 400 paintVerticalPartOfLeg(g, paintBounds, insets, 401 parentPath); 402 drawingCache.put(parentPath, Boolean.TRUE); 403 } 404 paintHorizontalPartOfLeg(g, 405 paintBounds, insets, bounds, 406 path, row, isExpanded, 407 hasBeenExpanded, isLeaf); 408 } 409 else if (rootVisible && row == 0) { 410 paintHorizontalPartOfLeg(g, 411 paintBounds, insets, bounds, 412 path, row, isExpanded, 413 hasBeenExpanded, isLeaf); 414 } 415 if (shouldPaintExpandControl(path, row, isExpanded, 416 hasBeenExpanded, isLeaf)) { 417 paintExpandControl(g, paintBounds, 418 insets, bounds, path, row, 419 isExpanded, hasBeenExpanded,isLeaf); 420 } 421 if ((bounds.y + bounds.height) >= endY) { 422 done = true; 423 } 424 } 425 else { 426 done = true; 427 } 428 row++; 429 } 430 } 431 cellContext.dispose(); 432 433 paintDropLine(g); 434 435 // Empty out the renderer pane, allowing renderers to be gc'ed. 436 rendererPane.removeAll(); 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 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 JTextField tf = new JTextField() { 764 @Override 765 public String getName() { 766 return "Tree.cellEditor"; 767 } 768 }; 769 DefaultCellEditor editor = new DefaultCellEditor(tf); 770 771 // One click to edit. 772 editor.setClickCountToStart(1); 773 return editor; 774 } 775 } 776 777 // 778 // BasicTreeUI directly uses expandIcon outside of the Synth methods. 779 // To get the correct context we return an instance of this that fetches 780 // the SynthContext as needed. 781 // 782 private class ExpandedIconWrapper extends SynthIcon { 783 public void paintIcon(SynthContext context, Graphics g, int x, 784 int y, int w, int h) { 785 if (context == null) { 786 context = getContext(tree); 787 SynthIcon.paintIcon(expandedIcon, context, g, x, y, w, h); 788 context.dispose(); 789 } 790 else { 791 SynthIcon.paintIcon(expandedIcon, context, g, x, y, w, h); 792 } 793 } 794 795 public int getIconWidth(SynthContext context) { 796 int width; 797 if (context == null) { 798 context = getContext(tree); 799 width = SynthIcon.getIconWidth(expandedIcon, context); 800 context.dispose(); 801 } 802 else { 803 width = SynthIcon.getIconWidth(expandedIcon, context); 804 } 805 return width; 806 } 807 808 public int getIconHeight(SynthContext context) { 809 int height; 810 if (context == null) { 811 context = getContext(tree); 812 height = SynthIcon.getIconHeight(expandedIcon, context); 813 context.dispose(); 814 } 815 else { 816 height = SynthIcon.getIconHeight(expandedIcon, context); 817 } 818 return height; 819 } 820 } 821 }