1 package fr.ifremer.quadrige3.ui.swing.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 fr.ifremer.quadrige3.core.dao.technical.Assert;
27 import fr.ifremer.quadrige3.ui.swing.model.AbstractBeanUIModel;
28 import org.apache.commons.collections4.CollectionUtils;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32 import java.util.*;
33 import java.util.stream.Collectors;
34
35
36
37
38
39
40
41
42
43 public abstract class AbstractTableUIModel<B, R extends AbstractRowUIModel, M extends AbstractTableUIModel<B, R, M>>
44 extends AbstractBeanUIModel<B, M> {
45
46 private static final long serialVersionUID = 1L;
47
48 private static final Log LOG = LogFactory.getLog(AbstractTableUIModel.class);
49
50
51
52
53 public static final String PROPERTY_ROWS = "rows";
54
55
56
57
58 public static final String PROPERTY_BEANS_LOADED = "rowsLoaded";
59
60
61
62
63 public static final String PROPERTY_SINGLE_ROW_SELECTED = "singleSelectedRow";
64
65
66
67
68 public static final String PROPERTY_SELECTED_ROWS = "selectedRows";
69
70
71
72
73 public static final String PROPERTY_ROWS_IN_ERROR = "rowsInError";
74
75
76
77
78 public static final String PROPERTY_ROWS_ADDED = "rowsAdded";
79
80
81
82
83 public static final String PROPERTY_ROWS_DELETED = "rowsDeleted";
84
85 private List<R> rows;
86
87 private R singleSelectedRow;
88
89 private Set<R> selectedRows;
90
91 private Set<R> rowsInError;
92
93 private AbstractTableModel tableModel;
94
95
96
97
98 protected AbstractTableUIModel() {
99 super(null, null);
100
101 rows = new ArrayList<>();
102 selectedRows = new HashSet<>();
103 rowsInError = new HashSet<>();
104 setValid(true);
105
106 addPropertyChangeListener(PROPERTY_ROWS_IN_ERROR, evt -> {
107 if (LOG.isDebugEnabled()) {
108 LOG.debug(PROPERTY_ROWS_IN_ERROR + " changed " + rowsInError.size());
109 }
110 setValid(hasNoRowInError());
111 });
112 }
113
114
115
116
117
118
119 public AbstractTableUIModel getInstance() {
120 return this;
121 }
122
123
124
125
126
127
128 @SuppressWarnings("EmptyMethod")
129 public void setInstance(AbstractTableUIModel model) {
130
131 }
132
133
134
135
136
137
138 public AbstractTableModel getTableModel() {
139 return tableModel;
140 }
141
142
143
144
145
146
147 public void setTableModel(AbstractTableModel tableModel) {
148 this.tableModel = tableModel;
149 }
150
151
152
153
154
155
156 @Override
157 protected final B newBean() {
158 return null;
159 }
160
161
162
163
164
165
166 public List<R> getRows() {
167 return rows;
168 }
169
170
171
172
173
174
175 public void setRows(List<R> rows) {
176 this.rows = new ArrayList<>();
177 if (rows != null) {
178 this.rows.addAll(rows);
179 }
180 onRowsChanged();
181 }
182
183
184
185
186
187
188 public void addRow(R row) {
189 addRows(Collections.singletonList(row));
190 }
191
192
193
194
195
196
197 public void addRows(List<R> rows) {
198 if (CollectionUtils.isEmpty(rows)) {
199 return;
200 }
201 this.rows.addAll(rows);
202 firePropertyChange(PROPERTY_ROWS_ADDED, null, rows);
203 onRowsChanged();
204 }
205
206
207
208
209
210
211 public void insertRowAfterSelected(R row) {
212 if (row == null) {
213 return;
214 }
215 if (singleSelectedRow == null || rows.indexOf(singleSelectedRow) + 1 >= rows.size()) {
216 addRow(row);
217 } else {
218 rows.add(rows.indexOf(singleSelectedRow) + 1, row);
219 firePropertyChange(PROPERTY_ROWS_ADDED, null, Collections.singletonList(row));
220 onRowsChanged();
221 }
222
223 }
224
225 private void onRowsChanged() {
226 setRowsInError(rows.stream().filter(row -> !row.isValid()).collect(Collectors.toSet()));
227
228
229 firePropertyChange(PROPERTY_ROWS, null, rows);
230
231 populateSelectedRows();
232 }
233
234
235
236
237 @Override
238 public void setBean(B bean) {
239 setBeans(Collections.singletonList(bean));
240 }
241
242
243
244
245
246
247 public void setBeans(Collection<B> beans) {
248 setBeans(beans, null);
249 }
250
251
252
253
254
255
256
257 public void setBeans(Collection<B> beans, Boolean calculated) {
258 setRows(convertBeans(beans, calculated));
259 firePropertyChange(PROPERTY_BEANS_LOADED, null, rows);
260 }
261
262
263
264
265
266
267 public void addBean(B bean) {
268 addBeans(Collections.singletonList(bean));
269 }
270
271
272
273
274
275
276
277 public void addBean(B bean, Boolean calculated) {
278 addBeans(Collections.singletonList(bean), calculated);
279 }
280
281
282
283
284
285
286 public void addBeans(List<B> beans) {
287 addBeans(beans, null);
288 }
289
290
291
292
293
294
295
296 public void addBeans(List<B> beans, Boolean calculated) {
297 addRows(convertBeans(beans, calculated));
298 }
299
300
301
302
303
304
305 public R addNewRow() {
306 return addNewRow(null);
307 }
308
309
310
311
312
313
314
315 public R addNewRow(B bean) {
316 R row = convertBean(bean, null);
317 addRow(row);
318 return row;
319 }
320
321
322
323
324
325
326 public R insertNewRowAfterSelected() {
327 R row = convertBean(null, null);
328 insertRowAfterSelected(row);
329 return row;
330 }
331
332 private List<R> convertBeans(Collection<B> beans, Boolean calculated) {
333
334 return CollectionUtils.isNotEmpty(beans)
335 ? beans.stream().map(b -> convertBean(b, calculated)).filter(Objects::nonNull).collect(Collectors.toList())
336 : new ArrayList<>();
337 }
338
339 @SuppressWarnings("unchecked")
340 private R convertBean(B bean, Boolean calculated) {
341 R row = null;
342 if (getTableModel() != null) {
343 row = (R) getTableModel().createNewRow();
344 }
345 if (row != null) {
346 if (bean != null) {
347 row.fromBean(bean);
348 row.setValid(true);
349 } else {
350 row.setValid(false);
351 }
352 if (calculated != null) {
353 row.setCalculated(calculated);
354 }
355 } else {
356 if (LOG.isWarnEnabled()) {
357 LOG.warn("convertBean can't create a new row! check the underlying table model and its createNewRow method");
358 }
359 }
360 return row;
361 }
362
363
364
365
366
367
368 public List<B> getBeans() {
369
370 return rows.stream().map(this::convertRow).collect(Collectors.toList());
371
372 }
373
374 @SuppressWarnings("unchecked")
375 private B convertRow(R row) {
376 return (B) row.toBean();
377 }
378
379
380
381
382
383
384 public int getRowCount() {
385 return rows.size();
386 }
387
388
389
390
391
392
393 public Set<R> getRowsInError() {
394 return rowsInError;
395 }
396
397
398
399
400
401
402 public final void setRowsInError(Set<R> rowsInError) {
403 this.rowsInError = rowsInError != null ? rowsInError : new HashSet<>();
404 firePropertyChange(PROPERTY_ROWS_IN_ERROR, null, null);
405 }
406
407
408
409
410
411
412 public void addRowInError(R row) {
413 rowsInError.add(row);
414 firePropertyChange(PROPERTY_ROWS_IN_ERROR, null, null);
415 }
416
417
418
419
420
421
422 public void removeRowInError(R row) {
423 rowsInError.remove(row);
424 firePropertyChange(PROPERTY_ROWS_IN_ERROR, null, null);
425 }
426
427
428
429
430
431
432 public boolean hasNoRowInError() {
433 return CollectionUtils.isEmpty(rowsInError);
434 }
435
436
437
438
439
440
441 public boolean hasAllRowMandatoryValid() {
442 return rows.stream().allMatch(AbstractRowUIModel::isMandatoryValid);
443 }
444
445
446
447
448
449
450 public Set<R> getSelectedRows() {
451 return selectedRows;
452 }
453
454
455
456
457
458
459 public List<B> getSelectedBeans() {
460 return selectedRows.stream().map(this::convertRow).collect(Collectors.toList());
461 }
462
463
464
465
466 public void populateSelectedRows() {
467 int previousHashCode = selectedRows.hashCode();
468 selectedRows = rows.stream().filter(AbstractRowUIModel::isSelected).collect(Collectors.toSet());
469 if (previousHashCode != selectedRows.hashCode()) {
470 firePropertyChange(PROPERTY_SELECTED_ROWS, null, selectedRows);
471 }
472 }
473
474
475
476
477
478
479 public void deleteRow(R rowToDelete) {
480 deleteRows(Collections.singletonList(rowToDelete));
481 }
482
483
484
485
486 public void deleteSelectedRows() {
487 deleteRows(selectedRows);
488 }
489
490
491
492
493
494
495 public void deleteRows(Collection<R> rowsToDelete) {
496 if (!rows.isEmpty() && rowsToDelete != null) {
497 Set<R> rowSet = rowsToDelete.stream().filter(Objects::nonNull).collect(Collectors.toSet());
498 rows.removeAll(rowSet);
499 firePropertyChange(PROPERTY_ROWS_DELETED, null, rowSet);
500 onRowsChanged();
501 }
502 }
503
504
505
506
507
508
509
510 @SuppressWarnings("unchecked")
511 public void updateBean(R oldRow, B newRowBean) {
512 Assert.notNull(oldRow);
513 Assert.state(rows.contains(oldRow), "the row to update should exists in actual rows");
514 Assert.notNull(newRowBean);
515
516 oldRow.fromBean(newRowBean);
517 }
518
519
520
521
522
523
524 public R getSingleSelectedRow() {
525 return singleSelectedRow;
526 }
527
528
529
530
531
532
533 public void setSingleSelectedRow(R singleSelectedRow) {
534 R oldValue = getSingleSelectedRow();
535 this.singleSelectedRow = singleSelectedRow;
536 firePropertyChange(PROPERTY_SINGLE_ROW_SELECTED, oldValue, singleSelectedRow);
537 }
538
539 }