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 } 875 876 877 883 public void setExpandsSelectedPaths(boolean expand) { 884 renderer.setExpandsSelectedPaths(expand); 885 } 886 887 892 public boolean getExpandsSelectedPaths() { 893 return renderer.getExpandsSelectedPaths(); 894 } 895 896 904 public TreePath getPathForLocation(int x, int y) { 905 int row = rowAtPoint(new Point (x,y)); 906 if (row == -1) { 907 return null; 908 } 909 return renderer.getPathForRow(row); 910 } 911 912 919 public TreePath getPathForRow(int row) { 920 return renderer.getPathForRow(row); 921 } 922 923 932 public void setScrollsOnExpand(boolean scroll) { 933 renderer.setScrollsOnExpand(scroll); 934 } 935 936 941 public boolean getScrollsOnExpand() { 942 return renderer.getScrollsOnExpand(); 943 } 944 945 953 public void setShowsRootHandles(boolean visible) { 954 renderer.setShowsRootHandles(visible); 955 } 956 957 962 public boolean getShowsRootHandles() { 963 return renderer.getShowsRootHandles(); 964 } 965 966 971 public TreeSelectionModel getTreeSelectionModel() { 972 return renderer.getSelectionModel(); } 974 975 982 public void sizeColumnsToFit(int resizingColumn) { 983 984 super.sizeColumnsToFit(resizingColumn); 985 if (getEditingColumn() != -1 && isHierarchical(editingColumn)) { 987 Rectangle cellRect = getCellRect(realEditingRow(), 988 getEditingColumn(), false); 989 Component component = getEditorComponent(); 990 component.setBounds(cellRect); 991 component.validate(); 992 } 993 } 994 995 1000 public void updateUI() { 1001 super.updateUI(); 1002 if (renderer != null) { 1003 renderer.updateUI(); 1005 1007 setDefaultEditor(AbstractTreeTableModel.hierarchicalColumnClass, 1011 new TreeTableCellEditor(this, renderer)); 1012 1013 if (getBackground() == null || getBackground()instanceof UIResource ) { 1014 setBackground(renderer.getBackground()); 1015 } 1016 } 1017 } 1018 1019 1026 public boolean isHierarchical(int column) { 1027 return AbstractTreeTableModel.hierarchicalColumnClass.isAssignableFrom( 1028 getColumnClass(column)); 1029 } 1030 1031 1038 private final void init(TreeTableCellRenderer renderer) { 1039 this.renderer = renderer; 1040 ListToTreeSelectionModelWrapper selectionWrapper = 1042 new ListToTreeSelectionModelWrapper(); 1043 1044 if (renderer != null) { 1046 renderer.bind(this); renderer.setSelectionModel(selectionWrapper); 1048 } 1049 1050 setSelectionModel(selectionWrapper.getListSelectionModel()); 1051 setDefaultRenderer(AbstractTreeTableModel.hierarchicalColumnClass, 1052 renderer); 1053 1054 PropertyChangeListener l = new PropertyChangeListener () { 1056 1057 public void propertyChange(PropertyChangeEvent evt) { 1058 JXTreeTable.this.renderer.putClientProperty(evt.getPropertyName(), evt.getNewValue()); 1059 1060 } 1061 1062 }; 1063 addPropertyChangeListener("JTree.lineStyle", l); 1064 1065 } 1066 1067 1068 1074 class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel { 1075 1076 protected boolean updatingListSelectionModel; 1077 1078 public ListToTreeSelectionModelWrapper() { 1079 super(); 1080 getListSelectionModel().addListSelectionListener 1081 (createListSelectionListener()); 1082 } 1083 1084 1089 ListSelectionModel getListSelectionModel() { 1090 return listSelectionModel; 1091 } 1092 1093 1098 public void resetRowSelection() { 1099 if (!updatingListSelectionModel) { 1100 updatingListSelectionModel = true; 1101 try { 1102 super.resetRowSelection(); 1103 } 1104 finally { 1105 updatingListSelectionModel = false; 1106 } 1107 } 1108 } 1114 1115 1118 protected ListSelectionListener createListSelectionListener() { 1119 return new ListSelectionHandler(); 1120 } 1121 1122 1127 protected void updateSelectedPathsFromSelectedRows() { 1128 if (!updatingListSelectionModel) { 1129 updatingListSelectionModel = true; 1130 try { 1131 int min = listSelectionModel.getMinSelectionIndex(); 1134 int max = listSelectionModel.getMaxSelectionIndex(); 1135 1136 clearSelection(); 1137 if (min != -1 && max != -1) { 1138 for (int counter = min; counter <= max; counter++) { 1139 if (listSelectionModel.isSelectedIndex(counter)) { 1140 TreePath selPath = renderer.getPathForRow( 1141 counter); 1142 1143 if (selPath != null) { 1144 addSelectionPath(selPath); 1145 } 1146 } 1147 } 1148 } 1149 } 1150 finally { 1151 updatingListSelectionModel = false; 1152 } 1153 } 1154 } 1155 1156 1160 class ListSelectionHandler implements ListSelectionListener { 1161 public void valueChanged(ListSelectionEvent e) { 1162 updateSelectedPathsFromSelectedRows(); 1163 } 1164 } 1165 } 1166 1167 private static class TreeTableModelAdapter extends AbstractTableModel { 1168 1180 TreeTableModelAdapter(TreeTableModel model, JTree tree) { 1181 assert model != null; 1182 assert tree != null; 1183 1184 this.tree = tree; this.model = model; 1186 1187 model.addTreeModelListener(new TreeModelListener () { 1192 public void treeNodesChanged(TreeModelEvent e) { 1193 delayedFireTableDataChanged(e, 0); 1194 } 1195 1196 public void treeNodesInserted(TreeModelEvent e) { 1197 delayedFireTableDataChanged(e, 1); 1198 } 1199 1200 public void treeNodesRemoved(TreeModelEvent e) { 1201 delayedFireTableDataChanged(e, 2); 1202 } 1203 1204 public void treeStructureChanged(TreeModelEvent e) { 1205 delayedFireTableDataChanged(); 1206 } 1207 }); 1208 1209 tree.addTreeExpansionListener(new TreeExpansionListener () { 1210 public void treeExpanded(TreeExpansionEvent event) { 1213 fireTableDataChanged(); 1214 } 1215 1216 public void treeCollapsed(TreeExpansionEvent event) { 1217 fireTableDataChanged(); 1218 } 1219 }); 1220 } 1221 1222 1227 public TreeTableModel getTreeTableModel() { 1228 return model; 1229 } 1230 1231 1238 protected JXTreeTable getTreeTable() { 1239 return treeTable; 1240 } 1241 1242 1247 protected final void bind(JXTreeTable treeTable) { 1248 if (treeTable == null) { 1251 throw new IllegalArgumentException ("null treeTable"); 1252 } 1253 1254 if (this.treeTable == null) { 1255 this.treeTable = treeTable; 1256 } 1257 else { 1258 throw new IllegalArgumentException ("adapter already bound"); 1259 } 1260 } 1261 1262 1265 public Class getColumnClass(int column) { 1266 return model.getColumnClass(column); 1267 } 1268 1269 1273 public int getColumnCount() { 1274 return model.getColumnCount(); 1275 } 1276 1277 public String getColumnName(int column) { 1278 return model.getColumnName(column); 1279 } 1280 1281 public int getRowCount() { 1282 return tree.getRowCount(); 1283 } 1284 1285 public Object getValueAt(int row, int column) { 1286 return model.getValueAt(nodeForRow(row), column); 1287 } 1288 1289 public boolean isCellEditable(int row, int column) { 1290 return model.isCellEditable(nodeForRow(row), column); 1291 } 1292 1293 public void setValueAt(Object value, int row, int column) { 1294 model.setValueAt(value, nodeForRow(row), column); 1295 } 1296 1297 protected Object nodeForRow(int row) { 1298 return tree.getPathForRow(row).getLastPathComponent(); 1299 } 1300 1301 1305 private void delayedFireTableDataChanged() { 1306 SwingUtilities.invokeLater(new Runnable () { 1307 public void run() { 1308 fireTableDataChanged(); 1309 } 1310 }); 1311 } 1312 1313 1317 private void delayedFireTableDataChanged(final TreeModelEvent tme, final int typeChange) { 1318 SwingUtilities.invokeLater(new Runnable () { 1319 public void run() { 1320 int indices[] = tme.getChildIndices(); 1321 TreePath path = tme.getTreePath(); 1322 if (indices != null) { 1323 if (tree.isExpanded(path)) { int startingRow = tree.getRowForPath(path)+1; 1326 int min = Integer.MAX_VALUE; 1327 int max = Integer.MIN_VALUE; 1328 for (int i=0;i<indices.length;i++) { 1329 if (indices[i] < min) { 1330 min = indices[i]; 1331 } 1332 if (indices[i] > max) { 1333 max = indices[i]; 1334 } 1335 } 1336 switch (typeChange) { 1337 case 0 : 1338 fireTableRowsUpdated(startingRow + min, startingRow+max); 1339 break; 1340 case 1: 1341 fireTableRowsInserted(startingRow + min, startingRow+max); 1342 break; 1343 case 2: 1344 fireTableRowsDeleted(startingRow + min, startingRow+max); 1345 break; 1346 } 1347 } 1348 } 1349 else { fireTableDataChanged(); 1351 } 1352 } 1353 }); 1354 } 1355 1356 1357 1358 private TreeTableModel model; private final JTree tree; private JXTreeTable treeTable = null; } 1362 1363 static class TreeTableCellRenderer extends JXTree implements 1364 TableCellRenderer { 1365 public TreeTableCellRenderer(TreeTableModel model) { 1367 super(model); 1368 putClientProperty("JTree.lineStyle", "None"); 1369 setRootVisible(false); setShowsRootHandles(true); 1372 setCellRenderer(new ClippedTreeCellRenderer()); 1373 } 1374 1375 1381 public final void bind(JXTreeTable treeTable) { 1382 if (treeTable == null) { 1385 throw new IllegalArgumentException ("null treeTable"); 1386 } 1387 1388 if (this.treeTable == null) { 1389 this.treeTable = treeTable; 1390 } 1391 else { 1392 throw new IllegalArgumentException ("renderer already bound"); 1393 } 1394 } 1395 1396 1400 public void updateUI() { 1401 super.updateUI(); 1402 TreeCellRenderer tcr = getCellRenderer(); 1405 if (tcr instanceof DefaultTreeCellRenderer ) { 1406 DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer ) tcr); 1407 dtcr.setBorderSelectionColor(null); 1410 dtcr.setTextSelectionColor( 1411 UIManager.getColor("Table.selectionForeground")); 1412 dtcr.setBackgroundSelectionColor( 1413 UIManager.getColor("Table.selectionBackground")); 1414 } 1415 } 1416 1417 1421 public void setRowHeight(int rowHeight) { 1422 super.setRowHeight(rowHeight); 1423 if (rowHeight > 0) { 1424 if (treeTable != null) { 1425 final int tableRowMargin = treeTable.getRowMargin(); 1427 assert tableRowMargin >= 0; 1428 final int tableRowHeight = rowHeight - (tableRowMargin << 1); 1429 if (treeTable.getRowHeight() != tableRowHeight) { 1430 treeTable.setRowHeight(tableRowHeight); 1431 } 1432 } 1433 } 1434 } 1435 1436 1439 public void setBounds(int x, int y, int w, int h) { 1440 if (treeTable != null) { 1441 y = 0; 1442 h = treeTable.getRowCount() * this.getRowHeight(); 1444 } 1445 super.setBounds(x, y, w, h); 1446 } 1447 1448 1452 public void paint(Graphics g) { 1453 int rowMargin = treeTable.getRowMargin(); 1454 int margins = rowMargin + (rowMargin >> 1) + (rowMargin % 2); 1458 int translationOffset = margins + visibleRow * getRowHeight(); 1459 g.translate(0, - translationOffset); 1460 1461 hierarchicalColumnWidth = getWidth(); 1462 super.paint(g); 1463 1464 if (highlightBorder != null) { 1466 highlightBorder.paintBorder(this, g, 0, 1473 translationOffset, 1474 getWidth(), 1475 getRowHeight() + 1 - 2 * (margins) ); 1477 1478 1479 } 1480 } 1481 1482 public Component getTableCellRendererComponent(JTable table, 1483 Object value, 1484 boolean isSelected, boolean hasFocus, int row, int column) { 1485 assert table == treeTable; 1486 1487 if (isSelected) { 1488 setBackground(table.getSelectionBackground()); 1489 setForeground(table.getSelectionForeground()); 1490 } 1491 else { 1492 setBackground(table.getBackground()); 1493 setForeground(table.getForeground()); 1494 } 1495 1496 highlightBorder = null; 1497 if (treeTable != null) { 1498 if (treeTable.realEditingRow() == row && 1499 treeTable.getEditingColumn() == column) { 1500 } 1501 else if (hasFocus) { 1502 highlightBorder = UIManager.getBorder( 1503 "Table.focusCellHighlightBorder"); 1504 } 1505 } 1506 1507 1508 visibleRow = row; 1509 1510 return this; 1511 } 1512 1513 private class ClippedTreeCellRenderer extends DefaultTreeCellRenderer { 1514 public void paint(Graphics g) { 1515 String fullText = super.getText(); 1516 1519 String shortText = SwingUtilities.layoutCompoundLabel( 1520 this, g.getFontMetrics(), fullText, getIcon(), 1521 getVerticalAlignment(), getHorizontalAlignment(), 1522 getVerticalTextPosition(), getHorizontalTextPosition(), 1523 getItemRect(itemRect), iconRect, textRect, 1524 getIconTextGap()); 1525 1526 1529 1530 setText(shortText); super.paint(g); 1532 setText(fullText); } 1534 1535 private Rectangle getItemRect(Rectangle itemRect) { 1536 getBounds(itemRect); 1537 itemRect.width = hierarchicalColumnWidth - itemRect.x; 1538 return itemRect; 1539 } 1540 1541 private final Rectangle iconRect = new Rectangle (); 1543 private final Rectangle textRect = new Rectangle (); 1544 private final Rectangle itemRect = new Rectangle (); 1546 } 1547 1548 1550 protected Border highlightBorder = null; 1551 protected JXTreeTable treeTable = null; 1552 protected int visibleRow = 0; 1553 1554 private int hierarchicalColumnWidth = 0; 1556 } 1557 1558 1564 protected ComponentAdapter getComponentAdapter() { 1565 return dataAdapter; 1567 } 1568 1569 private final ComponentAdapter dataAdapter = new TreeTableDataAdapter(this); 1570 1571 private final static int defaultRowHeight = 20; 1574 private final static Dimension spacing = new Dimension (0, 2); 1575 1576 static class TreeTableDataAdapter extends JXTable.TableAdapter { 1577 private final JXTreeTable table; 1578 1579 1585 public TreeTableDataAdapter(JXTreeTable component) { 1586 super(component); 1587 table = component; 1588 } 1589 public JXTreeTable getTreeTable() { 1590 return table; 1591 } 1592 1593 public boolean isExpanded() { 1594 return super.isExpanded(); 1595 } 1596 1597 public boolean hasFocus() { 1598 boolean focus = super.hasFocus(); 1599 return focus; 1600 } 1601 1602 public boolean isLeaf() { 1603 return super.isLeaf(); 1604 } 1605 1610 public boolean isHierarchical() { 1611 return table.isHierarchical(column); 1612 } 1613 } 1614 1615} 1616 | Popular Tags |