org.opencms.ade.containerpage.client.CmsContainerpageController.java Source code

Java tutorial

Introduction

Here is the source code for org.opencms.ade.containerpage.client.CmsContainerpageController.java

Source

/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.ade.containerpage.client;

import org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer;
import org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel;
import org.opencms.ade.containerpage.client.ui.CmsGroupContainerElementPanel;
import org.opencms.ade.containerpage.client.ui.I_CmsDropContainer;
import org.opencms.ade.containerpage.client.ui.css.I_CmsLayoutBundle;
import org.opencms.ade.containerpage.shared.CmsCntPageData;
import org.opencms.ade.containerpage.shared.CmsContainer;
import org.opencms.ade.containerpage.shared.CmsContainerElement;
import org.opencms.ade.containerpage.shared.CmsContainerElementData;
import org.opencms.ade.containerpage.shared.CmsCreateElementData;
import org.opencms.ade.containerpage.shared.CmsGroupContainer;
import org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService;
import org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageServiceAsync;
import org.opencms.gwt.client.CmsCoreProvider;
import org.opencms.gwt.client.dnd.CmsDNDHandler;
import org.opencms.gwt.client.dnd.I_CmsDNDController;
import org.opencms.gwt.client.rpc.CmsRpcAction;
import org.opencms.gwt.client.rpc.CmsRpcPrefetcher;
import org.opencms.gwt.client.ui.CmsNotification;
import org.opencms.gwt.client.ui.CmsNotification.Type;
import org.opencms.gwt.client.util.CmsDebugLog;
import org.opencms.gwt.client.util.CmsDomUtil;
import org.opencms.gwt.client.util.I_CmsSimpleCallback;
import org.opencms.gwt.shared.CmsContextMenuEntryBean;
import org.opencms.gwt.shared.CmsCoreData.AdeContext;
import org.opencms.gwt.shared.CmsLockInfo;
import org.opencms.gwt.shared.rpc.I_CmsCoreServiceAsync;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.CmsUUID;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.AnchorElement;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.ClosingEvent;
import com.google.gwt.user.client.Window.ClosingHandler;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * Data provider for the container-page editor. All data concerning the container-page is requested and maintained by this provider.<p>
 * 
 * @since 8.0.0
 */
public final class CmsContainerpageController {

    /**
     * A type which indicates the locking status of the currently edited container page.<p>
     */
    enum LockStatus {
        /** Locking the resource failed. */
        failed,

        /** The resource could be successfully locked. */
        locked,

        /** Locking the resource has not been tried. */
        unknown
    }

    /**
     * A RPC action implementation used to request the data for container-page elements.<p>
     */
    private class MultiElementAction extends CmsRpcAction<Map<String, CmsContainerElementData>> {

        /** Call-back executed on response. */
        private I_CmsSimpleCallback<Map<String, CmsContainerElementData>> m_callback;

        /** The requested client id's. */
        private Set<String> m_clientIds;

        /**
        "         * Constructor.<p>
         * 
         * @param clientIds the client id's
         * @param callback the call-back
         */
        public MultiElementAction(Set<String> clientIds,
                I_CmsSimpleCallback<Map<String, CmsContainerElementData>> callback) {

            super();
            m_clientIds = clientIds;
            m_callback = callback;
        }

        /**
         * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
         */
        @Override
        public void execute() {

            Map<String, CmsContainerElementData> result = new HashMap<String, CmsContainerElementData>();
            List<String> neededIds = new ArrayList<String>();
            Iterator<String> it = m_clientIds.iterator();
            while (it.hasNext()) {
                String clientId = it.next();
                if (m_elements.containsKey(clientId)) {
                    result.put(clientId, m_elements.get(clientId));
                } else {
                    neededIds.add(clientId);
                }
            }
            if (neededIds.size() == 0) {
                m_callback.execute(result);
            } else {
                getContainerpageService().getElementsData(CmsCoreProvider.get().getStructureId(),
                        getRequestParams(), m_clientIds, m_containerBeans, getLocale(), this);
            }

        }

        /**
         * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
         */
        @Override
        protected void onResponse(Map<String, CmsContainerElementData> result) {

            if (result != null) {
                addElements(result);
                Map<String, CmsContainerElementData> elements = new HashMap<String, CmsContainerElementData>();
                Iterator<String> it = m_clientIds.iterator();
                while (it.hasNext()) {
                    String clientId = it.next();
                    elements.put(clientId, m_elements.get(clientId));
                }
                m_callback.execute(elements);
            }
        }

    }

    /**
     * A RPC action implementation used to reload the data for a container-page element.<p>
     */
    private class ReloadElementAction extends CmsRpcAction<Map<String, CmsContainerElementData>> {

        /** The requested client id's. */
        private Set<String> m_clientIds;

        /**
         * Constructor.<p>
         * 
         * @param clientIds the client id's to reload
         */
        public ReloadElementAction(Set<String> clientIds) {

            super();
            m_clientIds = clientIds;
        }

        /**
         * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
         */
        @Override
        public void execute() {

            getContainerpageService().getElementsData(CmsCoreProvider.get().getStructureId(), getRequestParams(),
                    m_clientIds, m_containerBeans, getLocale(), this);

        }

        /**
         * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
         */
        @Override
        protected void onResponse(Map<String, CmsContainerElementData> result) {

            if (result == null) {
                return;
            }
            addElements(result);
            Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> it = getAllDragElements()
                    .iterator();
            while (it.hasNext()) {
                org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel containerElement = it.next();
                if (!m_clientIds.contains(containerElement.getId())) {
                    continue;
                }
                try {
                    replaceContainerElement(containerElement, m_elements.get(containerElement.getId()));
                } catch (Exception e) {
                    CmsDebugLog.getInstance().printLine("trying to replace");
                    CmsDebugLog.getInstance().printLine(e.getLocalizedMessage());
                }

            }
            resetEditableListButtons();
        }
    }

