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 }