View Javadoc
1   package fr.ifremer.dali.ui.swing.content.extraction.filters;
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 com.google.common.collect.Lists;
27  import fr.ifremer.dali.dto.DaliBeanFactory;
28  import fr.ifremer.dali.dto.DaliBeans;
29  import fr.ifremer.dali.dto.configuration.filter.FilterDTO;
30  import fr.ifremer.dali.dto.configuration.programStrategy.ProgramDTO;
31  import fr.ifremer.dali.dto.enums.ExtractionFilterTypeValues;
32  import fr.ifremer.dali.dto.referential.pmfm.PmfmDTO;
33  import fr.ifremer.dali.dto.system.extraction.ExtractionParameterDTO;
34  import fr.ifremer.dali.dto.system.extraction.ExtractionPeriodDTO;
35  import fr.ifremer.dali.dto.system.extraction.FilterTypeDTO;
36  import fr.ifremer.dali.dto.system.extraction.PmfmPresetDTO;
37  import fr.ifremer.dali.service.DaliTechnicalException;
38  import fr.ifremer.dali.ui.swing.content.extraction.ExtractionUI;
39  import fr.ifremer.dali.ui.swing.content.extraction.filters.period.ExtractionPeriodUI;
40  import fr.ifremer.dali.ui.swing.content.manage.filter.select.SelectFilterUI;
41  import fr.ifremer.dali.ui.swing.util.table.AbstractDaliTableModel;
42  import fr.ifremer.dali.ui.swing.util.table.AbstractDaliTableUIHandler;
43  import fr.ifremer.quadrige3.core.dao.technical.Assert;
44  import fr.ifremer.quadrige3.ui.core.dto.QuadrigeBean;
45  import fr.ifremer.quadrige3.ui.swing.table.SwingTable;
46  import jaxx.runtime.SwingUtil;
47  import org.apache.commons.logging.Log;
48  import org.apache.commons.logging.LogFactory;
49  import org.jdesktop.swingx.table.TableColumnExt;
50  
51  import javax.swing.JOptionPane;
52  import javax.swing.SwingUtilities;
53  import javax.swing.SwingWorker;
54  import java.awt.Dimension;
55  import java.awt.event.MouseAdapter;
56  import java.awt.event.MouseEvent;
57  import java.util.Collection;
58  import java.util.List;
59  import java.util.Map;
60  import java.util.Set;
61  import java.util.concurrent.ExecutionException;
62  import java.util.stream.Collectors;
63  
64  import static org.nuiton.i18n.I18n.t;
65  
66  /**
67   * Controller pour le tableau des observations.
68   */
69  public class ExtractionFiltersUIHandler extends
70          AbstractDaliTableUIHandler<ExtractionFiltersRowModel, ExtractionFiltersUIModel, ExtractionFiltersUI> {
71  
72      /**
73       * Logger.
74       */
75      private static final Log LOG = LogFactory.getLog(ExtractionFiltersUIHandler.class);
76      private FilterLoader filterLoader = new FilterLoader();
77  
78      /**
79       * {@inheritDoc}
80       */
81      @Override
82      public void beforeInit(final ExtractionFiltersUI ui) {
83          super.beforeInit(ui);
84  
85          // create model and register to the JAXX context
86          final ExtractionFiltersUIModel model = new ExtractionFiltersUIModel();
87          ui.setContextValue(model);
88      }
89  
90      /**
91       * {@inheritDoc}
92       */
93      @Override
94      public void afterInit(final ExtractionFiltersUI ui) {
95  
96          // Initialisation de l ecran
97          initUI(ui);
98  
99          // Initialisation du tableau
100         initTable();
101         SwingUtil.setLayerUI(ui.getExtractionsFiltersScrollPane(), ui.getTableBlockLayer());
102 
103         // Initialisation des listeners
104         initListeners();
105 
106         // first load (empty filters)
107         loadFilters();
108     }
109 
110     /**
111      * Initialisation du tableau.
112      */
113     private void initTable() {
114 
115         // filter type
116         TableColumnExt filterTypeCol = addColumn(ExtractionFiltersTableModel.FILTER_TYPE);
117         fixColumnWidth(filterTypeCol, 150);
118 
119         // filter
120         addColumn(
121                 null,
122                 new FilterElementsCellRenderer(getContext().getDecoratorService()),
123                 ExtractionFiltersTableModel.FILTER);
124 
125         ExtractionFiltersTableModel tableModel = new ExtractionFiltersTableModel(getTable().getColumnModel());
126         getTable().setModel(tableModel);
127 
128         // Initialisation du tableau
129         initTable(getTable(), true);
130 
131         // no sort
132         getTable().setSortable(false);
133         getTable().setEditable(false);
134 
135         // border
136         addEditionPanelBorder();
137 
138         // add double click auto edit line
139         getTable().addMouseListener(new MouseAdapter() {
140 
141             @Override
142             public void mouseClicked(MouseEvent e) {
143                 if (e.getClickCount() == 2) {
144                     getUI().getEditFilterButton().doClick();
145                 }
146             }
147         });
148 
149     }
150 
151     private void initListeners() {
152 
153     }
154 
155     /**
156      * {@inheritDoc}
157      */
158     @Override
159     protected boolean isRowValid(ExtractionFiltersRowModel row) {
160         return getModel().getSelectedExtraction() == null || (super.isRowValid(row) && isFilterValid(row));
161     }
162 
163     private boolean isFilterValid(ExtractionFiltersRowModel row) {
164 
165         row.getErrors().clear();
166         ExtractionFilterTypeValues extractionFilter = ExtractionFilterTypeValues.getExtractionFilterType(row.getFilterTypeId());
167         Assert.notNull(extractionFilter);
168 
169         switch (extractionFilter) {
170             case PERIOD:
171                 if (row.isFilterEmpty()) {
172                     DaliBeans.addError(row, t("dali.extraction.filters.error.period.empty.message"), ExtractionFiltersRowModel.PROPERTY_FILTER);
173                 }
174                 break;
175 
176             case PROGRAM:
177                 if (row.isFilterEmpty()) {
178                     DaliBeans.addError(row, t("dali.extraction.filters.error.program.empty.message"), ExtractionFiltersRowModel.PROPERTY_FILTER);
179                 }
180                 break;
181 
182         }
183 
184         return row.getErrors().isEmpty();
185     }
186 
187     /**
188      * {@inheritDoc}
189      */
190     @Override
191     public AbstractDaliTableModel<ExtractionFiltersRowModel> getTableModel() {
192         return (ExtractionFiltersTableModel) getTable().getModel();
193     }
194 
195     /**
196      * {@inheritDoc}
197      */
198     @Override
199     public SwingTable getTable() {
200         return ui.getExtractionsFiltersTable();
201     }
202 
203     /**
204      * <p>loadFilters.</p>
205      */
206     public void loadFilters() {
207 
208         if (!filterLoader.isDone()) {
209             filterLoader.cancel(true);
210         }
211 
212         getModel().setLoading(true);
213         filterLoader = new FilterLoader();
214         filterLoader.execute();
215     }
216 
217     /**
218      * <p>editFilter.</p>
219      */
220     @SuppressWarnings("unchecked")
221     public void editFilter() {
222 
223         final ExtractionFiltersRowModel rowModel = getModel().getSingleSelectedRow();
224 
225         if (rowModel == null) {
226             LOG.warn("no filter selected");
227             return;
228         }
229 
230         SwingUtilities.invokeLater(() -> {
231 
232             if (ExtractionFilterTypeValues.getExtractionFilterType(rowModel.getFilterTypeId()) == ExtractionFilterTypeValues.PERIOD) {
233 
234                 // open period editor
235                 ExtractionPeriodUI periodUI = new ExtractionPeriodUI(getContext());
236                 periodUI.getModel().setBeans((Collection<ExtractionPeriodDTO>) rowModel.getFilteredElements());
237                 periodUI.getHandler().recomputeRowsValidState(false);
238                 openDialog(periodUI);
239 
240                 // affect to model if valid
241                 if (periodUI.getModel().isValid()) {
242                     FilterDTO periodFilter = rowModel.getFilter();
243                     if (periodFilter == null) {
244                         periodFilter = DaliBeanFactory.newFilterDTO();
245                         periodFilter.setFilterTypeId(ExtractionFilterTypeValues.PERIOD.getFilterTypeId());
246                     }
247 
248                     List<ExtractionPeriodDTO> newPeriods = periodUI.getModel().getBeans();
249 
250                     if (isPmfmsConfigValid(
251                             DaliBeans.getFilterElementsIds(getModel().getSelectedExtraction(), ExtractionFilterTypeValues.PROGRAM),
252                             newPeriods)) {
253 
254                         // Filter is valid with extraction parameter : save it
255                         periodFilter.setElements(newPeriods);
256                         rowModel.setFilter(periodFilter);
257                         getModel().getSelectedExtraction().replaceFilter(periodFilter);
258                     }
259 
260                 }
261 
262             } else {
263 
264                 // open filter ui
265                 SelectFilterUI filterUI = new SelectFilterUI(getContext(), rowModel.getFilterTypeId());
266                 filterUI.getModel().setSelectedElements(rowModel.getFilteredElements());
267                 filterUI.setTitle(t("dali.extraction.filters.select.title", decorate(rowModel.getFilterType())));
268                 openDialog(filterUI, new Dimension(1000, 600));
269 
270                 if (filterUI.getModel().isValid()) {
271                     FilterDTO filter = rowModel.getFilter();
272                     if (filter == null) {
273                         filter = DaliBeanFactory.newFilterDTO();
274                         filter.setFilterTypeId(rowModel.getFilterTypeId());
275                     }
276 
277                     List<? extends QuadrigeBean> newValue = filterUI.getModel().getSelectedElements();
278                     boolean valid = true;
279 
280                     if (filter.getFilterTypeId().equals(ExtractionFilterTypeValues.PROGRAM.getFilterTypeId())) {
281                         // validate program filter with extraction parameter
282                         valid = isPmfmsConfigValid(
283                                 newValue.stream().map(bean -> ((ProgramDTO) bean).getCode()).collect(Collectors.toList()),
284                                 DaliBeans.getExtractionPeriods(getModel().getSelectedExtraction()));
285                     }
286 
287                     if (valid) {
288                         rowModel.setFilter(filter);
289                         filter.setFilterLoaded(true);
290                         filter.setElements(newValue);
291                         filter.setDirty(true);
292                         getModel().getSelectedExtraction().replaceFilter(filter);
293                     }
294                 }
295 
296             }
297 
298             recomputeRowsValidState();
299             getModel().firePropertyChanged(ExtractionFiltersUIModel.PROPERTY_VALID, null, getModel().isValid());
300             getTable().repaint();
301 
302         });
303 
304     }
305 
306     /**
307      * Check pmfms from configuration (if exists)
308      *
309      * @param programCodes program codes
310      * @param periods      periods
311      */
312     private boolean isPmfmsConfigValid(Collection<String> programCodes, Collection<ExtractionPeriodDTO> periods) {
313 
314         if (getModel().getSelectedExtraction().getParameter() == null) return true;
315 
316         ExtractionParameterDTO parameter = getModel().getSelectedExtraction().getParameter();
317 
318         // get all pmfm strategies for the actual filters
319         Set<PmfmDTO> allPmfms = getParentContainer(ExtractionUI.class).getHandler().getPmfmsForSelectedExtraction(programCodes, periods);
320 
321         boolean valid = parameter.getPmfmPresets().stream().map(PmfmPresetDTO::getPmfm).allMatch(allPmfms::contains)
322                 && allPmfms.containsAll(parameter.getPmfmResults());
323 
324         if (!valid) {
325             if (getContext().getDialogHelper().showConfirmDialog(
326                     t("dali.extraction.filters.invalidParameter.message"),
327                     t("dali.extraction.filters.title"),
328                     JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
329 
330                 // Reset current parameter and continue
331                 getModel().getSelectedExtraction().setParameter(null);
332                 getParentContainer(ExtractionUI.class).getConfigUI().getHandler().loadConfig();
333                 return true;
334             } else {
335 
336                 // User cancel
337                 return false;
338             }
339         } else {
340 
341             // Pmfms config is valid
342             return true;
343         }
344 
345     }
346 
347     private List<FilterTypeDTO> getFilterTypes() {
348         if (getModel().getFilterTypes() == null) {
349             getModel().setFilterTypes(getContext().getExtractionService().getFilterTypes());
350         }
351         return getModel().getFilterTypes();
352     }
353 
354     private class FilterLoader extends SwingWorker<List<ExtractionFiltersRowModel>, Void> {
355 
356         @Override
357         protected List<ExtractionFiltersRowModel> doInBackground() {
358             List<ExtractionFiltersRowModel> rows = Lists.newArrayList();
359             Map<Integer, FilterDTO> filtersByFilterTypeId = null;
360             if (getModel().getSelectedExtraction() != null) {
361                 // load filters
362                 getContext().getExtractionService().loadFilteredElements(getModel().getSelectedExtraction());
363                 // split by filter type id
364                 filtersByFilterTypeId = DaliBeans.mapByProperty(getModel().getSelectedExtraction().getFilters(), FilterDTO.PROPERTY_FILTER_TYPE_ID);
365             }
366 
367             for (FilterTypeDTO filterType : getFilterTypes()) {
368                 ExtractionFiltersRowModel rowModel = getTableModel().createNewRow();
369                 rowModel.setValid(true);
370                 rowModel.setFilterType(filterType);
371 
372                 if (filtersByFilterTypeId != null) {
373                     rowModel.setFilter(filtersByFilterTypeId.get(filterType.getId()));
374                 }
375 
376                 rows.add(rowModel);
377             }
378 
379             return rows;
380         }
381 
382         @Override
383         protected void done() {
384             try {
385                 if (isCancelled()) {
386                     return;
387                 }
388                 List<ExtractionFiltersRowModel> rows = get();
389                 getModel().setLoading(true);
390                 getTable().setVisibleRowCount(rows.size());
391                 getModel().setRows(rows);
392                 recomputeRowsValidState();
393                 if (rowsHaveFilteredElements(rows)) {
394                     getModel().firePropertyChanged(ExtractionFiltersUIModel.PROPERTY_VALID, null, getModel().isValid());
395                 }
396 
397             } catch (InterruptedException | ExecutionException e) {
398                 throw new DaliTechnicalException(e.getMessage(), e);
399             } finally {
400                 getModel().setLoading(false);
401             }
402         }
403 
404         private boolean rowsHaveFilteredElements(List<ExtractionFiltersRowModel> rows) {
405             for (ExtractionFiltersRowModel row : rows) {
406                 if (!row.isFilterEmpty()) return true;
407             }
408             return false;
409         }
410     }
411 }