001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ui.apps;
029
030import org.opencms.main.CmsLog;
031import org.opencms.main.OpenCms;
032import org.opencms.ui.A_CmsUI;
033import org.opencms.ui.CmsVaadinUtils;
034import org.opencms.ui.I_CmsAppView;
035import org.opencms.ui.Messages;
036import org.opencms.ui.apps.CmsWorkplaceAppManager.NavigationState;
037import org.opencms.ui.components.CmsAppViewLayout;
038import org.opencms.ui.components.I_CmsWindowCloseListener;
039import org.opencms.ui.components.OpenCmsTheme;
040
041import java.util.Collection;
042import java.util.HashMap;
043import java.util.HashSet;
044import java.util.Map;
045import java.util.Set;
046
047import org.apache.commons.logging.Log;
048
049import com.vaadin.event.Action;
050import com.vaadin.event.Action.Handler;
051import com.vaadin.event.ShortcutAction;
052import com.vaadin.navigator.ViewChangeListener;
053import com.vaadin.server.Page.BrowserWindowResizeEvent;
054import com.vaadin.server.Page.BrowserWindowResizeListener;
055import com.vaadin.ui.Dependency;
056import com.vaadin.ui.Dependency.Type;
057import com.vaadin.ui.Label;
058import com.vaadin.ui.UI;
059import com.vaadin.ui.VerticalLayout;
060import com.vaadin.ui.themes.ValoTheme;
061
062/**
063 * Displays the selected app.<p>
064 */
065public class CmsAppView
066implements ViewChangeListener, I_CmsWindowCloseListener, I_CmsAppView, Handler, BrowserWindowResizeListener {
067
068    /**
069     * Enum representing caching status of a view.<p>
070     */
071    public static enum CacheStatus {
072        /** Cache view. */
073        cache,
074
075        /** Cache view one time only. */
076        cacheOnce,
077
078        /** Don't cache view. */
079        noCache
080    }
081
082    /**
083     * Used in case the requested app can not be displayed to the current user.<p>
084     */
085    protected class NotAvailableApp implements I_CmsWorkplaceApp {
086
087        /**
088         * @see org.opencms.ui.apps.I_CmsWorkplaceApp#initUI(org.opencms.ui.apps.I_CmsAppUIContext)
089         */
090        public void initUI(I_CmsAppUIContext context) {
091
092            Label label = new Label(CmsVaadinUtils.getMessageText(Messages.GUI_APP_NOT_AVAILABLE_0));
093            label.addStyleName(ValoTheme.LABEL_H2);
094            label.addStyleName(OpenCmsTheme.LABEL_ERROR);
095            VerticalLayout content = new VerticalLayout();
096            content.setMargin(true);
097            content.addComponent(label);
098            context.setAppContent(content);
099        }
100
101        /**
102         * @see org.opencms.ui.apps.I_CmsWorkplaceApp#onStateChange(java.lang.String)
103         */
104        public void onStateChange(String state) {
105
106            // nothing to do
107        }
108
109    }
110
111    /** The history back action. */
112    private static final Action ACTION_HISTORY_BACK = new ShortcutAction(
113        "Alt+ArrowLeft",
114        ShortcutAction.KeyCode.ARROW_LEFT,
115        new int[] {ShortcutAction.ModifierKey.ALT});
116
117    /** The history forward action. */
118    private static final Action ACTION_HISTORY_FORWARD = new ShortcutAction(
119        "Alt+ArrowRight",
120        ShortcutAction.KeyCode.ARROW_RIGHT,
121        new int[] {ShortcutAction.ModifierKey.ALT});
122
123    /** The serial version id. */
124    private static final long serialVersionUID = -8128528863875050216L;
125
126    /** Logger instance for this class. */
127    private static final Log LOG = CmsLog.getLog(CmsAppView.class);
128
129    /** The current app. */
130    private I_CmsWorkplaceApp m_app;
131
132    /** The app shortcut actions. */
133    private Map<Action, Runnable> m_appActions;
134
135    /** The app configuration. */
136    private I_CmsWorkplaceAppConfiguration m_appConfig;
137
138    /** The app layout component. */
139    private CmsAppViewLayout m_appLayout;
140
141    /** The cache status. */
142    private CacheStatus m_cacheStatus = CacheStatus.noCache;
143
144    /** The default shortcut actions. */
145    private Map<Action, Runnable> m_defaultActions;
146
147    /** The requires restore from cache flag. */
148    private boolean m_requiresRestore;
149
150    /**
151     * Constructor.<p>
152     *
153     * @param appConfig the app configuration
154     */
155    public CmsAppView(I_CmsWorkplaceAppConfiguration appConfig) {
156
157        m_appConfig = appConfig;
158        m_defaultActions = new HashMap<Action, Runnable>();
159        m_defaultActions.put(ACTION_HISTORY_BACK, new Runnable() {
160
161            public void run() {
162
163                ((CmsAppWorkplaceUi)UI.getCurrent()).historyBack();
164            }
165        });
166        m_defaultActions.put(ACTION_HISTORY_FORWARD, new Runnable() {
167
168            public void run() {
169
170                ((CmsAppWorkplaceUi)UI.getCurrent()).historyForward();
171            }
172        });
173    }
174
175    /**
176     * @see com.vaadin.navigator.ViewChangeListener#afterViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent)
177     */
178    public void afterViewChange(ViewChangeEvent event) {
179
180        if (m_app instanceof ViewChangeListener) {
181            ((ViewChangeListener)m_app).afterViewChange(event);
182        }
183    }
184
185    /**
186     * @see com.vaadin.navigator.ViewChangeListener#beforeViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent)
187     */
188    public boolean beforeViewChange(ViewChangeEvent event) {
189
190        disableGlobalShortcuts();
191        if (m_appLayout != null) {
192            m_appLayout.closePopupViews();
193        }
194        if (m_app instanceof ViewChangeListener) {
195            return ((ViewChangeListener)m_app).beforeViewChange(event);
196        }
197        return true;
198    }
199
200    /**
201     * @see com.vaadin.server.Page.BrowserWindowResizeListener#browserWindowResized(com.vaadin.server.Page.BrowserWindowResizeEvent)
202     */
203    public void browserWindowResized(BrowserWindowResizeEvent event) {
204
205        if (m_appLayout != null) {
206            m_appLayout.browserWindowResized(event);
207        }
208    }
209
210    /**
211     * @see org.opencms.ui.I_CmsAppView#disableGlobalShortcuts()
212     */
213    public void disableGlobalShortcuts() {
214
215        UI.getCurrent().removeActionHandler(this);
216    }
217
218    /**
219     * @see org.opencms.ui.I_CmsAppView#enableGlobalShortcuts()
220     */
221    public void enableGlobalShortcuts() {
222
223        // to avoid multiple action handler registration, remove this first
224        UI.getCurrent().removeActionHandler(this);
225        UI.getCurrent().addActionHandler(this);
226    }
227
228    /**
229     * @see org.opencms.ui.I_CmsAppView#enter(java.lang.String)
230     */
231    public void enter(String newState) {
232
233        injectAdditionalStyles();
234        if (newState.startsWith(NavigationState.PARAM_SEPARATOR)) {
235            newState = newState.substring(1);
236        }
237        if ((m_appLayout != null) && (m_appConfig != null)) {
238            m_appLayout.setAppTitle(m_appConfig.getName(UI.getCurrent().getLocale()));
239        }
240        m_app.onStateChange(newState);
241        if (m_app instanceof I_CmsHasShortcutActions) {
242            m_appActions = ((I_CmsHasShortcutActions)m_app).getShortcutActions();
243        }
244        UI.getCurrent().addActionHandler(this);
245    }
246
247    /**
248     * @see com.vaadin.navigator.View#enter(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent)
249     */
250    public void enter(ViewChangeEvent event) {
251
252        String newState = event.getParameters();
253        enter(newState);
254    }
255
256    /**
257     * @see com.vaadin.event.Action.Handler#getActions(java.lang.Object, java.lang.Object)
258     */
259    public Action[] getActions(Object target, Object sender) {
260
261        if (m_appActions != null) {
262            Set<Action> actions = new HashSet<Action>(m_defaultActions.keySet());
263            actions.addAll(m_appActions.keySet());
264            return actions.toArray(new Action[actions.size()]);
265        }
266        return m_defaultActions.keySet().toArray(new Action[m_defaultActions.size()]);
267    }
268
269    /**
270     * Gets the cache status of the view.<p>
271     *
272     * @return the cache status of the view
273     */
274    public CacheStatus getCacheStatus() {
275
276        return m_cacheStatus;
277    }
278
279    /**
280     * @see org.opencms.ui.I_CmsAppView#getComponent()
281     */
282    public CmsAppViewLayout getComponent() {
283
284        if (m_app == null) {
285            return reinitComponent();
286        }
287        return m_appLayout;
288    }
289
290    /**
291     * @see org.opencms.ui.I_CmsAppView#getName()
292     */
293    public String getName() {
294
295        return m_appConfig.getId();
296    }
297
298    /**
299     * @see com.vaadin.event.Action.Handler#handleAction(com.vaadin.event.Action, java.lang.Object, java.lang.Object)
300     */
301    public void handleAction(Action action, Object sender, Object target) {
302
303        if ((m_appActions != null) && m_appActions.containsKey(action)) {
304            m_appActions.get(action).run();
305        } else if (m_defaultActions.containsKey(action)) {
306            m_defaultActions.get(action).run();
307        }
308    }
309
310    /**
311     * @see org.opencms.ui.I_CmsAppView#isCachable()
312     */
313    public boolean isCachable() {
314
315        return (m_app instanceof I_CmsCachableApp) && ((I_CmsCachableApp)m_app).isCachable();
316    }
317
318    /**
319     * @see org.opencms.ui.components.I_CmsWindowCloseListener#onWindowClose()
320     */
321    public void onWindowClose() {
322
323        if (m_app instanceof I_CmsWindowCloseListener) {
324            ((I_CmsWindowCloseListener)m_app).onWindowClose();
325        }
326        disableGlobalShortcuts();
327    }
328
329    /**
330     * @see org.opencms.ui.I_CmsAppView#reinitComponent()
331     */
332    public CmsAppViewLayout reinitComponent() {
333
334        if (m_app != null) {
335            beforeViewChange(
336                new ViewChangeEvent(CmsAppWorkplaceUi.get().getNavigator(), this, this, m_appConfig.getId(), ""));
337        }
338        if (!m_appConfig.getVisibility(A_CmsUI.getCmsObject()).isActive()) {
339            m_app = new NotAvailableApp();
340        } else {
341            m_app = m_appConfig.getAppInstance();
342        }
343        m_appLayout = new CmsAppViewLayout(m_appConfig.getId());
344        m_appLayout.setAppTitle(m_appConfig.getName(UI.getCurrent().getLocale()));
345        m_app.initUI(m_appLayout);
346        return m_appLayout;
347    }
348
349    /**
350     * @see org.opencms.ui.I_CmsAppView#requiresRestore()
351     */
352    public boolean requiresRestore() {
353
354        return m_requiresRestore;
355    }
356
357    /**
358     * Restores the view from cache.<p>
359     */
360    public void restoreFromCache() {
361
362        ((I_CmsCachableApp)m_app).onRestoreFromCache();
363        m_requiresRestore = false;
364    }
365
366    /**
367     * Sets the cache status.
368     *
369     * @param status the new cache status
370     */
371    public void setCacheStatus(CacheStatus status) {
372
373        m_cacheStatus = status;
374    }
375
376    /**
377     * @see org.opencms.ui.I_CmsAppView#setRequiresRestore(boolean)
378     */
379    public void setRequiresRestore(boolean restored) {
380
381        m_requiresRestore = restored;
382    }
383
384    /**
385     * @see java.lang.Object#toString()
386     */
387    @Override
388    public String toString() {
389
390        return "appView " + getName() + System.identityHashCode(this) + " (" + m_app + ")";
391    }
392
393    /**
394     * Inject external stylesheets.
395     */
396    private void injectAdditionalStyles() {
397
398        try {
399            Collection<String> stylesheets = OpenCms.getWorkplaceAppManager().getAdditionalStyleSheets();
400            for (String stylesheet : stylesheets) {
401                A_CmsUI.get().getPage().addDependency(new Dependency(Type.STYLESHEET, stylesheet));
402            }
403        } catch (Exception e) {
404            LOG.warn(e.getLocalizedMessage(), e);
405        }
406    }
407}