    /**
     * A RPC action implementation used to request the data for a single container-page element.<p>
     */
    private class SingleElementAction extends CmsRpcAction<Map<String, CmsContainerElementData>> {

        /** Call-back executed on response. */
        private I_CmsSimpleCallback<CmsContainerElementData> m_callback;

        /** The requested client id. */
        private String m_clientId;

        /**
         * Constructor.<p>
         * 
         * @param clientId the client id
         * @param callback the call-back
         */
        public SingleElementAction(String clientId, I_CmsSimpleCallback<CmsContainerElementData> callback) {

            super();
            m_clientId = clientId;
            m_callback = callback;
        }

        /**
         * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
         */
        @Override
        public void execute() {

            boolean cached = false;
            if (m_elements.containsKey(m_clientId)) {
                cached = true;
                CmsContainerElementData elementData = m_elements.get(m_clientId);
                if (elementData.isGroupContainer()) {
                    for (String subItemId : elementData.getSubItems()) {
                        if (!m_elements.containsKey(subItemId)) {
                            cached = false;
                            break;
                        }
                    }
                }
            }
            if (cached) {
                Scheduler.get().scheduleDeferred(new ScheduledCommand() {

                    /**
                     * @see com.google.gwt.user.client.Command#execute()
                     */
                    public void execute() {

                        getCallback().execute(m_elements.get(getClientId()));

                    }
                });
            } else {
                List<String> clientIds = new ArrayList<String>();
                clientIds.add(m_clientId);
                getContainerpageService().getElementsData(CmsCoreProvider.get().getStructureId(),
                        getRequestParams(), clientIds, m_containerBeans, getLocale(), this);
            }

        }

        /**
         * Returns the call-back function.<p>
         * 
         * @return the call-back function
         */
        protected I_CmsSimpleCallback<CmsContainerElementData> getCallback() {

            return m_callback;
        }

        /** 
         * Returns the requested elements id.<p>
         * 
         * @return the element client id
         */
        protected String getClientId() {

            return m_clientId;
        }

        /**
         * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
         */
        @Override
        protected void onResponse(Map<String, CmsContainerElementData> result) {

            if (result != null) {
                addElements(result);
                m_callback.execute(m_elements.get(m_clientId));
            }
        }
    }

    /** The client side id/setting-hash seperator. */
    public static final String CLIENT_ID_SEPERATOR = "#";

    /** Instance of the data provider. */
    private static CmsContainerpageController INSTANCE;

    /** The list of beans for the containers on the current page. */
    protected List<CmsContainer> m_containerBeans;

    /** The container element data. All requested elements will be cached here.*/
    protected Map<String, CmsContainerElementData> m_elements;

    /** The new element data by resource type name. */
    protected Map<String, CmsContainerElementData> m_newElements;

    /** The container-page handler. */
    CmsContainerpageHandler m_handler;

    /** The container page drag and drop controller. */
    private I_CmsDNDController m_cntDndController;

    /** The container-page RPC service. */
    private I_CmsContainerpageServiceAsync m_containerpageService;

    /** The container-page util instance. */
    private CmsContainerpageUtil m_containerpageUtil;

    /** The container data. */
    private Map<String, CmsContainerJso> m_containers;

    /** The container types within this page. */
    private Set<String> m_containerTypes;

    /** The XML content editor handler. */
    private CmsContentEditorHandler m_contentEditorHandler;

    /** The core RPC service instance. */
    private I_CmsCoreServiceAsync m_coreSvc;

    /** The prefetched data. */
    private CmsCntPageData m_data;

    /** The drag and drop handler. */
    private CmsDNDHandler m_dndHandler;

    /** The currently edited group-container element. */
    private CmsGroupContainerElementPanel m_editingGroupcontainer;

    /** The lock error message. */
    private String m_lockErrorMessage;

    /** The current lock status for the page. */
    private LockStatus m_lockStatus = LockStatus.unknown;

    /** Flag if the container-page has changed. */
    private boolean m_pageChanged;

    /** The drag targets within this page. */
    private Map<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> m_targetContainers;

    /**
     * Constructor.<p>
     */
    public CmsContainerpageController() {

        INSTANCE = this;
        m_data = (CmsCntPageData) CmsRpcPrefetcher.getSerializedObject(getContainerpageService(),
                CmsCntPageData.DICT_NAME);
    }

    /**
     * Returns the data provider instance.<p>
     * 
     * @return the data provider
     */
    public static CmsContainerpageController get() {

        if (INSTANCE == null) {
            CmsDebugLog.getInstance().printLine("WARNING: The data provider has not been initialized!");
            return null;
        }
        return INSTANCE;
    }

    /**
     * Returns the current URI.<p>
     * 
     * @return the current URI
     */
    public static String getCurrentUri() {

        return CmsCoreProvider.get().getUri();

    }

    /**
     * Returns the server id for a given client element id.<p>
     * 
     * @param clientId the client id including an optional element settings hash
     * 
     * @return the server id
     */
    public static String getServerId(String clientId) {

        String serverId = clientId;
        if (clientId.contains(CLIENT_ID_SEPERATOR)) {
            serverId = clientId.substring(0, clientId.indexOf(CLIENT_ID_SEPERATOR));
        }
        return serverId;
    }

    /**
     * Adds an element specified by it's id to the favorite list.<p>
     * 
     * @param clientId the element id
     */
    public void addToFavoriteList(final String clientId) {

        CmsRpcAction<Void> action = new CmsRpcAction<Void>() {

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
             */
            @Override
            public void execute() {

                getContainerpageService().addToFavoriteList(clientId, this);
            }

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
             */
            @Override
            protected void onResponse(Void result) {

                CmsNotification.get().send(Type.NORMAL,
                        Messages.get().key(Messages.GUI_NOTIFICATION_ADD_TO_FAVORITES_0));
            }
        };
        action.execute();
    }

