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.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsResourceTypeConfig; 032import org.opencms.ade.contenteditor.shared.CmsEditorConstants; 033import org.opencms.file.CmsObject; 034import org.opencms.file.CmsResource; 035import org.opencms.file.CmsResourceFilter; 036import org.opencms.file.types.I_CmsResourceType; 037import org.opencms.i18n.CmsEncoder; 038import org.opencms.jsp.CmsJspTagEdit; 039import org.opencms.main.CmsLog; 040import org.opencms.main.OpenCms; 041import org.opencms.security.CmsRole; 042import org.opencms.ui.A_CmsUI; 043import org.opencms.ui.CmsVaadinUtils; 044import org.opencms.ui.components.CmsErrorDialog; 045import org.opencms.ui.components.I_CmsWindowCloseListener; 046import org.opencms.ui.editors.I_CmsEditor; 047import org.opencms.util.CmsRequestUtil; 048import org.opencms.util.CmsStringUtil; 049import org.opencms.util.CmsUUID; 050import org.opencms.workplace.CmsWorkplace; 051import org.opencms.workplace.editors.CmsXmlContentEditor; 052 053import java.util.Collections; 054import java.util.Map; 055 056import org.apache.commons.logging.Log; 057 058import com.vaadin.event.Action; 059import com.vaadin.navigator.ViewChangeListener; 060import com.vaadin.server.Page; 061import com.vaadin.server.VaadinRequest; 062import com.vaadin.server.VaadinServletRequest; 063 064/** 065 * The editor app. Will open the appropriate editor for a resource.<p> 066 */ 067public class CmsEditor 068implements I_CmsWorkplaceApp, ViewChangeListener, I_CmsWindowCloseListener, I_CmsHasShortcutActions { 069 070 /** The back link prefix. */ 071 public static final String BACK_LINK_PREFIX = "backLink"; 072 073 /** The back link prefix. */ 074 public static final String PLAIN_TEXT_PREFIX = "plainText"; 075 076 /** The resource id state prefix. */ 077 public static final String RESOURCE_ID_PREFIX = "resourceId"; 078 079 /** The resource id state prefix. */ 080 public static final String RESOURCE_PATH_PREFIX = "resourcePath"; 081 082 /** Logger instance for this class. */ 083 private static final Log LOG = CmsLog.getLog(CmsEditor.class); 084 085 /** The serial version id. */ 086 private static final long serialVersionUID = 7503052469189004387L; 087 088 /** The UI context. */ 089 private I_CmsAppUIContext m_context; 090 091 /** The editor instance. */ 092 private I_CmsEditor m_editorInstance; 093 094 /** 095 * Returns the edit link for given resource structure id.<p> 096 * 097 * @param structureId the resource structure is 098 * @param plainText if plain text/source editing is required 099 * @param backLink the back link location 100 * 101 * @return the state 102 */ 103 public static String getEditLink(CmsUUID structureId, boolean plainText, String backLink) { 104 105 return CmsVaadinUtils.getWorkplaceLink( 106 org.opencms.ui.apps.CmsEditorConfiguration.APP_ID, 107 getEditState(structureId, plainText, backLink)); 108 } 109 110 /** 111 * Returns the edit state for the given resource structure id.<p> 112 * 113 * @param structureId the resource structure id 114 * @param plainText if plain text/source editing is required 115 * @param backLink the back link location 116 * 117 * @return the state 118 */ 119 public static String getEditState(CmsUUID structureId, boolean plainText, String backLink) { 120 121 String state = ""; 122 state = A_CmsWorkplaceApp.addParamToState(state, CmsEditor.RESOURCE_ID_PREFIX, structureId.toString()); 123 state = A_CmsWorkplaceApp.addParamToState(state, CmsEditor.PLAIN_TEXT_PREFIX, String.valueOf(plainText)); 124 state = A_CmsWorkplaceApp.addParamToState(state, CmsEditor.BACK_LINK_PREFIX, backLink); 125 return state; 126 } 127 128 /** 129 * Returns the edit state for the given resource structure id.<p> 130 * 131 * @param cms the cms context 132 * @param resourceType the resource type to create 133 * @param contextPath the context path 134 * @param modelFilePath the model file path 135 * @param plainText if plain text/source editing is required 136 * @param backLink the back link location 137 * 138 * @return the state 139 */ 140 public static String getEditStateForNew( 141 CmsObject cms, 142 I_CmsResourceType resourceType, 143 String contextPath, 144 String modelFilePath, 145 boolean plainText, 146 String backLink) { 147 148 String state = ""; 149 150 state = A_CmsWorkplaceApp.addParamToState( 151 state, 152 CmsXmlContentEditor.PARAM_NEWLINK, 153 CmsJspTagEdit.getNewLink(cms, resourceType, contextPath)); 154 155 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(modelFilePath)) { 156 state = A_CmsWorkplaceApp.addParamToState(state, CmsWorkplace.PARAM_MODELFILE, modelFilePath); 157 state = A_CmsWorkplaceApp.addParamToState( 158 state, 159 CmsEditorConstants.PARAM_MODE, 160 CmsEditorConstants.MODE_COPY); 161 } 162 state = A_CmsWorkplaceApp.addParamToState(state, CmsEditor.RESOURCE_PATH_PREFIX, contextPath); 163 state = A_CmsWorkplaceApp.addParamToState(state, CmsEditor.PLAIN_TEXT_PREFIX, String.valueOf(plainText)); 164 state = A_CmsWorkplaceApp.addParamToState(state, CmsEditor.BACK_LINK_PREFIX, backLink); 165 166 return state; 167 } 168 169 /** 170 * Navigates to the back link target.<p> 171 * 172 * @param backlink the back link 173 */ 174 public static void openBackLink(String backlink) { 175 176 if (!CmsRequestUtil.checkBacklink(backlink, ((VaadinServletRequest)VaadinRequest.getCurrent()))) { 177 backlink = CmsVaadinUtils.getWorkplaceLink(); 178 } 179 180 String current = Page.getCurrent().getLocation().toString(); 181 if (current.contains("#")) { 182 current = current.substring(0, current.indexOf("#")); 183 } 184 // check if the back link targets the workplace UI 185 if (backlink.startsWith(current)) { 186 // use the navigator to open the target 187 String target = backlink.substring(backlink.indexOf("#") + 1); 188 String decodedTarget = CmsEncoder.decode(target); 189 CmsAppWorkplaceUi.get().getNavigator().navigateTo(decodedTarget); 190 } else { 191 // otherwise set the new location 192 Page.getCurrent().setLocation(backlink); 193 } 194 } 195 196 /** 197 * @see com.vaadin.navigator.ViewChangeListener#afterViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent) 198 */ 199 public void afterViewChange(ViewChangeEvent event) { 200 201 if (m_editorInstance instanceof ViewChangeListener) { 202 ((ViewChangeListener)m_editorInstance).afterViewChange(event); 203 } 204 } 205 206 /** 207 * @see com.vaadin.navigator.ViewChangeListener#beforeViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent) 208 */ 209 public boolean beforeViewChange(ViewChangeEvent event) { 210 211 if (m_editorInstance instanceof ViewChangeListener) { 212 return ((ViewChangeListener)m_editorInstance).beforeViewChange(event); 213 } else { 214 return true; 215 } 216 } 217 218 /** 219 * @see org.opencms.ui.apps.I_CmsHasShortcutActions#getShortcutActions() 220 */ 221 public Map<Action, Runnable> getShortcutActions() { 222 223 if (m_editorInstance instanceof I_CmsHasShortcutActions) { 224 return ((I_CmsHasShortcutActions)m_editorInstance).getShortcutActions(); 225 } else { 226 return Collections.EMPTY_MAP; 227 } 228 } 229 230 /** 231 * @see org.opencms.ui.apps.I_CmsWorkplaceApp#initUI(org.opencms.ui.apps.I_CmsAppUIContext) 232 */ 233 public void initUI(I_CmsAppUIContext context) { 234 235 m_context = context; 236 } 237 238 /** 239 * @see org.opencms.ui.apps.I_CmsWorkplaceApp#onStateChange(java.lang.String) 240 */ 241 public void onStateChange(String state) { 242 243 CmsUUID resId = getResourceIdFromState(state); 244 String path = null; 245 if (resId == null) { 246 path = getResourcePathFromState(state); 247 } 248 CmsObject cms = A_CmsUI.getCmsObject(); 249 final String backlink = getBackLinkFromState(state); 250 try { 251 CmsResource resource = null; 252 if (resId != null) { 253 resource = cms.readResource(resId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 254 } else if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(path)) { 255 resource = cms.readResource(path, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 256 } 257 Map<String, String> params = A_CmsWorkplaceApp.getParamsFromState(state); 258 String newLink = params.get(CmsXmlContentEditor.PARAM_NEWLINK); 259 I_CmsEditor editor = null; 260 if (CmsStringUtil.isEmptyOrWhitespaceOnly(newLink)) { 261 262 // make sure the user has the required role 263 OpenCms.getRoleManager().checkRoleForResource(cms, CmsRole.ELEMENT_AUTHOR, cms.getSitePath(resource)); 264 editor = OpenCms.getWorkplaceAppManager().getEditorForResource(cms, resource, isPlainText(state)); 265 } else { 266 String typeName = CmsJspTagEdit.getTypeFromNewLink(newLink); 267 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(typeName); 268 editor = OpenCms.getWorkplaceAppManager().getEditorForType(type, isPlainText(state)); 269 String rootPath = CmsJspTagEdit.getRootPathFromNewLink(newLink); 270 CmsADEConfigData data = OpenCms.getADEManager().lookupConfiguration(cms, rootPath); 271 CmsResourceTypeConfig typeConfig = data.getResourceType(typeName); 272 if (!typeConfig.checkCreatable(cms, rootPath)) { 273 throw new RuntimeException(); 274 } 275 276 } 277 if (editor != null) { 278 m_editorInstance = editor.newInstance(); 279 280 params.remove(BACK_LINK_PREFIX); 281 params.remove(RESOURCE_ID_PREFIX); 282 params.remove(RESOURCE_PATH_PREFIX); 283 params.remove(PLAIN_TEXT_PREFIX); 284 m_editorInstance.initUI(m_context, resource, backlink, params); 285 } 286 287 } catch (Exception e) { 288 LOG.error("Error initializing the editor.", e); 289 CmsErrorDialog.showErrorDialog(e, new Runnable() { 290 291 public void run() { 292 293 openBackLink(backlink); 294 } 295 }); 296 } 297 } 298 299 /** 300 * @see org.opencms.ui.components.I_CmsWindowCloseListener#onWindowClose() 301 */ 302 public void onWindowClose() { 303 304 if (m_editorInstance instanceof I_CmsWindowCloseListener) { 305 ((I_CmsWindowCloseListener)m_editorInstance).onWindowClose(); 306 } 307 } 308 309 /** 310 * Returns the back link info from the given state.<p> 311 * 312 * @param state the state 313 * 314 * @return the back link info 315 */ 316 private String getBackLinkFromState(String state) { 317 318 return A_CmsWorkplaceApp.getParamFromState(state, BACK_LINK_PREFIX); 319 } 320 321 /** 322 * Returns the resource id form the given state.<p> 323 * 324 * @param state the state 325 * 326 * @return the resource id 327 */ 328 private CmsUUID getResourceIdFromState(String state) { 329 330 CmsUUID result = null; 331 String id = A_CmsWorkplaceApp.getParamFromState(state, RESOURCE_ID_PREFIX); 332 if (CmsUUID.isValidUUID(id)) { 333 result = new CmsUUID(id); 334 } 335 336 return result; 337 } 338 339 /** 340 * Returns the resource path from the given state.<p> 341 * 342 * @param state the state 343 * 344 * @return the resource path 345 */ 346 private String getResourcePathFromState(String state) { 347 348 return A_CmsWorkplaceApp.getParamFromState(state, RESOURCE_PATH_PREFIX); 349 } 350 351 /** 352 * Returns if plain text/source editing is requested. 353 * 354 * @param state the state 355 * 356 * @return <code>true</code> if plain text/source editing is requested 357 */ 358 private boolean isPlainText(String state) { 359 360 String val = A_CmsWorkplaceApp.getParamFromState(state, PLAIN_TEXT_PREFIX); 361 return Boolean.parseBoolean(val); 362 } 363 364}