View Javadoc
1   package fr.ifremer.quadrige3.ui.swing.action;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 UI Common
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 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.base.Preconditions;
27  import com.google.common.collect.Lists;
28  import fr.ifremer.quadrige3.core.config.QuadrigeCoreConfiguration;
29  import fr.ifremer.quadrige3.core.dao.technical.Assert;
30  import fr.ifremer.quadrige3.ui.swing.AbstractUIHandler;
31  import fr.ifremer.quadrige3.ui.swing.ApplicationUI;
32  import fr.ifremer.quadrige3.ui.swing.ApplicationUIContext;
33  import fr.ifremer.quadrige3.ui.swing.content.AbstractMainUIHandler;
34  import fr.ifremer.quadrige3.ui.swing.content.login.AuthenticationAction;
35  import fr.ifremer.quadrige3.ui.swing.model.ProgressionUIModel;
36  import org.apache.commons.collections4.CollectionUtils;
37  import org.apache.commons.lang3.StringUtils;
38  import org.apache.commons.logging.Log;
39  import org.apache.commons.logging.LogFactory;
40  import org.jdesktop.beans.AbstractBean;
41  import org.nuiton.jaxx.application.swing.action.AbstractApplicationAction;
42  import org.nuiton.jaxx.application.type.ApplicationProgressionModel;
43  import org.springframework.security.access.AccessDeniedException;
44  import org.springframework.security.core.AuthenticationException;
45  
46  import java.awt.Component;
47  import java.io.File;
48  import java.util.Arrays;
49  import java.util.List;
50  
51  import static org.nuiton.i18n.I18n.t;
52  
53  /**
54   * Application base action.
55   *
56   * @param <M>
57   * @param <UI>
58   * @param <H>
59   * @author Lionel Touseau <lionel.touseau@e-is.pro>
60   * @since 1.0
61   */
62  public abstract class AbstractAction<M extends AbstractBean, UI extends ApplicationUI<M, ?>, H extends AbstractUIHandler<M, UI>>
63          extends AbstractApplicationAction<M, UI, H> {
64  
65      private static final Log LOG = LogFactory.getLog(AbstractAction.class);
66      private static ProgressionUIModel progressionModel;
67  
68      private List<String> errorMessages;
69      private ApplicationProgressionModelWrapper progressionModelWrapper;
70  
71      /**
72       * <p>Constructor for AbstractAction.</p>
73       *
74       * @param handler  a H object.
75       * @param hideBody a boolean.
76       */
77      public AbstractAction(H handler, boolean hideBody) {
78          super(handler, hideBody);
79      }
80  
81      /**
82       * {@inheritDoc}
83       */
84      @Override
85      public ApplicationUIContext getContext() {
86          return getHandler().getContext();
87      }
88  
89      @Override
90      @Deprecated
91      public void setProgressionModel(ApplicationProgressionModel progressionModel) {
92          super.setProgressionModel(progressionModel);
93      }
94  
95      /**
96       * <p>setProgressionUIModel.</p>
97       *
98       * @param progressionModel a {@link ProgressionUIModel} object.
99       */
100     public void setProgressionUIModel(ProgressionUIModel progressionModel) {
101         AbstractAction.progressionModel = progressionModel;
102         this.progressionModelWrapper = progressionModel != null
103                 ? new ApplicationProgressionModelWrapper(progressionModel)
104                 : null;
105         super.setProgressionModel(progressionModelWrapper);
106     }
107 
108     /**
109      * {@inheritDoc}
110      */
111     @Override
112     @Deprecated
113     protected ApplicationProgressionModelWrapper getProgressionModel() {
114         return progressionModelWrapper;
115     }
116 
117     protected ProgressionUIModel getProgressionUIModel() {
118         return progressionModel;
119     }
120 
121     /**
122      * {@inheritDoc}
123      */
124     @Override
125     @Deprecated
126     protected void createProgressionModelIfRequired(int total) {
127     }
128 
129     /**
130      * Create a progression model
131      *
132      */
133     protected ProgressionUIModel createProgressionUIModel() {
134         return createProgressionUIModel(0);
135     }
136 
137     /**
138      * Create a progression model with an initialized total
139      *
140      * @return a brand new progression model with specified total
141      */
142     protected ProgressionUIModel createProgressionUIModel(long total) {
143         ProgressionUIModel progressionModel = new ProgressionUIModel();
144         setProgressionUIModel(progressionModel);
145         progressionModel.setTotal(total);
146         progressionModel.setMessage("");
147         return progressionModel;
148     }
149 
150     /**
151      * {@inheritDoc}
152      */
153     @Override
154     protected QuadrigeCoreConfiguration getConfig() {
155         return getContext().getConfiguration();
156     }
157 
158     /**
159      * {@inheritDoc}
160      */
161     @Override
162     protected void sendMessage(String message) {
163         getContext().showInformationMessage(message);
164     }
165 
166     /**
167      * <p>addErrorMessage.</p>
168      *
169      * @param errorMessage a {@link java.lang.String} object.
170      */
171     public void addErrorMessage(String errorMessage) {
172         if (errorMessages == null) {
173             errorMessages = Lists.newArrayList();
174         }
175         errorMessages.add(errorMessage);
176     }
177 
178     /**
179      * {@inheritDoc}
180      */
181     @Override
182     public boolean prepareAction() throws Exception {
183         errorMessages = null;
184         return super.prepareAction();
185     }
186 
187     /**
188      * {@inheritDoc}
189      */
190     @Override
191     public void postSuccessAction() {
192         super.postSuccessAction();
193 
194         displayErrors();
195     }
196 
197     /**
198      * {@inheritDoc}
199      */
200     @Override
201     public void postFailedAction(Throwable error) {
202 
203         // manage security exception 
204         if (error instanceof AuthenticationException) {
205 
206             if (LOG.isInfoEnabled()) {
207                 LOG.info("authentication needed");
208             }
209 
210             AuthenticationAction action = new AuthenticationAction((AbstractMainUIHandler) getContext().getMainUI().getHandler(), this);
211             action.setSkipScreenReload(true);
212             getActionEngine().runAction(action);
213 
214         } else if (error instanceof AccessDeniedException) {
215 
216             if (LOG.isInfoEnabled()) {
217                 LOG.info("access denied");
218             }
219 
220             getContext().getErrorHelper().showErrorDialog(t("quadrige3.error.authenticate.accessDenied"));
221         }
222     }
223 
224     /**
225      * {@inheritDoc}
226      */
227     @Override
228     protected void displayInfoMessage(String title, String message) {
229         getContext().getDialogHelper().showMessageDialog(message, title);
230     }
231 
232     /**
233      * {@inheritDoc}
234      */
235     @Override
236     protected void displayWarningMessage(String title, String message) {
237         getContext().getDialogHelper().showWarningDialog(message, title);
238     }
239 
240     /**
241      * {@inheritDoc}
242      */
243     protected void displayErrorMessage(String title, String message) {
244         getContext().getDialogHelper().showErrorDialog(message, title);
245     }
246 
247     private void displayErrors() {
248         if (CollectionUtils.isNotEmpty(errorMessages)) {
249             for (String errorMessage : errorMessages) {
250                 getContext().getErrorHelper().showErrorDialog(errorMessage, null);
251             }
252         }
253     }
254 
255     /**
256      * {@inheritDoc}
257      */
258     @Override
259     protected boolean askOverwriteFile(File file) {
260         return getHandler().askOverwriteFile(file);
261     }
262 
263     /**
264      * {@inheritDoc}
265      */
266     @Override
267     protected boolean askBeforeDelete(String title, String message) {
268         return getHandler().askBeforeDelete(title, message);
269     }
270 
271     /**
272      * <p>askBeforeDeleteMany.</p>
273      *
274      * @param title   a {@link java.lang.String} object.
275      * @param message a {@link java.lang.String} object.
276      * @param list    a {@link java.util.List} object.
277      * @return a boolean.
278      */
279     protected boolean askBeforeDeleteMany(String title, String message, List<String> list) {
280         return getHandler().askBeforeDeleteMany(title, message, list);
281     }
282 
283     /**
284      * <p>askSaveBeforeLeaving.</p>
285      *
286      * @param message a {@link java.lang.String} object.
287      * @return a int.
288      */
289     protected int askSaveBeforeLeaving(String message) {
290         return getHandler().askSaveBeforeLeaving(message);
291     }
292 
293     /**
294      * <p>askBeforeChangeTab.</p>
295      *
296      * @param message a {@link java.lang.String} object.
297      * @return a int.
298      */
299     protected int askBeforeChangeTab(String message) {
300         return getHandler().askBeforeChangeTab(message);
301     }
302 
303     /**
304      * <p>askBeforeReset.</p>
305      *
306      * @param title   a {@link java.lang.String} object.
307      * @param message a {@link java.lang.String} object.
308      * @return a boolean.
309      */
310     protected boolean askBeforeReset(String title, String message) {
311         return getHandler().askBeforeReset(title, message);
312     }
313 
314     /**
315      * <p>askCancelEditBeforeLeaving.</p>
316      *
317      * @param message a {@link java.lang.String} object.
318      * @return a boolean.
319      */
320     protected boolean askCancelEditBeforeLeaving(String message) {
321         return getHandler().askCancelEditBeforeLeaving(message);
322     }
323 
324     /**
325      * <p>askDeleteInvalidBeforeLeaving.</p>
326      *
327      * @param message a {@link java.lang.String} object.
328      * @return a boolean.
329      */
330     protected boolean askDeleteInvalidBeforeLeaving(String message) {
331         return getHandler().askDeleteInvalidBeforeLeaving(message);
332     }
333 
334     /**
335      * {@inheritDoc}
336      */
337     @Override
338     public void setActionDescription(String actionDescription) {
339         if (StringUtils.isNotBlank(actionDescription)) {
340             super.setActionDescription(actionDescription);
341         }
342     }
343 
344     public void forceActionDescription(String actionDescription) {
345         setActionDescription(actionDescription);
346         // Force label refresh
347         if (getContext().getActionUI() != null) {
348             getContext().getActionUI().getGlobalActionLabel().setText(t("jaxx.application.message.action.running", actionDescription));
349         }
350     }
351 
352     @Override
353     protected File chooseFile(String title, String buttonLabel, String... filters) {
354         File file = FileChooser.forLoadingFile()
355             .setTitle(title)
356             .setParent((Component) getUI())
357             .setApprovalText(buttonLabel)
358             .setPatternOrDescriptionFilters(Arrays.asList(filters))
359             .choose()
360             .getFile();
361 
362         if (LOG.isDebugEnabled()) {
363             LOG.debug(title + " : " + file);
364         }
365 
366         return file;
367     }
368 
369     /**
370      * Choisir des fichiers via un sélecteur graphique de fichiers.
371      *
372      * @param title       le titre du dialogue de sélection
373      * @param buttonLabel le label du boutton d'acceptation
374      * @param filters     les filtres + descriptions sur le sélecteur de fichiers
375      * @return les fichiers choisis
376      */
377     protected List<File> chooseFiles(String title,
378                               String buttonLabel,
379                               String... filters) {
380 
381         List<File> files = FileChooser.forLoadingFiles()
382             .setTitle(title)
383             .setParent((Component) getUI())
384             .setApprovalText(buttonLabel)
385             .setPatternOrDescriptionFilters(Arrays.asList(filters))
386             .choose()
387             .getFiles();
388 
389         if (LOG.isDebugEnabled()) {
390             LOG.debug(title + " : " + files);
391         }
392 
393         return files;
394     }
395 
396     @Override
397     protected File saveFile(File defaultFile, String filename, String extension, String title, String buttonLabel, String... filters) {
398         if (defaultFile != null && FileChooser.isCurrentDirectoryDefault()) {
399 
400             // set default directory to this one
401             FileChooser.setCurrentDirectory(defaultFile);
402         }
403         return saveFile(filename, extension, title, buttonLabel, filters);
404     }
405 
406     @Override
407     protected File saveFile(String filename, String extension, String title, String buttonLabel, String... filters) {
408         return saveFileWithStartDirectory(null, true, filename, extension, title, buttonLabel, filters);
409     }
410 
411     @Override
412     protected File saveFileWithStartDirectory(File startDirectory, boolean keepCurrentDirectory, String filename, String extension, String title, String buttonLabel, String... filters) {
413         boolean withExtension = StringUtils.isNotBlank(extension);
414         String filenameSuffix = withExtension ? "." + extension : "";
415 
416         File file = FileChooser.forSaving()
417             .setStartDirectory(startDirectory)
418             .setKeepCurrentDirectory(keepCurrentDirectory)
419             .setTitle(title)
420             .setParent((Component) getUI())
421             .setApprovalText(buttonLabel)
422             .setPatternOrDescriptionFilters(Arrays.asList(filters))
423             .setFilename(filename + filenameSuffix)
424             .choose()
425             .getFile();
426 
427         if (LOG.isDebugEnabled()) {
428             LOG.debug(title + " : " + file);
429         }
430         if (file != null) {
431             Preconditions.checkState(!file.isDirectory());
432 
433             // add extension if missing
434             if (withExtension && !file.getName().endsWith(filenameSuffix)) {
435                 file = new File(file.getParentFile(), file.getName() + filenameSuffix);
436             }
437 
438             // ask user to confirm overwrite.
439             boolean confirm = askOverwriteFile(file);
440 
441             if (!confirm) {
442                 // l'utilisateur n'a pas confirmé l'écrasement
443                 // donc pas de fichier en retour
444                 file = null;
445             }
446         }
447 
448         return file;
449     }
450 
451 
452 
453     /**
454      * <p>chooseDirectory.</p>
455      *
456      * @param title       a {@link java.lang.String} object.
457      * @param buttonLabel a {@link java.lang.String} object.
458      * @return a {@link java.io.File} object.
459      */
460     protected File chooseDirectory(String title, String buttonLabel) {
461         FileChooser.ToLoadDirectory toLoadDirectory = FileChooser.forLoadingDirectory();
462         toLoadDirectory.setParent(getContext().getMainUI());
463         toLoadDirectory.setTitle(title);
464         toLoadDirectory.setApprovalText(buttonLabel);
465         return toLoadDirectory.choose().getFile();
466     }
467 
468     public class ApplicationProgressionModelWrapper extends ApplicationProgressionModel {
469 
470         private final ProgressionUIModel progressionUIModel;
471 
472         ApplicationProgressionModelWrapper(ProgressionUIModel progressionUIModel) {
473             Assert.notNull(progressionUIModel);
474             this.progressionUIModel = progressionUIModel;
475             // send all event to this wrapper
476             progressionUIModel.addPropertyChangeListener(this::firePropertyChange);
477         }
478 
479         @Override
480         public int getTotal() {
481             return progressionUIModel.getTotal();
482         }
483 
484         @Override
485         public void setTotal(int total) {
486             progressionUIModel.setTotal(total);
487         }
488 
489         @Override
490         public void adaptTotal(int total) {
491             progressionUIModel.adaptTotal(total);
492         }
493 
494         @Override
495         public int getCurrent() {
496             return progressionUIModel.getCurrent();
497         }
498 
499         @Override
500         public void setCurrent(int current) {
501             progressionUIModel.setCurrent(current);
502         }
503 
504         @Override
505         public void increments(int nb) {
506             progressionUIModel.increments(nb);
507         }
508 
509         @Override
510         public float getRate() {
511             return 0;
512         }
513 
514         @Override
515         public void setRate(float rate) {
516         }
517 
518         @Override
519         public String getMessage() {
520             return progressionUIModel.getMessage();
521         }
522 
523         @Override
524         public void increments(String message) {
525             progressionUIModel.increments(message);
526         }
527 
528         @Override
529         public void setMessage(String message) {
530             progressionUIModel.setMessage(message);
531         }
532     }
533 }