    /**
     * Adds an element specified by it's id to the recent list.<p>
     * 
     * @param clientId the element id
     */
    public void addToRecentList(final String clientId) {

        CmsRpcAction<Void> action = new CmsRpcAction<Void>() {

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
             */
            @Override
            public void execute() {

                getContainerpageService().addToRecentList(clientId, this);
            }

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
             */
            @Override
            protected void onResponse(Void result) {

                // nothing to do
            }
        };
        action.execute();
    }

    /**
     * Creates a new resource for crag container elements with the status new and opens the content editor.<p>
     * 
     * @param element the container element
     */
    public void createAndEditNewElement(
            final org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element) {

        if (!element.isNew()) {
            return;
        }
        m_handler.showPageOverlay();
        CmsRpcAction<CmsCreateElementData> action = new CmsRpcAction<CmsCreateElementData>() {

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
             */
            @Override
            public void execute() {

                getContainerpageService().checkCreateNewElement(CmsCoreProvider.get().getStructureId(),
                        element.getId(), element.getNewType(), getLocale(), this);

            }

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
             */
            @Override
            protected void onResponse(CmsCreateElementData result) {

                if (result.needsModelSelection()) {
                    getHandler().openModelResourceSelect(element, result.getModelResources());
                } else {
                    openEditorForNewElement(element, result.getCreatedElement());
                }
            }
        };
        action.execute();
    }

    /**
     * Creates a new resource for crag container elements with the status new and opens the content editor.<p>
     * 
     * @param element the container element
     * @param modelResourceStructureId the model resource structure id
     */
    public void createAndEditNewElement(
            final org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element,
            final CmsUUID modelResourceStructureId) {

        CmsRpcAction<CmsContainerElement> action = new CmsRpcAction<CmsContainerElement>() {

            @Override
            public void execute() {

                getContainerpageService().createNewElement(CmsCoreProvider.get().getStructureId(), element.getId(),
                        element.getNewType(), modelResourceStructureId, getLocale(), this);

            }

            @Override
            protected void onResponse(CmsContainerElement result) {

                openEditorForNewElement(element, result);

            }
        };
        action.execute();
    }

    /**
     * Deletes an element from the VFS, removes it from all containers and the client side cache.<p>
     * 
     * @param elementId the element to delete
     * @param relatedElementId related element to reload after the element has been deleted
     */
    public void deleteElement(String elementId, final String relatedElementId) {

        elementId = getServerId(elementId);
        removeContainerElements(elementId);
        addToRecentList(elementId);
        reloadElements(new String[] { relatedElementId });
    }

    /**
     * Enables the favorites editing drag and drop controller.<p>
     * 
     * @param enable if <code>true</code> favorites editing will enabled, otherwise disabled
     * @param dndController the favorites editing drag and drop controller
     */
    public void enableFavoriteEditing(boolean enable, I_CmsDNDController dndController) {

        if (m_dndHandler.isDragging()) {
            // never switch drag and drop controllers while dragging
            return;
        }
        if (enable) {
            m_dndHandler.setController(dndController);
        } else {
            m_dndHandler.setController(m_cntDndController);
        }

    }

    /**
     * Returns all drag elements of the page.<p>
     * 
     * @return the drag elements
     */
    public List<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> getAllDragElements() {

        List<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> result = new ArrayList<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel>();
        Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> it = m_targetContainers.values()
                .iterator();
        while (it.hasNext()) {
            result.addAll(it.next().getAllDragElements());
        }
        if (isGroupcontainerEditing()) {
            Iterator<Widget> itSub = m_editingGroupcontainer.iterator();
            while (itSub.hasNext()) {
                Widget w = itSub.next();
                if (w instanceof org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) {
                    result.add((org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) w);
                }
            }
        }
        return result;
    }

    /**
     * Returns the data for the requested element, or <code>null</code> if the element has not been cached yet.<p>
     * 
     * @param clientId the element id
     * 
     * @return the element data
     */
    public CmsContainerElementData getCachedElement(String clientId) {

        if (m_elements.containsKey(clientId)) {
            return m_elements.get(clientId);
        }
        return null;
    }

    /**
     * Returns the data for the requested element, or <code>null</code> if the element has not been cached yet.<p>
     * 
     * @param resourceTypeName the element resource type
     * 
     * @return the element data
     */
    public CmsContainerElementData getCachedNewElement(String resourceTypeName) {

        if (m_newElements.containsKey(resourceTypeName)) {
            return m_newElements.get(resourceTypeName);
        }
        return null;
    }

    /**
     * Returns the container data of container with the given name.
     * 
     * @param containerName the container name
     * 
     * @return the container data
     */
    public CmsContainerJso getContainer(String containerName) {

        return m_containers.get(containerName);
    }

    /**
     * Returns the {@link org.opencms.ade.containerpage.client.CmsContainerpageUtil}.<p>
     *
     * @return the containerpage-util
     */
    public CmsContainerpageUtil getContainerpageUtil() {

        return m_containerpageUtil;
    }

    /**
     * Returns the containers.<p>
     *
     * @return the containers
     */
    public Map<String, CmsContainerJso> getContainers() {

        return m_containers;
    }

    /**
     * Returns the container drag target by name (HTML id attribute).<p>
     * 
     * @param containerName the container name
     * @return the drag target
     */
    public org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer getContainerTarget(
            String containerName) {

        return m_targetContainers.get(containerName);
    }

    /**
     * Returns a map of the container drag targets.<p>
     * 
     * @return the drag targets
     */
    public Map<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> getContainerTargets() {

        return m_targetContainers;
    }

    /**
     * Returns the type of container with the given name.<p>
     * 
     * @param containerName the container name
     * 
     * @return the container type
     */
    public String getContainerType(String containerName) {

        return getContainer(containerName).getType();
    }

    /**
     * Returns the XML content editor handler.<p>
     *
     * @return the XML content editor handler
     */
    public CmsContentEditorHandler getContentEditorHandler() {

        return m_contentEditorHandler;
    }

    /**
     * Returns the prefetched data.<p>
     *
     * @return the prefetched data
     */
    public CmsCntPageData getData() {

        return m_data;
    }

