001/* 002 * $Id: TreeTableDemo.java 1295 2012-07-20 10:13:54Z kleopatra $ 003 * 004 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022package org.jdesktop.swingx.demos.treetable; 023 024 025 026import java.awt.BorderLayout; 027 028import java.awt.Color; 029 030import java.awt.Component; 031 032import java.awt.Dimension; 033 034import java.awt.Point; 035 036import java.awt.Window; 037 038import java.awt.event.MouseEvent; 039 040import java.util.ArrayList; 041 042import java.util.List; 043 044import java.util.logging.Logger; 045 046 047 048import javax.swing.JButton; 049 050import javax.swing.JComponent; 051 052import javax.swing.JFrame; 053 054import javax.swing.JLabel; 055 056import javax.swing.JPanel; 057 058import javax.swing.JScrollPane; 059 060import javax.swing.SwingUtilities; 061 062import javax.swing.table.TableModel; 063 064import javax.swing.tree.TreePath; 065 066 067 068import org.jdesktop.application.Action; 069 070import org.jdesktop.swingx.JXPanel; 071 072import org.jdesktop.swingx.JXTreeTable; 073 074import org.jdesktop.swingx.decorator.AbstractHighlighter; 075 076import org.jdesktop.swingx.decorator.ColorHighlighter; 077 078import org.jdesktop.swingx.decorator.ComponentAdapter; 079 080import org.jdesktop.swingx.decorator.HighlightPredicate; 081 082import org.jdesktop.swingx.demos.tree.TreeDemoIconValues.LazyLoadingIconValue; 083 084import org.jdesktop.swingx.demos.tree.XTreeDemo; 085 086import org.jdesktop.swingx.event.AbstractInputEventDispatcher; 087 088import org.jdesktop.swingx.renderer.DefaultTableRenderer; 089 090import org.jdesktop.swingx.renderer.DefaultTreeRenderer; 091 092import org.jdesktop.swingx.renderer.IconValue; 093 094import org.jdesktop.swingx.renderer.StringValue; 095 096import org.jdesktop.swingx.renderer.StringValues; 097 098import org.jdesktop.swingx.table.ColumnFactory; 099 100import org.jdesktop.swingx.table.TableColumnExt; 101 102import org.jdesktop.swingx.treetable.TreeTableModel; 103 104import org.jdesktop.swingx.util.PaintUtils; 105 106import org.jdesktop.swingxset.JXDemoFrame; 107 108import org.jdesktop.swingxset.util.ComponentModels; 109 110import org.jdesktop.swingxset.util.DemoUtils; 111 112 113 114import com.sun.swingset3.DemoProperties; 115 116 117 118/** 119 * A demo for the {@code JXTreeTable}. 120 * 121 * @author Karl George Schaefer 122 */ 123 124 125 126@DemoProperties(value = "JXTreeTable Demo", category = "Data", description = "Demonstrates JXTreeTable, a tree-based, grid component.", sourceFiles = 127 128{ "org/jdesktop/swingx/demos/treetable/TreeTableDemo.java" , "org/jdesktop/swingx/demos/tree/TreeDemoIconValues.java" , "org/jdesktop/swingxset/JXDemoFrame.java" , "org/jdesktop/swingx/demos/treetable/resources/TreeTableDemo.properties" } ) 129 130@SuppressWarnings("serial") 131 132public class TreeTableDemo extends JPanel 133 134{ 135 136 137 138 @SuppressWarnings("unused") 139 140 private static final Logger LOG = Logger.getLogger(TreeTableDemo.class .getName()); 141 142 143 144 private JXTreeTable treeTable; 145 146 private boolean initialized; 147 148 private JButton refreshButton; 149 150 private JButton expandButton; 151 152 private JButton collapseButton; 153 154 private AbstractInputEventDispatcher inputEventDispatcher; 155 156 private AbstractHighlighter mouseOverHighlighter; 157 158 159 160 public TreeTableDemo() 161 162 { 163 164 super(new BorderLayout()); 165 166 initComponents(); 167 168 configureComponents(); 169 170 DemoUtils.injectResources(this); 171 172 bind(); 173 174 } 175 176 177 178 // ---------------- public api for Binding/Action control 179 180 181 182 183 184 @Action 185 186 public void refreshModel() 187 188 { 189 190 treeTable.setTreeTableModel(createTreeModel()); 191 192 expandAll(); 193 194 treeTable.packColumn(treeTable.getHierarchicalColumn(), -1); 195 196 } 197 198 199 200 201 // <snip> JXTreeTable convenience api 202 203 // expand/collapse all nodes 204 205 @Action 206 207 public void expandAll() 208 209 { 210 211 treeTable.expandAll(); 212 213 } 214 215 216 217 @Action 218 219 public void collapseAll() 220 221 { 222 223 treeTable.collapseAll(); 224 225 } 226 227 // </snip> 228 229 230 231 // ------------------- config/bind 232 233 234 235 236 237 private void bind() 238 239 { 240 241 // <snip>JXTreeTable column customization 242 243 // configure and install a custom columnFactory, arguably data related ;-) 244 245 ColumnFactory factory = new ColumnFactory() 246 247 { 248 249 String[] columnNameKeys = 250 251 { "componentType", "componentName", "componentLocation", "componentSize" }; 252 253 254 255 @Override 256 257 public void configureTableColumn(TableModel model, TableColumnExt columnExt) 258 259 { 260 261 super.configureTableColumn(model, columnExt); 262 263 if (columnExt.getModelIndex() < columnNameKeys.length) 264 265 { 266 267 columnExt.setTitle(DemoUtils.getResourceString(TreeTableDemo.class, columnNameKeys[columnExt.getModelIndex()])); 268 269 } 270 271 } 272 273 274 275 }; 276 277 treeTable.setColumnFactory(factory); 278 279 // </snip> 280 281 282 283 } 284 285 286 287 private void configureComponents() 288 289 { 290 291 // <snip> JXTreeTable rendering 292 293 // StringValue provides node text, used in hierarchical column 294 295 StringValue sv = new StringValue() 296 297 { 298 299 300 301 @Override 302 303 public String getString(Object value) 304 305 { 306 307 if (value instanceof Component) 308 309 { 310 311 Component component = (Component) value; 312 313 String simpleName = component.getClass().getSimpleName(); 314 315 if (simpleName.length() == 0) 316 317 { 318 319 // anonymous class 320 321 simpleName = component.getClass().getSuperclass().getSimpleName(); 322 323 } 324 325 return simpleName; 326 327 } 328 329 return StringValues.TO_STRING.getString(value); 330 331 } 332 333 }; 334 335 // </snip> 336 337 338 339 // StringValue for lazy icon loading 340 341 StringValue keyValue = new StringValue() 342 343 { 344 345 346 347 @Override 348 349 public String getString(Object value) 350 351 { 352 353 if (value == null) 354 355 { 356 357 return ""; 358 359 } 360 361 String simpleClassName = value.getClass().getSimpleName(); 362 363 if (simpleClassName.length() == 0) 364 365 { 366 367 // anonymous class 368 369 simpleClassName = value.getClass().getSuperclass().getSimpleName(); 370 371 } 372 373 return simpleClassName + ".png"; 374 375 } 376 377 }; 378 379 // <snip> JXTreeTable rendering 380 381 // IconValue provides node icon (same as in XTreeDemo) 382 383 IconValue iv = new LazyLoadingIconValue(XTreeDemo.class, keyValue, "fallback.png"); 384 385 // create and set a tree renderer using the custom Icon-/StringValue 386 387 treeTable.setTreeCellRenderer(new DefaultTreeRenderer(iv, sv)); 388 389 // string representation for use of Dimension/Point class 390 391 StringValue locSize = new StringValue() 392 393 { 394 395 396 397 @Override 398 399 public String getString(Object value) 400 401 { 402 403 int x; 404 405 int y; 406 407 if (value instanceof Dimension) 408 409 { 410 411 x = ((Dimension) value).width; 412 413 y = ((Dimension) value).height; 414 415 } 416 417 else if (value instanceof Point) 418 419 { 420 421 x = ((Point) value).x; 422 423 y = ((Point) value).y; 424 425 } 426 427 else 428 429 { 430 431 return StringValues.TO_STRING.getString(value); 432 433 } 434 435 return "(" + x + ", " + y + ")"; 436 437 } 438 439 }; 440 441 treeTable.setDefaultRenderer(Point.class, new DefaultTableRenderer(locSize, JLabel.CENTER)); 442 443 treeTable.setDefaultRenderer(Dimension.class, treeTable.getDefaultRenderer(Point.class)); 444 445 // </snip> 446 447 448 449 mouseOverHighlighter = new ColorHighlighter(HighlightPredicate.NEVER, PaintUtils.setSaturation(Color.MAGENTA, 0.3f), null); 450 451 treeTable.addHighlighter(mouseOverHighlighter); 452 453 454 455 treeTable.setColumnControlVisible(true); 456 457 458 459 refreshButton.setAction(DemoUtils.getAction(this, "refreshModel")); 460 461 expandButton.setAction(DemoUtils.getAction(this, "expandAll")); 462 463 collapseButton.setAction(DemoUtils.getAction(this, "collapseAll")); 464 465 466 467 // Demo specific config 468 469 DemoUtils.setSnippet("JXTreeTable convenience api", expandButton, collapseButton); 470 471 DemoUtils.setSnippet("JXTreeTable rendering", treeTable); 472 473 } 474 475 476 477 // <snip> Input-/FocusEvent notification 478 479 // update Highlighter's predicate to highlight the tree row 480 481 // which contains the component under the current mouse position 482 483 protected void updateHighlighter(Component component) 484 485 { 486 487 mouseOverHighlighter.setHighlightPredicate(HighlightPredicate.NEVER); 488 489 if (component != null) 490 491 { 492 493 494 495 List<Component> pathList = new ArrayList<Component>(); 496 497 while (component != null) 498 499 { 500 501 pathList.add(0, component); 502 503 component = component.getParent(); 504 505 } 506 507 final TreePath treePath = new TreePath(pathList.toArray()); 508 509 treeTable.scrollPathToVisible(treePath); 510 511 HighlightPredicate predicate = new HighlightPredicate() 512 513 { 514 515 516 517 @Override 518 519 public boolean isHighlighted(Component renderer, ComponentAdapter adapter) 520 521 { 522 523 return adapter.row == treeTable.getRowForPath(treePath); 524 525 } 526 527 }; 528 529 mouseOverHighlighter.setHighlightPredicate(predicate); 530 531 // </snip> 532 533 534 535 } 536 537 } 538 539 540 541 /** 542 * Overridden to create and install the component tree model. 543 */ 544 545 @Override 546 547 public void addNotify() 548 549 { 550 551 super.addNotify(); 552 553 if (!initialized) 554 555 { 556 557 initialized = true; 558 559 refreshModel(); 560 561 } 562 563 installInputEventListener(); 564 565 } 566 567 568 569 @Override 570 571 public void removeNotify() 572 573 { 574 575 uninstallInputEventListener(); 576 577 super.removeNotify(); 578 579 } 580 581 // <snip> Input-/FocusEvent notification 582 583 // install custom dispatcher with demo frame 584 585 private void installInputEventListener() 586 587 { 588 589 if (!(SwingUtilities.getWindowAncestor(this) instanceof JXDemoFrame)) 590 591 { 592 593 return; 594 595 } 596 597 JXDemoFrame window = (JXDemoFrame) SwingUtilities.getWindowAncestor(this); 598 599 if (inputEventDispatcher == null) 600 601 { 602 603 inputEventDispatcher = new AbstractInputEventDispatcher() 604 605 { 606 607 // updates Highlighter for mouseEntered/mouseExited 608 609 // of all components in the frame's container hierarchy 610 611 @Override 612 613 protected void processMouseEvent(MouseEvent e) 614 615 { 616 617 if (MouseEvent.MOUSE_ENTERED == e.getID()) 618 619 { 620 621 updateHighlighter(e.getComponent()); 622 623 } 624 625 else if (MouseEvent.MOUSE_EXITED == e.getID()) 626 627 { 628 629 updateHighlighter(null); 630 631 } 632 633 } 634 635 636 637 }; 638 639 } 640 641 window.setInputEventDispatcher(inputEventDispatcher); 642 643 // </snip> 644 645 646 647 } 648 649 650 651 private void uninstallInputEventListener() 652 653 { 654 655 if (!(SwingUtilities.getWindowAncestor(this) instanceof JXDemoFrame)) 656 657 { 658 659 return; 660 661 } 662 663 JXDemoFrame window = (JXDemoFrame) SwingUtilities.getWindowAncestor(this); 664 665 window.setInputEventDispatcher(null); 666 667 updateHighlighter(null); 668 669 670 671 } 672 673 674 675 private TreeTableModel createTreeModel() 676 677 { 678 679 Window window = SwingUtilities.getWindowAncestor(this); 680 681 return ComponentModels.getTreeTableModel(window != null ? window : this); 682 683 } 684 685 686 687 // ----------------- init 688 689 690 691 private void initComponents() 692 693 { 694 695 treeTable = new JXTreeTable(); 696 697 treeTable.setName("componentTreeTable"); 698 699 add(new JScrollPane(treeTable)); 700 701 702 703 JComponent control = new JXPanel(); 704 705 refreshButton = new JButton(); 706 707 refreshButton.setName("refreshButton"); 708 709 710 711 expandButton = new JButton(); 712 713 expandButton.setName("expandTreeTableButton"); 714 715 716 717 collapseButton = new JButton(); 718 719 collapseButton.setName("collapseTreeTableButton"); 720 721 722 723 // control.add(refreshButton); 724 725 control.add(expandButton); 726 727 control.add(collapseButton); 728 729 add(control, BorderLayout.SOUTH); 730 731 732 733 } 734 735 736 737 /** 738 * main method allows us to run as a standalone demo. 739 */ 740 741 public static void main(String[] args) 742 743 { 744 745 SwingUtilities.invokeLater(new Runnable() 746 747 { 748 749 public void run() 750 751 { 752 753 JFrame frame = new JFrame(TreeTableDemo.class.getAnnotation(DemoProperties.class).value()); 754 755 756 757 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 758 759 frame.getContentPane().add(new TreeTableDemo()); 760 761 frame.setPreferredSize(new Dimension(800, 600)); 762 763 frame.pack(); 764 765 frame.setLocationRelativeTo(null); 766 767 frame.setVisible(true); 768 769 } 770 771 } ); 772 773 } 774 775 776 777} 778 779