46 import javax.swing.tree.TreeCellEditor; |
46 import javax.swing.tree.TreeCellEditor; |
47 import javax.swing.tree.TreeCellRenderer; |
47 import javax.swing.tree.TreeCellRenderer; |
48 import javax.swing.tree.TreeModel; |
48 import javax.swing.tree.TreeModel; |
49 import javax.swing.tree.TreePath; |
49 import javax.swing.tree.TreePath; |
50 import sun.swing.plaf.synth.SynthIcon; |
50 import sun.swing.plaf.synth.SynthIcon; |
51 import sun.swing.plaf.synth.SynthUI; |
|
52 |
51 |
53 /** |
52 /** |
54 * Skinnable TreeUI. |
53 * Provides the Synth L&F UI delegate for |
|
54 * {@link javax.swing.JTree}. |
55 * |
55 * |
56 * @author Scott Violet |
56 * @author Scott Violet |
|
57 * @since 1.7 |
57 */ |
58 */ |
58 class SynthTreeUI extends BasicTreeUI implements PropertyChangeListener, |
59 public class SynthTreeUI extends BasicTreeUI |
59 SynthUI { |
60 implements PropertyChangeListener, SynthUI { |
60 private SynthStyle style; |
61 private SynthStyle style; |
61 private SynthStyle cellStyle; |
62 private SynthStyle cellStyle; |
62 |
63 |
63 private SynthContext paintContext; |
64 private SynthContext paintContext; |
64 |
65 |
65 private boolean drawHorizontalLines; |
66 private boolean drawHorizontalLines; |
66 private boolean drawVerticalLines; |
67 private boolean drawVerticalLines; |
67 |
68 |
68 private Object linesStyle; |
69 private Object linesStyle; |
69 |
70 |
70 private int leadRow; |
|
71 |
|
72 private int padding; |
71 private int padding; |
73 |
72 |
74 private boolean useTreeColors; |
73 private boolean useTreeColors; |
75 |
74 |
76 private Icon expandedIconWrapper; |
75 private Icon expandedIconWrapper = new ExpandedIconWrapper(); |
77 |
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 */ |
78 public static ComponentUI createUI(JComponent x) { |
83 public static ComponentUI createUI(JComponent x) { |
79 return new SynthTreeUI(); |
84 return new SynthTreeUI(); |
80 } |
85 } |
81 |
86 |
82 SynthTreeUI() { |
87 /** |
83 expandedIconWrapper = new ExpandedIconWrapper(); |
88 * @inheritDoc |
84 } |
89 */ |
85 |
|
86 @Override |
90 @Override |
87 public Icon getExpandedIcon() { |
91 public Icon getExpandedIcon() { |
88 return expandedIconWrapper; |
92 return expandedIconWrapper; |
89 } |
93 } |
90 |
94 |
|
95 /** |
|
96 * @inheritDoc |
|
97 */ |
91 @Override |
98 @Override |
92 protected void installDefaults() { |
99 protected void installDefaults() { |
93 updateStyle(tree); |
100 updateStyle(tree); |
94 } |
101 } |
95 |
102 |
146 context = getContext(tree, Region.TREE_CELL, ENABLED); |
153 context = getContext(tree, Region.TREE_CELL, ENABLED); |
147 cellStyle = SynthLookAndFeel.updateStyle(context, this); |
154 cellStyle = SynthLookAndFeel.updateStyle(context, this); |
148 context.dispose(); |
155 context.dispose(); |
149 } |
156 } |
150 |
157 |
|
158 /** |
|
159 * @inheritDoc |
|
160 */ |
151 @Override |
161 @Override |
152 protected void installListeners() { |
162 protected void installListeners() { |
153 super.installListeners(); |
163 super.installListeners(); |
154 tree.addPropertyChangeListener(this); |
164 tree.addPropertyChangeListener(this); |
155 } |
165 } |
156 |
166 |
|
167 /** |
|
168 * @inheritDoc |
|
169 */ |
157 @Override |
170 @Override |
158 public SynthContext getContext(JComponent c) { |
171 public SynthContext getContext(JComponent c) { |
159 return getContext(c, getComponentState(c)); |
172 return getContext(c, SynthLookAndFeel.getComponentState(c)); |
160 } |
173 } |
161 |
174 |
162 private SynthContext getContext(JComponent c, int state) { |
175 private SynthContext getContext(JComponent c, int state) { |
163 return SynthContext.getContext(SynthContext.class, c, |
176 return SynthContext.getContext(SynthContext.class, c, |
164 SynthLookAndFeel.getRegion(c), style, state); |
177 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 } |
178 } |
174 |
179 |
175 private SynthContext getContext(JComponent c, Region region) { |
180 private SynthContext getContext(JComponent c, Region region) { |
176 return getContext(c, region, getComponentState(c, region)); |
181 return getContext(c, region, getComponentState(c, region)); |
177 } |
182 } |
224 if (tree.getTransferHandler() instanceof UIResource) { |
238 if (tree.getTransferHandler() instanceof UIResource) { |
225 tree.setTransferHandler(null); |
239 tree.setTransferHandler(null); |
226 } |
240 } |
227 } |
241 } |
228 |
242 |
|
243 /** |
|
244 * @inheritDoc |
|
245 */ |
229 @Override |
246 @Override |
230 protected void uninstallListeners() { |
247 protected void uninstallListeners() { |
231 super.uninstallListeners(); |
248 super.uninstallListeners(); |
232 tree.removePropertyChangeListener(this); |
249 tree.removePropertyChangeListener(this); |
233 } |
250 } |
234 |
251 |
|
252 /** |
|
253 * @inheritDoc |
|
254 */ |
235 @Override |
255 @Override |
236 public void update(Graphics g, JComponent c) { |
256 public void update(Graphics g, JComponent c) { |
237 SynthContext context = getContext(c); |
257 SynthContext context = getContext(c); |
238 |
258 |
239 SynthLookAndFeel.update(context, g); |
259 SynthLookAndFeel.update(context, g); |
241 g, 0, 0, c.getWidth(), c.getHeight()); |
261 g, 0, 0, c.getWidth(), c.getHeight()); |
242 paint(context, g); |
262 paint(context, g); |
243 context.dispose(); |
263 context.dispose(); |
244 } |
264 } |
245 |
265 |
|
266 /** |
|
267 * @inheritDoc |
|
268 */ |
|
269 @Override |
246 public void paintBorder(SynthContext context, Graphics g, int x, |
270 public void paintBorder(SynthContext context, Graphics g, int x, |
247 int y, int w, int h) { |
271 int y, int w, int h) { |
248 context.getPainter().paintTreeBorder(context, g, x, y, w, h); |
272 context.getPainter().paintTreeBorder(context, g, x, y, w, h); |
249 } |
273 } |
250 |
274 |
|
275 /** |
|
276 * @inheritDoc |
|
277 */ |
251 @Override |
278 @Override |
252 public void paint(Graphics g, JComponent c) { |
279 public void paint(Graphics g, JComponent c) { |
253 SynthContext context = getContext(c); |
280 SynthContext context = getContext(c); |
254 |
281 |
255 paint(context, g); |
282 paint(context, g); |
256 context.dispose(); |
283 context.dispose(); |
257 } |
284 } |
258 |
285 |
259 private void updateLeadRow() { |
286 /** |
260 leadRow = getRowForPath(tree, tree.getLeadSelectionPath()); |
287 * Paints the specified component. |
261 } |
288 * |
262 |
289 * @param context context for the component being painted |
|
290 * @param g {@code Graphics} object used for painting |
|
291 */ |
263 protected void paint(SynthContext context, Graphics g) { |
292 protected void paint(SynthContext context, Graphics g) { |
264 paintContext = context; |
293 paintContext = context; |
265 |
294 |
266 updateLeadRow(); |
295 updateLeadSelectionRow(); |
267 |
296 |
268 Rectangle paintBounds = g.getClipBounds(); |
297 Rectangle paintBounds = g.getClipBounds(); |
269 Insets insets = tree.getInsets(); |
298 Insets insets = tree.getInsets(); |
270 TreePath initialPath = getClosestPathForLocation(tree, 0, |
299 TreePath initialPath = getClosestPathForLocation(tree, 0, |
271 paintBounds.y); |
300 paintBounds.y); |
390 |
418 |
391 // Empty out the renderer pane, allowing renderers to be gc'ed. |
419 // Empty out the renderer pane, allowing renderers to be gc'ed. |
392 rendererPane.removeAll(); |
420 rendererPane.removeAll(); |
393 } |
421 } |
394 |
422 |
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) { |
423 private void configureRenderer(SynthContext context) { |
473 TreeCellRenderer renderer = tree.getCellRenderer(); |
424 TreeCellRenderer renderer = tree.getCellRenderer(); |
474 |
425 |
475 if (renderer instanceof DefaultTreeCellRenderer) { |
426 if (renderer instanceof DefaultTreeCellRenderer) { |
476 DefaultTreeCellRenderer r = (DefaultTreeCellRenderer)renderer; |
427 DefaultTreeCellRenderer r = (DefaultTreeCellRenderer)renderer; |
514 path, row, isExpanded, |
468 path, row, isExpanded, |
515 hasBeenExpanded, isLeaf); |
469 hasBeenExpanded, isLeaf); |
516 } |
470 } |
517 } |
471 } |
518 |
472 |
|
473 /** |
|
474 * @inheritDoc |
|
475 */ |
519 @Override |
476 @Override |
520 protected void paintHorizontalLine(Graphics g, JComponent c, int y, |
477 protected void paintHorizontalLine(Graphics g, JComponent c, int y, |
521 int left, int right) { |
478 int left, int right) { |
522 paintContext.getStyle().getGraphicsUtils(paintContext).drawLine( |
479 paintContext.getStyle().getGraphicsUtils(paintContext).drawLine( |
523 paintContext, "Tree.horizontalLine", g, left, y, right, y, linesStyle); |
480 paintContext, "Tree.horizontalLine", g, left, y, right, y, linesStyle); |
524 } |
481 } |
525 |
482 |
|
483 /** |
|
484 * @inheritDoc |
|
485 */ |
526 @Override |
486 @Override |
527 protected void paintVerticalPartOfLeg(Graphics g, |
487 protected void paintVerticalPartOfLeg(Graphics g, |
528 Rectangle clipBounds, Insets insets, |
488 Rectangle clipBounds, Insets insets, |
529 TreePath path) { |
489 TreePath path) { |
530 if (drawVerticalLines) { |
490 if (drawVerticalLines) { |
531 super.paintVerticalPartOfLeg(g, clipBounds, insets, path); |
491 super.paintVerticalPartOfLeg(g, clipBounds, insets, path); |
532 } |
492 } |
533 } |
493 } |
534 |
494 |
|
495 /** |
|
496 * @inheritDoc |
|
497 */ |
535 @Override |
498 @Override |
536 protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, |
499 protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, |
537 int bottom) { |
500 int bottom) { |
538 paintContext.getStyle().getGraphicsUtils(paintContext).drawLine( |
501 paintContext.getStyle().getGraphicsUtils(paintContext).drawLine( |
539 paintContext, "Tree.verticalLine", g, x, top, x, bottom, linesStyle); |
502 paintContext, "Tree.verticalLine", g, x, top, x, bottom, linesStyle); |
540 } |
503 } |
541 |
504 |
542 protected void paintRow(TreeCellRenderer renderer, |
505 private void paintRow(TreeCellRenderer renderer, |
543 DefaultTreeCellRenderer dtcr, SynthContext treeContext, |
506 DefaultTreeCellRenderer dtcr, SynthContext treeContext, |
544 SynthContext cellContext, Graphics g, Rectangle clipBounds, |
507 SynthContext cellContext, Graphics g, Rectangle clipBounds, |
545 Insets insets, Rectangle bounds, Rectangle rowBounds, |
508 Insets insets, Rectangle bounds, Rectangle rowBounds, |
546 TreePath path, int row, boolean isExpanded, |
509 TreePath path, int row, boolean isExpanded, |
547 boolean hasBeenExpanded, boolean isLeaf) { |
510 boolean hasBeenExpanded, boolean isLeaf) { |
623 super.paintExpandControl(g, clipBounds, insets, bounds, path, row, |
586 super.paintExpandControl(g, clipBounds, insets, bounds, path, row, |
624 isExpanded, hasBeenExpanded, isLeaf); |
587 isExpanded, hasBeenExpanded, isLeaf); |
625 paintContext.setComponentState(state); |
588 paintContext.setComponentState(state); |
626 } |
589 } |
627 |
590 |
|
591 /** |
|
592 * @inheritDoc |
|
593 */ |
628 @Override |
594 @Override |
629 protected void drawCentered(Component c, Graphics graphics, Icon icon, |
595 protected void drawCentered(Component c, Graphics graphics, Icon icon, |
630 int x, int y) { |
596 int x, int y) { |
631 int w = SynthIcon.getIconWidth(icon, paintContext); |
597 int w = SynthIcon.getIconWidth(icon, paintContext); |
632 int h = SynthIcon.getIconHeight(icon, paintContext); |
598 int h = SynthIcon.getIconHeight(icon, paintContext); |
634 SynthIcon.paintIcon(icon, paintContext, graphics, |
600 SynthIcon.paintIcon(icon, paintContext, graphics, |
635 findCenteredX(x, w), |
601 findCenteredX(x, w), |
636 y - h/2, w, h); |
602 y - h/2, w, h); |
637 } |
603 } |
638 |
604 |
|
605 /** |
|
606 * @inheritDoc |
|
607 */ |
|
608 @Override |
639 public void propertyChange(PropertyChangeEvent event) { |
609 public void propertyChange(PropertyChangeEvent event) { |
640 if (SynthLookAndFeel.shouldUpdateStyle(event)) { |
610 if (SynthLookAndFeel.shouldUpdateStyle(event)) { |
641 updateStyle((JTree)event.getSource()); |
611 updateStyle((JTree)event.getSource()); |
642 } |
612 } |
643 |
613 |
644 if ("dropLocation" == event.getPropertyName()) { |
614 if ("dropLocation" == event.getPropertyName()) { |
645 JTree.DropLocation oldValue = (JTree.DropLocation)event.getOldValue(); |
615 JTree.DropLocation oldValue = (JTree.DropLocation)event.getOldValue(); |
646 repaintDropLocation(oldValue); |
616 repaintDropLocation(oldValue); |
647 repaintDropLocation(tree.getDropLocation()); |
617 repaintDropLocation(tree.getDropLocation()); |
|
618 } |
|
619 } |
|
620 |
|
621 /** |
|
622 * @inheritDoc |
|
623 */ |
|
624 @Override |
|
625 protected void paintDropLine(Graphics g) { |
|
626 JTree.DropLocation loc = tree.getDropLocation(); |
|
627 if (!isDropLine(loc)) { |
|
628 return; |
|
629 } |
|
630 |
|
631 Color c = (Color)style.get(paintContext, "Tree.dropLineColor"); |
|
632 if (c != null) { |
|
633 g.setColor(c); |
|
634 Rectangle rect = getDropLineRect(loc); |
|
635 g.fillRect(rect.x, rect.y, rect.width, rect.height); |
648 } |
636 } |
649 } |
637 } |
650 |
638 |
651 private void repaintDropLocation(JTree.DropLocation loc) { |
639 private void repaintDropLocation(JTree.DropLocation loc) { |
652 if (loc == null) { |
640 if (loc == null) { |