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.containerpage.client; 029 030import org.opencms.ade.containerpage.client.CmsContainerpageEvent.EventType; 031import org.opencms.ade.containerpage.client.ui.CmsConfirmRemoveDialog; 032import org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer; 033import org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel; 034import org.opencms.ade.containerpage.client.ui.CmsGroupContainerElementPanel; 035import org.opencms.ade.containerpage.client.ui.CmsRemovedElementDeletionDialog; 036import org.opencms.ade.containerpage.client.ui.CmsSmallElementsHandler; 037import org.opencms.ade.containerpage.client.ui.I_CmsDropContainer; 038import org.opencms.ade.containerpage.client.ui.css.I_CmsLayoutBundle; 039import org.opencms.ade.containerpage.client.ui.groupeditor.A_CmsGroupEditor; 040import org.opencms.ade.containerpage.client.ui.groupeditor.CmsGroupContainerEditor; 041import org.opencms.ade.containerpage.client.ui.groupeditor.CmsInheritanceContainerEditor; 042import org.opencms.ade.containerpage.shared.CmsCntPageData; 043import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementDeleteMode; 044import org.opencms.ade.containerpage.shared.CmsContainer; 045import org.opencms.ade.containerpage.shared.CmsContainerElement; 046import org.opencms.ade.containerpage.shared.CmsContainerElementData; 047import org.opencms.ade.containerpage.shared.CmsContainerPageGalleryData; 048import org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext; 049import org.opencms.ade.containerpage.shared.CmsCreateElementData; 050import org.opencms.ade.containerpage.shared.CmsDialogOptionsAndInfo; 051import org.opencms.ade.containerpage.shared.CmsElementSettingsConfig; 052import org.opencms.ade.containerpage.shared.CmsElementViewInfo; 053import org.opencms.ade.containerpage.shared.CmsGroupContainer; 054import org.opencms.ade.containerpage.shared.CmsGroupContainerSaveResult; 055import org.opencms.ade.containerpage.shared.CmsInheritanceContainer; 056import org.opencms.ade.containerpage.shared.CmsRemovedElementStatus; 057import org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService; 058import org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageServiceAsync; 059import org.opencms.ade.contenteditor.client.CmsContentEditor; 060import org.opencms.gwt.client.CmsCoreProvider; 061import org.opencms.gwt.client.I_CmsElementToolbarContext; 062import org.opencms.gwt.client.dnd.CmsCompositeDNDController; 063import org.opencms.gwt.client.dnd.CmsDNDHandler; 064import org.opencms.gwt.client.dnd.I_CmsDNDController; 065import org.opencms.gwt.client.rpc.CmsRpcAction; 066import org.opencms.gwt.client.rpc.CmsRpcPrefetcher; 067import org.opencms.gwt.client.ui.CmsErrorDialog; 068import org.opencms.gwt.client.ui.CmsNotification; 069import org.opencms.gwt.client.ui.CmsNotification.Type; 070import org.opencms.gwt.client.util.CmsDebugLog; 071import org.opencms.gwt.client.util.CmsDomUtil; 072import org.opencms.gwt.client.util.I_CmsSimpleCallback; 073import org.opencms.gwt.shared.CmsContextMenuEntryBean; 074import org.opencms.gwt.shared.CmsCoreData.AdeContext; 075import org.opencms.gwt.shared.CmsGwtConstants; 076import org.opencms.gwt.shared.CmsListInfoBean; 077import org.opencms.gwt.shared.CmsTemplateContextInfo; 078import org.opencms.gwt.shared.I_CmsUnlockData; 079import org.opencms.gwt.shared.I_CmsUnlockDataFactory; 080import org.opencms.gwt.shared.rpc.I_CmsCoreServiceAsync; 081import org.opencms.util.CmsDefaultSet; 082import org.opencms.util.CmsStringUtil; 083import org.opencms.util.CmsUUID; 084 085import java.util.ArrayList; 086import java.util.Collection; 087import java.util.HashMap; 088import java.util.HashSet; 089import java.util.Iterator; 090import java.util.List; 091import java.util.Map; 092import java.util.Map.Entry; 093import java.util.Set; 094 095import com.google.common.base.Optional; 096import com.google.common.collect.Lists; 097import com.google.gwt.core.client.GWT; 098import com.google.gwt.dom.client.AnchorElement; 099import com.google.gwt.dom.client.Element; 100import com.google.gwt.dom.client.EventTarget; 101import com.google.gwt.event.dom.client.KeyCodes; 102import com.google.gwt.event.logical.shared.ResizeEvent; 103import com.google.gwt.event.logical.shared.ResizeHandler; 104import com.google.gwt.event.logical.shared.ValueChangeEvent; 105import com.google.gwt.event.logical.shared.ValueChangeHandler; 106import com.google.gwt.user.client.Command; 107import com.google.gwt.user.client.Event; 108import com.google.gwt.user.client.Event.NativePreviewEvent; 109import com.google.gwt.user.client.Event.NativePreviewHandler; 110import com.google.gwt.user.client.History; 111import com.google.gwt.user.client.Timer; 112import com.google.gwt.user.client.Window; 113import com.google.gwt.user.client.rpc.AsyncCallback; 114import com.google.gwt.user.client.rpc.SerializationException; 115import com.google.gwt.user.client.rpc.ServiceDefTarget; 116import com.google.gwt.user.client.ui.RootPanel; 117import com.google.gwt.user.client.ui.Widget; 118import com.google.web.bindery.autobean.shared.AutoBean; 119import com.google.web.bindery.autobean.shared.AutoBeanCodex; 120 121/** 122 * Data provider for the container-page editor. All data concerning the container-page is requested and maintained by this provider.<p> 123 * 124 * @since 8.0.0 125 */ 126public final class CmsContainerpageController { 127 128 /** 129 * Enum which is used to control how elements are removed from the page.<p> 130 */ 131 public enum ElementRemoveMode { 132 /** Reference checks are performed and the user is asked for confirmation whether they really want to remove the element before the page is saved. */ 133 confirmRemove, 134 135 /** Reference checks are only performed after the page or group has been saved. */ 136 saveAndCheckReferences, 137 138 /** Element is just removed, no checks are performed. */ 139 silent; 140 } 141 142 /** 143 * Visitor interface used to process the current container content on the page.<p> 144 */ 145 public static interface I_PageContentVisitor { 146 147 /** 148 * This method is called before a container is processed.<p> 149 * 150 * If the method returns false, the container will be skipped.<p> 151 * 152 * @param name the container name 153 * @param container the container data object 154 * 155 * @return true if the container should be processed, true if it should be skipped 156 */ 157 boolean beginContainer(String name, CmsContainer container); 158 159 /** 160 * This method is called after all elements of a container have been processed.<p> 161 */ 162 void endContainer(); 163 164 /** 165 * This method is called for each element of a container.<p> 166 * 167 * @param element the container element 168 */ 169 void handleElement(CmsContainerPageElementPanel element); 170 } 171 172 /** 173 * This visitor implementation checks whether there are other elements in the current page 174 * which correspond to the same VFS resource as a given container element. 175 */ 176 public static class ReferenceCheckVisitor implements I_PageContentVisitor { 177 178 /** The element for which we want to check whether there are other references to the same resource. */ 179 private CmsContainerPageElementPanel m_elementPanel; 180 181 /** True if other references have been found. */ 182 private boolean m_hasReferences; 183 184 /** The structure id of the element. */ 185 private String m_structureId; 186 187 /** 188 * Creates a new instance.<p> 189 * 190 * @param elementPanel the element for which we want to check if there are other references 191 */ 192 public ReferenceCheckVisitor(CmsContainerPageElementPanel elementPanel) { 193 194 m_elementPanel = elementPanel; 195 m_structureId = getServerId(elementPanel.getId()); 196 } 197 198 /** 199 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#beginContainer(java.lang.String, org.opencms.ade.containerpage.shared.CmsContainer) 200 */ 201 public boolean beginContainer(String name, CmsContainer container) { 202 203 return !container.isDetailView(); 204 } 205 206 /** 207 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#endContainer() 208 */ 209 public void endContainer() { 210 211 // do nothing 212 } 213 214 /** 215 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#handleElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) 216 */ 217 public void handleElement(CmsContainerPageElementPanel element) { 218 219 if (element != m_elementPanel) { 220 String id = getServerId(element.getId()); 221 if (m_structureId.equals(id)) { 222 m_hasReferences = true; 223 } 224 } 225 } 226 227 /** 228 * Checks if other references have been found.<p> 229 * 230 * @return true if other references have been found 231 */ 232 public boolean hasReferences() { 233 234 return m_hasReferences; 235 } 236 237 } 238 239 /** 240 * Visitor implementation which is used to gather the container contents for saving.<p> 241 */ 242 protected class PageStateVisitor implements I_PageContentVisitor { 243 244 /** The current container name. */ 245 protected String m_containerName; 246 247 /** The contaienr which is currently being processed. */ 248 protected CmsContainer m_currentContainer; 249 250 /** The list of collected containers. */ 251 protected List<CmsContainer> m_resultContainers = new ArrayList<CmsContainer>(); 252 253 /** The list of elements of the currently processed container which have already been processed. */ 254 List<CmsContainerElement> m_currentElements; 255 256 /** 257 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#beginContainer(java.lang.String, org.opencms.ade.containerpage.shared.CmsContainer) 258 */ 259 public boolean beginContainer(String name, CmsContainer container) { 260 261 m_currentContainer = container; 262 m_containerName = name; 263 m_currentElements = new ArrayList<CmsContainerElement>(); 264 return true; 265 } 266 267 /** 268 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#endContainer() 269 */ 270 public void endContainer() { 271 272 CmsContainer container = new CmsContainer( 273 m_containerName, 274 m_currentContainer.getType(), 275 null, 276 m_currentContainer.getWidth(), 277 m_currentContainer.getMaxElements(), 278 m_currentContainer.isDetailViewContainer(), 279 m_currentContainer.isDetailView(), 280 true, 281 m_currentElements, 282 m_currentContainer.getParentContainerName(), 283 m_currentContainer.getParentInstanceId(), 284 m_currentContainer.getSettingPresets()); 285 container.setDetailOnly(m_currentContainer.isDetailOnly()); 286 container.setRootContainer(isRootContainer(m_currentContainer)); 287 m_resultContainers.add(container); 288 } 289 290 /** 291 * Gets the list of collected containers.<p> 292 * 293 * @return the list of containers 294 */ 295 public List<CmsContainer> getContainers() { 296 297 return m_resultContainers; 298 } 299 300 /** 301 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#handleElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) 302 */ 303 public void handleElement(CmsContainerPageElementPanel elementWidget) { 304 305 CmsContainerElement element = new CmsContainerElement(); 306 element.setClientId(elementWidget.getId()); 307 element.setResourceType(elementWidget.getNewType()); 308 element.setCreateNew(elementWidget.isCreateNew()); 309 element.setModelGroupId(elementWidget.getModelGroupId()); 310 element.setSitePath(elementWidget.getSitePath()); 311 element.setNewEditorDisabled(elementWidget.isNewEditorDisabled()); 312 m_currentElements.add(element); 313 } 314 315 } 316 317 /** 318 * Visitor implementation which is used to gather the container contents for saving.<p> 319 */ 320 protected class SaveDataVisitor implements I_PageContentVisitor { 321 322 /** The current container name. */ 323 protected String m_containerName; 324 325 /** The contaienr which is currently being processed. */ 326 protected CmsContainer m_currentContainer; 327 328 /** The list of collected containers. */ 329 protected List<CmsContainer> m_resultContainers = new ArrayList<CmsContainer>(); 330 331 /** The list of elements of the currently processed container which have already been processed. */ 332 List<CmsContainerElement> m_currentElements; 333 334 /** 335 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#beginContainer(java.lang.String, org.opencms.ade.containerpage.shared.CmsContainer) 336 */ 337 public boolean beginContainer(String name, CmsContainer container) { 338 339 if (container.isDetailView() || ((getData().getDetailId() != null) && !container.isDetailOnly())) { 340 m_currentContainer = null; 341 return false; 342 343 } else { 344 m_currentContainer = container; 345 m_containerName = name; 346 m_currentElements = new ArrayList<CmsContainerElement>(); 347 return true; 348 } 349 } 350 351 /** 352 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#endContainer() 353 */ 354 public void endContainer() { 355 356 CmsContainer container = new CmsContainer( 357 m_containerName, 358 m_currentContainer.getType(), 359 null, 360 m_currentContainer.getWidth(), 361 m_currentContainer.getMaxElements(), 362 m_currentContainer.isDetailViewContainer(), 363 m_currentContainer.isDetailView(), 364 true, 365 m_currentElements, 366 m_currentContainer.getParentContainerName(), 367 m_currentContainer.getParentInstanceId(), 368 m_currentContainer.getSettingPresets()); 369 370 container.setRootContainer(isRootContainer(m_currentContainer)); 371 m_resultContainers.add(container); 372 } 373 374 /** 375 * Gets the list of collected containers.<p> 376 * 377 * @return the list of containers 378 */ 379 public List<CmsContainer> getContainers() { 380 381 return m_resultContainers; 382 } 383 384 /** 385 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#handleElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) 386 */ 387 public void handleElement(CmsContainerPageElementPanel elementWidget) { 388 389 CmsContainerElement element = new CmsContainerElement(); 390 element.setClientId(elementWidget.getId()); 391 element.setResourceType(elementWidget.getNewType()); 392 element.setCreateNew(elementWidget.isCreateNew()); 393 element.setModelGroupId(elementWidget.getModelGroupId()); 394 element.setSitePath(elementWidget.getSitePath()); 395 element.setNewEditorDisabled(elementWidget.isNewEditorDisabled()); 396 m_currentElements.add(element); 397 } 398 399 } 400 401 /** 402 * A type which indicates the locking status of the currently edited container page.<p> 403 */ 404 enum LockStatus { 405 /** Locking the resource failed. */ 406 failed, 407 408 /** The resource could be successfully locked. */ 409 locked, 410 411 /** Locking the resource has not been tried. */ 412 unknown 413 } 414 415 /** 416 * A RPC action implementation used to request the data for container-page elements.<p> 417 */ 418 private class MultiElementAction extends CmsRpcAction<Map<String, CmsContainerElementData>> { 419 420 /** Call-back executed on response. */ 421 private I_CmsSimpleCallback<Map<String, CmsContainerElementData>> m_callback; 422 423 /** The requested client id's. */ 424 private Set<String> m_clientIds; 425 426 /** 427 " * Constructor.<p> 428 * 429 * @param clientIds the client id's 430 * @param callback the call-back 431 */ 432 public MultiElementAction( 433 Set<String> clientIds, 434 I_CmsSimpleCallback<Map<String, CmsContainerElementData>> callback) { 435 436 super(); 437 m_clientIds = clientIds; 438 m_callback = callback; 439 } 440 441 /** 442 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 443 */ 444 @Override 445 public void execute() { 446 447 Map<String, CmsContainerElementData> result = new HashMap<String, CmsContainerElementData>(); 448 List<String> neededIds = new ArrayList<String>(); 449 Iterator<String> it = m_clientIds.iterator(); 450 while (it.hasNext()) { 451 String clientId = it.next(); 452 if (m_elements.containsKey(clientId)) { 453 result.put(clientId, m_elements.get(clientId)); 454 } else { 455 neededIds.add(clientId); 456 } 457 } 458 if (neededIds.size() == 0) { 459 m_callback.execute(result); 460 } else { 461 getContainerpageService().getElementsData( 462 getData().getRpcContext(), 463 getData().getDetailId(), 464 getRequestParams(), 465 m_clientIds, 466 getPageState(), 467 false, 468 null, 469 getLocale(), 470 this); 471 } 472 473 } 474 475 /** 476 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 477 */ 478 @Override 479 protected void onResponse(Map<String, CmsContainerElementData> result) { 480 481 if (result != null) { 482 addElements(result); 483 Map<String, CmsContainerElementData> elements = new HashMap<String, CmsContainerElementData>(); 484 Iterator<String> it = m_clientIds.iterator(); 485 while (it.hasNext()) { 486 String clientId = it.next(); 487 elements.put(clientId, m_elements.get(clientId)); 488 } 489 m_callback.execute(elements); 490 } 491 } 492 493 } 494 495 /** 496 * A RPC action implementation used to reload the data for a container-page element.<p> 497 */ 498 private class ReloadElementAction extends CmsRpcAction<Map<String, CmsContainerElementData>> { 499 500 /** The callback to execute after the reload. */ 501 private Runnable m_callback; 502 503 /** The requested client id's. */ 504 private Set<String> m_clientIds; 505 506 /** 507 * Constructor.<p> 508 * 509 * @param clientIds the client id's to reload 510 * @param callback the callback to execute after the reload 511 */ 512 public ReloadElementAction(Set<String> clientIds, Runnable callback) { 513 514 super(); 515 m_clientIds = clientIds; 516 m_callback = callback; 517 } 518 519 /** 520 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 521 */ 522 @Override 523 public void execute() { 524 525 getContainerpageService().getElementsData( 526 getData().getRpcContext(), 527 getData().getDetailId(), 528 getRequestParams(), 529 m_clientIds, 530 getPageState(), 531 false, 532 null, 533 getLocale(), 534 this); 535 } 536 537 /** 538 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 539 */ 540 @Override 541 protected void onResponse(Map<String, CmsContainerElementData> result) { 542 543 if (result == null) { 544 return; 545 } 546 addElements(result); 547 Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> it = getAllDragElements().iterator(); 548 boolean reloadMarkerFound = false; 549 while (it.hasNext()) { 550 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel containerElement = it.next(); 551 if (!m_clientIds.contains(containerElement.getId())) { 552 continue; 553 } 554 try { 555 CmsContainerPageElementPanel replacer = replaceContainerElement( 556 containerElement, 557 result.get(containerElement.getId())); 558 if (replacer.getElement().getInnerHTML().contains(CmsGwtConstants.FORMATTER_RELOAD_MARKER)) { 559 reloadMarkerFound = true; 560 } 561 } catch (Exception e) { 562 CmsDebugLog.getInstance().printLine("trying to replace"); 563 CmsDebugLog.getInstance().printLine(e.getLocalizedMessage()); 564 } 565 566 } 567 if (isGroupcontainerEditing()) { 568 getGroupEditor().updateBackupElements(result); 569 getGroupcontainer().refreshHighlighting(); 570 } else { 571 if (reloadMarkerFound) { 572 CmsContainerpageController.get().reloadPage(); 573 } else { 574 long loadTime = result.values().iterator().next().getLoadTime(); 575 setLoadTime(Long.valueOf(loadTime)); 576 } 577 } 578 m_handler.updateClipboard(result); 579 resetEditButtons(); 580 CmsContainerpageController.get().fireEvent(new CmsContainerpageEvent(EventType.elementEdited)); 581 if (m_callback != null) { 582 m_callback.run(); 583 } 584 } 585 } 586 587 /** 588 * A RPC action implementation used to request the data for a single container-page element.<p> 589 */ 590 private class SingleElementAction extends CmsRpcAction<Map<String, CmsContainerElementData>> { 591 592 /** Always copy createNew elements in case reading data for a clipboard element used as a copy group. */ 593 private boolean m_alwaysCopy; 594 595 /** Call-back executed on response. */ 596 private I_CmsSimpleCallback<CmsContainerElementData> m_callback; 597 /** The requested client id. */ 598 private String m_clientId; 599 600 /** If this action was triggered by drag and drop from a container, this should contain the id of the origin container. */ 601 private String m_dndContainer; 602 603 /** 604 * Constructor.<p> 605 * 606 * @param clientId the client id 607 * @param callback the call-back 608 * @param alwaysCopy <code>true</code> in case reading data for a clipboard element used as a copy group 609 */ 610 public SingleElementAction( 611 String clientId, 612 boolean alwaysCopy, 613 I_CmsSimpleCallback<CmsContainerElementData> callback) { 614 615 super(); 616 m_clientId = clientId; 617 m_callback = callback; 618 m_alwaysCopy = alwaysCopy; 619 } 620 621 /** 622 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 623 */ 624 @Override 625 public void execute() { 626 627 List<String> clientIds = new ArrayList<String>(); 628 clientIds.add(m_clientId); 629 getContainerpageService().getElementsData( 630 getData().getRpcContext(), 631 getData().getDetailId(), 632 getRequestParams(), 633 clientIds, 634 getPageState(), 635 m_alwaysCopy, 636 m_dndContainer, 637 getLocale(), 638 this); 639 } 640 641 /** 642 * Sets the origin container for the drag and drop case.<p> 643 * 644 * @param containerId the origin container name 645 */ 646 public void setDndContainer(String containerId) { 647 648 m_dndContainer = containerId; 649 } 650 651 /** 652 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 653 */ 654 @Override 655 protected void onResponse(Map<String, CmsContainerElementData> result) { 656 657 if (result != null) { 658 addElements(result); 659 long loadTime = result.get(m_clientId).getLoadTime(); 660 setLoadTime(Long.valueOf(loadTime)); 661 m_callback.execute(result.get(m_clientId)); 662 } 663 } 664 } 665 666 /** The client side id/setting-hash seperator. */ 667 public static final String CLIENT_ID_SEPERATOR = "#"; 668 669 /** Parameter name. */ 670 public static final String PARAM_REMOVEMODE = "removemode"; 671 672 /** Instance of the data provider. */ 673 private static CmsContainerpageController INSTANCE; 674 675 /** The container element data. All requested elements will be cached here.*/ 676 protected Map<String, CmsContainerElementData> m_elements; 677 678 /** The new element data by resource type name. */ 679 protected Map<String, CmsContainerElementData> m_newElements; 680 681 /** The gallery data update timer. */ 682 Timer m_galleryUpdateTimer; 683 684 /** The currently editing group-container editor. */ 685 A_CmsGroupEditor m_groupEditor; 686 687 /** The container-page handler. */ 688 CmsContainerpageHandler m_handler; 689 690 /** The drag targets within this page. */ 691 Map<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> m_targetContainers; 692 693 /** The container page drag and drop controller. */ 694 private I_CmsDNDController m_cntDndController; 695 696 /** The container-page RPC service. */ 697 private I_CmsContainerpageServiceAsync m_containerpageService; 698 699 /** The container-page util instance. */ 700 private CmsContainerpageUtil m_containerpageUtil; 701 702 /** The container data. */ 703 private Map<String, CmsContainer> m_containers; 704 705 /** The XML content editor handler. */ 706 private CmsContentEditorHandler m_contentEditorHandler; 707 708 /** The core RPC service instance. */ 709 private I_CmsCoreServiceAsync m_coreSvc; 710 711 /** The current edit container level. */ 712 private int m_currentEditLevel = -1; 713 714 /** The prefetched data. */ 715 private CmsCntPageData m_data; 716 717 /** The DND controller. */ 718 private CmsCompositeDNDController m_dndController; 719 720 /** The drag and drop handler. */ 721 private CmsDNDHandler m_dndHandler; 722 723 /** Edit button position timer. */ 724 private Timer m_editButtonsPositionTimer; 725 726 /** The current element view. */ 727 private CmsElementViewInfo m_elementView; 728 729 /** Flag indicating that a content element is being edited. */ 730 private boolean m_isContentEditing; 731 732 /** The container page load time. */ 733 private long m_loadTime; 734 735 /** The lock error message. */ 736 private String m_lockErrorMessage; 737 738 /** The current lock status for the page. */ 739 private LockStatus m_lockStatus = LockStatus.unknown; 740 741 /** The max container level. */ 742 private int m_maxContainerLevel; 743 744 /** The model group base element id. */ 745 private String m_modelGroupElementId; 746 747 /** The browser location at the time the containerpage controller was initialized. */ 748 private String m_originalUrl; 749 750 /** Flag if the container-page has changed. */ 751 private boolean m_pageChanged; 752 753 /** The publish lock checker. */ 754 private CmsPublishLockChecker m_publishLockChecker = new CmsPublishLockChecker(this); 755 756 /** Timer to handle window resize. */ 757 private Timer m_resizeTimer; 758 759 /** Handler for small elements. */ 760 private CmsSmallElementsHandler m_smallElementsHandler; 761 762 /** 763 * Constructor.<p> 764 */ 765 public CmsContainerpageController() { 766 767 m_originalUrl = Window.Location.getHref(); 768 INSTANCE = this; 769 try { 770 m_data = (CmsCntPageData)CmsRpcPrefetcher.getSerializedObjectFromDictionary( 771 getContainerpageService(), 772 CmsCntPageData.DICT_NAME); 773 m_elementView = m_data.getElementView(); 774 m_modelGroupElementId = m_data.getModelGroupElementId(); 775 m_loadTime = m_data.getLoadTime(); 776 } catch (SerializationException e) { 777 CmsErrorDialog.handleException( 778 new Exception( 779 "Deserialization of page data failed. This may be caused by expired java-script resources, please clear your browser cache and try again.", 780 e)); 781 } 782 m_smallElementsHandler = new CmsSmallElementsHandler(getContainerpageService()); 783 if (m_data != null) { 784 m_smallElementsHandler.setEditSmallElements(m_data.isEditSmallElementsInitially(), false); 785 m_data.setRpcContext( 786 new CmsContainerPageRpcContext( 787 CmsCoreProvider.get().getStructureId(), 788 m_data.getTemplateContextInfo().getCurrentContext())); 789 } 790 791 } 792 793 /** 794 * Returns the data provider instance.<p> 795 * 796 * @return the data provider 797 */ 798 public static CmsContainerpageController get() { 799 800 if (INSTANCE == null) { 801 CmsDebugLog.getInstance().printLine("WARNING: The data provider has not been initialized!"); 802 return null; 803 } 804 return INSTANCE; 805 } 806 807 /** 808 * Returns the current URI.<p> 809 * 810 * @return the current URI 811 */ 812 public static String getCurrentUri() { 813 814 return CmsCoreProvider.get().getUri(); 815 816 } 817 818 /** 819 * Returns the server id for a given client element id.<p> 820 * 821 * @param clientId the client id including an optional element settings hash 822 * 823 * @return the server id 824 */ 825 public static String getServerId(String clientId) { 826 827 String serverId = clientId; 828 if (clientId.contains(CLIENT_ID_SEPERATOR)) { 829 serverId = clientId.substring(0, clientId.lastIndexOf(CLIENT_ID_SEPERATOR)); 830 } 831 return serverId; 832 } 833 834 /** 835 * Checks whether element removal should be confirmed.<p> 836 * 837 * @return true if element removal should be confirmed 838 */ 839 public static boolean isConfirmRemove() { 840 841 Map<String, String> params = CmsCoreProvider.get().getAdeParameters(); 842 String removeMode = params.get(PARAM_REMOVEMODE); 843 return (removeMode == null) || removeMode.equals("confirm"); 844 } 845 846 /** 847 * Adds a handler for container page events.<p> 848 * 849 * @param handler the handler to add 850 */ 851 public void addContainerpageEventHandler(I_CmsContainerpageEventHandler handler) { 852 853 CmsCoreProvider.get().getEventBus().addHandler(CmsContainerpageEvent.TYPE, handler); 854 } 855 856 /** 857 * Adds an element specified by it's id to the favorite list.<p> 858 * 859 * @param clientId the element id 860 */ 861 public void addToFavoriteList(final String clientId) { 862 863 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 864 865 /** 866 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 867 */ 868 @Override 869 public void execute() { 870 871 getContainerpageService().addToFavoriteList(getData().getRpcContext(), clientId, this); 872 } 873 874 /** 875 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 876 */ 877 @Override 878 protected void onResponse(Void result) { 879 880 CmsNotification.get().send( 881 Type.NORMAL, 882 Messages.get().key(Messages.GUI_NOTIFICATION_ADD_TO_FAVORITES_0)); 883 } 884 }; 885 action.execute(); 886 } 887 888 /** 889 * Adds an element specified by it's id to the recent list.<p> 890 * 891 * @param clientId the element id 892 * @param nextAction the action to execute after the element has been added 893 */ 894 public void addToRecentList(final String clientId, final Runnable nextAction) { 895 896 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 897 898 /** 899 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 900 */ 901 @Override 902 public void execute() { 903 904 getContainerpageService().addToRecentList(getData().getRpcContext(), clientId, this); 905 } 906 907 /** 908 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 909 */ 910 @Override 911 protected void onResponse(Void result) { 912 913 if (nextAction != null) { 914 nextAction.run(); 915 } 916 } 917 }; 918 action.execute(); 919 } 920 921 /** 922 * Checks whether GWT widgets are available for all fields of a content.<p> 923 * 924 * @param structureId the structure id of the content 925 * @param resultCallback the callback for the result 926 */ 927 public void checkNewWidgetsAvailable(final CmsUUID structureId, final AsyncCallback<Boolean> resultCallback) { 928 929 CmsRpcAction<Boolean> action = new CmsRpcAction<Boolean>() { 930 931 @Override 932 public void execute() { 933 934 start(200, false); 935 getContainerpageService().checkNewWidgetsAvailable(structureId, this); 936 } 937 938 @Override 939 protected void onResponse(Boolean result) { 940 941 stop(false); 942 resultCallback.onSuccess(result); 943 } 944 945 // empty 946 }; 947 action.execute(); 948 949 } 950 951 /** 952 * Checks for container elements that are no longer present within the DOM.<p> 953 */ 954 public void cleanUpContainers() { 955 956 List<String> removed = new ArrayList<String>(); 957 for (Entry<String, CmsContainerPageContainer> entry : m_targetContainers.entrySet()) { 958 if (!RootPanel.getBodyElement().isOrHasChild(entry.getValue().getElement())) { 959 removed.add(entry.getKey()); 960 } 961 } 962 for (String containerId : removed) { 963 m_targetContainers.remove(containerId); 964 m_containers.remove(containerId); 965 } 966 if (removed.size() > 0) { 967 scheduleGalleryUpdate(); 968 } 969 } 970 971 /** 972 * Copies an element and asynchronously returns the structure id of the copy.<p> 973 * 974 * @param id the element id 975 * @param callback the callback for the result 976 */ 977 public void copyElement(final String id, final I_CmsSimpleCallback<CmsUUID> callback) { 978 979 CmsRpcAction<CmsUUID> action = new CmsRpcAction<CmsUUID>() { 980 981 @Override 982 public void execute() { 983 984 start(200, false); 985 getContainerpageService().copyElement( 986 CmsCoreProvider.get().getStructureId(), 987 new CmsUUID(id), 988 getData().getLocale(), 989 this); 990 } 991 992 @Override 993 protected void onResponse(CmsUUID result) { 994 995 stop(false); 996 callback.execute(result); 997 } 998 999 }; 1000 action.execute(); 1001 } 1002 1003 /** 1004 * Creates a new resource for crag container elements with the status new and opens the content editor.<p> 1005 * 1006 * @param element the container element 1007 * @param inline <code>true</code> to open the inline editor for the given element if available 1008 */ 1009 public void createAndEditNewElement( 1010 final org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element, 1011 final boolean inline) { 1012 1013 if (!element.isNew()) { 1014 return; 1015 } 1016 1017 final CmsContainer container = m_containers.get(element.getParentTarget().getContainerId()); 1018 1019 m_handler.showPageOverlay(); 1020 CmsRpcAction<CmsCreateElementData> action = new CmsRpcAction<CmsCreateElementData>() { 1021 1022 /** 1023 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 1024 */ 1025 @Override 1026 public void execute() { 1027 1028 getContainerpageService().checkCreateNewElement( 1029 CmsCoreProvider.get().getStructureId(), 1030 element.getId(), 1031 element.getNewType(), 1032 container, 1033 getLocale(), 1034 this); 1035 1036 } 1037 1038 /** 1039 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 1040 */ 1041 @Override 1042 protected void onResponse(CmsCreateElementData result) { 1043 1044 if (result.needsModelSelection()) { 1045 getHandler().openModelResourceSelect(element, result.getModelResources()); 1046 } else { 1047 openEditorForNewElement(element, result.getCreatedElement(), inline); 1048 } 1049 } 1050 }; 1051 action.execute(); 1052 } 1053 1054 /** 1055 * Creates a new resource for drag container elements with the status new and opens the content editor.<p> 1056 * 1057 * @param element the container element 1058 * @param modelResourceStructureId the model resource structure id 1059 */ 1060 public void createAndEditNewElement( 1061 final org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element, 1062 final CmsUUID modelResourceStructureId) { 1063 1064 CmsRpcAction<CmsContainerElement> action = new CmsRpcAction<CmsContainerElement>() { 1065 1066 @Override 1067 public void execute() { 1068 1069 getContainerpageService().createNewElement( 1070 CmsCoreProvider.get().getStructureId(), 1071 element.getId(), 1072 element.getNewType(), 1073 modelResourceStructureId, 1074 getLocale(), 1075 this); 1076 1077 } 1078 1079 @Override 1080 protected void onResponse(CmsContainerElement result) { 1081 1082 openEditorForNewElement(element, result, false); 1083 1084 } 1085 }; 1086 action.execute(); 1087 } 1088 1089 /** 1090 * Creates a new element.<p> 1091 * 1092 * @param element the widget belonging to the element which is currently in memory only 1093 * @param callback the callback to call with the result 1094 */ 1095 public void createNewElement( 1096 final CmsContainerPageElementPanel element, 1097 final AsyncCallback<CmsContainerElement> callback) { 1098 1099 CmsRpcAction<CmsContainerElement> action = new CmsRpcAction<CmsContainerElement>() { 1100 1101 @Override 1102 public void execute() { 1103 1104 getContainerpageService().createNewElement( 1105 CmsCoreProvider.get().getStructureId(), 1106 element.getId(), 1107 element.getNewType(), 1108 null, 1109 getLocale(), 1110 this); 1111 1112 } 1113 1114 @Override 1115 protected void onResponse(CmsContainerElement result) { 1116 1117 callback.onSuccess(result); 1118 } 1119 }; 1120 action.execute(); 1121 } 1122 1123 /** 1124 * Deletes an element from the VFS, removes it from all containers and the client side cache.<p> 1125 * 1126 * @param elementId the element to delete 1127 * @param relatedElementId related element to reload after the element has been deleted 1128 */ 1129 public void deleteElement(String elementId, final String relatedElementId) { 1130 1131 elementId = getServerId(elementId); 1132 removeContainerElements(elementId); 1133 addToRecentList(elementId, null); 1134 reloadElements(new String[] {relatedElementId}, () -> {/*do nothing*/}); 1135 } 1136 1137 /** 1138 * Disables the inline editing for all content elements but the given one.<p> 1139 * 1140 * @param notThisOne the content element not to disable 1141 */ 1142 public void disableInlineEditing(CmsContainerPageElementPanel notThisOne) { 1143 1144 removeEditButtonsPositionTimer(); 1145 if (isGroupcontainerEditing()) { 1146 for (Widget element : m_groupEditor.getGroupContainerWidget()) { 1147 if ((element instanceof CmsContainerPageElementPanel) && (element != notThisOne)) { 1148 ((CmsContainerPageElementPanel)element).removeInlineEditor(); 1149 } 1150 } 1151 } else { 1152 for (org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer container : m_targetContainers.values()) { 1153 for (Widget element : container) { 1154 if ((element instanceof CmsContainerPageElementPanel) && (element != notThisOne)) { 1155 ((CmsContainerPageElementPanel)element).removeInlineEditor(); 1156 } 1157 } 1158 } 1159 } 1160 } 1161 1162 /** 1163 * Enables the favorites editing drag and drop controller.<p> 1164 * 1165 * @param enable if <code>true</code> favorites editing will enabled, otherwise disabled 1166 * @param dndController the favorites editing drag and drop controller 1167 */ 1168 public void enableFavoriteEditing(boolean enable, I_CmsDNDController dndController) { 1169 1170 if (m_dndHandler.isDragging()) { 1171 // never switch drag and drop controllers while dragging 1172 return; 1173 } 1174 if (enable) { 1175 m_dndHandler.setController(dndController); 1176 } else { 1177 m_dndHandler.setController(m_cntDndController); 1178 } 1179 1180 } 1181 1182 /** 1183 * Replaces all element instances of the original element with the new element within the former copy model.<p> 1184 * 1185 * @param originalElementId the original element id 1186 * @param modelGroupParent the model group parent element 1187 * @param elementData the replace element data 1188 */ 1189 public void executeCopyModelReplace( 1190 String originalElementId, 1191 Element modelGroupParent, 1192 CmsContainerElementData elementData) { 1193 1194 String serverId = getServerId(originalElementId); 1195 for (CmsContainerPageContainer cont : m_targetContainers.values()) { 1196 if (modelGroupParent.isOrHasChild(cont.getElement())) { 1197 // look for instances of the original element 1198 for (Widget child : cont) { 1199 if ((child instanceof CmsContainerPageElementPanel) 1200 && ((CmsContainerPageElementPanel)child).getId().startsWith(serverId)) { 1201 CmsContainerPageElementPanel replacer = null; 1202 String elementContent = elementData.getContents().get(cont.getContainerId()); 1203 if ((elementContent != null) && (elementContent.trim().length() > 0)) { 1204 try { 1205 replacer = getContainerpageUtil().createElement(elementData, cont, false); 1206 cont.insert(replacer, cont.getWidgetIndex(child)); 1207 child.removeFromParent(); 1208 initializeSubContainers(replacer); 1209 } catch (Exception e) { 1210 //ignore 1211 } 1212 } 1213 } 1214 } 1215 } 1216 } 1217 } 1218 1219 /** 1220 * Fires an event on the core event bus.<p> 1221 * 1222 * @param event the event to fire 1223 */ 1224 public void fireEvent(CmsContainerpageEvent event) { 1225 1226 CmsCoreProvider.get().getEventBus().fireEvent(event); 1227 1228 } 1229 1230 /** 1231 * Returns all drag elements of the page.<p> 1232 * 1233 * @return the drag elements 1234 */ 1235 public List<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> getAllDragElements() { 1236 1237 List<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> result = new ArrayList<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel>(); 1238 Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> it = m_targetContainers.values().iterator(); 1239 while (it.hasNext()) { 1240 result.addAll(it.next().getAllDragElements()); 1241 } 1242 if (isGroupcontainerEditing()) { 1243 Iterator<Widget> itSub = m_groupEditor.getGroupContainerWidget().iterator(); 1244 while (itSub.hasNext()) { 1245 Widget w = itSub.next(); 1246 if (w instanceof org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) { 1247 result.add((org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel)w); 1248 } 1249 } 1250 } 1251 return result; 1252 } 1253 1254 /** 1255 * Returns the data for the requested element, or <code>null</code> if the element has not been cached yet.<p> 1256 * 1257 * @param clientId the element id 1258 * 1259 * @return the element data 1260 */ 1261 public CmsContainerElementData getCachedElement(String clientId) { 1262 1263 if (m_elements.containsKey(clientId)) { 1264 return m_elements.get(clientId); 1265 } 1266 return null; 1267 } 1268 1269 /** 1270 * Returns the data for the requested element, or <code>null</code> if the element has not been cached yet.<p> 1271 * 1272 * @param resourceTypeName the element resource type 1273 * 1274 * @return the element data 1275 */ 1276 public CmsContainerElementData getCachedNewElement(String resourceTypeName) { 1277 1278 if (m_newElements.containsKey(resourceTypeName)) { 1279 return m_newElements.get(resourceTypeName); 1280 } 1281 return null; 1282 } 1283 1284 /** 1285 * Returns the container data of container with the given name. 1286 * 1287 * @param containerName the container name 1288 * 1289 * @return the container data 1290 */ 1291 public CmsContainer getContainer(String containerName) { 1292 1293 return m_containers.get(containerName); 1294 } 1295 1296 /** 1297 * Gets the container element widget to which the given element belongs, or Optional.absent if none could be found.<p> 1298 * 1299 * @param element the element for which the container element widget should be found 1300 * 1301 * @return the container element widget, or Optional.absent if none can be found 1302 */ 1303 public Optional<CmsContainerPageElementPanel> getContainerElementWidgetForElement(Element element) { 1304 1305 final Element parentContainerElement = CmsDomUtil.getAncestor( 1306 element, 1307 I_CmsLayoutBundle.INSTANCE.dragdropCss().dragElement()); 1308 if (parentContainerElement == null) { 1309 return Optional.absent(); 1310 } 1311 final List<CmsContainerPageElementPanel> result = Lists.newArrayList(); 1312 processPageContent(new I_PageContentVisitor() { 1313 1314 public boolean beginContainer(String name, CmsContainer container) { 1315 1316 // we don't need to look into the container if we have already found our container element 1317 return result.isEmpty(); 1318 } 1319 1320 public void endContainer() { 1321 1322 // do nothing 1323 } 1324 1325 public void handleElement(CmsContainerPageElementPanel current) { 1326 1327 if ((current.getElement() == parentContainerElement) && result.isEmpty()) { 1328 result.add(current); 1329 } 1330 } 1331 }); 1332 if (result.isEmpty()) { 1333 return Optional.absent(); 1334 } else { 1335 return Optional.fromNullable(result.get(0)); 1336 } 1337 } 1338 1339 /** 1340 * Returns the container-page RPC service.<p> 1341 * 1342 * @return the container-page service 1343 */ 1344 public I_CmsContainerpageServiceAsync getContainerpageService() { 1345 1346 if (m_containerpageService == null) { 1347 m_containerpageService = GWT.create(I_CmsContainerpageService.class); 1348 String serviceUrl = CmsCoreProvider.get().link("org.opencms.ade.containerpage.CmsContainerpageService.gwt"); 1349 ((ServiceDefTarget)m_containerpageService).setServiceEntryPoint(serviceUrl); 1350 } 1351 return m_containerpageService; 1352 } 1353 1354 /** 1355 * Returns the {@link org.opencms.ade.containerpage.client.CmsContainerpageUtil}.<p> 1356 * 1357 * @return the containerpage-util 1358 */ 1359 public CmsContainerpageUtil getContainerpageUtil() { 1360 1361 return m_containerpageUtil; 1362 } 1363 1364 /** 1365 * Returns the containers.<p> 1366 * 1367 * @return the containers 1368 */ 1369 public Map<String, CmsContainer> getContainers() { 1370 1371 return m_containers; 1372 } 1373 1374 /** 1375 * Returns the container drag target by name (HTML id attribute).<p> 1376 * 1377 * @param containerName the container name 1378 * @return the drag target 1379 */ 1380 public org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer getContainerTarget(String containerName) { 1381 1382 return m_targetContainers.get(containerName); 1383 } 1384 1385 /** 1386 * Returns a map of the container drag targets.<p> 1387 * 1388 * @return the drag targets 1389 */ 1390 public Map<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> getContainerTargets() { 1391 1392 Map<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> result = new HashMap<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer>(); 1393 for (Entry<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> entry : m_targetContainers.entrySet()) { 1394 if (entry.getValue().isEditable() 1395 && (!isDetailPage() || (entry.getValue().isDetailOnly() || entry.getValue().isDetailView()))) { 1396 result.put(entry.getKey(), entry.getValue()); 1397 } 1398 } 1399 return result; 1400 } 1401 1402 /** 1403 * Returns the type of container with the given name.<p> 1404 * 1405 * @param containerName the container name 1406 * 1407 * @return the container type 1408 */ 1409 public String getContainerType(String containerName) { 1410 1411 return getContainer(containerName).getType(); 1412 } 1413 1414 /** 1415 * Returns the XML content editor handler.<p> 1416 * 1417 * @return the XML content editor handler 1418 */ 1419 public CmsContentEditorHandler getContentEditorHandler() { 1420 1421 return m_contentEditorHandler; 1422 } 1423 1424 /** 1425 * Returns the prefetched data.<p> 1426 * 1427 * @return the prefetched data 1428 */ 1429 public CmsCntPageData getData() { 1430 1431 return m_data; 1432 } 1433 1434 /** 1435 * Returns the delete options for the given content element.<p> 1436 * 1437 * @param clientId the content id 1438 * @param callback the callback to execute 1439 */ 1440 public void getDeleteOptions(final String clientId, final I_CmsSimpleCallback<CmsDialogOptionsAndInfo> callback) { 1441 1442 CmsRpcAction<CmsDialogOptionsAndInfo> action = new CmsRpcAction<CmsDialogOptionsAndInfo>() { 1443 1444 @Override 1445 public void execute() { 1446 1447 getContainerpageService().getDeleteOptions( 1448 clientId, 1449 getData().getRpcContext().getPageStructureId(), 1450 getData().getRequestParams(), 1451 this); 1452 } 1453 1454 @Override 1455 protected void onResponse(CmsDialogOptionsAndInfo result) { 1456 1457 callback.execute(result); 1458 } 1459 }; 1460 action.execute(); 1461 } 1462 1463 /** 1464 * Gets the DND controller.<p> 1465 * 1466 * @return the DND controller 1467 */ 1468 public CmsCompositeDNDController getDndController() { 1469 1470 return m_dndController; 1471 } 1472 1473 /** 1474 * Returns the drag and drop handler.<p> 1475 * 1476 * @return the drag and drop handler 1477 */ 1478 public CmsDNDHandler getDndHandler() { 1479 1480 return m_dndHandler; 1481 } 1482 1483 /** 1484 * Returns the edit options for the given content element.<p> 1485 * 1486 * @param clientId the content id 1487 * @param isListElement in case a list element, not a container element is about to be edited 1488 * @param callback the callback to execute 1489 */ 1490 public void getEditOptions( 1491 final String clientId, 1492 final boolean isListElement, 1493 final I_CmsSimpleCallback<CmsDialogOptionsAndInfo> callback) { 1494 1495 CmsRpcAction<CmsDialogOptionsAndInfo> action = new CmsRpcAction<CmsDialogOptionsAndInfo>() { 1496 1497 @Override 1498 public void execute() { 1499 1500 getContainerpageService().getEditOptions( 1501 clientId, 1502 getData().getRpcContext().getPageStructureId(), 1503 getData().getRequestParams(), 1504 isListElement, 1505 this); 1506 } 1507 1508 @Override 1509 protected void onResponse(CmsDialogOptionsAndInfo result) { 1510 1511 callback.execute(result); 1512 } 1513 }; 1514 action.execute(); 1515 } 1516 1517 /** 1518 * Requests the data for a container element specified by the client id for drag and drop from a container. The data will be provided to the given call-back function.<p> 1519 * 1520 * @param clientId the element id 1521 * @param containerId the id of the container from which the element is being dragged 1522 * @param alwaysCopy <code>true</code> in case reading data for a clipboard element used as a copy group 1523 * @param callback the call-back to execute with the requested data 1524 */ 1525 public void getElementForDragAndDropFromContainer( 1526 final String clientId, 1527 final String containerId, 1528 boolean alwaysCopy, 1529 final I_CmsSimpleCallback<CmsContainerElementData> callback) { 1530 1531 SingleElementAction action = new SingleElementAction(clientId, alwaysCopy, callback); 1532 action.setDndContainer(containerId); 1533 action.execute(); 1534 } 1535 1536 /** 1537 * Requests the data for container elements specified by the client id. The data will be provided to the given call-back function.<p> 1538 * 1539 * @param clientIds the element id's 1540 * @param callback the call-back to execute with the requested data 1541 */ 1542 public void getElements(Set<String> clientIds, I_CmsSimpleCallback<Map<String, CmsContainerElementData>> callback) { 1543 1544 MultiElementAction action = new MultiElementAction(clientIds, callback); 1545 action.execute(); 1546 } 1547 1548 /** 1549 * Requests the element settings config data for a container element specified by the client id. The data will be provided to the given call-back function.<p> 1550 * 1551 * @param clientId the element id 1552 * @param containerId the parent container id 1553 * @param callback the call-back to execute with the requested data 1554 */ 1555 public void getElementSettingsConfig( 1556 final String clientId, 1557 final String containerId, 1558 final I_CmsSimpleCallback<CmsElementSettingsConfig> callback) { 1559 1560 CmsRpcAction<CmsElementSettingsConfig> action = new CmsRpcAction<CmsElementSettingsConfig>() { 1561 1562 /** 1563 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 1564 */ 1565 @Override 1566 public void execute() { 1567 1568 start(100, true); 1569 getContainerpageService().getElementSettingsConfig( 1570 getData().getRpcContext(), 1571 clientId, 1572 containerId, 1573 getPageState(), 1574 getLocale(), 1575 this); 1576 1577 } 1578 1579 /** 1580 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 1581 */ 1582 @Override 1583 protected void onResponse(CmsElementSettingsConfig result) { 1584 1585 if (result != null) { 1586 callback.execute(result); 1587 } 1588 stop(false); 1589 } 1590 }; 1591 action.execute(); 1592 } 1593 1594 /** 1595 * Returns the current element view.<p> 1596 * 1597 * @return the current element view 1598 */ 1599 public CmsElementViewInfo getElementView() { 1600 1601 return m_elementView; 1602 } 1603 1604 /** 1605 * Retrieves a container element with a given set of settings.<p> 1606 * 1607 * @param clientId the id of the container element 1608 * @param settings the set of settings 1609 * 1610 * @param callback the callback which should be executed when the element has been loaded 1611 */ 1612 public void getElementWithSettings( 1613 final String clientId, 1614 final Map<String, String> settings, 1615 final I_CmsSimpleCallback<CmsContainerElementData> callback) { 1616 1617 CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() { 1618 1619 /** 1620 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 1621 */ 1622 @Override 1623 public void execute() { 1624 1625 start(200, false); 1626 getContainerpageService().getElementWithSettings( 1627 getData().getRpcContext(), 1628 getData().getDetailId(), 1629 getRequestParams(), 1630 clientId, 1631 settings, 1632 getPageState(), 1633 getLocale(), 1634 this); 1635 1636 } 1637 1638 /** 1639 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 1640 */ 1641 @Override 1642 protected void onResponse(CmsContainerElementData result) { 1643 1644 stop(false); 1645 if (result != null) { 1646 // cache the loaded element 1647 m_elements.put(result.getClientId(), result); 1648 } 1649 callback.execute(result); 1650 } 1651 1652 }; 1653 action.execute(); 1654 1655 } 1656 1657 /** 1658 * Returns the group-container element being edited.<p> 1659 * 1660 * @return the group-container 1661 */ 1662 public CmsGroupContainerElementPanel getGroupcontainer() { 1663 1664 return m_groupEditor.getGroupContainerWidget(); 1665 } 1666 1667 /** 1668 * Returns the id of the currently edited group-container.<p> 1669 * 1670 * @return the group-container id, or <code>null</code> if no editing is taking place 1671 */ 1672 public String getGroupcontainerId() { 1673 1674 if (m_groupEditor != null) { 1675 return m_groupEditor.getGroupContainerWidget().getContainerId(); 1676 } 1677 return null; 1678 } 1679 1680 /** 1681 * Returns the container-page handler.<p> 1682 * 1683 * @return the container-page handler 1684 */ 1685 public CmsContainerpageHandler getHandler() { 1686 1687 return m_handler; 1688 } 1689 1690 /** 1691 * Returns the time off page load.<p> 1692 * 1693 * @return the time stamp 1694 */ 1695 public long getLoadTime() { 1696 1697 return m_loadTime; 1698 } 1699 1700 /** 1701 * Gets the lock error message.<p> 1702 * 1703 * @return the lock error message 1704 */ 1705 public String getLockErrorMessage() { 1706 1707 return m_lockErrorMessage; 1708 } 1709 1710 /** 1711 * Returns the model group base element id.<p> 1712 * 1713 * @return the model group base element id 1714 */ 1715 public String getModelGroupElementId() { 1716 1717 return m_modelGroupElementId; 1718 } 1719 1720 /** 1721 * Collects all container elements which are model groups.<p> 1722 * 1723 * @return the list of model group container elements 1724 */ 1725 public List<CmsContainerPageElementPanel> getModelGroups() { 1726 1727 final List<CmsContainerPageElementPanel> result = Lists.newArrayList(); 1728 1729 processPageContent(new I_PageContentVisitor() { 1730 1731 public boolean beginContainer(String name, CmsContainer container) { 1732 1733 return true; 1734 } 1735 1736 public void endContainer() { 1737 1738 // do nothing 1739 } 1740 1741 public void handleElement(CmsContainerPageElementPanel element) { 1742 1743 if (element.isModelGroup()) { 1744 result.add(element); 1745 } 1746 } 1747 }); 1748 return result; 1749 } 1750 1751 /** 1752 * Returns the element data for a resource type representing a new element.<p> 1753 * 1754 * @param resourceType the resource type name 1755 * @param callback the callback to execute with the new element data 1756 */ 1757 public void getNewElement(final String resourceType, final I_CmsSimpleCallback<CmsContainerElementData> callback) { 1758 1759 CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() { 1760 1761 @Override 1762 public void execute() { 1763 1764 getContainerpageService().getNewElementData( 1765 getData().getRpcContext(), 1766 getData().getDetailId(), 1767 getRequestParams(), 1768 resourceType, 1769 getPageState(), 1770 getLocale(), 1771 this); 1772 } 1773 1774 @Override 1775 protected void onResponse(CmsContainerElementData result) { 1776 1777 m_elements.put(result.getClientId(), result); 1778 callback.execute(result); 1779 } 1780 }; 1781 action.execute(); 1782 } 1783 1784 /** 1785 * Fetches the options for creating a new element from the edit handler.<p> 1786 * 1787 * @param clientId the client id of the element 1788 * @param callback the callback which is called with the result 1789 */ 1790 public void getNewOptions(final String clientId, final I_CmsSimpleCallback<CmsDialogOptionsAndInfo> callback) { 1791 1792 CmsRpcAction<CmsDialogOptionsAndInfo> action = new CmsRpcAction<CmsDialogOptionsAndInfo>() { 1793 1794 @Override 1795 public void execute() { 1796 1797 getContainerpageService().getNewOptions( 1798 clientId, 1799 getData().getRpcContext().getPageStructureId(), 1800 getData().getRequestParams(), 1801 this); 1802 } 1803 1804 @Override 1805 protected void onResponse(CmsDialogOptionsAndInfo result) { 1806 1807 callback.execute(result); 1808 } 1809 }; 1810 1811 action.execute(); 1812 } 1813 1814 /** 1815 * Produces the "return code", which is needed to return to the current page from the sitemap.<p> 1816 * 1817 * @return the return code 1818 */ 1819 public String getReturnCode() { 1820 1821 CmsUUID ownId = CmsCoreProvider.get().getStructureId(); 1822 CmsUUID detailId = m_data.getDetailId(); 1823 if (detailId != null) { 1824 return "" + ownId + ":" + detailId; 1825 } else { 1826 return "" + ownId; 1827 } 1828 } 1829 1830 /** 1831 * Returns the deserialized element data.<p> 1832 * 1833 * @param data the data to deserialize 1834 * 1835 * @return the container element 1836 * @throws SerializationException if deserialization fails 1837 */ 1838 public CmsContainer getSerializedContainer(String data) throws SerializationException { 1839 1840 return (CmsContainer)CmsRpcPrefetcher.getSerializedObjectFromString(getContainerpageService(), data); 1841 } 1842 1843 /** 1844 * Returns the deserialized element data.<p> 1845 * 1846 * @param data the data to deserialize 1847 * 1848 * @return the container element 1849 * @throws SerializationException if deserialization fails 1850 */ 1851 public CmsContainerElement getSerializedElement(String data) throws SerializationException { 1852 1853 return (CmsContainerElement)CmsRpcPrefetcher.getSerializedObjectFromString(getContainerpageService(), data); 1854 } 1855 1856 /** 1857 * Gets the handler for small elements.<p> 1858 * 1859 * @return the small elements handler 1860 */ 1861 public CmsSmallElementsHandler getSmallElementsHandler() { 1862 1863 return m_smallElementsHandler; 1864 } 1865 1866 /** 1867 * Gets the view with the given id.<p> 1868 * 1869 * @param value the view id as a string 1870 * 1871 * @return the view with the given id, or null if no such view is available 1872 */ 1873 public CmsElementViewInfo getView(String value) { 1874 1875 for (CmsElementViewInfo info : m_data.getElementViews()) { 1876 if (info.getElementViewId().toString().equals(value)) { 1877 return info; 1878 } 1879 } 1880 return null; 1881 } 1882 1883 /** 1884 * Handler that gets called when the template context setting of an element was changed by the user.<p> 1885 * 1886 * @param element the element whose template context setting was changed 1887 * 1888 * @param newValue the new value of the setting 1889 */ 1890 public void handleChangeTemplateContext(final CmsContainerPageElementPanel element, final String newValue) { 1891 1892 if (CmsStringUtil.isEmptyOrWhitespaceOnly(newValue) || CmsTemplateContextInfo.EMPTY_VALUE.equals(newValue)) { 1893 if (CmsInheritanceContainerEditor.getInstance() != null) { 1894 CmsInheritanceContainerEditor.getInstance().removeElement(element); 1895 } else { 1896 removeElement(element, ElementRemoveMode.silent); 1897 } 1898 } 1899 } 1900 1901 /** 1902 * Asks the user for confirmation before removing a container page element.<p> 1903 * 1904 * @param element the element for which the user should confirm the removal 1905 */ 1906 public void handleConfirmRemove(final CmsContainerPageElementPanel element) { 1907 1908 if (element.isNew()) { 1909 element.removeFromParent(); 1910 cleanUpContainers(); 1911 setPageChanged(); 1912 return; 1913 } 1914 checkElementReferences(element, new AsyncCallback<CmsRemovedElementStatus>() { 1915 1916 public void onFailure(Throwable caught) { 1917 1918 // ignore, will never be executed 1919 1920 } 1921 1922 public void onSuccess(CmsRemovedElementStatus status) { 1923 1924 boolean showDeleteCheckbox = status.isDeletionCandidate(); 1925 ElementDeleteMode deleteMode = status.getElementDeleteMode(); 1926 if (deleteMode == null) { 1927 deleteMode = getData().getDeleteMode(); 1928 } 1929 CmsConfirmRemoveDialog removeDialog = new CmsConfirmRemoveDialog( 1930 status.getElementInfo(), 1931 showDeleteCheckbox, 1932 deleteMode, 1933 new AsyncCallback<Boolean>() { 1934 1935 public void onFailure(Throwable caught) { 1936 1937 element.removeHighlighting(); 1938 } 1939 1940 public void onSuccess(Boolean shouldDeleteResource) { 1941 1942 Runnable[] nextActions = new Runnable[] {}; 1943 1944 if (shouldDeleteResource.booleanValue()) { 1945 final CmsRpcAction<Void> deleteAction = new CmsRpcAction<Void>() { 1946 1947 @Override 1948 public void execute() { 1949 1950 start(200, true); 1951 1952 CmsUUID id = new CmsUUID(getServerId(element.getId())); 1953 CmsCoreProvider.getVfsService().deleteResource(id, this); 1954 } 1955 1956 @Override 1957 public void onResponse(Void result) { 1958 1959 stop(true); 1960 } 1961 }; 1962 nextActions = new Runnable[] {new Runnable() { 1963 1964 public void run() { 1965 1966 deleteAction.execute(); 1967 } 1968 }}; 1969 } 1970 I_CmsDropContainer container = element.getParentTarget(); 1971 element.removeFromParent(); 1972 if (container instanceof CmsContainerPageContainer) { 1973 ((CmsContainerPageContainer)container).checkEmptyContainers(); 1974 } 1975 cleanUpContainers(); 1976 setPageChanged(nextActions); 1977 } 1978 }); 1979 removeDialog.center(); 1980 } 1981 1982 }); 1983 } 1984 1985 /** 1986 * Calls the edit handler to handle the delete action.<p> 1987 * 1988 * @param clientId the content client id 1989 * @param deleteOption the selected delete option 1990 * @param callback the callback to execute after the delete 1991 */ 1992 public void handleDelete( 1993 final String clientId, 1994 final String deleteOption, 1995 final I_CmsSimpleCallback<Void> callback) { 1996 1997 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 1998 1999 @Override 2000 public void execute() { 2001 2002 getContainerpageService().handleDelete( 2003 clientId, 2004 deleteOption, 2005 getData().getRpcContext().getPageStructureId(), 2006 getData().getRequestParams(), 2007 this); 2008 } 2009 2010 @Override 2011 protected void onResponse(Void result) { 2012 2013 if (callback != null) { 2014 callback.execute(result); 2015 } 2016 } 2017 }; 2018 action.execute(); 2019 } 2020 2021 /** 2022 * Returns if the selection button is active.<p> 2023 * 2024 * @return <code>true</code> if the selection button is active 2025 */ 2026 public boolean hasActiveSelection() { 2027 2028 return m_handler.hasActiveSelection(); 2029 } 2030 2031 /** 2032 * Returns if the page has changed.<p> 2033 * 2034 * @return <code>true</code> if the page has changed 2035 */ 2036 public boolean hasPageChanged() { 2037 2038 return m_pageChanged; 2039 } 2040 2041 /** 2042 * Hides list collector direct edit buttons, if present.<p> 2043 */ 2044 public void hideEditableListButtons() { 2045 2046 removeEditButtonsPositionTimer(); 2047 for (org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer container : m_targetContainers.values()) { 2048 container.hideEditableListButtons(); 2049 } 2050 } 2051 2052 /** 2053 * Initializes the controller.<p> 2054 * 2055 * @param handler the container-page handler 2056 * @param dndHandler the drag and drop handler 2057 * @param contentEditorHandler the XML content editor handler 2058 * @param containerpageUtil the container-page utility 2059 */ 2060 public void init( 2061 CmsContainerpageHandler handler, 2062 CmsDNDHandler dndHandler, 2063 CmsContentEditorHandler contentEditorHandler, 2064 CmsContainerpageUtil containerpageUtil) { 2065 2066 Window.addResizeHandler(new ResizeHandler() { 2067 2068 public void onResize(ResizeEvent event) { 2069 2070 CmsContainerpageController.this.onResize(); 2071 } 2072 }); 2073 m_containerpageUtil = containerpageUtil; 2074 m_handler = handler; 2075 m_contentEditorHandler = contentEditorHandler; 2076 m_dndHandler = dndHandler; 2077 m_cntDndController = m_dndHandler.getController(); 2078 2079 m_elements = new HashMap<String, CmsContainerElementData>(); 2080 m_newElements = new HashMap<String, CmsContainerElementData>(); 2081 m_containers = new HashMap<String, CmsContainer>(); 2082 if (m_data == null) { 2083 m_handler.m_editor.disableEditing(Messages.get().key(Messages.ERR_READING_CONTAINER_PAGE_DATA_0)); 2084 CmsErrorDialog dialog = new CmsErrorDialog( 2085 Messages.get().key(Messages.ERR_READING_CONTAINER_PAGE_DATA_0), 2086 null); 2087 dialog.center(); 2088 return; 2089 } 2090 // ensure any embedded flash players are set opaque so UI elements may be placed above them 2091 CmsDomUtil.fixFlashZindex(RootPanel.getBodyElement()); 2092 m_targetContainers = m_containerpageUtil.consumeContainers(m_containers, RootPanel.getBodyElement()); 2093 updateContainerLevelInfo(); 2094 resetEditButtons(); 2095 Event.addNativePreviewHandler(new NativePreviewHandler() { 2096 2097 public void onPreviewNativeEvent(NativePreviewEvent event) { 2098 2099 previewNativeEvent(event); 2100 } 2101 }); 2102 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_data.getNoEditReason())) { 2103 m_handler.m_editor.disableEditing(m_data.getNoEditReason()); 2104 } else { 2105 checkLockInfo(); 2106 } 2107 2108 // initialize the browser history handler 2109 History.addValueChangeHandler(new ValueChangeHandler<String>() { 2110 2111 public void onValueChange(ValueChangeEvent<String> event) { 2112 2113 String historyToken = event.getValue(); 2114 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(historyToken)) { 2115 getContentEditorHandler().openEditorForHistory(historyToken); 2116 } else { 2117 getContentEditorHandler().closeContentEditor(); 2118 } 2119 } 2120 }); 2121 AsyncCallback<Void> doNothing = new AsyncCallback<Void>() { 2122 2123 public void onFailure(Throwable caught) { 2124 2125 // nothing to do 2126 } 2127 2128 public void onSuccess(Void result) { 2129 2130 // nothing to do 2131 } 2132 }; 2133 getContainerpageService().setLastPage(CmsCoreProvider.get().getStructureId(), m_data.getDetailId(), doNothing); 2134 2135 // check if there is already a history item available 2136 String historyToken = History.getToken(); 2137 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(historyToken)) { 2138 m_contentEditorHandler.openEditorForHistory(historyToken); 2139 } 2140 2141 updateGalleryData(false, null); 2142 addContainerpageEventHandler(event -> { 2143 updateDetailPreviewStyles(); 2144 }); 2145 updateDetailPreviewStyles(); 2146 updateButtonsForCurrentView(); 2147 startPublishLockCheck(); 2148 } 2149 2150 /** 2151 * Checks for element sub containers.<p> 2152 * 2153 * @param containerElement the container element 2154 */ 2155 public void initializeSubContainers(CmsContainerPageElementPanel containerElement) { 2156 2157 int containerCount = m_targetContainers.size(); 2158 m_targetContainers.putAll(m_containerpageUtil.consumeContainers(m_containers, containerElement.getElement())); 2159 updateContainerLevelInfo(); 2160 if (m_targetContainers.size() > containerCount) { 2161 // in case new containers have been added, the gallery data needs to be updated 2162 scheduleGalleryUpdate(); 2163 } 2164 } 2165 2166 /** 2167 * Returns if the given container is editable.<p> 2168 * 2169 * @param dragParent the parent container 2170 * 2171 * @return <code>true</code> if the given container is editable 2172 */ 2173 public boolean isContainerEditable(I_CmsDropContainer dragParent) { 2174 2175 boolean isSubElement = dragParent instanceof CmsGroupContainerElementPanel; 2176 boolean isContainerEditable = dragParent.isEditable() 2177 && (isSubElement || !isDetailPage() || dragParent.isDetailView() || dragParent.isDetailOnly()); 2178 return isContainerEditable; 2179 } 2180 2181 /** 2182 * Returns the flag indicating that a content element is being edited.<p> 2183 * 2184 * @return the flag indicating that a content element is being edited 2185 */ 2186 public boolean isContentEditing() { 2187 2188 return m_isContentEditing; 2189 } 2190 2191 /** 2192 * Returns if this page displays a detail view.<p> 2193 * 2194 * @return <code>true</code> if this page displays a detail view 2195 */ 2196 public boolean isDetailPage() { 2197 2198 return m_data.getDetailId() != null; 2199 } 2200 2201 /** 2202 * Checks if the page editing features should be disabled.<p> 2203 * 2204 * @return true if the page editing features should be disabled 2205 */ 2206 public boolean isEditingDisabled() { 2207 2208 return (m_data == null) 2209 || CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_data.getNoEditReason()) 2210 || (m_lockStatus == LockStatus.failed); 2211 } 2212 2213 /** 2214 * Returns if a group-container is currently being edited.<p> 2215 * 2216 * @return <code>true</code> if a group-container is being edited 2217 */ 2218 public boolean isGroupcontainerEditing() { 2219 2220 return m_groupEditor != null; 2221 } 2222 2223 /** 2224 * Checks whether the given element should be inline editable.<p> 2225 * 2226 * @param element the element 2227 * @param dragParent the element parent 2228 * 2229 * @return <code>true</code> if the element should be inline editable 2230 */ 2231 public boolean isInlineEditable(CmsContainerPageElementPanel element, I_CmsDropContainer dragParent) { 2232 2233 CmsUUID elemView = element.getElementView(); 2234 return !getData().isUseClassicEditor() 2235 && CmsStringUtil.isEmptyOrWhitespaceOnly(element.getNoEditReason()) 2236 && hasActiveSelection() 2237 && matchRootView(elemView) 2238 && isContainerEditable(dragParent) 2239 && matchesCurrentEditLevel(dragParent) 2240 && (getData().isModelGroup() || !element.hasModelGroupParent()) 2241 && (!(dragParent instanceof CmsGroupContainerElementPanel) || isGroupcontainerEditing()); 2242 } 2243 2244 /** 2245 * Method to leave the page without saving.<p> 2246 * 2247 * @param targetUri the new URI to call 2248 */ 2249 public void leaveUnsaved(String targetUri) { 2250 2251 setPageChanged(false, true); 2252 Window.Location.assign(targetUri); 2253 } 2254 2255 /** 2256 * Loads the context menu entries.<p> 2257 * 2258 * @param structureId the structure id of the resource to get the context menu entries for 2259 * @param context the ade context (sitemap or containerpae) 2260 */ 2261 public void loadContextMenu(final CmsUUID structureId, final AdeContext context) { 2262 2263 /** The RPC menu action for the container page dialog. */ 2264 CmsRpcAction<List<CmsContextMenuEntryBean>> menuAction = new CmsRpcAction<List<CmsContextMenuEntryBean>>() { 2265 2266 /** 2267 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 2268 */ 2269 @Override 2270 public void execute() { 2271 2272 getCoreService().getContextMenuEntries(structureId, context, this); 2273 } 2274 2275 /** 2276 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 2277 */ 2278 @Override 2279 public void onResponse(List<CmsContextMenuEntryBean> menuBeans) { 2280 2281 m_handler.insertContextMenu(menuBeans, structureId); 2282 } 2283 }; 2284 menuAction.execute(); 2285 2286 } 2287 2288 /** 2289 * Loads the favorite list and adds the elements to the favorite list widget of the tool-bar menu.<p> 2290 * 2291 * @param callback the call-back to execute with the result data 2292 */ 2293 public void loadFavorites(final I_CmsSimpleCallback<List<CmsContainerElementData>> callback) { 2294 2295 CmsRpcAction<List<CmsContainerElementData>> action = new CmsRpcAction<List<CmsContainerElementData>>() { 2296 2297 /** 2298 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 2299 */ 2300 @Override 2301 public void execute() { 2302 2303 start(200, true); 2304 getContainerpageService().getFavoriteList( 2305 CmsCoreProvider.get().getStructureId(), 2306 getData().getDetailId(), 2307 getPageState(), 2308 getLocale(), 2309 this); 2310 } 2311 2312 /** 2313 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 2314 */ 2315 @Override 2316 protected void onResponse(List<CmsContainerElementData> result) { 2317 2318 stop(false); 2319 addElements(result); 2320 callback.execute(result); 2321 } 2322 }; 2323 action.execute(); 2324 } 2325 2326 /** 2327 * Loads the recent list and adds the elements to the recent list widget of the tool-bar menu.<p> 2328 * 2329 * @param callback the call-back to execute with the result data 2330 */ 2331 public void loadRecent(final I_CmsSimpleCallback<List<CmsContainerElementData>> callback) { 2332 2333 CmsRpcAction<List<CmsContainerElementData>> action = new CmsRpcAction<List<CmsContainerElementData>>() { 2334 2335 /** 2336 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 2337 */ 2338 @Override 2339 public void execute() { 2340 2341 start(200, true); 2342 getContainerpageService().getRecentList( 2343 CmsCoreProvider.get().getStructureId(), 2344 getData().getDetailId(), 2345 getPageState(), 2346 getLocale(), 2347 this); 2348 } 2349 2350 /** 2351 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 2352 */ 2353 @Override 2354 protected void onResponse(List<CmsContainerElementData> result) { 2355 2356 stop(false); 2357 addElements(result); 2358 callback.execute(result); 2359 } 2360 }; 2361 action.execute(); 2362 } 2363 2364 /** 2365 * Locks the container-page.<p> 2366 * 2367 * @param callback the callback to execute 2368 */ 2369 public void lockContainerpage(final I_CmsSimpleCallback<Boolean> callback) { 2370 2371 if (m_lockStatus == LockStatus.locked) { 2372 callback.execute(Boolean.TRUE); 2373 } else if (m_lockStatus == LockStatus.failed) { 2374 callback.execute(Boolean.FALSE); 2375 } else { 2376 I_CmsSimpleCallback<String> call = new I_CmsSimpleCallback<String>() { 2377 2378 public void execute(String lockError) { 2379 2380 if (lockError == null) { 2381 onLockSuccess(); 2382 callback.execute(Boolean.TRUE); 2383 } else { 2384 onLockFail(lockError); 2385 callback.execute(Boolean.FALSE); 2386 } 2387 } 2388 }; 2389 2390 if (getData().getDetailContainerPage() != null) { 2391 CmsCoreProvider.get().lockOrReturnError(getData().getDetailContainerPage(), getLoadTime(), call); 2392 } else { 2393 CmsCoreProvider.get().lockOrReturnError(CmsCoreProvider.get().getStructureId(), getLoadTime(), call); 2394 } 2395 } 2396 } 2397 2398 /** 2399 * Returns true if the view with the given view id and the current view have the same root view.<p> 2400 * 2401 * @param viewIdFromElement the id of a view 2402 * @return true if the root view of the id matches the root view of the current view 2403 */ 2404 public boolean matchRootView(CmsUUID viewIdFromElement) { 2405 2406 if (viewIdFromElement == null) { 2407 viewIdFromElement = CmsUUID.getNullUUID(); 2408 } 2409 CmsElementViewInfo viewFromElement = getView(viewIdFromElement.toString()); 2410 return (viewFromElement != null) && viewFromElement.getRootViewId().equals(m_elementView.getRootViewId()); 2411 } 2412 2413 /** 2414 * This method should be called when locking the page has failed.<p> 2415 * 2416 * @param lockError the locking information 2417 */ 2418 public void onLockFail(String lockError) { 2419 2420 m_lockStatus = LockStatus.failed; 2421 m_handler.onLockFail(lockError); 2422 } 2423 2424 /** 2425 * This method should be called when locking the page has succeeded.<p> 2426 * 2427 */ 2428 public void onLockSuccess() { 2429 2430 assert m_lockStatus == LockStatus.unknown; 2431 m_lockStatus = LockStatus.locked; 2432 } 2433 2434 /** 2435 * Handler which is executed when the window closes.<p> 2436 */ 2437 public void onWindowClose() { 2438 2439 // causes synchronous RPC call 2440 unlockContainerpage(); 2441 } 2442 2443 /** 2444 * Calls the edit handler to prepare the given content element for editing.<p> 2445 * 2446 * @param clientId the element id 2447 * @param editOption the selected edit option 2448 * @param callback the callback to execute 2449 */ 2450 public void prepareForEdit( 2451 final String clientId, 2452 final String editOption, 2453 final I_CmsSimpleCallback<CmsUUID> callback) { 2454 2455 CmsRpcAction<CmsUUID> action = new CmsRpcAction<CmsUUID>() { 2456 2457 @Override 2458 public void execute() { 2459 2460 getContainerpageService().prepareForEdit( 2461 clientId, 2462 editOption, 2463 getData().getRpcContext().getPageStructureId(), 2464 getData().getRequestParams(), 2465 this); 2466 } 2467 2468 @Override 2469 protected void onResponse(CmsUUID result) { 2470 2471 callback.execute(result); 2472 } 2473 }; 2474 action.execute(); 2475 } 2476 2477 /** 2478 * Reinitializes the buttons in the container element menus.<p> 2479 */ 2480 public void reinitializeButtons() { 2481 2482 if (isGroupcontainerEditing()) { 2483 m_groupEditor.reinitializeButtons(); 2484 } else { 2485 List<CmsContainerPageElementPanel> elemWidgets = getAllContainerPageElements(true); 2486 2487 for (CmsContainerPageElementPanel elemWidget : elemWidgets) { 2488 if (requiresOptionBar(elemWidget, elemWidget.getParentTarget())) { 2489 getContainerpageUtil().addOptionBar(elemWidget); 2490 } else { 2491 // otherwise remove any present option bar 2492 elemWidget.setElementOptionBar(null); 2493 } 2494 elemWidget.showEditableListButtons(); 2495 } 2496 } 2497 } 2498 2499 /** 2500 * Re-initializes the inline editing.<p> 2501 */ 2502 public void reInitInlineEditing() { 2503 2504 removeEditButtonsPositionTimer(); 2505 if ((m_targetContainers == null) || getData().isUseClassicEditor()) { 2506 // if the target containers are not initialized yet or classic editor is set, don't do anything 2507 return; 2508 } 2509 if (isGroupcontainerEditing()) { 2510 for (Widget element : m_groupEditor.getGroupContainerWidget()) { 2511 if (((element instanceof CmsContainerPageElementPanel) 2512 && isInlineEditable( 2513 (CmsContainerPageElementPanel)element, 2514 m_groupEditor.getGroupContainerWidget()))) { 2515 ((CmsContainerPageElementPanel)element).initInlineEditor(this); 2516 } 2517 } 2518 } else { 2519 for (CmsContainerPageContainer container : m_targetContainers.values()) { 2520 // first remove inline editors 2521 for (Widget element : container) { 2522 if ((element instanceof CmsContainerPageElementPanel)) { 2523 ((CmsContainerPageElementPanel)element).removeInlineEditor(); 2524 } 2525 } 2526 2527 // add inline editors only on suitable elements 2528 if (isContainerEditable(container) && matchesCurrentEditLevel(container)) { 2529 for (Widget element : container) { 2530 if ((element instanceof CmsContainerPageElementPanel) 2531 && isInlineEditable((CmsContainerPageElementPanel)element, container)) { 2532 ((CmsContainerPageElementPanel)element).initInlineEditor(this); 2533 } 2534 } 2535 } 2536 } 2537 } 2538 } 2539 2540 /** 2541 * Reloads the content for the given elements and related elements. 2542 * 2543 * @param ids the element ids 2544 * @param callback the callback to execute after the reload 2545 */ 2546 public void reloadElements(Collection<String> ids, Runnable callback) { 2547 2548 Set<String> related = new HashSet<String>(); 2549 for (String id : ids) { 2550 related.addAll(getRelatedElementIds(id)); 2551 } 2552 if (!related.isEmpty()) { 2553 ReloadElementAction action = new ReloadElementAction(related, callback); 2554 action.execute(); 2555 } 2556 } 2557 2558 /** 2559 * Reloads the content for the given element and all related elements.<p> 2560 * 2561 * Call this if the element content has changed.<p> 2562 * 2563 * @param ids the element ids 2564 * @param callback the callback to execute after the reload 2565 */ 2566 public void reloadElements(String[] ids, Runnable callback) { 2567 2568 Set<String> related = new HashSet<String>(); 2569 for (int i = 0; i < ids.length; i++) { 2570 related.addAll(getRelatedElementIds(ids[i])); 2571 } 2572 if (!related.isEmpty()) { 2573 ReloadElementAction action = new ReloadElementAction(related, callback); 2574 action.execute(); 2575 } 2576 } 2577 2578 /** 2579 * Reloads a container page element with a new set of settings.<p> 2580 * 2581 * @param elementWidget the widget of the container page element which should be reloaded 2582 * @param clientId the id of the container page element which should be reloaded 2583 * @param settings the new set of settings 2584 * @param afterReloadAction a callback which is executed after the element has been reloaded 2585 */ 2586 public void reloadElementWithSettings( 2587 final org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel elementWidget, 2588 final String clientId, 2589 final Map<String, String> settings, 2590 final I_CmsSimpleCallback<CmsContainerPageElementPanel> afterReloadAction) { 2591 2592 final I_CmsSimpleCallback<CmsContainerElementData> callback = new I_CmsSimpleCallback<CmsContainerElementData>() { 2593 2594 public void execute(CmsContainerElementData newElement) { 2595 2596 try { 2597 final CmsContainerPageElementPanel replacement = replaceContainerElement(elementWidget, newElement); 2598 resetEditButtons(); 2599 addToRecentList(newElement.getClientId(), null); 2600 afterReloadAction.execute(replacement); 2601 } catch (Exception e) { 2602 // should never happen 2603 CmsDebugLog.getInstance().printLine(e.getLocalizedMessage()); 2604 } 2605 } 2606 }; 2607 2608 if (!isGroupcontainerEditing()) { 2609 2610 lockContainerpage(new I_CmsSimpleCallback<Boolean>() { 2611 2612 public void execute(Boolean arg) { 2613 2614 if (arg.booleanValue()) { 2615 CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() { 2616 2617 @Override 2618 public void execute() { 2619 2620 start(500, true); 2621 getContainerpageService().saveElementSettings( 2622 getData().getRpcContext(), 2623 getData().getDetailId(), 2624 getRequestParams(), 2625 clientId, 2626 settings, 2627 getPageState(), 2628 getLocale(), 2629 this); 2630 } 2631 2632 @Override 2633 protected void onResponse(CmsContainerElementData result) { 2634 2635 stop(false); 2636 CmsContainerpageController.get().fireEvent( 2637 new CmsContainerpageEvent(EventType.pageSaved)); 2638 setPageChanged(false, false); 2639 if (result != null) { 2640 // cache the loaded element 2641 m_elements.put(result.getClientId(), result); 2642 setLoadTime(Long.valueOf(result.getLoadTime())); 2643 } 2644 callback.execute(result); 2645 } 2646 }; 2647 action.execute(); 2648 } 2649 } 2650 }); 2651 2652 } else { 2653 getElementWithSettings(clientId, settings, callback); 2654 } 2655 } 2656 2657 /** 2658 * Reloads the page.<p> 2659 */ 2660 public void reloadPage() { 2661 2662 Timer timer = new Timer() { 2663 2664 @Override 2665 @SuppressWarnings("synthetic-access") 2666 public void run() { 2667 2668 Window.Location.reload(); 2669 } 2670 }; 2671 2672 timer.schedule(150); 2673 2674 } 2675 2676 /** 2677 * Removes the given container element from its parent container.<p> 2678 * 2679 * @param dragElement the element to remove 2680 */ 2681 public void removeElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel dragElement) { 2682 2683 ElementRemoveMode removeMode = isConfirmRemove() 2684 ? ElementRemoveMode.confirmRemove 2685 : ElementRemoveMode.saveAndCheckReferences; 2686 removeElement(dragElement, removeMode); 2687 } 2688 2689 /** 2690 * Removes the given container element from its parent container.<p> 2691 * 2692 * @param dragElement the element to remove 2693 * @param removeMode the remove mode 2694 */ 2695 public void removeElement( 2696 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel dragElement, 2697 ElementRemoveMode removeMode) { 2698 2699 if (isGroupcontainerEditing()) { 2700 dragElement.removeFromParent(); 2701 if (!getGroupcontainer().iterator().hasNext()) { 2702 // group-container is empty, mark it 2703 getGroupcontainer().addStyleName(I_CmsLayoutBundle.INSTANCE.containerpageCss().emptyGroupContainer()); 2704 } 2705 getGroupcontainer().refreshHighlighting(); 2706 } else { 2707 final String id = dragElement.getId(); 2708 if (id != null) { 2709 addToRecentList(id, null); 2710 } 2711 2712 I_CmsDropContainer container = dragElement.getParentTarget(); 2713 switch (removeMode) { 2714 case saveAndCheckReferences: 2715 dragElement.removeFromParent(); 2716 if (container instanceof CmsContainerPageContainer) { 2717 ((CmsContainerPageContainer)container).checkEmptyContainers(); 2718 } 2719 cleanUpContainers(); 2720 Runnable checkReferencesAction = new Runnable() { 2721 2722 public void run() { 2723 2724 checkReferencesToRemovedElement(id); 2725 } 2726 }; 2727 setPageChanged(checkReferencesAction); 2728 break; 2729 case confirmRemove: 2730 handleConfirmRemove(dragElement); 2731 break; 2732 case silent: 2733 default: 2734 dragElement.removeFromParent(); 2735 if (container instanceof CmsContainerPageContainer) { 2736 ((CmsContainerPageContainer)container).checkEmptyContainers(); 2737 } 2738 cleanUpContainers(); 2739 setPageChanged(); 2740 break; 2741 } 2742 } 2743 } 2744 2745 /** 2746 * Replaces the given drag-element with the given container element.<p> 2747 * 2748 * @param containerElement the container element to replace 2749 * @param elementData the new element data 2750 * 2751 * @return the container element which replaced the old one 2752 * 2753 * @throws Exception if something goes wrong 2754 */ 2755 public CmsContainerPageElementPanel replaceContainerElement( 2756 CmsContainerPageElementPanel containerElement, 2757 CmsContainerElementData elementData) 2758 throws Exception { 2759 2760 I_CmsDropContainer parentContainer = containerElement.getParentTarget(); 2761 String containerId = parentContainer.getContainerId(); 2762 CmsContainerPageElementPanel replacer = null; 2763 String elementContent = elementData.getContents().get(containerId); 2764 if ((elementContent != null) && (elementContent.trim().length() > 0)) { 2765 replacer = getContainerpageUtil().createElement(elementData, parentContainer, false); 2766 2767 if (containerElement.isNew()) { 2768 // if replacing element data has the same structure id, keep the 'new' state by setting the new type property 2769 // this should only be the case when editing settings of a new element that has not been created in the VFS yet 2770 String id = getServerId(containerElement.getId()); 2771 if (elementData.getClientId().startsWith(id)) { 2772 replacer.setNewType(containerElement.getNewType()); 2773 } 2774 } 2775 replacer.setCreateNew(containerElement.isCreateNew()); 2776 // replacer.setModelGroup(containerElement.isModelGroup()); 2777 if (isGroupcontainerEditing() && (containerElement.getInheritanceInfo() != null)) { 2778 // in case of inheritance container editing, keep the inheritance info 2779 replacer.setInheritanceInfo(containerElement.getInheritanceInfo()); 2780 // set the proper element options 2781 CmsInheritanceContainerEditor.getInstance().setOptionBar(replacer); 2782 } 2783 parentContainer.insert(replacer, parentContainer.getWidgetIndex(containerElement)); 2784 containerElement.removeFromParent(); 2785 initializeSubContainers(replacer); 2786 } 2787 cleanUpContainers(); 2788 return replacer; 2789 } 2790 2791 /** 2792 * Replaces the given element with another content while keeping it's settings.<p> 2793 * 2794 * @param elementWidget the element to replace 2795 * @param elementId the id of the replacing content 2796 * @param callback the callback to execute after the element is replaced 2797 */ 2798 public void replaceElement( 2799 final CmsContainerPageElementPanel elementWidget, 2800 final String elementId, 2801 Runnable callback) { 2802 2803 final CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() { 2804 2805 @Override 2806 public void execute() { 2807 2808 start(500, true); 2809 getContainerpageService().replaceElement( 2810 getData().getRpcContext(), 2811 getData().getDetailId(), 2812 getRequestParams(), 2813 elementWidget.getId(), 2814 elementId, 2815 getPageState(), 2816 getLocale(), 2817 this); 2818 } 2819 2820 @Override 2821 protected void onResponse(CmsContainerElementData result) { 2822 2823 stop(false); 2824 2825 if (result != null) { 2826 // cache the loaded element 2827 m_elements.put(result.getClientId(), result); 2828 try { 2829 replaceContainerElement(elementWidget, result); 2830 resetEditButtons(); 2831 addToRecentList(result.getClientId(), null); 2832 setPageChanged(new Runnable() { 2833 2834 public void run() { 2835 2836 if (callback != null) { 2837 callback.run(); 2838 } 2839 } 2840 }); 2841 } catch (Exception e) { 2842 // should never happen 2843 CmsDebugLog.getInstance().printLine(e.getLocalizedMessage()); 2844 } 2845 } 2846 } 2847 }; 2848 2849 if (!isGroupcontainerEditing()) { 2850 2851 lockContainerpage(new I_CmsSimpleCallback<Boolean>() { 2852 2853 public void execute(Boolean arg) { 2854 2855 if (arg.booleanValue()) { 2856 action.execute(); 2857 } 2858 } 2859 }); 2860 2861 } else { 2862 action.execute(); 2863 } 2864 } 2865 2866 /** 2867 * Checks whether the given element should display the option bar.<p> 2868 * 2869 * @param element the element 2870 * @param dragParent the element parent 2871 * 2872 * @return <code>true</code> if the given element should display the option bar 2873 */ 2874 public boolean requiresOptionBar(CmsContainerPageElementPanel element, I_CmsDropContainer dragParent) { 2875 2876 return element.hasViewPermission() 2877 && (!element.hasModelGroupParent() || getData().isModelGroup()) 2878 && (matchRootView(element.getElementView()) 2879 || isGroupcontainerEditing() 2880 || shouldShowModelgroupOptionBar(element)) 2881 && isContainerEditable(dragParent) 2882 && matchesCurrentEditLevel(dragParent); 2883 } 2884 2885 /** 2886 * Resets all edit buttons an there positions.<p> 2887 */ 2888 public void resetEditButtons() { 2889 2890 removeEditButtonsPositionTimer(); 2891 m_editButtonsPositionTimer = new Timer() { 2892 2893 /** Timer run counter. */ 2894 private int m_timerRuns; 2895 2896 @Override 2897 public void run() { 2898 2899 for (org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer container : m_targetContainers.values()) { 2900 container.showEditableListButtons(); 2901 container.updateOptionBars(); 2902 } 2903 if (m_timerRuns > 3) { 2904 cancel(); 2905 } 2906 m_timerRuns++; 2907 } 2908 }; 2909 m_editButtonsPositionTimer.scheduleRepeating(100); 2910 } 2911 2912 /** 2913 * Resets the container-page.<p> 2914 */ 2915 public void resetPage() { 2916 2917 setPageChanged(false, true); 2918 Window.Location.reload(); 2919 } 2920 2921 /** 2922 * Method to save and leave the page.<p> 2923 * 2924 * @param leaveCommand the command to execute to leave the page 2925 */ 2926 public void saveAndLeave(final Command leaveCommand) { 2927 2928 if (hasPageChanged()) { 2929 CmsRpcAction<Long> action = new CmsRpcAction<Long>() { 2930 2931 /** 2932 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 2933 */ 2934 @Override 2935 public void execute() { 2936 2937 if (getData().getDetailContainerPage() != null) { 2938 getContainerpageService().saveDetailContainers( 2939 getData().getDetailId(), 2940 getData().getDetailContainerPage(), 2941 getPageContent(), 2942 this); 2943 } else { 2944 getContainerpageService().saveContainerpage( 2945 CmsCoreProvider.get().getStructureId(), 2946 getPageContent(), 2947 this); 2948 } 2949 } 2950 2951 /** 2952 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 2953 */ 2954 @Override 2955 protected void onResponse(Long result) { 2956 2957 setLoadTime(result); 2958 CmsNotification.get().send(Type.NORMAL, Messages.get().key(Messages.GUI_NOTIFICATION_PAGE_SAVED_0)); 2959 CmsContainerpageController.get().fireEvent(new CmsContainerpageEvent(EventType.pageSaved)); 2960 setPageChanged(false, true); 2961 leaveCommand.execute(); 2962 } 2963 }; 2964 action.execute(); 2965 } 2966 } 2967 2968 /** 2969 * Method to save and leave the page.<p> 2970 * 2971 * @param targetUri the new URI to call 2972 */ 2973 public void saveAndLeave(final String targetUri) { 2974 2975 if (hasPageChanged()) { 2976 CmsRpcAction<Long> action = new CmsRpcAction<Long>() { 2977 2978 /** 2979 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 2980 */ 2981 @Override 2982 public void execute() { 2983 2984 if (getData().getDetailContainerPage() != null) { 2985 getContainerpageService().saveDetailContainers( 2986 getData().getDetailId(), 2987 getData().getDetailContainerPage(), 2988 getPageContent(), 2989 this); 2990 } else { 2991 getContainerpageService().saveContainerpage( 2992 CmsCoreProvider.get().getStructureId(), 2993 getPageContent(), 2994 this); 2995 } 2996 } 2997 2998 /** 2999 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3000 */ 3001 @Override 3002 protected void onResponse(Long result) { 3003 3004 setLoadTime(result); 3005 CmsNotification.get().send(Type.NORMAL, Messages.get().key(Messages.GUI_NOTIFICATION_PAGE_SAVED_0)); 3006 CmsContainerpageController.get().fireEvent(new CmsContainerpageEvent(EventType.pageSaved)); 3007 setPageChanged(false, true); 3008 Window.Location.assign(targetUri); 3009 } 3010 }; 3011 action.execute(); 3012 } 3013 } 3014 3015 /** 3016 * Saves the clipboard tab index selected by the user.<p> 3017 * 3018 * @param tabIndex the tab index 3019 */ 3020 public void saveClipboardTab(final int tabIndex) { 3021 3022 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 3023 3024 @Override 3025 public void execute() { 3026 3027 start(1, false); 3028 getContainerpageService().saveClipboardTab(tabIndex, this); 3029 } 3030 3031 @Override 3032 protected void onResponse(Void result) { 3033 3034 stop(false); 3035 } 3036 }; 3037 action.execute(); 3038 } 3039 3040 /** 3041 * Saves the current state of the container-page.<p> 3042 * 3043 * @param afterSaveActions the actions to execute after saving 3044 */ 3045 public void saveContainerpage(final Runnable... afterSaveActions) { 3046 3047 if (hasPageChanged()) { 3048 final CmsRpcAction<Long> action = new CmsRpcAction<Long>() { 3049 3050 /** 3051 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3052 */ 3053 @Override 3054 public void execute() { 3055 3056 start(500, true); 3057 if (getData().getDetailContainerPage() != null) { 3058 getContainerpageService().saveDetailContainers( 3059 getData().getDetailId(), 3060 getData().getDetailContainerPage(), 3061 getPageContent(), 3062 this); 3063 } else { 3064 getContainerpageService().saveContainerpage( 3065 CmsCoreProvider.get().getStructureId(), 3066 getPageContent(), 3067 this); 3068 } 3069 } 3070 3071 /** 3072 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3073 */ 3074 @Override 3075 protected void onResponse(Long result) { 3076 3077 setLoadTime(result); 3078 stop(false); 3079 setPageChanged(false, false); 3080 CmsContainerpageController.get().fireEvent(new CmsContainerpageEvent(EventType.pageSaved)); 3081 for (Runnable afterSaveAction : afterSaveActions) { 3082 afterSaveAction.run(); 3083 } 3084 } 3085 }; 3086 if (getData().getDetailContainerPage() != null) { 3087 action.execute(); 3088 } else { 3089 lockContainerpage(new I_CmsSimpleCallback<Boolean>() { 3090 3091 public void execute(Boolean arg) { 3092 3093 if (arg.booleanValue()) { 3094 action.execute(); 3095 } 3096 } 3097 }); 3098 } 3099 } 3100 } 3101 3102 /** 3103 * Saves the favorite list.<p> 3104 * 3105 * @param clientIds the client id's of the list's elements 3106 */ 3107 public void saveFavoriteList(final List<String> clientIds) { 3108 3109 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 3110 3111 /** 3112 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3113 */ 3114 @Override 3115 public void execute() { 3116 3117 getContainerpageService().saveFavoriteList(clientIds, CmsCoreProvider.get().getUri(), this); 3118 } 3119 3120 /** 3121 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3122 */ 3123 @Override 3124 protected void onResponse(Void result) { 3125 3126 CmsNotification.get().send( 3127 Type.NORMAL, 3128 Messages.get().key(Messages.GUI_NOTIFICATION_FAVORITES_SAVED_0)); 3129 } 3130 }; 3131 action.execute(); 3132 } 3133 3134 /** 3135 * Saves the group-container.<p> 3136 * 3137 * @param groupContainer the group-container data to save 3138 * @param groupContainerElement the group-container widget 3139 */ 3140 public void saveGroupcontainer( 3141 final CmsGroupContainer groupContainer, 3142 final CmsGroupContainerElementPanel groupContainerElement) { 3143 3144 if (getGroupcontainer() != null) { 3145 CmsRpcAction<CmsGroupContainerSaveResult> action = new CmsRpcAction<CmsGroupContainerSaveResult>() { 3146 3147 /** 3148 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3149 */ 3150 @Override 3151 public void execute() { 3152 3153 start(0, true); 3154 getContainerpageService().saveGroupContainer( 3155 getData().getRpcContext(), 3156 getData().getDetailId(), 3157 getRequestParams(), 3158 groupContainer, 3159 getPageState(), 3160 getLocale(), 3161 this); 3162 } 3163 3164 /** 3165 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3166 */ 3167 @Override 3168 protected void onResponse(CmsGroupContainerSaveResult saveResult) { 3169 3170 stop(false); 3171 Map<String, CmsContainerElementData> elementData = saveResult.getElementData(); 3172 m_elements.putAll(elementData); 3173 try { 3174 replaceContainerElement(groupContainerElement, elementData.get(groupContainerElement.getId())); 3175 } catch (Exception e) { 3176 CmsDebugLog.getInstance().printLine("Error replacing group container element"); 3177 } 3178 addToRecentList(groupContainerElement.getId(), null); 3179 CmsNotification.get().send( 3180 Type.NORMAL, 3181 Messages.get().key(Messages.GUI_NOTIFICATION_GROUP_CONTAINER_SAVED_0)); 3182 List<CmsRemovedElementStatus> removedElements = saveResult.getRemovedElements(); 3183 for (CmsRemovedElementStatus removedElement : removedElements) { 3184 askWhetherRemovedElementShouldBeDeleted(removedElement); 3185 } 3186 3187 } 3188 }; 3189 action.execute(); 3190 3191 } 3192 } 3193 3194 /** 3195 * Saves the inheritance container.<p> 3196 * 3197 * @param inheritanceContainer the inheritance container data to save 3198 * @param groupContainerElement the group container widget 3199 */ 3200 public void saveInheritContainer( 3201 final CmsInheritanceContainer inheritanceContainer, 3202 final CmsGroupContainerElementPanel groupContainerElement) { 3203 3204 if (getGroupcontainer() != null) { 3205 CmsRpcAction<Map<String, CmsContainerElementData>> action = new CmsRpcAction<Map<String, CmsContainerElementData>>() { 3206 3207 /** 3208 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3209 */ 3210 @Override 3211 public void execute() { 3212 3213 start(0, true); 3214 getContainerpageService().saveInheritanceContainer( 3215 CmsCoreProvider.get().getStructureId(), 3216 getData().getDetailId(), 3217 inheritanceContainer, 3218 getPageState(), 3219 getLocale(), 3220 this); 3221 } 3222 3223 /** 3224 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3225 */ 3226 @Override 3227 protected void onResponse(Map<String, CmsContainerElementData> result) { 3228 3229 stop(false); 3230 m_elements.putAll(result); 3231 try { 3232 replaceContainerElement(groupContainerElement, result.get(groupContainerElement.getId())); 3233 } catch (Exception e) { 3234 CmsDebugLog.getInstance().printLine("Error replacing group container element"); 3235 } 3236 addToRecentList(groupContainerElement.getId(), null); 3237 CmsNotification.get().send( 3238 Type.NORMAL, 3239 Messages.get().key(Messages.GUI_NOTIFICATION_INHERITANCE_CONTAINER_SAVED_0)); 3240 3241 } 3242 }; 3243 action.execute(); 3244 3245 } 3246 } 3247 3248 /** 3249 * Sets the flag indicating that a content element is being edited.<p> 3250 * 3251 * @param isContentEditing the flag indicating that a content element is being edited 3252 */ 3253 public void setContentEditing(boolean isContentEditing) { 3254 3255 if (m_groupEditor != null) { 3256 if (isContentEditing) { 3257 m_groupEditor.hidePopup(); 3258 } else { 3259 m_groupEditor.showPopup(); 3260 } 3261 } 3262 m_isContentEditing = isContentEditing; 3263 } 3264 3265 /** 3266 * Sets the DND controller.<p> 3267 * 3268 * @param dnd the new DND controller 3269 */ 3270 public void setDndController(CmsCompositeDNDController dnd) { 3271 3272 m_dndController = dnd; 3273 } 3274 3275 /** 3276 * Sets the element view.<p> 3277 * 3278 * @param viewInfo the element view 3279 * @param nextAction the action to execute after setting the view 3280 */ 3281 public void setElementView(CmsElementViewInfo viewInfo, Runnable nextAction) { 3282 3283 if (viewInfo != null) { 3284 m_elementView = viewInfo; 3285 3286 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 3287 3288 @SuppressWarnings("synthetic-access") 3289 @Override 3290 public void execute() { 3291 3292 getContainerpageService().setElementView(m_elementView.getElementViewId(), this); 3293 } 3294 3295 @Override 3296 protected void onResponse(Void result) { 3297 3298 // nothing to do 3299 } 3300 }; 3301 action.execute(); 3302 3303 m_currentEditLevel = -1; 3304 reinitializeButtons(); 3305 updateButtonsForCurrentView(); 3306 reInitInlineEditing(); 3307 updateGalleryData(true, nextAction); 3308 } 3309 } 3310 3311 /** 3312 * Sets the model group base element id.<p> 3313 * 3314 * @param modelGroupElementId the model group base element id 3315 */ 3316 public void setModelGroupElementId(String modelGroupElementId) { 3317 3318 m_modelGroupElementId = modelGroupElementId; 3319 } 3320 3321 /** 3322 * Marks the page as changed.<p> 3323 * 3324 * @param nextActions the actions to perform after the page has been marked as changed 3325 */ 3326 public void setPageChanged(Runnable... nextActions) { 3327 3328 if (!isGroupcontainerEditing()) { 3329 // the container page will be saved immediately 3330 m_pageChanged = true; 3331 saveContainerpage(nextActions); 3332 } 3333 } 3334 3335 /** 3336 * Method to determine whether a container element should be shown in the current template context.<p> 3337 * 3338 * @param elementData the element data 3339 * 3340 * @return true if the element should be shown 3341 */ 3342 public boolean shouldShowInContext(CmsContainerElementData elementData) { 3343 3344 CmsTemplateContextInfo contextInfo = getData().getTemplateContextInfo(); 3345 if (contextInfo.getCurrentContext() == null) { 3346 return true; 3347 } 3348 CmsDefaultSet<String> allowedContexts = contextInfo.getAllowedContexts().get(elementData.getResourceType()); 3349 if ((allowedContexts != null) && !allowedContexts.contains(contextInfo.getCurrentContext())) { 3350 return false; 3351 } 3352 3353 String settingValue = elementData.getSettings().get(CmsTemplateContextInfo.SETTING); 3354 return (settingValue == null) || settingValue.contains(contextInfo.getCurrentContext()); 3355 } 3356 3357 /** 3358 * Tells the controller that group-container editing has started.<p> 3359 * 3360 * @param groupContainer the group container 3361 * @param isElementGroup <code>true</code> if the group container is an element group and not an inheritance group 3362 */ 3363 public void startEditingGroupcontainer( 3364 final CmsGroupContainerElementPanel groupContainer, 3365 final boolean isElementGroup) { 3366 3367 removeEditButtonsPositionTimer(); 3368 I_CmsSimpleCallback<Boolean> callback = new I_CmsSimpleCallback<Boolean>() { 3369 3370 public void execute(Boolean arg) { 3371 3372 if (arg.booleanValue()) { 3373 if (isElementGroup) { 3374 m_groupEditor = CmsGroupContainerEditor.openGroupcontainerEditor( 3375 groupContainer, 3376 CmsContainerpageController.this, 3377 m_handler); 3378 } else { 3379 m_groupEditor = CmsInheritanceContainerEditor.openInheritanceContainerEditor( 3380 groupContainer, 3381 CmsContainerpageController.this, 3382 m_handler); 3383 } 3384 } else { 3385 CmsNotification.get().send( 3386 Type.WARNING, 3387 Messages.get().key(Messages.GUI_NOTIFICATION_UNABLE_TO_LOCK_0)); 3388 } 3389 } 3390 }; 3391 if ((m_groupEditor == null) && (groupContainer.isNew())) { 3392 callback.execute(Boolean.TRUE); 3393 } else { 3394 lockContainerpage(callback); 3395 } 3396 3397 } 3398 3399 /** 3400 * Starts the publish lock check. 3401 */ 3402 public void startPublishLockCheck() { 3403 3404 Set<CmsUUID> elementIds = new HashSet<>(); 3405 processPageContent(new I_PageContentVisitor() { 3406 3407 public boolean beginContainer(String name, CmsContainer container) { 3408 3409 return true; 3410 } 3411 3412 public void endContainer() { 3413 3414 // do nothing 3415 } 3416 3417 public void handleElement(CmsContainerPageElementPanel element) { 3418 3419 if (element.hasWritePermission() && element.getLockInfo().isPublishLock()) { 3420 CmsUUID structureId = element.getStructureId(); 3421 if (structureId != null) { 3422 elementIds.add(structureId); 3423 } 3424 } 3425 } 3426 }); 3427 3428 m_publishLockChecker.addIdsToCheck(elementIds); 3429 } 3430 3431 /** 3432 * Tells the controller that group-container editing has stopped.<p> 3433 */ 3434 public void stopEditingGroupcontainer() { 3435 3436 m_groupEditor = null; 3437 } 3438 3439 /** 3440 * Unlocks the given resource.<p> 3441 * 3442 * @param structureId the structure id of the resource to unlock 3443 * 3444 * @return <code>true</code> if the resource was unlocked successfully 3445 */ 3446 public boolean unlockResource(CmsUUID structureId) { 3447 3448 return CmsCoreProvider.get().unlock(structureId); 3449 } 3450 3451 /** 3452 * Updates he 3453 */ 3454 public void updateButtonsForCurrentView() { 3455 3456 String nonDefaultViewClass = I_CmsLayoutBundle.INSTANCE.containerpageCss().nonDefaultView(); 3457 CmsUUID viewId = getElementView().getRootViewId(); 3458 if (viewId.isNullUUID()) { 3459 RootPanel.get().removeStyleName(nonDefaultViewClass); 3460 } else { 3461 RootPanel.get().addStyleName(nonDefaultViewClass); 3462 } 3463 } 3464 3465 /** 3466 * Adds the given element data to the element cache.<p> 3467 * 3468 * @param elements the element data 3469 */ 3470 protected void addElements(List<CmsContainerElementData> elements) { 3471 3472 for (CmsContainerElementData element : elements) { 3473 m_elements.put(element.getClientId(), element); 3474 } 3475 } 3476 3477 /** 3478 * Adds the given element data to the element cache.<p> 3479 * 3480 * @param elements the element data 3481 */ 3482 protected void addElements(Map<String, CmsContainerElementData> elements) { 3483 3484 for (CmsContainerElementData element : elements.values()) { 3485 m_elements.put(element.getClientId(), element); 3486 } 3487 } 3488 3489 /** 3490 * Asks the user whether an element which has been removed should be deleted.<p> 3491 * 3492 * @param status the status of the removed element 3493 */ 3494 protected void askWhetherRemovedElementShouldBeDeleted(final CmsRemovedElementStatus status) { 3495 3496 CmsRemovedElementDeletionDialog dialog = new CmsRemovedElementDeletionDialog(status); 3497 dialog.center(); 3498 } 3499 3500 /** 3501 * Checks that a removed can be possibly deleted and if so, asks the user if it should be deleted.<p> 3502 * 3503 * @param id the client id of the element 3504 */ 3505 protected void checkReferencesToRemovedElement(final String id) { 3506 3507 if (id != null) { 3508 //NOTE: We only use an RPC call here to check for references on the server side. If, at a later point, we decide 3509 //to add a save button again, this will have to be changed, because then we have to consider client-side state. 3510 CmsRpcAction<CmsRemovedElementStatus> getStatusAction = new CmsRpcAction<CmsRemovedElementStatus>() { 3511 3512 @Override 3513 public void execute() { 3514 3515 start(200, true); 3516 getContainerpageService().getRemovedElementStatus(id, null, this); 3517 } 3518 3519 @Override 3520 public void onResponse(final CmsRemovedElementStatus status) { 3521 3522 stop(false); 3523 if (status.isDeletionCandidate()) { 3524 askWhetherRemovedElementShouldBeDeleted(status); 3525 3526 } 3527 } 3528 3529 }; 3530 getStatusAction.execute(); 3531 3532 } 3533 } 3534 3535 /** 3536 * Disables option and toolbar buttons.<p> 3537 */ 3538 protected void deactivateOnClosing() { 3539 3540 removeEditButtonsPositionTimer(); 3541 m_handler.deactivateCurrentButton(); 3542 m_handler.disableToolbarButtons(); 3543 } 3544 3545 /** 3546 * Helper method to get all current container page elements.<p> 3547 * 3548 * @param includeGroupContents true if the contents of group containers should also be included 3549 * 3550 * @return the list of current container page elements 3551 */ 3552 protected List<CmsContainerPageElementPanel> getAllContainerPageElements(boolean includeGroupContents) { 3553 3554 List<CmsContainerPageElementPanel> elemWidgets = new ArrayList<CmsContainerPageElementPanel>(); 3555 for (Entry<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> entry : CmsContainerpageController.get().getContainerTargets().entrySet()) { 3556 Iterator<Widget> elIt = entry.getValue().iterator(); 3557 while (elIt.hasNext()) { 3558 try { 3559 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel elementWidget = (org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel)elIt.next(); 3560 elemWidgets.add(elementWidget); 3561 if (includeGroupContents && (elementWidget instanceof CmsGroupContainerElementPanel)) { 3562 List<CmsContainerPageElementPanel> groupChildren = ((CmsGroupContainerElementPanel)elementWidget).getGroupChildren(); 3563 elemWidgets.addAll(groupChildren); 3564 } 3565 } catch (ClassCastException e) { 3566 // no proper container element, skip it (this should never happen!) 3567 CmsDebugLog.getInstance().printLine( 3568 "WARNING: there is an inappropriate element within a container"); 3569 } 3570 } 3571 } 3572 return elemWidgets; 3573 } 3574 3575 /** 3576 * Returns the core RPC service.<p> 3577 * 3578 * @return the core service 3579 */ 3580 protected I_CmsCoreServiceAsync getCoreService() { 3581 3582 if (m_coreSvc == null) { 3583 m_coreSvc = CmsCoreProvider.getService(); 3584 } 3585 return m_coreSvc; 3586 } 3587 3588 /** 3589 * Returns the currently active group editor.<p> 3590 * 3591 * @return the currently active group editor 3592 */ 3593 protected A_CmsGroupEditor getGroupEditor() { 3594 3595 return m_groupEditor; 3596 } 3597 3598 /** 3599 * Returns the content locale.<p> 3600 * 3601 * @return the content locale 3602 */ 3603 protected String getLocale() { 3604 3605 return m_data.getLocale(); 3606 } 3607 3608 /** 3609 * Gets the page content for purposes of saving.<p> 3610 * 3611 * @return the page content 3612 */ 3613 protected List<CmsContainer> getPageContent() { 3614 3615 SaveDataVisitor visitor = new SaveDataVisitor(); 3616 processPageContent(visitor); 3617 return visitor.getContainers(); 3618 3619 } 3620 3621 /** 3622 * Returns the containers of the page in their current state.<p> 3623 * 3624 * @return the containers of the page 3625 */ 3626 protected List<CmsContainer> getPageState() { 3627 3628 PageStateVisitor visitor = new PageStateVisitor(); 3629 processPageContent(visitor); 3630 return visitor.getContainers(); 3631 } 3632 3633 /** 3634 * Returns the request parameters of the displayed container-page.<p> 3635 * 3636 * @return the request parameters 3637 */ 3638 protected String getRequestParams() { 3639 3640 return m_data.getRequestParams(); 3641 } 3642 3643 /** 3644 * Checks if any of the containers are nested containers.<p> 3645 * 3646 * @return true if there are nested containers 3647 */ 3648 protected boolean hasNestedContainers() { 3649 3650 boolean hasNestedContainers = false; 3651 for (CmsContainer container : m_containers.values()) { 3652 if (container.getParentContainerName() != null) { 3653 hasNestedContainers = true; 3654 break; 3655 } 3656 } 3657 return hasNestedContainers; 3658 } 3659 3660 /** 3661 * Returns whether the given container is considered a root container.<p> 3662 * 3663 * @param container the container to check 3664 * 3665 * @return <code>true</code> if the given container is a root container 3666 */ 3667 protected boolean isRootContainer(CmsContainer container) { 3668 3669 boolean isRoot = false; 3670 if (!container.isSubContainer()) { 3671 isRoot = true; 3672 } else if (container.isDetailOnly()) { 3673 CmsContainer parent = getContainer(container.getParentContainerName()); 3674 isRoot = (parent != null) && !parent.isDetailOnly(); 3675 } 3676 return isRoot; 3677 } 3678 3679 /** 3680 * Opens the editor for the newly created element.<p> 3681 * 3682 * @param element the container element 3683 * @param newElementData the new element data 3684 * @param inline <code>true</code> to open the inline editor for the given element if available 3685 */ 3686 protected void openEditorForNewElement( 3687 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element, 3688 CmsContainerElement newElementData, 3689 boolean inline) { 3690 3691 String oldId = element.getNewType(); 3692 element.setNewType(null); 3693 if (inline) { 3694 String newId = getServerId(newElementData.getClientId()); 3695 CmsContentEditor.replaceResourceIds(element.getElement(), oldId, newId); 3696 } 3697 element.setId(newElementData.getClientId()); 3698 element.setSitePath(newElementData.getSitePath()); 3699 if (!isGroupcontainerEditing()) { 3700 setPageChanged(); 3701 } 3702 getHandler().hidePageOverlay(); 3703 getHandler().openEditorForElement(element, inline, true); 3704 } 3705 3706 /** 3707 * Previews events. Shows the leaving page dialog, if the page has changed and an anchor has been clicked.<p> 3708 * Also triggers an element view change on 'Ctrl+E'.<p> 3709 * 3710 * @param event the native event 3711 */ 3712 protected void previewNativeEvent(NativePreviewEvent event) { 3713 3714 Event nativeEvent = Event.as(event.getNativeEvent()); 3715 3716 if ((nativeEvent.getTypeInt() == Event.ONCLICK) && hasPageChanged()) { 3717 EventTarget target = nativeEvent.getEventTarget(); 3718 if (!Element.is(target)) { 3719 return; 3720 } 3721 Element element = Element.as(target); 3722 element = CmsDomUtil.getAncestor(element, CmsDomUtil.Tag.a); 3723 if (element == null) { 3724 return; 3725 } 3726 AnchorElement anc = AnchorElement.as(element); 3727 final String uri = anc.getHref(); 3728 3729 // avoid to abort events for date-picker widgets 3730 if (CmsStringUtil.isEmptyOrWhitespaceOnly(uri) 3731 || (CmsDomUtil.getAncestor(element, "x-date-picker") != null)) { 3732 return; 3733 } 3734 nativeEvent.preventDefault(); 3735 nativeEvent.stopPropagation(); 3736 m_handler.leavePage(uri); 3737 } 3738 if (event.getTypeInt() == Event.ONKEYDOWN) { 3739 int keyCode = nativeEvent.getKeyCode(); 3740 if ((keyCode == KeyCodes.KEY_F5) && hasPageChanged()) { 3741 // user pressed F5 3742 nativeEvent.preventDefault(); 3743 nativeEvent.stopPropagation(); 3744 m_handler.leavePage(Window.Location.getHref()); 3745 } 3746 if (nativeEvent.getCtrlKey() || nativeEvent.getMetaKey()) { 3747 // look for short cuts 3748 if (keyCode == KeyCodes.KEY_E) { 3749 if (nativeEvent.getShiftKey()) { 3750 circleContainerEditLayers(); 3751 } else { 3752 openNextElementView(); 3753 } 3754 nativeEvent.preventDefault(); 3755 nativeEvent.stopPropagation(); 3756 } 3757 } 3758 } 3759 } 3760 3761 /** 3762 * Iterates over all the container contents and calls a visitor object with the visited containers/elements as parameters. 3763 * 3764 * @param visitor the visitor which the container elements should be passed to 3765 */ 3766 protected void processPageContent(I_PageContentVisitor visitor) { 3767 3768 for (Entry<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> entry : m_targetContainers.entrySet()) { 3769 3770 CmsContainer cnt = m_containers.get(entry.getKey()); 3771 if (visitor.beginContainer(entry.getKey(), cnt)) { 3772 Iterator<Widget> elIt = entry.getValue().iterator(); 3773 while (elIt.hasNext()) { 3774 try { 3775 CmsContainerPageElementPanel elementWidget = (CmsContainerPageElementPanel)elIt.next(); 3776 visitor.handleElement(elementWidget); 3777 } catch (ClassCastException e) { 3778 // no proper container element, skip it (this should never happen!) 3779 CmsDebugLog.getInstance().printLine( 3780 "WARNING: there is an inappropriate element within a container"); 3781 } 3782 } 3783 visitor.endContainer(); 3784 } 3785 } 3786 } 3787 3788 /** 3789 * Removes all container elements with the given id from all containers and the client side cache.<p> 3790 * 3791 * @param resourceId the resource id 3792 */ 3793 protected void removeContainerElements(String resourceId) { 3794 3795 boolean changed = false; 3796 Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> it = getAllDragElements().iterator(); 3797 while (it.hasNext()) { 3798 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel containerElement = it.next(); 3799 if (resourceId.startsWith(containerElement.getId())) { 3800 containerElement.removeFromParent(); 3801 changed = true; 3802 } 3803 } 3804 for (String elementId : m_elements.keySet()) { 3805 if (elementId.startsWith(resourceId)) { 3806 m_elements.remove(elementId); 3807 } 3808 } 3809 if (changed) { 3810 setPageChanged(); 3811 } 3812 } 3813 3814 /** 3815 * Schedules an update of the gallery data according to the current element view and the editable containers.<p> 3816 */ 3817 protected void scheduleGalleryUpdate() { 3818 3819 // only if not already scheduled 3820 if (m_galleryUpdateTimer == null) { 3821 m_galleryUpdateTimer = new Timer() { 3822 3823 @Override 3824 public void run() { 3825 3826 m_galleryUpdateTimer = null; 3827 updateGalleryData(false, null); 3828 } 3829 }; 3830 m_galleryUpdateTimer.schedule(50); 3831 } 3832 } 3833 3834 /** 3835 * Sets the page changed flag and initializes the window closing handler if necessary.<p> 3836 * 3837 * @param changed if <code>true</code> the page has changed 3838 * @param unlock if <code>true</code> the page will be unlocked for unchanged pages 3839 */ 3840 protected void setPageChanged(boolean changed, boolean unlock) { 3841 3842 if (changed) { 3843 if (!m_pageChanged) { 3844 m_pageChanged = changed; 3845 lockContainerpage(new I_CmsSimpleCallback<Boolean>() { 3846 3847 public void execute(Boolean arg) { 3848 3849 // nothing to do 3850 } 3851 }); 3852 } 3853 } else { 3854 m_pageChanged = changed; 3855 if (unlock) { 3856 unlockContainerpage(); 3857 } 3858 } 3859 } 3860 3861 /** 3862 * Asynchronously unlocks the container page. 3863 */ 3864 protected void unlockContainerpage() { 3865 3866 I_CmsUnlockDataFactory factory = GWT.create(I_CmsUnlockDataFactory.class); 3867 AutoBean<I_CmsUnlockData> unlockParams = factory.unlockData(); 3868 unlockParams.as().setPageId("" + CmsCoreProvider.get().getStructureId()); 3869 if (getData().getDetailId() != null) { 3870 unlockParams.as().setDetailId("" + getData().getDetailId()); 3871 } 3872 unlockParams.as().setLocale(CmsCoreProvider.get().getLocale()); 3873 String url = CmsCoreProvider.get().link("/handleBuiltinService" + CmsGwtConstants.HANDLER_UNLOCK_PAGE); 3874 sendBeacon(url, AutoBeanCodex.encode(unlockParams).getPayload()); 3875 } 3876 3877 /** 3878 * Returns the pages of editable containers.<p> 3879 * 3880 * @return the containers 3881 */ 3882 List<CmsContainer> getEditableContainers() { 3883 3884 List<CmsContainer> containers = new ArrayList<CmsContainer>(); 3885 for (CmsContainer container : m_containers.values()) { 3886 if ((m_targetContainers.get(container.getName()) != null) 3887 && isContainerEditable(m_targetContainers.get(container.getName()))) { 3888 containers.add(container); 3889 } 3890 } 3891 return containers; 3892 } 3893 3894 /** 3895 * Handles a window resize to reset highlighting and the edit button positions.<p> 3896 */ 3897 void handleResize() { 3898 3899 m_resizeTimer = null; 3900 resetEditButtons(); 3901 } 3902 3903 /** 3904 * Call on window resize.<p> 3905 */ 3906 void onResize() { 3907 3908 if (!isGroupcontainerEditing() && (m_resizeTimer == null)) { 3909 m_resizeTimer = new Timer() { 3910 3911 @Override 3912 public void run() { 3913 3914 handleResize(); 3915 } 3916 }; 3917 m_resizeTimer.schedule(300); 3918 } 3919 } 3920 3921 /** 3922 * Sets the load time.<p> 3923 * 3924 * @param time the time to set 3925 */ 3926 void setLoadTime(Long time) { 3927 3928 if (time != null) { 3929 m_loadTime = time.longValue(); 3930 } 3931 } 3932 3933 /** 3934 * Updates the gallery data according to the current element view and the editable containers.<p> 3935 * This method should only be called from the gallery update timer to avoid unnecessary requests.<p> 3936 * 3937 * @param viewChanged <code>true</code> in case the element view changed 3938 * @param nextAction the action to execute after updating the gallery data 3939 */ 3940 void updateGalleryData(final boolean viewChanged, final Runnable nextAction) { 3941 3942 CmsRpcAction<CmsContainerPageGalleryData> dataAction = new CmsRpcAction<CmsContainerPageGalleryData>() { 3943 3944 @Override 3945 public void execute() { 3946 3947 getContainerpageService().getGalleryDataForPage( 3948 getEditableContainers(), 3949 getElementView().getElementViewId(), 3950 CmsCoreProvider.get().getUri(), 3951 getData().getLocale(), 3952 this); 3953 } 3954 3955 @Override 3956 protected void onResponse(CmsContainerPageGalleryData result) { 3957 3958 m_handler.m_editor.getAdd().updateGalleryData(result, viewChanged); 3959 if (nextAction != null) { 3960 nextAction.run(); 3961 } 3962 } 3963 }; 3964 dataAction.execute(); 3965 } 3966 3967 /** 3968 * Checks whether there are other references to a given container page element.<p> 3969 * 3970 * @param element the element to check 3971 * @param callback the callback which will be called with the result of the check (true if there are other references) 3972 */ 3973 private void checkElementReferences( 3974 final CmsContainerPageElementPanel element, 3975 final AsyncCallback<CmsRemovedElementStatus> callback) { 3976 3977 ReferenceCheckVisitor visitor = new ReferenceCheckVisitor(element); 3978 processPageContent(visitor); 3979 if (visitor.hasReferences()) { 3980 // Don't need to ask the server because we already know we have other references in the same page 3981 CmsRpcAction<CmsListInfoBean> infoAction = new CmsRpcAction<CmsListInfoBean>() { 3982 3983 @Override 3984 public void execute() { 3985 3986 start(200, true); 3987 CmsCoreProvider.getVfsService().getPageInfo(new CmsUUID(getServerId(element.getId())), this); 3988 } 3989 3990 @Override 3991 protected void onResponse(CmsListInfoBean result) { 3992 3993 stop(false); 3994 callback.onSuccess(new CmsRemovedElementStatus(null, result, false, null)); 3995 } 3996 }; 3997 infoAction.execute(); 3998 } else { 3999 CmsRpcAction<CmsRemovedElementStatus> getStatusAction = new CmsRpcAction<CmsRemovedElementStatus>() { 4000 4001 @Override 4002 public void execute() { 4003 4004 start(200, true); 4005 getContainerpageService().getRemovedElementStatus( 4006 element.getId(), 4007 CmsCoreProvider.get().getStructureId(), 4008 this); 4009 } 4010 4011 @Override 4012 public void onResponse(final CmsRemovedElementStatus status) { 4013 4014 stop(false); 4015 callback.onSuccess(status); 4016 } 4017 4018 }; 4019 getStatusAction.execute(); 4020 4021 } 4022 } 4023 4024 /** 4025 * Checks if the page was locked by another user at load time.<p> 4026 */ 4027 private void checkLockInfo() { 4028 4029 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getData().getLockInfo())) { 4030 CmsNotification.get().send(Type.ERROR, getData().getLockInfo()); 4031 m_lockStatus = LockStatus.failed; 4032 m_handler.m_editor.disableEditing(getData().getLockInfo()); 4033 } 4034 } 4035 4036 /** 4037 * Selects the next container edit level.<p> 4038 */ 4039 private void circleContainerEditLayers() { 4040 4041 if (m_isContentEditing || isGroupcontainerEditing() || (m_maxContainerLevel == 0)) { 4042 return; 4043 } 4044 boolean hasEditables = false; 4045 int previousLevel = m_currentEditLevel; 4046 String message = ""; 4047 while (!hasEditables) { 4048 if (m_currentEditLevel == m_maxContainerLevel) { 4049 m_currentEditLevel = -1; 4050 message = Messages.get().key(Messages.GUI_SWITCH_EDIT_LEVEL_ALL_1, m_elementView.getTitle()); 4051 } else { 4052 m_currentEditLevel++; 4053 message = Messages.get().key(Messages.GUI_SWITCH_EDIT_LEVEL_1, Integer.valueOf(m_currentEditLevel)); 4054 } 4055 reinitializeButtons(); 4056 hasEditables = !CmsDomUtil.getElementsByClass( 4057 I_CmsElementToolbarContext.ELEMENT_OPTION_BAR_CSS_CLASS).isEmpty(); 4058 } 4059 if (previousLevel != m_currentEditLevel) { 4060 CmsNotification.get().send(Type.NORMAL, message); 4061 } 4062 } 4063 4064 /** 4065 * Returns all element id's related to the given one.<p> 4066 * 4067 * @param id the element id 4068 * @return the related id's 4069 */ 4070 private Set<String> getRelatedElementIds(String id) { 4071 4072 Set<String> result = new HashSet<String>(); 4073 if (id != null) { 4074 result.add(id); 4075 String serverId = getServerId(id); 4076 4077 Iterator<String> it = m_elements.keySet().iterator(); 4078 while (it.hasNext()) { 4079 String elId = it.next(); 4080 if (elId.startsWith(serverId)) { 4081 result.add(elId); 4082 } 4083 } 4084 4085 Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> itEl = getAllDragElements().iterator(); 4086 while (itEl.hasNext()) { 4087 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element = itEl.next(); 4088 if (element.getId().startsWith(serverId)) { 4089 result.add(element.getId()); 4090 } 4091 } 4092 } 4093 return result; 4094 } 4095 4096 /** 4097 * Checks whether the given container matches the current edit level.<p> 4098 * 4099 * @param container the container to check 4100 * 4101 * @return <code>true</code> if the given container matches the current edit level 4102 */ 4103 private boolean matchesCurrentEditLevel(I_CmsDropContainer container) { 4104 4105 boolean result = !(container instanceof CmsContainerPageContainer) 4106 || (m_currentEditLevel == -1) 4107 || (m_currentEditLevel == ((CmsContainerPageContainer)container).getContainerLevel()); 4108 return result; 4109 } 4110 4111 /** 4112 * Opens the next available root element view.<p> 4113 */ 4114 private void openNextElementView() { 4115 4116 List<CmsElementViewInfo> views = getData().getElementViews(); 4117 if (views.size() > 1) { 4118 CmsUUID current = m_elementView.getRootViewId(); 4119 4120 // look for the current view index 4121 int currentIndex = -1; 4122 for (int i = 0; i < views.size(); i++) { 4123 CmsElementViewInfo view = views.get(i); 4124 if (view.isRoot() && current.equals(view.getElementViewId())) { 4125 currentIndex = i; 4126 break; 4127 } 4128 } 4129 if (currentIndex != -1) { 4130 CmsElementViewInfo target = null; 4131 // look for the next root view 4132 for (int i = currentIndex + 1; i < views.size(); i++) { 4133 CmsElementViewInfo view = views.get(i); 4134 if (view.isRoot()) { 4135 target = view; 4136 break; 4137 } 4138 } 4139 if (target == null) { 4140 // start at the beginning 4141 for (int i = 0; i < currentIndex; i++) { 4142 CmsElementViewInfo view = views.get(i); 4143 if (view.isRoot()) { 4144 target = view; 4145 break; 4146 } 4147 } 4148 } 4149 if (target != null) { 4150 final String viewName = target.getTitle(); 4151 Runnable action = new Runnable() { 4152 4153 public void run() { 4154 4155 CmsNotification.get().send( 4156 Type.NORMAL, 4157 Messages.get().key(Messages.GUI_SWITCH_ELEMENT_VIEW_NOTIFICATION_1, viewName)); 4158 } 4159 }; 4160 setElementView(target, action); 4161 } 4162 } 4163 } 4164 } 4165 4166 /** 4167 * Removes the edit buttons position timer.<p> 4168 */ 4169 private void removeEditButtonsPositionTimer() { 4170 4171 if (m_editButtonsPositionTimer != null) { 4172 m_editButtonsPositionTimer.cancel(); 4173 m_editButtonsPositionTimer = null; 4174 } 4175 } 4176 4177 /** 4178 * Calls the browser's sendBeacon function. 4179 * 4180 * @param url the URL to send the data to 4181 * @param data the data to send 4182 */ 4183 private native void sendBeacon(String url, String data) /*-{ 4184 $wnd.navigator.sendBeacon(url, data); 4185 }-*/; 4186 4187 /** 4188 * Checks whether given element is a model group and it's option bar edit points should be visible.<p> 4189 * 4190 * @param element the element to check 4191 * 4192 * @return <code>true</code> in case the current page is not a model group page, 4193 * the given element is a model group and it is inside a view visible to the current user 4194 */ 4195 private boolean shouldShowModelgroupOptionBar(CmsContainerPageElementPanel element) { 4196 4197 if (!getData().isModelGroup() && element.isModelGroup()) { 4198 for (CmsElementViewInfo info : getData().getElementViews()) { 4199 if (info.getElementViewId().equals(element.getElementView())) { 4200 return true; 4201 } 4202 } 4203 } 4204 4205 return false; 4206 } 4207 4208 /** 4209 * Updates the container level info on the present containers.<p> 4210 */ 4211 private void updateContainerLevelInfo() { 4212 4213 Map<String, CmsContainerPageContainer> containers = new HashMap<String, CmsContainerPageContainer>(); 4214 List<CmsContainerPageContainer> temp = new ArrayList<CmsContainerPageContainer>(m_targetContainers.values()); 4215 m_maxContainerLevel = 0; 4216 boolean progress = true; 4217 while (!temp.isEmpty() && progress) { 4218 int size = containers.size(); 4219 Iterator<CmsContainerPageContainer> it = temp.iterator(); 4220 while (it.hasNext()) { 4221 CmsContainerPageContainer container = it.next(); 4222 int level = -1; 4223 if (CmsStringUtil.isEmptyOrWhitespaceOnly(container.getParentContainerId())) { 4224 level = 0; 4225 } else if (containers.containsKey(container.getParentContainerId())) { 4226 level = containers.get(container.getParentContainerId()).getContainerLevel() + 1; 4227 } 4228 if (level > -1) { 4229 container.setContainerLevel(level); 4230 containers.put(container.getContainerId(), container); 4231 it.remove(); 4232 if (level > m_maxContainerLevel) { 4233 m_maxContainerLevel = level; 4234 } 4235 } 4236 } 4237 progress = containers.size() > size; 4238 } 4239 } 4240 4241 /** 4242 * Sets the oc-detail-preview class on first container elements of an appropriate type in detail containers, 4243 * if we are currently not showing a detail content. 4244 */ 4245 private void updateDetailPreviewStyles() { 4246 4247 Set<String> detailTypes = getData().getDetailTypes(); 4248 if ((getData().getDetailId() != null) || detailTypes.isEmpty()) { 4249 return; 4250 } 4251 for (Element elem : CmsDomUtil.getElementsByClass(CmsGwtConstants.CLASS_DETAIL_PREVIEW)) { 4252 elem.removeClassName(CmsGwtConstants.CLASS_DETAIL_PREVIEW); 4253 } 4254 boolean defaultDetailPage = detailTypes.contains(CmsGwtConstants.DEFAULT_DETAILPAGE_TYPE); 4255 4256 processPageContent(new I_PageContentVisitor() { 4257 4258 boolean m_isdetail = false; 4259 4260 public boolean beginContainer(String name, CmsContainer container) { 4261 4262 m_isdetail = container.isDetailViewContainer(); 4263 return true; 4264 } 4265 4266 public void endContainer() { 4267 4268 // do nothing 4269 } 4270 4271 public void handleElement(CmsContainerPageElementPanel element) { 4272 4273 if (m_isdetail && (defaultDetailPage || detailTypes.contains(element.getResourceType()))) { 4274 element.addStyleName(CmsGwtConstants.CLASS_DETAIL_PREVIEW); 4275 } 4276 } 4277 }); 4278 4279 } 4280}