| 1 7 8 9 package org.jdesktop.swing; 10 11 import java.util.Enumeration ; 12 import java.util.EventObject ; 13 import java.util.Enumeration ; 14 15 import java.awt.Color ; 16 import java.awt.Component ; 17 import java.awt.Dimension ; 18 import java.awt.Graphics ; 19 import java.awt.Point ; 20 import java.awt.Rectangle ; 21 import java.awt.event.ActionEvent ; 22 import java.awt.event.InputEvent ; 23 import java.awt.event.MouseEvent ; 24 import java.beans.PropertyChangeEvent ; 25 import java.beans.PropertyChangeListener ; 26 27 import javax.swing.ActionMap ; 28 import javax.swing.BorderFactory ; 29 import javax.swing.Icon ; 30 import javax.swing.JTable ; 31 import javax.swing.JTree ; 32 import javax.swing.ListSelectionModel ; 33 import javax.swing.SwingUtilities ; 34 import javax.swing.UIManager ; 35 import javax.swing.border.Border ; 36 import javax.swing.event.ListSelectionEvent ; 37 import javax.swing.event.ListSelectionListener ; 38 import javax.swing.event.TreeExpansionEvent ; 39 import javax.swing.event.TreeExpansionListener ; 40 import javax.swing.event.TreeModelEvent ; 41 import javax.swing.event.TreeModelListener ; 42 import javax.swing.plaf.UIResource ; 43 import javax.swing.plaf.basic.BasicTreeUI ; 44 import javax.swing.table.AbstractTableModel ; 45 import javax.swing.table.TableCellRenderer ; 46 import javax.swing.table.TableModel ; 47 import javax.swing.tree.DefaultTreeCellRenderer ; 48 import javax.swing.tree.DefaultTreeSelectionModel ; 49 import javax.swing.tree.TreeCellRenderer ; 50 import javax.swing.tree.TreePath ; 51 import javax.swing.tree.TreeSelectionModel ; 52 53 import org.jdesktop.swing.decorator.ComponentAdapter; 54 import org.jdesktop.swing.treetable.AbstractTreeTableModel; 55 import org.jdesktop.swing.treetable.DefaultTreeTableModel; 56 import org.jdesktop.swing.treetable.TreeTableCellEditor; 57 import org.jdesktop.swing.treetable.TreeTableModel; 58 59 96 public class JXTreeTable extends JXTable { 97 private Icon collapsedIcon = null; 99 private Icon expandedIcon = null; 100 private Icon closedIcon = null; 101 private Icon openIcon = null; 102 private Icon leafIcon = null; 103 104 108 private TreeTableCellRenderer renderer = null; 109 111 115 public JXTreeTable() { 116 this(new DefaultTreeTableModel()); 117 } 118 119 125 public JXTreeTable(TreeTableModel treeModel) { 126 this(treeModel, new JXTreeTable.TreeTableCellRenderer(treeModel)); 131 } 132 133 146 private JXTreeTable(TreeTableModel treeModel, TreeTableCellRenderer renderer) { 147 152 super(new TreeTableModelAdapter(treeModel, renderer)); 154 155 if (treeModel != renderer.getModel()) { throw new IllegalArgumentException ("Mismatched TreeTableModel"); 158 } 159 160 init(renderer); initActions(); 163 164 setDefaultEditor(AbstractTreeTableModel.hierarchicalColumnClass, 166 new TreeTableCellEditor(this, renderer)); 167 168 setShowGrid(false); 171 setIntercellSpacing(spacing); 174 setRowHeight(getRowHeight()); setRowMargin(getRowMargin()); 181 } 182 183 184 private void initActions() { 185 ActionMap map = getActionMap(); 187 map.put("expand-all", new Actions("expand-all")); 188 map.put("collapse-all", new Actions("collapse-all")); 189 } 190 191 195 private class Actions extends UIAction { 196 Actions(String name) { 197 super(name); 198 } 199 200 public void actionPerformed(ActionEvent evt) { 201 if ("expand-all".equals(getName())) { 202 expandAll(); 203 } 204 else if ("collapse-all".equals(getName())) { 205 collapseAll(); 206 } 207 } 208 } 209 210 213 protected void resetSorter() { 214 } 216 217 220 protected void setSorter(int columnIndex) { 221 } 223 224 238 public void setShowHorizontalLines(boolean show) { 239 super.setShowHorizontalLines(show); 240 } 241 242 256 public void setShowVerticalLines(boolean show) { 257 super.setShowVerticalLines(show); 258 } 259 260 269 public boolean editCellAt(int row, int column, EventObject e) { 270 expandOrCollapseNode(e); boolean canEdit = super.editCellAt(row, column, e); 272 if (canEdit && isHierarchical(column)) { 273 repaint(getCellRect(row, column, false)); 274 } 275 return canEdit; 276 } 277 278 private void expandOrCollapseNode(EventObject e) { 279 if (e instanceof MouseEvent ) { 280 MouseEvent me = (MouseEvent ) e; 281 if (me.getModifiers() == 0 || 288 me.getModifiers() == InputEvent.BUTTON1_MASK) { 289 final int count = getColumnCount(); 290 for (int i = count - 1; i >= 0; i--) { 291 if (isHierarchical(i)) { 292 293 int savedHeight = renderer.getRowHeight(); 294 renderer.setRowHeight(getRowHeight()); 295 MouseEvent pressed = new MouseEvent  296 (renderer, 297 me.getID(), 298 me.getWhen(), 299 me.getModifiers(), 300 me.getX() - getCellRect(0, i, false).x, 301 me.getY(), 302 me.getClickCount(), 303 me.isPopupTrigger()); 304 renderer.dispatchEvent(pressed); 305 MouseEvent released = new MouseEvent  307 (renderer, 308 java.awt.event.MouseEvent.MOUSE_RELEASED, 309 pressed.getWhen(), 310 pressed.getModifiers(), 311 pressed.getX(), 312 pressed.getY(), 313 pressed.getClickCount(), 314 pressed.isPopupTrigger()); 315 renderer.dispatchEvent(released); 316 renderer.setRowHeight(savedHeight); 317 break; 318 } 319 } 320 } 321 } 322 } 323 324 333 public int getEditingRow() { 334 return isHierarchical(editingColumn) ? -1 : editingRow; 335 } 336 337 341 private int realEditingRow() { 342 return editingRow; 343 } 344 345 352 public void setTreeTableModel(TreeTableModel treeModel) { 353 355 renderer.setModel(treeModel); 358 setModel(new TreeTableModelAdapter(treeModel, renderer)); 360 if (treeModel != renderer.getModel()) { throw new IllegalArgumentException ("Mismatched TreeTableModel"); 363 } 364 369 setDefaultEditor(AbstractTreeTableModel.hierarchicalColumnClass, 371 new TreeTableCellEditor(this, renderer)); 372 373 setRowHeight(getRowHeight()); setRowMargin(getRowMargin()); } 380 381 386 public TreeTableModel getTreeTableModel() { 387 return ((TreeTableModelAdapter) getModel()).getTreeTableModel(); 388 } 389 390 412 public final void setModel(TableModel tableModel) { if (tableModel instanceof TreeTableModelAdapter) { 414 if (((TreeTableModelAdapter) tableModel).getTreeTable() == null) { 415 super.setModel(tableModel); 420 ((TreeTableModelAdapter) tableModel).bind(this); } 426 else { 427 throw new IllegalArgumentException ("model already bound"); 428 } 429 } 430 else { 431 throw new IllegalArgumentException ("unsupported model type"); 432 } 433 } 434 435 444 public final void setRowHeight(int row, int rowHeight) { 445 throw new UnsupportedOperationException ("variable height rows not supported"); 446 } 447 448 454 public void setRowHeight(int rowHeight) { 455 super.setRowHeight(rowHeight); 456 adjustTreeRowHeight(); } 458 459 468 public void setColumnMargin(int columnMargin) { 469 super.setColumnMargin(columnMargin); 470 } 471 472 484 public void setRowMargin(int rowMargin) { 485 super.setRowMargin(rowMargin); 488 adjustTreeRowHeight(); } 490 491 495 private void adjustTreeRowHeight() { 496 final int treeRowHeight = rowHeight + (rowMargin << 1); 497 if (renderer != null && renderer.getRowHeight() != treeRowHeight) { 498 renderer.setRowHeight(treeRowHeight); 499 } 500 } 501 502 521 public void setSelectionMode(int mode) { 522 if (renderer != null) { 523 switch (mode) { 524 case ListSelectionModel.SINGLE_INTERVAL_SELECTION: { 525 renderer.getSelectionModel().setSelectionMode( 526 TreeSelectionModel.CONTIGUOUS_TREE_SELECTION); 527 break; 528 } 529 case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION: { 530 renderer.getSelectionModel().setSelectionMode( 531 TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); 532 break; 533 } 534 default: { 535 renderer.getSelectionModel().setSelectionMode( 536 TreeSelectionModel.SINGLE_TREE_SELECTION); 537 break; 538 } 539 } 540 } 541 super.setSelectionMode(mode); 542 } 543 544 552 public Component prepareRenderer(TableCellRenderer renderer, int row, 553 int column) { 554 if (isHierarchical(column)) { 556 if (collapsedIcon != null) { 557 setCollapsedIcon(collapsedIcon); 558 } 559 if (expandedIcon != null) { 560 setExpandedIcon(expandedIcon); 561 } 562 if (openIcon != null) { 563 setOpenIcon(openIcon); 564 } 565 if (closedIcon != null) { 566 setClosedIcon(closedIcon); 567 } 568 if (leafIcon != null) { 569 setLeafIcon(leafIcon); 570 } 571 } 572 573 Component component = super.prepareRenderer(renderer, row, column); 574 ComponentAdapter adapter = getComponentAdapter(); 576 adapter.row = row; 577 adapter.column = column; 578 579 return applyRenderer(component, adapter); 581 } 582 583 590 protected Component applyRenderer(Component component, 591 ComponentAdapter adapter) { 592 if (component == null) { 593 throw new IllegalArgumentException ("null component"); 594 } 595 if (adapter == null) { 596 throw new IllegalArgumentException ("null component data adapter"); 597 } 598 599 if (isHierarchical(adapter.column)) { 600 TreeCellRenderer tcr = renderer.getCellRenderer(); 604 605 if (tcr instanceof DefaultTreeCellRenderer ) { 606 DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer ) tcr); 607 if (adapter.isSelected()) { 608 dtcr.setTextSelectionColor(component.getForeground()); 609 dtcr.setBackgroundSelectionColor(component.getBackground()); 610 } else { 611 dtcr.setTextNonSelectionColor(component.getForeground()); 612 dtcr.setBackgroundNonSelectionColor(component.getBackground()); 613 } 614 } 615 } 616 return component; 617 } 618 619 624 public void setCellRenderer(TreeCellRenderer cellRenderer) { 625 if (renderer != null) { 626 renderer.setCellRenderer(cellRenderer); 627 } 628 } 629 630 631 636 public void setCollapsedIcon(Icon icon) { 637 try { 638 ( (BasicTreeUI ) (renderer.getUI())).setCollapsedIcon(icon); 639 collapsedIcon = icon; 641 } 642 catch (ClassCastException ex) { 643 644 System.err.println(ex); 645 } 646 } 647 648 653 public void setExpandedIcon(Icon icon) { 654 try { 655 ( (BasicTreeUI ) (renderer.getUI())).setExpandedIcon(icon); 656 expandedIcon = icon; 658 } 659 catch (ClassCastException ex) { 660 661 System.err.println(ex); 662 } 663 } 664 665 670 public void setOpenIcon(Icon icon) { 671 try { 672 ((DefaultTreeCellRenderer ) renderer.getCellRenderer()).setOpenIcon(icon); 673 openIcon = icon; 675 } 676 catch (ClassCastException ex) { 677 678 System.err.println(ex); 679 } 680 } 681 682 687 public void setClosedIcon(Icon icon) { 688 try { 689 ((DefaultTreeCellRenderer ) renderer.getCellRenderer()).setClosedIcon(icon); 690 closedIcon = icon; 692 } 693 catch (ClassCastException ex) { 694 695 System.err.println(ex); 696 } 697 } 698 699 704 public void setLeafIcon(Icon icon) { 705 try { 706 ((DefaultTreeCellRenderer ) renderer.getCellRenderer()).setLeafIcon(icon); 707 leafIcon = icon; 709 } 710 catch (ClassCastException ex) { 711 712 System.err.println(ex); 713 } 714 } 715 716 722 public void clearSelection() { 723 if (renderer != null) { 724 renderer.clearSelection(); 725 } 726 super.clearSelection(); 727 } 728 729 732 public void collapseAll() { 733 renderer.collapseAll(); 734 } 735 736 739 public void expandAll() { 740 renderer.expandAll(); 741 } 742 743 748 public void collapsePath(TreePath path) { 749 renderer.collapsePath(path); 750 } 751 752 757 public void expandPath(TreePath path) { 758 renderer.expandPath(path); 759 } 760 761 765 public void collapseRow(int row) { 766 renderer.collapseRow(row); 767 } 768 769 773 public void expandRow(int row) { 774 renderer.expandRow(row); 775 } 776 777 782 public void setRootVisible(boolean visible) { 783 renderer.setRootVisible(visible); 784 } 785 786 791 public boolean isRootVisible() { 792 return renderer.isRootVisible(); 793 } 794 795 803 public boolean isVisible(TreePath path) { 804 return renderer.isVisible(path); 805 } 806 807 815 public boolean isExpanded(TreePath path) { 816 return renderer.isExpanded(path); 817 } 818 819 827 public boolean isExpanded(int row) { 828 return renderer.isExpanded(row); 829 } 830 831 840 public boolean isCollapsed(TreePath path) { 841 return renderer.isCollapsed(path); 842 } 843 844 851 public boolean isCollapsed(int row) { 852 return renderer.isCollapsed(row); 853 } 854 855 856 871 872 public Enumeration getExpandedDescendants(TreePath parent) { 873 return renderer.getExpandedDescendants(parent); 874 &n
|