    /**
     * Returns the drag and drop handler.<p>
     *
     * @return the drag and drop handler
     */
    public CmsDNDHandler getDndHandler() {

        return m_dndHandler;
    }

    /**
     * Requests the data for a container element specified by the client id. The data will be provided to the given call-back function.<p>
     * 
     * @param clientId the element id
     * @param callback the call-back to execute with the requested data
     */
    public void getElement(final String clientId, final I_CmsSimpleCallback<CmsContainerElementData> callback) {

        SingleElementAction action = new SingleElementAction(clientId, callback);
        action.execute();
    }

    /**
     * Requests the data for container elements specified by the client id. The data will be provided to the given call-back function.<p>
     * 
     * @param clientIds the element id's
     * @param callback the call-back to execute with the requested data
     */
    public void getElements(Set<String> clientIds,
            I_CmsSimpleCallback<Map<String, CmsContainerElementData>> callback) {

        MultiElementAction action = new MultiElementAction(clientIds, callback);
        action.execute();
    }

    /**
     * Returns the group-container element being edited.<p>
     * 
     * @return the group-container
     */
    public CmsGroupContainerElementPanel getGroupcontainer() {

        return m_editingGroupcontainer;
    }

    /**
     * Returns the id of the currently edited group-container.<p>
     * 
     * @return the group-container id, or <code>null</code> if no editing is taking place
     */
    public String getGroupcontainerId() {

        if (m_editingGroupcontainer != null) {
            return m_editingGroupcontainer.getContainerId();
        }
        return null;
    }

    /**
     * Returns the container-page handler.<p>
     *
     * @return the container-page handler
     */
    public CmsContainerpageHandler getHandler() {

        return m_handler;
    }

    /** 
     * Gets the lock error message.<p>
     * 
     * @return the lock error message
     */
    public String getLockErrorMessage() {

        return m_lockErrorMessage;
    }

    /**
     * Returns the element data for a resource type representing a new element.<p>
     * 
     * @param resourceType the resource type name
     * @param callback the callback to execute with the new element data
     */
    public void getNewElement(final String resourceType,
            final I_CmsSimpleCallback<CmsContainerElementData> callback) {

        if (m_elements.containsKey(resourceType)) {
            Scheduler.get().scheduleDeferred(new ScheduledCommand() {

                /**
                 * @see com.google.gwt.user.client.Command#execute()
                 */
                public void execute() {

                    callback.execute(m_elements.get(resourceType));

                }
            });
        } else {
            CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() {

                @Override
                public void execute() {

                    getContainerpageService().getNewElementData(CmsCoreProvider.get().getStructureId(),

                            getRequestParams(), resourceType, m_containerBeans, getLocale(), this);
                }

                @Override
                protected void onResponse(CmsContainerElementData result) {

                    m_elements.put(result.getClientId(), result);
                    callback.execute(result);
                }
            };
            action.execute();
        }
    }

    /**
     * Produces the "return code", which is needed to return to the current page from the sitemap.<p>
     * 
     * @return the return code 
     */
    public String getReturnCode() {

        CmsUUID ownId = CmsCoreProvider.get().getStructureId();
        CmsUUID detailId = m_data.getDetailId();
        if (detailId != null) {
            return "" + ownId + ":" + detailId;
        } else {
            return "" + ownId;
        }
    }

    /**
     * Returns if the page has changed.<p>
     * 
     * @return <code>true</code> if the page has changed
     */
    public boolean hasPageChanged() {

        return m_pageChanged;
    }

    /**
     * Hides list collector direct edit buttons, if present.<p>
     */
    public void hideEditableListButtons() {

        for (org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer container : m_targetContainers
                .values()) {
            container.hideEditableListButtons();
        }
    }

    /**
     * Initializes the controller.<p>
     * 
     * @param handler the container-page handler
     * @param dndHandler the drag and drop handler
     * @param contentEditorHandler the XML content editor handler
     * @param containerpageUtil the container-page utility
     */
    public void init(CmsContainerpageHandler handler, CmsDNDHandler dndHandler,
            CmsContentEditorHandler contentEditorHandler, CmsContainerpageUtil containerpageUtil) {

        m_containerpageUtil = containerpageUtil;
        m_handler = handler;
        m_contentEditorHandler = contentEditorHandler;
        m_dndHandler = dndHandler;
        m_cntDndController = m_dndHandler.getController();

        m_elements = new HashMap<String, CmsContainerElementData>();
        m_newElements = new HashMap<String, CmsContainerElementData>();
        m_containerTypes = new HashSet<String>();
        m_containers = new HashMap<String, CmsContainerJso>();

        JsArray<CmsContainerJso> containers = CmsContainerJso.getContainers();
        for (int i = 0; i < containers.length(); i++) {
            CmsContainerJso container = containers.get(i);
            m_containerTypes.add(container.getType());
            m_containers.put(container.getName(), container);
        }
        m_containerBeans = createEmptyContainerBeans();
        // ensure any embedded flash players are set opaque so UI elements may be placed above them
        CmsDomUtil.fixFlashZindex(RootPanel.getBodyElement());
        m_targetContainers = m_containerpageUtil.consumeContainers(m_containers);
        for (CmsContainerPageContainer cont : m_targetContainers.values()) {
            Element elem = DOM.getElementById(cont.getContainerId());
            CmsContainerpageEditor.getZIndexManager().addContainer(cont.getContainerId(), elem);
        }
        resetEditableListButtons();
        Event.addNativePreviewHandler(new NativePreviewHandler() {

            public void onPreviewNativeEvent(NativePreviewEvent event) {

                previewNativeEvent(event);
            }
        });
        // adding on close handler
        Window.addWindowClosingHandler(new ClosingHandler() {

            /**
             * @see com.google.gwt.user.client.Window.ClosingHandler#onWindowClosing(com.google.gwt.user.client.Window.ClosingEvent)
             */
            public void onWindowClosing(ClosingEvent event) {

                deactivateOnClosing();
                if (hasPageChanged() && !isEditingDisabled()) {
                    boolean savePage = Window
                            .confirm(Messages.get().key(Messages.GUI_DIALOG_SAVE_BEFORE_LEAVING_0));
                    if (savePage) {
                        syncSaveContainerpage();
                    } else {
                        unlockContainerpage();
                    }
                }
            }
        });
    }

