001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (C) Alkacon Software (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.acacia.client; 029 030import org.opencms.acacia.client.CmsUndoRedoHandler.ChangeType; 031import org.opencms.acacia.client.css.I_CmsLayoutBundle; 032import org.opencms.acacia.client.entity.I_CmsEntityBackend; 033import org.opencms.acacia.client.ui.CmsAttributeValueView; 034import org.opencms.acacia.client.ui.CmsInlineEntityWidget; 035import org.opencms.acacia.client.widgets.I_CmsFormEditWidget; 036import org.opencms.acacia.shared.CmsEntity; 037import org.opencms.acacia.shared.CmsEntityAttribute; 038import org.opencms.acacia.shared.CmsType; 039import org.opencms.gwt.client.dnd.CmsDNDHandler; 040import org.opencms.gwt.client.dnd.CmsDNDHandler.Orientation; 041import org.opencms.gwt.client.ui.CmsTabbedPanel; 042import org.opencms.gwt.client.util.CmsMoveAnimation; 043import org.opencms.gwt.shared.CmsGwtLog; 044 045import java.util.ArrayList; 046import java.util.List; 047 048import com.google.gwt.dom.client.Element; 049import com.google.gwt.dom.client.Style.Position; 050import com.google.gwt.dom.client.Style.Unit; 051import com.google.gwt.event.logical.shared.ResizeHandler; 052import com.google.gwt.user.client.Command; 053import com.google.gwt.user.client.ui.FlowPanel; 054import com.google.gwt.user.client.ui.Panel; 055import com.google.gwt.user.client.ui.Widget; 056 057/** 058 * The attribute handler. Handles value changes, addition of new values, remove and move operations on values.<p> 059 */ 060public class CmsAttributeHandler extends CmsRootHandler { 061 062 /** The global widget resize handler. */ 063 private static ResizeHandler m_resizeHandler; 064 065 /** The scroll element. */ 066 private static Element m_scrollElement; 067 068 /** The attribute name. */ 069 private String m_attributeName; 070 071 /** The attribute type. */ 072 private CmsType m_attributeType; 073 074 /** Registered attribute values. */ 075 private List<CmsAttributeValueView> m_attributeValueViews; 076 077 /** The attribute drag and drop handler. */ 078 private CmsDNDHandler m_dndHandler; 079 080 /** The entity. */ 081 private CmsEntity m_entity; 082 083 /** The entity back end instance. */ 084 private I_CmsEntityBackend m_entityBackEnd; 085 086 /** The entity type. */ 087 private CmsType m_entityType; 088 089 /** The parent attribute handler. */ 090 private I_CmsAttributeHandler m_parentHandler; 091 092 /** The single value index. */ 093 private int m_singleValueIndex; 094 095 /** The widget service. */ 096 private I_CmsWidgetService m_widgetService; 097 098 /** 099 * Constructor.<p> 100 * 101 * @param entityBackEnd the entity back end instance 102 * @param entity the entity 103 * @param attributeName the attribute name 104 * @param widgetService the widget service 105 */ 106 public CmsAttributeHandler( 107 I_CmsEntityBackend entityBackEnd, 108 CmsEntity entity, 109 String attributeName, 110 I_CmsWidgetService widgetService) { 111 112 // single value handling is disable by default 113 m_singleValueIndex = -1; 114 m_entityBackEnd = entityBackEnd; 115 m_entity = entity; 116 m_attributeName = attributeName; 117 m_widgetService = widgetService; 118 m_attributeValueViews = new ArrayList<CmsAttributeValueView>(); 119 if (!getAttributeType().isSimpleType()) { 120 int count = 0; 121 CmsEntityAttribute attribute = entity.getAttribute(attributeName); 122 if (attribute != null) { 123 count = attribute.getValueCount(); 124 } 125 initHandlers(count); 126 } 127 } 128 129 /** 130 * Clears the error styles on the given tabbed panel.<p> 131 * 132 * @param tabbedPanel the tabbed panel 133 */ 134 public static void clearErrorStyles(CmsTabbedPanel<?> tabbedPanel) { 135 136 for (int i = 0; i < tabbedPanel.getTabCount(); i++) { 137 Widget tab = tabbedPanel.getTabWidget(i); 138 tab.setTitle(null); 139 tab.getParent().removeStyleName(I_CmsLayoutBundle.INSTANCE.form().hasError()); 140 tab.getParent().removeStyleName(I_CmsLayoutBundle.INSTANCE.form().hasWarning()); 141 } 142 } 143 144 /** 145 * Returns the global widget resize handler.<p> 146 * 147 * @return the global widget resize handler 148 */ 149 public static ResizeHandler getResizeHandler() { 150 151 return m_resizeHandler; 152 } 153 154 /** 155 * Returns <code>true</code> if a global widget resize handler is present.<p> 156 * 157 * @return <code>true</code> if a global widget resize handler is present 158 */ 159 public static boolean hasResizeHandler() { 160 161 return m_resizeHandler != null; 162 } 163 164 /** 165 * Sets the global widget resize handler.<p> 166 * 167 * @param handler the resize handler 168 */ 169 public static void setResizeHandler(ResizeHandler handler) { 170 171 m_resizeHandler = handler; 172 } 173 174 /** 175 * Sets the scroll element. To be used for automatic scrolling during drag and drop.<p> 176 * 177 * @param scrollElement the scroll element 178 */ 179 public static void setScrollElement(Element scrollElement) { 180 181 m_scrollElement = scrollElement; 182 } 183 184 /** 185 * Adds a new attribute value below the reference view.<p> 186 * 187 * @param reference the reference value view 188 */ 189 public void addNewAttributeValue(CmsAttributeValueView reference) { 190 191 // make sure not to add more values than allowed 192 int maxOccurrence = getEntityType().getAttributeMaxOccurrence(m_attributeName); 193 CmsEntityAttribute attribute = m_entity.getAttribute(m_attributeName); 194 boolean mayHaveMore = ((attribute == null) || (attribute.getValueCount() < maxOccurrence)); 195 if (mayHaveMore) { 196 if (getAttributeType().isSimpleType()) { 197 int valueIndex = reference.getValueIndex() + 1; 198 String defaultValue = m_widgetService.getDefaultAttributeValue( 199 m_attributeName, 200 getSimplePath(valueIndex)); 201 I_CmsFormEditWidget widget = m_widgetService.getAttributeFormWidget(m_attributeName); 202 203 boolean insertLast = false; 204 if (reference.getElement().getNextSiblingElement() == null) { 205 m_entity.addAttributeValue(m_attributeName, defaultValue); 206 insertLast = true; 207 } else { 208 valueIndex = reference.getValueIndex() + 1; 209 m_entity.insertAttributeValue(m_attributeName, defaultValue, valueIndex); 210 m_widgetService.addChangedOrderPath(getSimplePath(-1)); 211 } 212 CmsAttributeValueView valueWidget = reference; 213 if (reference.hasValue()) { 214 valueWidget = new CmsAttributeValueView( 215 this, 216 m_widgetService.getAttributeLabel(m_attributeName), 217 m_widgetService.getAttributeHelp(m_attributeName)); 218 if (m_widgetService.isDisplaySingleLine(m_attributeName)) { 219 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SINGLE_LINE); 220 } 221 if (insertLast) { 222 ((FlowPanel)reference.getParent()).add(valueWidget); 223 } else { 224 ((FlowPanel)reference.getParent()).insert(valueWidget, valueIndex); 225 } 226 227 } 228 valueWidget.setValueWidget(widget, defaultValue, defaultValue, true); 229 } else { 230 CmsEntity value = m_entityBackEnd.createEntity(null, getAttributeType().getId()); 231 insertValueAfterReference(value, reference); 232 } 233 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 234 if (handler.isIntitalized()) { 235 handler.addChange(m_entity.getId(), m_attributeName, reference.getValueIndex() + 1, ChangeType.add); 236 } 237 } 238 updateButtonVisisbility(); 239 } 240 241 /** 242 * Adds a new attribute value and adds the required widgets to the editor DOM.<p> 243 * 244 * @param value the value entity 245 */ 246 public void addNewAttributeValue(CmsEntity value) { 247 248 // make sure not to add more values than allowed 249 int maxOccurrence = getEntityType().getAttributeMaxOccurrence(m_attributeName); 250 CmsEntityAttribute attribute = m_entity.getAttribute(m_attributeName); 251 boolean mayHaveMore = ((attribute == null) || (attribute.getValueCount() < maxOccurrence)); 252 if (mayHaveMore && value.getTypeName().equals(m_attributeType.getId())) { 253 m_entity.addAttributeValue(m_attributeName, value); 254 int valueIndex = m_entity.getAttribute(m_attributeName).getValueCount() - 1; 255 CmsAttributeValueView valueView = null; 256 if ((m_attributeValueViews.size() == 1) && !m_attributeValueViews.get(0).hasValue()) { 257 valueView = m_attributeValueViews.get(0); 258 } else { 259 valueView = new CmsAttributeValueView( 260 this, 261 m_widgetService.getAttributeLabel(m_attributeName), 262 m_widgetService.getAttributeHelp(m_attributeName)); 263 } 264 265 CmsRenderer.setAttributeChoice(m_widgetService, valueView, getAttributeType()); 266 ((FlowPanel)m_attributeValueViews.get(0).getParent()).add(valueView); 267 268 insertHandlers(valueIndex); 269 I_CmsEntityRenderer renderer = m_widgetService.getRendererForAttribute(m_attributeName, getAttributeType()); 270 valueView.setValueEntity(renderer, value); 271 272 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 273 if (handler.isIntitalized()) { 274 handler.addChange(m_entity.getId(), m_attributeName, valueIndex, ChangeType.add); 275 } 276 } 277 } 278 279 /** 280 * Adds a new attribute value and adds the required widgets to the editor DOM.<p> 281 * 282 * @param value the simple value 283 */ 284 public void addNewAttributeValue(String value) { 285 286 // make sure not to add more values than allowed 287 int maxOccurrence = getEntityType().getAttributeMaxOccurrence(m_attributeName); 288 CmsEntityAttribute attribute = m_entity.getAttribute(m_attributeName); 289 boolean mayHaveMore = ((attribute == null) || (attribute.getValueCount() < maxOccurrence)); 290 if (mayHaveMore && getAttributeType().isSimpleType()) { 291 I_CmsFormEditWidget widget = m_widgetService.getAttributeFormWidget(m_attributeName); 292 m_entity.addAttributeValue(m_attributeName, value); 293 int valueCount = m_entity.getAttribute(m_attributeName).getValueCount(); 294 String defaultValue = m_widgetService.getDefaultAttributeValue( 295 m_attributeName, 296 getSimplePath(valueCount - 1)); 297 CmsAttributeValueView valueView = null; 298 if ((m_attributeValueViews.size() == 1) && !m_attributeValueViews.get(0).hasValue()) { 299 valueView = m_attributeValueViews.get(0); 300 valueView.setActive(); 301 // setActive may have reset the value, so we set it again 302 m_entity.setAttributeValue(m_attributeName, value, valueCount - 1); 303 valueView.getValueWidget().setValue(value); 304 } else { 305 valueView = new CmsAttributeValueView( 306 this, 307 m_widgetService.getAttributeLabel(m_attributeName), 308 m_widgetService.getAttributeHelp(m_attributeName)); 309 if (m_widgetService.isDisplaySingleLine(m_attributeName)) { 310 valueView.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SINGLE_LINE); 311 } 312 ((FlowPanel)m_attributeValueViews.get(0).getParent()).add(valueView); 313 valueView.setValueWidget(widget, value, defaultValue, true); 314 } 315 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 316 if (handler.isIntitalized()) { 317 handler.addChange( 318 m_entity.getId(), 319 m_attributeName, 320 m_entity.getAttribute(m_attributeName).getValueCount() - 1, 321 ChangeType.add); 322 } 323 updateButtonVisisbility(); 324 } 325 } 326 327 /** 328 * Adds a new attribute value below the reference index.<p> 329 * This will not execute any DOM manipulations.<p> 330 * 331 * @param referenceIndex the reference value index 332 */ 333 public void addNewAttributeValueToEntity(int referenceIndex) { 334 335 // make sure not to add more values than allowed 336 int maxOccurrence = getEntityType().getAttributeMaxOccurrence(m_attributeName); 337 CmsEntityAttribute attribute = m_entity.getAttribute(m_attributeName); 338 boolean mayHaveMore = ((attribute == null) || (attribute.getValueCount() < maxOccurrence)); 339 if (mayHaveMore) { 340 if (getAttributeType().isSimpleType()) { 341 String defaultValue = m_widgetService.getDefaultAttributeValue( 342 m_attributeName, 343 getSimplePath(referenceIndex + 1)); 344 if ((attribute == null) || (attribute.getValueCount() == (referenceIndex + 1))) { 345 m_entity.addAttributeValue(m_attributeName, defaultValue); 346 } else { 347 m_entity.insertAttributeValue(m_attributeName, defaultValue, referenceIndex + 1); 348 m_widgetService.addChangedOrderPath(getSimplePath(-1)); 349 } 350 } else { 351 CmsEntity value = m_entityBackEnd.createEntity(null, m_attributeType.getId()); 352 if ((attribute == null) || (attribute.getValueCount() == (referenceIndex + 1))) { 353 m_entity.addAttributeValue(m_attributeName, value); 354 } else { 355 m_entity.insertAttributeValue(m_attributeName, value, referenceIndex + 1); 356 m_widgetService.addChangedOrderPath(getSimplePath(-1)); 357 } 358 insertHandlers(referenceIndex + 1); 359 } 360 } 361 } 362 363 /** 364 * Adds a new choice attribute value.<p> 365 * 366 * @param reference the reference value view 367 * @param choicePath the path of the selected (possibly nested) choice attribute, consisting of attribute names 368 */ 369 public void addNewChoiceAttributeValue(CmsAttributeValueView reference, List<String> choicePath) { 370 371 CmsValueFocusHandler.getInstance().clearFocus(); 372 m_widgetService.addChangedOrderPath(getSimplePath(-1)); 373 if (isChoiceHandler()) { 374 addChoiceOption(reference, choicePath); 375 } else { 376 addComplexChoiceValue(reference, choicePath); 377 } 378 updateButtonVisisbility(); 379 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 380 if (handler.isIntitalized()) { 381 handler.addChange(m_entity.getId(), m_attributeName, reference.getValueIndex() + 1, ChangeType.choice); 382 } 383 } 384 385 /** 386 * Applies a value change to the entity data as well as to the value view widget.<p> 387 * 388 * @param value the value 389 * @param valueIndex the value index 390 */ 391 public void changeValue(String value, int valueIndex) { 392 393 m_attributeValueViews.get(valueIndex).getValueWidget().setValue(value, false); 394 changeEntityValue(value, valueIndex); 395 } 396 397 /** 398 * @see org.opencms.acacia.client.CmsRootHandler#collectSimplePath(org.opencms.acacia.client.I_CmsAttributeHandler) 399 */ 400 @Override 401 public String collectSimplePath(I_CmsAttributeHandler childHandler) { 402 403 int index = -1; 404 for (int i = 0; i < m_handlers.size(); i++) { 405 if (m_handlers.get(i).get(childHandler.getAttributeName()) == childHandler) { 406 index = i; 407 break; 408 } 409 } 410 if (index == -1) { 411 throw new RuntimeException("Child handler is not properly registered."); 412 } 413 return getSimplePath(index) + "/"; 414 } 415 416 /** 417 * Creates a sequence of nested entities according to a given path of choice attribute names.<p> 418 * 419 * @param value the entity into which the new entities for the given path should be inserted 420 * @param choicePath the path of choice attributes 421 */ 422 public void createNestedEntitiesForChoicePath(CmsEntity value, List<String> choicePath) { 423 424 CmsEntity parentValue = value; 425 for (String attributeChoice : choicePath) { 426 CmsType choiceType = m_entityBackEnd.getType(parentValue.getTypeName()).getAttributeType( 427 CmsType.CHOICE_ATTRIBUTE_NAME); 428 CmsEntity choice = m_entityBackEnd.createEntity(null, choiceType.getId()); 429 parentValue.addAttributeValue(CmsType.CHOICE_ATTRIBUTE_NAME, choice); 430 CmsType choiceOptionType = choiceType.getAttributeType(attributeChoice); 431 if (choiceOptionType.isSimpleType()) { 432 String choiceValue = m_widgetService.getDefaultAttributeValue(attributeChoice, getSimplePath(0)); 433 choice.addAttributeValue(attributeChoice, choiceValue); 434 break; 435 } else { 436 CmsEntity choiceValue = m_entityBackEnd.createEntity(null, choiceOptionType.getId()); 437 choice.addAttributeValue(attributeChoice, choiceValue); 438 parentValue = choiceValue; 439 } 440 } 441 } 442 443 /** 444 * Destroys the attribute handler instance.<p> 445 */ 446 public void destroy() { 447 448 m_attributeName = null; 449 m_attributeType = null; 450 m_attributeValueViews.clear(); 451 m_attributeValueViews = null; 452 m_dndHandler = null; 453 m_entity = null; 454 m_entityType = null; 455 m_entityBackEnd = null; 456 m_widgetService = null; 457 } 458 459 /** 460 * Returns the attribute name.<p> 461 * 462 * @return the attribute name 463 */ 464 @Override 465 public String getAttributeName() { 466 467 return m_attributeName; 468 } 469 470 /** 471 * Returns the attribute type.<p> 472 * 473 * @return the attribute type 474 */ 475 public CmsType getAttributeType() { 476 477 if (m_attributeType == null) { 478 m_attributeType = getEntityType().getAttributeType(m_attributeName); 479 } 480 return m_attributeType; 481 } 482 483 /** 484 * Returns the drag and drop handler.<p> 485 * 486 * @return the drag and drop handler 487 */ 488 public CmsDNDHandler getDNDHandler() { 489 490 if (m_dndHandler == null) { 491 m_dndHandler = new CmsDNDHandler(new CmsAttributeDNDController()); 492 m_dndHandler.setOrientation(Orientation.VERTICAL); 493 m_dndHandler.setScrollEnabled(true); 494 m_dndHandler.setScrollElement(m_scrollElement); 495 } 496 return m_dndHandler; 497 } 498 499 /** 500 * Returns the entity id.<p> 501 * 502 * @return the entity id 503 */ 504 public String getEntityId() { 505 506 return m_entity.getId(); 507 } 508 509 /** 510 * Gets the maximum occurrence of the attribute.<p> 511 * 512 * @return the maximum occurrence 513 */ 514 public int getMaxOccurence() { 515 516 return getEntityType().getAttributeMaxOccurrence(m_attributeName); 517 } 518 519 /** 520 * Returns the simple value path for the given index.<p> 521 * This will use the last fragment of the attribute name and concatenate it with the parent path.<p> 522 * If the given index equals -1 no value index will be appended 523 * 524 * @param index the value index 525 * 526 * @return the simple path 527 */ 528 public String getSimplePath(int index) { 529 530 String simpleName = m_attributeName.substring(m_attributeName.lastIndexOf("/") + 1); 531 String result = m_parentHandler.collectSimplePath(this) + simpleName; 532 if (index != -1) { 533 result += "[" + (index + 1) + "]"; 534 } 535 return result; 536 } 537 538 /** 539 * Gets the widget service.<p> 540 * 541 * @return the widget service 542 */ 543 public I_CmsWidgetService getWidgetService() { 544 545 return m_widgetService; 546 } 547 548 /** 549 * Handles value changes from the view.<p> 550 * 551 * @param reference the attribute value reference 552 * @param value the value 553 */ 554 public void handleValueChange(CmsAttributeValueView reference, String value) { 555 556 handleValueChange(reference.getValueIndex(), value); 557 } 558 559 /** 560 * Handles value changes from the view.<p> 561 * 562 * @param valueIndex the value index 563 * @param value the value 564 */ 565 public void handleValueChange(int valueIndex, String value) { 566 567 if (isSingleValueHandler()) { 568 valueIndex = m_singleValueIndex; 569 } 570 changeEntityValue(value, valueIndex); 571 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 572 if (handler.isIntitalized()) { 573 handler.addChange(m_entity.getId(), m_attributeName, valueIndex, ChangeType.value); 574 } 575 } 576 577 /** 578 * Return true if there is a single remaining value, which is optional.<p> 579 * 580 * @return true if this has only one optional value 581 */ 582 public boolean hasSingleOptionalValue() { 583 584 return ((getEntityType().getAttributeMinOccurrence(m_attributeName) == 0) 585 && (m_entity.getAttribute(m_attributeName) != null) 586 && (m_entity.getAttribute(m_attributeName).getValueCount() == 1)); 587 } 588 589 /** 590 * Returns if there is a value view widget registered for the given index.<p> 591 * 592 * @param valueIndex the value index 593 * 594 * @return <code>true</code> if there is a value view widget registered for the given index 595 */ 596 public boolean hasValueView(int valueIndex) { 597 598 return m_attributeValueViews.size() > valueIndex; 599 } 600 601 /** 602 * Adds a new attribute value and adds the required widgets to the editor DOM.<p> 603 * 604 * @param value the value entity 605 * @param index the position in which to insert the new value 606 * @param container the widget containing the attribute value views 607 */ 608 public void insertNewAttributeValue(CmsEntity value, int index, Panel container) { 609 610 // make sure not to add more values than allowed 611 int maxOccurrence = getEntityType().getAttributeMaxOccurrence(m_attributeName); 612 CmsEntityAttribute attribute = m_entity.getAttribute(m_attributeName); 613 boolean mayHaveMore = ((attribute == null) || (attribute.getValueCount() < maxOccurrence)); 614 if (mayHaveMore && value.getTypeName().equals(m_attributeType.getId())) { 615 m_entity.insertAttributeValue(m_attributeName, value, index); 616 int valueIndex = index; 617 CmsAttributeValueView valueView = null; 618 if ((m_attributeValueViews.size() == 1) && !m_attributeValueViews.get(0).hasValue()) { 619 valueView = m_attributeValueViews.get(0); 620 } else { 621 valueView = new CmsAttributeValueView( 622 this, 623 m_widgetService.getAttributeLabel(m_attributeName), 624 m_widgetService.getAttributeHelp(m_attributeName)); 625 } 626 CmsRenderer.setAttributeChoice(m_widgetService, valueView, getAttributeType()); 627 m_attributeValueViews.remove(valueView); 628 m_attributeValueViews.add(index, valueView); 629 630 ((FlowPanel)container).insert(valueView, index); 631 632 insertHandlers(valueIndex); 633 634 I_CmsEntityRenderer renderer = m_widgetService.getRendererForAttribute(m_attributeName, getAttributeType()); 635 valueView.setValueEntity(renderer, value); 636 637 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 638 if (handler.isIntitalized()) { 639 handler.addChange(m_entity.getId(), m_attributeName, valueIndex, ChangeType.add); 640 } 641 } 642 } 643 644 /** 645 * Returns if this is a choice handler.<p> 646 * 647 * @return <code>true</code> if this is a choice handler 648 */ 649 public boolean isChoiceHandler() { 650 651 return CmsType.CHOICE_ATTRIBUTE_NAME.equals(m_attributeName); 652 } 653 654 /** 655 * Moves the give attribute value from one position to another.<p> 656 * 657 * @param valueView the value to move 658 * @param currentPosition the current position 659 * @param targetPosition the target position 660 */ 661 public void moveAttributeValue(CmsAttributeValueView valueView, int currentPosition, int targetPosition) { 662 663 if (currentPosition == targetPosition) { 664 return; 665 } 666 FlowPanel parent = (FlowPanel)valueView.getParent(); 667 m_widgetService.addChangedOrderPath(getSimplePath(-1)); 668 valueView.removeFromParent(); 669 m_attributeValueViews.remove(valueView); 670 CmsAttributeValueView valueWidget = null; 671 if (isChoiceHandler()) { 672 removeHandlers(currentPosition); 673 CmsEntity value = m_entity.getAttribute(m_attributeName).getComplexValues().get(currentPosition); 674 m_entity.removeAttributeValue(m_attributeName, currentPosition); 675 m_entity.insertAttributeValue(m_attributeName, value, targetPosition); 676 String attributeChoice = getChoiceName(targetPosition); 677 CmsType optionType = getAttributeType().getAttributeType(attributeChoice); 678 valueWidget = new CmsAttributeValueView( 679 this, 680 m_widgetService.getAttributeLabel(attributeChoice), 681 m_widgetService.getAttributeHelp(attributeChoice)); 682 if (optionType.isSimpleType() && m_widgetService.isDisplaySingleLine(attributeChoice)) { 683 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SINGLE_LINE); 684 } 685 parent.insert(valueWidget, targetPosition); 686 insertHandlers(targetPosition); 687 if (optionType.isSimpleType()) { 688 valueWidget.setValueWidget( 689 m_widgetService.getAttributeFormWidget(attributeChoice), 690 value.getAttribute(attributeChoice).getSimpleValue(), 691 m_widgetService.getDefaultAttributeValue(attributeChoice, getSimplePath(targetPosition)), 692 true); 693 } else { 694 valueWidget.setValueEntity( 695 m_widgetService.getRendererForAttribute(attributeChoice, getAttributeType()), 696 value.getAttribute(attributeChoice).getComplexValue()); 697 } 698 699 List<CmsChoiceMenuEntryBean> menuEntries = CmsRenderer.getChoiceEntries(getAttributeType(), true); 700 for (CmsChoiceMenuEntryBean menuEntry : menuEntries) { 701 valueWidget.addChoice(m_widgetService, menuEntry); 702 } 703 } else if (getAttributeType().isSimpleType()) { 704 String value = m_entity.getAttribute(m_attributeName).getSimpleValues().get(currentPosition); 705 m_entity.removeAttributeValue(m_attributeName, currentPosition); 706 m_entity.insertAttributeValue(m_attributeName, value, targetPosition); 707 valueWidget = new CmsAttributeValueView( 708 this, 709 m_widgetService.getAttributeLabel(m_attributeName), 710 m_widgetService.getAttributeHelp(m_attributeName)); 711 if (m_widgetService.isDisplaySingleLine(m_attributeName)) { 712 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SINGLE_LINE); 713 } 714 parent.insert(valueWidget, targetPosition); 715 valueWidget.setValueWidget( 716 m_widgetService.getAttributeFormWidget(m_attributeName), 717 value, 718 m_widgetService.getDefaultAttributeValue(m_attributeName, getSimplePath(targetPosition)), 719 true); 720 } else { 721 removeHandlers(currentPosition); 722 CmsEntity value = m_entity.getAttribute(m_attributeName).getComplexValues().get(currentPosition); 723 m_entity.removeAttributeValue(m_attributeName, currentPosition); 724 m_entity.insertAttributeValue(m_attributeName, value, targetPosition); 725 valueWidget = new CmsAttributeValueView( 726 this, 727 m_widgetService.getAttributeLabel(m_attributeName), 728 m_widgetService.getAttributeHelp(m_attributeName)); 729 parent.insert(valueWidget, targetPosition); 730 insertHandlers(targetPosition); 731 valueWidget.setValueEntity( 732 m_widgetService.getRendererForAttribute(m_attributeName, getAttributeType()), 733 value); 734 if (getAttributeType().getAttributeType(CmsType.CHOICE_ATTRIBUTE_NAME) != null) { 735 List<CmsChoiceMenuEntryBean> menuEntries = CmsRenderer.getChoiceEntries(getAttributeType(), false); 736 for (CmsChoiceMenuEntryBean entry : menuEntries) { 737 valueWidget.addChoice(m_widgetService, entry); 738 } 739 } 740 } 741 m_attributeValueViews.remove(valueWidget); 742 m_attributeValueViews.add(targetPosition, valueWidget); 743 updateButtonVisisbility(); 744 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 745 if (handler.isIntitalized()) { 746 handler.addChange(m_entity.getId(), m_attributeName, 0, ChangeType.sort); 747 } 748 } 749 750 /** 751 * Moves the reference value down in the value list.<p> 752 * 753 * @param reference the reference value 754 */ 755 public void moveAttributeValueDown(final CmsAttributeValueView reference) { 756 757 final int index = reference.getValueIndex(); 758 if (index >= (m_entity.getAttribute(m_attributeName).getValueCount() - 1)) { 759 return; 760 } 761 m_widgetService.addChangedOrderPath(getSimplePath(-1)); 762 reference.hideAllButtons(); 763 Element parent = reference.getElement().getParentElement(); 764 parent.getStyle().setPosition(Position.RELATIVE); 765 final Element placeHolder = reference.getPlaceholder(null); 766 int top = reference.getElement().getOffsetTop(); 767 int left = reference.getElement().getOffsetLeft(); 768 int width = reference.getOffsetWidth(); 769 reference.getElement().getStyle().setPosition(Position.ABSOLUTE); 770 reference.getElement().getStyle().setZIndex(5); 771 parent.insertAfter(placeHolder, reference.getElement().getNextSibling()); 772 reference.getElement().getStyle().setTop(top, Unit.PX); 773 reference.getElement().getStyle().setLeft(left, Unit.PX); 774 reference.getElement().getStyle().setWidth(width, Unit.PX); 775 new CmsMoveAnimation(reference.getElement(), top, left, placeHolder.getOffsetTop(), left, new Command() { 776 777 public void execute() { 778 779 clearMoveAnimationStyles(placeHolder, reference); 780 moveAttributeValue(reference, index, index + 1); 781 782 } 783 }).run(200); 784 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 785 if (handler.isIntitalized()) { 786 handler.addChange(m_entity.getId(), m_attributeName, 0, ChangeType.sort); 787 } 788 } 789 790 /** 791 * Moves the reference value up in the value list.<p> 792 * 793 * @param reference the reference value 794 */ 795 public void moveAttributeValueUp(final CmsAttributeValueView reference) { 796 797 final int index = reference.getValueIndex(); 798 if (index == 0) { 799 return; 800 } 801 m_widgetService.addChangedOrderPath(getSimplePath(-1)); 802 reference.hideAllButtons(); 803 Element parent = reference.getElement().getParentElement(); 804 parent.getStyle().setPosition(Position.RELATIVE); 805 final Element placeHolder = reference.getPlaceholder(null); 806 int top = reference.getElement().getOffsetTop(); 807 int left = reference.getElement().getOffsetLeft(); 808 int width = reference.getOffsetWidth(); 809 reference.getElement().getStyle().setPosition(Position.ABSOLUTE); 810 reference.getElement().getStyle().setZIndex(5); 811 parent.insertBefore(placeHolder, reference.getElement().getPreviousSibling()); 812 reference.getElement().getStyle().setTop(top, Unit.PX); 813 reference.getElement().getStyle().setLeft(left, Unit.PX); 814 reference.getElement().getStyle().setWidth(width, Unit.PX); 815 new CmsMoveAnimation(reference.getElement(), top, left, placeHolder.getOffsetTop(), left, new Command() { 816 817 public void execute() { 818 819 clearMoveAnimationStyles(placeHolder, reference); 820 moveAttributeValue(reference, index, index - 1); 821 822 } 823 }).run(200); 824 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 825 if (handler.isIntitalized()) { 826 handler.addChange(m_entity.getId(), m_attributeName, 0, ChangeType.sort); 827 } 828 } 829 830 /** 831 * Registers an attribute value view.<p> 832 * 833 * @param attributeValue the attribute value view 834 */ 835 public void registerAttributeValue(CmsAttributeValueView attributeValue) { 836 837 m_attributeValueViews.add(attributeValue); 838 } 839 840 /** 841 * Removes the reference attribute value view.<p> 842 * 843 * @param reference the reference view 844 */ 845 public void removeAttributeValue(CmsAttributeValueView reference) { 846 847 removeAttributeValue(reference, false); 848 } 849 850 /** 851 * Removes the reference attribute value view.<p> 852 * 853 * @param reference the reference view 854 * @param force <code>true</code> if the widget should be removed even if it is the last one 855 */ 856 public void removeAttributeValue(CmsAttributeValueView reference, boolean force) { 857 858 CmsAttributeHandler parentHandler = null; 859 CmsAttributeValueView parentView = null; 860 boolean removeParent = false; 861 862 CmsEntityAttribute attribute = m_entity.getAttribute(m_attributeName); 863 if (isChoiceHandler() && attribute.isSingleValue()) { 864 // removing last choice value, so remove choice itself 865 parentHandler = (CmsAttributeHandler)m_parentHandler; 866 parentView = reference.getParentView(); 867 removeParent = true; 868 } 869 870 if (attribute.isSingleValue() && !force) { 871 reference.removeValue(); 872 if (!attribute.isSimpleValue()) { 873 removeHandlers(0); 874 List<CmsEntity> entityValues = attribute.getComplexValues(); 875 if (entityValues.size() >= 1) { // this should be always 1, but make it conditional to be on the safe side 876 CmsEntity entityToRemove = entityValues.get(0); 877 m_entityBackEnd.removeEntity(entityToRemove.getId()); 878 } 879 } 880 m_entity.removeAttribute(m_attributeName); 881 } else { 882 int index = reference.getValueIndex(); 883 if (attribute.isComplexValue()) { 884 removeHandlers(index); 885 CmsEntity value = attribute.getComplexValues().get(index); 886 m_entity.removeAttributeValue(m_attributeName, index); 887 m_entityBackEnd.removeEntity(value.getId()); 888 } else { 889 m_entity.removeAttributeValue(m_attributeName, index); 890 } 891 reference.removeFromParent(); 892 m_attributeValueViews.remove(reference); 893 894 } 895 updateButtonVisisbility(); 896 if (removeParent && (parentHandler != null) && (parentView != null)) { 897 parentHandler.removeAttributeValue(parentView); 898 parentView.setCollapsed(false); 899 } 900 CmsUndoRedoHandler handler = CmsUndoRedoHandler.getInstance(); 901 if (handler.isIntitalized()) { 902 handler.addChange(m_entity.getId(), m_attributeName, 0, ChangeType.remove); 903 } 904 905 } 906 907 /** 908 * Removes the attribute value from the given index, also manipulating the editor DOM to display the change.<p> 909 * 910 * @param valueIndex the value index 911 */ 912 public void removeAttributeValue(int valueIndex) { 913 914 if (m_attributeValueViews.size() > valueIndex) { 915 removeAttributeValue(m_attributeValueViews.get(valueIndex)); 916 } 917 } 918 919 /** 920 * Removes the attribute value (and corresponding widget) with the given index, and returns 921 * the parent widget.<p> 922 * 923 * @param valueIndex the value index 924 * @param force <code>true</code> if the widget should be removed even if it is the last one 925 * 926 * @return the parent widget 927 */ 928 public Panel removeAttributeValueAndReturnPrevParent(int valueIndex, boolean force) { 929 930 if (m_attributeValueViews.size() > valueIndex) { 931 CmsAttributeValueView view = m_attributeValueViews.get(valueIndex); 932 Panel result = (Panel)view.getParent(); 933 removeAttributeValue(view, force); 934 return result; 935 } 936 return null; 937 938 } 939 940 /** 941 * Removes the attribute value with the given index.<p> 942 * This will not execute any DOM manipulations.<p> 943 * 944 * @param valueIndex the index of the attribute value to remove 945 */ 946 public void removeAttributeValueFromEntity(int valueIndex) { 947 948 CmsEntityAttribute attribute = m_entity.getAttribute(m_attributeName); 949 if (attribute.isSingleValue()) { 950 if (attribute.isComplexValue()) { 951 removeHandlers(0); 952 } 953 m_entity.removeAttribute(m_attributeName); 954 } else { 955 if (attribute.isComplexValue()) { 956 removeHandlers(valueIndex); 957 CmsEntity value = attribute.getComplexValues().get(valueIndex); 958 m_entity.removeAttributeValue(m_attributeName, valueIndex); 959 m_entityBackEnd.removeEntity(value.getId()); 960 } else { 961 m_entity.removeAttributeValue(m_attributeName, valueIndex); 962 } 963 } 964 } 965 966 /** 967 * Removes validation messages for all views associated with this attribute handler.<p> 968 */ 969 public void removeValidationMessages() { 970 971 for (CmsAttributeValueView view : m_attributeValueViews) { 972 view.removeValidationMessage(); 973 } 974 } 975 976 /** 977 * Sets the error message for the given value index.<p> 978 * 979 * @param valueIndex the value index 980 * @param message the error message 981 * @param tabbedPanel the forms tabbed panel if available 982 */ 983 public void setErrorMessage(int valueIndex, String message, CmsTabbedPanel<?> tabbedPanel) { 984 985 if (!m_attributeValueViews.isEmpty()) { 986 FlowPanel parent = (FlowPanel)m_attributeValueViews.get(0).getParent(); 987 CmsAttributeValueView valueView = (CmsAttributeValueView)parent.getWidget(valueIndex); 988 valueView.setErrorMessage(message); 989 if (tabbedPanel != null) { 990 int tabIndex = tabbedPanel.getTabIndex(valueView.getElement()); 991 if (tabIndex > -1) { 992 Widget tab = tabbedPanel.getTabWidget(tabIndex); 993 tab.setTitle("This tab has errors."); 994 tab.getParent().removeStyleName(I_CmsLayoutBundle.INSTANCE.form().hasWarning()); 995 tab.getParent().addStyleName(I_CmsLayoutBundle.INSTANCE.form().hasError()); 996 } 997 998 } 999 } 1000 } 1001 1002 /** 1003 * @see org.opencms.acacia.client.CmsRootHandler#setHandlerById(java.lang.String, org.opencms.acacia.client.CmsAttributeHandler) 1004 */ 1005 @Override 1006 public void setHandlerById(String attributeName, CmsAttributeHandler handler) { 1007 1008 if (m_parentHandler != null) { 1009 m_parentHandler.setHandlerById(attributeName, handler); 1010 } 1011 } 1012 1013 /** 1014 * Sets the parent attribute handler.<p> 1015 * 1016 * @param handler the parent attribute handler 1017 */ 1018 public void setParentHandler(I_CmsAttributeHandler handler) { 1019 1020 m_parentHandler = handler; 1021 } 1022 1023 /** 1024 * Sets the warning message for the given value index.<p> 1025 * 1026 * @param valueIndex the value index 1027 * @param message the warning message 1028 * @param tabbedPanel the forms tabbed panel if available 1029 */ 1030 public void setWarningMessage(int valueIndex, String message, CmsTabbedPanel<?> tabbedPanel) { 1031 1032 if (!m_attributeValueViews.isEmpty()) { 1033 FlowPanel parent = (FlowPanel)m_attributeValueViews.get(0).getParent(); 1034 CmsAttributeValueView valueView = (CmsAttributeValueView)parent.getWidget(valueIndex); 1035 valueView.setWarningMessage(message); 1036 if (tabbedPanel != null) { 1037 int tabIndex = tabbedPanel.getTabIndex(valueView.getElement()); 1038 if (tabIndex > -1) { 1039 Widget tab = tabbedPanel.getTabWidget(tabIndex); 1040 tab.setTitle("This tab has warnings."); 1041 tab.getParent().addStyleName(I_CmsLayoutBundle.INSTANCE.form().hasWarning()); 1042 } 1043 1044 } 1045 } 1046 } 1047 1048 /** 1049 * Updates the add, remove and sort button visibility on the given inline widget or all registered attribute value views.<p> 1050 * 1051 * @param inlineWidget the inline widget 1052 */ 1053 public void updateButtonVisibilty(CmsInlineEntityWidget inlineWidget) { 1054 1055 int minOccurrence = 0; 1056 int maxOccurrence = 0; 1057 if (isChoiceHandler()) { 1058 minOccurrence = 0; 1059 maxOccurrence = getEntityType().getChoiceMaxOccurrence(); 1060 } else { 1061 minOccurrence = getEntityType().getAttributeMinOccurrence(m_attributeName); 1062 maxOccurrence = getEntityType().getAttributeMaxOccurrence(m_attributeName); 1063 } 1064 CmsEntityAttribute attribute = m_entity.getAttribute(m_attributeName); 1065 boolean mayHaveMore = (maxOccurrence > minOccurrence) 1066 && ((((attribute == null) && (!getAttributeType().isSimpleType() || (inlineWidget != null))) 1067 || ((attribute != null) && (attribute.getValueCount() < maxOccurrence)))); 1068 boolean needsRemove = false; 1069 boolean needsSort = false; 1070 if ((isChoiceHandler() || !getEntityType().isChoice()) && m_entity.hasAttribute(m_attributeName)) { 1071 int valueCount = m_entity.getAttribute(m_attributeName).getValueCount(); 1072 needsRemove = (maxOccurrence > minOccurrence) && (valueCount > minOccurrence); 1073 needsSort = !isSingleValueHandler() && (valueCount > 1); 1074 } 1075 if (inlineWidget != null) { 1076 boolean mayEdit = (attribute != null) && (attribute.getValueCount() > inlineWidget.getAttributeIndex()); 1077 inlineWidget.updateButtonVisibility(mayEdit, mayHaveMore, needsRemove, needsSort); 1078 } else { 1079 for (CmsAttributeValueView value : m_attributeValueViews) { 1080 value.updateButtonVisibility(mayHaveMore, needsRemove, needsSort); 1081 } 1082 } 1083 } 1084 1085 /** 1086 * Updates the add, remove and sort button visibility on all registered attribute value views.<p> 1087 */ 1088 public void updateButtonVisisbility() { 1089 1090 updateButtonVisibilty(null); 1091 } 1092 1093 /** 1094 * Returns if the attribute handler is handling a single value only.<p> 1095 * 1096 * @return <code>true</code> if the attribute handler is handling a single value only 1097 */ 1098 protected boolean isSingleValueHandler() { 1099 1100 return m_singleValueIndex > -1; 1101 } 1102 1103 /** 1104 * Sets the single value index.<p> 1105 * 1106 * @param valueIndex the value index 1107 */ 1108 protected void setSingleValueIndex(int valueIndex) { 1109 1110 m_singleValueIndex = valueIndex; 1111 } 1112 1113 /** 1114 * Clears the inline styles used during move animation.<p> 1115 * 1116 * @param placeHolder the animation place holder 1117 * @param reference the moved attribute widget 1118 */ 1119 void clearMoveAnimationStyles(Element placeHolder, CmsAttributeValueView reference) { 1120 1121 placeHolder.removeFromParent(); 1122 reference.getElement().getParentElement().getStyle().clearPosition(); 1123 reference.getElement().getStyle().clearPosition(); 1124 reference.getElement().getStyle().clearWidth(); 1125 reference.getElement().getStyle().clearZIndex(); 1126 reference.showButtons(); 1127 } 1128 1129 /** 1130 * Adds a new choice option.<p> 1131 * 1132 * @param reference the reference view 1133 * @param choicePath the choice attribute path 1134 */ 1135 private void addChoiceOption(CmsAttributeValueView reference, List<String> choicePath) { 1136 1137 String attributeChoice = choicePath.get(0); 1138 CmsType optionType = getAttributeType().getAttributeType(attributeChoice); 1139 int valueIndex = reference.getValueIndex() + 1; 1140 CmsEntity choiceEntity = m_entityBackEnd.createEntity(null, getAttributeType().getId()); 1141 CmsAttributeValueView valueWidget = reference; 1142 if (reference.hasValue()) { 1143 valueWidget = new CmsAttributeValueView( 1144 this, 1145 m_widgetService.getAttributeLabel(attributeChoice), 1146 m_widgetService.getAttributeHelp(attributeChoice)); 1147 if (optionType.isSimpleType() && m_widgetService.isDisplaySingleLine(attributeChoice)) { 1148 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SINGLE_LINE); 1149 } 1150 } 1151 1152 List<CmsChoiceMenuEntryBean> menuEntries = CmsRenderer.getChoiceEntries(getAttributeType(), true); 1153 for (CmsChoiceMenuEntryBean menuEntry : menuEntries) { 1154 valueWidget.addChoice(m_widgetService, menuEntry); 1155 } 1156 1157 m_entity.insertAttributeValue(m_attributeName, choiceEntity, valueIndex); 1158 ((FlowPanel)reference.getParent()).insert(valueWidget, valueIndex); 1159 insertHandlers(valueWidget.getValueIndex()); 1160 1161 if (optionType.isSimpleType()) { 1162 String defaultValue = m_widgetService.getDefaultAttributeValue(attributeChoice, getSimplePath(valueIndex)); 1163 I_CmsFormEditWidget widget = m_widgetService.getAttributeFormWidget(attributeChoice); 1164 choiceEntity.addAttributeValue(attributeChoice, defaultValue); 1165 valueWidget.setValueWidget(widget, defaultValue, defaultValue, true); 1166 } else { 1167 CmsEntity value = m_entityBackEnd.createEntity(null, optionType.getId()); 1168 choiceEntity.addAttributeValue(attributeChoice, value); 1169 List<String> remainingAttributeNames = tail(choicePath); 1170 createNestedEntitiesForChoicePath(value, remainingAttributeNames); 1171 I_CmsEntityRenderer renderer = m_widgetService.getRendererForAttribute(attributeChoice, optionType); 1172 valueWidget.setValueEntity(renderer, value); 1173 } 1174 updateButtonVisisbility(); 1175 1176 } 1177 1178 /** 1179 * Adds a new complex value which corresponds to a choice element.<p> 1180 * 1181 * @param reference the reference view 1182 * @param choicePath the path of choice attribute names 1183 */ 1184 private void addComplexChoiceValue(CmsAttributeValueView reference, List<String> choicePath) { 1185 1186 CmsEntity value = m_entityBackEnd.createEntity(null, getAttributeType().getId()); 1187 CmsEntity parentValue = value; 1188 for (String attributeChoice : choicePath) { 1189 CmsType choiceType = m_entityBackEnd.getType(parentValue.getTypeName()).getAttributeType( 1190 CmsType.CHOICE_ATTRIBUTE_NAME); 1191 CmsEntity choice = m_entityBackEnd.createEntity(null, choiceType.getId()); 1192 parentValue.addAttributeValue(CmsType.CHOICE_ATTRIBUTE_NAME, choice); 1193 CmsType choiceOptionType = choiceType.getAttributeType(attributeChoice); 1194 if (choiceOptionType.isSimpleType()) { 1195 String choiceValue = m_widgetService.getDefaultAttributeValue(attributeChoice, getSimplePath(0)); 1196 choice.addAttributeValue(attributeChoice, choiceValue); 1197 break; 1198 } else { 1199 CmsEntity choiceValue = m_entityBackEnd.createEntity(null, choiceOptionType.getId()); 1200 choice.addAttributeValue(attributeChoice, choiceValue); 1201 parentValue = choiceValue; 1202 } 1203 } 1204 insertValueAfterReference(value, reference); 1205 if (getMaxOccurence() == 1) { 1206 reference.setCollapsed(true); 1207 } 1208 } 1209 1210 /** 1211 * Changes the attribute value.<p> 1212 * 1213 * @param valueIndex the attribute value index 1214 * @param value the value 1215 */ 1216 private void changeEntityValue(String value, int valueIndex) { 1217 1218 if (getEntityType().isChoice()) { 1219 CmsEntity choice = m_entity.getAttribute(CmsType.CHOICE_ATTRIBUTE_NAME).getComplexValues().get(valueIndex); 1220 String attributeName = getChoiceName(valueIndex); 1221 if (attributeName != null) { 1222 choice.setAttributeValue(attributeName, value, 0); 1223 } 1224 } else { 1225 m_entity.setAttributeValue(m_attributeName, value, valueIndex); 1226 } 1227 } 1228 1229 /** 1230 * Returns the attribute choice name for the given index.<p> 1231 * 1232 * @param valueIndex the value index 1233 * 1234 * @return the attribute choice name 1235 */ 1236 private String getChoiceName(int valueIndex) { 1237 1238 if (isChoiceHandler()) { 1239 CmsEntity choice = m_entity.getAttribute(CmsType.CHOICE_ATTRIBUTE_NAME).getComplexValues().get(valueIndex); 1240 if (choice != null) { 1241 for (String option : getAttributeType().getAttributeNames()) { 1242 if (choice.hasAttribute(option)) { 1243 return option; 1244 1245 } 1246 } 1247 } 1248 } 1249 return null; 1250 } 1251 1252 /** 1253 * Returns the entity type.<p> 1254 * 1255 * @return the entity type 1256 */ 1257 private CmsType getEntityType() { 1258 1259 if (m_entityType == null) { 1260 m_entityType = m_entityBackEnd.getType(m_entity.getTypeName()); 1261 } 1262 return m_entityType; 1263 } 1264 1265 /** 1266 * Inserts an entity value after the given reference.<p> 1267 * 1268 * @param value the entity value 1269 * @param reference the reference 1270 */ 1271 private void insertValueAfterReference(CmsEntity value, CmsAttributeValueView reference) { 1272 1273 int valueIndex = -1; 1274 if (reference.getElement().getNextSiblingElement() == null) { 1275 m_entity.addAttributeValue(m_attributeName, value); 1276 } else { 1277 valueIndex = reference.getValueIndex() + 1; 1278 m_entity.insertAttributeValue(m_attributeName, value, valueIndex); 1279 } 1280 CmsAttributeValueView valueWidget = reference; 1281 if (reference.hasValue()) { 1282 valueWidget = new CmsAttributeValueView( 1283 this, 1284 m_widgetService.getAttributeLabel(m_attributeName), 1285 m_widgetService.getAttributeHelp(m_attributeName)); 1286 CmsRenderer.setAttributeChoice(m_widgetService, valueWidget, getAttributeType()); 1287 if (valueIndex == -1) { 1288 ((FlowPanel)reference.getParent()).add(valueWidget); 1289 m_attributeValueViews.remove(valueWidget); 1290 m_attributeValueViews.add(valueWidget); 1291 } else { 1292 ((FlowPanel)reference.getParent()).insert(valueWidget, valueIndex); 1293 m_attributeValueViews.remove(valueWidget); 1294 m_attributeValueViews.add(valueIndex, valueWidget); 1295 m_widgetService.addChangedOrderPath(getSimplePath(-1)); 1296 } 1297 1298 } 1299 valueIndex = valueWidget.getValueIndex(); 1300 insertHandlers(valueIndex); 1301 I_CmsEntityRenderer renderer = m_widgetService.getRendererForAttribute(m_attributeName, getAttributeType()); 1302 valueWidget.setValueEntity(renderer, value); 1303 } 1304 1305 /** 1306 * Creates a list consisting of all but the first element of another list.<p> 1307 * 1308 * @param values the list 1309 * 1310 * @return the tail of the list 1311 */ 1312 private List<String> tail(List<String> values) { 1313 1314 List<String> result = new ArrayList<String>(); 1315 boolean first = true; 1316 for (String value : values) { 1317 if (!first) { 1318 result.add(value); 1319 } 1320 first = false; 1321 } 1322 return result; 1323 1324 } 1325}