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