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.css.I_CmsLayoutBundle; 031import org.opencms.acacia.client.entity.I_CmsEntityBackend; 032import org.opencms.acacia.client.ui.CmsAttributeValueView; 033import org.opencms.acacia.client.ui.CmsInlineEntityWidget; 034import org.opencms.acacia.client.ui.CmsValuePanel; 035import org.opencms.acacia.client.widgets.I_CmsEditWidget; 036import org.opencms.acacia.shared.CmsEntity; 037import org.opencms.acacia.shared.CmsEntityAttribute; 038import org.opencms.acacia.shared.CmsTabInfo; 039import org.opencms.acacia.shared.CmsType; 040import org.opencms.gwt.client.I_CmsHasResizeOnShow; 041import org.opencms.gwt.client.ui.CmsTabbedPanel; 042import org.opencms.gwt.client.ui.CmsTabbedPanel.CmsTabbedPanelStyle; 043import org.opencms.gwt.client.util.CmsPositionBean; 044import org.opencms.gwt.shared.CmsGwtConstants; 045 046import java.util.Iterator; 047import java.util.List; 048 049import com.google.gwt.core.client.Scheduler; 050import com.google.gwt.core.client.Scheduler.RepeatingCommand; 051import com.google.gwt.core.client.Scheduler.ScheduledCommand; 052import com.google.gwt.dom.client.Element; 053import com.google.gwt.dom.client.Style.Unit; 054import com.google.gwt.event.logical.shared.ResizeEvent; 055import com.google.gwt.event.logical.shared.ResizeHandler; 056import com.google.gwt.event.logical.shared.SelectionEvent; 057import com.google.gwt.event.logical.shared.SelectionHandler; 058import com.google.gwt.event.logical.shared.ValueChangeEvent; 059import com.google.gwt.event.logical.shared.ValueChangeHandler; 060import com.google.gwt.user.client.DOM; 061import com.google.gwt.user.client.ui.FlowPanel; 062import com.google.gwt.user.client.ui.HTML; 063import com.google.gwt.user.client.ui.Panel; 064import com.google.gwt.user.client.ui.Widget; 065 066/** 067 * Renders the widgets for an in-line form.<p> 068 */ 069public class CmsRenderer implements I_CmsEntityRenderer { 070 071 /** 072 * Calls resize on tab selection on the tabs child hierarchy.<p> 073 */ 074 protected class TabSelectionHandler implements SelectionHandler<Integer> { 075 076 /** The tabbed panel. */ 077 CmsTabbedPanel<FlowPanel> m_tabsPanel; 078 079 /** 080 * Constructor.<p> 081 * 082 * @param tabsPanel the tabbed panel 083 */ 084 TabSelectionHandler(CmsTabbedPanel<FlowPanel> tabsPanel) { 085 086 m_tabsPanel = tabsPanel; 087 } 088 089 /** 090 * @see com.google.gwt.event.logical.shared.SelectionHandler#onSelection(com.google.gwt.event.logical.shared.SelectionEvent) 091 */ 092 public void onSelection(final SelectionEvent<Integer> event) { 093 094 Scheduler.get().scheduleDeferred(new ScheduledCommand() { 095 096 public void execute() { 097 098 FlowPanel tab = m_tabsPanel.getWidget(event.getSelectedItem().intValue()); 099 for (Widget w : tab) { 100 if (w instanceof I_CmsHasResizeOnShow) { 101 ((I_CmsHasResizeOnShow)w).resizeOnShow(); 102 } 103 } 104 } 105 }); 106 107 } 108 } 109 110 /** 111 * Handles the size of a tabbed panel.<p> 112 */ 113 protected class TabSizeHandler implements SelectionHandler<Integer>, ValueChangeHandler<CmsEntity>, ResizeHandler { 114 115 /** The context panel. */ 116 private Panel m_context; 117 118 /** The tabbed panel. */ 119 private CmsTabbedPanel<FlowPanel> m_tabbedPanel; 120 121 /** 122 * Constructor.<p> 123 * 124 * @param tabbedPanel the tabbed panel 125 * @param context the context panel 126 */ 127 public TabSizeHandler(CmsTabbedPanel<FlowPanel> tabbedPanel, Panel context) { 128 129 m_tabbedPanel = tabbedPanel; 130 m_context = context; 131 } 132 133 /** 134 * @see com.google.gwt.event.logical.shared.ResizeHandler#onResize(com.google.gwt.event.logical.shared.ResizeEvent) 135 */ 136 public void onResize(ResizeEvent event) { 137 138 triggerHeightAdjustment(); 139 } 140 141 /** 142 * @see com.google.gwt.event.logical.shared.SelectionHandler#onSelection(com.google.gwt.event.logical.shared.SelectionEvent) 143 */ 144 public void onSelection(SelectionEvent<Integer> event) { 145 146 triggerHeightAdjustment(); 147 } 148 149 /** 150 * @see com.google.gwt.event.logical.shared.ValueChangeHandler#onValueChange(com.google.gwt.event.logical.shared.ValueChangeEvent) 151 */ 152 public void onValueChange(ValueChangeEvent<CmsEntity> event) { 153 154 triggerHeightAdjustment(); 155 } 156 157 /** 158 * Adjusts the tabbed panel height to the height of the current tab content.<p> 159 */ 160 protected void adjustContextHeight() { 161 162 int tabIndex = m_tabbedPanel.getSelectedIndex(); 163 FlowPanel tab = m_tabbedPanel.getWidget(tabIndex); 164 int height = CmsPositionBean.getInnerDimensions(tab.getElement()).getHeight() 165 + m_tabbedPanel.getTabBarHeight(); 166 int newHeight = 22 + height; 167 m_context.getElement().getStyle().setHeight(newHeight, Unit.PX); 168 } 169 170 /** 171 * Triggers the tab panel height adjustment scheduled after the browsers event loop.<p> 172 */ 173 private void triggerHeightAdjustment() { 174 175 Scheduler.get().scheduleDeferred(new ScheduledCommand() { 176 177 public void execute() { 178 179 adjustContextHeight(); 180 } 181 }); 182 } 183 } 184 185 /** 186 * The widget value change handler.<p> 187 */ 188 protected class WidgetChangeHandler implements ValueChangeHandler<String> { 189 190 /** The attribute handler. */ 191 private CmsAttributeHandler m_attributeHandler; 192 193 /** The value index. */ 194 private int m_valueIndex; 195 196 /** 197 * Constructor.<p> 198 * 199 * @param attributeHandler the attribute handler 200 * @param valueIndex the value index, only relevant for in-line rendering 201 */ 202 protected WidgetChangeHandler(CmsAttributeHandler attributeHandler, int valueIndex) { 203 204 m_attributeHandler = attributeHandler; 205 m_valueIndex = valueIndex; 206 } 207 208 /** 209 * @see com.google.gwt.event.logical.shared.ValueChangeHandler#onValueChange(com.google.gwt.event.logical.shared.ValueChangeEvent) 210 */ 211 public void onValueChange(ValueChangeEvent<String> event) { 212 213 m_attributeHandler.handleValueChange(m_valueIndex, event.getValue()); 214 } 215 } 216 217 /** The entity CSS class. */ 218 public static final String ENTITY_CLASS = I_CmsLayoutBundle.INSTANCE.form().entity(); 219 220 /** The attribute label CSS class. */ 221 public static final String LABEL_CLASS = I_CmsLayoutBundle.INSTANCE.form().label(); 222 223 /** The renderer name. */ 224 public static final String RENDERER_NAME = "default"; 225 226 /** The widget holder CSS class. */ 227 public static final String WIDGET_HOLDER_CLASS = I_CmsLayoutBundle.INSTANCE.form().widgetHolder(); 228 229 /** The entity back end instance. */ 230 I_CmsEntityBackend m_entityBackEnd; 231 232 /** The widget service. */ 233 I_CmsWidgetService m_widgetService; 234 235 /** 236 * Constructor.<p> 237 * 238 * @param entityBackEnd the entity back end instance 239 * @param widgetService the widget service 240 */ 241 public CmsRenderer(I_CmsEntityBackend entityBackEnd, I_CmsWidgetService widgetService) { 242 243 m_entityBackEnd = entityBackEnd; 244 m_widgetService = widgetService; 245 } 246 247 /** 248 * Gets the paths of nested choice attributes starting from a given type.<p> 249 * 250 * @param attributeType the type from which to start 251 * @param startingAtChoiceAttribute true if the attribute is a synthetic CHOICE_ATTRIBUTE 252 * 253 * @return the list of nested choice attribute name paths 254 */ 255 public static List<CmsChoiceMenuEntryBean> getChoiceEntries( 256 CmsType attributeType, 257 boolean startingAtChoiceAttribute) { 258 259 CmsChoiceMenuEntryBean rootEntry = new CmsChoiceMenuEntryBean(null); 260 collectChoiceEntries(attributeType, startingAtChoiceAttribute, rootEntry); 261 return rootEntry.getChildren(); 262 } 263 264 /** 265 * Sets the attribute choices if present.<p> 266 * 267 * @param widgetService the widget service to use 268 * @param valueWidget the value widget 269 * @param attributeType the attribute type 270 */ 271 public static void setAttributeChoice( 272 I_CmsWidgetService widgetService, 273 CmsAttributeValueView valueWidget, 274 CmsType attributeType) { 275 276 if (attributeType.isChoice()) { 277 List<CmsChoiceMenuEntryBean> menuEntries = getChoiceEntries(attributeType, false); 278 for (CmsChoiceMenuEntryBean menuEntry : menuEntries) { 279 valueWidget.addChoice(widgetService, menuEntry); 280 } 281 } 282 } 283 284 /** 285 * Recursive helper method to create a tree structure of choice menu entries for a choice type.<p> 286 * 287 * @param startType the type from which to start 288 * @param startingAtChoiceAttribute true if the recursion starts at a synthetic choice attribute 289 * @param currentEntry the current menu entry bean 290 */ 291 private static void collectChoiceEntries( 292 CmsType startType, 293 boolean startingAtChoiceAttribute, 294 CmsChoiceMenuEntryBean currentEntry) { 295 296 if (startingAtChoiceAttribute || startType.isChoice()) { 297 CmsType choiceType = startingAtChoiceAttribute 298 ? startType 299 : startType.getAttributeType(CmsType.CHOICE_ATTRIBUTE_NAME); 300 for (String choiceName : choiceType.getAttributeNames()) { 301 CmsChoiceMenuEntryBean subEntry = currentEntry.addChild(choiceName); 302 CmsType includedType = choiceType.getAttributeType(choiceName); 303 collectChoiceEntries(includedType, false, subEntry); 304 } 305 } 306 } 307 308 /** 309 * @see org.opencms.acacia.client.I_CmsEntityRenderer#configure(java.lang.String) 310 */ 311 public I_CmsEntityRenderer configure(String configuration) { 312 313 return this; 314 } 315 316 /** 317 * @see org.opencms.acacia.client.I_CmsEntityRenderer#getName() 318 */ 319 public String getName() { 320 321 return RENDERER_NAME; 322 } 323 324 /** 325 * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderAttributeValue(org.opencms.acacia.shared.CmsEntity, org.opencms.acacia.client.CmsAttributeHandler, int, com.google.gwt.user.client.ui.Panel) 326 */ 327 public void renderAttributeValue( 328 CmsEntity parentEntity, 329 CmsAttributeHandler attributeHandler, 330 int attributeIndex, 331 Panel context) { 332 333 CmsType entityType = m_entityBackEnd.getType(parentEntity.getTypeName()); 334 CmsType attributeType = attributeHandler.getAttributeType(); 335 String attributeName = attributeHandler.getAttributeName(); 336 int minOccurrence = entityType.getAttributeMinOccurrence(attributeName); 337 CmsEntityAttribute attribute = parentEntity.getAttribute(attributeName); 338 if ((attribute == null) && (minOccurrence > 0)) { 339 attribute = createEmptyAttribute(parentEntity, attributeName, attributeHandler, minOccurrence); 340 } 341 342 CmsValuePanel attributeElement = new CmsValuePanel(); 343 context.add(attributeElement); 344 context.addStyleName(ENTITY_CLASS); 345 CmsRootHandler parentHandler = new CmsRootHandler(); 346 parentHandler.ensureHandlers(attributeIndex); 347 parentHandler.setHandler(attributeIndex, attributeName, attributeHandler); 348 attributeHandler.setSingleValueIndex(attributeIndex); 349 String label = m_widgetService.getAttributeLabel(attributeName); 350 String help = m_widgetService.getAttributeHelp(attributeName); 351 if (attribute != null) { 352 I_CmsEntityRenderer renderer = m_widgetService.getRendererForAttribute(attributeName, attributeType); 353 CmsAttributeValueView valueWidget = new CmsAttributeValueView(attributeHandler, label, help); 354 if (attributeType.isChoice() && (entityType.getAttributeMaxOccurrence(attributeName) == 1)) { 355 valueWidget.setCollapsed(true); 356 } 357 attributeElement.add(valueWidget); 358 if (attribute.isSimpleValue()) { 359 valueWidget.setValueWidget( 360 m_widgetService.getAttributeFormWidget(attributeName), 361 attribute.getSimpleValues().get(attributeIndex), 362 m_widgetService.getDefaultAttributeValue( 363 attributeName, 364 attributeHandler.getSimplePath(attributeIndex)), 365 true); 366 if (m_widgetService.isDisplayCompact(attributeName)) { 367 // widget should be displayed in compact view, using only 50% of the available width 368 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_FIRST_COLUMN); 369 } else { 370 if (m_widgetService.isDisplaySingleLine(attributeName)) { 371 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SINGLE_LINE); 372 } 373 } 374 } else { 375 valueWidget.setValueEntity(renderer, attribute.getComplexValues().get(attributeIndex)); 376 if (m_widgetService.isDisplayCompact(attributeName)) { 377 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_NESTED); 378 } 379 } 380 setAttributeChoice(valueWidget, attributeType); 381 } 382 attributeHandler.updateButtonVisisbility(); 383 } 384 385 /** 386 * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderForm(org.opencms.acacia.shared.CmsEntity, java.util.List, com.google.gwt.user.client.ui.Panel, org.opencms.acacia.client.I_CmsAttributeHandler, int) 387 */ 388 public CmsTabbedPanel<FlowPanel> renderForm( 389 CmsEntity entity, 390 List<CmsTabInfo> tabInfos, 391 Panel context, 392 I_CmsAttributeHandler parentHandler, 393 int attributeIndex) { 394 395 if ((tabInfos == null) || (tabInfos.size() < 2)) { 396 if ((tabInfos != null) && (tabInfos.size() == 1)) { 397 renderDescription(tabInfos.get(0), context); 398 } 399 renderForm(entity, context, parentHandler, attributeIndex); 400 finishTab(context); 401 return null; 402 } else { 403 404 context.getElement().getStyle().setHeight(600, Unit.PX); 405 context.getElement().setAttribute("typeof", entity.getTypeName()); 406 context.getElement().setAttribute(CmsGwtConstants.ATTR_DATA_ID, entity.getId()); 407 context.getElement().getStyle().setPadding(0, Unit.PX); 408 CmsTabbedPanel<FlowPanel> tabbedPanel = new CmsTabbedPanel<FlowPanel>(CmsTabbedPanelStyle.classicTabs); 409 context.add(tabbedPanel); 410 411 tabbedPanel.addStyleName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().wrapTabs()); 412 final TabSizeHandler tabSizeHandler = new TabSizeHandler(tabbedPanel, context); 413 tabbedPanel.addSelectionHandler(tabSizeHandler); 414 entity.addValueChangeHandler(tabSizeHandler); 415 // adjust the tab panel height after a delay as some widgets may need time to initialize 416 Scheduler.get().scheduleFixedDelay(new RepeatingCommand() { 417 418 private int m_counter; 419 420 /** 421 * @see com.google.gwt.core.client.Scheduler.RepeatingCommand#execute() 422 */ 423 public boolean execute() { 424 425 tabSizeHandler.adjustContextHeight(); 426 m_counter++; 427 return m_counter < 6; 428 } 429 }, 200); 430 CmsAttributeHandler.setResizeHandler(tabSizeHandler); 431 tabbedPanel.addSelectionHandler(new TabSelectionHandler(tabbedPanel)); 432 tabbedPanel.getElement().getStyle().setBorderWidth(0, Unit.PX); 433 Iterator<CmsTabInfo> tabIt = tabInfos.iterator(); 434 CmsTabInfo currentTab = tabIt.next(); 435 CmsTabInfo nextTab = tabIt.next(); 436 FlowPanel tabPanel = createTab(); 437 renderDescription(currentTab, tabPanel); 438 tabbedPanel.addNamed(tabPanel, currentTab.getTabName(), currentTab.getTabId()); 439 CmsType entityType = m_entityBackEnd.getType(entity.getTypeName()); 440 List<String> attributeNames = entityType.getAttributeNames(); 441 CmsAttributeValueView lastCompactView = null; 442 boolean collapsed = currentTab.isCollapsed() 443 && ((nextTab != null) && attributeNames.get(1).endsWith("/" + nextTab.getStartName())); 444 for (final String attributeName : attributeNames) { 445 if (!m_widgetService.isVisible(attributeName)) { 446 // attributes configured as invisible, will be skipped 447 continue; 448 } 449 if ((nextTab != null) && attributeName.endsWith("/" + nextTab.getStartName())) { 450 currentTab = nextTab; 451 nextTab = tabIt.hasNext() ? tabIt.next() : null; 452 finishTab(tabPanel); 453 tabPanel = createTab(); 454 renderDescription(currentTab, tabPanel); 455 tabbedPanel.addNamed(tabPanel, currentTab.getTabName(), currentTab.getTabId()); 456 // check if the tab content may be collapsed 457 if (currentTab.isCollapsed()) { 458 int currentIndex = attributeNames.indexOf(attributeName); 459 collapsed = ((currentIndex + 1) == attributeNames.size()) 460 || ((nextTab != null) 461 && attributeNames.get(currentIndex + 1).endsWith("/" + nextTab.getStartName())); 462 } 463 if (lastCompactView != null) { 464 // previous widget was set to first column mode, 465 // revert that as no following widget will occupy the second column 466 lastCompactView.setCompactMode(CmsAttributeValueView.COMPACT_MODE_WIDE); 467 } 468 } 469 CmsAttributeHandler handler = new CmsAttributeHandler( 470 m_entityBackEnd, 471 entity, 472 attributeName, 473 m_widgetService); 474 parentHandler.setHandler(attributeIndex, attributeName, handler); 475 CmsType attributeType = entityType.getAttributeType(attributeName); 476 int minOccurrence = entityType.getAttributeMinOccurrence(attributeName); 477 CmsEntityAttribute attribute = entity.getAttribute(attributeName); 478 // only single complex values may be collapsed 479 if (collapsed 480 && (attribute != null) 481 && !attributeType.isSimpleType() 482 && (minOccurrence == 1) 483 && (entityType.getAttributeMaxOccurrence(attributeName) == 1)) { 484 I_CmsEntityRenderer renderer = m_widgetService.getRendererForAttribute( 485 attributeName, 486 attributeType); 487 renderer.renderForm(attribute.getComplexValue(), tabPanel, handler, 0); 488 } else { 489 CmsValuePanel attributeElement = new CmsValuePanel(); 490 tabPanel.add(attributeElement); 491 if ((attribute == null) && (minOccurrence > 0)) { 492 attribute = createEmptyAttribute(entity, attributeName, handler, minOccurrence); 493 } 494 lastCompactView = renderAttribute( 495 entityType, 496 attributeType, 497 attribute, 498 handler, 499 attributeElement, 500 attributeName, 501 lastCompactView); 502 } 503 handler.updateButtonVisisbility(); 504 } 505 finishTab(tabPanel); 506 if (lastCompactView != null) { 507 // previous widget was set to first column mode, 508 // revert that as no following widget will occupy the second column 509 lastCompactView.setCompactMode(CmsAttributeValueView.COMPACT_MODE_WIDE); 510 } 511 512 return tabbedPanel; 513 } 514 } 515 516 /** 517 * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderForm(org.opencms.acacia.shared.CmsEntity, com.google.gwt.user.client.ui.Panel, org.opencms.acacia.client.I_CmsAttributeHandler, int) 518 */ 519 public void renderForm(CmsEntity entity, Panel context, I_CmsAttributeHandler parentHandler, int attributeIndex) { 520 521 context.addStyleName(ENTITY_CLASS); 522 context.getElement().setAttribute("typeof", entity.getTypeName()); 523 context.getElement().setAttribute(CmsGwtConstants.ATTR_DATA_ID, entity.getId()); 524 CmsType entityType = m_entityBackEnd.getType(entity.getTypeName()); 525 CmsAttributeValueView lastCompactView = null; 526 if (entityType.isChoice()) { 527 CmsEntityAttribute attribute = entity.getAttribute(CmsType.CHOICE_ATTRIBUTE_NAME); 528 CmsAttributeHandler handler = new CmsAttributeHandler( 529 m_entityBackEnd, 530 entity, 531 CmsType.CHOICE_ATTRIBUTE_NAME, 532 m_widgetService); 533 parentHandler.setHandler(attributeIndex, CmsType.CHOICE_ATTRIBUTE_NAME, handler); 534 CmsValuePanel attributeElement = new CmsValuePanel(); 535 if ((attribute != null) && attribute.isComplexValue()) { 536 for (CmsEntity choiceEntity : attribute.getComplexValues()) { 537 CmsType choiceType = m_entityBackEnd.getType(choiceEntity.getTypeName()); 538 List<CmsEntityAttribute> choiceAttributes = choiceEntity.getAttributes(); 539 CmsEntityAttribute choiceAttribute = choiceAttributes.get(0); 540 CmsType attributeType = choiceType.getAttributeType(choiceAttribute.getAttributeName()); 541 I_CmsEntityRenderer renderer = m_widgetService.getRendererForAttribute( 542 choiceAttribute.getAttributeName(), 543 attributeType); 544 String label = m_widgetService.getAttributeLabel(choiceAttribute.getAttributeName()); 545 String help = m_widgetService.getAttributeHelp(choiceAttribute.getAttributeName()); 546 context.add(attributeElement); 547 CmsAttributeValueView valueWidget = new CmsAttributeValueView(handler, label, help); 548 attributeElement.add(valueWidget); 549 if (choiceAttribute.isSimpleValue()) { 550 valueWidget.setValueWidget( 551 m_widgetService.getAttributeFormWidget(choiceAttribute.getAttributeName()), 552 choiceAttribute.getSimpleValue(), 553 m_widgetService.getDefaultAttributeValue( 554 choiceAttribute.getAttributeName(), 555 handler.getSimplePath(attributeIndex)), 556 true); 557 if (m_widgetService.isDisplaySingleLine(choiceAttribute.getAttributeName())) { 558 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SINGLE_LINE); 559 } 560 } else { 561 valueWidget.setValueEntity(renderer, choiceAttribute.getComplexValue()); 562 if (m_widgetService.isDisplayCompact(choiceAttribute.getAttributeName())) { 563 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_NESTED); 564 } 565 } 566 setAttributeChoice(valueWidget, entityType); 567 } 568 } 569 handler.updateButtonVisisbility(); 570 } else { 571 List<String> attributeNames = entityType.getAttributeNames(); 572 for (String attributeName : attributeNames) { 573 if (!m_widgetService.isVisible(attributeName)) { 574 // attributes configured as invisible, will be skipped 575 continue; 576 } 577 int minOccurrence = entityType.getAttributeMinOccurrence(attributeName); 578 CmsEntityAttribute attribute = entity.getAttribute(attributeName); 579 CmsAttributeHandler handler = new CmsAttributeHandler( 580 m_entityBackEnd, 581 entity, 582 attributeName, 583 m_widgetService); 584 parentHandler.setHandler(attributeIndex, attributeName, handler); 585 if ((attribute == null) && (minOccurrence > 0)) { 586 attribute = createEmptyAttribute(entity, attributeName, handler, minOccurrence); 587 } 588 589 CmsType attributeType = entityType.getAttributeType(attributeName); 590 CmsValuePanel attributeElement = new CmsValuePanel(); 591 context.add(attributeElement); 592 lastCompactView = renderAttribute( 593 entityType, 594 attributeType, 595 attribute, 596 handler, 597 attributeElement, 598 attributeName, 599 lastCompactView); 600 } 601 } 602 if (lastCompactView != null) { 603 // previous widget was set to first column mode, 604 // revert that as no following widget will occupy the second column 605 lastCompactView.setCompactMode(CmsAttributeValueView.COMPACT_MODE_WIDE); 606 } 607 } 608 609 /** 610 * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderInline(org.opencms.acacia.shared.CmsEntity, org.opencms.acacia.client.I_CmsInlineFormParent, org.opencms.acacia.client.I_CmsInlineHtmlUpdateHandler, org.opencms.acacia.client.I_CmsAttributeHandler, int) 611 */ 612 public void renderInline( 613 CmsEntity entity, 614 I_CmsInlineFormParent formParent, 615 I_CmsInlineHtmlUpdateHandler updateHandler, 616 I_CmsAttributeHandler parentHandler, 617 int attributeIndex) { 618 619 CmsType entityType = m_entityBackEnd.getType(entity.getTypeName()); 620 List<String> attributeNames = entityType.getAttributeNames(); 621 for (String attributeName : attributeNames) { 622 CmsType attributeType = entityType.getAttributeType(attributeName); 623 I_CmsEntityRenderer renderer = m_widgetService.getRendererForAttribute(attributeName, attributeType); 624 renderer.renderInline( 625 entity, 626 attributeName, 627 formParent, 628 updateHandler, 629 parentHandler, 630 attributeIndex, 631 entityType.getAttributeMinOccurrence(attributeName), 632 entityType.getAttributeMaxOccurrence(attributeName)); 633 } 634 } 635 636 /** 637 * @see org.opencms.acacia.client.I_CmsEntityRenderer#renderInline(org.opencms.acacia.shared.CmsEntity, java.lang.String, org.opencms.acacia.client.I_CmsInlineFormParent, org.opencms.acacia.client.I_CmsInlineHtmlUpdateHandler, org.opencms.acacia.client.I_CmsAttributeHandler, int, int, int) 638 */ 639 public void renderInline( 640 CmsEntity parentEntity, 641 String attributeName, 642 I_CmsInlineFormParent formParent, 643 I_CmsInlineHtmlUpdateHandler updateHandler, 644 I_CmsAttributeHandler parentHandler, 645 int attributeIndex, 646 int minOccurrence, 647 int maxOccurrence) { 648 649 CmsEntityAttribute attribute = parentEntity.getAttribute(attributeName); 650 CmsAttributeHandler handler = new CmsAttributeHandler( 651 m_entityBackEnd, 652 parentEntity, 653 attributeName, 654 m_widgetService); 655 parentHandler.setHandler(attributeIndex, attributeName, handler); 656 if (attribute != null) { 657 List<Element> elements = m_entityBackEnd.getAttributeElements( 658 parentEntity, 659 attributeName, 660 formParent.getElement()); 661 if (!elements.isEmpty()) { 662 for (int i = 0; i < elements.size(); i++) { 663 Element element = elements.get(i); 664 I_CmsEditWidget widget = m_widgetService.getAttributeInlineWidget(attributeName, element); 665 if (attribute.isSimpleValue() && (widget != null)) { 666 Element tempSpan = DOM.createSpan(); 667 tempSpan.setInnerHTML(attribute.getSimpleValues().get(i)); 668 String value = tempSpan.getInnerHTML().trim(); 669 // verify the current value equals the element content 670 String innerHtml = element.getInnerHTML().trim(); 671 if (innerHtml.equals(value)) { 672 widget.addValueChangeHandler(new WidgetChangeHandler(handler, i)); 673 formParent.adoptWidget(widget); 674 } else { 675 CmsInlineEntityWidget.createWidgetForEntity( 676 element, 677 formParent, 678 parentEntity, 679 handler, 680 i, 681 updateHandler, 682 m_widgetService); 683 } 684 } else { 685 CmsInlineEntityWidget.createWidgetForEntity( 686 element, 687 formParent, 688 parentEntity, 689 handler, 690 i, 691 updateHandler, 692 m_widgetService); 693 } 694 } 695 } 696 if (attribute.isComplexValue()) { 697 int index = 0; 698 for (CmsEntity entity : attribute.getComplexValues()) { 699 renderInline(entity, formParent, updateHandler, handler, index); 700 index++; 701 } 702 } 703 } else { 704 List<Element> elements = m_entityBackEnd.getAttributeElements( 705 parentEntity, 706 attributeName, 707 formParent.getElement()); 708 if (!elements.isEmpty() && (elements.size() == 1)) { 709 CmsInlineEntityWidget.createWidgetForEntity( 710 elements.get(0), 711 formParent, 712 parentEntity, 713 handler, 714 -1, 715 updateHandler, 716 m_widgetService); 717 } 718 } 719 720 } 721 722 /** 723 * Creates an empty attribute.<p> 724 * 725 * @param parentEntity the parent entity 726 * @param attributeName the attribute name 727 * @param handler the attribute handler 728 * @param minOccurrence the minimum occurrence of the attribute 729 * 730 * @return the entity attribute 731 */ 732 protected CmsEntityAttribute createEmptyAttribute( 733 CmsEntity parentEntity, 734 String attributeName, 735 CmsAttributeHandler handler, 736 int minOccurrence) { 737 738 CmsEntityAttribute result = null; 739 CmsType attributeType = m_entityBackEnd.getType(parentEntity.getTypeName()).getAttributeType(attributeName); 740 if (attributeType.isSimpleType()) { 741 for (int i = 0; i < minOccurrence; i++) { 742 parentEntity.addAttributeValue( 743 attributeName, 744 m_widgetService.getDefaultAttributeValue(attributeName, handler.getSimplePath(i))); 745 } 746 result = parentEntity.getAttribute(attributeName); 747 } else { 748 for (int i = 0; i < minOccurrence; i++) { 749 parentEntity.addAttributeValue( 750 attributeName, 751 m_entityBackEnd.createEntity(null, attributeType.getId())); 752 } 753 result = parentEntity.getAttribute(attributeName); 754 } 755 return result; 756 } 757 758 /** 759 * Creates a tab.<p> 760 * 761 * @return the created tab 762 */ 763 private FlowPanel createTab() { 764 765 FlowPanel tabPanel; 766 tabPanel = new FlowPanel(); 767 tabPanel.addStyleName(ENTITY_CLASS); 768 tabPanel.addStyleName(I_CmsLayoutBundle.INSTANCE.form().formParent()); 769 tabPanel.getElement().getStyle().setMargin(0, Unit.PX); 770 return tabPanel; 771 } 772 773 /** 774 * This is called after the last attribute for a tab (or for the whole content, if no tabs are used) is rendered. 775 * 776 * @param panel the parent panel into which the attributes were rendered 777 */ 778 private void finishTab(Panel panel) { 779 780 /* 781 * Place an element after all the other attribute elements in the panel. 782 * We need this because the 'column' layout causes attributes to be floated, which 783 * confuses the algorithm used to resize the tab panel. 784 */ 785 FlowPanel formTabTerminator = new FlowPanel(); 786 formTabTerminator.addStyleName(I_CmsLayoutBundle.INSTANCE.form().formTabTerminator()); 787 panel.add(formTabTerminator); 788 } 789 790 /** 791 * Renders a single attribute.<p> 792 * 793 * @param entityType the type of the entity containing the attribute 794 * @param attributeType the attribute type 795 * @param attribute the attribute, or null if not set 796 * @param handler the attribute handler 797 * @param attributeElement the attribute parent element 798 * @param attributeName the attribute name 799 * @param lastCompactView the previous attribute view that was rendered in compact mode if present 800 * 801 * @return the last attribute view that was rendered in compact mode if present 802 */ 803 private CmsAttributeValueView renderAttribute( 804 CmsType entityType, 805 CmsType attributeType, 806 CmsEntityAttribute attribute, 807 CmsAttributeHandler handler, 808 CmsValuePanel attributeElement, 809 String attributeName, 810 CmsAttributeValueView lastCompactView) { 811 812 String label = m_widgetService.getAttributeLabel(attributeName); 813 String help = m_widgetService.getAttributeHelp(attributeName); 814 if (attribute != null) { 815 I_CmsEntityRenderer renderer = m_widgetService.getRendererForAttribute(attributeName, attributeType); 816 for (int i = 0; i < attribute.getValueCount(); i++) { 817 CmsAttributeValueView valueWidget = new CmsAttributeValueView(handler, label, help); 818 if (attributeType.isChoice() && (entityType.getAttributeMaxOccurrence(attributeName) == 1)) { 819 valueWidget.setCollapsed(true); 820 } 821 attributeElement.add(valueWidget); 822 if (attribute.isSimpleValue()) { 823 valueWidget.setValueWidget( 824 m_widgetService.getAttributeFormWidget(attributeName), 825 attribute.getSimpleValues().get(i), 826 m_widgetService.getDefaultAttributeValue(attributeName, handler.getSimplePath(i)), 827 true); 828 // check for compact view setting 829 if (m_widgetService.isDisplayCompact(attributeName)) { 830 // widget should be displayed in compact view, using only 50% of the available width 831 if (lastCompactView == null) { 832 // set mode to first column 833 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_FIRST_COLUMN); 834 lastCompactView = valueWidget; 835 } else { 836 // previous widget is displayed as first column, set second column mode 837 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SECOND_COLUMN); 838 lastCompactView = null; 839 } 840 } else { 841 if (lastCompactView != null) { 842 // previous widget was set to first column mode, 843 // revert that as the current widget will be displayed in a new line 844 lastCompactView.setCompactMode(CmsAttributeValueView.COMPACT_MODE_WIDE); 845 lastCompactView = null; 846 } 847 if (m_widgetService.isDisplaySingleLine(attributeName)) { 848 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SINGLE_LINE); 849 } 850 } 851 } else { 852 valueWidget.setValueEntity(renderer, attribute.getComplexValues().get(i)); 853 if (lastCompactView != null) { 854 // previous widget was set to first column mode, 855 // revert that as the current widget will be displayed in a new line 856 lastCompactView.setCompactMode(CmsAttributeValueView.COMPACT_MODE_WIDE); 857 lastCompactView = null; 858 } 859 if (m_widgetService.isDisplayCompact(attributeName)) { 860 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_NESTED); 861 } 862 } 863 setAttributeChoice(valueWidget, attributeType); 864 } 865 } else { 866 CmsAttributeValueView valueWidget = new CmsAttributeValueView(handler, label, help); 867 attributeElement.add(valueWidget); 868 if (attributeType.isSimpleType()) { 869 // create a deactivated widget, to add the attribute on click 870 valueWidget.setValueWidget( 871 m_widgetService.getAttributeFormWidget(attributeName), 872 "", 873 m_widgetService.getDefaultAttributeValue(attributeName, handler.getSimplePath(0)), 874 false); 875 // check for compact view setting 876 if (m_widgetService.isDisplayCompact(attributeName)) { 877 // widget should be displayed in compact view, using only 50% of the available width 878 if (lastCompactView == null) { 879 // set mode to first column 880 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_FIRST_COLUMN); 881 lastCompactView = valueWidget; 882 } else { 883 // previous widget is displayed as first column, set second column mode 884 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SECOND_COLUMN); 885 lastCompactView = null; 886 } 887 } else { 888 if (lastCompactView != null) { 889 // previous widget was set to first column mode, 890 // revert that as the current widget will be displayed in a new line 891 lastCompactView.setCompactMode(CmsAttributeValueView.COMPACT_MODE_WIDE); 892 lastCompactView = null; 893 } 894 if (m_widgetService.isDisplaySingleLine(attributeName)) { 895 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_SINGLE_LINE); 896 } 897 } 898 } else { 899 if (lastCompactView != null) { 900 // previous widget was set to first column mode, 901 // revert that as the current widget will be displayed in a new line 902 lastCompactView.setCompactMode(CmsAttributeValueView.COMPACT_MODE_WIDE); 903 lastCompactView = null; 904 } 905 if (m_widgetService.isDisplayCompact(attributeName)) { 906 valueWidget.setCompactMode(CmsAttributeValueView.COMPACT_MODE_NESTED); 907 } 908 } 909 setAttributeChoice(valueWidget, attributeType); 910 } 911 handler.updateButtonVisisbility(); 912 return lastCompactView; 913 } 914 915 /** 916 * Renders the tab description in a given panel.<p> 917 * @param tabInfo the tab info object 918 * 919 * @param descriptionParent the panel in which to render the tab description 920 */ 921 private void renderDescription(CmsTabInfo tabInfo, Panel descriptionParent) { 922 923 if (tabInfo.getDescription() != null) { 924 HTML descriptionLabel = new HTML(); 925 descriptionLabel.addStyleName(I_CmsLayoutBundle.INSTANCE.form().tabDescription()); 926 if (!tabInfo.getDescription().startsWith("<div")) { 927 // add default styling in case of simple HTML 928 descriptionLabel.addStyleName(I_CmsLayoutBundle.INSTANCE.form().tabDescriptionPanel()); 929 } 930 descriptionLabel.setHTML(tabInfo.getDescription()); 931 descriptionParent.add(descriptionLabel); 932 } 933 } 934 935 /** 936 * Sets the attribute choices if present.<p> 937 * 938 * @param valueWidget the value widget 939 * @param attributeType the attribute type 940 */ 941 private void setAttributeChoice(CmsAttributeValueView valueWidget, CmsType attributeType) { 942 943 setAttributeChoice(m_widgetService, valueWidget, attributeType); 944 } 945}