001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH (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, 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.jsp; 029 030import org.opencms.ade.sitemap.shared.CmsClientSitemapEntry; 031import org.opencms.file.CmsPropertyDefinition; 032import org.opencms.file.CmsResource; 033import org.opencms.i18n.CmsMessages; 034 035import java.util.Map; 036 037/** 038 * Bean to collect navigation information from a resource in the OpenCms VFS.<p> 039 * 040 * Each navigation element contains a number of information about a VFS resource, 041 * obtained either from the resources properties or attributes. 042 * You can use this information to generate a HTML navigation for 043 * files in the VFS in your template.<p> 044 * 045 * Note: this class has a natural ordering that is inconsistent with equals.<p> 046 * 047 * @since 6.0.0 048 * 049 * @see org.opencms.jsp.CmsJspNavBuilder 050 */ 051public class CmsJspNavElement implements Comparable<CmsJspNavElement> { 052 053 /** The navigation position has changed flag. */ 054 private boolean m_changedNavPos; 055 056 /** The file name. */ 057 private String m_fileName; 058 059 /** The has navigation flag. */ 060 private Boolean m_hasNav; 061 062 /** Flag indicating whether this is a hidden navigation entry. */ 063 private Boolean m_isHiddenNavigationEntry; 064 065 /** The navigation tree level. */ 066 private int m_navTreeLevel = Integer.MIN_VALUE; 067 068 /** The navigation position. */ 069 private float m_position; 070 071 /** The properties. */ 072 private Map<String, String> m_properties; 073 074 /** The resource. */ 075 private CmsResource m_resource; 076 077 /** The site path. */ 078 private String m_sitePath; 079 080 /** The navigation text. */ 081 private String m_text; 082 083 /** 084 * Empty constructor required for every JavaBean, does nothing.<p> 085 * 086 * Call one of the init methods after you have created an instance 087 * of the bean. Instead of using the constructor you should use 088 * the static factory methods provided by this class to create 089 * navigation beans that are properly initialized with current 090 * OpenCms context.<p> 091 * 092 * @see CmsJspNavBuilder#getNavigationForResource() 093 * @see CmsJspNavBuilder#getNavigationForFolder() 094 * @see CmsJspNavBuilder#getNavigationTreeForFolder(int, int) 095 */ 096 public CmsJspNavElement() { 097 098 // empty 099 } 100 101 /** 102 * Create a new instance of the bean and calls the init method 103 * with the provided parameters.<p> 104 * 105 * @param sitePath will be passed to <code>init</code> 106 * @param resource the resource 107 * @param properties will be passed to <code>init</code> 108 */ 109 public CmsJspNavElement(String sitePath, CmsResource resource, Map<String, String> properties) { 110 111 setResource(resource); 112 init(sitePath, properties); 113 } 114 115 /** 116 * Create a new instance of the bean and calls the init method 117 * with the provided parameters.<p> 118 * 119 * @param sitePath will be passed to <code>init</code> 120 * @param resource the resource 121 * @param properties will be passed to <code>init</code> 122 * @param navTreeLevel will be passed to <code>init</code> 123 * 124 * @see #init(String, Map, int) 125 */ 126 public CmsJspNavElement(String sitePath, CmsResource resource, Map<String, String> properties, int navTreeLevel) { 127 128 setResource(resource); 129 init(sitePath, properties, navTreeLevel); 130 } 131 132 /** 133 * Create a new instance of the bean and calls the init method 134 * with the provided parameters.<p> 135 * 136 * @param sitePath will be passed to <code>init</code> 137 * @param properties will be passed to <code>init</code> 138 * 139 * @see #init(String, Map) 140 * 141 * @deprecated use {@link #CmsJspNavElement(String, CmsResource, Map)} 142 */ 143 @Deprecated 144 public CmsJspNavElement(String sitePath, Map<String, String> properties) { 145 146 init(sitePath, properties, -1); 147 } 148 149 /** 150 * Create a new instance of the bean and calls the init method 151 * with the provided parameters.<p> 152 * 153 * @param sitePath will be passed to <code>init</code> 154 * @param properties will be passed to <code>init</code> 155 * @param navTreeLevel will be passed to <code>init</code> 156 * 157 * @see #init(String, Map, int) 158 * 159 * @deprecated use {@link #CmsJspNavElement(String, CmsResource, Map, int)} 160 */ 161 @Deprecated 162 public CmsJspNavElement(String sitePath, Map<String, String> properties, int navTreeLevel) { 163 164 init(sitePath, properties, navTreeLevel); 165 } 166 167 /** 168 * Note: this class has a natural ordering that is inconsistent with equals.<p> 169 * 170 * @see java.lang.Comparable#compareTo(Object) 171 */ 172 public int compareTo(CmsJspNavElement obj) { 173 174 if (obj == this) { 175 return 0; 176 } 177 float pos = obj.getNavPosition(); 178 // please note: can't just subtract and cast to int here because of float precision loss 179 if (m_position == pos) { 180 return 0; 181 } 182 return (m_position < pos) ? -1 : 1; 183 } 184 185 /** 186 * Note: this class has a natural ordering that is inconsistent with equals.<p> 187 * 188 * @see java.lang.Object#equals(Object) 189 */ 190 @Override 191 public boolean equals(Object obj) { 192 193 if (obj == this) { 194 return true; 195 } 196 if (obj instanceof CmsJspNavElement) { 197 return ((CmsJspNavElement)obj).m_sitePath.equals(m_sitePath); 198 } 199 return false; 200 } 201 202 /** 203 * Returns the value of the property PROPERTY_DESCRIPTION of this navigation element, 204 * or <code>null</code> if this property is not set.<p> 205 * 206 * @return the value of the property PROPERTY_DESCRIPTION of this navigation element 207 * or <code>null</code> if this property is not set 208 */ 209 public String getDescription() { 210 211 return m_properties.get(CmsPropertyDefinition.PROPERTY_DESCRIPTION); 212 } 213 214 /** 215 * Returns the filename of the navigation element, i.e. 216 * the name of the navigation resource without any path information.<p> 217 * 218 * @return the filename of the navigation element, i.e. 219 * the name of the navigation resource without any path information 220 */ 221 public String getFileName() { 222 223 if (m_fileName == null) { 224 // use "lazy initializing" 225 if (!m_sitePath.endsWith("/")) { 226 m_fileName = m_sitePath.substring(m_sitePath.lastIndexOf("/") + 1, m_sitePath.length()); 227 } else { 228 m_fileName = m_sitePath.substring( 229 m_sitePath.substring(0, m_sitePath.length() - 1).lastIndexOf("/") + 1, 230 m_sitePath.length()); 231 } 232 } 233 return m_fileName; 234 } 235 236 /** 237 * Returns the value of the property <code>{@link CmsPropertyDefinition#PROPERTY_NAVINFO}</code> of this 238 * navigation element, or <code>null</code> if this property is not set.<p> 239 * 240 * @return the value of the property or <code>null</code> if this property is not set 241 */ 242 public String getInfo() { 243 244 return m_properties.get(CmsPropertyDefinition.PROPERTY_NAVINFO); 245 } 246 247 /** 248 * Returns the value of the property <code>{@link CmsPropertyDefinition#PROPERTY_LOCALE}</code> of this 249 * navigation element, or <code>null</code> if this property is not set.<p> 250 * 251 * @return the value of the property or <code>null</code> if this property is not set 252 */ 253 public String getLocale() { 254 255 return m_properties.get(CmsPropertyDefinition.PROPERTY_LOCALE); 256 } 257 258 /** 259 * Returns the value of the property <code>{@link CmsPropertyDefinition#PROPERTY_NAVIMAGE}</code> of this 260 * navigation element, or <code>null</code> if this property is not set.<p> 261 * 262 * @return the value of the property or <code>null</code> if this property is not set 263 */ 264 public String getNavImage() { 265 266 return m_properties.get(CmsPropertyDefinition.PROPERTY_NAVIMAGE); 267 } 268 269 /** 270 * Returns the value of the property C_PROPERTY_NAVPOS converted to a <code>float</code>, 271 * or a value of <code>Float.MAX_VALUE</code> if the navigation position property is not 272 * set (or not a valid number) for this resource.<p> 273 * 274 * @return float the value of the property C_PROPERTY_NAVPOS converted to a <code>float</code>, 275 * or a value of <code>Float.MAX_VALUE</code> if the navigation position property is not 276 * set (or not a valid number) for this resource 277 */ 278 public float getNavPosition() { 279 280 return m_position; 281 } 282 283 /** 284 * Returns the value of the property PROPERTY_NAVTEXT of this navigation element, 285 * or a warning message if this property is not set 286 * (this method will never return <code>null</code>).<p> 287 * 288 * @return the value of the property PROPERTY_NAVTEXT of this navigation element, 289 * or a warning message if this property is not set 290 * (this method will never return <code>null</code>) 291 */ 292 public String getNavText() { 293 294 if (m_text == null) { 295 // use "lazy initializing" 296 m_text = m_properties.get(CmsPropertyDefinition.PROPERTY_NAVTEXT); 297 if (m_text == null) { 298 m_text = CmsMessages.formatUnknownKey(CmsPropertyDefinition.PROPERTY_NAVTEXT); 299 } 300 } 301 return m_text; 302 } 303 304 /** 305 * Returns the navigation tree level of this resource.<p> 306 * 307 * @return the navigation tree level of this resource 308 */ 309 public int getNavTreeLevel() { 310 311 if (m_navTreeLevel < 0) { 312 // use "lazy initializing" 313 m_navTreeLevel = CmsResource.getPathLevel(m_sitePath); 314 } 315 return m_navTreeLevel; 316 } 317 318 /** 319 * Returns the name of the parent folder of the resource of this navigation element.<p> 320 * 321 * @return the name of the parent folder of the resource of this navigation element 322 */ 323 public String getParentFolderName() { 324 325 return CmsResource.getParentFolder(m_sitePath); 326 } 327 328 /** 329 * Returns the original map of all file properties of the resource that 330 * the navigation element belongs to.<p> 331 * 332 * Please note that the original reference is returned, so be careful when making 333 * changes to the map.<p> 334 * 335 * @return the original map of all file properties of the resource that 336 * the navigation element belongs to 337 */ 338 public Map<String, String> getProperties() { 339 340 return m_properties; 341 } 342 343 /** 344 * Returns the value of the selected property from this navigation element.<p> 345 * 346 * The navigation element contains a hash of all file properties of the resource that 347 * the navigation element belongs to.<p> 348 * 349 * @param key the property name to look up 350 * 351 * @return the value of the selected property 352 */ 353 public String getProperty(String key) { 354 355 return m_properties.get(key); 356 } 357 358 /** 359 * Returns the resource.<p> 360 * 361 * @return the resource 362 */ 363 public CmsResource getResource() { 364 365 return m_resource; 366 } 367 368 /** 369 * Returns the resource name this navigation element was initialized with.<p> 370 * 371 * @return the resource name this navigation element was initialized with 372 */ 373 public String getResourceName() { 374 375 return m_sitePath; 376 } 377 378 /** 379 * Returns the value of the property PROPERTY_TITLE of this navigation element, 380 * or <code>null</code> if this property is not set.<p> 381 * 382 * @return the value of the property PROPERTY_TITLE of this navigation element 383 * or <code>null</code> if this property is not set 384 */ 385 public String getTitle() { 386 387 return m_properties.get(CmsPropertyDefinition.PROPERTY_TITLE); 388 } 389 390 /** 391 * Returns if the navigation position has been changed since initialization.<p> 392 * 393 * @return <code>true</code> if the navigation position has been changed since initialization 394 */ 395 public boolean hasChangedNavPosition() { 396 397 return m_changedNavPos; 398 } 399 400 /** 401 * Note: this class has a natural ordering that is inconsistent with equals.<p> 402 * 403 * @see java.lang.Object#hashCode() 404 */ 405 @Override 406 public int hashCode() { 407 408 return m_sitePath.hashCode(); 409 } 410 411 /** 412 * Same as calling {@link #init(String, Map, int) 413 * init(String, Hashtable, -1)}.<p> 414 * 415 * @param resource the name of the resource to extract the navigation 416 * information from 417 * @param properties the properties of the resource read from the vfs 418 */ 419 public void init(String resource, Map<String, String> properties) { 420 421 init(resource, properties, -1); 422 } 423 424 /** 425 * Initialized the member variables of this bean with the values 426 * provided.<p> 427 * 428 * A resource will be in the navigation if at least one of the two properties 429 * <code>I_CmsConstants.PROPERTY_NAVTEXT</code> or 430 * <code>I_CmsConstants.PROPERTY_NAVPOS</code> is set. Otherwise 431 * it will be ignored.<p> 432 * 433 * This bean does provides static methods to create a new instance 434 * from the context of a current CmsObject. Call these static methods 435 * in order to get a properly initialized bean.<p> 436 * 437 * @param resource the name of the resource to extract the navigation 438 * information from 439 * @param properties the properties of the resource read from the vfs 440 * @param navTreeLevel tree level of this resource, for building 441 * navigation trees 442 * 443 * @see CmsJspNavBuilder#getNavigationForResource() 444 */ 445 public void init(String resource, Map<String, String> properties, int navTreeLevel) { 446 447 m_sitePath = resource; 448 m_properties = properties; 449 m_navTreeLevel = navTreeLevel; 450 // init the position value 451 m_position = Float.MAX_VALUE; 452 try { 453 m_position = Float.parseFloat(m_properties.get(CmsPropertyDefinition.PROPERTY_NAVPOS)); 454 } catch (Exception e) { 455 // m_position will have Float.MAX_VALUE, so navigation element will 456 // appear last in navigation 457 } 458 } 459 460 /** 461 * Returns <code>true</code> if this navigation element describes a folder, 462 * <code>false</code> otherwise.<p> 463 * 464 * @return <code>true</code> if this navigation element describes a folder, 465 * <code>false</code> otherwise.<p> 466 */ 467 public boolean isFolderLink() { 468 469 return m_sitePath.endsWith("/"); 470 } 471 472 /** 473 * Returns <code>true</code> if this navigation element is in the navigation, 474 * <code>false</code> otherwise.<p> 475 * 476 * A resource is considered to be in the navigation, if <ol> 477 * <li>it has the property PROPERTY_NAVTEXT set 478 * <li><em>or</em> it has the property PROPERTY_NAVPOS set 479 * <li><em>and</em> it is not a temporary file as defined by {@link CmsResource#isTemporaryFileName(String)}.</ol> 480 * 481 * @return <code>true</code> if this navigation element is in the navigation, <code>false</code> otherwise 482 */ 483 public boolean isInNavigation() { 484 485 if (m_hasNav == null) { 486 // use "lazy initializing" 487 Object o1 = m_properties.get(CmsPropertyDefinition.PROPERTY_NAVTEXT); 488 Object o2 = m_properties.get(CmsPropertyDefinition.PROPERTY_NAVPOS); 489 m_hasNav = Boolean.valueOf(((o1 != null) || (o2 != null)) && !CmsResource.isTemporaryFileName(m_sitePath)); 490 } 491 return m_hasNav.booleanValue(); 492 } 493 494 /** 495 * Returns if this is a hidden navigation entry.<p> 496 * 497 * @return <code>true</code> if this is a hidden navigation entry 498 */ 499 public boolean isHiddenNavigationEntry() { 500 501 if (m_isHiddenNavigationEntry == null) { 502 // use "lazy initializing" 503 String navInfo = m_properties.get(CmsPropertyDefinition.PROPERTY_NAVINFO); 504 m_isHiddenNavigationEntry = Boolean.valueOf(CmsClientSitemapEntry.HIDDEN_NAVIGATION_ENTRY.equals(navInfo)); 505 } 506 return m_isHiddenNavigationEntry.booleanValue(); 507 } 508 509 /** 510 * Returns if the navigation element represents a navigation level, linking to it's first sub-element.<p> 511 * 512 * @return <code>true</code> if the navigation element represents a navigation level 513 */ 514 public boolean isNavigationLevel() { 515 516 return CmsJspNavBuilder.NAVIGATION_LEVEL_FOLDER.equals( 517 m_properties.get(CmsPropertyDefinition.PROPERTY_DEFAULT_FILE)); 518 } 519 520 /** 521 * Sets the value that will be returned by the {@link #getNavPosition()} 522 * method of this class.<p> 523 * 524 * @param value the value to set 525 */ 526 public void setNavPosition(float value) { 527 528 m_position = value; 529 m_changedNavPos = true; 530 } 531 532 /** 533 * Returns the site path of the target resource. This may not be the same as the navigation resource.<p> 534 * 535 * @return the target resource site path 536 */ 537 protected String getSitePath() { 538 539 return m_sitePath; 540 } 541 542 /** 543 * Sets the resource.<p> 544 * 545 * @param resource the resource to set 546 */ 547 protected void setResource(CmsResource resource) { 548 549 m_resource = resource; 550 } 551}