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 GmbH & Co. KG, 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.workplace.commons; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProperty; 032import org.opencms.file.CmsPropertyDefinition; 033import org.opencms.file.CmsResource; 034import org.opencms.file.CmsResourceFilter; 035import org.opencms.i18n.CmsEncoder; 036import org.opencms.i18n.CmsMessages; 037import org.opencms.jsp.CmsJspActionElement; 038import org.opencms.jsp.CmsJspNavBuilder; 039import org.opencms.jsp.CmsJspNavBuilder.Visibility; 040import org.opencms.jsp.CmsJspNavElement; 041import org.opencms.main.CmsException; 042import org.opencms.main.CmsLog; 043import org.opencms.main.OpenCms; 044import org.opencms.security.CmsPermissionSet; 045import org.opencms.util.CmsStringUtil; 046import org.opencms.workplace.CmsDialog; 047import org.opencms.workplace.CmsWorkplace; 048import org.opencms.workplace.CmsWorkplaceSettings; 049 050import java.util.ArrayList; 051import java.util.List; 052 053import javax.servlet.http.HttpServletRequest; 054import javax.servlet.http.HttpServletResponse; 055import javax.servlet.jsp.JspException; 056import javax.servlet.jsp.PageContext; 057 058import org.apache.commons.logging.Log; 059 060/** 061 * Provides methods for the change navigation dialog.<p> 062 * 063 * The following files use this class: 064 * <ul> 065 * <li>/commons/chnav.jsp 066 * </ul> 067 * <p> 068 * 069 * @since 6.0.0 070 */ 071public class CmsChnav extends CmsDialog { 072 073 /** Value for the action: change the navigation. */ 074 public static final int ACTION_CHNAV = 100; 075 076 /** The dialog type. */ 077 public static final String DIALOG_TYPE = "chnav"; 078 079 /** Request parameter name for the navigation position. */ 080 public static final String PARAM_NAVPOS = "navpos"; 081 082 /** Request parameter name for the navigation text. */ 083 public static final String PARAM_NAVTEXT = "navtext"; 084 085 /** The log object for this class. */ 086 private static final Log LOG = CmsLog.getLog(CmsChnav.class); 087 088 /** The NavPos parameter. */ 089 private String m_paramNavpos; 090 091 /** The NavText parameter. */ 092 private String m_paramNavtext; 093 094 /** 095 * Public constructor.<p> 096 * 097 * @param jsp an initialized JSP action element 098 */ 099 public CmsChnav(CmsJspActionElement jsp) { 100 101 super(jsp); 102 } 103 104 /** 105 * Public constructor with JSP variables.<p> 106 * 107 * @param context the JSP page context 108 * @param req the JSP request 109 * @param res the JSP response 110 */ 111 public CmsChnav(PageContext context, HttpServletRequest req, HttpServletResponse res) { 112 113 this(new CmsJspActionElement(context, req, res)); 114 } 115 116 /** 117 * Builds the HTML for the select box of the navigation position.<p> 118 * 119 * @param cms the CmsObject 120 * @param filename the current file 121 * @param attributes optional attributes for the <select> tag, do not add the "name" atribute! 122 * @param messages the localized workplace messages 123 * 124 * @return the HTML for a navigation position select box 125 */ 126 public static String buildNavPosSelector(CmsObject cms, String filename, String attributes, CmsMessages messages) { 127 128 // get current file navigation element 129 CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(cms); 130 CmsJspNavElement curNav = navBuilder.getNavigationForResource(filename); 131 132 // get the parent folder of the current file 133 filename = CmsResource.getParentFolder(filename); 134 135 // get navigation of the current folder 136 List<CmsJspNavElement> navList = navBuilder.getNavigationForFolder( 137 filename, 138 Visibility.includeHidden, 139 CmsResourceFilter.DEFAULT); 140 float maxValue = 0; 141 float nextPos = 0; 142 143 // calculate value for the first navigation position 144 float firstValue = 1; 145 if (navList.size() > 0) { 146 try { 147 CmsJspNavElement ne = navList.get(0); 148 maxValue = ne.getNavPosition(); 149 } catch (Exception e) { 150 // should usually never happen 151 LOG.error(e.getLocalizedMessage()); 152 } 153 } 154 155 if (maxValue != 0) { 156 firstValue = maxValue / 2; 157 } 158 159 List<String> options = new ArrayList<String>(navList.size() + 1); 160 List<String> values = new ArrayList<String>(navList.size() + 1); 161 162 // add the first entry: before first element 163 options.add(messages.key(Messages.GUI_CHNAV_POS_FIRST_0)); 164 values.add(firstValue + ""); 165 166 // show all present navigation elements in box 167 for (int i = 0; i < navList.size(); i++) { 168 CmsJspNavElement ne = navList.get(i); 169 String navText = ne.getNavText(); 170 float navPos = ne.getNavPosition(); 171 // get position of next nav element 172 nextPos = navPos + 2; 173 if ((i + 1) < navList.size()) { 174 nextPos = navList.get(i + 1).getNavPosition(); 175 } 176 // calculate new position of current nav element 177 float newPos; 178 if ((nextPos - navPos) > 1) { 179 newPos = navPos + 1; 180 } else { 181 newPos = (navPos + nextPos) / 2; 182 } 183 184 // check new maxValue of positions and increase it 185 if (navPos > maxValue) { 186 maxValue = navPos; 187 } 188 189 // if the element is the current file, mark it in selectbox 190 if ((curNav != null) && curNav.getNavText().equals(navText) && (curNav.getNavPosition() == navPos)) { 191 options.add( 192 CmsEncoder.escapeHtml( 193 messages.key(Messages.GUI_CHNAV_POS_CURRENT_1, new Object[] {ne.getFileName()}))); 194 values.add("-1"); 195 } else { 196 options.add(CmsEncoder.escapeHtml(navText + " [" + ne.getFileName() + "]")); 197 values.add(newPos + ""); 198 } 199 } 200 201 // add the entry: at the last position 202 options.add(messages.key(Messages.GUI_CHNAV_POS_LAST_0)); 203 values.add((maxValue + 1) + ""); 204 205 // add the entry: no change 206 options.add(messages.key(Messages.GUI_CHNAV_NO_CHANGE_0)); 207 if ((curNav != null) && (curNav.getNavPosition() == Float.MAX_VALUE)) { 208 // current resource has no valid position, use "last position" 209 values.add((maxValue + 1) + ""); 210 } else { 211 // current resource has valid position, use "-1" for no change 212 values.add("-1"); 213 } 214 215 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(attributes)) { 216 attributes = " " + attributes; 217 } else { 218 attributes = ""; 219 } 220 return CmsWorkplace.buildSelect( 221 "name=\"" + PARAM_NAVPOS + "\"" + attributes, 222 options, 223 values, 224 values.size() - 1, 225 true); 226 } 227 228 /** 229 * Performs the navigation change.<p> 230 * 231 * @throws JspException if including a JSP subelement is not successful 232 */ 233 public void actionChangeNav() throws JspException { 234 235 // save initialized instance of this class in request attribute for included sub-elements 236 getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this); 237 238 // get request parameters 239 String filename = getParamResource(); 240 // do not use #getParamNavText since it is decoded, see CmsWorkplace#fillParamValues(HttpServletRequest) 241 String newText = getJsp().getRequest().getParameter(PARAM_NAVTEXT); 242 String selectedPosString = getParamNavpos(); 243 244 try { 245 // lock resource if autolock is enabled 246 checkLock(getParamResource()); 247 // save the new NavText if not null 248 if (newText != null) { 249 CmsProperty newNavText = new CmsProperty(); 250 newNavText.setName(CmsPropertyDefinition.PROPERTY_NAVTEXT); 251 CmsProperty oldNavText = getCms().readPropertyObject( 252 filename, 253 CmsPropertyDefinition.PROPERTY_NAVTEXT, 254 false); 255 if (oldNavText.isNullProperty()) { 256 // property value was not already set 257 if (OpenCms.getWorkplaceManager().isDefaultPropertiesOnStructure()) { 258 newNavText.setStructureValue(newText); 259 } else { 260 newNavText.setResourceValue(newText); 261 } 262 } else { 263 if (oldNavText.getStructureValue() != null) { 264 newNavText.setStructureValue(newText); 265 newNavText.setResourceValue(oldNavText.getResourceValue()); 266 } else { 267 newNavText.setResourceValue(newText); 268 } 269 } 270 271 String oldStructureValue = oldNavText.getStructureValue(); 272 String newStructureValue = newNavText.getStructureValue(); 273 if (CmsStringUtil.isEmpty(oldStructureValue)) { 274 oldStructureValue = CmsProperty.DELETE_VALUE; 275 } 276 if (CmsStringUtil.isEmpty(newStructureValue)) { 277 newStructureValue = CmsProperty.DELETE_VALUE; 278 } 279 280 String oldResourceValue = oldNavText.getResourceValue(); 281 String newResourceValue = newNavText.getResourceValue(); 282 if (CmsStringUtil.isEmpty(oldResourceValue)) { 283 oldResourceValue = CmsProperty.DELETE_VALUE; 284 } 285 if (CmsStringUtil.isEmpty(newResourceValue)) { 286 newResourceValue = CmsProperty.DELETE_VALUE; 287 } 288 289 // change nav text only if it has been changed 290 if (!oldResourceValue.equals(newResourceValue) || !oldStructureValue.equals(newStructureValue)) { 291 getCms().writePropertyObject(getParamResource(), newNavText); 292 } 293 } 294 295 // determine the selected position 296 float selectedPos = -1; 297 try { 298 selectedPos = Float.parseFloat(selectedPosString); 299 } catch (Exception e) { 300 // can usually be ignored 301 if (LOG.isInfoEnabled()) { 302 LOG.info(e.getLocalizedMessage()); 303 } 304 } 305 306 // only update the position if a change is requested 307 if (selectedPos != -1) { 308 CmsProperty newNavPos = new CmsProperty(); 309 newNavPos.setName(CmsPropertyDefinition.PROPERTY_NAVPOS); 310 CmsProperty oldNavPos = getCms().readPropertyObject( 311 filename, 312 CmsPropertyDefinition.PROPERTY_NAVPOS, 313 false); 314 if (oldNavPos.isNullProperty()) { 315 // property value was not already set 316 if (OpenCms.getWorkplaceManager().isDefaultPropertiesOnStructure()) { 317 newNavPos.setStructureValue(selectedPosString); 318 } else { 319 newNavPos.setResourceValue(selectedPosString); 320 } 321 } else { 322 if (oldNavPos.getStructureValue() != null) { 323 newNavPos.setStructureValue(selectedPosString); 324 newNavPos.setResourceValue(oldNavPos.getResourceValue()); 325 } else { 326 newNavPos.setResourceValue(selectedPosString); 327 } 328 } 329 getCms().writePropertyObject(filename, newNavPos); 330 } 331 } catch (Throwable e) { 332 // error during chnav, show error dialog 333 includeErrorpage(this, e); 334 } 335 // chnav operation was successful, return to workplace 336 actionCloseDialog(); 337 } 338 339 /** 340 * Builds the HTML for the select box of the navigation position.<p> 341 * 342 * @return the HTML for a navigation position select box 343 */ 344 public String buildNavPosSelector() { 345 346 return buildNavPosSelector(getCms(), getParamResource(), null, getMessages()); 347 } 348 349 /** 350 * Returns the escaped NavText property value of the current resource.<p> 351 * 352 * @return the NavText property value of the current resource 353 */ 354 public String getCurrentNavText() { 355 356 try { 357 String navText = getCms().readPropertyObject( 358 getParamResource(), 359 CmsPropertyDefinition.PROPERTY_NAVTEXT, 360 false).getValue(); 361 if (navText == null) { 362 navText = ""; 363 } 364 return CmsEncoder.escapeXml(navText); 365 } catch (CmsException e) { 366 // can usually be ignored 367 if (LOG.isInfoEnabled()) { 368 LOG.info(e.getLocalizedMessage()); 369 } 370 return ""; 371 } 372 373 } 374 375 /** 376 * Returns the value of the navigation position parameter, 377 * or null if this parameter was not provided.<p> 378 * 379 * The navigation position parameter defines the new value for 380 * the NavPos property.<p> 381 * 382 * @return the value of the target parameter 383 */ 384 public String getParamNavpos() { 385 386 return m_paramNavpos; 387 } 388 389 /** 390 * Returns the value of the navigation text parameter, 391 * or null if this parameter was not provided.<p> 392 * 393 * The navigation text parameter defines the new value for 394 * the NavText property.<p> 395 * 396 * @return the value of the target parameter 397 */ 398 public String getParamNavtext() { 399 400 return m_paramNavtext; 401 } 402 403 /** 404 * Sets the value of the navigation position parameter.<p> 405 * 406 * @param value the value to set 407 */ 408 public void setParamNavpos(String value) { 409 410 m_paramNavpos = value; 411 } 412 413 /** 414 * Sets the value of the navigation text parameter.<p> 415 * 416 * @param value the value to set 417 */ 418 public void setParamNavtext(String value) { 419 420 m_paramNavtext = value; 421 } 422 423 /** 424 * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest) 425 */ 426 @Override 427 protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) { 428 429 // fill the parameter values in the get/set methods 430 fillParamValues(request); 431 432 // check the required permissions to change navigation of the resource 433 if (!checkResourcePermissions(CmsPermissionSet.ACCESS_WRITE, false)) { 434 // no write permissions for the resource, set cancel action to close dialog 435 setParamAction(DIALOG_CANCEL); 436 } 437 438 // set the dialog type 439 setParamDialogtype(DIALOG_TYPE); 440 // set the action for the JSP switch 441 if (DIALOG_TYPE.equals(getParamAction())) { 442 setAction(ACTION_CHNAV); 443 } else if (DIALOG_LOCKS_CONFIRMED.equals(getParamAction())) { 444 setAction(ACTION_LOCKS_CONFIRMED); 445 } else if (DIALOG_CANCEL.equals(getParamAction())) { 446 setAction(ACTION_CANCEL); 447 } else { 448 setAction(ACTION_DEFAULT); 449 // build title for chnav dialog 450 setParamTitle(key(Messages.GUI_CHNAV_1, new Object[] {CmsResource.getName(getParamResource())})); 451 } 452 } 453 454}