    /**
     * Checks if the page editing features should be disabled.<p>
     * 
     * @return true if the page editing features should be disabled 
     */
    public boolean isEditingDisabled() {

        return m_lockStatus == LockStatus.failed;
    }

    /**
     * Returns if a group-container is currently being edited.<p>
     * 
     * @return <code>true</code> if a group-container is being edited
     */
    public boolean isGroupcontainerEditing() {

        return m_editingGroupcontainer != null;
    }

    /**
     * Method to leave the page without saving.<p>
     * 
     * @param targetUri the new URI to call
     */
    public void leaveUnsaved(String targetUri) {

        setPageChanged(false, true);
        Window.Location.assign(targetUri);
    }

    /**
     * Loads the context menu entries.<p>
     * 
     * @param structureId the structure id of the resource to get the context menu entries for  
     * @param context the ade context (sitemap or containerpae)
     */
    public void loadContextMenu(final CmsUUID structureId, final AdeContext context) {

        /** The RPC menu action for the container page dialog. */
        CmsRpcAction<List<CmsContextMenuEntryBean>> menuAction = new CmsRpcAction<List<CmsContextMenuEntryBean>>() {

            /**
            * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
            */
            @Override
            public void execute() {

                getCoreService().getContextMenuEntries(structureId, context, this);
            }

            /**
            * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
            */
            @Override
            public void onResponse(List<CmsContextMenuEntryBean> menuBeans) {

                m_handler.insertContextMenu(menuBeans, structureId);
            }
        };
        menuAction.execute();

    }

    /**
     * Loads the favorite list and adds the elements to the favorite list widget of the tool-bar menu.<p>
     * 
     * @param callback the call-back to execute with the result data 
     */
    public void loadFavorites(final I_CmsSimpleCallback<List<CmsContainerElementData>> callback) {

        CmsRpcAction<List<CmsContainerElementData>> action = new CmsRpcAction<List<CmsContainerElementData>>() {

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
             */
            @Override
            public void execute() {

                start(200, true);
                getContainerpageService().getFavoriteList(CmsCoreProvider.get().getStructureId(), m_containerBeans,
                        getLocale(), this);
            }

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
             */
            @Override
            protected void onResponse(List<CmsContainerElementData> result) {

                stop(false);
                addElements(result);
                callback.execute(result);
            }
        };
        action.execute();
    }

    /**
     * Loads the recent list and adds the elements to the recent list widget of the tool-bar menu.<p>
     * 
     * @param callback the call-back to execute with the result data
     */
    public void loadRecent(final I_CmsSimpleCallback<List<CmsContainerElementData>> callback) {

        CmsRpcAction<List<CmsContainerElementData>> action = new CmsRpcAction<List<CmsContainerElementData>>() {

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
             */
            @Override
            public void execute() {

                start(200, true);
                getContainerpageService().getRecentList(CmsCoreProvider.get().getStructureId(), m_containerBeans,
                        getLocale(), this);
            }

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
             */
            @Override
            protected void onResponse(List<CmsContainerElementData> result) {

                stop(false);
                addElements(result);
                callback.execute(result);
            }
        };
        action.execute();
    }

    /**
     * Locks the container-page.<p>
     * 
     * @return <code>true</code> if page was locked successfully 
     */
    public boolean lockContainerpage() {

        if (m_lockStatus == LockStatus.locked) {
            return true;
        }
        if (m_lockStatus == LockStatus.failed) {
            return false;
        }
        CmsLockInfo lockInfo = CmsCoreProvider.get()
                .lockTempAndCheckModification(CmsCoreProvider.get().getStructureId(), m_data.getDateLastModified());
        if (lockInfo.couldLock()) {
            onLockSuccess(lockInfo);
            return true;
        } else {
            onLockFail(lockInfo);
            return false;
        }
    }

    /**
     * This method should be called when locking the page has failed.<p>
     * 
     * @param lockInfo the locking information  
     */
    public void onLockFail(CmsLockInfo lockInfo) {

        m_lockStatus = LockStatus.failed;
        m_handler.onLockFail(lockInfo);
    }

    /**
     * This method should be called when locking the page has succeeded.<p>
     * 
     * @param lockInfo the locking information 
     */
    public void onLockSuccess(CmsLockInfo lockInfo) {

        assert m_lockStatus == LockStatus.unknown;
        m_lockStatus = LockStatus.locked;
    }

    /**
     * Reloads the content for the given element and all related elements.<p>
     * 
     * Call this if the element content has changed.<p>
     * 
     * @param ids the element id's
     */
    public void reloadElements(String[] ids) {

        Set<String> related = new HashSet<String>();
        for (int i = 0; i < ids.length; i++) {
            related.addAll(getRelatedElementIds(ids[i]));
        }
        ReloadElementAction action = new ReloadElementAction(related);
        action.execute();
    }

    /**
     * Reloads a container page element with a new set of settings.<p>
     * 
     * @param elementWidget the widget of the container page element which should be reloaded
     * @param clientId the id of the container page element which should be reloaded
     * @param settings the new set of settings 
     */
    public void reloadElementWithSettings(
            final org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel elementWidget,
            String clientId, Map<String, String> settings) {

        I_CmsSimpleCallback<CmsContainerElementData> callback = new I_CmsSimpleCallback<CmsContainerElementData>() {

            public void execute(CmsContainerElementData newElement) {

                try {
                    replaceContainerElement(elementWidget, newElement);
                    if (!isGroupcontainerEditing()) {
                        setPageChanged(true, false);
                    }
                    resetEditableListButtons();
                    addToRecentList(newElement.getClientId());
                } catch (Exception e) {
                    // should never happen
                    CmsDebugLog.getInstance().printLine(e.getLocalizedMessage());
                }
            }
        };
        getElementWithSettings(clientId, settings, callback);
    }

