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.components; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.detailpage.CmsDetailPageInfo; 032import org.opencms.db.CmsResourceState; 033import org.opencms.file.CmsObject; 034import org.opencms.file.CmsResource; 035import org.opencms.file.CmsResourceFilter; 036import org.opencms.file.types.CmsResourceTypeFolderExtended; 037import org.opencms.file.types.CmsResourceTypeFolderSubSitemap; 038import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 039import org.opencms.file.types.I_CmsResourceType; 040import org.opencms.jsp.CmsJspNavBuilder; 041import org.opencms.main.CmsException; 042import org.opencms.main.CmsLog; 043import org.opencms.main.OpenCms; 044import org.opencms.security.CmsSecurityException; 045import org.opencms.ui.CmsCssIcon; 046import org.opencms.ui.CmsVaadinUtils; 047import org.opencms.workplace.CmsWorkplace; 048import org.opencms.workplace.explorer.CmsExplorerTypeSettings; 049import org.opencms.workplace.explorer.CmsResourceUtil; 050import org.opencms.workplace.list.Messages; 051import org.opencms.xml.containerpage.CmsXmlDynamicFunctionHandler; 052 053import java.util.List; 054 055import org.apache.commons.logging.Log; 056 057import com.google.common.collect.Lists; 058import com.vaadin.server.ExternalResource; 059import com.vaadin.server.FontIcon; 060import com.vaadin.server.Resource; 061import com.vaadin.v7.shared.ui.label.ContentMode; 062import com.vaadin.v7.ui.Label; 063 064/** 065 * Displays the resource icon and state and lock info.<p> 066 * Important: To avoid issues with click event propagation within tables, we are required to extent the Label component. 067 */ 068public class CmsResourceIcon extends Label { 069 070 /** Enum used to control icon display style. */ 071 public enum IconMode { 072 /** locale compare mode. */ 073 localeCompare, 074 075 /** sitemap selection mode. */ 076 sitemapSelect; 077 } 078 079 /** The changed icon class. */ 080 public static final String ICON_CLASS_CHANGED = "oc-icon-16-overlay-changed"; 081 082 /** The other user lock icon class. */ 083 public static final String ICON_CLASS_LOCK_OTHER = "oc-icon-16-lock-other"; 084 085 /** The own user lock icon class. */ 086 public static final String ICON_CLASS_LOCK_OWN = "oc-icon-16-lock-own"; 087 088 /** The publish lock icon class. */ 089 public static final String ICON_CLASS_LOCK_PUBLISH = "oc-icon-16-lock-publish"; 090 091 /** The shared lock icon class. */ 092 public static final String ICON_CLASS_LOCK_SHARED = "oc-icon-16-lock-shared"; 093 094 /** The sibling icon class. */ 095 public static final String ICON_CLASS_SIBLING = "oc-icon-16-overlay-sibling"; 096 097 /** The log object for this class. */ 098 private static final Log LOG = CmsLog.getLog(CmsResourceIcon.class); 099 100 /** The serial version id. */ 101 private static final long serialVersionUID = 5031544534869165777L; 102 103 /** 104 * Constuctor.<p> 105 * To be used in declarative layouts. Make sure to call initContent later on.<p> 106 */ 107 public CmsResourceIcon() { 108 109 setPrimaryStyleName(OpenCmsTheme.RESOURCE_ICON); 110 setContentMode(ContentMode.HTML); 111 } 112 113 /** 114 * Constructor.<p> 115 * 116 * @param resUtil the resource util 117 * @param state the resource state 118 * @param showLocks <code>true</code> to show the resource locks 119 */ 120 public CmsResourceIcon(CmsResourceUtil resUtil, CmsResourceState state, boolean showLocks) { 121 122 this(); 123 initContent(resUtil, state, showLocks, true); 124 } 125 126 /** 127 * Returns the default file type or detail type for the given resource.<p> 128 * 129 * @param cms the cms context 130 * @param resource the container page resource 131 * 132 * @return the detail content type 133 */ 134 public static String getDefaultFileOrDetailType(CmsObject cms, CmsResource resource) { 135 136 String type = null; 137 138 if (resource.isFolder() 139 && !(OpenCms.getResourceManager().getResourceType(resource) instanceof CmsResourceTypeFolderExtended) 140 && !CmsJspNavBuilder.isNavLevelFolder(cms, resource)) { 141 try { 142 CmsResource defaultFile = cms.readDefaultFile(resource, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 143 if (defaultFile != null) { 144 type = getDetailType(cms, defaultFile, resource); 145 if (type == null) { 146 type = OpenCms.getResourceManager().getResourceType(defaultFile).getTypeName(); 147 } 148 149 } 150 } catch (CmsSecurityException e) { 151 // ignore 152 } 153 } else if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)) { 154 type = getDetailType(cms, resource, null); 155 156 } 157 return type; 158 159 } 160 161 /** 162 * Returns the detail content type for container pages that may be detail pages.<p> 163 * 164 * @param cms the cms context 165 * @param detailPage the container page resource 166 * @param parentFolder the parent folder or <code>null</code> 167 * 168 * @return the detail content type 169 */ 170 public static String getDetailType(CmsObject cms, CmsResource detailPage, CmsResource parentFolder) { 171 172 String type = null; 173 try { 174 if (OpenCms.getADEManager().isDetailPage(cms, detailPage)) { 175 List<CmsDetailPageInfo> detailPages = OpenCms.getADEManager().getRawDetailPages(cms); 176 if (parentFolder == null) { 177 parentFolder = cms.readParentFolder(detailPage.getStructureId()); 178 } 179 for (CmsDetailPageInfo info : detailPages) { 180 if (info.getId().equals(detailPage.getStructureId()) 181 || info.getId().equals(parentFolder.getStructureId())) { 182 type = info.getType(); 183 if (type.startsWith(CmsDetailPageInfo.FUNCTION_PREFIX)) { 184 type = CmsXmlDynamicFunctionHandler.TYPE_FUNCTION; 185 } 186 break; 187 } 188 } 189 } 190 } catch (CmsException e) { 191 // parent folder can't be read, ignore 192 } 193 return type; 194 } 195 196 /** 197 * Returns the icon HTML.<p> 198 * 199 * @param resUtil the resource util for the resource 200 * @param state the resource state 201 * @param showLocks <code>true</code> to show lock state overlay 202 * 203 * @return the icon HTML 204 */ 205 public static String getIconHTML(CmsResourceUtil resUtil, CmsResourceState state, boolean showLocks) { 206 207 return "<span class=\"" 208 + OpenCmsTheme.RESOURCE_ICON 209 + "\">" 210 + getIconInnerHTML(resUtil, state, showLocks, true) 211 + "</span>"; 212 } 213 214 /** 215 * Gets the resource icon for a resource for use in a CmsResourceInfo widget when used in a sitemap context.<p> 216 * 217 * @param cms the CMS context 218 * @param resource a resource 219 * @param iconMode the icon mode 220 * @return the path for the resource icon 221 */ 222 public static Resource getSitemapResourceIcon(CmsObject cms, CmsResource resource, IconMode iconMode) { 223 224 CmsResource defaultFile = null; 225 List<CmsResource> resourcesForType = Lists.newArrayList(); 226 resourcesForType.add(resource); 227 boolean skipDefaultFile = (iconMode == IconMode.sitemapSelect) 228 && OpenCms.getResourceManager().matchResourceType( 229 CmsResourceTypeFolderSubSitemap.TYPE_SUBSITEMAP, 230 resource.getTypeId()); 231 if (resource.isFolder() && !skipDefaultFile) { 232 233 try { 234 defaultFile = cms.readDefaultFile(resource, CmsResourceFilter.IGNORE_EXPIRATION); 235 if (defaultFile != null) { 236 resourcesForType.add(0, defaultFile); 237 } 238 } catch (Exception e) { 239 // Shouldn't normally happen - readDefaultFile returns null instead of throwing an exception when it doesn't find a default file 240 } 241 } 242 if (CmsJspNavBuilder.isNavLevelFolder(cms, resource)) { 243 return new CmsCssIcon(CmsExplorerTypeSettings.ICON_STYLE_NAV_LEVEL_BIG); 244 } 245 CmsResource maybePage = resourcesForType.get(0); 246 if (CmsResourceTypeXmlContainerPage.isContainerPage(maybePage)) { 247 CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(cms, maybePage.getRootPath()); 248 for (CmsDetailPageInfo realInfo : config.getAllDetailPages(true)) { 249 if (realInfo.getUri().equals(maybePage.getRootPath()) 250 || realInfo.getUri().equals(CmsResource.getParentFolder(maybePage.getRootPath()))) { 251 CmsExplorerTypeSettings settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting( 252 realInfo.getIconType()); 253 if (settings != null) { 254 return CmsResourceUtil.getBigIconResource(settings, resource.getName()); 255 } 256 } 257 } 258 } 259 260 Resource result = null; 261 for (CmsResource res : resourcesForType) { 262 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(res); 263 CmsExplorerTypeSettings settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(type.getTypeName()); 264 if (settings != null) { 265 result = CmsResourceUtil.getBigIconResource(settings, res.getName()); 266 break; 267 } 268 } 269 return result; 270 } 271 272 /** 273 * Returns the tree caption HTML including the resource icon.<p> 274 * 275 * @param resourceName the resource name to display 276 * @param resUtil the resource util for the resource 277 * @param state the resource state 278 * @param showLocks <code>true</code> to show lock state overlay 279 * 280 * @return the icon HTML 281 */ 282 public static String getTreeCaptionHTML( 283 String resourceName, 284 CmsResourceUtil resUtil, 285 CmsResourceState state, 286 boolean showLocks) { 287 288 return CmsResourceIcon.getIconHTML(resUtil, null, false) 289 + "<span class=\"o-tree-caption\">" 290 + resourceName 291 + "</span>"; 292 } 293 294 /** 295 * Returns the icon inner HTML.<p> 296 * 297 * @param resUtil the resource util for the resource 298 * @param state the resource state 299 * @param showLocks <code>true</code> to show lock state overlay 300 * @param showDetailIcon <code>true</code> to show the detail icon overlay 301 * 302 * @return the icon inner HTML 303 */ 304 private static String getIconInnerHTML( 305 CmsResourceUtil resUtil, 306 CmsResourceState state, 307 boolean showLocks, 308 boolean showDetailIcon) { 309 310 Resource iconResource = resUtil.getBigIconResource(); 311 312 return getIconInnerHTML(resUtil, iconResource, state, showLocks, showDetailIcon); 313 } 314 315 /** 316 * Returns the icon inner HTML.<p> 317 * 318 * @param resUtil the resource util for the resource 319 * @param iconResource the icon path 320 * @param state the resource state 321 * @param showLocks <code>true</code> to show lock state overlay 322 * @param showDetailIcon <code>true</code> to show the detail icon overlay 323 * 324 * @return the icon inner HTML 325 */ 326 private static String getIconInnerHTML( 327 CmsResourceUtil resUtil, 328 Resource iconResource, 329 CmsResourceState state, 330 boolean showLocks, 331 boolean showDetailIcon) { 332 333 String content; 334 if (iconResource instanceof FontIcon) { 335 content = ((FontIcon)iconResource).getHtml(); 336 } else if (iconResource instanceof ExternalResource) { 337 content = "<img src=\"" + ((ExternalResource)iconResource).getURL() + "\" />"; 338 } else { 339 content = ""; 340 } 341 342 boolean isNavLevel = false; 343 344 if (resUtil != null) { 345 if (showDetailIcon && !isNavLevel) { 346 347 if (resUtil.getResource().isFolder()) { 348 String detailType = getDefaultFileOrDetailType(resUtil.getCms(), resUtil.getResource()); 349 if (detailType != null) { 350 String smallIconUri = getSmallTypeIconHTML(detailType, false); 351 if (smallIconUri != null) { 352 content += smallIconUri; 353 } 354 } 355 } else if (CmsResourceTypeXmlContainerPage.isContainerPage(resUtil.getResource())) { 356 String detailType = getDefaultFileOrDetailType(resUtil.getCms(), resUtil.getResource()); 357 if (detailType != null) { 358 String smallIconUri = getSmallTypeIconHTML(detailType, true); 359 if (smallIconUri != null) { 360 content += smallIconUri; 361 } 362 } 363 364 } 365 } 366 if (showLocks) { 367 String lockIcon; 368 String message = null; 369 if (resUtil.getLock().getSystemLock().isPublish()) { 370 lockIcon = OpenCmsTheme.LOCK_PUBLISH + " " + ICON_CLASS_LOCK_PUBLISH; 371 message = CmsVaadinUtils.getMessageText( 372 org.opencms.workplace.explorer.Messages.GUI_PUBLISH_TOOLTIP_0); 373 } else { 374 switch (resUtil.getLockState()) { 375 case 1: 376 lockIcon = OpenCmsTheme.LOCK_OTHER + " " + ICON_CLASS_LOCK_OTHER; 377 break; 378 379 case 2: 380 lockIcon = OpenCmsTheme.LOCK_SHARED + " " + ICON_CLASS_LOCK_SHARED; 381 break; 382 case 3: 383 lockIcon = OpenCmsTheme.LOCK_USER + " " + ICON_CLASS_LOCK_OWN; 384 break; 385 default: 386 lockIcon = null; 387 } 388 if (lockIcon != null) { 389 message = CmsVaadinUtils.getMessageText( 390 Messages.GUI_EXPLORER_LIST_ACTION_LOCK_NAME_2, 391 resUtil.getLockedByName(), 392 resUtil.getLockedInProjectName()); 393 } 394 } 395 if (lockIcon != null) { 396 content += getOverlaySpan(lockIcon, message); 397 } 398 } 399 } 400 if (state != null) { 401 String title = resUtil != null 402 ? CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_LABEL_USER_LAST_MODIFIED_0) 403 + " " 404 + resUtil.getUserLastModified() 405 : null; 406 if (state.isChanged() || state.isDeleted()) { 407 content += getOverlaySpan(OpenCmsTheme.STATE_CHANGED + " " + ICON_CLASS_CHANGED, title); 408 } else if (state.isNew()) { 409 content += getOverlaySpan(OpenCmsTheme.STATE_NEW + " " + ICON_CLASS_CHANGED, title); 410 } 411 } 412 if ((resUtil != null) && (resUtil.getLinkType() == 1)) { 413 content += getOverlaySpan(OpenCmsTheme.SIBLING + " " + ICON_CLASS_SIBLING, null); 414 } 415 return content; 416 } 417 418 /** 419 * Generates an overlay icon span.<p> 420 * 421 * @param title the span title 422 * @param cssClass the CSS class 423 * 424 * @return the span element string 425 */ 426 private static String getOverlaySpan(String cssClass, String title) { 427 428 StringBuffer result = new StringBuffer(); 429 result.append("<span class=\"").append(cssClass).append("\""); 430 if (title != null) { 431 result.append(" title=\"").append(title).append("\""); 432 } 433 result.append("></span>"); 434 return result.toString(); 435 } 436 437 /** 438 * Returns the URI of the small resource type icon for the given type.<p> 439 * 440 * @param type the resource type name 441 * @param isPageOverlay <code>true</code> in case this is a page overlay and not a folder overlay 442 * 443 * @return the icon URI 444 */ 445 private static String getSmallTypeIconHTML(String type, boolean isPageOverlay) { 446 447 CmsExplorerTypeSettings typeSettings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(type); 448 if ((typeSettings == null) && LOG.isWarnEnabled()) { 449 LOG.warn("Could not read explorer type settings for " + type); 450 } 451 String result = null; 452 String overlayClass = isPageOverlay ? "o-page-icon-overlay" : "o-icon-overlay"; 453 if (typeSettings != null) { 454 if (typeSettings.getSmallIconStyle() != null) { 455 result = "<span class=\"v-icon " 456 + overlayClass 457 + " " 458 + typeSettings.getSmallIconStyle() 459 + "\"> </span>"; 460 } else if (typeSettings.getIcon() != null) { 461 result = "<img src=\"" 462 + CmsWorkplace.getResourceUri(CmsWorkplace.RES_PATH_FILETYPES + typeSettings.getIcon()) 463 + "\" class=\"" 464 + overlayClass 465 + "\" />"; 466 } else { 467 result = "<span class=\"v-icon " 468 + overlayClass 469 + " " 470 + CmsExplorerTypeSettings.ICON_STYLE_DEFAULT_SMALL 471 + "\"> </span>"; 472 } 473 } 474 return result; 475 } 476 477 /** 478 * Initializes the content.<p> 479 * 480 * @param resUtil the resource util 481 * @param state the resource state 482 * @param showLocks <code>true</code> to show the resource locks 483 * @param showDetailIcon <code>true</code> to show the detail icon overlay 484 */ 485 public void initContent( 486 CmsResourceUtil resUtil, 487 CmsResourceState state, 488 boolean showLocks, 489 boolean showDetailIcon) { 490 491 setValue(getIconInnerHTML(resUtil, state, showLocks, showDetailIcon)); 492 } 493 494 /** 495 * Initializes the content.<p> 496 * 497 * @param resUtil the resource util 498 * @param iconResource the icon path 499 * @param state the resource state 500 * @param showLocks <code>true</code> to show the resource locks 501 * @param showDetailIcon <code>true</code> to show the detail icon overlay 502 */ 503 public void initContent( 504 CmsResourceUtil resUtil, 505 Resource iconResource, 506 CmsResourceState state, 507 boolean showLocks, 508 boolean showDetailIcon) { 509 510 setValue(getIconInnerHTML(resUtil, iconResource, state, showLocks, showDetailIcon)); 511 } 512}