View Javadoc
1   package fr.ifremer.quadrige2.ui.swing.common.content;
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.base.Preconditions;
27  import fr.ifremer.quadrige2.core.security.AuthenticationInfo;
28  import fr.ifremer.quadrige2.ui.swing.common.*;
29  import fr.ifremer.quadrige2.ui.swing.common.content.db.DbManagerUIHandler;
30  import fr.ifremer.quadrige2.ui.swing.common.content.login.LoginUI;
31  import jaxx.runtime.SwingUtil;
32  import jaxx.runtime.validator.swing.SwingValidator;
33  import org.apache.commons.lang3.StringUtils;
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  import org.nuiton.jaxx.application.bean.RemoveablePropertyChangeListener;
37  import org.nuiton.jaxx.application.swing.util.CloseableUI;
38  
39  import javax.swing.*;
40  import java.awt.Cursor;
41  import java.awt.event.ActionEvent;
42  import java.awt.event.ActionListener;
43  import java.beans.PropertyChangeEvent;
44  import java.util.Locale;
45  
46  import static org.nuiton.i18n.I18n.t;
47  
48  /**
49   * <p>AbstractMainUIHandler class.</p>
50   *
51   * @since 0.1
52   */
53  public abstract class AbstractMainUIHandler<M extends ApplicationUIContext, UI extends MainUI<? extends AbstractMainUIHandler>> extends AbstractUIHandler<ApplicationUIContext, UI> {
54  
55      /**
56       * Logger.
57       */
58      private static final Log LOG = LogFactory.getLog(AbstractMainUIHandler.class);
59  
60      private JComponent currentBody;
61  
62      private Timer messageTimer;
63  
64      /**
65       * <p>reloadDbManagerText.</p>
66       */
67      public void reloadDbManagerText() {
68  
69          ApplicationUI<?, ?> body = (ApplicationUI<?, ?>) currentBody;
70  
71          if (body != null && body.getHandler() instanceof DbManagerUIHandler) {
72              DbManagerUIHandler dbManagerUIHandler = (DbManagerUIHandler) body.getHandler();
73              dbManagerUIHandler.updateMessage();
74          }
75      }
76  
77      //------------------------------------------------------------------------//
78      //-- AbstractApplicationUIHandler methods                                     --//
79      //------------------------------------------------------------------------//
80  
81      /**
82       * {@inheritDoc}
83       */
84      @Override
85      public void beforeInit(UI ui) {
86          super.beforeInit(ui);
87          ApplicationUIContext context = ApplicationUIContext.getInstance();
88          ui.setContextValue(context);
89  
90          context.installActionUI(ui);
91          context.addPropertyChangeListener(new RemoveablePropertyChangeListener() {
92              @Override
93              public void propertyChange(final PropertyChangeEvent evt) {
94                  String propertyName = evt.getPropertyName();
95                  if (ApplicationUIContext.PROPERTIES_TO_SAVE.contains(propertyName)) {
96  
97                      // change the ui title
98                      changeTitle();
99  
100                 } else if (propertyName.equals(ApplicationUIContext.PROPERTY_SCREEN)) {
101 
102                     // change the current screen
103                     setScreen((Screen) evt.getNewValue());
104                 }
105             }
106         });
107         ui.setContextValue(ui, MainUI.class.getName());
108 
109         // ecoute des changements de l'état busy
110         context.addPropertyChangeListener(ApplicationUIContext.PROPERTY_BUSY, new RemoveablePropertyChangeListener() {
111 
112             @Override
113             public void propertyChange(PropertyChangeEvent evt) {
114                 Boolean newvalue = (Boolean) evt.getNewValue();
115                 updateBusyState(newvalue != null && newvalue);
116             }
117         });
118 
119         // ecoute des changements de l'état busy
120         context.addPropertyChangeListener(ApplicationUIContext.PROPERTY_HIDE_BODY, new RemoveablePropertyChangeListener() {
121 
122             @Override
123             public void propertyChange(PropertyChangeEvent evt) {
124                 Boolean newvalue = (Boolean) evt.getNewValue();
125                 if (getUI() != null && getUI().getBody() != null) {
126                     getUI().getBody().setVisible(newvalue != null && newvalue);
127                 }
128             }
129         });
130 
131     }
132 
133     /**
134      * <p>updateBusyState.</p>
135      *
136      * @param busy a boolean.
137      */
138     protected void updateBusyState(boolean busy) {
139 
140         if (LOG.isDebugEnabled()) {
141             LOG.debug(busy ? "block ui in busy mode" : "unblock ui in none busy mode");
142         }
143 
144         // update cursor
145         getUI().setCursor(busy ? Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR) : Cursor.getDefaultCursor());
146 
147         if (getUI().getMenu() != null) {
148             if (busy) getUI().getMenu().removeNotify();
149             else getUI().getMenu().addNotify();
150         }
151     }
152 
153     /**
154      * {@inheritDoc}
155      */
156     @Override
157     public void afterInit(UI ui) {
158 
159         initUI(ui);
160 
161         // allow MainUI frame to move even when UIAction performing or modal dialog (DOCUMENT_MODAL or APPLICATION_MODAL) opened
162         // only dialog with TOOLKIT_MODAL mode will block MainUI
163         // TODO : à laisser en commentaire tant ques les ActionUI de JAXX sont TOOLKIT_MODAL (ou superieure à APPLICATION_MODAL)
164         // spécialement dans FileChooserUtil qui n'ouvre pas en modal
165         // sinon lors des actions longues, le menu est toujours dispo
166         // par contre on perd la possibilté de bouger la fenetre lors de ces actions
167 //        ui.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
168 
169         // installation layer de blocage en mode busy
170         SwingUtil.setLayerUI(getUI().getBody(), getUI().getBusyBlockLayerUI());
171 
172         //FIXME-TC See why this binding is not setted ?
173 //        ui.applyDataBinding(MainUI.BINDING_MENU_CHANGE_LOCALE_FR_ENABLED);
174 //        ui.applyDataBinding(MainUI.BINDING_MENU_CHANGE_LOCALE_UK_ENABLED);
175 
176         // Init SwingSession
177         getContext().initSwingSession(getUI());
178 
179         changeTitle();
180 
181         JToolBar bar = getUI().getBottomBar();
182         getUI().getStatus().addWidget(bar, 0);
183 
184         messageTimer = new Timer(3000, new ActionListener() {
185 
186             @Override
187             public void actionPerformed(ActionEvent e) {
188                 getUI().getStatus().clearStatus();
189             }
190         });
191         messageTimer.setRepeats(false);
192 
193     }
194 
195     /**
196      * {@inheritDoc}
197      */
198     @Override
199     protected JComponent getComponentToFocus() {
200         return currentBody;
201     }
202 
203     /**
204      * <p>Getter for the field <code>currentBody</code>.</p>
205      *
206      * @return a {@link JComponent} object.
207      */
208     public JComponent getCurrentBody() {
209         return currentBody;
210     }
211 
212     /**
213      * <p>closeUI.</p>
214      */
215     public void closeUI() {
216 
217         // close ui
218         onCloseUI();
219 
220         getContext().saveSwingSession(null);
221 
222         // close context
223         getContext().close();
224 
225     }
226 
227     /**
228      * {@inheritDoc}
229      */
230     @Override
231     public void onCloseUI() {
232 
233         if (getUI() != null) {
234 
235             // clean ui
236             ApplicationUIUtil.removeBindings(getUI());
237             getUI().setVisible(false);
238         }
239     }
240 
241     //------------------------------------------------------------------------//
242     //-- Public methods                                                     --//
243     //------------------------------------------------------------------------//
244 
245     /**
246      * <p>reloadUI.</p>
247      */
248     public void reloadUI() {
249 
250         //close ui
251         onCloseUI();
252 
253         // restart ui TODO trouver comment faire
254 //        RunUI.reloadUI(getContext());
255         showNotImplementedFunctionnality();
256 
257     }
258 
259     /**
260      * <p>changeLocale.</p>
261      *
262      * @param locale a {@link Locale} object.
263      */
264     public void changeLocale(Locale locale) {
265 
266         // change locale (and save configuration)
267         getModel().setLocale(locale);
268 
269         // close reload
270         reloadUI();
271     }
272 
273     /**
274      * {@inheritDoc}
275      */
276     @Override
277     public final void showInformationMessage(String message) {
278         getUI().getStatus().setStatus(ApplicationUIUtil.getHtmlString(message));
279 
280         messageTimer.restart();
281     }
282 
283     /**
284      * <p>registerValidator.</p>
285      *
286      * @param validator a {@link SwingValidator} object.
287      */
288     public void registerValidator(SwingValidator<?> validator) {
289         getUI().getValidatorMessageWidget().registerValidator(validator);
290     }
291 
292     /**
293      * {@inheritDoc}
294      */
295     @Override
296     public void clearValidators() {
297         getUI().getValidatorMessageWidget().clearValidators();
298     }
299 
300     /**
301      * <p>quitCurrentScreen.</p>
302      *
303      * @return a boolean.
304      */
305     public boolean quitCurrentScreen() {
306 
307         boolean canClose;
308         if (getContext().getScreen() == null || currentBody == null) {
309 
310             // no screen, surely can quit
311             canClose = true;
312             if (LOG.isWarnEnabled()) {
313                 LOG.warn("==================================================");
314                 LOG.warn("No screen, Should then skipCheckCurrent in action.");
315                 LOG.warn("==================================================");
316             }
317         } else {
318             ApplicationUI<?, ?> body = (ApplicationUI<?, ?>) currentBody;
319             Preconditions.checkNotNull(currentBody);
320             AbstractUIHandler<?, ?> handler = body.getHandler();
321             if (handler instanceof CloseableUI) {
322 
323                 // try to quit UI
324                 canClose = ((CloseableUI) handler).quitUI();
325             } else {
326 
327                 // can always close ui
328                 canClose = true;
329             }
330         }
331         return canClose;
332     }
333 
334     //------------------------------------------------------------------------//
335     //-- Internal methods                                                   --//
336     //------------------------------------------------------------------------//
337 
338     /**
339      * <p>setScreen.</p>
340      *
341      * @param screen a {@link Screen} object.
342      *               <p>
343      *               TODO ???? à mettre dans un listener quand un nouvel écran est demandé
344      */
345     protected void setScreen(Screen screen) {
346 
347         ApplicationUIContext context = getContext();
348 
349         // close current body (if any)
350         if (currentBody != null) {
351             ApplicationUI<?, ?> body = (ApplicationUI<?, ?>) currentBody;
352             body.getHandler().onCloseUI();
353 
354             getContext().saveSwingSession(currentBody);
355 
356             getUI().getBody().remove(currentBody);
357 
358             currentBody = null;
359         }
360 
361         if (screen != null) {
362 
363             // load new body
364             ApplicationUI<?, ?> screenUI = context.getApplicationUI(screen);
365 
366             if (screenUI != null) {
367 
368                 // TODO créer l'icône dans chaque écran (dans le beforeInit comme le model)
369                 Icon icon = screenUI.getContextValue(Icon.class);
370 
371                 final JButton showHelp = getUI().getShowHelp();
372                 final JToolBar rightDecoration = new JToolBar();
373                 rightDecoration.setFloatable(false);
374                 rightDecoration.setOpaque(false);
375                 rightDecoration.setBorderPainted(false);
376                 rightDecoration.add(showHelp, 0);
377                 this.currentBody = (JComponent) screenUI;
378                 context.getSwingSession().add(currentBody, true);
379                 getUI().getBody().setTitle(screenUI.getHandler().getTitle());
380                 getUI().getBody().setContentContainer(currentBody);
381                 getUI().getBody().setLeftDecoration(new JLabel(icon));
382                 getUI().getBody().setRightDecoration(rightDecoration);
383                 getUI().getBody().getRightDecoration().setVisible(true);
384 
385             } else {
386 
387                 // if no screen, set fallback screen
388                 context.getDialogHelper().showErrorDialog(t("quadrige2.main.screen.error", screen.getName()));
389                 context.setFallBackScreen();
390             }
391         }
392     }
393 
394     /**
395      * <p>changeTitle.</p>
396      */
397     public void changeTitle() {
398 
399         String title = getContext().getSelectedScreenTitle();
400 
401         getUI().setTitle(t("quadrige2.main.title.application",
402                 getConfig().getApplicationName(),
403                 getConfig().getVersion(),
404                 title));
405 
406     }
407 
408     /**
409      * <p>askAuthenticationInfo.</p>
410      *
411      * @param url a {@link String} object.
412      * @return a {@link fr.ifremer.quadrige2.core.security.AuthenticationInfo} object.
413      */
414     public AuthenticationInfo askAuthenticationInfo(String url) {
415 
416         AuthenticationInfo authentication;
417 
418         // Auto-login, if config as login/pwd (only the first time)
419         if (getContext().getAuthenticationInfo() == null
420                 && StringUtils.isNotBlank(getConfig().getAuthenticationDefaultUsername())
421                 && StringUtils.isNotBlank(getConfig().getAuthenticationDefaultPassword())) {
422             authentication = new AuthenticationInfo(
423                     getConfig().getAuthenticationDefaultUsername(),
424                     getConfig().getAuthenticationDefaultPassword()
425             );
426         }
427 
428         // Open the login dialog
429         else {
430             LoginUI loginUI = new LoginUI((ApplicationUI) getUI());
431             loginUI.getModel().setUrl(url);
432             loginUI.getModel().setAuthenticationInfo(getContext().getAuthenticationInfo());
433             openDialogForceOnTop(loginUI);
434             authentication = loginUI.getModel().getAuthenticationInfo();
435         }
436 
437         if (authentication != null) {
438 
439             // store it back in authentication store
440             getContext().setAuthenticationInfo(authentication);
441         }
442 
443         return authentication;
444     }
445 
446 }