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}