View Javadoc

1   /**
2    * This file Copyright (c) 2012-2014 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.ui.dialog;
35  
36  import info.magnolia.i18nsystem.I18nizer;
37  import info.magnolia.i18nsystem.SimpleTranslator;
38  import info.magnolia.objectfactory.ComponentProvider;
39  import info.magnolia.ui.api.action.ActionDefinition;
40  import info.magnolia.ui.api.action.ActionExecutionException;
41  import info.magnolia.ui.api.action.ActionExecutor;
42  import info.magnolia.ui.api.app.AppContext;
43  import info.magnolia.ui.api.app.SubAppContext;
44  import info.magnolia.ui.api.context.UiContext;
45  import info.magnolia.ui.api.message.Message;
46  import info.magnolia.ui.api.message.MessageType;
47  import info.magnolia.ui.api.overlay.ConfirmationCallback;
48  import info.magnolia.ui.api.overlay.OverlayLayer.ModalityLevel;
49  import info.magnolia.ui.dialog.actionarea.ActionAreaPresenter;
50  import info.magnolia.ui.dialog.actionarea.ActionListener;
51  import info.magnolia.ui.dialog.actionarea.EditorActionAreaPresenter;
52  import info.magnolia.ui.dialog.actionarea.view.EditorActionAreaView;
53  import info.magnolia.ui.dialog.definition.DialogDefinition;
54  import info.magnolia.ui.vaadin.dialog.BaseDialog;
55  import info.magnolia.ui.vaadin.overlay.MessageStyleTypeEnum;
56  
57  import javax.inject.Inject;
58  
59  import net.sf.cglib.proxy.Enhancer;
60  
61  import org.slf4j.Logger;
62  import org.slf4j.LoggerFactory;
63  
64  import com.vaadin.event.ShortcutAction.KeyCode;
65  import com.vaadin.event.ShortcutAction.ModifierKey;
66  import com.vaadin.event.ShortcutListener;
67  import com.vaadin.server.WebBrowser;
68  import com.vaadin.ui.Panel;
69  import com.vaadin.ui.UI;
70  
71  /**
72   * Base implementation of {@link DialogPresenter}.
73   */
74  public class BaseDialogPresenter implements DialogPresenter, ActionListener {
75  
76      private Logger log = LoggerFactory.getLogger(getClass());
77  
78      private DialogView view;
79  
80      protected ComponentProvider componentProvider;
81  
82      private ActionExecutor executor;
83  
84      private EditorActionAreaPresenter editorActionAreaPresenter;
85  
86      private final I18nizer i18nizer;
87  
88      private final SimpleTranslator i18n;
89  
90      private UiContext uiContext;
91  
92      private DialogDefinition definition;
93  
94      @Inject
95      public BaseDialogPresenter(ComponentProvider componentProvider, ActionExecutor executor, DialogView view, I18nizer i18nizer, SimpleTranslator i18n) {
96          this.componentProvider = componentProvider;
97          this.executor = executor;
98          this.view = view;
99          this.i18nizer = i18nizer;
100         this.i18n = i18n;
101     }
102 
103     @Override
104     public DialogView getView() {
105         return view;
106     }
107 
108     @Override
109     public ActionAreaPresenter getActionArea() {
110         return editorActionAreaPresenter;
111     }
112 
113     @Override
114     public void closeDialog() {
115         view.close();
116     }
117 
118     @Override
119     public void addShortcut(final String actionName, final int keyCode, final int... modifiers) {
120 
121         view.addShortcut(new ShortcutListener(actionName, keyCode, modifiers) {
122             @Override
123             public void handleAction(Object sender, Object target) {
124                 executeAction(actionName, new Object[0]);
125             }
126         });
127     }
128 
129     @Override
130     public DialogView start(DialogDefinition dialogDefinition, UiContext uiContext) {
131         this.uiContext = uiContext;
132         // ChooseDialogDefinition is already enhanced as it is obtained via ContentAppDescriptor.getChooseDialog() at ContentApp.openChooseDialog(..)
133         if (Enhancer.isEnhanced(dialogDefinition.getClass())) {
134             this.definition = dialogDefinition;
135         } else {
136             this.definition = i18nizer.decorate(dialogDefinition);
137         }
138 
139         this.editorActionAreaPresenter = componentProvider.newInstance(definition.getActionArea().getPresenterClass());
140         EditorActionAreaView editorActionAreaView = editorActionAreaPresenter.start(filterActions(), definition.getActionArea(), this, uiContext);
141 
142         // Set modifier key based on OS.
143         int osSpecificModifierKey;
144         UI ui = UI.getCurrent();
145         if (ui != null) {
146             WebBrowser browser = ui.getPage().getWebBrowser();
147             if (browser.isWindows()) {
148                 osSpecificModifierKey = ModifierKey.CTRL;
149             } else {
150                 // osx and linux
151                 osSpecificModifierKey = ModifierKey.META;
152             }
153 
154             if (definition.getActions().containsKey(BaseDialog.COMMIT_ACTION_NAME)) {
155                 addShortcut(BaseDialog.COMMIT_ACTION_NAME, KeyCode.S, osSpecificModifierKey);
156             }
157             if (definition.getActions().containsKey(BaseDialog.CANCEL_ACTION_NAME)) {
158                 addShortcut(BaseDialog.CANCEL_ACTION_NAME, KeyCode.W, osSpecificModifierKey);
159             }
160             if (definition.getModalityLevel() == ModalityLevel.LIGHT) {
161                 view.addShortcut(new CloseDialogShortcutListener(KeyCode.ESCAPE));
162             }
163 
164         } else {
165             log.warn("The current Vaadin UI was null when starting {}, as a result dialog keyboard shortcuts will not work.", this);
166         }
167 
168         view.addShortcut(new CloseDialogAfterConfirmationShortcutListener(KeyCode.ESCAPE));
169         view.addShortcut(new CommitDialogShortcutListener(KeyCode.ENTER));
170 
171         this.view.setActionAreaView(editorActionAreaView);
172         this.view.setModalityLevel(definition.getModalityLevel());
173         if (definition.isWide()){
174             this.view.setWide(true);
175         }
176         return this.view;
177     }
178 
179     protected Iterable<ActionDefinition> filterActions() {
180         return getDefinition().getActions().values();
181     }
182 
183     protected Object[] getActionParameters(String actionName) {
184         return new Object[] { this };
185     }
186 
187     @Override
188     public void onActionFired(String actionName, Object... actionContextParams) {
189         executeAction(actionName, actionContextParams);
190     }
191 
192     protected void executeAction(String actionName, Object[] actionContextParams) {
193         Object[] providedParameters = getActionParameters(actionName);
194         Object[] combinedParameters = new Object[providedParameters.length + actionContextParams.length];
195         System.arraycopy(providedParameters, 0, combinedParameters, 0, providedParameters.length);
196         System.arraycopy(actionContextParams, 0, combinedParameters, providedParameters.length, actionContextParams.length);
197         try {
198             executor.execute(actionName, combinedParameters);
199         } catch (ActionExecutionException e) {
200             String exceptionStatement = i18n.translate("ui-dialog.actionexecutionerror.basemessage");
201             Message error = new Message(MessageType.ERROR, exceptionStatement, e.getMessage());
202             log.error(exceptionStatement, e);
203             if (uiContext instanceof AppContext) {
204                 ((AppContext) uiContext).sendLocalMessage(error);
205             } else if (uiContext instanceof SubAppContext) {
206                 ((SubAppContext) uiContext).getAppContext().sendLocalMessage(error);
207             }
208 
209         }
210     }
211 
212     protected DialogDefinition getDefinition() {
213         return definition;
214     }
215 
216     protected ActionExecutor getExecutor() {
217         return executor;
218     }
219 
220     protected I18nizer getI18nizer() {
221         return i18nizer;
222     }
223 
224     /**
225      * A shortcut listener used to close the dialog.
226      */
227     protected class CloseDialogShortcutListener extends ShortcutListener {
228 
229         public CloseDialogShortcutListener(int keyCode, int... modifierKey) {
230             super("", keyCode, modifierKey);
231         }
232 
233         @Override
234         public void handleAction(Object sender, Object target) {
235             closeDialog();
236         }
237     }
238 
239     /**
240      * A shortcut listener which opens a confirmation to confirm closing the dialog.
241      */
242     protected class CloseDialogAfterConfirmationShortcutListener extends ShortcutListener {
243 
244         public CloseDialogAfterConfirmationShortcutListener(int keyCode, int... modifierKey) {
245             super("", keyCode, modifierKey);
246         }
247 
248         @Override
249         public void handleAction(Object sender, Object target) {
250             uiContext.openConfirmation(
251                     MessageStyleTypeEnum.WARNING, i18n.translate("ui-dialog.closeConfirmation.title"), i18n.translate("ui-dialog.closeConfirmation.body"), i18n.translate("ui-dialog.closeConfirmation.confirmButton"), i18n.translate("ui-dialog.cancelButton"), false,
252                     new ConfirmationCallback() {
253                         @Override
254                         public void onSuccess() {
255                             closeDialog();
256                         }
257 
258                         @Override
259                         public void onCancel() {
260                             if (getView() instanceof Panel) {
261                                 ((Panel) getView()).focus();
262                             }
263                         }
264                     });
265         }
266     }
267 
268     /**
269      * A shortcut listener used to commit the dialog.
270      */
271     protected class CommitDialogShortcutListener extends ShortcutListener {
272 
273         public CommitDialogShortcutListener(int keyCode, int... modifierKey) {
274             super("", keyCode, modifierKey);
275         }
276 
277         @Override
278         public void handleAction(Object sender, Object target) {
279             // textareas are excluded on the client-side, see 'EnterFriendlyShortcutActionHandler', used in PanelConnector
280             executeAction(BaseDialog.COMMIT_ACTION_NAME, new Object[0]);
281         }
282     }
283 }