001 package org.springframework.richclient.widget.table.glazedlists; 002 003 import ca.odell.glazedlists.*; 004 import ca.odell.glazedlists.event.ListEvent; 005 import ca.odell.glazedlists.event.ListEventListener; 006 import ca.odell.glazedlists.gui.TableFormat; 007 import ca.odell.glazedlists.gui.WritableTableFormat; 008 import ca.odell.glazedlists.swing.*; 009 import com.jgoodies.forms.layout.CellConstraints; 010 import com.jgoodies.forms.layout.FormLayout; 011 import com.jgoodies.forms.layout.Size; 012 import com.jgoodies.forms.layout.Sizes; 013 import org.jdesktop.swingx.JXTable; 014 import org.jdesktop.swingx.decorator.*; 015 import org.jdesktop.swingx.table.TableColumnExt; 016 import org.jdesktop.xswingx.JXSearchField; 017 import org.springframework.richclient.application.Application; 018 import org.springframework.richclient.command.AbstractCommand; 019 import org.springframework.richclient.command.ActionCommand; 020 import org.springframework.richclient.command.CommandGroup; 021 import org.springframework.richclient.command.config.CommandConfigurer; 022 import org.springframework.richclient.util.RcpSupport; 023 import org.springframework.richclient.util.ValueMonitor; 024 import org.springframework.richclient.widget.AbstractWidget; 025 import org.springframework.richclient.widget.table.TableCellRenderers; 026 import org.springframework.richclient.widget.table.TableDescription; 027 import org.springframework.richclient.widget.table.TableWidget; 028 029 import javax.swing.*; 030 import javax.swing.border.Border; 031 import javax.swing.event.*; 032 import javax.swing.table.DefaultTableCellRenderer; 033 import javax.swing.table.TableCellEditor; 034 import javax.swing.table.TableCellRenderer; 035 import java.awt.*; 036 import java.awt.event.FocusAdapter; 037 import java.awt.event.FocusEvent; 038 import java.awt.event.ActionListener; 039 import java.awt.event.ActionEvent; 040 import java.beans.PropertyChangeEvent; 041 import java.beans.PropertyChangeListener; 042 import java.util.*; 043 import java.util.List; 044 045 public final class GlazedListTableWidget extends AbstractWidget implements TableWidget 046 { 047 private JXTable theTable = new JXTable(); 048 049 private JScrollPane tableScroller; 050 051 private ValueMonitor selectionMonitor = new ValueMonitor(); 052 053 private EventTableModel<Object> tableModel; 054 055 private EventSelectionModel<Object> selectionModel; 056 057 private EventList<Object> dataList; 058 059 private EventList<Object> shownList; 060 061 private SortedList<Object> sortedList; 062 063 private JTextField textFilterField; 064 065 private AbstractCommand[] navigationCommands; 066 067 private CommandGroup navigationCommandGroup; 068 069 private CommandGroup selectColumnCommandGroup; 070 071 private CommandConfigurer commandConfigurer; 072 073 private JLabel countLabel; 074 075 static 076 { 077 UIManager.put("JXTable.column.horizontalScroll", RcpSupport.getMessage("JXTable.horizontalScroll.label")); 078 UIManager.put("JXTable.column.packAll", RcpSupport.getMessage("JXTable.packAll.label")); 079 UIManager.put("JXTable.column.packSelected", RcpSupport.getMessage("JXTable.packSelected.label")); 080 } 081 082 /** 083 * CellEditorListener op de selectiekolom om de selectieListeners gezamelijk 084 * te triggeren . 085 */ 086 private CellEditorListener userSelectionCellEditorListener = new CellEditorListener() 087 { 088 089 public void editingStopped(ChangeEvent e) 090 { 091 fireUserSelectionChangedEvent(); 092 } 093 094 public void editingCanceled(ChangeEvent e) 095 { 096 } 097 }; 098 099 private Set dirtyRows = new HashSet(); 100 101 private CellEditorListener dirtyRowCellEditorListener = new CellEditorListener() 102 { 103 104 public void editingCanceled(ChangeEvent e) 105 { 106 } 107 108 109 public void editingStopped(ChangeEvent e) 110 { 111 dirtyRows.add(getSelectedRows()[0]); 112 } 113 }; 114 115 /** 116 * De listeners geregistreerd op de selectiekolom, getriggerd door 117 * {@link #userSelectionCellEditorListener}. 118 */ 119 private List<PropertyChangeListener> userSelectionListeners; 120 121 public GlazedListTableWidget(List<? extends Object> rows, TableDescription tableDesc) 122 { 123 this(rows, tableDesc, tableDesc.getDefaultComparator()); 124 } 125 126 public GlazedListTableWidget(List<? extends Object> rows, TableDescription tableDesc, 127 Comparator comparator) 128 { 129 this(tableDesc.getDataType(), rows, GlazedListsSupport.makeTableFormat(tableDesc), GlazedListsSupport 130 .makeFilterProperties(tableDesc), comparator, tableDesc.hasSelectColumn()); 131 // Als de tablewidget met ons eigen TableDescription class is gemaakt 132 // kunnen we additionele dingen als width/resizable/renderer en editor 133 // zetten 134 // bedenking: zouden we tabledesc van een iterator voorzien om over de 135 // kolommen te lopen? 136 TableCellEditor columnEditor = null; 137 for (int i = 0; i < tableDesc.getColumnCount(); ++i) 138 { 139 TableColumnExt column = (TableColumnExt) theTable.getColumns(true).get(i); 140 int columnWidth = tableDesc.getMaxColumnWidth(i); 141 if (columnWidth > 0) 142 { 143 column.setMaxWidth(columnWidth); 144 } 145 columnWidth = tableDesc.getMinColumnWidth(i); 146 if (columnWidth > 0) 147 { 148 column.setMinWidth(columnWidth); 149 } 150 column.setResizable(tableDesc.isResizable(i)); 151 column.setVisible(tableDesc.isVisible(i)); 152 columnEditor = tableDesc.getColumnEditor(i); 153 if (columnEditor != null) 154 { 155 if (tableDesc.isSelectColumn(i)) 156 { 157 columnEditor.addCellEditorListener(userSelectionCellEditorListener); 158 } 159 else 160 { 161 columnEditor.addCellEditorListener(dirtyRowCellEditorListener); 162 } 163 column.setCellEditor(columnEditor); 164 } 165 if (tableDesc.getColumnRenderer(i) != null) 166 { 167 TableCellRenderer renderer = tableDesc.getColumnRenderer(i); 168 column.setCellRenderer(renderer); 169 if (renderer instanceof DefaultTableCellRenderer) 170 { 171 int align = ((DefaultTableCellRenderer) renderer).getHorizontalAlignment(); 172 switch (align) 173 { 174 case SwingConstants.CENTER: 175 column.setHeaderRenderer(wrapInSortArrowHeaderRenderer(TableCellRenderers.CENTER_ALIGNED_HEADER_RENDERER)); 176 break; 177 case SwingConstants.RIGHT: 178 column.setHeaderRenderer(wrapInSortArrowHeaderRenderer(TableCellRenderers.RIGHT_ALIGNED_HEADER_RENDERER)); 179 break; 180 default: 181 break; 182 } 183 } 184 } 185 } 186 } 187 188 private TableCellRenderer wrapInSortArrowHeaderRenderer(TableCellRenderer renderer) 189 { 190 if (tableComparatorChooser != null) 191 { 192 return tableComparatorChooser.createSortArrowHeaderRenderer(renderer); 193 } 194 else 195 { 196 return renderer; 197 } 198 } 199 200 public GlazedListTableWidget(Class dataType, List<? extends Object> rows, TableFormat format, 201 String[] filterProperties) 202 { 203 this(dataType, rows, format, filterProperties, null, false); 204 } 205 206 public GlazedListTableWidget(Class dataType, List<? extends Object> rows, TableFormat format, 207 String[] filterProperties, Comparator comparator, boolean addHighlightSelectColumn) 208 { 209 theTable.setColumnControlVisible(true); 210 theTable.getSelectionMapper().setEnabled(false); 211 commandConfigurer = (CommandConfigurer) Application.services().getService(CommandConfigurer.class); 212 dataList = rows == null ? new BasicEventList<Object>() : GlazedLists.eventList(rows); 213 214 sortedList = new SortedList<Object>(dataList, comparator); 215 this.shownList = sortedList; 216 217 if (filterProperties != null) 218 { 219 textFilterField = new JXSearchField(RcpSupport.getMessage("glazedListTableWidget.textFilterField.prompt")); 220 textFilterField.addFocusListener(new FocusAdapter() 221 { 222 @Override 223 public void focusGained(FocusEvent e) 224 { 225 textFilterField.selectAll(); 226 } 227 }); 228 shownList = new FilterList<Object>(shownList, 229 new TextComponentMatcherEditor(textFilterField, GlazedLists.textFilterator(dataType, 230 filterProperties))); 231 } 232 233 selectionModel = new EventSelectionModel<Object>(shownList); 234 selectionModel.addListSelectionListener(new SelectionNavigationListener()); 235 theTable.setSelectionModel(selectionModel); 236 237 tableModel = new EventJXTableModel<Object>(shownList, format); 238 theTable.setModel(tableModel); 239 240 if (addHighlightSelectColumn) 241 { 242 Highlighter selectHighlighter = new ColorHighlighter(HIGHLIGHTSELECTCOLUMN, new Color(0xF0, 0xF0, 0xE0), Color.BLACK); 243 setHighlighters(HighlighterFactory.createSimpleStriping(), selectHighlighter); 244 initializeSelectColumnCommands(); 245 } 246 else 247 { 248 setHighlighters(HighlighterFactory.createSimpleStriping()); 249 } 250 251 if (sortedList != null) 252 { 253 theTable.setSortable(false); 254 theTable.getTableHeader().setDefaultRenderer(TableCellRenderers.LEFT_ALIGNED_HEADER_RENDERER); 255 tableComparatorChooser = TableComparatorChooser 256 .install(theTable, sortedList, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE_WITH_UNDO); 257 // the following is a fix for the selection sort and navigation problem 258 tableComparatorChooser.addSortActionListener(new ActionListener() 259 { 260 public void actionPerformed(ActionEvent e) 261 { 262 EventList<Object> selected = selectionModel.getSelected(); 263 int[] indexes = new int[selected.size()]; 264 int i = 0; 265 for (Object o : selected) 266 { 267 indexes[i++] = shownList.indexOf(o); 268 } 269 selectionModel.clearSelection(); 270 for (int index : indexes) 271 { 272 selectionModel.addSelectionInterval(index, index); 273 } 274 } 275 }); 276 } 277 278 theTable.setPreferredScrollableViewportSize(new Dimension(50, 50)); 279 tableScroller = new JScrollPane(theTable); 280 theTable.setHorizontalScrollEnabled(true); 281 initializeNavigationCommands(); 282 } 283 284 /** 285 * Enable the row height to diverge from the default height. 286 * <p/> 287 * NOTE: this is experimental as there is a problem with glazedlists and jxtable. 288 * (see note on ExtendedJXTable above) 289 */ 290 public void setRowHeightEnabled(boolean rowHeightEnabled) 291 { 292 theTable.setRowHeightEnabled(true); 293 } 294 295 private class SelectionNavigationListener implements ListSelectionListener 296 { 297 298 public void valueChanged(ListSelectionEvent e) 299 { 300 // enkel op einde van reeks selection veranderingen reageren. 301 if (!e.getValueIsAdjusting()) 302 { 303 if (selectionModel.getSelected().size() == 1) 304 { 305 selectionMonitor.setValue(selectionModel.getSelected().get(0)); 306 } 307 else 308 { 309 Object[] selectedRows = selectionModel.getSelected().toArray(); 310 selectionMonitor.setValue(selectedRows.length > 0 ? selectedRows : null); 311 } 312 313 int selectedIndex = selectionModel.getAnchorSelectionIndex(); 314 int lastIndex = shownList.size() - 1; 315 boolean emptyList = (lastIndex == -1); 316 boolean onFirst = (selectedIndex == 0); 317 boolean onLast = (selectedIndex == lastIndex); 318 319 navigationCommands[NAVIGATE_FIRST].setEnabled(!emptyList && !onFirst); 320 navigationCommands[NAVIGATE_PREVIOUS].setEnabled(!emptyList && !onFirst); 321 navigationCommands[NAVIGATE_NEXT].setEnabled(!emptyList && !onLast); 322 navigationCommands[NAVIGATE_LAST].setEnabled(!emptyList && !onLast); 323 } 324 } 325 } 326 327 public static final HighlightPredicate HIGHLIGHTSELECTCOLUMN = new HighlightSelectColumn(); 328 329 private TableComparatorChooser tableComparatorChooser; 330 331 static class HighlightSelectColumn implements HighlightPredicate 332 { 333 334 public boolean isHighlighted(Component renderer, ComponentAdapter adapter) 335 { 336 Object selectedValue = adapter.getValueAt(adapter.row, 0); 337 return Boolean.TRUE.equals(selectedValue); 338 } 339 } 340 341 public void setHighlighters(Highlighter... highlighters) 342 { 343 this.theTable.setHighlighters(highlighters); 344 } 345 346 /** 347 * {@inheritDoc} 348 */ 349 public boolean isEmpty() 350 { 351 return this.dataList.isEmpty(); 352 } 353 354 /** 355 * {@inheritDoc} 356 */ 357 public int nrOfRows() 358 { 359 return this.tableModel.getRowCount(); 360 } 361 362 private void initializeNavigationCommands() 363 { 364 this.navigationCommands = new AbstractCommand[4]; 365 this.navigationCommands[NAVIGATE_FIRST] = new ActionCommand(NAVIGATE_FIRSTROW_CMDID) 366 { 367 368 @Override 369 protected void doExecuteCommand() 370 { 371 selectionModel.setSelectionInterval(0, 0); 372 scrollToSelectedRow(); 373 } 374 }; 375 this.navigationCommands[NAVIGATE_PREVIOUS] = new ActionCommand(NAVIGATE_PREVIOUSROW_CMDID) 376 { 377 378 @Override 379 protected void doExecuteCommand() 380 { 381 int newIndex = selectionModel.getAnchorSelectionIndex() - 1; 382 newIndex = (newIndex < 0) ? 0 : newIndex; 383 selectionModel.setSelectionInterval(newIndex, newIndex); 384 scrollToSelectedRow(); 385 } 386 }; 387 this.navigationCommands[NAVIGATE_NEXT] = new ActionCommand(NAVIGATE_NEXTROW_CMDID) 388 { 389 390 @Override 391 protected void doExecuteCommand() 392 { 393 int newIndex = selectionModel.getAnchorSelectionIndex() + 1; 394 int lastIndex = shownList.size() - 1; 395 newIndex = (newIndex > lastIndex) ? lastIndex : newIndex; 396 selectionModel.setSelectionInterval(newIndex, newIndex); 397 scrollToSelectedRow(); 398 } 399 }; 400 this.navigationCommands[NAVIGATE_LAST] = new ActionCommand(NAVIGATE_LASTROW_CMDID) 401 { 402 403 @Override 404 protected void doExecuteCommand() 405 { 406 int lastIndex = shownList.size() - 1; 407 selectionModel.setSelectionInterval(lastIndex, lastIndex); 408 scrollToSelectedRow(); 409 } 410 }; 411 412 for (int i = 0; i < this.navigationCommands.length; i++) 413 { 414 this.commandConfigurer.configure(this.navigationCommands[i]); 415 this.navigationCommands[i].setEnabled(false); 416 } 417 this.navigationCommandGroup = CommandGroup.createCommandGroup(this.navigationCommands); 418 } 419 420 private void fireUserSelectionChangedEvent() 421 { 422 if (userSelectionListeners != null) 423 { 424 for (Iterator listeners = userSelectionListeners.iterator(); listeners.hasNext();) 425 { 426 PropertyChangeListener listener = (PropertyChangeListener) listeners.next(); 427 listener.propertyChange(new PropertyChangeEvent(this, "selection", null, null)); 428 } 429 } 430 } 431 432 public void addUserSelectionListener(PropertyChangeListener listener) 433 { 434 if (userSelectionListeners == null) 435 { 436 userSelectionListeners = new ArrayList<PropertyChangeListener>(); 437 } 438 userSelectionListeners.add(listener); 439 } 440 441 private void initializeSelectColumnCommands() 442 { 443 final WritableTableFormat writableTableFormat = (WritableTableFormat) this.tableModel 444 .getTableFormat(); 445 AbstractCommand selectAll = new ActionCommand(SELECT_ALL_ID) 446 { 447 448 @Override 449 protected void doExecuteCommand() 450 { 451 shownList.getReadWriteLock().writeLock().lock(); 452 Iterator i = shownList.iterator(); 453 while (i.hasNext()) 454 { 455 writableTableFormat.setColumnValue(i.next(), Boolean.TRUE, 0); 456 } 457 shownList.getReadWriteLock().writeLock().unlock(); 458 theTable.repaint(); 459 fireUserSelectionChangedEvent(); 460 } 461 }; 462 this.commandConfigurer.configure(selectAll); 463 AbstractCommand selectNone = new ActionCommand(SELECT_NONE_ID) 464 { 465 466 @Override 467 protected void doExecuteCommand() 468 { 469 shownList.getReadWriteLock().writeLock().lock(); 470 Iterator i = shownList.iterator(); 471 while (i.hasNext()) 472 { 473 writableTableFormat.setColumnValue(i.next(), Boolean.FALSE, 0); 474 } 475 shownList.getReadWriteLock().writeLock().unlock(); 476 theTable.repaint(); 477 fireUserSelectionChangedEvent(); 478 } 479 }; 480 this.commandConfigurer.configure(selectNone); 481 AbstractCommand selectInverse = new ActionCommand(SELECT_INVERSE_ID) 482 { 483 484 @Override 485 protected void doExecuteCommand() 486 { 487 shownList.getReadWriteLock().writeLock().lock(); 488 Iterator i = shownList.iterator(); 489 while (i.hasNext()) 490 { 491 Object rowObject = i.next(); 492 Object columnValue = writableTableFormat.getColumnValue(rowObject, 0); 493 writableTableFormat.setColumnValue(rowObject, Boolean.TRUE.equals(columnValue) 494 ? Boolean.FALSE 495 : Boolean.TRUE, 0); 496 } 497 shownList.getReadWriteLock().writeLock().unlock(); 498 theTable.repaint(); 499 fireUserSelectionChangedEvent(); 500 } 501 }; 502 this.commandConfigurer.configure(selectInverse); 503 this.selectColumnCommandGroup = CommandGroup.createCommandGroup(new Object[]{selectAll, selectNone, 504 selectInverse}); 505 } 506 507 public final void setRows(Collection newRows) 508 { 509 this.dataList.getReadWriteLock().writeLock().lock(); 510 try 511 { 512 this.dirtyRows.clear(); 513 theTable.clearSelection(); 514 this.dataList.clear(); 515 this.dataList.addAll(newRows); 516 517 scrollToSelectedRow(); // new rows, scroll back to top 518 } 519 finally 520 { 521 this.dataList.getReadWriteLock().writeLock().unlock(); 522 } 523 } 524 525 public final List getRows() 526 { 527 return new ArrayList<Object>(this.dataList); 528 } 529 530 public final List getVisibleRows() 531 { 532 return new ArrayList<Object>(this.shownList); 533 } 534 535 public void addRowObject(Object newObject) 536 { 537 this.dataList.getReadWriteLock().writeLock().lock(); 538 try 539 { 540 this.dataList.add(newObject); 541 } 542 finally 543 { 544 this.dataList.getReadWriteLock().writeLock().unlock(); 545 } 546 } 547 548 public void addRows(Collection rows) 549 { 550 this.dataList.getReadWriteLock().writeLock().lock(); 551 try 552 { 553 this.dataList.addAll(rows); 554 } 555 finally 556 { 557 this.dataList.getReadWriteLock().writeLock().unlock(); 558 } 559 } 560 561 public void removeRowObject(Object objectToRemove) 562 { 563 this.dataList.getReadWriteLock().writeLock().lock(); 564 try 565 { 566 dirtyRows.remove(objectToRemove); 567 this.dataList.remove(objectToRemove); 568 } 569 finally 570 { 571 this.dataList.getReadWriteLock().writeLock().unlock(); 572 } 573 } 574 575 public int selectRowObject(Object toPointTo, Observer originatingObserver) 576 { 577 int index = this.shownList.indexOf(toPointTo); 578 selectRowObject(index, originatingObserver); 579 return index; 580 } 581 582 public void selectRowObject(final int index, final Observer originatingObserver) 583 { 584 Runnable doSelectRowObject = new Runnable() 585 { 586 587 public void run() 588 { 589 if (originatingObserver != null) 590 { 591 selectionMonitor.deleteObserver(originatingObserver); 592 } 593 594 if ((index > -1) && (shownList.size() > index)) 595 { 596 selectionModel.setSelectionInterval(index, index); 597 } 598 else 599 { 600 selectionModel.clearSelection(); 601 } 602 scrollToSelectedRow(); 603 604 if (originatingObserver != null) 605 { 606 selectionMonitor.addObserver(originatingObserver); 607 } 608 } 609 }; 610 if (SwingUtilities.isEventDispatchThread()) 611 { 612 doSelectRowObject.run(); 613 } 614 else 615 { 616 SwingUtilities.invokeLater(doSelectRowObject); 617 } 618 619 } 620 621 public void addSelection(final Object[] rows, final Observer originatingObserver) 622 { 623 Runnable doAddSelection = new Runnable() 624 { 625 public void run() 626 { 627 if (originatingObserver != null) 628 { 629 selectionMonitor.deleteObserver(originatingObserver); 630 } 631 for (int i = 0; i < rows.length; i++) 632 { 633 int index = shownList.indexOf(rows[i]); 634 selectionModel.addSelectionInterval(index, index); 635 } 636 if (originatingObserver != null) 637 { 638 selectionMonitor.addObserver(originatingObserver); 639 } 640 } 641 }; 642 if (SwingUtilities.isEventDispatchThread()) 643 { 644 doAddSelection.run(); 645 } 646 else 647 { 648 SwingUtilities.invokeLater(doAddSelection); 649 } 650 } 651 652 public boolean hasSelection() 653 { 654 return !this.selectionModel.isSelectionEmpty(); 655 } 656 657 public synchronized void scrollToSelectedRow() 658 { 659 Runnable doScrollToSelectedRow = new Runnable() 660 { 661 public void run() 662 { 663 if (theTable.isVisible()) 664 { 665 int selectedRow = theTable.getSelectedRow(); 666 if (selectedRow != -1) 667 { 668 Rectangle cellRect = theTable.getCellRect(selectedRow, 0, true); 669 Rectangle viewRect = tableScroller.getViewport().getViewRect(); 670 if (!viewRect.contains(cellRect)) 671 { 672 if (cellRect.y < viewRect.y) // cell is above view (or cut above) 673 { 674 tableScroller.getViewport().setViewPosition(cellRect.getLocation()); 675 } 676 else // cell is below view (or cut below) 677 { 678 tableScroller.getViewport().scrollRectToVisible(cellRect); 679 } 680 } 681 } 682 else 683 { 684 tableScroller.getViewport().setViewPosition(new Point(0, 0)); 685 } 686 } 687 } 688 }; 689 if (SwingUtilities.isEventDispatchThread()) 690 { 691 doScrollToSelectedRow.run(); 692 } 693 else 694 { 695 SwingUtilities.invokeLater(doScrollToSelectedRow); 696 } 697 } 698 699 public void replaceRowObject(Object oldObject, Object newObject, Observer originatingObserver) 700 { 701 this.dataList.getReadWriteLock().writeLock().lock(); 702 try 703 { 704 dirtyRows.remove(oldObject); 705 int index = this.dataList.indexOf(oldObject); 706 if (index != -1) 707 { 708 boolean wasSelected = this.selectionModel.isSelectedIndex(this.shownList.indexOf(oldObject)); 709 710 if (wasSelected && (originatingObserver != null)) 711 { 712 this.selectionMonitor.deleteObserver(originatingObserver); 713 } 714 715 this.dataList.set(index, newObject); 716 717 if (wasSelected) 718 { 719 int indexToSelect = this.shownList.indexOf(newObject); 720 this.selectionModel.addSelectionInterval(indexToSelect, indexToSelect); 721 if (originatingObserver != null) 722 { 723 this.selectionMonitor.addObserver(originatingObserver); 724 } 725 } 726 } 727 } 728 finally 729 { 730 this.dataList.getReadWriteLock().writeLock().unlock(); 731 } 732 } 733 734 public void replaceRows(final Collection oldObject, final Collection newObject) 735 { 736 Runnable doReplaceRows = new Runnable() 737 { 738 public void run() 739 { 740 dataList.getReadWriteLock().writeLock().lock(); 741 try 742 { 743 dirtyRows.clear(); 744 dataList.removeAll(oldObject); 745 dataList.addAll(newObject); 746 } 747 finally 748 { 749 dataList.getReadWriteLock().writeLock().unlock(); 750 } 751 } 752 }; 753 if (SwingUtilities.isEventDispatchThread()) 754 { 755 doReplaceRows.run(); 756 } 757 else 758 { 759 SwingUtilities.invokeLater(doReplaceRows); 760 } 761 } 762 763 public void unSelectAll() 764 { 765 Runnable doUnselectAll = new Runnable() 766 { 767 public void run() 768 { 769 selectionModel.clearSelection(); 770 } 771 }; 772 if (SwingUtilities.isEventDispatchThread()) 773 { 774 doUnselectAll.run(); 775 } 776 else 777 { 778 SwingUtilities.invokeLater(doUnselectAll); 779 } 780 } 781 782 public Object[] getSelectedRows() 783 { 784 return this.selectionModel.getSelected().toArray(); 785 } 786 787 public JComponent getComponent() 788 { 789 return this.tableScroller; 790 } 791 792 public JTable getTable() 793 { 794 return this.theTable; 795 } 796 797 public void addSelectionObserver(Observer observer) 798 { 799 this.selectionMonitor.addObserver(observer); 800 } 801 802 public void removeSelectionObserver(Observer observer) 803 { 804 this.selectionMonitor.deleteObserver(observer); 805 } 806 807 public void addTableModelListener(TableModelListener listener) 808 { 809 this.tableModel.addTableModelListener(listener); 810 } 811 812 public void removeTableModelListener(TableModelListener listener) 813 { 814 this.tableModel.removeTableModelListener(listener); 815 } 816 817 public void updateTable() 818 { 819 this.tableModel.fireTableDataChanged(); 820 } 821 822 public JTextField getTextFilterField() 823 { 824 return textFilterField; 825 } 826 827 public AbstractCommand[] getNavigationCommands() 828 { 829 return navigationCommands; 830 } 831 832 public JComponent getNavigationButtonBar() 833 { 834 return getNavigationButtonBar(Sizes.PREFERRED, BorderFactory.createEmptyBorder()); 835 } 836 837 public JComponent getNavigationButtonBar(Size size, Border border) 838 { 839 return this.navigationCommandGroup.createButtonBar(size, border); 840 } 841 842 public CommandGroup getNavigationCommandGroup() 843 { 844 return this.navigationCommandGroup; 845 } 846 847 public CommandGroup getSelectColumnCommandGroup() 848 { 849 return this.selectColumnCommandGroup; 850 } 851 852 public JComponent getSelectButtonBar() 853 { 854 return this.selectColumnCommandGroup.createButtonBar(Sizes.PREFERRED, BorderFactory 855 .createEmptyBorder()); 856 } 857 858 public JComponent getButtonBar() 859 { 860 if (this.selectColumnCommandGroup != null) 861 { 862 JPanel buttons = new JPanel(new FormLayout("fill:pref, 3dlu, fill:pref, 3dlu, fill:pref", 863 "fill:pref:grow")); 864 CellConstraints cc = new CellConstraints(); 865 buttons.add(getSelectButtonBar(), cc.xy(1, 1)); 866 buttons.add(new JSeparator(SwingConstants.VERTICAL), cc.xy(3, 1)); 867 buttons.add(getNavigationButtonBar(), cc.xy(5, 1)); 868 return buttons; 869 } 870 return getNavigationButtonBar(); 871 } 872 873 public JLabel getListSummaryLabel() 874 { 875 if (countLabel == null) 876 { 877 countLabel = createCountLabel(); 878 } 879 return countLabel; 880 } 881 882 private JLabel createCountLabel() 883 { 884 final JLabel label = new JLabel(""); 885 886 setTextForListSummaryLabel(label); 887 888 shownList.addListEventListener(new ListEventListener<Object>() 889 { 890 public void listChanged(ListEvent<Object> evt) 891 { 892 if (!evt.isReordering()) 893 { 894 setTextForListSummaryLabel(label); 895 } 896 } 897 }); 898 899 theTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() 900 { 901 public void valueChanged(ListSelectionEvent e) 902 { 903 if (!e.getValueIsAdjusting()) 904 { 905 setTextForListSummaryLabel(label); 906 } 907 } 908 909 }); 910 911 return label; 912 } 913 914 private void setTextForListSummaryLabel(final JLabel label) 915 { 916 SwingUtilities.invokeLater(new Runnable() 917 { 918 public void run() 919 { 920 Integer index = 0; 921 Integer selectedCount = 0; 922 Integer totalCount = shownList.size(); 923 924 if (getSelectedRows() != null && getSelectedRows().length > 0) 925 { 926 index = shownList.indexOf(getSelectedRows()[0]); 927 index++; 928 selectedCount = getSelectedRows().length; 929 } 930 931 label.setText(RcpSupport.getMessage("glazedListTableWidget", "listSummary", "label", new Object[]{index, selectedCount, totalCount})); 932 } 933 }); 934 } 935 936 937 @Override 938 public void onAboutToShow() 939 { 940 super.onAboutToShow(); 941 this.theTable.requestFocusInWindow(); 942 } 943 944 public Set getDirtyRows() 945 { 946 return dirtyRows; 947 } 948 949 }