1 package fr.ifremer.quadrige2.ui.swing.common.table;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import com.google.common.base.Preconditions;
27 import com.google.common.collect.Sets;
28 import fr.ifremer.quadrige2.core.dao.technical.decorator.DecoratorComparator;
29 import fr.ifremer.quadrige2.core.service.ClientServiceLocator;
30 import fr.ifremer.quadrige2.core.service.decorator.DecoratorService;
31 import fr.ifremer.quadrige2.ui.swing.common.AbstractUIHandler;
32 import fr.ifremer.quadrige2.ui.swing.common.ApplicationUI;
33 import fr.ifremer.quadrige2.ui.swing.common.model.BeanMonitor;
34 import fr.ifremer.quadrige2.ui.swing.common.table.action.AbstractCellSelectionAction;
35 import fr.ifremer.quadrige2.ui.swing.common.table.action.NextCellSelectionAction;
36 import fr.ifremer.quadrige2.ui.swing.common.table.action.NextRowSelectionAction;
37 import fr.ifremer.quadrige2.ui.swing.common.table.action.PreviousCellSelectionAction;
38 import fr.ifremer.quadrige2.ui.swing.common.table.editor.DatePickerCellEditor;
39 import fr.ifremer.quadrige2.ui.swing.common.table.editor.DatePickerCellEditor2;
40 import fr.ifremer.quadrige2.ui.swing.common.table.editor.StringGenericCellEditor;
41 import fr.ifremer.quadrige2.ui.swing.common.table.renderer.DateCellRenderer;
42 import fr.ifremer.quadrige2.ui.swing.common.table.renderer.ExtendedDecoratorCellRenderer;
43 import org.apache.commons.collections4.CollectionUtils;
44 import org.apache.commons.collections4.comparators.ComparableComparator;
45 import org.apache.commons.lang3.ArrayUtils;
46 import org.apache.commons.lang3.StringUtils;
47 import org.apache.commons.logging.Log;
48 import org.apache.commons.logging.LogFactory;
49 import org.jdesktop.swingx.JXTable;
50 import org.jdesktop.swingx.table.TableColumnExt;
51 import org.nuiton.decorator.Decorator;
52
53 import javax.swing.JComponent;
54 import javax.swing.KeyStroke;
55 import javax.swing.ListSelectionModel;
56 import javax.swing.SwingUtilities;
57 import javax.swing.event.*;
58 import javax.swing.table.*;
59 import java.awt.Component;
60 import java.beans.IndexedPropertyChangeEvent;
61 import java.beans.PropertyChangeEvent;
62 import java.beans.PropertyChangeListener;
63 import java.text.Collator;
64 import java.util.Comparator;
65 import java.util.Date;
66 import java.util.List;
67 import java.util.Set;
68
69
70
71
72
73
74
75
76
77 public abstract class AbstractTableUIHandler<R extends AbstractRowUIModel<?, ?>, M extends AbstractTableUIModel<?, R, M>, UI extends ApplicationUI<M, ?>>
78 extends AbstractUIHandler<M, UI> {
79
80
81
82
83 public static final int DEFAULT_ROW_HEIGHT = 24;
84
85
86
87 protected static final int DEFAULT_MIN_COLUMN_WIDTH = 80;
88
89
90
91 private static final Log LOG = LogFactory.getLog(AbstractTableUIHandler.class);
92
93
94
95
96
97 private final BeanMonitor<R> rowMonitor;
98
99
100
101 private ListSelectionListener tableSelectionListener;
102 private ListSelectionListener tableScrollSelectionListener;
103 private TableColumnModelListener columnModelListener;
104 private RowSorterListener rowSorterListener;
105
106
107
108
109
110
111 @SuppressWarnings("unchecked")
112 protected AbstractTableUIHandler(String... properties) {
113
114 rowMonitor = new BeanMonitor<>(properties);
115
116
117 rowMonitor.addPropertyChangeListener(BeanMonitor.PROPERTY_BEAN, new PropertyChangeListener() {
118
119 final Set<String> propertiesToSkip = Sets.newHashSet(getRowPropertiesToIgnore());
120
121 final PropertyChangeListener l = new PropertyChangeListener() {
122
123 @Override
124 public void propertyChange(PropertyChangeEvent evt) {
125 String propertyName = evt.getPropertyName();
126
127 R row = (R) evt.getSource();
128
129 Object oldValue = evt.getOldValue();
130 Object newValue = evt.getNewValue();
131
132 int rowIndex = getTableModel().getRowIndex(row);
133
134 if (AbstractRowUIModel.PROPERTY_VALID.equals(propertyName)) {
135 onRowValidStateChanged(rowIndex, row,
136 (Boolean) oldValue,
137 (Boolean) newValue);
138 } else if (AbstractRowUIModel.PROPERTY_MODIFY.equals(propertyName)) {
139 onRowModifyStateChanged(rowIndex, row,
140 (Boolean) oldValue,
141 (Boolean) newValue);
142 } else if (AbstractRowUIModel.PROPERTY_SELECTED.equals(propertyName)) {
143 onRowSelectedStateChanged(rowIndex, row,
144 (Boolean) oldValue,
145 (Boolean) newValue);
146 } else if (!propertiesToSkip.contains(propertyName)) {
147 if (LOG.isDebugEnabled()) {
148 LOG.debug(
149 "row [" + rowIndex + "] property " + propertyName + " changed from " + oldValue + " to " + newValue);
150 }
151
152
153 if (oldValue != null || newValue != null) {
154 onRowModified(rowIndex, row, propertyName,
155 evt instanceof IndexedPropertyChangeEvent ? ((IndexedPropertyChangeEvent)evt).getIndex() : null,
156 oldValue, newValue);
157 }
158 }
159 }
160 };
161
162 @Override
163 public void propertyChange(PropertyChangeEvent evt) {
164 R oldValue = (R) evt.getOldValue();
165 R newValue = (R) evt.getNewValue();
166 if (LOG.isDebugEnabled()) {
167 LOG.debug("Monitor row changed from " + oldValue + " to " + newValue);
168 }
169 if (oldValue != null) {
170 oldValue.removePropertyChangeListener(l);
171 }
172 if (newValue != null) {
173 newValue.addPropertyChangeListener(l);
174 }
175 }
176 });
177 }
178
179
180
181
182
183
184
185 public abstract AbstractTableModel<R> getTableModel();
186
187
188
189
190
191
192
193 public abstract JXTable getTable();
194
195
196
197
198
199
200
201
202 protected boolean isRowValid(R row) {
203
204
205 for (ColumnIdentifier<R> identifier : getTableModel().getMandatoryIdentifiers()) {
206 Object value = identifier.getValue(row);
207 if (value == null) {
208 row.setMandatoryValid(false);
209 return false;
210 }
211 if (value instanceof String && StringUtils.isBlank((String) value)) {
212 row.setMandatoryValid(false);
213 return false;
214 }
215 }
216
217 row.setMandatoryValid(true);
218 return true;
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232 protected void onRowModified(int rowIndex, R row, String propertyName, Integer propertyIndex, Object oldValue, Object newValue) {
233 getModel().setModify(true);
234 getTable().repaint();
235 recomputeRowValidState(row);
236 }
237
238
239
240
241
242
243
244
245
246
247 protected String[] getRowPropertiesToIgnore() {
248 return ArrayUtils.EMPTY_STRING_ARRAY;
249 }
250
251
252
253
254
255
256 protected void onModelRowsChanged(List<R> rows) {
257 if (LOG.isDebugEnabled()) {
258 LOG.debug("Will set " + (rows == null ? 0 : rows.size())
259 + " rows on model.");
260 }
261 cleanRowMonitor();
262 getTableModel().setRows(rows);
263 }
264
265
266
267
268
269
270 protected void onRowsAdded(List<R> addedRows) {
271 if (LOG.isDebugEnabled()) {
272 LOG.debug((addedRows == null ? 0 : addedRows.size())
273 + " rows added on model.");
274 }
275 }
276
277
278
279
280
281
282
283
284
285 protected void onRowModifyStateChanged(int rowIndex, R row, Boolean oldValue, Boolean newValue) {
286 if (LOG.isDebugEnabled()) {
287 LOG.debug("row [" + rowIndex + "] modify state changed from "
288 + oldValue + " to " + newValue);
289 }
290 }
291
292
293
294
295
296
297
298
299
300 protected void onRowValidStateChanged(int rowIndex, R row, Boolean oldValue, Boolean newValue) {
301 if (LOG.isDebugEnabled()) {
302 LOG.debug("row [" + rowIndex + "] valid state changed from "
303 + oldValue + " to " + newValue);
304 }
305 if (rowIndex > -1) {
306 getTableModel().fireTableRowsUpdated(rowIndex, rowIndex);
307 }
308 }
309
310
311
312
313
314
315
316
317
318 protected void onRowSelectedStateChanged(int rowIndex, R row, Boolean oldValue, Boolean newValue) {
319 if (LOG.isDebugEnabled()) {
320 LOG.debug("row [" + rowIndex + "] selected state changed from "
321 + oldValue + " to " + newValue);
322 }
323 recalculateRowSelection(row);
324 }
325
326 private void recalculateRowSelection(R currentRow) {
327
328
329 getModel().populateSelectedRows();
330
331
332 if (currentRow == null) {
333 return;
334 }
335
336
337 for (TableColumn column : getTable().getColumns()) {
338 if (column instanceof CheckTableColumn) {
339 CheckTableColumn checkTableColumn = (CheckTableColumn) column;
340 boolean all = true;
341 Boolean currentSelected = currentRow.isSelected();
342 for (R row : getTableModel().getRows()) {
343 if (!currentSelected.equals(row.isSelected())) {
344 all = false;
345 break;
346 }
347 }
348 checkTableColumn.setAllEnabled(all);
349 checkTableColumn.setAllSelected(!all || currentSelected);
350
351
352 JTableHeader h = getTable().getTableHeader();
353 h.repaint(h.getHeaderRect(getTable().convertColumnIndexToView(checkTableColumn.getModelIndex())));
354 break;
355 }
356 }
357 }
358
359
360
361
362 public void selectAllValidRows() {
363 if (getModel().getRowCount() > 0) {
364 for (R row : getModel().getRows()) {
365 if (row.isValid()) {
366 row.selected = true;
367 }
368 }
369 recalculateRowSelection(getModel().getRows().get(0));
370 }
371 }
372
373
374
375
376 public void selectAllEditableRows() {
377 if (getModel().getRowCount() > 0) {
378 for (R row : getModel().getRows()) {
379 if (!row.isCalculated() && row.isEditable()) {
380 row.selected = true;
381 }
382 }
383 recalculateRowSelection(getModel().getRows().get(0));
384 }
385 }
386
387
388
389
390 public void unselectAllRows() {
391 if (getModel().getRowCount() > 0) {
392 for (R row : getModel().getRows()) {
393 row.selected = false;
394 }
395 recalculateRowSelection(getModel().getRows().get(0));
396 }
397 }
398
399
400
401
402
403
404
405
406
407
408 protected void initTable(JXTable table) {
409 initTable(table, false);
410 }
411
412
413
414
415
416
417
418 protected void initTable(JXTable table, boolean forceSingleSelection) {
419 initTable(table, forceSingleSelection, false);
420 }
421
422
423
424
425
426
427
428
429 @SuppressWarnings("unchecked")
430 protected void initTable(JXTable table, boolean singleSelection, boolean checkBoxSelection) {
431 Preconditions.checkArgument(!(singleSelection && checkBoxSelection), "Could not have both 'singleSelection' and 'checkBoxSelection' to 'true'");
432
433 if (!(table.getTableHeader() instanceof SwingTableHeader)) {
434
435 table.setTableHeader(new SwingTableHeader(getTable().getColumnModel()));
436 table.getTableHeader().setTable(table);
437 table.getTableHeader().updateUI();
438 }
439
440
441 getModel().setTableModel(getTableModel());
442
443 getTableModel().setTableUIModel(getModel());
444
445
446 table.setAutoResizeMode(JXTable.AUTO_RESIZE_OFF);
447
448 table.setRowHeight(DEFAULT_ROW_HEIGHT);
449 table.setHorizontalScrollEnabled(true);
450 table.packAll();
451
452
453 table.getTableHeader().setReorderingAllowed(true);
454
455
456 table.putClientProperty(JXTable.USE_DTCR_COLORMEMORY_HACK, Boolean.FALSE);
457 addHighlighters(table);
458
459
460 getModel().addPropertyChangeListener(AbstractTableUIModel.PROPERTY_ROWS, new PropertyChangeListener() {
461
462 @Override
463 public void propertyChange(PropertyChangeEvent evt) {
464 onModelRowsChanged((List<R>) evt.getNewValue());
465 }
466 });
467
468 getTableModel().setRows(getModel().getRows());
469
470
471 getModel().addPropertyChangeListener(AbstractTableUIModel.PROPERTY_ROWS_ADDED, new PropertyChangeListener() {
472 @Override
473 public void propertyChange(PropertyChangeEvent evt) {
474 onRowsAdded((List<R>) evt.getNewValue());
475 }
476 });
477
478
479
480
481
482 uninstallSortController();
483
484 if (singleSelection) {
485
486 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
487
488 } else {
489
490
491 if (checkBoxSelection) {
492
493
494 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
495
496
497 CheckTableColumn<R, M> selectCol = new CheckTableColumn<>(table, getModel());
498 table.getColumnModel().addColumn(selectCol);
499 getTableModel().addCheckTableColumnIdentifier(selectCol.getIdentifier());
500
501 } else {
502
503
504 getTable().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
505 }
506 }
507
508
509 installSortController();
510
511
512
513
514
515 uninstallTableSelectionListener();
516
517
518 installTableSelectionListener();
519
520
521 table.setColumnControlVisible(true);
522 table.setColumnControl(new ColumnControlButton(table));
523
524
525
526
527
528 table.setDefaultEditor(String.class, new StringGenericCellEditor());
529
530
531 overrideTabKeyActions(table);
532
533 }
534
535 private void overrideTabKeyActions(JXTable table) {
536
537 overrideKeyAction(table, "pressed TAB", AbstractCellSelectionAction.Direction.NEXT_CELL);
538 overrideKeyAction(table, "shift pressed TAB", AbstractCellSelectionAction.Direction.PREVIOUS_CELL);
539 overrideKeyAction(table, "pressed RIGHT", AbstractCellSelectionAction.Direction.NEXT_CELL);
540 overrideKeyAction(table, "pressed LEFT", AbstractCellSelectionAction.Direction.PREVIOUS_CELL);
541 overrideKeyAction(table, "pressed DOWN", AbstractCellSelectionAction.Direction.NEXT_ROW);
542 overrideKeyAction(table, "pressed ENTER", AbstractCellSelectionAction.Direction.NEXT_ROW);
543
544 }
545
546 private void overrideKeyAction(JXTable table, String key, AbstractCellSelectionAction.Direction direction) {
547
548 String actionName = "actionFor" + StringUtils.deleteWhitespace(StringUtils.capitalize(key));
549
550
551 AbstractCellSelectionAction action = null;
552 switch (direction) {
553
554 case NEXT_CELL:
555 action = new NextCellSelectionAction(actionName, this);
556 break;
557 case PREVIOUS_CELL:
558 action = new PreviousCellSelectionAction(actionName, this);
559 break;
560 case NEXT_ROW:
561 action = new NextRowSelectionAction(actionName, this);
562 break;
563 case PREVIOUS_ROW:
564 break;
565 }
566
567 if (action == null) {
568 return;
569 }
570
571
572 table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(key), actionName);
573
574
575 table.getActionMap().put(actionName, action);
576
577 }
578
579
580
581
582 protected void installTableSelectionListener() {
583
584 Preconditions.checkState(
585 tableSelectionListener == null,
586 "There is already a tableSelectionListener registered, remove it before invoking this method.");
587
588
589 tableSelectionListener = new ListSelectionListener() {
590
591 int lastMinIndex = -1;
592 int lastMaxIndex = -1;
593
594 @Override
595 public void valueChanged(ListSelectionEvent e) {
596
597 ListSelectionModel source = (ListSelectionModel) e.getSource();
598
599 if (LOG.isDebugEnabled()) {
600 LOG.debug("Selection changed: " + e);
601 }
602
603
604
605
606
607
608 int minIndex = source.getMinSelectionIndex();
609 int maxIndex = source.getMaxSelectionIndex();
610
611 if (source.isSelectionEmpty()) {
612 minIndex = -1;
613 maxIndex = -1;
614 }
615 if (minIndex == lastMinIndex && maxIndex == lastMaxIndex) {
616 return;
617 }
618 lastMinIndex = minIndex;
619 lastMaxIndex = maxIndex;
620
621
622
623 rowMonitor.setBean(null);
624
625
626 if (!getTableModel().hasCheckTableColumn()) {
627
628 for (R row : getModel().getSelectedRows()) {
629 row.setSelected(false);
630 }
631
632
633 for (int index = minIndex; index <= maxIndex; index++) {
634 if (source.isSelectedIndex(index)) {
635 int modelIndex = getTable().convertRowIndexToModel(index);
636 R row = getTableModel().getEntry(modelIndex);
637 row.setSelected(true);
638 }
639 }
640
641 }
642
643 R newRow;
644
645
646 if (source.isSelectionEmpty() || source.getLeadSelectionIndex() < 0 || source.getLeadSelectionIndex() >= getTable().getRowCount()) {
647 newRow = null;
648 } else {
649 int rowIndex = source.getLeadSelectionIndex();
650 int modelIndex = getTable().convertRowIndexToModel(rowIndex);
651 newRow = getTableModel().getEntry(modelIndex);
652 if (LOG.isDebugEnabled()) {
653 LOG.debug("Will monitor entry: " + rowIndex);
654 }
655 }
656
657 rowMonitor.setBean(newRow);
658 getModel().setSingleSelectedRow(newRow);
659
660
661 if (newRow != null && source.getMinSelectionIndex() == source.getMaxSelectionIndex()) {
662 selectRow(newRow);
663 }
664
665
666 recalculateRowSelection(newRow);
667
668 }
669 };
670
671 if (LOG.isDebugEnabled()) {
672 LOG.debug("Install " + tableSelectionListener + " on tableModel " + getTableModel());
673 }
674
675 getTable().getSelectionModel().addListSelectionListener(tableSelectionListener);
676 }
677
678
679
680
681 protected void uninstallTableSelectionListener() {
682
683 if (tableSelectionListener != null) {
684
685 if (LOG.isDebugEnabled()) {
686 LOG.debug("Uninstall " + tableSelectionListener);
687 }
688
689
690 getTable().getSelectionModel().removeListSelectionListener(tableSelectionListener);
691 tableSelectionListener = null;
692 }
693 }
694
695
696
697
698 protected void installTableScrollSelectionListener() {
699 Preconditions.checkState(
700 tableScrollSelectionListener == null,
701 "There is already a tableScrollSelectionListener registered, remove it before invoking this method.");
702
703 tableScrollSelectionListener = new ListSelectionListener() {
704
705 @Override
706 public void valueChanged(ListSelectionEvent e) {
707 if (!e.getValueIsAdjusting()) {
708 int colIndex = getTable().getSelectedColumn();
709 int rowIndex = getTable().getSelectedRow();
710 if (rowIndex > -1 && colIndex > -1) {
711 getTable().scrollCellToVisible(rowIndex, colIndex);
712 }
713 }
714 }
715 };
716
717 getTable().getSelectionModel().addListSelectionListener(tableScrollSelectionListener);
718 getTable().getColumnModel().getSelectionModel().addListSelectionListener(tableScrollSelectionListener);
719 }
720
721
722
723
724 protected void uninstallTableScrollSelectionListener() {
725 if (tableScrollSelectionListener != null) {
726
727 if (LOG.isDebugEnabled()) {
728 LOG.debug("Uninstall " + tableScrollSelectionListener);
729 }
730
731
732 getTable().getSelectionModel().removeListSelectionListener(tableScrollSelectionListener);
733 getTable().getColumnModel().getSelectionModel().removeListSelectionListener(tableScrollSelectionListener);
734 tableScrollSelectionListener = null;
735 }
736 }
737
738
739 protected void installSaveTableStateListener() {
740 Preconditions.checkState(
741 columnModelListener == null,
742 "There is already a columnModelListener registered, remove it before invoking this method.");
743 Preconditions.checkState(
744 rowSorterListener == null,
745 "There is already a rowSorterListener registered, remove it before invoking this method.");
746
747 columnModelListener = new TableColumnModelListener() {
748 @Override
749 public void columnAdded(TableColumnModelEvent event) {
750 if (!getModel().isLoading()) {
751 if (LOG.isDebugEnabled()) LOG.debug(event);
752 saveTableInSwingSession();
753 }
754 }
755
756 @Override
757 public void columnRemoved(TableColumnModelEvent event) {
758 if (!getModel().isLoading()) {
759 if (LOG.isDebugEnabled()) LOG.debug(event);
760 saveTableInSwingSession();
761 }
762 }
763
764 @Override
765 public void columnMoved(TableColumnModelEvent event) {
766 if (!getModel().isLoading() && event.getFromIndex() != event.getToIndex()) {
767 if (LOG.isDebugEnabled()) LOG.debug(event);
768 saveTableInSwingSession();
769 }
770 }
771
772 @Override
773 public void columnMarginChanged(ChangeEvent event) {
774 if (!getModel().isLoading()) {
775 if (LOG.isDebugEnabled()) LOG.debug(event);
776 saveTableInSwingSession();
777 }
778 }
779
780 @Override
781 public void columnSelectionChanged(ListSelectionEvent event) {
782 }
783 };
784
785 getTable().getColumnModel().addColumnModelListener(columnModelListener);
786
787
788 if (getTable().getRowSorter() != null) {
789 rowSorterListener = new RowSorterListener() {
790 @Override
791 public void sorterChanged(RowSorterEvent event) {
792 if (!getModel().isLoading() && event.getType().equals(RowSorterEvent.Type.SORT_ORDER_CHANGED)) {
793 if (LOG.isDebugEnabled()) LOG.debug(event);
794 saveTableInSwingSession();
795 }
796 }
797 };
798
799 getTable().getRowSorter().addRowSorterListener(rowSorterListener);
800 }
801 }
802
803 protected void saveTableInSwingSession() {
804 getContext().saveComponentInSwingSession(getTable(), getTableModel().getStateContext());
805 }
806
807 protected void uninstallSaveTableStateListener() {
808 if (columnModelListener != null) {
809 getTable().getColumnModel().removeColumnModelListener(columnModelListener);
810 columnModelListener = null;
811 }
812 if (rowSorterListener != null) {
813 if (getTable().getRowSorter() != null) {
814 getTable().getRowSorter().removeRowSorterListener(rowSorterListener);
815 }
816 rowSorterListener = null;
817 }
818 }
819
820
821
822
823 protected void cleanRowMonitor() {
824 rowMonitor.clearModified();
825 }
826
827
828
829
830
831
832 public final void recomputeRowValidState(R row) {
833
834
835 boolean valid = isRowValid(row);
836
837
838 row.setValid(valid);
839
840 if (valid) {
841 getModel().removeRowInError(row);
842 } else {
843 getModel().addRowInError(row);
844 }
845
846 }
847
848
849
850
851 public void recomputeRowsValidState() {
852 recomputeRowsValidState(true);
853 }
854
855
856
857
858
859
860 public void recomputeRowsValidState(boolean validIfNoRow) {
861 List<R> rows = getModel().getRows();
862 if (LOG.isDebugEnabled()) {
863 LOG.debug("Will valid " + (rows == null ? 0 : rows.size())
864 + " rows on model.");
865 }
866
867 if (CollectionUtils.isNotEmpty(rows)) {
868
869
870 Set<R> invalidRows = Sets.newHashSet();
871 for (R row : rows) {
872
873
874 row.setValid(isRowValid(row));
875
876
877 if (!row.isValid()) {
878 invalidRows.add(row);
879 }
880 }
881
882
883 getModel().setRowsInError(invalidRows);
884
885 } else {
886 getModel().setValid(validIfNoRow);
887 }
888
889 }
890
891
892
893
894 public void stopCellEditing() {
895
896 if (getTable().isEditing()) {
897 getTable().getCellEditor().stopCellEditing();
898 }
899 }
900
901
902
903
904
905
906
907
908 protected TableColumnExt addDatePickerColumnToModel(TableColumnModel model, ColumnIdentifier<R> identifier, String dateFormat) {
909 return addDatePickerColumnToModel(model, identifier, dateFormat, true);
910 }
911
912
913
914
915
916
917
918
919
920 protected TableColumnExt addDatePickerColumnToModel(TableColumnModel model, ColumnIdentifier<R> identifier, String dateFormat, boolean isEditable) {
921 return addColumnToModel(
922 model,
923 isEditable ? newDateCellEditor(dateFormat) : null,
924 newDateCellRenderer(dateFormat),
925 identifier);
926 }
927
928
929
930
931
932
933
934 protected TableCellEditor newDateCellEditor(String pattern) {
935 return new DatePickerCellEditor(pattern);
936 }
937
938
939
940
941
942
943
944 protected TableCellEditor newDateCellEditor2(String pattern) {
945 return new DatePickerCellEditor2(pattern);
946 }
947
948
949
950
951
952
953
954 protected TableCellRenderer newDateCellRenderer(String pattern) {
955 return new DateCellRenderer(getTable().getDefaultRenderer(Date.class), pattern);
956 }
957
958
959
960
961
962
963
964 protected TableCellRenderer newTableCellRender(ColumnIdentifier<?> identifier) {
965 return newTableCellRender(identifier.getPropertyType(), identifier.getDecoratorName());
966 }
967
968
969
970
971 @Override
972 protected <O> TableCellRenderer newTableCellRender(Class<O> type, String name) {
973 Decorator<O> decorator = getDecorator(type, name);
974 return new ExtendedDecoratorCellRenderer(decorator);
975 }
976
977 protected <O> TableCellRenderer newTableCellRender(Class<O> type, String context, String tooltipContext) {
978 Decorator<O> decorator = getDecorator(type, context);
979 Decorator<O> tooltipDecorator = getDecorator(type, tooltipContext);
980 return new ExtendedDecoratorCellRenderer(decorator, tooltipDecorator);
981 }
982
983
984
985
986 @Override
987 protected <O> TableCellRenderer newTableCellRender(Class<O> type) {
988 return this.newTableCellRender(type, null);
989 }
990
991
992
993
994
995
996
997 protected void fixColumnWidth(TableColumn column, int width) {
998 column.setMinWidth(width);
999 column.setMaxWidth(width);
1000 }
1001
1002
1003
1004
1005
1006
1007 public void selectRow(R row) {
1008 int rowViewIndex = getRowViewIndex(row);
1009 if (rowViewIndex == -1) {
1010 return;
1011 }
1012 if (getTable().getSelectionMode() != ListSelectionModel.SINGLE_SELECTION) {
1013 row.setSelected(true);
1014 }
1015 selectCell(rowViewIndex, null);
1016 }
1017
1018
1019
1020
1021
1022
1023 public void selectRows(List<R> rows) {
1024
1025 for (R row : rows) {
1026 int rowViewIndex = getRowViewIndex(row);
1027 if (rowViewIndex != -1) {
1028 row.setSelected(true);
1029 getTable().addRowSelectionInterval(rowViewIndex, rowViewIndex);
1030
1031 if (rows.indexOf(row) == rows.size() - 1) {
1032 getTable().scrollCellToVisible(rowViewIndex, 0);
1033 recalculateRowSelection(row);
1034 }
1035 }
1036 }
1037
1038 }
1039
1040
1041
1042
1043
1044
1045 public void setFocusOnCell(final R row) {
1046
1047
1048 getModel().setSingleSelectedRow(row);
1049 recomputeRowValidState(row);
1050
1051 SwingUtilities.invokeLater(new Runnable() {
1052 @Override
1053 public void run() {
1054
1055
1056 int rowViewIndex = getRowViewIndex(row);
1057 if (rowViewIndex == -1) {
1058 return;
1059 }
1060
1061
1062 final ColumnIdentifier<?> columnIdentifier = getTableModel().getFirstColumnEditing();
1063 if (columnIdentifier != null) {
1064 int indexColonne = getTable().getColumnExt(columnIdentifier).getModelIndex();
1065 int columnViewIndex = getTable().convertColumnIndexToView(indexColonne);
1066
1067 while (columnViewIndex < getTable().getColumnCount(false) && !getTable().isCellEditable(rowViewIndex, columnViewIndex)) {
1068 columnViewIndex++;
1069 }
1070
1071
1072 if (columnViewIndex >= getTable().getColumnCount(false)) {
1073 return;
1074 }
1075
1076
1077 selectCell(rowViewIndex, columnViewIndex);
1078
1079
1080 getTable().editCellAt(rowViewIndex, columnViewIndex);
1081 }
1082 }
1083 });
1084 }
1085
1086
1087
1088
1089
1090
1091
1092 public void selectCell(Integer rowIndex, Integer colIndex) {
1093
1094 int row = rowIndex != null ? rowIndex : getTable().getSelectedRow();
1095 row = row != -1 ? row : 0;
1096 int col = colIndex != null ? colIndex : getTable().getSelectedColumn();
1097 col = col != -1 ? col : 0;
1098
1099 if (row >= 0) {
1100 getTable().setRowSelectionInterval(row, row);
1101 }
1102 if (col >= 0) {
1103 getTable().setColumnSelectionInterval(col, col);
1104 }
1105 getTable().scrollCellToVisible(row, col);
1106 }
1107
1108
1109
1110
1111
1112
1113
1114 private int getRowViewIndex(R row) {
1115 if (row == null) {
1116 return -1;
1117 }
1118 int rowIndex = getTableModel().getRowIndex(row);
1119 if (rowIndex == -1) {
1120 return -1;
1121 }
1122 return getTable().convertRowIndexToView(rowIndex);
1123 }
1124
1125
1126
1127
1128
1129
1130 protected SwingTableColumnModel newTableColumnModel() {
1131 return new SwingTableColumnModel();
1132 }
1133
1134
1135
1136
1137
1138
1139 protected void uninstallSortController() {
1140
1141
1142 getTable().setAutoCreateRowSorter(false);
1143
1144
1145 getTable().setRowSorter(null);
1146 }
1147
1148
1149
1150
1151 @SuppressWarnings("unchecked")
1152 protected void installSortController() {
1153
1154
1155 uninstallSortController();
1156
1157 SwingTableSortController controller = new SwingTableSortController(getTableModel());
1158
1159 getTable().setRowSorter(controller);
1160
1161
1162 DecoratorService decoratorService = ClientServiceLocator.instance().getDecoratorService();
1163 for (int i = 0; i < getTable().getColumnModel().getColumnCount(); i++) {
1164
1165 Comparator comparator = null;
1166 TableColumnExt column = getTable().getColumnExt(i);
1167
1168 if (!column.isSortable()) {
1169 controller.setSortable(column.getModelIndex(), false);
1170 continue;
1171 }
1172
1173 ColumnIdentifier identifier = (ColumnIdentifier) column.getIdentifier();
1174
1175 if (decoratorService != null) {
1176 Decorator decorator = decoratorService.getDecoratorByType(identifier.getPropertyType(), identifier.getDecoratorName());
1177 if (decorator != null) {
1178
1179 comparator = new DecoratorComparator(decorator);
1180 }
1181 }
1182
1183 if (comparator == null) {
1184 Class<?> columnClass = identifier.getPropertyType();
1185 if (columnClass == String.class) {
1186
1187 comparator = Collator.getInstance();
1188 } else if (Comparable.class.isAssignableFrom(columnClass)) {
1189
1190 comparator = new ComparableComparator();
1191 }
1192 }
1193
1194
1195 controller.setComparator(column.getModelIndex(), comparator);
1196 }
1197 }
1198
1199
1200
1201
1202
1203
1204 public Component getNextComponentToFocus() {
1205 return null;
1206 }
1207
1208
1209
1210
1211
1212
1213 public Component getPreviousComponentToFocus() {
1214 return null;
1215 }
1216 }