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