View Javadoc
1   package fr.ifremer.dali.ui.swing.content.home.operation.add;
2   
3   /*
4    * #%L
5    * Dali :: UI
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2014 - 2015 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   *
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   *
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import fr.ifremer.dali.decorator.DecoratorService;
27  import fr.ifremer.dali.dto.DaliBeans;
28  import fr.ifremer.dali.dto.data.sampling.SamplingOperationDTO;
29  import fr.ifremer.dali.dto.enums.FilterTypeValues;
30  import fr.ifremer.dali.dto.referential.DepartmentDTO;
31  import fr.ifremer.dali.dto.referential.SamplingEquipmentDTO;
32  import fr.ifremer.dali.dto.referential.pmfm.PmfmDTO;
33  import fr.ifremer.dali.service.StatusFilter;
34  import fr.ifremer.dali.ui.swing.content.home.operation.OperationsTableModel;
35  import fr.ifremer.dali.ui.swing.content.home.operation.OperationsTableRowModel;
36  import fr.ifremer.dali.ui.swing.content.home.operation.OperationsTableUIModel;
37  import fr.ifremer.dali.ui.swing.util.DaliUI;
38  import fr.ifremer.dali.ui.swing.util.table.AbstractDaliTableModel;
39  import fr.ifremer.dali.ui.swing.util.table.AbstractDaliTableUIHandler;
40  import fr.ifremer.quadrige3.ui.swing.component.coordinate.CoordinateEditor;
41  import fr.ifremer.quadrige3.ui.swing.table.SwingTable;
42  import fr.ifremer.quadrige3.ui.swing.table.editor.ExtendedComboBoxCellEditor;
43  import fr.ifremer.quadrige3.ui.swing.table.editor.LocalTimeCellEditor;
44  import org.apache.commons.collections4.CollectionUtils;
45  import org.jdesktop.swingx.table.TableColumnExt;
46  import org.nuiton.jaxx.application.swing.util.Cancelable;
47  
48  import javax.swing.AbstractAction;
49  import javax.swing.JComponent;
50  import javax.swing.JTextField;
51  import javax.swing.KeyStroke;
52  import java.awt.Component;
53  import java.awt.event.ActionEvent;
54  import java.util.ArrayList;
55  import java.util.List;
56  
57  import static org.nuiton.i18n.I18n.t;
58  
59  /**
60   * Controleur pour l'écran principale de l'acceuil.
61   */
62  public class AddOperationTableUIHandler extends AbstractDaliTableUIHandler<OperationsTableRowModel, AddOperationTableUIModel, AddOperationTableUI> implements Cancelable {
63  
64      private ExtendedComboBoxCellEditor<SamplingEquipmentDTO> samplingEquipmentCellEditor;
65      private ExtendedComboBoxCellEditor<DepartmentDTO> samplingDepartmentCellEditor;
66      private ExtendedComboBoxCellEditor<DepartmentDTO> analystDepartmentCellEditor;
67  
68      /**
69       * {@inheritDoc}
70       */
71      @Override
72      public AbstractDaliTableModel<OperationsTableRowModel> getTableModel() {
73          return (OperationsTableModel) getTable().getModel();
74      }
75  
76      /**
77       * {@inheritDoc}
78       */
79      @Override
80      public SwingTable getTable() {
81          return getUI().getAddOperationTable();
82      }
83  
84      /**
85       * {@inheritDoc}
86       */
87      @Override
88      public void beforeInit(AddOperationTableUI ui) {
89          super.beforeInit(ui);
90  
91          // create model and register to the JAXX context
92          final AddOperationTableUIModel model = new AddOperationTableUIModel();
93          ui.setContextValue(model);
94      }
95  
96      /**
97       * {@inheritDoc}
98       */
99      @Override
100     public void afterInit(AddOperationTableUI addOperationTableUI) {
101 
102         // Initialiser l UI
103         initUI(ui);
104 
105         createSamplingDepartmentCellEditor();
106         createAnalystDepartmentCellEditor();
107         createSamplingEquipmentCellEditor();
108 
109         initTable();
110 
111         // add listener on TAB key to follow focus to table
112         String tabActionName = "newTABAction";
113         JTextField field = getUI().getNbOperationEditor().getTextField();
114         field.setFocusTraversalKeysEnabled(false);
115         field.getInputMap().put(KeyStroke.getKeyStroke("pressed TAB"), tabActionName);
116         field.getActionMap().put(tabActionName, new AbstractAction() {
117             @Override
118             public void actionPerformed(ActionEvent e) {
119                 setFocusOnCell(getModel().getRows().get(0));
120             }
121         });
122         // fix Mantis #37266 set default value to 1
123         getModel().setNbOperation(1);
124         field.selectAll();
125     }
126 
127     /**
128      * Charge les colonnes dynamiques.
129      *
130      * @param tableModel Le model
131      */
132     public void load(final OperationsTableUIModel tableModel) {
133         getModel().setSurvey(tableModel.getSurvey());
134 
135         // Chargement des psfms du tableau
136         List<PmfmDTO> pmfms = tableModel.getPmfms();
137         getModel().setPmfms(pmfms);
138         addPmfmColumns(
139                 getModel().getPmfms(),
140                 SamplingOperationDTO.PROPERTY_PMFMS,
141                 DecoratorService.NAME_WITH_UNIT,
142                 OperationsTableModel.TIME);
143 
144         boolean notEmpty = CollectionUtils.isNotEmpty(getModel().getPmfmColumns());
145 
146         // Le prelevement
147         SamplingOperationDTO newSamplingOperation = getContext().getObservationService().newSamplingOperation(getModel().getSurvey(), pmfms);
148 
149         // Chargement du tableau avec les prelevements
150         getModel().setRows(null);
151         OperationsTableRowModel newRow = getModel().addNewRow(newSamplingOperation);
152 
153         // If no PMFM, hide analysis column and set default (Mantis #42617)
154 //        forceColumnVisibleAtLastPosition(OperationsTableModel.ANALYST, notEmpty);
155         // Don't force position (Mantis #49939)
156         forceColumnVisible(OperationsTableModel.ANALYST, notEmpty);
157 
158         // Set analyst from pmfm strategies
159         if (notEmpty) {
160             newRow.setAnalyst(getContext().getProgramStrategyService().getAnalysisDepartmentOfAppliedStrategyBySurvey(getModel().getSurvey()));
161         }
162 
163         recomputeRowsValidState(false);
164 
165     }
166 
167     /**
168      * Initialisation du tableau.
169      */
170     private void initTable() {
171 
172         // La table des prelevements
173         final SwingTable table = getTable();
174 
175         // Colonne engin
176         final TableColumnExt colSamplingEquipment = addColumn(
177                 samplingEquipmentCellEditor,
178                 newTableCellRender(OperationsTableModel.SAMPLING_EQUIPMENT),
179                 OperationsTableModel.SAMPLING_EQUIPMENT
180         );
181         colSamplingEquipment.setSortable(true);
182         colSamplingEquipment.setMinWidth(200);
183 
184         // Colonne Heure
185         final TableColumnExt colTime = addColumn(
186                 new LocalTimeCellEditor(),
187                 newTableCellRender(Integer.class, DecoratorService.TIME_IN_HOURS_MINUTES),
188                 OperationsTableModel.TIME);
189         colTime.setSortable(true);
190         colTime.setMinWidth(50);
191 
192         //------ Colonnes optionnelles
193 
194         // Colonne Taille
195         final TableColumnExt colSize = addColumn(
196                 newNumberCellEditor(Double.class, false, DaliUI.DECIMAL7_PATTERN),
197                 newNumberCellRenderer(7),
198                 OperationsTableModel.SIZE);
199         colSize.setSortable(true);
200         colSize.setMinWidth(50);
201 
202         // Colonne Unite taille
203         final TableColumnExt colSizeUnit = addExtendedComboDataColumnToModel(
204                 OperationsTableModel.SIZE_UNIT,
205                 getContext().getReferentialService().getUnits(StatusFilter.ACTIVE),
206                 false);
207         colSizeUnit.setSortable(true);
208         colSizeUnit.setMinWidth(100);
209 
210         // Colonne service préleveur
211         final TableColumnExt colSamplingDepartment = addColumn(
212                 samplingDepartmentCellEditor,
213                 newTableCellRender(OperationsTableModel.SAMPLING_DEPARTMENT),
214                 OperationsTableModel.SAMPLING_DEPARTMENT
215         );
216         colSamplingDepartment.setSortable(true);
217         colSamplingDepartment.setMinWidth(100);
218 
219         // Colonne service analyste
220         final TableColumnExt colAnalystDepartment = addColumn(
221                 analystDepartmentCellEditor,
222                 newTableCellRender(OperationsTableModel.ANALYST),
223                 OperationsTableModel.ANALYST
224         );
225         colAnalystDepartment.setSortable(true);
226         colAnalystDepartment.setMinWidth(100);
227 
228         // Colonne niveau
229         final TableColumnExt colDepthLevel = addExtendedComboDataColumnToModel(
230                 OperationsTableModel.DEPTH_LEVEL,
231                 getContext().getReferentialService().getLevels(),
232                 false);
233         colDepthLevel.setSortable(true);
234         colDepthLevel.setMinWidth(100);
235 
236         // Colonne immersion
237         final TableColumnExt colDepth = addColumn(
238                 newNumberCellEditor(Double.class, false, DaliUI.DECIMAL2_PATTERN),
239                 newNumberCellRenderer(2),
240                 OperationsTableModel.DEPTH);
241         colDepth.setSortable(true);
242         colDepth.setMinWidth(100);
243 
244         // Colonne immersion min
245         final TableColumnExt colMinDepth = addColumn(
246                 newNumberCellEditor(Double.class, false, DaliUI.DECIMAL2_PATTERN),
247                 newNumberCellRenderer(2),
248                 OperationsTableModel.MIN_DEPTH);
249         colMinDepth.setSortable(true);
250         colMinDepth.setMinWidth(100);
251 
252         // Colonne immersion
253         final TableColumnExt colMaxDepth = addColumn(
254                 newNumberCellEditor(Double.class, false, DaliUI.DECIMAL2_PATTERN),
255                 newNumberCellRenderer(2),
256                 OperationsTableModel.MAX_DEPTH);
257         colMaxDepth.setSortable(true);
258         colMaxDepth.setMinWidth(100);
259 
260         // Colonne Coordonnées réelles
261         final TableColumnExt colLatitude = addCoordinateColumnToModel(
262                 CoordinateEditor.CoordinateType.LATITUDE_MIN,
263                 OperationsTableModel.LATITUDE);
264         colLatitude.setSortable(true);
265         colLatitude.setMinWidth(100);
266 
267         final TableColumnExt colLongitude = addCoordinateColumnToModel(
268                 CoordinateEditor.CoordinateType.LONGITUDE_MIN,
269                 OperationsTableModel.LONGITUDE);
270         colLongitude.setSortable(true);
271         colLongitude.setMinWidth(100);
272 
273         // Colonne informations de positionnement
274         final TableColumnExt colPositioning = addExtendedComboDataColumnToModel(
275                 OperationsTableModel.POSITIONING,
276                 getContext().getReferentialService().getPositioningSystems(),
277                 false);
278         colPositioning.setSortable(true);
279         colPositioning.setMinWidth(100);
280 
281         final TableColumnExt colPositioningPrecision = addColumn(
282                 OperationsTableModel.POSITIONING_PRECISION);
283         colPositioningPrecision.setSortable(true);
284         colPositioningPrecision.setMinWidth(100);
285         colPositioningPrecision.setEditable(false);
286 
287         // Modele de la table
288         final OperationsTableModel tableModel = new OperationsTableModel(getTable().getColumnModel(), false);
289         table.setModel(tableModel);
290 
291         // Initialisation de la table
292         initTable(table, true);
293 
294         // Les colonnes optionnelles sont invisibles
295         colSize.setVisible(false);
296         colSizeUnit.setVisible(false);
297         colSamplingDepartment.setVisible(false);
298         colDepthLevel.setVisible(false);
299         colDepth.setVisible(false);
300         colMinDepth.setVisible(false);
301         colMaxDepth.setVisible(false);
302         colLatitude.setVisible(false);
303         colLongitude.setVisible(false);
304         colPositioning.setVisible(false);
305         colPositioningPrecision.setVisible(false);
306 
307     }
308 
309     private void createSamplingEquipmentCellEditor() {
310 
311         samplingEquipmentCellEditor = newExtendedComboBoxCellEditor(null,
312                 SamplingEquipmentDTO.class, false);
313 
314         samplingEquipmentCellEditor.setAction("unfilter", "dali.common.unfilter", e -> {
315             if (!askBefore(t("dali.common.unfilter"), t("dali.common.unfilter.confirmation"))) {
316                 return;
317             }
318             // unfilter location
319             updateSamplingEquipmentCellEditor(true);
320         });
321 
322         updateSamplingEquipmentCellEditor(false);
323     }
324 
325     private void updateSamplingEquipmentCellEditor(boolean forceNoFilter) {
326 
327         samplingEquipmentCellEditor.getCombo().setActionEnabled(!forceNoFilter && getContext().getDataContext().isContextFiltered(FilterTypeValues.SAMPLING_EQUIPMENT));
328 
329         samplingEquipmentCellEditor.getCombo().setData(
330                 getContext().getObservationService().getAvailableSamplingEquipments(forceNoFilter));
331     }
332 
333     private void createSamplingDepartmentCellEditor() {
334 
335         samplingDepartmentCellEditor = newExtendedComboBoxCellEditor(null,
336                 DepartmentDTO.class, false);
337 
338         samplingDepartmentCellEditor.setAction("unfilter", "dali.common.unfilter", e -> {
339             if (!askBefore(t("dali.common.unfilter"), t("dali.common.unfilter.confirmation"))) {
340                 return;
341             }
342             // unfilter location
343             updateSamplingDepartmentCellEditor(true);
344         });
345 
346         updateSamplingDepartmentCellEditor(false);
347     }
348 
349     private void updateSamplingDepartmentCellEditor(boolean forceNoFilter) {
350 
351         samplingDepartmentCellEditor.getCombo().setActionEnabled(!forceNoFilter && getContext().getDataContext().isContextFiltered(FilterTypeValues.DEPARTMENT));
352 
353         samplingDepartmentCellEditor.getCombo().setData(getContext().getObservationService().getAvailableDepartments(forceNoFilter));
354     }
355 
356     private void createAnalystDepartmentCellEditor() {
357 
358         analystDepartmentCellEditor = newExtendedComboBoxCellEditor(null,
359                 DepartmentDTO.class, false);
360 
361         analystDepartmentCellEditor.setAction("unfilter", "dali.common.unfilter", e -> {
362             if (!askBefore(t("dali.common.unfilter"), t("dali.common.unfilter.confirmation"))) {
363                 return;
364             }
365             // unfilter location
366             updateAnalystDepartmentCellEditor(true);
367         });
368 
369         updateAnalystDepartmentCellEditor(false);
370     }
371 
372     private void updateAnalystDepartmentCellEditor(boolean forceNoFilter) {
373 
374         analystDepartmentCellEditor.getCombo().setActionEnabled(!forceNoFilter && getContext().getDataContext().isContextFiltered(FilterTypeValues.DEPARTMENT));
375 
376         analystDepartmentCellEditor.getCombo().setData(getContext().getObservationService().getAvailableDepartments(forceNoFilter));
377     }
378 
379     /**
380      * {@inheritDoc}
381      */
382     @Override
383     protected boolean isRowValid(final OperationsTableRowModel row) {
384 
385         return super.isRowValid(row) & isOperationValid(row);
386     }
387 
388     private boolean isOperationValid(OperationsTableRowModel row) {
389 
390         // coordinates
391         if (row.getLatitude() == null ^ row.getLongitude() == null) {
392             DaliBeans.addError(row, t("dali.validator.error.coordinate.invalid"), OperationsTableRowModel.PROPERTY_LONGITUDE, OperationsTableRowModel.PROPERTY_LATITUDE);
393         }
394 
395         // positioning
396         if (row.getLatitude() != null && row.getLongitude() != null && row.getPositioning() == null) {
397             DaliBeans.addError(row, t("dali.validator.error.positioning.required"), OperationsTableRowModel.PROPERTY_POSITIONING);
398         }
399 
400         // analyst
401         if (row.getAnalyst() == null && row.getMeasurements().stream().anyMatch(measurement -> !DaliBeans.isMeasurementEmpty(measurement))) {
402             DaliBeans.addError(row, t("dali.validator.error.analyst.required"), OperationsTableRowModel.PROPERTY_ANALYST);
403         }
404 
405         // length
406         if (row.getSize() != null && row.getSizeUnit() == null) {
407             DaliBeans.addError(row, t("dali.validator.error.sizeUnit.required"), OperationsTableRowModel.PROPERTY_SIZE_UNIT);
408         }
409 
410         boolean hasNoError = DaliBeans.hasNoBlockingError(row);
411 
412         if (!hasNoError) {
413             ensureColumnsWithErrorAreVisible(row);
414         }
415 
416         return hasNoError;
417     }
418 
419     /**
420      * <p>valid.</p>
421      */
422     public void valid() {
423 
424         // Recuperation du nombre de prelevements a creer
425         final Integer nbOperation = getModel().getNbOperation();
426         if (nbOperation == null || nbOperation <= 0) {
427 
428             // Le nombre de prelevements doit être renseigne
429             getContext().getDialogHelper().showErrorDialog(getUI(),
430                     t("dali.home.samplingOperation.new.number.error.message"),
431                     t("dali.home.samplingOperation.new.number.error.title"));
432         } else {
433             // Prelevement saisi
434             OperationsTableRowModel rowModel = getModel().getRows().get(0);
435 
436             // keep analyst (not bound property)
437             DepartmentDTO analyst = rowModel.getAnalyst();
438 
439             // convert and clean rows
440             SamplingOperationDTO operation = rowModel.toBean();
441             getModel().setRows(null);
442 
443             // Add default service from observation, if any
444             if (operation.getSamplingDepartment() == null) {
445                 // should not happened
446                 operation.setSamplingDepartment(getModel().getSurvey().getDepartment());
447             }
448 
449 //            // Compute next sampling operation name
450 //            StringIterator labelIterator = null;
451 //            if (getConfig().isSamplingOperationAutoLabelEnable()) {
452 //                labelIterator = StringIterator.newStringIteratorByProperty(getModel().getSamplingOperationsModel().getRows(), SamplingOperationDTO.PROPERTY_NAME);
453 //            }
454 
455             // Creation des prelevements
456             final List<SamplingOperationDTO> operations = new ArrayList<>();
457 
458             for (int i = 0; i < nbOperation; i++) {
459 
460                 // Ajout du prelevement dans la liste
461                 final SamplingOperationDTO newOperation = DaliBeans.duplicate(operation);
462                 if (newOperation != null) {
463 //                    if (labelIterator != null) {
464 //                        // Mantis #38330 Use label auto generation only if enabled by configuration
465 //                        newOperation.setName(labelIterator.next());
466 //                    }
467                     operations.add(newOperation);
468 
469                     // do it at creation time
470                     newOperation.setMeasurementsLoaded(true);
471                 }
472             }
473 
474             // Ajout des prelevements
475             getModel().setBeans(operations);
476 
477             // restore analyst
478             getModel().getRows().forEach(row -> row.setAnalyst(analyst));
479 
480             // Quitter la dialogue
481             closeDialog();
482         }
483     }
484 
485     @Override
486     protected JComponent getComponentToFocus() {
487         return getUI().getNbOperationEditor();
488     }
489 
490     /**
491      * {@inheritDoc}
492      */
493     @Override
494     public Component getNextComponentToFocus() {
495         return getUI().getValidButton();
496     }
497 
498     /**
499      * {@inheritDoc}
500      */
501     @Override
502     public void cancel() {
503         getModel().setRows(null);
504         getModel().setValid(false);
505         closeDialog();
506     }
507 }