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