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.contextmenu; 029 030import static org.opencms.ui.contextmenu.CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE; 031import static org.opencms.ui.contextmenu.CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 032import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.controlpermission; 033import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.defaultfile; 034import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.deleted; 035import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.file; 036import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.folder; 037import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.haseditor; 038import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.hassourcecodeeditor; 039import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.inproject; 040import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.mylock; 041import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.noinheritedlock; 042import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.nootherlock; 043import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notdeleted; 044import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notinproject; 045import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notnew; 046import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notonline; 047import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notpointer; 048import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notunchangedfile; 049import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.otherlock; 050import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.pagefolder; 051import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.pointer; 052import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.publishpermission; 053import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.replacable; 054import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.roleeditor; 055import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.rolewpuser; 056import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.unlocked; 057import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.writepermisssion; 058import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.xmlunmarshal; 059 060import org.opencms.file.CmsObject; 061import org.opencms.file.CmsResource; 062import org.opencms.file.CmsResourceFilter; 063import org.opencms.file.types.CmsResourceTypeImage; 064import org.opencms.file.types.CmsResourceTypePointer; 065import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 066import org.opencms.file.types.CmsResourceTypeXmlContent; 067import org.opencms.file.types.CmsResourceTypeXmlPage; 068import org.opencms.file.types.I_CmsResourceType; 069import org.opencms.loader.CmsDumpLoader; 070import org.opencms.lock.CmsLock; 071import org.opencms.main.CmsException; 072import org.opencms.main.CmsLog; 073import org.opencms.main.OpenCms; 074import org.opencms.security.CmsPermissionSet; 075import org.opencms.security.CmsRole; 076import org.opencms.ui.I_CmsDialogContext; 077import org.opencms.ui.editors.messagebundle.CmsMessageBundleEditorTypes.BundleType; 078import org.opencms.workplace.explorer.CmsResourceUtil; 079import org.opencms.xml.content.CmsXmlContentFactory; 080 081import java.util.Set; 082 083import org.apache.commons.logging.Log; 084 085import com.google.common.collect.Sets; 086 087/** 088 * Standard visibility check implementation.<p> 089 * 090 * Instances of this class are configured with a set of flags, each of which corresponds to a check to perform which 091 * may cause the context menu item to be hidden or deactivated.<p> 092 */ 093public final class CmsStandardVisibilityCheck extends A_CmsSimpleVisibilityCheck { 094 095 /** Default visibility check for 'edit-like' operations on folders. */ 096 public static final CmsStandardVisibilityCheck COPY_PAGE = new CmsStandardVisibilityCheck( 097 roleeditor, 098 notonline, 099 notdeleted, 100 pagefolder); 101 102 /** Default visibility check for 'edit-like' operations on resources. */ 103 public static final CmsStandardVisibilityCheck DEFAULT = new CmsStandardVisibilityCheck( 104 roleeditor, 105 notonline, 106 notdeleted, 107 writepermisssion, 108 inproject); 109 110 /** 111 * Check for operations which need a default file.<p> 112 */ 113 public static final I_CmsHasMenuItemVisibility DEFAULT_DEFAULTFILE = new CmsStandardVisibilityCheck( 114 roleeditor, 115 notonline, 116 notdeleted, 117 writepermisssion, 118 inproject, 119 defaultfile); 120 121 /** Default visibility check for 'edit-like' operations on folders. */ 122 public static final CmsStandardVisibilityCheck DEFAULT_FOLDERS = new CmsStandardVisibilityCheck( 123 folder, 124 roleeditor, 125 notonline, 126 notdeleted, 127 writepermisssion, 128 inproject); 129 130 /** Like DEFAULT, but only active for files. */ 131 public static final CmsStandardVisibilityCheck EDIT = new CmsStandardVisibilityCheck( 132 file, 133 notpointer, 134 roleeditor, 135 notonline, 136 notdeleted, 137 writepermisssion, 138 inproject, 139 xmlunmarshal, 140 haseditor); 141 142 /** Like DEFAULT, but only active for files. */ 143 public static final CmsStandardVisibilityCheck EDIT_CODE = new CmsStandardVisibilityCheck( 144 file, 145 hassourcecodeeditor, 146 roleeditor, 147 notonline, 148 notdeleted, 149 writepermisssion, 150 inproject, 151 haseditor); 152 153 /** Visibility check for editing external links (pointers). */ 154 public static final I_CmsHasMenuItemVisibility EDIT_POINTER = new CmsStandardVisibilityCheck( 155 file, 156 roleeditor, 157 notonline, 158 notdeleted, 159 writepermisssion, 160 inproject, 161 pointer); 162 163 /** Check for locking resources. */ 164 public static final CmsStandardVisibilityCheck LOCK = new CmsStandardVisibilityCheck( 165 unlocked, 166 roleeditor, 167 notonline, 168 notdeleted, 169 inproject); 170 171 /** Visibility check used for copy to project dialog. */ 172 public static final CmsStandardVisibilityCheck OTHER_PROJECT = new CmsStandardVisibilityCheck( 173 roleeditor, 174 notonline, 175 notdeleted, 176 notinproject); 177 178 /** Visibility check for the permissions dialog. */ 179 public static final I_CmsHasMenuItemVisibility PERMISSIONS = new CmsStandardVisibilityCheck( 180 roleeditor, 181 notonline, 182 notdeleted, 183 writepermisssion, 184 controlpermission, 185 inproject); 186 187 /** Visibility check for publish option. */ 188 public static final CmsStandardVisibilityCheck PUBLISH = new CmsStandardVisibilityCheck( 189 notunchangedfile, 190 publishpermission, 191 notonline, 192 inproject); 193 194 /** Check for the 'replace' operation. */ 195 public static final CmsStandardVisibilityCheck REPLACE = new CmsStandardVisibilityCheck( 196 replacable, 197 roleeditor, 198 notonline, 199 notdeleted, 200 writepermisssion, 201 inproject); 202 203 /** Default check for 'locked resources' action. */ 204 public static final CmsStandardVisibilityCheck SHOW_LOCKS = new CmsStandardVisibilityCheck( 205 notonline, 206 inproject, 207 folder); 208 209 /** Permission check for stealing locks. */ 210 public static final I_CmsHasMenuItemVisibility STEAL_LOCK = new CmsStandardVisibilityCheck( 211 otherlock, 212 noinheritedlock, 213 inproject); 214 215 /** Visibility check for undelete option. */ 216 public static final CmsStandardVisibilityCheck UNDELETE = new CmsStandardVisibilityCheck( 217 roleeditor, 218 notonline, 219 deleted, 220 writepermisssion, 221 inproject); 222 223 /** Visibility check for the undo function. */ 224 public static final CmsStandardVisibilityCheck UNDO = new CmsStandardVisibilityCheck( 225 notunchangedfile, 226 notnew, 227 roleeditor, 228 notonline, 229 notdeleted, 230 writepermisssion, 231 inproject); 232 233 /** Visibility check for the undo function. */ 234 public static final CmsStandardVisibilityCheck UNLOCK = new CmsStandardVisibilityCheck( 235 mylock, 236 noinheritedlock, 237 inproject); 238 239 /** Default visibility check for view operations on resources. */ 240 public static final CmsStandardVisibilityCheck VIEW = new CmsStandardVisibilityCheck(roleeditor, notdeleted); 241 242 /** Always active. */ 243 public static final I_CmsHasMenuItemVisibility VISIBLE = new CmsStandardVisibilityCheck(); 244 245 /** Logger instance for this class. */ 246 private static final Log LOG = CmsLog.getLog(CmsStandardVisibilityCheck.class); 247 248 /** The set of flags. */ 249 private Set<CmsVisibilityCheckFlag> m_flags = Sets.newHashSet(); 250 251 /** 252 * Creates a new instance using the given flags.<p> 253 * 254 * Note that the order of the flags does not matter; the checks corresponding to the flags are performed in a fixed order. 255 * 256 * @param flags the flags indicating which checks to perform 257 */ 258 public CmsStandardVisibilityCheck(CmsVisibilityCheckFlag... flags) { 259 260 for (CmsVisibilityCheckFlag flag : flags) { 261 m_flags.add(flag); 262 } 263 } 264 265 /** 266 * Helper method to make checking for a flag very short (character count).<p> 267 * 268 * @param flag the flag to check 269 * 270 * @return true if this instance was configured with the given flag 271 */ 272 public boolean flag(CmsVisibilityCheckFlag flag) { 273 274 return m_flags.contains(flag); 275 } 276 277 /** 278 * @see org.opencms.ui.contextmenu.A_CmsSimpleVisibilityCheck#getSingleVisibility(org.opencms.file.CmsObject, org.opencms.file.CmsResource) 279 */ 280 @Override 281 public CmsMenuItemVisibilityMode getSingleVisibility(CmsObject cms, CmsResource resource) { 282 283 boolean prioritize = false; 284 String inActiveKey = null; 285 if (resource != null) { 286 if (flag(roleeditor) && !OpenCms.getRoleManager().hasRoleForResource(cms, CmsRole.EDITOR, resource)) { 287 return VISIBILITY_INVISIBLE; 288 } 289 if (flag(rolewpuser) 290 && !OpenCms.getRoleManager().hasRoleForResource(cms, CmsRole.WORKPLACE_USER, resource)) { 291 return VISIBILITY_INVISIBLE; 292 } 293 } else { 294 if (flag(roleeditor) && !OpenCms.getRoleManager().hasRole(cms, CmsRole.EDITOR)) { 295 return VISIBILITY_INVISIBLE; 296 } 297 298 if (flag(rolewpuser) && !OpenCms.getRoleManager().hasRole(cms, CmsRole.WORKPLACE_USER)) { 299 return VISIBILITY_INVISIBLE; 300 } 301 } 302 if (flag(notonline) && cms.getRequestContext().getCurrentProject().isOnlineProject()) { 303 return VISIBILITY_INVISIBLE; 304 } 305 306 if ((resource != null)) { 307 CmsResourceUtil resUtil = new CmsResourceUtil(cms, resource); 308 if (flag(file) && !resource.isFile()) { 309 return VISIBILITY_INVISIBLE; 310 } 311 312 if (flag(defaultfile)) { 313 if (!resource.isFile()) { 314 return VISIBILITY_INVISIBLE; 315 } 316 try { 317 CmsResource parentFolder = cms.readParentFolder(resource.getStructureId()); 318 if (parentFolder == null) { 319 return VISIBILITY_INVISIBLE; 320 } 321 CmsResource defaultFile = cms.readDefaultFile(parentFolder, CmsResourceFilter.IGNORE_EXPIRATION); 322 if ((defaultFile == null) || !(defaultFile.getStructureId().equals(resource.getStructureId()))) { 323 return VISIBILITY_INVISIBLE; 324 } 325 } catch (CmsException e) { 326 LOG.error(e.getLocalizedMessage(), e); 327 return VISIBILITY_INVISIBLE; 328 } 329 } 330 331 if (flag(folder) && resource.isFile()) { 332 return VISIBILITY_INVISIBLE; 333 } 334 335 if (flag(pagefolder)) { 336 if (!resource.isFolder()) { 337 return VISIBILITY_INVISIBLE; 338 } 339 try { 340 CmsResource defaultFile; 341 defaultFile = cms.readDefaultFile("" + resource.getStructureId()); 342 if ((defaultFile == null) || !CmsResourceTypeXmlContainerPage.isContainerPage(defaultFile)) { 343 return VISIBILITY_INVISIBLE; 344 } 345 } catch (CmsException e) { 346 LOG.warn(e.getLocalizedMessage(), e); 347 return VISIBILITY_INVISIBLE; 348 } 349 } 350 351 if (flag(pointer) 352 && !OpenCms.getResourceManager().matchResourceType( 353 CmsResourceTypePointer.getStaticTypeName(), 354 resource.getTypeId())) { 355 return VISIBILITY_INVISIBLE; 356 } 357 358 if (flag(notpointer) 359 && OpenCms.getResourceManager().matchResourceType( 360 CmsResourceTypePointer.getStaticTypeName(), 361 resource.getTypeId())) { 362 return VISIBILITY_INVISIBLE; 363 } 364 365 if (flag(replacable)) { 366 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resource); 367 boolean usesDumpLoader = type.getLoaderId() == CmsDumpLoader.RESOURCE_LOADER_ID; 368 if (!usesDumpLoader && !(type instanceof CmsResourceTypeImage)) { 369 return VISIBILITY_INVISIBLE; 370 } 371 372 } 373 374 if (flag(hassourcecodeeditor)) { 375 I_CmsResourceType type = resUtil.getResourceType(); 376 boolean hasSourcecodeEditor = (type instanceof CmsResourceTypeXmlContent) 377 || (type instanceof CmsResourceTypeXmlPage) 378 || (type instanceof CmsResourceTypePointer) 379 || OpenCms.getResourceManager().matchResourceType( 380 BundleType.PROPERTY.toString(), 381 resource.getTypeId()); 382 if (!hasSourcecodeEditor) { 383 return VISIBILITY_INVISIBLE; 384 } 385 } 386 387 if (flag(unlocked)) { 388 CmsLock lock = resUtil.getLock(); 389 if (!lock.isUnlocked()) { 390 return VISIBILITY_INVISIBLE; 391 } 392 prioritize = true; 393 } 394 395 if (flag(otherlock)) { 396 CmsLock lock = resUtil.getLock(); 397 if (lock.isUnlocked() || lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) { 398 return VISIBILITY_INVISIBLE; 399 } 400 prioritize = true; 401 } 402 403 if (flag(nootherlock)) { 404 CmsLock lock = resUtil.getLock(); 405 if (!lock.isUnlocked() && !lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) { 406 return VISIBILITY_INVISIBLE; 407 } 408 } 409 410 if (flag(mylock)) { 411 CmsLock lock = resUtil.getLock(); 412 if (!lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) { 413 return VISIBILITY_INVISIBLE; 414 } 415 prioritize = true; 416 } 417 418 if (flag(noinheritedlock)) { 419 CmsLock lock = resUtil.getLock(); 420 if (lock.isInherited()) { 421 return VISIBILITY_INVISIBLE; 422 } 423 } 424 425 if (flag(notunchangedfile) && resource.isFile() && resUtil.getResource().getState().isUnchanged()) { 426 inActiveKey = Messages.GUI_CONTEXTMENU_TITLE_INACTIVE_UNCHANGED_0; 427 } 428 429 if (flag(notnew) && (inActiveKey == null) && resource.getState().isNew()) { 430 inActiveKey = Messages.GUI_CONTEXTMENU_TITLE_INACTIVE_NEW_UNCHANGED_0; 431 } 432 433 if (flag(xmlunmarshal)) { 434 if (CmsResourceTypeXmlContent.isXmlContent(resource)) { 435 try { 436 CmsXmlContentFactory.unmarshal(cms, cms.readFile(resource)); 437 } catch (Exception e) { 438 return VISIBILITY_INVISIBLE; 439 } 440 } 441 442 } 443 444 if (flag(haseditor) && (OpenCms.getWorkplaceAppManager().getEditorForResource(resource, false) == null)) { 445 return VISIBILITY_INVISIBLE; 446 } 447 448 if (flag(inproject) && (!resUtil.isInsideProject() || resUtil.getProjectState().isLockedForPublishing())) { 449 return VISIBILITY_INVISIBLE; 450 } 451 452 if (flag(notinproject) 453 && (resUtil.isInsideProject() || resUtil.getProjectState().isLockedForPublishing())) { 454 return VISIBILITY_INVISIBLE; 455 } 456 457 if (flag(publishpermission)) { 458 try { 459 if (!cms.hasPermissions( 460 resource, 461 CmsPermissionSet.ACCESS_DIRECT_PUBLISH, 462 false, 463 CmsResourceFilter.ALL)) { 464 return VISIBILITY_INVISIBLE; 465 } 466 } catch (CmsException e) { 467 LOG.error(e.getLocalizedMessage(), e); 468 } 469 } 470 471 if (flag(controlpermission)) { 472 try { 473 if (!cms.hasPermissions( 474 resource, 475 CmsPermissionSet.ACCESS_CONTROL, 476 false, 477 CmsResourceFilter.IGNORE_EXPIRATION)) { 478 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 479 } 480 } catch (CmsException e) { 481 LOG.warn("Error checking context menu entry permissions", e); 482 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 483 } 484 } 485 486 if (flag(writepermisssion)) { 487 try { 488 if (!resUtil.getLock().isLockableBy(cms.getRequestContext().getCurrentUser())) { 489 // set invisible if not lockable 490 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 491 } 492 if (!resUtil.isEditable() 493 || !cms.hasPermissions( 494 resUtil.getResource(), 495 CmsPermissionSet.ACCESS_WRITE, 496 false, 497 CmsResourceFilter.ALL)) { 498 inActiveKey = Messages.GUI_CONTEXTMENU_TITLE_INACTIVE_PERM_WRITE_0; 499 } 500 } catch (CmsException e) { 501 LOG.debug("Error checking context menu entry permissions.", e); 502 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 503 } 504 } 505 506 if (flag(notdeleted) && (inActiveKey == null) && resUtil.getResource().getState().isDeleted()) { 507 inActiveKey = Messages.GUI_CONTEXTMENU_TITLE_INACTIVE_DELETED_0; 508 } 509 510 if (flag(deleted) && !resource.getState().isDeleted()) { 511 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 512 } 513 514 } else { 515 return VISIBILITY_INVISIBLE; 516 } 517 if (inActiveKey != null) { 518 return CmsMenuItemVisibilityMode.VISIBILITY_INACTIVE.addMessageKey(inActiveKey).prioritize(prioritize); 519 } 520 return VISIBILITY_ACTIVE.prioritize(prioritize); 521 } 522 523 /** 524 * @see org.opencms.ui.contextmenu.I_CmsHasMenuItemVisibility#getVisibility(org.opencms.ui.I_CmsDialogContext) 525 */ 526 public CmsMenuItemVisibilityMode getVisibility(I_CmsDialogContext context) { 527 528 return getVisibility(context.getCms(), context.getResources()); 529 } 530 531 /** 532 * @see java.lang.Object#toString() 533 */ 534 @Override 535 public String toString() { 536 537 return "visibility[" + m_flags + "]"; 538 } 539}