View Javadoc
1   package fr.ifremer.tutti.ui.swing.content.operation.catches.species.frequency;
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 fr.ifremer.tutti.persistence.entities.data.CopyIndividualObservationMode;
26  import fr.ifremer.tutti.persistence.entities.data.FishingOperation;
27  import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModel;
28  import fr.ifremer.tutti.persistence.entities.protocol.Rtp;
29  import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocol;
30  import fr.ifremer.tutti.persistence.entities.referential.Caracteristic;
31  import fr.ifremer.tutti.persistence.entities.referential.CaracteristicBean;
32  import fr.ifremer.tutti.service.cruise.CruiseCache;
33  import fr.ifremer.tutti.service.sampling.IndividualObservationSamplingCacheRequest;
34  import fr.ifremer.tutti.type.WeightUnit;
35  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.SpeciesOrBenthosBatchUISupport;
36  import fr.ifremer.tutti.ui.swing.content.operation.catches.species.edit.SpeciesBatchRowModel;
37  import fr.ifremer.tutti.ui.swing.util.computable.ComputableData;
38  import fr.ifremer.tutti.ui.swing.util.table.AbstractTuttiTableUIModel;
39  import fr.ifremer.tutti.util.Numbers;
40  import fr.ifremer.tutti.util.Weights;
41  import java.awt.Color;
42  import java.beans.PropertyVetoException;
43  import java.util.ArrayList;
44  import java.util.HashSet;
45  import java.util.List;
46  import java.util.Set;
47  import org.apache.commons.collections4.CollectionUtils;
48  import org.apache.commons.logging.Log;
49  import org.apache.commons.logging.LogFactory;
50  
51  /**
52   * @author Tony Chemit - chemit@codelutin.com
53   * @since 0.2
54   */
55  public class SpeciesFrequencyUIModel extends AbstractTuttiTableUIModel<SpeciesBatchRowModel, SpeciesFrequencyRowModel, SpeciesFrequencyUIModel> {
56  
57      /** Logger. */
58      private static final Log log = LogFactory.getLog(SpeciesFrequencyUIModel.class);
59  
60      private static final long serialVersionUID = 1L;
61  
62      public static final String PROPERTY_BATCH = "batch";
63  
64      public static final String PROPERTY_CONFIGURATION_MODE = "configurationMode";
65  
66      public static final String PROPERTY_FREQUENCIES_CONFIGURATION_MODE = "frequenciesConfigurationMode";
67  
68      public static final String PROPERTY_STEP = "step";
69  
70      private static final String PROPERTY_MIN_STEP = "minStep";
71  
72      private static final String PROPERTY_MAX_STEP = "maxStep";
73  
74      public static final String PROPERTY_CAN_GENERATE = "canGenerate";
75  
76      public static final String PROPERTY_FREQUENCIES_MODE = "frequenciesMode";
77  
78      public static final String PROPERTY_AUTO_GEN_MODE = "autoGenMode";
79  
80      public static final String PROPERTY_RAFALE_MODE = "rafaleMode";
81  
82      public static final String PROPERTY_SIMPLE_COUNTING_MODE = "simpleCountingMode";
83  
84      public static final String PROPERTY_SIMPLE_COUNT = "simpleCount";
85  
86      public static final String PROPERTY_LENGTH_STEP_CARACTERISTIC = "lengthStepCaracteristic";
87  
88      public static final String PROPERTY_LENGTH_STEP_CARACTERISTIC_UNIT = "lengthStepCaracteristicUnit";
89  
90      public static final String PROPERTY_TOTAL_NUMBER = "totalNumber";
91  
92      public static final String PROPERTY_TOTAL_WEIGHT = "totalWeight";
93  
94      public static final String PROPERTY_TOTAL_COMPUTED_WEIGHT = "totalComputedWeight";
95  
96      public static final String PROPERTY_COPY_RTP_WEIGHTS = "copyRtpWeights";
97  
98      public static final String PROPERTY_RTP = "rtp";
99  
100     public static final String PROPERTY_ADD_INDIVIDUAL_OBSERVATION_ON_RAFALE = "addIndividualObservationOnRafale";
101 
102     public static final String PROPERTY_FREQUENCIES_COLOR = "frequenciesColor";
103 
104     public static final String PROPERTY_INDIVIDUAL_OBSERVATION_COLOR = "individualObservationColor";
105 
106     public static final String PROPERTY_EMPTY_ROWS = "emptyRows";
107 
108     public static final String PROPERTY_NEXT_EDITABLE_ROW_INDEX = "nextEditableRowIndex";
109 
110     public static final String PROPERTY_CAN_EDIT_LENGTH_STEP = "canEditLengthStep";
111 
112     public static final String PROPERTY_CAN_GO_PREV_BATCH = "canGoPrevBatch";
113 
114     public static final String PROPERTY_CAN_GO_NEXT_BATCH = "canGoNextBatch";
115 
116     public static final String PROPERTY_COPY_INDIVIDUAL_OBSERVATION_MODE = "copyIndividualObservationMode";
117 
118     public static final String PROPERTY_COPY_INDIVIDUAL_OBSERVATION_ALL = "copyIndividualObservationAll";
119 
120     public static final String PROPERTY_COPY_INDIVIDUAL_OBSERVATION_NOTHING = "copyIndividualObservationNothing";
121 
122     public static final String PROPERTY_COPY_INDIVIDUAL_OBSERVATION_SIZE = "copyIndividualObservationSize";
123 
124     public static final String PROPERTY_INIT_BATCH_EDITION = "initBatchEdition";
125 
126     public static final String PROPERTY_NON_EMPTY_INDIVIDUAL_OBSERVATION_ROWS_IN_ERROR = "nonEmptyIndividualObservationRowsInError";
127 
128     private final SpeciesOrBenthosBatchUISupport speciesOrBenthosBatchUISupport;
129 
130     /**
131      * Fill mode.
132      *
133      * @since 0.2
134      */
135     private FrequencyConfigurationMode configurationMode;
136 
137     /**
138      * Fill mode.
139      *
140      * @since 4.5
141      */
142     private FrequencyConfigurationMode frequenciesConfigurationMode;
143 
144     /**
145      * Fishing operation of the species batch.
146      *
147      * @since 4.5
148      */
149     private FishingOperation fishingOperation;
150 
151     /**
152      * Batch that contains frequencies.
153      *
154      * @since 0.2
155      */
156     private SpeciesBatchRowModel batch;
157 
158     /**
159      * Default step to addIndividualObservation length step.
160      *
161      * @since 0.2
162      */
163     private Float step;
164 
165     /**
166      * Min step to auto generate length steps.
167      *
168      * @since 0.2
169      */
170     private Float minStep;
171 
172     /**
173      * Max step to auto generate length steps.
174      *
175      * @since 0.2
176      */
177     private Float maxStep;
178 
179     /**
180      * Length step caracteristic.
181      *
182      * @since 0.3
183      */
184     private Caracteristic lengthStepCaracteristic;
185 
186     /**
187      * Sum of the number of each valid row
188      *
189      * @since 2.3
190      */
191     private Integer totalNumber;
192 
193     /**
194      * Sum of the weight of each valid row, or sample weight
195      *
196      * @since 3.8
197      */
198     private ComputableData<Float> totalComputedOrNotWeight;
199 
200     /**
201      * Rtp of the species batch
202      *
203      * @since 4.5
204      */
205     private Rtp rtp;
206 
207     /**
208      * copy the weigths computed with the RTPs of the protocol
209      *
210      * @since 4.5
211      */
212     private boolean copyRtpWeights;
213 
214     /**
215      * Add individual observation rows when a lengthstep is added with the rafale mode
216      *
217      * @since 4.5
218      */
219     private boolean addIndividualObservationOnRafale;
220 
221     /**
222      * Number in case of simple counting mode
223      *
224      * @since 1.0
225      */
226     private Integer simpleCount;
227 
228     /**
229      * The index of the next editable row (null if none).
230      *
231      * @since 2.5
232      */
233     private Integer nextEditableRowIndex;
234 
235     private Set<SpeciesFrequencyRowModel> emptyRows;
236 
237     /**
238      * Sample categories model.
239      *
240      * @since 2.4
241      */
242     private final SampleCategoryModel sampleCategoryModel;
243 
244     /**
245      * Weight unit.
246      *
247      * @since 2.5
248      */
249     private final WeightUnit weightUnit;
250 
251     private final WeightUnit individualObservationWeightUnit;
252 
253     /**
254      * To store all caches used by the screen
255      *
256      * @since 3.11
257      */
258     private final SpeciesFrequencyUIModelCache cache;
259 
260     /**
261      * Can edit length step? (only if no row is filled).
262      * see https://forge.codelutin.com/issues/5694
263      *
264      * @since 3.11
265      */
266     private boolean canEditLengthStep;
267 
268     /**
269      * What to copy from the individual observations to the data table
270      *
271      * @since 4.5
272      */
273     private CopyIndividualObservationMode copyIndividualObservationMode;
274 
275     /**
276      * computed when species change, used to enable or disable menu
277      */
278     private boolean canGoPrevBatch = true;
279 
280     /**
281      * computed when species change, used to enable or disable menu
282      */
283     private boolean canGoNextBatch = true;
284 
285     /**
286      * Is the model is loading?
287      */
288     private boolean initBatchEdition;
289 
290     private final AverageWeightsHistogramModel averageWeightsHistogramModel;
291     private final FrequenciesHistogramModel frequenciesHistogramModel;
292     private final IndividualObservationBatchUIModel individualObservationModel;
293 
294     private final IndividualObservationUICache individualObservationUICache;
295     private final SamplingCodeUICache samplingCodeUICache;
296     private SpeciesFrequencyTableModel frequencyTableModel;
297 
298     private final boolean protocolFilled;
299     private final boolean protocolUseCalcifiedPieceSampling;
300 
301     public SpeciesFrequencyUIModel(SpeciesOrBenthosBatchUISupport speciesOrBenthosBatchUISupport,
302                                    WeightUnit individualObservationWeightUnit,
303                                    SampleCategoryModel sampleCategoryModel,
304                                    Caracteristic sexCaracteristic,
305                                    List<Caracteristic> protocolIndividualObservationCaracteristics,
306                                    CruiseCache cruiseCache,
307                                    Integer cruiseId,
308                                    TuttiProtocol protocol) {
309         super(SpeciesBatchRowModel.class, null, null);
310         this.protocolFilled = protocol != null;
311         this.protocolUseCalcifiedPieceSampling = protocolFilled && protocol.isUseCalcifiedPieceSampling();
312         this.speciesOrBenthosBatchUISupport = speciesOrBenthosBatchUISupport;
313         this.weightUnit = speciesOrBenthosBatchUISupport.getWeightUnit();
314         this.individualObservationWeightUnit = individualObservationWeightUnit;
315         this.sampleCategoryModel = sampleCategoryModel;
316         this.totalComputedOrNotWeight = new ComputableData<>();
317         this.totalComputedOrNotWeight.addPropagateListener(PROPERTY_TOTAL_WEIGHT, this);
318         this.copyIndividualObservationMode = CopyIndividualObservationMode.NOTHING;
319         this.canEditLengthStep = true;
320         this.cache = new SpeciesFrequencyUIModelCache();
321         // default to rafale see https://forge.codelutin.com/issues/8361
322         this.frequenciesConfigurationMode = FrequencyConfigurationMode.RAFALE;
323         setEmptyRows(new HashSet<>());
324 
325         this.individualObservationModel = new IndividualObservationBatchUIModel(this, sexCaracteristic, protocolIndividualObservationCaracteristics);
326         this.averageWeightsHistogramModel = new AverageWeightsHistogramModel(weightUnit);
327         this.frequenciesHistogramModel = new FrequenciesHistogramModel();
328 
329         this.individualObservationUICache = new IndividualObservationUICache(cruiseCache, this);
330         this.samplingCodeUICache = new SamplingCodeUICache(cruiseCache.getSamplingCodeCache(), this, cruiseId);
331 
332     }
333 
334     public SpeciesFrequencyUIModelCache getCache() {
335         return cache;
336     }
337 
338     public SamplingCodeUICache getSamplingCodeUICache() {
339         return samplingCodeUICache;
340     }
341 
342     public IndividualObservationUICache getIndividualObservationUICache() {
343         return individualObservationUICache;
344     }
345 
346     public AverageWeightsHistogramModel getAverageWeightsHistogramModel() {
347         return averageWeightsHistogramModel;
348     }
349 
350     public FrequenciesHistogramModel getFrequenciesHistogramModel() {
351         return frequenciesHistogramModel;
352     }
353 
354     public WeightUnit getWeightUnit() {
355         return weightUnit;
356     }
357 
358     public boolean isInitBatchEdition() {
359         return initBatchEdition;
360     }
361 
362     public void setInitBatchEdition(boolean initBatchEdition) {
363         Object oldValue = isInitBatchEdition();
364         this.initBatchEdition = initBatchEdition;
365         firePropertyChange(PROPERTY_INIT_BATCH_EDITION, oldValue, initBatchEdition);
366     }
367 
368     public void reloadRows() {
369 
370         setEmptyRows(new HashSet<>());
371 
372         cache.loadCache(rows);
373 
374         recomputeRowsValidateState();
375 
376         //FIXME Je préfèrerais ne pas pusher, ...
377         frequenciesHistogramModel.reloadRows(rows);
378         averageWeightsHistogramModel.reloadRows(rows);
379 
380         recomputeTotalNumber();
381         recomputeTotalWeight();
382 
383     }
384 
385     public boolean isRowValid(SpeciesFrequencyRowModel row) {
386 
387         // lengthStepCaracteristic conditions : not null
388         boolean valid = row.getLengthStepCaracteristic() != null;
389 
390         if (valid) {
391 
392             // lengthStep conditions : not null and positive + not found in more than one row
393             Float lengthStep = row.getLengthStep();
394             valid = lengthStep != null
395                     && lengthStep > 0
396                     && cache.numberOfRows(lengthStep) < 2;
397         }
398 
399         if (valid) {
400 
401             // number conditions : number filled
402             valid = row.withNumber();
403 
404         }
405 
406         if (valid) {
407 
408             // weight conditions : with no weight, or weight filled
409             valid = getNbRowsWithWeight() == 0 || row.withWeight();
410 
411         }
412 
413         return valid;
414     }
415 
416     @Override
417     protected SpeciesBatchRowModel newEntity() {
418         return new SpeciesBatchRowModel(weightUnit, sampleCategoryModel);
419     }
420 
421     public FrequencyConfigurationMode getConfigurationMode() {
422         return configurationMode;
423     }
424 
425     public void setConfigurationMode(FrequencyConfigurationMode configurationMode) {
426         Object oldValue = getConfigurationMode();
427         this.configurationMode = configurationMode;
428         firePropertyChange(PROPERTY_FREQUENCIES_MODE, null, isFrequenciesMode());
429         firePropertyChange(PROPERTY_SIMPLE_COUNTING_MODE, null, isSimpleCountingMode());
430         firePropertyChange(PROPERTY_CONFIGURATION_MODE, oldValue, configurationMode);
431     }
432 
433     public FrequencyConfigurationMode getFrequenciesConfigurationMode() {
434         return frequenciesConfigurationMode;
435     }
436 
437     public void setFrequenciesConfigurationMode(FrequencyConfigurationMode frequenciesConfigurationMode) {
438         Object oldValue = getFrequenciesConfigurationMode();
439         this.frequenciesConfigurationMode = frequenciesConfigurationMode;
440         firePropertyChange(PROPERTY_AUTO_GEN_MODE, null, isAutoGenMode());
441         firePropertyChange(PROPERTY_RAFALE_MODE, null, isRafaleMode());
442         firePropertyChange(PROPERTY_FREQUENCIES_CONFIGURATION_MODE, oldValue, getFrequenciesConfigurationMode());
443     }
444 
445     public Float getStep() {
446         return step;
447     }
448 
449     public void setStep(Caracteristic caracteristic) {
450         Float step = null;
451         if (caracteristic != null) {
452             step = caracteristic.getPrecision();
453         }
454         if (step == null) {
455             // on ne met pas 1 c'est la valeur par défaut
456             step = CaracteristicBean.DEFAULT_PRECISION;
457         }
458         setStep(step);
459     }
460 
461     public void setStep(Float step) {
462         Object oldValue = getStep();
463         this.step = step;
464         firePropertyChange(PROPERTY_STEP, oldValue, step);
465     }
466 
467     public Caracteristic getLengthStepCaracteristic() {
468         return lengthStepCaracteristic;
469     }
470 
471     public void setLengthStepCaracteristic(Caracteristic lengthStepCaracteristic) {
472         Object oldValue = getLengthStepCaracteristic();
473         this.lengthStepCaracteristic = lengthStepCaracteristic;
474         firePropertyChange(PROPERTY_LENGTH_STEP_CARACTERISTIC, oldValue, lengthStepCaracteristic);
475         firePropertyChange(PROPERTY_CAN_GENERATE, null, isCanGenerate());
476         firePropertyChange(PROPERTY_LENGTH_STEP_CARACTERISTIC_UNIT, null, getLengthStepCaracteristicUnit());
477     }
478 
479     public String getLengthStepCaracteristicUnit() {
480         return lengthStepCaracteristic == null ? null : lengthStepCaracteristic.getUnit();
481     }
482 
483     public float convertFromMm(float source) {
484         return Numbers.convertFromMm(source, getLengthStepCaracteristicUnit());
485     }
486 
487     public Float getMinStep() {
488         return minStep;
489     }
490 
491     public void setMinStep(Float minStep) {
492         Object oldValue = getMinStep();
493         this.minStep = minStep;
494         firePropertyChange(PROPERTY_MIN_STEP, oldValue, minStep);
495         firePropertyChange(PROPERTY_CAN_GENERATE, null, isCanGenerate());
496     }
497 
498     public Float getMaxStep() {
499         return maxStep;
500     }
501 
502     public void setMaxStep(Float maxStep) {
503         Object oldValue = getMaxStep();
504         this.maxStep = maxStep;
505         firePropertyChange(PROPERTY_MAX_STEP, oldValue, maxStep);
506         firePropertyChange(PROPERTY_CAN_GENERATE, null, isCanGenerate());
507     }
508 
509     public Integer getSimpleCount() {
510         return simpleCount;
511     }
512 
513     public void setSimpleCount(Integer simpleCount) {
514         Object oldValue = getSimpleCount();
515         this.simpleCount = simpleCount;
516         firePropertyChange(PROPERTY_SIMPLE_COUNT, oldValue, simpleCount);
517     }
518 
519     public boolean isCanEditLengthStep() {
520         return canEditLengthStep;
521     }
522 
523     public void setCanEditLengthStep(boolean canEditLengthStep) {
524         Object oldValue = isCanEditLengthStep();
525         this.canEditLengthStep = canEditLengthStep;
526         firePropertyChange(PROPERTY_CAN_EDIT_LENGTH_STEP, oldValue, canEditLengthStep);
527     }
528 
529     public Integer getNextEditableRowIndex() {
530         return nextEditableRowIndex;
531     }
532 
533     public void setNextEditableRowIndex(Integer nextEditableRowIndex) {
534         Object oldValue = getNextEditableRowIndex();
535         this.nextEditableRowIndex = nextEditableRowIndex;
536         firePropertyChange(PROPERTY_NEXT_EDITABLE_ROW_INDEX, oldValue, nextEditableRowIndex);
537     }
538 
539     public boolean isSimpleCountingMode() {
540         return FrequencyConfigurationMode.SIMPLE_COUNTING == configurationMode;
541     }
542 
543     public boolean isFrequenciesMode() {
544         return FrequencyConfigurationMode.FREQUENCIES == configurationMode;
545     }
546 
547     public boolean isAutoGenMode() {
548         return FrequencyConfigurationMode.AUTO_GEN == frequenciesConfigurationMode;
549     }
550 
551     public boolean isRafaleMode() {
552         return FrequencyConfigurationMode.RAFALE == frequenciesConfigurationMode;
553     }
554 
555     public boolean isCanGenerate() {
556         return minStep != null && maxStep != null && maxStep > minStep && lengthStepCaracteristic != null;
557     }
558 
559     public FishingOperation getFishingOperation() {
560         return fishingOperation;
561     }
562 
563     public void setFishingOperation(FishingOperation fishingOperation) {
564         this.fishingOperation = fishingOperation;
565     }
566 
567     public SpeciesBatchRowModel getBatch() {
568         return batch;
569     }
570 
571     public void setBatch(SpeciesBatchRowModel batch) {
572         this.batch = batch;
573         firePropertyChange(PROPERTY_BATCH, null, batch);
574     }
575 
576     public float getLengthStep(float lengthStep) {
577         int intValue = (int) (lengthStep * 10);
578         int intStep = (int) (step * 10);
579         int correctIntStep = intValue - (intValue % intStep);
580         return correctIntStep / 10f;
581     }
582 
583     // FIXME poussin 20160608 ce code est duplique avec le CaracteristicBean#getLengthStepInMm
584     // Il faudrait supprimer le code qui est ici pour utiliser celui de l'objet.
585     //
586     public Integer getLengthStepInMm(Float lengthStep) {
587         Integer lengthClass;
588         
589         Caracteristic c = getLengthStepCaracteristic();
590         if (c != null && c.getPrecision().equals(step)) {
591             lengthClass = c.getLengthStepInMm(lengthStep);
592         } else {
593             // legacy code, here because step and unit can be set independantly :(
594             // this is very strange, and must be refactored (step and unit must
595             // be all time associate via Caracteristic object)
596             if (lengthStep == null) {
597                 lengthClass = null;
598             } else {
599                 int intValue = (int) (lengthStep * 10);
600                 int intStep = (int) (step * 10);
601                 int correctIntStep = intValue - (intValue % intStep);
602                 lengthClass = Numbers.convertToMm(correctIntStep / 10f, getLengthStepCaracteristicUnit());
603             }
604         }
605         return lengthClass;
606     }
607 
608     public Integer getTotalNumber() {
609         return totalNumber;
610     }
611 
612     public void setTotalNumber(Integer totalNumber) {
613         Object oldValue = getTotalNumber();
614         this.totalNumber = totalNumber;
615         firePropertyChange(PROPERTY_TOTAL_NUMBER, oldValue, totalNumber);
616     }
617 
618     public ComputableData<Float> getTotalComputedOrNotWeight() {
619         return totalComputedOrNotWeight;
620     }
621 
622     public Float getTotalWeight() {
623         return totalComputedOrNotWeight.getData();
624     }
625 
626     public void setTotalWeight(Float totalWeight) {
627         Object oldValue = getTotalWeight();
628         this.totalComputedOrNotWeight.setData(weightUnit.round(totalWeight));
629         firePropertyChange(PROPERTY_TOTAL_WEIGHT, oldValue, totalWeight);
630     }
631 
632     public Float getTotalComputedWeight() {
633         return totalComputedOrNotWeight.getComputedData();
634     }
635 
636     public void setTotalComputedWeight(Float totalComputedWeight) {
637         Object oldValue = getTotalComputedWeight();
638         this.totalComputedOrNotWeight.setComputedData(weightUnit.round(totalComputedWeight));
639         firePropertyChange(PROPERTY_TOTAL_COMPUTED_WEIGHT, oldValue, totalComputedWeight);
640     }
641 
642     // Utilisé dans un validateur, ne pas supprimer
643     public boolean isTotalWeightSameAsComputedWeight() {
644         Float totalWeight = getTotalWeight();
645         Float totalComputedWeight = getTotalComputedWeight();
646         return totalWeight != null && totalComputedWeight != null
647                 && WeightUnit.KG.isEquals(totalWeight, totalComputedWeight);
648     }
649 
650     public Rtp getRtp() {
651         return rtp;
652     }
653 
654     public void setRtp(Rtp rtp) {
655         Object oldValue = getRtp();
656         this.rtp = rtp;
657         firePropertyChange(PROPERTY_RTP, oldValue, rtp);
658     }
659 
660     public boolean isCopyRtpWeights() {
661         return copyRtpWeights;
662     }
663 
664     public void setCopyRtpWeights(boolean copyRtpWeights) {
665         boolean oldValue = isCopyRtpWeights();
666         try {
667             fireVetoableChange(PROPERTY_COPY_RTP_WEIGHTS, oldValue, copyRtpWeights);
668             this.copyRtpWeights = copyRtpWeights;
669             firePropertyChange(PROPERTY_COPY_RTP_WEIGHTS, oldValue, copyRtpWeights);
670 
671         } catch (PropertyVetoException e) {
672             if (log.isErrorEnabled()) {
673                 log.error("error in setting copyRtpWeights", e);
674             }
675             firePropertyChange(PROPERTY_COPY_RTP_WEIGHTS, copyRtpWeights, oldValue);
676         }
677     }
678 
679     public CopyIndividualObservationMode getCopyIndividualObservationMode() {
680         return copyIndividualObservationMode;
681     }
682 
683     public void setCopyIndividualObservationMode(CopyIndividualObservationMode copyIndividualObservationMode) {
684         Object oldFrequenciesColor = getFrequenciesColor();
685         Object oldIndividualObservationColor = getIndividualObservationColor();
686 
687         CopyIndividualObservationMode oldValue = getCopyIndividualObservationMode();
688         boolean oldCopyAll = isCopyIndividualObservationAll();
689         boolean oldCopyNothing = isCopyIndividualObservationNothing();
690         boolean oldCopySize = isCopyIndividualObservationSize();
691         this.copyIndividualObservationMode = copyIndividualObservationMode;
692         firePropertyChange(PROPERTY_COPY_INDIVIDUAL_OBSERVATION_ALL, oldCopyAll, isCopyIndividualObservationAll());
693         firePropertyChange(PROPERTY_COPY_INDIVIDUAL_OBSERVATION_NOTHING, oldCopyNothing, isCopyIndividualObservationNothing());
694         firePropertyChange(PROPERTY_COPY_INDIVIDUAL_OBSERVATION_SIZE, oldCopySize, isCopyIndividualObservationSize());
695         firePropertyChange(PROPERTY_COPY_INDIVIDUAL_OBSERVATION_MODE, oldValue, getCopyIndividualObservationMode());
696 
697         firePropertyChange(PROPERTY_FREQUENCIES_COLOR, oldFrequenciesColor, getFrequenciesColor());
698         firePropertyChange(PROPERTY_INDIVIDUAL_OBSERVATION_COLOR, oldIndividualObservationColor, getIndividualObservationColor());
699     }
700 
701     public boolean mustCopyIndividualObservationSize() {
702         return isCopyIndividualObservationAll() || isCopyIndividualObservationSize();
703     }
704 
705     public boolean isCopyIndividualObservationAll() {
706         return CopyIndividualObservationMode.ALL == copyIndividualObservationMode;
707     }
708 
709     public boolean isCopyIndividualObservationNothing() {
710         return CopyIndividualObservationMode.NOTHING == copyIndividualObservationMode;
711     }
712 
713     public boolean isCopyIndividualObservationSize() {
714         return CopyIndividualObservationMode.SIZE == copyIndividualObservationMode;
715     }
716 
717     public boolean isCanGoPrevBatch() {
718         return canGoPrevBatch;
719     }
720 
721     public void setCanGoPrevBatch(boolean canGoPrevBatch) {
722         boolean old = this.canGoPrevBatch;
723         this.canGoPrevBatch = canGoPrevBatch;
724         firePropertyChange(PROPERTY_CAN_GO_PREV_BATCH, old, canGoPrevBatch);
725     }
726 
727     public boolean isCanGoNextBatch() {
728         return canGoNextBatch;
729     }
730 
731     public void setCanGoNextBatch(boolean canGoNextBatch) {
732         boolean old = this.canGoNextBatch;
733         this.canGoNextBatch = canGoNextBatch;
734         firePropertyChange(PROPERTY_CAN_GO_NEXT_BATCH, old, canGoNextBatch);
735     }
736 
737     public Set<SpeciesFrequencyRowModel> getEmptyRows() {
738         return emptyRows;
739     }
740 
741     public void setEmptyRows(Set<SpeciesFrequencyRowModel> emptyRows) {
742         this.emptyRows = emptyRows;
743         firePropertyChange(PROPERTY_EMPTY_ROWS, null, emptyRows);
744     }
745 
746     public boolean isAddIndividualObservationOnRafale() {
747         return addIndividualObservationOnRafale;
748     }
749 
750     public void setAddIndividualObservationOnRafale(boolean addIndividualObservationOnRafale) {
751         Object oldFrequenciesColor = getFrequenciesColor();
752         Object oldIndividualObservationColor = getIndividualObservationColor();
753 
754         Object oldValue = isAddIndividualObservationOnRafale();
755         this.addIndividualObservationOnRafale = addIndividualObservationOnRafale;
756         firePropertyChange(PROPERTY_ADD_INDIVIDUAL_OBSERVATION_ON_RAFALE, oldValue, addIndividualObservationOnRafale);
757 
758         firePropertyChange(PROPERTY_FREQUENCIES_COLOR, oldFrequenciesColor, getFrequenciesColor());
759         firePropertyChange(PROPERTY_INDIVIDUAL_OBSERVATION_COLOR, oldIndividualObservationColor, getIndividualObservationColor());
760     }
761 
762     public Color getFrequenciesColor() {
763         Color result = javax.swing.UIManager.getColor("JXTitledPanel.titleBackground");
764         if (isAddIndividualObservationOnRafale()) {
765             if (isCopyIndividualObservationAll()) {
766                 result = Color.GREEN;
767             } else if (isCopyIndividualObservationSize()) {
768                 result = new Color(0, 255, 140);
769             }
770         } else {
771             result = Color.GREEN;
772         }
773         return result;
774     }
775     
776     public Color getIndividualObservationColor() {
777         Color result = javax.swing.UIManager.getColor("JXTitledPanel.titleBackground");
778         if (isAddIndividualObservationOnRafale()) {
779             result = Color.GREEN;
780         }
781         return result;
782     }
783 
784     public int getNbRowsWithWeight() {
785         return cache.getNbRowsWithWeight();
786     }
787 
788     public boolean isSomeRowsWithWeightAndOtherWithout() {
789 
790         boolean result;
791 
792         if (CollectionUtils.isEmpty(rows)) {
793 
794             // no row
795             result = false;
796 
797         } else {
798 
799             // there is some rows
800 
801             int nbNoneEmptyRows = 0;
802             int nbNoneEmptyRowsWithWeight = 0;
803 
804             for (SpeciesFrequencyRowModel row : rows) {
805 
806                 if (row.isEmpty()) {
807 
808                     // no value on rows, no check on it
809                     continue;
810                 }
811 
812                 nbNoneEmptyRows++;
813 
814                 if (row.getWeight() != null) {
815 
816                     nbNoneEmptyRowsWithWeight++;
817 
818                 }
819 
820             }
821 
822             result = nbNoneEmptyRowsWithWeight > 0 && nbNoneEmptyRows != nbNoneEmptyRowsWithWeight;
823 
824         }
825 
826         return result;
827 
828     }
829 
830     public void updateEmptyRow(SpeciesFrequencyRowModel row) {
831         if (row.isValid() && row.getNumber() == null && row.getWeight() == null) {
832             emptyRows.add(row);
833         } else {
834             emptyRows.remove(row);
835         }
836         firePropertyChange(PROPERTY_EMPTY_ROWS, null, emptyRows);
837     }
838 
839     public void recomputeTotalWeight() {
840 
841         Float computeTotalWeight = cache.computeTotalWeight();
842         setTotalComputedWeight(computeTotalWeight);
843 
844     }
845 
846     public void recomputeTotalNumber() {
847 
848         int computeTotalNumber = 0;
849         if (rows != null) {
850             for (SpeciesFrequencyRowModel row : rows) {
851                 if (!row.isValid()) {
852                     continue;
853                 }
854                 if (row.getNumber() != null) {
855                     computeTotalNumber += row.getNumber();
856                 }
857             }
858         }
859         setTotalNumber(computeTotalNumber);
860 
861     }
862 
863     public void recomputeCanEditLengthStep() {
864 
865         boolean result = frequencyTableModel.recomputeCanEditLengthStep();
866 
867         if (result) {
868             result = individualObservationModel.recomputeCanEditLengthStep();
869         }
870 
871         setCanEditLengthStep(result);
872 
873     }
874 
875     public void computeRowWeightWithRtp() {
876         rows.forEach(this::computeRowWeightWithRtp);
877     }
878 
879     public void computeRowWeightWithRtp(SpeciesFrequencyRowModel row) {
880 
881         Float computedWeight = null;
882 
883         if (row.withNumber() && row.getLengthStep() != null && withRtp()) {
884             // computedWeightForLengthStep in grams
885             float computedWeightForLengthStep = Weights.computeWithRtp(getRtp(), row.getLengthStep(), getLengthStepCaracteristicUnit());
886             computedWeight = Weights.convert(WeightUnit.G, weightUnit, row.getNumber() * computedWeightForLengthStep);
887         }
888 
889         row.setRtpComputedWeight(computedWeight);
890 
891         if (isCopyRtpWeights() && !isCopyIndividualObservationAll()) {
892             row.setWeight(computedWeight);
893         }
894 
895     }
896 
897     public boolean withRtp() {
898         return rtp != null;
899     }
900 
901     public void recomputeRowsValidateState() {
902 
903         if (log.isInfoEnabled()) {
904             log.info("Revalidate all frequency rows");
905         }
906 
907         rowsInError.clear();
908 
909         rows.forEach(row -> {
910             // recompute row valid state
911             boolean valid = isRowValid(row);
912 
913             // apply it to row
914             row.setValid(valid);
915             if (!valid) {
916                 rowsInError.add(row);
917             }
918 
919         });
920 
921         firePropertyChange(PROPERTY_ROWS_IN_ERROR, null, rowsInError);
922 
923     }
924 
925     protected final void recomputeRowValidState(SpeciesFrequencyRowModel row) {
926 
927         // recompute row valid state
928         boolean valid = isRowValid(row);
929 
930         // apply it to row
931         row.setValid(valid);
932 
933         if (valid) {
934             removeRowInError(row);
935         } else {
936             addRowInError(row);
937         }
938 
939     }
940 
941     public SpeciesOrBenthosBatchUISupport getSpeciesOrBenthosBatchUISupport() {
942         return speciesOrBenthosBatchUISupport;
943     }
944 
945     public WeightUnit getIndividualObservationWeightUnit() {
946         return individualObservationWeightUnit;
947     }
948 
949     public IndividualObservationBatchUIModel getIndividualObservationModel() {
950         return individualObservationModel;
951     }
952 
953     private boolean nonEmptyIndividualObservationRowsInError;
954 
955     // Ne pas supprimer utiliser par la validation
956     public boolean isNonEmptyIndividualObservationRowsInError() {
957         return nonEmptyIndividualObservationRowsInError;
958     }
959 
960     // Ne pas supprimer utiliser par la validation
961     public void setNonEmptyIndividualObservationRowsInError(boolean nonEmptyIndividualObservationRowsInError) {
962         boolean oldValue = isNonEmptyIndividualObservationRowsInError();
963         this.nonEmptyIndividualObservationRowsInError = nonEmptyIndividualObservationRowsInError;
964         firePropertyChanged(PROPERTY_NON_EMPTY_INDIVIDUAL_OBSERVATION_ROWS_IN_ERROR, oldValue, nonEmptyIndividualObservationRowsInError);
965     }
966 
967     public void clear() {
968 
969         setRows(new ArrayList<>());
970 
971         recomputeCanEditLengthStep();
972 
973     }
974 
975     public IndividualObservationSamplingCacheRequest toSamplingCacheRequest(IndividualObservationBatchRowModel row) {
976         return new IndividualObservationSamplingCacheRequest(fishingOperation,
977                                                              row.getSpecies(),
978                                                              getLengthStepInMm(row.getSize()),
979                                                              individualObservationModel.getMaturityValue(row),
980                                                              individualObservationModel.getGender(row),
981                                                              row.getSamplingCode());
982     }
983 
984     public void addIndividualObservationsInCache(List<IndividualObservationBatchRowModel> individualObservations) {
985 
986         individualObservationUICache.addIndividualObservations(individualObservations);
987         samplingCodeUICache.addIndividualObservations(individualObservations);
988 
989     }
990 
991     public List<IndividualObservationBatchRowModel> getValidIndividualObservations() {
992 
993         List<IndividualObservationBatchRowModel> result = new ArrayList<>(individualObservationModel.getRows());
994         result.removeAll(individualObservationModel.getRowsInError());
995         return result;
996 
997     }
998 
999     public void setFrequencyTableModel(SpeciesFrequencyTableModel frequencyTableModel) {
1000         this.frequencyTableModel = frequencyTableModel;
1001     }
1002 
1003     public SpeciesFrequencyTableModel getFrequencyTableModel() {
1004         return frequencyTableModel;
1005     }
1006 
1007     public boolean isProtocolFilled() {
1008         return protocolFilled;
1009     }
1010 
1011     public boolean isProtocolUseCalcifiedPieceSampling() {
1012         return protocolUseCalcifiedPieceSampling;
1013     }
1014 
1015 
1016     public void loadSpeciesBatch(SpeciesBatchRowModel speciesBatch) {
1017 
1018         Integer number = speciesBatch.getNumber();
1019         setSimpleCount(number);
1020 
1021         setTotalNumber(null);
1022         setTotalComputedWeight(null);
1023         setTotalWeight(null);
1024 
1025         setTotalWeight(speciesBatch.getWeight());
1026 
1027     }
1028 
1029     public FrequencyConfigurationMode guessFrequencyConfigurationMode() {
1030 
1031         FrequencyConfigurationMode mode;
1032         if (getSimpleCount() != null || lengthStepCaracteristic == null) {
1033 
1034             mode = FrequencyConfigurationMode.SIMPLE_COUNTING;
1035 
1036         } else {
1037 
1038             mode = FrequencyConfigurationMode.FREQUENCIES;
1039 
1040         }
1041         return mode;
1042 
1043     }
1044 }