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.ade.contenteditor.shared; 029 030import org.opencms.acacia.shared.CmsAttributeConfiguration; 031import org.opencms.acacia.shared.CmsEntity; 032import org.opencms.acacia.shared.CmsEntityAttribute; 033import org.opencms.acacia.shared.CmsTabInfo; 034import org.opencms.acacia.shared.CmsType; 035import org.opencms.gwt.shared.CmsModelResourceInfo; 036import org.opencms.util.CmsUUID; 037 038import java.util.ArrayList; 039import java.util.Collection; 040import java.util.List; 041import java.util.Map; 042import java.util.Set; 043 044/** 045 * Contains all information needed for editing an XMLContent.<p> 046 */ 047public class CmsContentDefinition extends org.opencms.acacia.shared.CmsContentDefinition { 048 049 /** The id of the element settings tab. */ 050 public static final String SETTINGS_TAB_ID = "###formattersettings###"; 051 052 /** The entity id prefix. */ 053 private static final String ENTITY_ID_PREFIX = "http://opencms.org/resources/"; 054 055 /** The value of the acacia-unlock configuration option. */ 056 private boolean m_autoUnlock; 057 058 /** The available locales. */ 059 private Map<String, String> m_availableLocales; 060 061 /** A map from attribute names to complex widget configurations. */ 062 private Map<String, CmsComplexWidgetData> m_complexWidgetData; 063 064 /** The content locales. */ 065 private List<String> m_contentLocales; 066 067 /** Flag indicating the resource needs to removed on cancel. */ 068 private boolean m_deleteOnCancel; 069 070 /** Indicates that editor change handlers are configured. */ 071 private Set<String> m_editorChangeScopes; 072 073 /** The external widget configurations. */ 074 private List<CmsExternalWidgetConfiguration> m_externalWidgetConfigurations; 075 076 /** The resource icon classes. */ 077 private String m_iconClasses; 078 079 /** The direct edit flag (set to true for classic direct edit mode). */ 080 private boolean m_isDirectEdit; 081 082 /** The model file informations. */ 083 private List<CmsModelResourceInfo> m_modelInfos; 084 085 /** The new link. */ 086 private String m_newLink; 087 088 /** Flag indicating the current content has an invalid XML structure and was auto corrected. */ 089 private boolean m_performedAutocorrection; 090 091 /** The reference resource structure id. */ 092 private CmsUUID m_referenceResourceId; 093 094 /** The resource type name. */ 095 private String m_resourceType; 096 097 /** True if the element should be marked as 'reused' in the content editor. */ 098 private boolean m_reusedElement; 099 100 /** The site path. */ 101 private String m_sitePath; 102 103 /** The paths to skip during locale synchronization. */ 104 private Collection<String> m_skipPaths; 105 106 /** The elements that require a synchronization across all locales. */ 107 private List<String> m_synchronizations; 108 109 /** The locale synchronization values. */ 110 private Map<String, String> m_syncValues; 111 112 /** The content title. */ 113 private String m_title; 114 115 /** 116 * Constructor for model file informations object.<p> 117 * 118 * @param modelInfos the model file informations 119 * @param newLink the new link 120 * @param referenceId the reference resource structure id 121 * @param locale the locale 122 */ 123 public CmsContentDefinition( 124 List<CmsModelResourceInfo> modelInfos, 125 String newLink, 126 CmsUUID referenceId, 127 String locale) { 128 129 super(null, null, null, null, null, true, locale); 130 m_modelInfos = modelInfos; 131 m_newLink = newLink; 132 m_referenceResourceId = referenceId; 133 } 134 135 /** 136 * Constructor.<p> 137 * 138 * @param entityId the entity id 139 * @param entities the locale specific entities of the content 140 * @param configurations the attribute configurations 141 * @param externalWidgetConfigurations the external widget configurations 142 * @param complexWidgetData the complex widget configurations 143 * @param types the types 144 * @param tabInfos the tab information 145 * @param locale the content locale 146 * @param contentLocales the content locales 147 * @param availableLocales the available locales 148 * @param synchronizations the elements that require a synchronization across all locales 149 * @param syncValues the locale synchronization values 150 * @param skipPaths the paths to skip during locale synchronization 151 * @param title the content title 152 * @param sitePath the site path 153 * @param resourceType the resource type name 154 * @param iconClasses the resource icon classes 155 * @param performedAutocorrection flag indicating the current content has an invalid XML structure and was auto corrected 156 * @param autoUnlock false if the editor should not unlock resources automatically in standalone mode 157 * @param editorChangeScopes the editor change handler scopes 158 */ 159 public CmsContentDefinition( 160 String entityId, 161 Map<String, CmsEntity> entities, 162 Map<String, CmsAttributeConfiguration> configurations, 163 Collection<CmsExternalWidgetConfiguration> externalWidgetConfigurations, 164 Map<String, CmsComplexWidgetData> complexWidgetData, 165 Map<String, CmsType> types, 166 List<CmsTabInfo> tabInfos, 167 String locale, 168 List<String> contentLocales, 169 Map<String, String> availableLocales, 170 List<String> synchronizations, 171 Map<String, String> syncValues, 172 Collection<String> skipPaths, 173 String title, 174 String sitePath, 175 String resourceType, 176 String iconClasses, 177 boolean performedAutocorrection, 178 boolean autoUnlock, 179 Set<String> editorChangeScopes) { 180 181 super(entityId, entities, configurations, types, tabInfos, true, locale); 182 m_contentLocales = contentLocales; 183 m_availableLocales = availableLocales; 184 m_synchronizations = synchronizations; 185 m_syncValues = syncValues; 186 m_skipPaths = skipPaths; 187 m_complexWidgetData = complexWidgetData; 188 m_title = title; 189 m_sitePath = sitePath; 190 m_resourceType = resourceType; 191 m_iconClasses = iconClasses; 192 m_externalWidgetConfigurations = new ArrayList<CmsExternalWidgetConfiguration>(externalWidgetConfigurations); 193 m_performedAutocorrection = performedAutocorrection; 194 m_autoUnlock = autoUnlock; 195 m_editorChangeScopes = editorChangeScopes; 196 } 197 198 /** 199 * Constructor for serialization only.<p> 200 */ 201 protected CmsContentDefinition() { 202 203 super(); 204 } 205 206 /** 207 * Returns the UUID according to the given entity id.<p> 208 * 209 * @param entityId the entity id 210 * 211 * @return the entity id 212 */ 213 public static CmsUUID entityIdToUuid(String entityId) { 214 215 if (entityId.startsWith(ENTITY_ID_PREFIX)) { 216 entityId = entityId.substring(entityId.lastIndexOf("/") + 1); 217 } 218 return new CmsUUID(entityId); 219 } 220 221 /** 222 * Extracts the locale from the entity id.<p> 223 * 224 * @param entityId the entity id 225 * 226 * @return the locale 227 */ 228 public static String getLocaleFromId(String entityId) { 229 230 if (entityId.startsWith(ENTITY_ID_PREFIX)) { 231 return entityId.substring(ENTITY_ID_PREFIX.length(), entityId.lastIndexOf("/")); 232 } 233 return null; 234 } 235 236 /** 237 * Returns the value for the given XPath expression.<p> 238 * 239 * @param entity the entity 240 * @param path the path 241 * 242 * @return the value 243 */ 244 public static String getValueForPath(CmsEntity entity, String path) { 245 246 String result = null; 247 if (path.startsWith("/")) { 248 path = path.substring(1); 249 } 250 String attributeName; 251 if (path.contains("/")) { 252 attributeName = path.substring(0, path.indexOf("/")); 253 path = path.substring(path.indexOf("/")); 254 } else { 255 attributeName = path; 256 path = null; 257 } 258 int index = org.opencms.acacia.shared.CmsContentDefinition.extractIndex(attributeName); 259 if (index > 0) { 260 index--; 261 } 262 attributeName = entity.getTypeName() 263 + "/" 264 + org.opencms.acacia.shared.CmsContentDefinition.removeIndex(attributeName); 265 CmsEntityAttribute attribute = entity.getAttribute(attributeName); 266 if (!((attribute == null) || (attribute.isComplexValue() && (path == null)))) { 267 if (attribute.isSimpleValue()) { 268 if ((path == null) && (attribute.getValueCount() > 0)) { 269 List<String> values = attribute.getSimpleValues(); 270 result = values.get(index); 271 } 272 } else if (attribute.getValueCount() > (index)) { 273 List<CmsEntity> values = attribute.getComplexValues(); 274 result = getValueForPath(values.get(index), path); 275 } 276 } 277 return result; 278 } 279 280 /** 281 * Transfers values from the original entity to the given target entity.<p> 282 * 283 * @param original the original entity 284 * @param target the target entity 285 * @param transferAttributes the attributes to consider for the value transfer 286 * @param entityTypes the entity types 287 * @param attributeConfigurations the attribute configurations 288 * @param considerDefaults if default values should be added according to minimum occurrence settings 289 */ 290 public static void transferValues( 291 CmsEntity original, 292 CmsEntity target, 293 List<String> transferAttributes, 294 Map<String, CmsType> entityTypes, 295 Map<String, CmsAttributeConfiguration> attributeConfigurations, 296 boolean considerDefaults) { 297 298 CmsType entityType = entityTypes.get(target.getTypeName()); 299 for (String attributeName : entityType.getAttributeNames()) { 300 CmsType attributeType = entityTypes.get(entityType.getAttributeTypeName(attributeName)); 301 if (transferAttributes.contains(attributeName)) { 302 303 target.removeAttribute(attributeName); 304 CmsEntityAttribute attribute = original != null ? original.getAttribute(attributeName) : null; 305 if (attribute != null) { 306 if (attributeType.isSimpleType()) { 307 for (String value : attribute.getSimpleValues()) { 308 target.addAttributeValue(attributeName, value); 309 } 310 if (considerDefaults) { 311 for (int i = attribute.getValueCount(); i < entityType.getAttributeMinOccurrence( 312 attributeName); i++) { 313 target.addAttributeValue( 314 attributeName, 315 attributeConfigurations.get(attributeName).getDefaultValue()); 316 } 317 } 318 } else { 319 for (CmsEntity value : attribute.getComplexValues()) { 320 target.addAttributeValue(attributeName, value); 321 } 322 if (considerDefaults) { 323 for (int i = attribute.getValueCount(); i < entityType.getAttributeMinOccurrence( 324 attributeName); i++) { 325 target.addAttributeValue( 326 attributeName, 327 createDefaultValueEntity(attributeType, entityTypes, attributeConfigurations)); 328 } 329 } 330 } 331 } else if (considerDefaults) { 332 for (int i = 0; i < entityType.getAttributeMinOccurrence(attributeName); i++) { 333 if (attributeType.isSimpleType()) { 334 target.addAttributeValue( 335 attributeName, 336 attributeConfigurations.get(attributeName).getDefaultValue()); 337 } else { 338 target.addAttributeValue( 339 attributeName, 340 createDefaultValueEntity(attributeType, entityTypes, attributeConfigurations)); 341 } 342 } 343 } 344 } else { 345 if (!attributeType.isSimpleType()) { 346 CmsEntityAttribute targetAttribute = target.getAttribute(attributeName); 347 CmsEntityAttribute originalAttribute = original != null 348 ? original.getAttribute(attributeName) 349 : null; 350 if (targetAttribute != null) { 351 for (int i = 0; i < targetAttribute.getComplexValues().size(); i++) { 352 CmsEntity subTarget = targetAttribute.getComplexValues().get(i); 353 CmsEntity subOriginal = (originalAttribute != null) 354 && (originalAttribute.getComplexValues().size() > i) 355 ? originalAttribute.getComplexValues().get(i) 356 : null; 357 transferValues( 358 subOriginal, 359 subTarget, 360 transferAttributes, 361 entityTypes, 362 attributeConfigurations, 363 considerDefaults); 364 } 365 } 366 } 367 } 368 } 369 } 370 371 /** 372 * Returns the entity id according to the given UUID.<p> 373 * 374 * @param uuid the UUID 375 * @param locale the content locale 376 * 377 * @return the entity id 378 */ 379 public static String uuidToEntityId(CmsUUID uuid, String locale) { 380 381 return ENTITY_ID_PREFIX + locale + "/" + uuid.toString(); 382 } 383 384 /** 385 * Creates an entity object containing the default values configured for it's type.<p> 386 * 387 * @param entityType the entity type 388 * @param entityTypes the entity types 389 * @param attributeConfigurations the attribute configurations 390 * 391 * @return the created entity 392 */ 393 protected static CmsEntity createDefaultValueEntity( 394 CmsType entityType, 395 Map<String, CmsType> entityTypes, 396 Map<String, CmsAttributeConfiguration> attributeConfigurations) { 397 398 CmsEntity result = new CmsEntity(null, entityType.getId()); 399 for (String attributeName : entityType.getAttributeNames()) { 400 CmsType attributeType = entityTypes.get(entityType.getAttributeTypeName(attributeName)); 401 for (int i = 0; i < entityType.getAttributeMinOccurrence(attributeName); i++) { 402 if (attributeType.isSimpleType()) { 403 result.addAttributeValue( 404 attributeName, 405 attributeConfigurations.get(attributeName).getDefaultValue()); 406 } else { 407 result.addAttributeValue( 408 attributeName, 409 createDefaultValueEntity(attributeType, entityTypes, attributeConfigurations)); 410 } 411 } 412 } 413 return result; 414 } 415 416 /** 417 * Returns the available locales.<p> 418 * 419 * @return the available locales 420 */ 421 public Map<String, String> getAvailableLocales() { 422 423 return m_availableLocales; 424 } 425 426 /** 427 * Gets the complex widget configurations.<p> 428 * 429 * @return the complex widget configurations 430 */ 431 public Map<String, CmsComplexWidgetData> getComplexWidgetData() { 432 433 return m_complexWidgetData; 434 } 435 436 /** 437 * Returns the content locales.<p> 438 * 439 * @return the content locales 440 */ 441 public List<String> getContentLocales() { 442 443 return m_contentLocales; 444 } 445 446 /** 447 * Returns the editor change handler scopes.<p> 448 * 449 * @return the editor change handler scopes 450 */ 451 public Set<String> getEditorChangeScopes() { 452 453 return m_editorChangeScopes; 454 } 455 456 /** 457 * Returns the external widget configurations.<p> 458 * 459 * @return the external widget configurations 460 */ 461 public List<CmsExternalWidgetConfiguration> getExternalWidgetConfigurations() { 462 463 return m_externalWidgetConfigurations; 464 } 465 466 /** 467 * Returns the resource icon classes.<p> 468 * 469 * @return the resource icon classes 470 */ 471 public String getIconClasses() { 472 473 return m_iconClasses; 474 } 475 476 /** 477 * Returns the model file informations.<p> 478 * 479 * @return the model file informations 480 */ 481 public List<CmsModelResourceInfo> getModelInfos() { 482 483 return m_modelInfos; 484 } 485 486 /** 487 * Returns the new link.<p> 488 * 489 * @return the new link 490 */ 491 public String getNewLink() { 492 493 return m_newLink; 494 } 495 496 /** 497 * Returns the reference resource structure id.<p> 498 * 499 * @return the reference resource structure id 500 */ 501 public CmsUUID getReferenceResourceId() { 502 503 return m_referenceResourceId; 504 } 505 506 /** 507 * Returns the resource type.<p> 508 * 509 * @return the resource type 510 */ 511 public String getResourceType() { 512 513 return m_resourceType; 514 } 515 516 /** 517 * Returns the site path.<p> 518 * 519 * @return the site path 520 */ 521 public String getSitePath() { 522 523 return m_sitePath; 524 } 525 526 /** 527 * Returns the paths to skip during locale synchronization.<p> 528 * 529 * @return the paths to skip during locale synchronization 530 */ 531 public Collection<String> getSkipPaths() { 532 533 return m_skipPaths; 534 } 535 536 /** 537 * Returns the elements that require a synchronization across all locales.<p> 538 * 539 * @return the element paths 540 */ 541 public List<String> getSynchronizations() { 542 543 return m_synchronizations; 544 } 545 546 /** 547 * Returns the locale synchronization values.<p> 548 * 549 * @return the locale synchronization values 550 */ 551 public Map<String, String> getSyncValues() { 552 553 return m_syncValues; 554 } 555 556 /** 557 * Returns the title.<p> 558 * 559 * @return the title 560 */ 561 public String getTitle() { 562 563 return m_title; 564 } 565 566 /** 567 * Returns <code>true</code> if any editor change handlers have been configured for this content type.<p> 568 * 569 * @return <code>true</code> if any editor change handlers have been configured for this content type.<p> 570 */ 571 public boolean hasEditorChangeHandlers() { 572 573 return (m_editorChangeScopes != null) && !m_editorChangeScopes.isEmpty(); 574 } 575 576 /** 577 * Returns if there are locale synchronized elements configured.<p> 578 * 579 * @return <code>true</code> if there are locale synchronized elements configured 580 */ 581 public boolean hasSynchronizedElements() { 582 583 return !m_synchronizations.isEmpty(); 584 } 585 586 /** 587 * Returns the value of the acacia-unlock configuration option.<p> 588 * 589 * @return the value of the acacia-unlock configuration option 590 */ 591 public boolean isAutoUnlock() { 592 593 return m_autoUnlock; 594 } 595 596 /** 597 * Returns if the resource needs to removed on cancel.<p> 598 * 599 * @return <code>true</code> if the resource needs to removed on cancel 600 */ 601 public boolean isDeleteOnCancel() { 602 603 return m_deleteOnCancel; 604 } 605 606 /** 607 * Returns true if the direct edit flag is set, which means that the editor was opened from the classic direct edit mode.<p> 608 * 609 * @return true if the direct edit flag is set 610 */ 611 public boolean isDirectEdit() { 612 613 return m_isDirectEdit; 614 } 615 616 /** 617 * Returns if the model file informations are present, in this case no additional data is contained.<p> 618 * 619 * @return <code>true</code> if the definition contains the model file informations 620 */ 621 public boolean isModelInfo() { 622 623 return m_modelInfos != null; 624 } 625 626 /** 627 * Returns if auto correction was performed.<p> 628 * 629 * @return <code>true</code> if auto correction was performed 630 */ 631 public boolean isPerformedAutocorrection() { 632 633 return m_performedAutocorrection; 634 } 635 636 /** 637 * Checks if the element should be marked as 'reused' in the editor. 638 * 639 * @return true if the element should be marked as 'reused' in the editor 640 */ 641 public boolean isReusedElement() { 642 643 return m_reusedElement; 644 } 645 646 /** 647 * Sets if the resource needs to removed on cancel.<p> 648 * 649 * @param deleteOnCancel <code>true</code> if the resource needs to removed on cancel 650 */ 651 public void setDeleteOnCancel(boolean deleteOnCancel) { 652 653 m_deleteOnCancel = deleteOnCancel; 654 } 655 656 /** 657 * Sets the value of the direct edit flag.<p> 658 * 659 * @param isDirectEdit the new value for the direct edit flag 660 */ 661 public void setDirectEdit(boolean isDirectEdit) { 662 663 m_isDirectEdit = isDirectEdit; 664 } 665 666 /** 667 * Enables / disables marking of the element as 'reused' in the content editor. 668 * 669 * @param reused true if the element should be shown as 'reused' 670 */ 671 public void setReusedElement(boolean reused) { 672 673 m_reusedElement = reused; 674 675 } 676}