1 package fr.ifremer.tutti.ui.swing.content.protocol.calcifiedpiecessampling;
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
27 import fr.ifremer.tutti.persistence.entities.referential.Caracteristic;
28 import fr.ifremer.tutti.persistence.entities.referential.Species;
29 import fr.ifremer.tutti.service.DecoratorService;
30 import fr.ifremer.tutti.ui.swing.content.protocol.EditProtocolSpeciesRowModel;
31 import fr.ifremer.tutti.ui.swing.content.protocol.EditProtocolUIModel;
32 import fr.ifremer.tutti.ui.swing.util.AbstractTuttiBeanUIModel;
33 import fr.ifremer.tutti.ui.swing.util.AbstractTuttiUIHandler;
34 import fr.ifremer.tutti.ui.swing.util.TuttiUI;
35 import fr.ifremer.tutti.ui.swing.util.TuttiUIUtil;
36 import jaxx.runtime.SwingUtil;
37 import jaxx.runtime.swing.JAXXWidgetUtil;
38 import jaxx.runtime.swing.editor.cell.NumberCellEditor;
39 import jaxx.runtime.validator.swing.SwingValidator;
40 import org.jdesktop.swingx.JXTable;
41 import org.jdesktop.swingx.decorator.FontHighlighter;
42 import org.jdesktop.swingx.decorator.HighlightPredicate;
43 import org.jdesktop.swingx.decorator.Highlighter;
44 import org.jdesktop.swingx.table.DefaultTableColumnModelExt;
45 import org.jdesktop.swingx.table.TableColumnExt;
46
47 import javax.swing.JComponent;
48 import javax.swing.JLabel;
49 import javax.swing.JMenuItem;
50 import javax.swing.SwingConstants;
51 import javax.swing.border.LineBorder;
52 import javax.swing.event.CellEditorListener;
53 import javax.swing.event.ChangeEvent;
54 import javax.swing.table.JTableHeader;
55 import javax.swing.table.TableCellRenderer;
56 import java.awt.Color;
57 import java.awt.Component;
58 import java.awt.Font;
59 import java.beans.PropertyChangeEvent;
60 import java.beans.PropertyChangeListener;
61 import java.util.ArrayList;
62 import java.util.List;
63 import java.util.Optional;
64 import java.util.TreeSet;
65 import java.util.stream.Collectors;
66
67 import static org.nuiton.i18n.I18n.t;
68
69
70
71
72
73 public class CalcifiedPiecesSamplingEditorUIHandler extends AbstractTuttiUIHandler<EditProtocolUIModel, CalcifiedPiecesSamplingEditorUI> {
74
75 protected Caracteristic sexCaracteristic;
76
77 protected final PropertyChangeListener rowChangeListener = new PropertyChangeListener() {
78
79 @Override
80 public void propertyChange(PropertyChangeEvent evt) {
81 getModel().setModify(true);
82
83 String propertyName = evt.getPropertyName();
84 CalcifiedPiecesSamplingEditorRowModel row = (CalcifiedPiecesSamplingEditorRowModel) evt.getSource();
85
86 if (CalcifiedPiecesSamplingEditorRowModel.PROPERTY_MIN_SIZE.equals(propertyName)) {
87
88 List<CalcifiedPiecesSamplingEditorRowModel> cpsRows = getModel().getCpsRows();
89
90 int newRowIndex = cpsRows.indexOf(row);
91 int previousRowIndex = newRowIndex - 1;
92 CalcifiedPiecesSamplingEditorRowModel previousRow = cpsRows.get(previousRowIndex);
93
94 Integer newValue = (Integer) evt.getNewValue();
95
96 if (newValue == null) {
97 row.setMinSize(0);
98
99 } else if (newValue <= previousRow.getMinSize() + 1
100 || row.getMaxSize() != null && newValue >= row.getMaxSize()) {
101
102 row.setMinSize((Integer) evt.getOldValue());
103
104 } else {
105 previousRow.setMaxSize(newValue - 1);
106 CalcifiedPiecesSamplingEditorTableModel model =
107 (CalcifiedPiecesSamplingEditorTableModel) getUI().getCpsTable().getModel();
108 model.fireTableRowsUpdated(previousRowIndex, newRowIndex);
109 }
110
111 } else if (CalcifiedPiecesSamplingEditorRowModel.PROPERTY_SAMPLING_INTERVAL.equals(propertyName)) {
112 if (evt.getNewValue() == null) {
113 row.setSamplingInterval(0);
114 }
115 }
116 }
117 };
118
119 @Override
120 public void beforeInit(CalcifiedPiecesSamplingEditorUI ui) {
121 super.beforeInit(ui);
122 sexCaracteristic = getPersistenceService().getSexCaracteristic();
123 }
124
125 @Override
126 public void afterInit(CalcifiedPiecesSamplingEditorUI calcifiedPiecesSamplingEditorUI) {
127 initUI(calcifiedPiecesSamplingEditorUI);
128
129 initBeanFilterableComboBox(ui.getSpeciesComboBox(), new ArrayList<>(), null, DecoratorService.WITH_SURVEY_CODE);
130
131 ui.getSpeciesComboBox().getComboBoxModel().addWillChangeSelectedItemListener(evt -> {
132 Species species = (Species) evt.getNextSelectedItem();
133 if (species != null) {
134 Optional<EditProtocolSpeciesRowModel> protocolSpecies = getModel().getProtocolSpeciesRowForSpecies(species);
135 if (protocolSpecies.isPresent()) {
136 getUI().getMaturityCheckBox().setSelected(protocolSpecies.get().getMaturityPmfm() != null);
137 }
138 }
139 });
140
141 JXTable cpsTable = ui.getCpsTable();
142
143 DefaultTableColumnModelExt columnModel = initTableColumnModel();
144
145 final CalcifiedPiecesSamplingEditorTableModel tableModel =
146 new CalcifiedPiecesSamplingEditorTableModel(columnModel);
147 cpsTable.setModel(tableModel);
148 cpsTable.setColumnModel(columnModel);
149
150
151 tableModel.addTableModelListener(e -> getModel().setModify(true));
152
153 JTableHeader tableHeader = cpsTable.getTableHeader();
154
155
156 tableHeader.setReorderingAllowed(false);
157
158
159 SwingUtil.scrollToTableSelection(cpsTable);
160
161 addHighlighters(cpsTable);
162
163
164 getModel().addPropertyChangeListener(EditProtocolUIModel.PROPERTY_CPS_ROWS,
165 evt -> {
166 List<CalcifiedPiecesSamplingEditorRowModel> rows =
167 (List<CalcifiedPiecesSamplingEditorRowModel>) evt.getNewValue();
168 for (CalcifiedPiecesSamplingEditorRowModel row : rows) {
169 row.removePropertyChangeListener(rowChangeListener);
170 row.addPropertyChangeListener(rowChangeListener);
171 }
172 tableModel.setRows(rows);
173 tableModel.fireTableDataChanged();
174
175 getUI().getSpeciesComboBox().removeItems(rows.stream()
176 .map(CalcifiedPiecesSamplingEditorRowModel::getProtocolSpecies)
177 .map(EditProtocolSpeciesRowModel::getSpecies)
178 .collect(Collectors.toList()));
179 });
180
181 }
182
183 @Override
184 protected void addHighlighters(JXTable cpsTable) {
185 CalcifiedPiecesSamplingEditorTableModel tableModel = (CalcifiedPiecesSamplingEditorTableModel) cpsTable.getModel();
186
187 HighlightPredicate notSelectedPredicate = new HighlightPredicate.NotHighlightPredicate(HighlightPredicate.IS_SELECTED);
188 HighlightPredicate rowIsInvalidPredicate = (renderer, adapter) -> {
189
190 boolean result = false;
191 if (adapter.isEditable()) {
192
193 int viewRow = adapter.row;
194 int modelRow = adapter.convertRowIndexToModel(viewRow);
195 AbstractTuttiBeanUIModel row = tableModel.getEntry(modelRow);
196 result = !row.isValid();
197 }
198 return result;
199 };
200 HighlightPredicate rowIsValidPredicate =
201 new HighlightPredicate.NotHighlightPredicate(rowIsInvalidPredicate);
202 Highlighter selectedHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
203 HighlightPredicate.IS_SELECTED,
204 getConfig().getColorSelectedRow());
205 cpsTable.addHighlighter(selectedHighlighter);
206
207
208 Highlighter readOnlyHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
209 new HighlightPredicate.AndHighlightPredicate(
210 HighlightPredicate.READ_ONLY,
211 notSelectedPredicate),
212 getConfig().getColorRowReadOnly());
213 cpsTable.addHighlighter(readOnlyHighlighter);
214
215
216 Highlighter readOnlySelectedHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
217 new HighlightPredicate.AndHighlightPredicate(
218 HighlightPredicate.READ_ONLY,
219 HighlightPredicate.IS_SELECTED),
220 getConfig().getColorRowReadOnly().darker());
221 cpsTable.addHighlighter(readOnlySelectedHighlighter);
222
223
224 Highlighter validHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
225 new HighlightPredicate.AndHighlightPredicate(
226 HighlightPredicate.EDITABLE,
227 notSelectedPredicate,
228 rowIsInvalidPredicate),
229 getConfig().getColorRowInvalid());
230 cpsTable.addHighlighter(validHighlighter);
231
232
233 Highlighter validSelectedHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
234 new HighlightPredicate.AndHighlightPredicate(
235 HighlightPredicate.EDITABLE,
236 HighlightPredicate.IS_SELECTED,
237 rowIsInvalidPredicate),
238 getConfig().getColorRowInvalid().darker());
239 cpsTable.addHighlighter(validSelectedHighlighter);
240
241
242
243 HighlightPredicate speciesOrderEven = (renderer, adapter) -> {
244 int rowIndex = adapter.convertRowIndexToModel(adapter.row);
245 return tableModel.isSpeciesOrderEven(rowIndex);
246 };
247
248 Highlighter evenHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
249 new HighlightPredicate.AndHighlightPredicate(
250 new HighlightPredicate.NotHighlightPredicate(speciesOrderEven),
251 notSelectedPredicate,
252 rowIsValidPredicate,
253 HighlightPredicate.READ_ONLY),
254 getConfig().getColorAlternateRow().darker());
255 cpsTable.addHighlighter(evenHighlighter);
256
257 Highlighter oddHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
258 new HighlightPredicate.AndHighlightPredicate(
259 speciesOrderEven,
260 notSelectedPredicate,
261 rowIsValidPredicate,
262 HighlightPredicate.READ_ONLY),
263 Color.WHITE.darker());
264 cpsTable.addHighlighter(oddHighlighter);
265
266 Highlighter evenNotReadOnlyHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
267 new HighlightPredicate.AndHighlightPredicate(
268 new HighlightPredicate.NotHighlightPredicate(speciesOrderEven),
269 notSelectedPredicate,
270 rowIsValidPredicate,
271 HighlightPredicate.EDITABLE),
272 getConfig().getColorAlternateRow());
273 cpsTable.addHighlighter(evenNotReadOnlyHighlighter);
274
275 Highlighter oddNotReadOnlyHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
276 new HighlightPredicate.AndHighlightPredicate(
277 speciesOrderEven,
278 notSelectedPredicate,
279 rowIsValidPredicate,
280 HighlightPredicate.EDITABLE),
281 Color.WHITE);
282 cpsTable.addHighlighter(oddNotReadOnlyHighlighter);
283
284
285 Highlighter evenSelectedHighlighter = TuttiUIUtil.newBackgroundColorHighlighter(
286 new HighlightPredicate.AndHighlightPredicate(
287 new HighlightPredicate.NotHighlightPredicate(speciesOrderEven),
288 HighlightPredicate.IS_SELECTED,
289 rowIsValidPredicate,
290 HighlightPredicate.EDITABLE),
291 getConfig().getColorSelectedRow());
292 cpsTable.addHighlighter(evenSelectedHighlighter);
293
294
295
296 Font font = cpsTable.getFont().deriveFont(Font.BOLD);
297 Highlighter selectHighlighter = new FontHighlighter(HighlightPredicate.IS_SELECTED, font);
298 cpsTable.addHighlighter(selectHighlighter);
299
300 HighlightPredicate rowWithoutValuePredicate = (renderer, adapter) -> {
301 int rowIndex = adapter.convertRowIndexToModel(adapter.row);
302 CalcifiedPiecesSamplingEditorRowModel entry = tableModel.getEntry(rowIndex);
303 Integer maxByLenghtStep = entry.getMaxByLenghtStep();
304 return maxByLenghtStep == null || maxByLenghtStep == 0;
305 };
306
307 font = cpsTable.getFont().deriveFont(Font.ITALIC);
308 cpsTable.addHighlighter(new FontHighlighter(rowWithoutValuePredicate, font));
309 }
310
311 protected DefaultTableColumnModelExt initTableColumnModel() {
312
313 NumberCellEditor numberCellEditor = JAXXWidgetUtil.newNumberTableCellEditor(Integer.class, false);
314 numberCellEditor.getNumberEditor().setSelectAllTextOnError(true);
315 numberCellEditor.getNumberEditor().getTextField().setBorder(new LineBorder(Color.GRAY, 2));
316 numberCellEditor.getNumberEditor().setNumberPattern(TuttiUI.INT_6_DIGITS_PATTERN);
317
318
319 TableCellRenderer infiniteRenderer = (table, value, isSelected, hasFocus, row, column) -> {
320
321 Component result = table.getDefaultRenderer(Integer.class)
322 .getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
323 if (result instanceof JLabel) {
324 JLabel jLabel = (JLabel) result;
325 String decoratedValue = getDecorator(Integer.class, DecoratorService.NULL_INFINITE).toString(value);
326 jLabel.setText(decoratedValue);
327 jLabel.setHorizontalTextPosition(SwingConstants.RIGHT);
328 }
329 return result;
330 };
331
332 JXTable cpsTable = ui.getCpsTable();
333
334 DefaultTableColumnModelExt columnModel = new DefaultTableColumnModelExt();
335
336
337 TableCellRenderer speciesRenderer = (table, value, isSelected, hasFocus, row, column) -> {
338
339 Component result = table.getDefaultRenderer(String.class)
340 .getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
341 if (result instanceof JLabel) {
342 JLabel jLabel = (JLabel) result;
343 EditProtocolSpeciesRowModel species = (EditProtocolSpeciesRowModel) value;
344 jLabel.setText(decorate(species.getSpecies(), DecoratorService.WITH_SURVEY_CODE));
345 }
346 return result;
347 };
348 addColumnToModel(columnModel,
349 null,
350 speciesRenderer,
351 CalcifiedPiecesSamplingEditorTableModel.SPECIES);
352
353
354
355 addColumnToModel(columnModel,
356 null,
357 newTableCellRender(Boolean.class, DecoratorService.MATURITY),
358 CalcifiedPiecesSamplingEditorTableModel.MATURITY);
359
360 TableColumnExt sexColumn = addBooleanColumnToModel(columnModel, CalcifiedPiecesSamplingEditorTableModel.SEX, cpsTable);
361
362
363 sexColumn.getCellEditor().addCellEditorListener(new CellEditorListener() {
364
365 @Override
366 public void editingStopped(ChangeEvent e) {
367
368 int selectedRow = getUI().getCpsTable().getSelectedRow();
369
370 List<CalcifiedPiecesSamplingEditorRowModel> cpsRows = getModel().getCpsRows();
371 CalcifiedPiecesSamplingEditorRowModel row = cpsRows.get(selectedRow);
372
373 List<CalcifiedPiecesSamplingEditorRowModel> rowsToChangeSex =
374 cpsRows.stream().filter(r -> r.getProtocolSpecies().equals(row.getProtocolSpecies())).collect(Collectors.toList());
375
376 rowsToChangeSex.forEach(r -> r.setSex(row.isSex()));
377
378 TreeSet<Integer> indexesToUpdate =
379 new TreeSet<>(rowsToChangeSex.stream().map(cpsRows::indexOf).collect(Collectors.toSet()));
380
381 CalcifiedPiecesSamplingEditorTableModel tableModel =
382 (CalcifiedPiecesSamplingEditorTableModel) getUI().getCpsTable().getModel();
383 tableModel.fireTableRowsUpdated(indexesToUpdate.first(), indexesToUpdate.last());
384 }
385
386 @Override
387 public void editingCanceled(ChangeEvent e) {
388
389 }
390 });
391
392 addIntegerColumnToModel(columnModel, CalcifiedPiecesSamplingEditorTableModel.MIN_SIZE, TuttiUI.INT_6_DIGITS_PATTERN, cpsTable);
393
394 addColumnToModel(columnModel, null, infiniteRenderer, CalcifiedPiecesSamplingEditorTableModel.MAX_SIZE);
395
396 addColumnToModel(columnModel, numberCellEditor, infiniteRenderer, CalcifiedPiecesSamplingEditorTableModel.MAX_BY_LENGHT_STEP);
397
398 addIntegerColumnToModel(columnModel, CalcifiedPiecesSamplingEditorTableModel.SAMPLING_INTERVAL, TuttiUI.INT_6_DIGITS_PATTERN, cpsTable);
399
400 addColumnToModel(columnModel, numberCellEditor, infiniteRenderer, CalcifiedPiecesSamplingEditorTableModel.OPERATION_LIMITATION);
401
402 addColumnToModel(columnModel, numberCellEditor, infiniteRenderer, CalcifiedPiecesSamplingEditorTableModel.ZONE_LIMITATION);
403
404 return columnModel;
405 }
406
407 @Override
408 protected void beforeOpenPopup(int modelRowIndex, int modelColumnIndex) {
409 super.beforeOpenPopup(modelRowIndex, modelColumnIndex);
410
411 boolean speciesDeletable;
412 boolean splitEnabled;
413 boolean rowDeletable;
414
415 JMenuItem deleteSpeciesMenu = getUI().getDeleteSpeciesMenu();
416
417 int selectedRowCount = getUI().getCpsTable().getSelectedRowCount();
418
419 if (selectedRowCount > 1) {
420
421
422 speciesDeletable = true;
423 splitEnabled = false;
424 rowDeletable = false;
425
426 deleteSpeciesMenu.setText(t("tutti.editCps.deleteMoreThanOneSpecies"));
427 deleteSpeciesMenu.setToolTipText(t("tutti.editCps.deleteMoreThanOneSpecies.tip"));
428
429 } else {
430
431 speciesDeletable = modelRowIndex >= 0 && modelRowIndex < getModel().getCpsRows().size();
432 splitEnabled = speciesDeletable;
433 rowDeletable = speciesDeletable;
434
435 if (speciesDeletable) {
436
437 CalcifiedPiecesSamplingEditorRowModel selectedRow = getModel().getCpsRows().get(modelRowIndex);
438
439 Integer minSize = selectedRow.getMinSize();
440
441 splitEnabled = selectedRow.getMaxSize() == null
442 || selectedRow.getMaxSize() - minSize > 1;
443 rowDeletable = minSize > 0;
444
445 }
446
447 deleteSpeciesMenu.setText(t("tutti.editCps.deleteOneSpecies"));
448 deleteSpeciesMenu.setToolTipText(t("tutti.editCps.deleteOneSpecies.tip"));
449
450 }
451
452 getUI().getSplitCpsRowMenu().setEnabled(splitEnabled);
453
454 getUI().getDeleteCpsRowMenu().setEnabled(rowDeletable);
455
456 deleteSpeciesMenu.setEnabled(speciesDeletable);
457
458 }
459
460 @Override
461 protected JComponent getComponentToFocus() {
462 return null;
463 }
464
465 @Override
466 public void onCloseUI() {
467
468 }
469
470 @Override
471 public SwingValidator<EditProtocolUIModel> getValidator() {
472 return null;
473 }
474
475
476 public CalcifiedPiecesSamplingEditorRowModel createNewRow(Species species,
477 Boolean maturity) {
478
479 Optional<EditProtocolSpeciesRowModel> speciesProtocolRow = getEditProtocolSpeciesRowModel(species);
480 boolean sex = speciesProtocolRow.isPresent()
481 && speciesProtocolRow.get().containsMandatorySampleCategoryId(sexCaracteristic.getIdAsInt());
482
483 return createNewRow(speciesProtocolRow.orElse(null), maturity, sex, 0, null);
484 }
485
486 public CalcifiedPiecesSamplingEditorRowModel createNewRow(Species species,
487 Boolean maturity,
488 boolean sex,
489 Integer minSize,
490 Integer maxSize) {
491
492 Optional<EditProtocolSpeciesRowModel> speciesProtocolRow = getEditProtocolSpeciesRowModel(species);
493
494 return createNewRow(speciesProtocolRow.orElse(null), maturity, sex, minSize, maxSize);
495 }
496
497 public CalcifiedPiecesSamplingEditorRowModel createNewRow(EditProtocolSpeciesRowModel species,
498 Boolean maturity,
499 boolean sex,
500 Integer minSize,
501 Integer maxSize) {
502
503 JXTable cpsTable = getUI().getCpsTable();
504 CalcifiedPiecesSamplingEditorTableModel tableModel = (CalcifiedPiecesSamplingEditorTableModel) cpsTable.getModel();
505
506 CalcifiedPiecesSamplingEditorRowModel newRow = tableModel.createNewRow(species, maturity, sex, minSize, maxSize);
507 newRow.removePropertyChangeListener(rowChangeListener);
508 newRow.addPropertyChangeListener(rowChangeListener);
509
510 return newRow;
511 }
512
513 protected Optional<EditProtocolSpeciesRowModel> getEditProtocolSpeciesRowModel(Species species) {
514
515 Optional<EditProtocolSpeciesRowModel> speciesProtocolRow = getModel().getSpeciesRow()
516 .stream()
517 .filter(sp -> species.equals(sp.getSpecies()))
518 .findFirst();
519
520 if (!speciesProtocolRow.isPresent()) {
521 speciesProtocolRow = getModel().getBenthosRow()
522 .stream()
523 .filter(sp -> species.equals(sp.getSpecies()))
524 .findFirst();
525 }
526 return speciesProtocolRow;
527 }
528 }