View Javadoc
1   package fr.ifremer.reefdb.ui.swing.content.observation.shared;
2   
3   /*
4    * #%L
5    * Reef DB :: 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 com.google.common.collect.ImmutableList;
27  import fr.ifremer.quadrige3.core.dao.technical.Assert;
28  import fr.ifremer.quadrige3.ui.swing.table.SwingTable;
29  import fr.ifremer.quadrige3.ui.swing.table.state.SwingTableSessionState;
30  import fr.ifremer.reefdb.dto.ReefDbBeanFactory;
31  import fr.ifremer.reefdb.dto.ReefDbBeans;
32  import fr.ifremer.reefdb.dto.data.measurement.MeasurementAware;
33  import fr.ifremer.reefdb.dto.data.measurement.MeasurementDTO;
34  import fr.ifremer.reefdb.dto.referential.pmfm.PmfmDTO;
35  import fr.ifremer.reefdb.ui.swing.util.ReefDbUI;
36  import fr.ifremer.reefdb.ui.swing.util.table.ReefDbColumnIdentifier;
37  import fr.ifremer.reefdb.ui.swing.util.table.renderer.MultipleValueCellRenderer;
38  import jaxx.runtime.swing.session.State;
39  import org.nuiton.jaxx.application.swing.util.Cancelable;
40  
41  import javax.swing.table.TableColumn;
42  import java.util.ArrayList;
43  import java.util.List;
44  import java.util.Objects;
45  
46  /**
47   * abstract handler for multiline edition
48   */
49  public abstract class AbstractMeasurementsMultiEditUIHandler<
50      R extends AbstractMeasurementsGroupedRowModel<MeasurementDTO, R>,
51      M extends AbstractMeasurementsMultiEditUIModel<MeasurementDTO, R, M>,
52      UI extends ReefDbUI<M, ?>
53      >
54      extends AbstractMeasurementsGroupedTableUIHandler<R, M, UI>
55      implements Cancelable {
56  
57      /**
58       * <p>Constructor for AbstractMeasurementsMultiEditUIHandler.</p>
59       */
60      public AbstractMeasurementsMultiEditUIHandler() {
61          super(R.PROPERTY_TAXON_GROUP,
62              R.PROPERTY_TAXON,
63              R.PROPERTY_INDIVIDUAL_PMFMS,
64              R.PROPERTY_COMMENT);
65      }
66  
67      /**
68       * get the referent table for columns adjustments
69       *
70       * @return the referent table
71       */
72      protected abstract SwingTable getReferentTable();
73  
74      /**
75       * Don't really build rows but create a multi edit row
76       *
77       * @param readOnly readOnly
78       * @return rows from model
79       */
80      @Override
81      protected List<R> buildRows(boolean readOnly) {
82  
83          if (getModel().getRowsToEdit().isEmpty())
84              return null;
85  
86          // Create a ghost row without parent
87          R multiEditRow = createNewRow(readOnly, null);
88          multiEditRow.setIndividualPmfms(new ArrayList<>(getModel().getPmfms()));
89          ReefDbBeans.createEmptyMeasurements(multiEditRow);
90  
91          boolean firstRow = true;
92          for (R row : getModel().getRowsToEdit()) {
93  
94              // find multiple value on each known columns
95              findMultipleValueOnIdentifier(row, multiEditRow, firstRow);
96  
97              // find multiple value on each measurement
98              findMultipleValueOnPmfmIdentifier(row, multiEditRow, firstRow);
99  
100             firstRow = false;
101         }
102 
103         overrideColumnRenderersAndEditors(multiEditRow);
104 
105         overrideColumnWidthAndPosition();
106 
107         return ImmutableList.of(multiEditRow);
108     }
109 
110     // detect multiple values on each column
111     private void findMultipleValueOnIdentifier(R row, R multiEditRow, boolean firstRow) {
112 
113         for (ReefDbColumnIdentifier<R> identifier : getModel().getIdentifiersToCheck()) {
114             if (!multiEditRow.getMultipleValuesOnIdentifier().contains(identifier)) {
115                 if (!Objects.equals(identifier.getValue(row), identifier.getValue(multiEditRow))) {
116                     if (firstRow) {
117                         // on first row, consider a unique value
118                         identifier.setValue(multiEditRow, identifier.getValue(row));
119                     } else {
120                         // on other rows, if the value differs, set it as multiple
121                         identifier.setValue(multiEditRow, null);
122                         multiEditRow.addMultipleValuesOnIdentifier(identifier);
123                     }
124                 }
125             }
126         }
127     }
128 
129     // detect multiple values on each pmfm column
130     private void findMultipleValueOnPmfmIdentifier(R row, R multiEditRow, boolean firstRow) {
131 
132         for (PmfmDTO pmfm : getModel().getPmfms()) {
133             if (!multiEditRow.getMultipleValuesOnPmfmIds().contains(pmfm.getId())) {
134                 MeasurementDTO multiMeasurement = ReefDbBeans.getIndividualMeasurementByPmfmId(multiEditRow, pmfm.getId());
135                 Assert.notNull(multiMeasurement, "should be already present");
136                 MeasurementDTO measurement = ReefDbBeans.getIndividualMeasurementByPmfmId(row, pmfm.getId());
137                 if (measurement == null) {
138                     // create ghost measurement
139                     measurement = ReefDbBeanFactory.newMeasurementDTO();
140                     measurement.setPmfm(pmfm);
141                 }
142 
143                 if (!ReefDbBeans.measurementValuesEquals(multiMeasurement, measurement)) {
144                     if (firstRow) {
145                         // on first row, consider a unique value
146                         multiMeasurement.setNumericalValue(measurement.getNumericalValue());
147                         multiMeasurement.setQualitativeValue(measurement.getQualitativeValue());
148                     } else {
149                         // on other rows, if the value differs, set it as multiple
150                         multiMeasurement.setNumericalValue(null);
151                         multiMeasurement.setQualitativeValue(null);
152                         multiEditRow.addMultipleValuesOnPmfmId(pmfm.getId());
153                     }
154                 }
155             }
156         }
157     }
158 
159     /**
160      * Override all column renderers with specific behavior if multiple values is found
161      *
162      * @param multiEditRow
163      */
164     private void overrideColumnRenderersAndEditors(R multiEditRow) {
165 
166         multiEditRow.getMultipleValuesOnIdentifier().forEach(identifier -> {
167             TableColumn col = getTable().getColumnExt(identifier);
168             // override the renderer
169             col.setCellRenderer(new MultipleValueCellRenderer(col.getCellRenderer()));
170         });
171         multiEditRow.getMultipleValuesOnPmfmIds().forEach(pmfmId ->
172             getModel().getPmfmColumns().stream().filter(pmfmTableColumn -> pmfmTableColumn.getPmfmId() == pmfmId).findFirst()
173                 .ifPresent(pmfmTableColumn -> {
174                         // override the renderer
175                         pmfmTableColumn.setCellRenderer(new MultipleValueCellRenderer(pmfmTableColumn.getCellRenderer()));
176                         // and set not editable if the pmfm is set as read-only
177                         if (getModel().getReadOnlyPmfmIds().contains(pmfmId))
178                             pmfmTableColumn.setEditable(false);
179                     }
180                 ));
181     }
182 
183     private void overrideColumnWidthAndPosition() {
184 
185         // get the state of the referent table
186         State referentState = getContext().getSwingSession().findStateByComponentName(".*" + getReferentTable().getName());
187 
188         // apply this state to the current table
189         if (referentState instanceof SwingTableSessionState) {
190             referentState.setState(getTable(), referentState);
191         }
192     }
193 
194     @Override
195     protected void onRowsAdded(List<R> addedRows) {
196         // Don't call super method because the row is already initialized in buildRows()
197 //        super.onRowsAdded(addedRows);
198     }
199 
200     @Override
201     protected List<? extends MeasurementAware> getMeasurementAwareModels() {
202         // nothing to return, this handler don't save model
203         return null;
204     }
205 
206     @Override
207     protected MeasurementAware getMeasurementAwareModelForRow(R row) {
208         // nothing to return, this handler don't save model
209         return null;
210     }
211 
212     @Override
213     protected void filterMeasurements() {
214     }
215 
216     public void valid() {
217         if (getModel().isValid()) {
218             closeDialog();
219         }
220     }
221 
222     @Override
223     public void cancel() {
224         stopListenValidatorValid(getValidator());
225         getModel().setValid(false);
226         closeDialog();
227     }
228 
229 }