    /**
     * Removes the given container element from its parent container.<p>
     * 
     * @param dragElement the element to remove
     */
    public void removeElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel dragElement) {

        dragElement.removeFromParent();
        if (isGroupcontainerEditing()) {
            if (!getGroupcontainer().iterator().hasNext()) {
                // group-container is empty, mark it
                getGroupcontainer()
                        .addStyleName(I_CmsLayoutBundle.INSTANCE.containerpageCss().emptyGroupContainer());
            }
        } else {
            // only set changed if not editing a group container
            String id = dragElement.getId();
            if (id != null) {
                addToRecentList(id);
            }
            setPageChanged();
        }
    }

    /**
     * Replaces the given drag-element with the given container element.<p>
     * 
     * @param containerElement the container element to replace
     * @param elementData the new element data
     * 
     * @throws Exception if something goes wrong
     */
    public void replaceContainerElement(
            org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel containerElement,
            CmsContainerElementData elementData) throws Exception {

        I_CmsDropContainer parentContainer = containerElement.getParentTarget();
        String containerId = parentContainer.getContainerId();

        String elementContent = elementData.getContents().get(containerId);
        if ((elementContent != null) && (elementContent.trim().length() > 0)) {
            org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel replacer = getContainerpageUtil()
                    .createElement(elementData, parentContainer);
            if (containerElement.isNew()) {
                // if replacing element data has the same structure id, keep the 'new' state by setting the new type property
                // this should only be the case when editing settings of a new element that has not been created in the VFS yet
                String id = getServerId(containerElement.getId());
                if (elementData.getClientId().startsWith(id)) {
                    replacer.setNewType(containerElement.getNewType());
                }
            }
            parentContainer.insert(replacer, parentContainer.getWidgetIndex(containerElement));
            containerElement.removeFromParent();
        }
    }

    /**
     * Shows list collector direct edit buttons (old direct edit style), if present.<p>
     */
    public void resetEditableListButtons() {

        for (org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer container : m_targetContainers
                .values()) {
            container.showEditableListButtons();
        }
    }

    /**
     * Resets the container-page.<p>
     */
    public void resetPage() {

        setPageChanged(false, true);
        Window.Location.reload();
    }

    /**
     * Method to save and leave the page.<p>
     * 
     * @param leaveCommand the command to execute to leave the page
     */
    public void saveAndLeave(final Command leaveCommand) {

        if (hasPageChanged()) {
            CmsRpcAction<Void> action = new CmsRpcAction<Void>() {

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
                 */
                @Override
                public void execute() {

                    getContainerpageService().saveContainerpage(CmsCoreProvider.get().getStructureId(),
                            getPageContent(), getLocale(), this);
                }

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
                 */
                @Override
                protected void onResponse(Void result) {

                    CmsNotification.get().send(Type.NORMAL,
                            Messages.get().key(Messages.GUI_NOTIFICATION_PAGE_SAVED_0));
                    setPageChanged(false, true);
                    leaveCommand.execute();
                }
            };
            action.execute();
        }
    }

    /**
     * Method to save and leave the page.<p>
     * 
     * @param targetUri the new URI to call
     */
    public void saveAndLeave(final String targetUri) {

        if (hasPageChanged()) {
            CmsRpcAction<Void> action = new CmsRpcAction<Void>() {

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
                 */
                @Override
                public void execute() {

                    getContainerpageService().saveContainerpage(CmsCoreProvider.get().getStructureId(),
                            getPageContent(), getLocale(), this);
                }

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
                 */
                @Override
                protected void onResponse(Void result) {

                    CmsNotification.get().send(Type.NORMAL,
                            Messages.get().key(Messages.GUI_NOTIFICATION_PAGE_SAVED_0));
                    setPageChanged(false, true);
                    Window.Location.assign(targetUri);
                }
            };
            action.execute();
        }
    }

    /**
     * Saves the current state of the container-page.<p>
     */
    public void saveContainerpage() {

        if (hasPageChanged()) {
            CmsRpcAction<Void> action = new CmsRpcAction<Void>() {

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
                 */
                @Override
                public void execute() {

                    setLoadingMessage(org.opencms.gwt.client.Messages.get()
                            .key(org.opencms.gwt.client.Messages.GUI_SAVING_0));
                    start(0, true);
                    getContainerpageService().saveContainerpage(CmsCoreProvider.get().getStructureId(),
                            getPageContent(), getLocale(), this);
                }

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
                 */
                @Override
                protected void onResponse(Void result) {

                    stop(true);
                    setPageChanged(false, false);
                    Window.Location.reload();
                }
            };
            action.execute();
        }
    }

    /**
     * Saves the favorite list.<p>
     * 
     * @param clientIds the client id's of the list's elements
     */
    public void saveFavoriteList(final List<String> clientIds) {

        CmsRpcAction<Void> action = new CmsRpcAction<Void>() {

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
             */
            @Override
            public void execute() {

                getContainerpageService().saveFavoriteList(clientIds, this);
            }

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
             */
            @Override
            protected void onResponse(Void result) {

                CmsNotification.get().send(Type.NORMAL,
                        Messages.get().key(Messages.GUI_NOTIFICATION_FAVORITES_SAVED_0));
            }
        };
        action.execute();
    }

    /**
     * Saves the group-container.<p>
     * 
     * @param groupContainer the group-container data to save 
     * @param groupContainerElement the group-container widget
     */
    public void saveGroupcontainer(final CmsGroupContainer groupContainer,
            final CmsGroupContainerElementPanel groupContainerElement) {

        if (getGroupcontainer() != null) {
            CmsRpcAction<Map<String, CmsContainerElementData>> action = new CmsRpcAction<Map<String, CmsContainerElementData>>() {

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
                 */
                @Override
                public void execute() {

                    getContainerpageService().saveGroupContainer(CmsCoreProvider.get().getStructureId(),
                            getRequestParams(), groupContainer, m_containerBeans, getLocale(), this);
                }

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
                 */
                @Override
                protected void onResponse(Map<String, CmsContainerElementData> result) {

                    m_elements.putAll(result);
                    try {
                        replaceContainerElement(groupContainerElement, result.get(groupContainerElement.getId()));
                    } catch (Exception e) {
                        CmsDebugLog.getInstance().printLine("Error replacing group container element");
                    }
                    addToRecentList(groupContainerElement.getId());
                    CmsNotification.get().send(Type.NORMAL,
                            Messages.get().key(Messages.GUI_NOTIFICATION_GROUP_CONTAINER_SAVED_0));
                }
            };
            action.execute();

        }
    }

    /**
     * Sets the page changed flag to <code>true</code>.<p>
     */
    public void setPageChanged() {

        if (!hasPageChanged()) {
            setPageChanged(true, false);
        }
    }

    /**
     * Writes the tool-bar visibility into the session cache.<p>
     * 
     * @param visible <code>true</code> if the tool-bar is visible
     */
    public void setToolbarVisible(final boolean visible) {

        CmsRpcAction<Void> action = new CmsRpcAction<Void>() {

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
             */
            @Override
            public void execute() {

                getCoreService().setToolbarVisible(visible, this);
            }

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
             */
            @Override
            protected void onResponse(Void result) {

                //nothing to do
            }
        };
        action.execute();
        if (visible) {
            resetEditableListButtons();
        }
    }

    /**
     * Tells the controller that group-container editing has started.<p>
     * 
     * @param groupContainer the group-container
     * 
     * @return <code>true</code> if group-container resource was locked and can be edited
     */
    public boolean startEditingGroupcontainer(CmsGroupContainerElementPanel groupContainer) {

        if (groupContainer.isNew() || CmsCoreProvider.get().lock(groupContainer.getStructureId())) {
            m_editingGroupcontainer = groupContainer;
            return true;
        }
        CmsNotification.get().send(Type.WARNING, Messages.get().key(Messages.GUI_NOTIFICATION_UNABLE_TO_LOCK_0));
        return false;
    }

    /**
     * Tells the controller that group-container editing has stopped.<p>
     */
    public void stopEditingGroupcontainer() {

        m_editingGroupcontainer = null;
    }

    /** 
     * Adds the given element data to the element cache.<p>
     * 
     * @param elements the element data
     */
    protected void addElements(List<CmsContainerElementData> elements) {

        for (CmsContainerElementData element : elements) {
            m_elements.put(element.getClientId(), element);
        }
    }

    /** 
     * Adds the given element data to the element cache.<p>
     * 
     * @param elements the element data
     */
    protected void addElements(Map<String, CmsContainerElementData> elements) {

        m_elements.putAll(elements);
    }

    /**
     * Disables option and toolbar buttons.<p>
     */
    protected void deactivateOnClosing() {

        m_handler.deactivateCurrentButton();
        m_handler.deactivateToolbarButtons();
    }

    /**
     * Returns the container-page RPC service.<p>
     * 
     * @return the container-page service
     */
    protected I_CmsContainerpageServiceAsync getContainerpageService() {

        if (m_containerpageService == null) {
            m_containerpageService = GWT.create(I_CmsContainerpageService.class);
            String serviceUrl = CmsCoreProvider.get()
                    .link("org.opencms.ade.containerpage.CmsContainerpageService.gwt");
            ((ServiceDefTarget) m_containerpageService).setServiceEntryPoint(serviceUrl);
        }
        return m_containerpageService;
    }

    /**
     * Returns the core RPC service.<p>
     * 
     * @return the core service
     */
    protected I_CmsCoreServiceAsync getCoreService() {

        if (m_coreSvc == null) {
            m_coreSvc = CmsCoreProvider.getService();
        }
        return m_coreSvc;
    }

    /**
     * Returns the content locale.<p>
     * 
     * @return the content locale
     */
    protected String getLocale() {

        return m_data.getLocale();
    }

    /**
     * Returns the current containers and their elements.<p>
     * 
     * @return the list of containers
     */
    protected List<CmsContainer> getPageContent() {

        List<CmsContainer> containers = new ArrayList<CmsContainer>();
        for (Entry<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> entry : m_targetContainers
                .entrySet()) {

            CmsContainerJso cnt = m_containers.get(entry.getKey());
            // only consider containers that are not marked as detail view
            if (!cnt.isDetailView()) {
                List<CmsContainerElement> elements = new ArrayList<CmsContainerElement>();
                Iterator<Widget> elIt = entry.getValue().iterator();
                while (elIt.hasNext()) {
                    try {
                        CmsContainerPageElementPanel elementWidget = (CmsContainerPageElementPanel) elIt.next();
                        CmsContainerElement element = new CmsContainerElement();
                        element.setClientId(elementWidget.getId());
                        element.setResourceType(elementWidget.getNewType());
                        element.setNew(elementWidget.isNew());
                        element.setSitePath(elementWidget.getSitePath());
                        elements.add(element);
                    } catch (ClassCastException e) {
                        // no proper container element, skip it (this should never happen!)
                        CmsDebugLog.getInstance()
                                .printLine("WARNING: there is an inappropriate element within a container");
                    }
                }
                containers.add(new CmsContainer(entry.getKey(), cnt.getType(), cnt.getWidth(), cnt.getMaxElements(),
                        elements));
            }

        }
        return containers;
    }

    /**
     * Returns the request parameters of the displayed container-page.<p>
     * 
     * @return the request parameters
     */
    protected String getRequestParams() {

        return m_data.getRequestParams();
    }

    /**
     * Opens the editor for the newly created element.<p>
     * 
     * @param element the container element
     * @param newElementData the new element data
     */
    protected void openEditorForNewElement(
            org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element,
            CmsContainerElement newElementData) {

        element.setNewType(null);
        element.setId(newElementData.getClientId());
        element.setSitePath(newElementData.getSitePath());
        setPageChanged();
        getHandler().hidePageOverlay();
        getHandler().openEditorForElement(element);
    }

    /**
    * Previews events. Shows the leaving page dialog, if the page has changed and an anchor has been clicked.<p>
    * 
    * @param event the native event
    */
    protected void previewNativeEvent(NativePreviewEvent event) {

        Event nativeEvent = Event.as(event.getNativeEvent());
        if (!hasPageChanged()) {
            return;
        }
        if ((nativeEvent.getTypeInt() == Event.ONCLICK)) {
            EventTarget target = nativeEvent.getEventTarget();
            if (!Element.is(target)) {
                return;
            }
            Element element = Element.as(target);
            element = CmsDomUtil.getAncestor(element, CmsDomUtil.Tag.a);
            if (element == null) {
                return;
            }
            AnchorElement anc = AnchorElement.as(element);
            final String uri = anc.getHref();

            // avoid to abort events for date-picker widgets
            if (CmsStringUtil.isEmptyOrWhitespaceOnly(uri)
                    || (CmsDomUtil.getAncestor(element, "x-date-picker") != null)) {
                return;
            }
            nativeEvent.preventDefault();
            nativeEvent.stopPropagation();
            m_handler.leavePage(uri);
        }
        if ((event.getTypeInt() == Event.ONKEYDOWN) && (nativeEvent.getKeyCode() == 116)) {
            // user pressed F5
            nativeEvent.preventDefault();
            nativeEvent.stopPropagation();
            m_handler.leavePage(Window.Location.getHref());
        }
    }

    /**
     * Removes all container elements with the given id from all containers and the client side cache.<p>
     * 
     * @param resourceId the resource id
     */
    protected void removeContainerElements(String resourceId) {

        Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> it = getAllDragElements()
                .iterator();
        while (it.hasNext()) {
            org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel containerElement = it.next();
            if (resourceId.startsWith(containerElement.getId())) {
                containerElement.removeFromParent();
                setPageChanged();
            }
        }
        for (String elementId : m_elements.keySet()) {
            if (elementId.startsWith(resourceId)) {
                m_elements.remove(elementId);
            }
        }
    }

    /**
     * Sets the page changed flag and initializes the window closing handler if necessary.<p>
     * 
     * @param changed if <code>true</code> the page has changed
     * @param unlock if <code>true</code> the page will be unlocked for unchanged pages
     */
    protected void setPageChanged(boolean changed, boolean unlock) {

        if (changed) {
            if (!m_pageChanged) {

                m_pageChanged = changed;
                if (lockContainerpage()) {
                    m_handler.enableSaveReset(!isEditingDisabled());
                }
            }
        } else {
            m_pageChanged = changed;
            m_handler.enableSaveReset(false);
            if (unlock) {
                unlockContainerpage();
            }
        }
    }

    /**
     * Saves the container-page in a synchronized RPC call.<p>
     */
    protected void syncSaveContainerpage() {

        if (hasPageChanged()) {
            CmsRpcAction<Void> action = new CmsRpcAction<Void>() {

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
                 */
                @Override
                public void execute() {

                    getContainerpageService().syncSaveContainerpage(CmsCoreProvider.get().getStructureId(),
                            getPageContent(), getLocale(), this);
                }

                /**
                 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
                 */
                @Override
                protected void onResponse(Void result) {

                    CmsNotification.get().send(Type.NORMAL,
                            Messages.get().key(Messages.GUI_NOTIFICATION_PAGE_SAVED_0));
                    setPageChanged(false, false);
                }
            };
            action.execute();
        }
    }

    /**
     * Unlocks the container-page in a synchronized RPC call.<p>
     */
    protected void unlockContainerpage() {

        if (CmsCoreProvider.get().unlock(CmsCoreProvider.get().getStructureId())) {
            CmsDebugLog.getInstance().printLine(Messages.get().key(Messages.GUI_NOTIFICATION_PAGE_UNLOCKED_0));
        } else {
            // ignore
        }
    }

    /**
     * Creates beans for each of this page's containers and ignore their contents.<p>
     * 
     * @return a list of container beans without contents 
     */
    private List<CmsContainer> createEmptyContainerBeans() {

        List<CmsContainer> result = new ArrayList<CmsContainer>();
        for (CmsContainerJso containerJso : m_containers.values()) {
            CmsContainer container = new CmsContainer(containerJso.getName(), containerJso.getType(),
                    containerJso.getWidth(), containerJso.getMaxElements(), null);
            result.add(container);
        }
        return result;
    }

    /**
     * Retrieves a container element with a given set of settings.<p>
     * 
     * @param clientId the id of the container element
     * @param settings the set of settings
     *  
     * @param callback the callback which should be executed when the element has been loaded 
     */
    private void getElementWithSettings(final String clientId, final Map<String, String> settings,
            final I_CmsSimpleCallback<CmsContainerElementData> callback) {

        CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() {

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
             */
            @Override
            public void execute() {

                start(200, false);
                getContainerpageService().getElementWithSettings(CmsCoreProvider.get().getStructureId(),
                        getRequestParams(), clientId, settings, m_containerBeans, getLocale(), this);

            }

            /**
             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
             */
            @Override
            protected void onResponse(CmsContainerElementData result) {

                stop(false);
                if (result != null) {
                    // cache the loaded element
                    m_elements.put(result.getClientId(), result);
                }
                callback.execute(result);
            }

        };
        action.execute();
    }

    /**
     * Returns all element id's related to the given one.<p>
     * 
     * @param id the element id
     * @return the related id's
     */
    private Set<String> getRelatedElementIds(String id) {

        Set<String> result = new HashSet<String>();
        result.add(id);
        String serverId = getServerId(id);

        Iterator<String> it = m_elements.keySet().iterator();
        while (it.hasNext()) {
            String elId = it.next();
            if (elId.startsWith(serverId)) {
                result.add(elId);
            }
        }

        Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> itEl = getAllDragElements()
                .iterator();
        while (itEl.hasNext()) {
            org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element = itEl.next();
            if (element.getId().startsWith(serverId)) {
                result.add(element.getId());
            }
        }
        return result;
    }
}