| 1 7 8 package org.jdesktop.swing; 9 10 import java.text.MessageFormat ; 11 import java.util.ArrayList ; 12 import java.util.Date ; 13 import java.util.Enumeration ; 14 import java.util.Iterator ; 15 import java.util.List ; 16 import java.util.Hashtable ; 17 import java.util.Timer ; 18 import java.util.TimerTask ; 19 import java.util.Vector ; 20 import java.util.regex.Pattern ; 21 import javax.print.attribute.HashPrintRequestAttributeSet ; 22 import javax.print.attribute.PrintRequestAttributeSet ; 23 24 import java.awt.Color ; 25 import java.awt.Component ; 26 import java.awt.Dimension ; 27 import java.awt.EventQueue ; 28 import java.awt.FontMetrics ; 29 import java.awt.Graphics ; 30 import java.awt.Point ; 31 import java.awt.Rectangle ; 32 import java.awt.event.*; 33 import java.awt.print.Printable ; 34 import java.awt.print.PrinterException ; 35 import java.awt.print.PrinterJob ; 36 37 import java.text.DateFormat ; 38 import java.text.NumberFormat ; 39 40 import javax.swing.ActionMap ; 41 import javax.swing.Icon ; 42 import javax.swing.ImageIcon ; 43 import javax.swing.JCheckBox ; 44 import javax.swing.JLabel ; 45 import javax.swing.JTable ; 46 import javax.swing.JViewport ; 47 import javax.swing.ListSelectionModel ; 48 import javax.swing.UIDefaults ; 49 import javax.swing.event.TableModelEvent ; 50 import javax.swing.table.DefaultTableCellRenderer ; 51 import javax.swing.table.JTableHeader ; 52 import javax.swing.table.TableCellRenderer ; 53 import javax.swing.table.TableColumn ; 54 import javax.swing.table.TableColumnModel ; 55 import javax.swing.table.TableModel ; 56 57 import org.jdesktop.swing.data.Link; 58 import org.jdesktop.swing.data.MetaData; 59 import org.jdesktop.swing.data.MetaDataProvider; 60 import org.jdesktop.swing.data.DefaultTableModelExt; 61 62 import org.jdesktop.swing.table.ColumnHeaderRenderer; 63 import org.jdesktop.swing.table.TableColumnExt; 64 import org.jdesktop.swing.table.TableColumnModelExt; 65 66 import org.jdesktop.swing.decorator.ComponentAdapter; 67 import org.jdesktop.swing.decorator.FilterPipeline; 68 import org.jdesktop.swing.decorator.HighlighterPipeline; 69 import org.jdesktop.swing.decorator.PipelineEvent; 70 import org.jdesktop.swing.decorator.PipelineListener; 71 import org.jdesktop.swing.decorator.Sorter; 72 import org.jdesktop.swing.table.DefaultTableColumnModelExt; 73 74 81 public class JXTable extends JTable implements PipelineListener, Searchable { 82 83 public static boolean TRACE = false; 84 88 public static final int PRINT_MODE_NORMAL = 0; 89 90 95 public static final int PRINT_MODE_FIT_WIDTH = 1; 96 97 protected Sorter sorter = null; 98 protected FilterPipeline filters = null; 99 protected HighlighterPipeline highlighters = null; 100 101 private final ComponentAdapter dataAdapter = new TableAdapter(this); 103 104 private final static MouseAdapter headerListener = new MouseAdapter() { 106 public void mouseClicked(MouseEvent e) { 108 JTableHeader header = (JTableHeader ) e.getSource(); 109 JXTable table = (JXTable) header.getTable(); 110 if (!table.isSortable()) return; 111 if ((e.getModifiersEx() & e.SHIFT_DOWN_MASK) == e.SHIFT_DOWN_MASK) { 112 table.resetSorter(); 113 } 114 else { 115 116 int column = header.getColumnModel().getColumnIndexAtX(e.getX()); 117 if (column >= 0) { 118 table.setSorter(column); 119 } 120 } 121 header.repaint(); 122 } 123 }; 124 125 130 private transient boolean isPrinting = false; 131 132 private boolean sortable = false; 133 private int visibleRowCount = 18; 134 135 public JXTable() { 136 init(); 137 } 138 139 public JXTable(TableModel dm) { 140 super(dm); 141 init(); 142 } 143 144 public JXTable(TableModel dm, TableColumnModel cm) { 145 super(dm, cm); 146 init(); 147 } 148 149 public JXTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) { 150 super(dm, cm, sm); 151 init(); 152 } 153 154 public JXTable(int numRows, int numColumns) { 155 super(numRows, numColumns); 156 init(); 157 } 158 159 public JXTable(Vector rowData, Vector columnNames) { 160 super(rowData, columnNames); 161 init(); 162 } 163 164 public JXTable(Object [][] rowData, Object [] columnNames) { 165 super(rowData, columnNames); 166 init(); 167 } 168 169 protected void init() { 170 setSortable(true); 171 ActionMap map = getActionMap(); 173 map.put("print", new Actions("print")); 174 map.put("find", new Actions("find")); 175 176 LinkHandler handler = new LinkHandler(); 180 addMouseListener(handler); 181 addMouseMotionListener(handler); 182 } 183 184 185 194 public TableCellRenderer getNewDefaultRenderer(Class columnClass) { 195 TableCellRenderer renderer = getDefaultRenderer(columnClass); 196 if (renderer != null) { 197 try { 198 return (TableCellRenderer ) renderer.getClass().newInstance(); 199 } catch (Exception e) { 200 e.printStackTrace(); 201 } 202 } 203 return null; 204 } 205 206 private void setLazyValue(Hashtable h, Class c, String s) { 207 h.put(c, new UIDefaults.ProxyLazyValue (s)); 208 } 209 210 private void setLazyRenderer(Class c, String s) { 211 setLazyValue(defaultRenderersByColumnClass, c, s); 212 } 213 214 219 protected void createDefaultRenderers() { 220 226 defaultRenderersByColumnClass = new UIDefaults (); 227 228 setLazyRenderer(Object .class, 230 "javax.swing.table.DefaultTableCellRenderer"); 231 232 setLazyRenderer(Number .class, "org.jdesktop.swing.JXTable$NumberRenderer"); 234 235 setLazyRenderer(Float .class, "org.jdesktop.swing.JXTable$DoubleRenderer"); 237 setLazyRenderer(Double .class, "org.jdesktop.swing.JXTable$DoubleRenderer"); 238 239 setLazyRenderer(Date .class, "org.jdesktop.swing.JXTable$DateRenderer"); 241 242 setLazyRenderer(Icon .class, "org.jdesktop.swing.JXTable$IconRenderer"); 244 setLazyRenderer(ImageIcon .class, "org.jdesktop.swing.JXTable$IconRenderer"); 245 246 setLazyRenderer(Boolean .class, "org.jdesktop.swing.JXTable$BooleanRenderer"); 248 249 setLazyRenderer(Link.class, "org.jdesktop.swing.JXTable$LinkRenderer"); 251 } 252 253 254 258 private class Actions extends UIAction { 259 Actions(String name) { 260 super(name); 261 } 262 263 public void actionPerformed(ActionEvent evt) { 264 if ("print".equals(getName())) { 265 try { 266 print(); 267 } 268 catch (PrinterException ex) { 269 ex.printStackTrace(); 271 } 272 } 273 else if ("find".equals(getName())) { 274 find(); 275 } 276 } 277 } 278 279 private JXFindDialog dialog = null; 280 private boolean automaticSortDisabled; 281 282 private void find() { 283 if (dialog == null) { 284 dialog = new JXFindDialog(this); 285 } 286 dialog.setVisible(true); 287 } 288 289 301 public void setSortable(boolean sortable) { 302 if (sortable == isSortable()) return; 303 this.sortable = sortable; 304 firePropertyChange("sortable", !sortable, sortable); 305 if (sorter != null) { 307 contentsChanged(null); 308 } 309 310 } 311 312 public boolean isSortable() { 313 return sortable; 314 } 315 316 317 326 public void tableChanged(TableModelEvent e) { 327 Selection selection = new Selection(this); 328 if (filters != null) { 329 filters.flush(); } 331 else if (sorter != null) { 332 sorter.refresh(); 333 } 337 338 super.tableChanged(e); 339 restoreSelection(selection); 340 } 341 342 public void contentsChanged(PipelineEvent e) { 343 removeSorter(); 344 clearSelection(); 345 346 setRowHeight(getRowHeight()); 349 revalidate(); 350 repaint(); 351 } 352 353 public int getRowCount() { 354 int count; 355 if (filters == null) { 356 count = getModel().getRowCount(); 357 } 358 else { 359 count = filters.getOutputSize(); 360 } 361 return count; 362 } 363 364 371 public int convertRowIndexToModel(int row) { 372 if (sorter == null) { 373 if (filters == null) { 374 return row; 375 } 376 else { 377 return filters.convertRowIndexToModel(row); 379 } 380 } 381 else { 382 return sorter.convertRowIndexToModel(row); 385 } 386 } 387 388 395 public int convertRowIndexToView(int row) { 396 if (sorter == null) { 397 if (filters == null) { 398 return row; 399 } 400 else { 401 return filters.convertRowIndexToView(row); 403 } 404 } 405 else { 406 return sorter.convertRowIndexToView(row); 409 } 410 } 411 412 415 public Object getValueAt(int row, int column) { 416 if (sorter == null) { if (filters == null) { return super.getValueAt(row, column); } 420 else { return filters.getValueAt(row, convertColumnIndexToModel(column)); 422 } 423 } 424 else { return sorter.getValueAt(row, convertColumnIndexToModel(column)); 426 } 427 } 428 429 public void setValueAt(Object aValue, int row, int column) { 430 if (sorter == null) { 431 if (filters == null) { 432 super.setValueAt(aValue, row, column); 433 } 434 else { 435 filters.setValueAt(aValue, row, convertColumnIndexToModel(column)); 436 } 437 } 438 else { 439 sorter.setValueAt(aValue, row, convertColumnIndexToModel(column)); 440 } 441 } 442 443 public boolean isCellEditable(int row, int column) { 444 if (sorter == null) { 445 if (filters == null) { 446 return super.isCellEditable(row, column); 447 } 448 else { 449 return filters.isCellEditable(row, convertColumnIndexToModel(column)); 450 } 451 } 452 else { 453 return sorter.isCellEditable(row, convertColumnIndexToModel(column)); 454 } 455 } 456 457 public void setModel(TableModel newModel) { 458 clearSelection(); 462 super.setModel(newModel); 463 use(filters); 464 } 465 466 467 473 public void setTableHeader(JTableHeader tableHeader) { 474 if (tableHeader != null) { 476 tableHeader.addMouseListener(headerListener); 477 tableHeader.setDefaultRenderer(new ColumnHeaderRenderer()); 478 } 479 super.setTableHeader(tableHeader); 480 } 481 482 487 488 protected TableColumnModel createDefaultColumnModel() { 489 return new DefaultTableColumnModelExt(); 490 } 491 492 private void restoreSelection(Selection selection) { 493 clearSelection(); 495 for (int i = 0; i < selection.selected.length; i++) { 496 if ((selection.selected[i] != selection.lead) && (selection.selected[i] < getModel().getRowCount())) { 499 int index = convertRowIndexToView(selection.selected[i]); 500 selectionModel.addSelectionInterval(index, index); 501 } 502 } 503 504 if ((selection.lead >= 0) && (selection.lead < getModel().getRowCount())) { 507 selection.lead = convertRowIndexToView(selection.lead); 508 selectionModel.addSelectionInterval(selection.lead, selection.lead); 509 } 510 } 511 512 public FilterPipeline getFilters() { 513 return filters; 514 } 515 516 521 private void use(FilterPipeline pipeline) { 522 if (pipeline != null) { 523 if (initialUse(pipeline)) { 525 pipeline.addPipelineListener(this); 526 pipeline.assign(getComponentAdapter()); 527 } 528 pipeline.flush(); 529 } 530 } 531 532 537 private boolean initialUse(FilterPipeline pipeline) { 538 PipelineListener[] l = pipeline.getPipelineListeners(); 539 for (int i = 0; i < l.length; i++) { 540 if (this.equals(l[i])) return false; 541 } 542 return true; 543 } 544 545 public void setFilters(FilterPipeline pipeline) { 546 unsetFilters(); 547 doSetFilters(pipeline); 548 } 549 550 private void unsetFilters() { 551 if (filters == null) return; 552 filters.removePipelineListener(this); 554 contentsChanged(null); 557 } 558 559 private void doSetFilters(FilterPipeline pipeline) { 560 filters = pipeline; 561 use(filters); 562 } 563 564 public HighlighterPipeline getHighlighters() { 565 return highlighters; 566 } 567 568 public void setHighlighters(HighlighterPipeline pipeline) { 569 highlighters = pipeline; 570 } 571 572 private void removeSorter() { 573 sorter = null; 579 getTableHeader().repaint(); 580 } 581 582 583 586 protected void resetSorter() { 587 if (sorter != null) { 588 Selection selection = new Selection(this); 589 removeSorter(); 590 restoreSelection(selection); 591 } 592 } 593 594 private Sorter refreshSorter(int columnIndex) { 595 TableColumn col = getColumnModel().getColumn(columnIndex); 596 if (col instanceof TableColumnExt) { 597 TableColumnExt column = (TableColumnExt) col; 598 Sorter newSorter = column.getSorter(); 599 if (newSorter != null) { 600 newSorter.interpose(null, getComponentAdapter(), null); 603 newSorter.interpose(filters, getComponentAdapter(), sorter); return newSorter; 606 } 607 } 608 return sorter; 609 } 610 611 614 protected void setSorter(int columnIndex) { 615 Selection selection = new Selection(this); 616 if (sorter == null) { 617 sorter = refreshSorter(columnIndex); } 619 else { 620 int modelColumnIndex = convertColumnIndexToModel(columnIndex); 621 if (sorter.getColumnIndex() == modelColumnIndex) { 622 sorter.toggle(); 623 } 624 else { 625 sorter = refreshSorter(columnIndex); } 627 } 628 restoreSelection(selection); 629 } 630 631 634 public Sorter getSorter(int columnIndex) { 635 return sorter == null ? null : 636 sorter.getColumnIndex() == convertColumnIndexToModel(columnIndex) ? 637 sorter : null; 638 } 639 640 643 protected void removeColumns() { 644 646 TableColumnModel cm = getColumnModel(); 647 while (cm.getColumnCount() > 0) { 648 cm.removeColumn(cm.getColumn(0)); 649 } 650 } 651 652 public List getColumns() { 653 return null; 654 } 655 656 668 669 public TableColumnExt getColumnExt(Object identifier) { 670 return (TableColumnExt)super.getColumn(identifier); 671 } 672 673 public TableColumnExt getColumnExt(int viewColumnIndex) { 674 return (TableColumnExt) getColumnModel().getColumn(viewColumnIndex); 675 } 676 677 689 713 714 722 protected TableModel createDefaultDataModel() { 723 return new DefaultTableModelExt(); 724 } 725 726 public void createDefaultColumnsFromModel() { 727 TableModel model = getModel(); 728 if (model != null) { 729 int modelColumnCount = model.getColumnCount(); 733 TableColumn newColumns[] = new TableColumn [modelColumnCount]; 734 for (int i = 0; i < newColumns.length; i++) { 735 newColumns[i] = createColumn(i); 736 } 737 738 if (model instanceof MetaDataProvider) { 739 MetaData metaData[] = ((MetaDataProvider)model).getMetaData(); 740 for(int i = 0; i < metaData.length; i++) { 741 newColumns[i].setIdentifier(metaData[i].getName()); 742 newColumns[i].setHeaderValue(metaData[i].getLabel()); 743 } 744 } 745 746 TableColumnModel columnModel = getColumnModel(); 748 while (columnModel.getColumnCount() > 0) { 749 columnModel.removeColumn(columnModel.getColumn(0)); 750 } 751 752 for (int i = 0; i < newColumns.length; i++) { 754 addColumn(newColumns[i]); 755 } 756 } 757 } 758 759 protected TableColumn createColumn(int modelIndex) { 760 return new TableColumnExt(modelIndex); 761 } 762 763 764 769 public int getColumnMargin() { 770 return getColumnModel().getColumnMargin(); 771 } 772 773 778 public void setColumnMargin(int value) { 779 getColumnModel().setColumnMargin(value); 780 } 781 782 787 public int getSelectionMode() { 788 return getSelectionModel().getSelectionMode(); 789 } 790 791 802 public Component prepareRenderer(TableCellRenderer renderer, int row, 803 int column) { 804 Component stamp = super.prepareRenderer(renderer, row, column); 805 if (highlighters == null) { 806 return stamp; } 808 else { 809 ComponentAdapter adapter = getComponentAdapter(); 811 adapter.row = row; 812 adapter.column = column; 813 return highlighters.apply(stamp, adapter); 814 } 815 } 816 817 protected ComponentAdapter getComponentAdapter() { 818 return dataAdapter; 820 } 821 822 public int search(String searchString) { 823 return search(searchString, -1); 824 } 825 826 public int search(String searchString, int columnIndex) { 827 Pattern pattern = null; 828 if (searchString != null) { 829 return search(Pattern.compile(searchString, 0), columnIndex); 830 } 831 return -1; 832 } 833 834 public int search(Pattern pattern) { 835 return search(pattern, -1); 836 } 837 838 public int search(Pattern pattern, int startIndex) { 839 return search(pattern, startIndex, false); 840 } 841 842 private int lastCol = 0; 844 845 849 public int search(Pattern pattern, int startIndex, boolean backwards) { 850 if (pattern == null) { 851 lastCol = 0; 852 return -1; 853 } 854 int rows = getRowCount(); 855 int endCol = getColumnCount(); 856 857 int startRow = startIndex + 1; 858 int matc
|