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