View Javadoc
1   package fr.ifremer.tutti.ui.swing.content.operation.catches.species.create;
2   
3   /*
4    * #%L
5    * Tutti :: UI
6    * %%
7    * Copyright (C) 2012 - 2014 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the 
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public 
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  import com.google.common.collect.Multimap;
26  import fr.ifremer.adagio.core.dao.referential.pmfm.QualitativeValueId;
27  import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModel;
28  import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModelEntry;
29  import fr.ifremer.tutti.persistence.entities.protocol.SpeciesProtocol;
30  import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocols;
31  import fr.ifremer.tutti.persistence.entities.referential.Caracteristic;
32  import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValue;
33  import fr.ifremer.tutti.persistence.entities.referential.Species;
34  import fr.ifremer.tutti.service.DecoratorService;
35  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.EditSpeciesBatchPanelUI;
36  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.SpeciesOrBenthosBatchUISupport;
37  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.edit.SpeciesBatchUIModel;
38  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.split.SplitSpeciesBatchRowModel;
39  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.split.SplitSpeciesBatchTableModel;
40  import fr.ifremer.tutti.ui.swing.util.TuttiBeanMonitor;
41  import fr.ifremer.tutti.ui.swing.util.TuttiUI;
42  import fr.ifremer.tutti.ui.swing.util.table.AbstractTuttiTableUIHandler;
43  import jaxx.runtime.validator.swing.SwingValidator;
44  import org.apache.commons.logging.Log;
45  import org.apache.commons.logging.LogFactory;
46  import org.jdesktop.swingx.JXTable;
47  import org.jdesktop.swingx.table.DefaultTableColumnModelExt;
48  
49  import javax.swing.JComponent;
50  import java.beans.PropertyChangeEvent;
51  import java.beans.PropertyChangeListener;
52  import java.util.ArrayList;
53  import java.util.List;
54  import java.util.Objects;
55  import java.util.Optional;
56  
57  /**
58   * Handler of {@link CreateSpeciesBatchUI}.
59   *
60   * @author Tony Chemit - chemit@codelutin.com
61   * @since 0.3
62   */
63  public class CreateSpeciesBatchUIHandler extends AbstractTuttiTableUIHandler<SplitSpeciesBatchRowModel, CreateSpeciesBatchUIModel, CreateSpeciesBatchUI> {
64  
65      /** Logger. */
66      private static final Log log = LogFactory.getLog(CreateSpeciesBatchUIHandler.class);
67  
68      public static final PropertyChangeListener PROPERTY_WEIGHT_CHANGED_LISTENER = new PropertyChangeListener() {
69  
70          @Override
71          public void propertyChange(PropertyChangeEvent evt) {
72              if (evt.getNewValue() != null) {
73                  ((SplitSpeciesBatchRowModel) evt.getSource()).setSelected(true);
74              }
75          }
76      };
77  
78      protected final PropertyChangeListener PROPERTY_SELECTED_CATEGORY_CHANGED_LISTENER = new PropertyChangeListener() {
79  
80          @Override
81          public void propertyChange(PropertyChangeEvent evt) {
82  
83              // can change the selected category
84              CreateSpeciesBatchUIModel source =
85                      (CreateSpeciesBatchUIModel) evt.getSource();
86  
87              // when selected category change, sample total weight is reset
88              source.setSampleWeight(null);
89  
90              SampleCategoryModelEntry newValue =
91                      (SampleCategoryModelEntry) evt.getNewValue();
92              generateTableModel(newValue);
93          }
94      };
95  
96      protected final PropertyChangeListener PROPERTY_SPECIES_CHANGED_LISTENER = new PropertyChangeListener() {
97  
98          @Override
99          public void propertyChange(PropertyChangeEvent evt) {
100 
101             CreateSpeciesBatchUIModel source = (CreateSpeciesBatchUIModel) evt.getSource();
102 
103             Species newValue = (Species) evt.getNewValue();
104 
105             if (log.isDebugEnabled()) {
106                 log.debug("New Selected species " + (newValue == null ? null : decorate(newValue)));
107             }
108 
109             if (newValue == null || source.getSpeciesUsed() == null) {
110 
111                 // reset V/HV category
112                 source.setSampleCategory(null);
113 
114                 source.setSpeciesProtocolFrequencyMode(null);
115 
116             } else {
117 
118                 // select the last used V/HV category used, or sorted if no batch has been created
119 
120                 List<CaracteristicQualitativeValue> qualitativeValues =
121                         CreateSpeciesBatchUIHandler.this.ui.getSampleCategoryComboBox().getData();
122 
123                 CaracteristicQualitativeValue newCategory = null;
124 
125                 CaracteristicQualitativeValue defaultCategory = getModel().getLastSampleCategoryUsed();
126                 if (defaultCategory == null) {
127                     defaultCategory = sortedValue;
128                 }
129 
130                 for (CaracteristicQualitativeValue qualitativeValue : qualitativeValues) {
131                     if (source.isSpeciesAndCategoryAvailable(newValue, qualitativeValue)) {
132                         newCategory = qualitativeValue;
133 
134                         if (newCategory.equals(defaultCategory)) {
135                             break;
136                         }
137                     }
138                 }
139                 source.setSampleCategory(newCategory);
140 
141                 // reset selected category
142                 if (log.isDebugEnabled()) {
143                     log.debug("Remove selected category before changing the categories...");
144                 }
145                 source.setSelectedCategory(null);
146 
147                 // compute the selected sample category
148 
149 
150                 SampleCategoryModelEntry selectedCategory = source.getSpeciesOrBenthosBatchUISupport().getBestFirstSampleCategory(
151                         getUI().getCategoryComboBox().getData(),
152                         newValue
153                 );
154 
155                 if (log.isDebugEnabled()) {
156                     log.debug("Selected category : " + selectedCategory);
157                 }
158 
159                 // set new selected category
160                 source.setSelectedCategory(selectedCategory);
161 
162                 // get species protocol to check the measurement method
163                 // poussin 20161230 fixes bug #8674 getSpeciesOrBenthosProtocol and not getSpeciesProtocol
164                 SpeciesProtocol speciesProtocol = TuttiProtocols.getSpeciesOrBenthosProtocol(getDataContext().getProtocol(),
165                             newValue.getReferenceTaxonId());
166 
167                 CreateSpeciesBatchUIModel.SpeciesProtocolFrequencyMode frequencyMode = null;
168                 if (speciesProtocol != null) {
169                     if (speciesProtocol.getLengthStepPmfmId() != null) {
170                         frequencyMode = CreateSpeciesBatchUIModel.SpeciesProtocolFrequencyMode.MEASURE;
171                     } else {
172                         frequencyMode = CreateSpeciesBatchUIModel.SpeciesProtocolFrequencyMode.COUNT;
173                     }
174                 }
175                 source.setSpeciesProtocolFrequencyMode(frequencyMode);
176             }
177         }
178     };
179 
180     /**
181      * Qualitative value for the Vrac.
182      *
183      * @since 2.5
184      */
185     protected CaracteristicQualitativeValue sortedValue;
186 //
187 //    /**
188 //     * Sample categories model.
189 //     *
190 //     * @since 2.4
191 //     */
192 //    protected SampleCategoryModel sampleCategoryModel;
193 
194     public CreateSpeciesBatchUIHandler() {
195         super(SplitSpeciesBatchRowModel.PROPERTY_SELECTED,
196               SplitSpeciesBatchRowModel.PROPERTY_CATEGORY_VALUE,
197               SplitSpeciesBatchRowModel.PROPERTY_WEIGHT);
198     }
199 
200     //------------------------------------------------------------------------//
201     //-- AbstractTuttiTableUIHandler methods                                --//
202     //------------------------------------------------------------------------//
203 
204     @Override
205     public SplitSpeciesBatchTableModel getTableModel() {
206         return (SplitSpeciesBatchTableModel) getTable().getModel();
207     }
208 
209     @Override
210     public JXTable getTable() {
211         return ui.getTable();
212     }
213 
214     @Override
215     protected boolean isRowValid(SplitSpeciesBatchRowModel row) {
216         return row.isSelected();
217     }
218 
219     @Override
220     protected void saveSelectedRowIfRequired(TuttiBeanMonitor<SplitSpeciesBatchRowModel> rowMonitor, SplitSpeciesBatchRowModel row) {
221         if (rowMonitor.wasModified()) {
222 
223             if (row.isValid()) {
224                 if (log.isInfoEnabled()) {
225                     log.info("Change row that was modified and valid");
226                 }
227             }
228 
229             rowMonitor.clearModified();
230         }
231     }
232 
233     @Override
234     protected void onAfterSelectedRowChanged(int oldRowIndex,
235                                              SplitSpeciesBatchRowModel oldRow,
236                                              int newRowIndex,
237                                              SplitSpeciesBatchRowModel newRow) {
238         super.onAfterSelectedRowChanged(oldRowIndex, oldRow, newRowIndex, newRow);
239         if (newRow != null) {
240 
241             // Recompute the valid state of the row
242             recomputeRowValidState(newRow);
243 
244             // Need to recompute the sample weight
245             computeSampleWeight();
246         }
247     }
248 
249     @Override
250     protected void onRowModified(int rowIndex,
251                                  SplitSpeciesBatchRowModel row,
252                                  String propertyName,
253                                  Object oldValue,
254                                  Object newValue) {
255 
256         // Recompute the valid state of the row
257         recomputeRowValidState(row);
258 
259         // Need to recompute the sample weight
260         computeSampleWeight();
261     }
262 
263     //------------------------------------------------------------------------//
264     //-- AbstractTuttiUIHandler methods                                     --//
265     //------------------------------------------------------------------------//
266 
267     @Override
268     public void beforeInit(CreateSpeciesBatchUI ui) {
269 
270         super.beforeInit(ui);
271 
272         SampleCategoryModel sampleCategoryModel = getDataContext().getSampleCategoryModel();
273 
274         SampleCategoryModelEntry caracteristic = sampleCategoryModel.getCategoryById(sampleCategoryModel.getFirstCategoryId());
275 
276         Integer vracId = QualitativeValueId.SORTED_VRAC.getValue();
277 
278         CaracteristicQualitativeValue vracValue = null;
279         for (CaracteristicQualitativeValue caracteristicQualitativeValue : caracteristic.getCaracteristic().getQualitativeValue()) {
280 
281             if (vracId.equals(caracteristicQualitativeValue.getIdAsInt())) {
282                 vracValue = caracteristicQualitativeValue;
283                 break;
284             }
285         }
286         Objects.requireNonNull(vracValue, "Could not found vrac qualitative value");
287         sortedValue = vracValue;
288 
289         SpeciesOrBenthosBatchUISupport speciesOrBenthosBatchUISupport = ui.getContextValue(SpeciesOrBenthosBatchUISupport.class, ui.getSpeciesOrBenthosContext());
290         CreateSpeciesBatchUIModel model = new CreateSpeciesBatchUIModel(speciesOrBenthosBatchUISupport, sampleCategoryModel);
291         this.ui.setContextValue(model);
292         listModelIsModify(model);
293     }
294 
295     @Override
296     public void afterInit(CreateSpeciesBatchUI ui) {
297 
298         initUI(this.ui);
299 
300         CreateSpeciesBatchUIModel model = getModel();
301 
302         initBeanFilterableComboBox(this.ui.getSpeciesComboBox(),
303                                    new ArrayList<>(),
304                                    null,
305                                    DecoratorService.FROM_PROTOCOL);
306 
307         List<SampleCategoryModelEntry> categories = new ArrayList<>();
308 
309         // add all categories
310         categories.addAll(model.getSampleCategoryModel().getCategory());
311 
312         // remove the first one (V/HV)
313         categories.remove(0);
314 
315         initBeanFilterableComboBox(this.ui.getCategoryComboBox(),
316                                    new ArrayList<>(categories),
317                                    null);
318 
319         Caracteristic caracteristic =
320                 getPersistenceService().getSortedUnsortedCaracteristic();
321 
322         initBeanFilterableComboBox(this.ui.getSampleCategoryComboBox(),
323                                    new ArrayList<>(caracteristic.getQualitativeValue()),
324                                    null);
325 
326 
327         model.addPropertyChangeListener(CreateSpeciesBatchUIModel.PROPERTY_SPECIES, PROPERTY_SPECIES_CHANGED_LISTENER);
328 
329         // when selected category changed, regenerate the table model + add inside some default rows
330         model.addPropertyChangeListener(CreateSpeciesBatchUIModel.PROPERTY_SELECTED_CATEGORY, PROPERTY_SELECTED_CATEGORY_CHANGED_LISTENER);
331 
332         generateTableModel(null);
333 
334         initTable(getTable());
335 
336         listenValidatorValid(this.ui.getValidator(), model);
337     }
338 
339     @Override
340     protected JComponent getComponentToFocus() {
341         return getUI().getSpeciesComboBox();
342     }
343 
344     @Override
345     public void onCloseUI() {
346 
347         if (log.isDebugEnabled()) {
348             log.debug("closing: " + ui);
349         }
350 
351         clearValidators();
352 
353         // evict model from validator
354         ui.getValidator().setBean(null);
355 
356         // when canceling always invalid model
357         getModel().setValid(false);
358 
359         EditSpeciesBatchPanelUI parent = getParentContainer(EditSpeciesBatchPanelUI.class);
360         parent.switchToEditBatch();
361 
362     }
363 
364     @Override
365     public SwingValidator<CreateSpeciesBatchUIModel> getValidator() {
366         return ui.getValidator();
367     }
368 
369     //------------------------------------------------------------------------//
370     //-- Public methods                                                     --//
371     //------------------------------------------------------------------------//
372 
373     public void openUI(SpeciesBatchUIModel batchModel) {
374 
375         CreateSpeciesBatchUIModel model = getModel();
376 
377         // connect model to validator
378         ui.getValidator().setBean(model);
379 
380         model.setSpecies(null);
381         model.setSampleCategory(null);
382         model.setBatchSampleCategoryWeight(null);
383         model.setBatchWeight(null);
384         model.setBatchCount(null);
385 
386         List<Species> speciesToUse = new ArrayList<>();
387 
388         Multimap<CaracteristicQualitativeValue, Species> speciesUsed = model.getSpeciesUsed();
389         speciesUsed.clear();
390 
391         if (batchModel != null) {
392 
393             speciesUsed.putAll(batchModel.getSpeciesUsed());
394 
395             // compute which species can still be used
396 
397             List<Species> allSpecies = model.getSpeciesOrBenthosBatchUISupport().getReferentSpeciesWithSurveyCode(true);
398 
399             speciesToUse.addAll(allSpecies);
400         }
401 
402         model.setAvailableSpecies(speciesToUse);
403     }
404 
405     //------------------------------------------------------------------------//
406     //-- Internal methods                                                   --//
407     //------------------------------------------------------------------------//
408 
409     protected void computeSampleWeight() {
410 
411         Optional<Float> result = getTableModel().getTotalWeight();
412 //        List<SplitSpeciesBatchRowModel> rows = getTableModel().getRows();
413 //        for (SplitSpeciesBatchRowModel row : rows) {
414 //            if (row.isSelected()) {
415 //                Float weight = row.getWeight();
416 //                if (weight != null) {
417 //                    if (result == null) {
418 //                        result = 0f;
419 //                    }
420 //                    result += weight;
421 //                }
422 //            }
423 //        }
424         getModel().setSampleWeight(result.orElse(null));
425     }
426 
427     protected void generateTableModel(SampleCategoryModelEntry category) {
428 
429         if (log.isDebugEnabled()) {
430             log.debug("Generate table model for category " + category);
431         }
432         CreateSpeciesBatchUIModel model = getModel();
433 
434         // when generate a new table model, then reset previous rows from model
435         model.setRows(null);
436 
437         Caracteristic data = null;
438 
439         JXTable table = getTable();
440 
441         DefaultTableColumnModelExt columnModel = new DefaultTableColumnModelExt();
442 
443         { // Selection
444 
445             addBooleanColumnToModel(columnModel,
446                                     SplitSpeciesBatchTableModel.SELECTED,
447                                     table);
448         }
449 
450         boolean editableCategoryValue = false;
451         if (category != null) {
452 
453             if (!category.getCaracteristic().isQualitativeValueEmpty()) {
454 
455                 // qualitative category
456                 data = category.getCaracteristic();
457             } else {
458                 editableCategoryValue = true;
459                 addFloatColumnToModel(columnModel,
460                                       SplitSpeciesBatchTableModel.EDITABLE_CATEGORY_VALUE,
461                                       TuttiUI.DECIMAL1_PATTERN,
462                                       table);
463             }
464 
465             if (data != null) {
466 
467                 if (log.isDebugEnabled()) {
468                     log.debug("Got " + data.sizeQualitativeValue() + " qualitative data to add");
469                 }
470                 addColumnToModel(columnModel,
471                                  null,
472                                  newTableCellRender(CaracteristicQualitativeValue.class),
473                                  SplitSpeciesBatchTableModel.READ_ONLY_CATEGORY_VALUE);
474             }
475             { // Weight
476 
477                 addFloatColumnToModel(columnModel,
478                                       SplitSpeciesBatchTableModel.WEIGHT,
479                                       model.getSpeciesOrBenthosBatchUISupport().getWeightUnit(),
480                                       table);
481             }
482         }
483 
484         // create table model
485         SplitSpeciesBatchTableModel tableModel = new SplitSpeciesBatchTableModel(columnModel,
486                                                                                  model,
487                                                                                  editableCategoryValue,
488                                                                                  false);
489 
490         // remove all listener on tables we could add before
491         uninstallTableSaveOnRowChangedSelectionListener();
492         uninstallTableKeyListener(getTable());
493 
494         if (log.isDebugEnabled()) {
495             log.debug("Install new table model " + tableModel);
496         }
497         table.setModel(tableModel);
498         table.setColumnModel(columnModel);
499 
500         // install table listeners
501         installTableSaveOnRowChangedSelectionListener();
502         installTableKeyListener(columnModel, table);
503 
504         // fill datas
505 
506         List<SplitSpeciesBatchRowModel> rows = new ArrayList<>();
507 
508         if (data != null) {
509 
510             // add a row for each qualitive value
511             for (CaracteristicQualitativeValue qualitativeValue : data.getQualitativeValue()) {
512                 if (log.isDebugEnabled()) {
513                     log.debug("Add QV: " + qualitativeValue);
514                 }
515                 SplitSpeciesBatchRowModel newRow = tableModel.createNewRow();
516                 newRow.setCategoryValue(qualitativeValue);
517                 newRow.addPropertyChangeListener(SplitSpeciesBatchRowModel.PROPERTY_WEIGHT, PROPERTY_WEIGHT_CHANGED_LISTENER);
518                 rows.add(newRow);
519             }
520         }
521 
522         if (log.isDebugEnabled()) {
523             log.debug("Will add " + rows.size() + " rows in table model " +
524                               "(can add a first empty row? " + editableCategoryValue + ").");
525         }
526 
527         model.setRows(rows);
528     }
529 
530 }