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.CmsContainerpageController.ElementRemoveMode;
031import org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer;
032import org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel;
033import org.opencms.ade.containerpage.client.ui.CmsElementSettingsDialog;
034import org.opencms.ade.containerpage.client.ui.CmsElementSettingsDialog.NoFormatterException;
035import org.opencms.ade.containerpage.client.ui.CmsGroupContainerElementPanel;
036import org.opencms.ade.containerpage.client.ui.CmsListAddDialog;
037import org.opencms.ade.containerpage.client.ui.CmsSmallElementsHandler;
038import org.opencms.ade.containerpage.client.ui.I_CmsDropContainer;
039import org.opencms.ade.containerpage.shared.CmsContainerElement;
040import org.opencms.ade.containerpage.shared.CmsContainerElementData;
041import org.opencms.ade.containerpage.shared.CmsElementSettingsConfig;
042import org.opencms.ade.containerpage.shared.CmsElementViewInfo;
043import org.opencms.ade.containerpage.shared.CmsLocaleLinkBean;
044import org.opencms.ade.publish.client.CmsPublishDialog;
045import org.opencms.ade.publish.shared.CmsPublishOptions;
046import org.opencms.ade.upload.client.I_CmsUploadContext;
047import org.opencms.ade.upload.client.lists.CmsUploadPopup;
048import org.opencms.gwt.client.CmsCoreProvider;
049import org.opencms.gwt.client.I_CmsEditableData;
050import org.opencms.gwt.client.dnd.I_CmsDNDController;
051import org.opencms.gwt.client.rpc.CmsRpcAction;
052import org.opencms.gwt.client.ui.A_CmsToolbarHandler;
053import org.opencms.gwt.client.ui.A_CmsToolbarMenu;
054import org.opencms.gwt.client.ui.CmsAcceptDeclineCancelDialog;
055import org.opencms.gwt.client.ui.CmsAlertDialog;
056import org.opencms.gwt.client.ui.CmsConfirmDialog;
057import org.opencms.gwt.client.ui.CmsListItem;
058import org.opencms.gwt.client.ui.CmsLockReportDialog;
059import org.opencms.gwt.client.ui.CmsModelSelectDialog;
060import org.opencms.gwt.client.ui.CmsNotification;
061import org.opencms.gwt.client.ui.CmsNotification.Type;
062import org.opencms.gwt.client.ui.I_CmsAcceptDeclineCancelHandler;
063import org.opencms.gwt.client.ui.I_CmsConfirmDialogHandler;
064import org.opencms.gwt.client.ui.I_CmsModelSelectHandler;
065import org.opencms.gwt.client.ui.I_CmsToolbarButton;
066import org.opencms.gwt.client.ui.contenteditor.I_CmsContentEditorHandler;
067import org.opencms.gwt.client.ui.contextmenu.A_CmsContextMenuItem;
068import org.opencms.gwt.client.ui.contextmenu.CmsContextMenuEntry;
069import org.opencms.gwt.client.ui.contextmenu.CmsPreview;
070import org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuCommand;
071import org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuEntry;
072import org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuHandler;
073import org.opencms.gwt.client.ui.css.I_CmsInputCss;
074import org.opencms.gwt.client.ui.css.I_CmsInputLayoutBundle;
075import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
076import org.opencms.gwt.client.ui.input.CmsSelectBox;
077import org.opencms.gwt.client.ui.resourceinfo.CmsResourceInfoDialog;
078import org.opencms.gwt.client.util.CmsDomUtil;
079import org.opencms.gwt.client.util.CmsStyleVariable;
080import org.opencms.gwt.client.util.I_CmsSimpleCallback;
081import org.opencms.gwt.shared.CmsClientVariantInfo;
082import org.opencms.gwt.shared.CmsContextMenuEntryBean;
083import org.opencms.gwt.shared.CmsCoreData;
084import org.opencms.gwt.shared.CmsCoreData.AdeContext;
085import org.opencms.gwt.shared.CmsGwtConstants;
086import org.opencms.gwt.shared.CmsListElementCreationDialogData;
087import org.opencms.gwt.shared.CmsListElementCreationOption;
088import org.opencms.gwt.shared.CmsLockInfo;
089import org.opencms.gwt.shared.CmsModelResourceInfo;
090import org.opencms.gwt.shared.CmsTemplateContextInfo;
091import org.opencms.gwt.shared.I_CmsEditableDataExtensions;
092import org.opencms.util.CmsStringUtil;
093import org.opencms.util.CmsUUID;
094
095import java.util.ArrayList;
096import java.util.Arrays;
097import java.util.Date;
098import java.util.HashMap;
099import java.util.Iterator;
100import java.util.List;
101import java.util.Map;
102
103import com.google.common.base.Objects;
104import com.google.common.collect.Lists;
105import com.google.common.collect.Maps;
106import com.google.gwt.dom.client.Style;
107import com.google.gwt.dom.client.Style.Position;
108import com.google.gwt.dom.client.Style.Unit;
109import com.google.gwt.event.logical.shared.CloseEvent;
110import com.google.gwt.event.logical.shared.CloseHandler;
111import com.google.gwt.event.logical.shared.ValueChangeEvent;
112import com.google.gwt.event.logical.shared.ValueChangeHandler;
113import com.google.gwt.http.client.UrlBuilder;
114import com.google.gwt.user.client.Command;
115import com.google.gwt.user.client.Cookies;
116import com.google.gwt.user.client.Window;
117import com.google.gwt.user.client.rpc.AsyncCallback;
118import com.google.gwt.user.client.ui.PopupPanel;
119import com.google.gwt.user.client.ui.RootPanel;
120import com.google.gwt.user.client.ui.SimplePanel;
121
122/**
123 * The container-page handler.<p>
124 *
125 * @since 8.0.0
126 */
127public class CmsContainerpageHandler extends A_CmsToolbarHandler {
128
129    /**
130     * Action which is executed when the user selects a client variant.<p>
131     */
132    class ClientVariantSelectAction implements Runnable {
133
134        /** The template context name. */
135        private String m_context;
136
137        /** The variant bean. */
138        private CmsClientVariantInfo m_variant;
139
140        /**
141         * Creates a new instance.<p>
142         *
143         * @param context the context name
144         * @param variant the variant information
145         */
146        public ClientVariantSelectAction(String context, CmsClientVariantInfo variant) {
147
148            m_context = context;
149            m_variant = variant;
150        }
151
152        /**
153         * @see java.lang.Runnable#run()
154         */
155        public void run() {
156
157            deactivateCurrentButton();
158            m_clientVariantDisplay.show(m_context, m_variant);
159        }
160    }
161
162    /**
163     * Action which does nothing.<p>
164     */
165    public static final Runnable DO_NOTHING = new Runnable() {
166
167        /**
168         * @see java.lang.Runnable#run()
169         */
170        public void run() {
171
172            // do nothing
173
174        }
175
176    };
177
178    /** The container-page controller. */
179    protected CmsContainerpageController m_controller;
180
181    /** The container-page editor. */
182    protected CmsContainerpageEditor m_editor;
183
184    /** The widget used for displaying the client variants. */
185    CmsClientVariantDisplay m_clientVariantDisplay = new CmsClientVariantDisplay(this);
186
187    /** The currently active tool-bar button. */
188    private I_CmsToolbarButton m_activeButton;
189
190    /** The edit button visibility style variable. */
191    private CmsStyleVariable m_editButtonVibility;
192
193    /** Overlay to prevent user actions while shown. */
194    private SimplePanel m_overlay;
195
196    /** Field to store the 'prefill' context menu entry that gets manually moved to a different location later by the context menu code. */
197    private CmsContextMenuEntryBean m_prefill;
198
199    /**
200     * Constructor.<p>
201     *
202     * @param controller the container-page controller
203     * @param editor the container-page editor
204     */
205    public CmsContainerpageHandler(CmsContainerpageController controller, CmsContainerpageEditor editor) {
206
207        m_controller = controller;
208        m_editor = editor;
209        m_editButtonVibility = new CmsStyleVariable(RootPanel.get());
210    }
211
212    /**
213     * Activates the selection button.<p>
214     */
215    public void activateSelection() {
216
217        m_editor.getSelection().setActive(true);
218        setEditButtonsVisible(true);
219        reInitInlineEditing();
220    }
221
222    /**
223     * Adds the given list item widget to the favorite list widget.<p>
224     *
225     * @param listItem the list item
226     */
227    public void addToFavorites(CmsListItem listItem) {
228
229        m_editor.getClipboard().addToFavorites(listItem);
230    }
231
232    /**
233     * Adds the element with the given id to the favorite list.<p>
234     *
235     * @param clientId the client id
236     */
237    public void addToFavorites(String clientId) {
238
239        m_controller.addToFavoriteList(clientId);
240    }
241
242    /**
243     * Adds the given list item widget to the recent list widget.<p>
244     *
245     * @param listItem the list item
246     */
247    public void addToRecent(CmsListItem listItem) {
248
249        m_editor.getClipboard().addToRecent(listItem);
250    }
251
252    /**
253     * Adds the element with the given id to the favorite list.<p>
254     *
255     * @param clientId the client id
256     */
257    public void addToRecent(String clientId) {
258
259        m_controller.addToRecentList(clientId, null);
260    }
261
262    /**
263     * Switches the template context.<p>
264     *
265     * @param cookieName the cookie name
266     * @param value the new template context
267     */
268    @SuppressWarnings("deprecation")
269    public void changeTemplateContextManually(final String cookieName, final String value) {
270
271        if (value != null) {
272            Cookies.setCookie(cookieName, value, new Date(300, 0, 1), null, "/", false);
273        } else {
274            Cookies.removeCookie(cookieName, "/");
275        }
276        Window.Location.reload();
277    }
278
279    /**
280     * Checks whether GWT widgets are available for all fields of a content.<p>
281     *
282     * @param structureId the structure id of the content
283     *
284     * @param asyncCallback the callback for the result
285     */
286    public void checkNewWidgetsAvailable(CmsUUID structureId, AsyncCallback<Boolean> asyncCallback) {
287
288        m_controller.checkNewWidgetsAvailable(structureId, asyncCallback);
289    }
290
291    /**
292     * Creates a context menu entry.<p>
293     *
294     * @param structureId structure id of the resource
295     * @param name the label
296     * @param checked true if checkbox should be displayed
297     * @param action the action to execute
298     *
299     * @return the menu entry
300     */
301    public CmsContextMenuEntry createSimpleContextMenuEntry(
302        CmsUUID structureId,
303        String name,
304        boolean checked,
305        final Runnable action) {
306
307        CmsContextMenuEntry entry = createRawMenuEntry(structureId, action);
308        decorateMenuEntry(entry, name, checked);
309        return entry;
310    }
311
312    /**
313     * Creates a select box used to switch between views from the gallery dialog.<p>
314     *
315     * @return the created select box
316     */
317    public CmsSelectBox createViewSelectorForGalleryDialog() {
318
319        List<CmsElementViewInfo> elementViews = m_controller.getData().getElementViews();
320        if (elementViews.size() <= 1) {
321            return null;
322        }
323        CmsUUID currentView = m_controller.getElementView().getElementViewId();
324        Map<String, String> options = Maps.newHashMap();
325        for (CmsElementViewInfo view : elementViews) {
326            options.put("" + view.getElementViewId(), view.getTitle());
327        }
328        CmsSelectBox result = new CmsSelectBox(options);
329        result.setFormValueAsString(currentView.toString());
330        result.addValueChangeHandler(new ValueChangeHandler<String>() {
331
332            public void onValueChange(ValueChangeEvent<String> event) {
333
334                m_editor.getAdd().setActive(false);
335                CmsElementViewInfo newValue = m_controller.getView(event.getValue());
336                setElementView(newValue, new Runnable() {
337
338                    public void run() {
339
340                        m_editor.getAdd().setActive(true);
341                    }
342                });
343            }
344        });
345        result.getElement().getStyle().setWidth(250, Unit.PX);
346
347        return result;
348    }
349
350    /**
351     * De-activates the current button.<p>
352     */
353    public void deactivateCurrentButton() {
354
355        if (m_activeButton != null) {
356            if (m_activeButton == m_editor.getSelection()) {
357                m_controller.disableInlineEditing(null);
358            }
359            m_activeButton.setActive(false);
360            m_activeButton = null;
361        }
362        setEditButtonsVisible(false);
363    }
364
365    /**
366     * De-activates menu button.<p>
367     */
368    public void deactivateMenuButton() {
369
370        if ((m_activeButton != null) && (m_activeButton instanceof A_CmsToolbarMenu<?>)) {
371            ((A_CmsToolbarMenu<?>)m_activeButton).setActive(false);
372        }
373    }
374
375    /**
376     * Deactivates the selection.<p>
377     */
378    public void deactivateSelection() {
379
380        m_editor.getSelection().setActive(false);
381    }
382
383    /**
384     * Deactivates all toolbar buttons.<p>
385     */
386    public void disableToolbarButtons() {
387
388        m_editor.disableToolbarButtons();
389    }
390
391    /**
392     * Starts the property editor for the given container element.<p>
393     *
394     * @param elementWidget the container element widget for which the properties should be edited
395     */
396    public void editElementSettings(final CmsContainerPageElementPanel elementWidget) {
397
398        m_controller.getElementSettingsConfig(
399            elementWidget.getId(),
400            elementWidget.getParentTarget().getContainerId(),
401            new I_CmsSimpleCallback<CmsElementSettingsConfig>() {
402
403                public void execute(final CmsElementSettingsConfig settingsConfig) {
404
405                    CmsContainerElementData elementBean = settingsConfig.getElementData();
406
407                    if (!elementBean.getClientId().equals(elementWidget.getId())) {
408                        // the client id may have changed, update the element widget
409                        elementWidget.setId(elementBean.getClientId());
410                    }
411                    Map<String, String> settingPresets = getSettingPresets(elementWidget);
412                    try {
413                        CmsElementSettingsDialog dialog = new CmsElementSettingsDialog(
414                            m_controller,
415                            elementWidget,
416                            settingsConfig,
417                            settingPresets);
418                        dialog.show();
419                    } catch (NoFormatterException e) {
420                        String ctype = "???";
421                        String cname = "???";
422                        String schema = "???";
423                        if (settingsConfig.getSchema() != null) {
424                            schema = settingsConfig.getSchema();
425                        }
426                        try {
427                            I_CmsDropContainer dropContainer = elementWidget.getParentTarget();
428                            if (dropContainer instanceof CmsContainerPageContainer) {
429                                CmsContainerPageContainer cpc = (CmsContainerPageContainer)dropContainer;
430                                ctype = cpc.getContainerType();
431                                cname = cpc.getContainerId();
432                            }
433                        } catch (Exception e2) {
434                            /*ignore*/
435                        }
436                        String path = "???";
437                        try {
438                            path = elementBean.getSitePath();
439                        } catch (Exception e2) {
440                            /*ignore*/
441                        }
442                        CmsAlertDialog alert = new CmsAlertDialog(
443                            org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_ERROR_0),
444                            Messages.get().key(Messages.GUI_NO_FORMATTER_4, path, cname, ctype, schema));
445                        alert.center();
446                    }
447                }
448
449                /**
450                 * Gets the map of setting presets.<p>
451                 *
452                 * @param elementWidget2 the element widget
453                 * @return the setting presets
454                 */
455                private Map<String, String> getSettingPresets(CmsContainerPageElementPanel elementWidget2) {
456
457                    I_CmsDropContainer dropContainer = elementWidget2.getParentTarget();
458                    if (dropContainer instanceof CmsContainerPageContainer) {
459                        CmsContainerPageContainer container = (CmsContainerPageContainer)dropContainer;
460                        return container.getSettingPresets();
461                    } else {
462                        return new HashMap<String, String>();
463                    }
464                }
465            });
466    }
467
468    /**
469     * Enables the favorites editing drag and drop controller.<p>
470     *
471     * @param enable if <code>true</code> favorites editing will enabled, otherwise disabled
472     * @param dndController the favorites editing drag and drop controller
473     */
474    public void enableFavoriteEditing(boolean enable, I_CmsDNDController dndController) {
475
476        m_controller.enableFavoriteEditing(enable, dndController);
477    }
478
479    /**
480     * Enables the toolbar buttons.<p>
481     */
482    public void enableToolbarButtons() {
483
484        m_editor.enableToolbarButtons(m_controller.hasPageChanged(), m_controller.getData().getNoEditReason());
485    }
486
487    /**
488     * @see org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuHandler#ensureLockOnResource(org.opencms.util.CmsUUID, org.opencms.gwt.client.util.I_CmsSimpleCallback)
489     */
490    public void ensureLockOnResource(CmsUUID structureId, I_CmsSimpleCallback<Boolean> callback) {
491
492        m_controller.lockContainerpage(callback);
493    }
494
495    /**
496     * @see org.opencms.gwt.client.ui.I_CmsToolbarHandler#getActiveButton()
497     */
498    public I_CmsToolbarButton getActiveButton() {
499
500        return m_activeButton;
501    }
502
503    /**
504     * @see org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuHandler#getContextMenuCommands()
505     */
506    public Map<String, I_CmsContextMenuCommand> getContextMenuCommands() {
507
508        return m_editor.getContextMenuCommands();
509    }
510
511    /**
512     * @see org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuHandler#getContextType()
513     */
514    public String getContextType() {
515
516        return CmsGwtConstants.CONTEXT_TYPE_CONTAINERPAGE_TOOLBAR;
517    }
518
519    /**
520     * @see org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuHandler#getEditorHandler()
521     */
522    public I_CmsContentEditorHandler getEditorHandler() {
523
524        return m_controller.getContentEditorHandler();
525    }
526
527    /**
528     * Leaves the current page and opens the site-map.<p>
529     */
530    public void gotoSitemap() {
531
532        final String sitemapUri = CmsCoreProvider.get().link(m_controller.getData().getSitemapUri());
533        if (sitemapUri.equals("")) {
534            return; // normally, we shouldn't even get to this point because the sitemap button should be disabled
535        }
536        Command leaveCommand = new Command() {
537
538            public void execute() {
539
540                Window.Location.replace(
541                    sitemapUri
542                        + "?"
543                        + CmsCoreData.PARAM_PATH
544                        + "="
545                        + CmsContainerpageController.getCurrentUri()
546                        + "&"
547                        + CmsCoreData.PARAM_RETURNCODE
548                        + "="
549                        + m_controller.getReturnCode());
550            }
551
552        };
553        leavePage(leaveCommand);
554    }
555
556    /**
557     * Returns if the selection button is active.<p>
558     *
559     * @return <code>true</code> if the selection button is active
560     */
561    public boolean hasActiveSelection() {
562
563        return m_editor.getSelection().isActive();
564    }
565
566    /**
567     * Hides any open menu.<p>
568     */
569    public void hideMenu() {
570
571        if ((m_activeButton != null) && (m_activeButton instanceof A_CmsToolbarMenu<?>)) {
572            ((A_CmsToolbarMenu<?>)m_activeButton).hideMenu();
573        }
574    }
575
576    /**
577     * Removes page overlay if present.<p>
578     */
579    public void hidePageOverlay() {
580
581        if (m_overlay != null) {
582            m_overlay.removeFromParent();
583        }
584    }
585
586    /**
587     * Inserts the context menu.<p>
588     *
589     * @param menuBeans the menu beans from the server
590     * @param structureId the structure id of the resource for which the context menu entries should be generated
591     */
592    public void insertContextMenu(List<CmsContextMenuEntryBean> menuBeans, CmsUUID structureId) {
593
594        List<I_CmsContextMenuEntry> menuEntries = transformEntries(menuBeans, structureId);
595        m_editor.getContext().showMenu(menuEntries);
596    }
597
598    /**
599     * Call to leave the page. Will open save/leave/cancel dialog if page contains any changes.<p>
600     *
601     * @param leavingCommand the page leaving command
602     */
603    public void leavePage(final Command leavingCommand) {
604
605        if (!m_controller.hasPageChanged() || m_controller.isEditingDisabled()) {
606            leavingCommand.execute();
607            return;
608        }
609        CmsAcceptDeclineCancelDialog leavingDialog = getLeaveDialog();
610        leavingDialog.setHandler(new I_CmsAcceptDeclineCancelHandler() {
611
612            /**
613             * @see org.opencms.gwt.client.ui.I_CmsAcceptDeclineCancelHandler#onAccept()
614             */
615            public void onAccept() {
616
617                m_controller.saveAndLeave(leavingCommand);
618            }
619
620            /**
621             * @see org.opencms.gwt.client.ui.I_CmsCloseDialogHandler#onClose()
622             */
623            public void onClose() {
624
625                deactivateCurrentButton();
626                activateSelection();
627            }
628
629            /**
630             * @see org.opencms.gwt.client.ui.I_CmsAcceptDeclineCancelHandler#onDecline()
631             */
632            public void onDecline() {
633
634                m_controller.setPageChanged(false, true);
635                leavingCommand.execute();
636            }
637        });
638        leavingDialog.center();
639    }
640
641    /**
642     * Call to leave the page. Will open save/leave/cancel dialog if page contains any changes.<p>
643     *
644     * @param target the target
645     */
646    public void leavePage(final String target) {
647
648        if (!m_controller.hasPageChanged() || m_controller.isEditingDisabled()) {
649            m_controller.leaveUnsaved(target);
650            return;
651        }
652        CmsAcceptDeclineCancelDialog leavingDialog = getLeaveDialog();
653        leavingDialog.setHandler(new I_CmsAcceptDeclineCancelHandler() {
654
655            /**
656             * @see org.opencms.gwt.client.ui.I_CmsAcceptDeclineCancelHandler#onAccept()
657             */
658            public void onAccept() {
659
660                m_controller.saveAndLeave(target);
661            }
662
663            /**
664             * @see org.opencms.gwt.client.ui.I_CmsCloseDialogHandler#onClose()
665             */
666            public void onClose() {
667
668                deactivateCurrentButton();
669                activateSelection();
670            }
671
672            /**
673             * @see org.opencms.gwt.client.ui.I_CmsAcceptDeclineCancelHandler#onDecline()
674             */
675            public void onDecline() {
676
677                m_controller.leaveUnsaved(target);
678            }
679        });
680        leavingDialog.center();
681    }
682
683    /**
684     * Loads the context menu entries for a given URI.<p>
685     *
686     * @param structureId the structure id of the resource for which the context menu should be loaded
687     * @param context the ade context (sitemap or containerpage)
688     */
689    public void loadContextMenu(CmsUUID structureId, final AdeContext context) {
690
691        m_controller.loadContextMenu(structureId, context);
692    }
693
694    /**
695     * Loads the favorite list from the server and adds it's items to the clip-board.<p>
696     */
697    public void loadFavorites() {
698
699        m_controller.loadFavorites(new I_CmsSimpleCallback<List<CmsContainerElementData>>() {
700
701            /**
702             * Generating the list item widgets and inserting them into the favorite list.<p>
703             *
704             * @param arg the element data
705             */
706            public void execute(List<CmsContainerElementData> arg) {
707
708                m_editor.getClipboard().clearFavorites();
709                Iterator<CmsContainerElementData> it = arg.iterator();
710                while (it.hasNext()) {
711                    addToFavorites(m_controller.getContainerpageUtil().createListItem(it.next()));
712                }
713                m_editor.getClipboard().updateSize();
714            }
715        });
716    }
717
718    /**
719     * Loads the recent list from the server and adds it's items to the clip-board.<p>
720     */
721    public void loadRecent() {
722
723        m_controller.loadRecent(new I_CmsSimpleCallback<List<CmsContainerElementData>>() {
724
725            /**
726             * Generating the list item widgets and inserting them into the recent list.<p>
727             *
728             * @param arg the element data
729             */
730            public void execute(List<CmsContainerElementData> arg) {
731
732                m_editor.getClipboard().clearRecent();
733                Iterator<CmsContainerElementData> it = arg.iterator();
734                while (it.hasNext()) {
735                    addToRecent(m_controller.getContainerpageUtil().createListItem(it.next()));
736                }
737                m_editor.getClipboard().updateSize();
738            }
739        });
740    }
741
742    /**
743     * Should be called when locking the container page failed.<p>
744     *
745     * @param errorMessage the locking information
746     */
747    public void onLockFail(String errorMessage) {
748
749        m_editor.disableEditing(errorMessage);
750        CmsAlertDialog alert = new CmsAlertDialog(
751            Messages.get().key(Messages.ERR_LOCK_TITLE_RESOURCE_LOCKED_0),
752            errorMessage);
753        alert.addCloseHandler(new CloseHandler<PopupPanel>() {
754
755            public void onClose(CloseEvent<PopupPanel> event) {
756
757                m_controller.reloadPage();
758            }
759        });
760
761        alert.center();
762    }
763
764    /**
765     * @see org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuHandler#onSiteOrProjectChange(java.lang.String, java.lang.String)
766     */
767    public void onSiteOrProjectChange(String sitePath, String serverLink) {
768
769        leavePage(serverLink);
770    }
771
772    /**
773     * Opens the edit dialog for the specified element.<p>
774     *
775     * @param element the element to edit
776     * @param inline <code>true</code> to open the inline editor for the given element if available
777     * @param wasNew <code>true</code> in case this is a newly created element not previously edited
778     */
779    public void openEditorForElement(final CmsContainerPageElementPanel element, boolean inline, boolean wasNew) {
780
781        if (element.isNew()) {
782            //openEditorForElement will be called again asynchronously when the RPC for creating the element has finished
783            m_controller.createAndEditNewElement(element, inline);
784            return;
785        }
786
787        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(element.getNoEditReason())) {
788            CmsNotification.get().send(
789                CmsNotification.Type.WARNING,
790                "should be deactivated: " + element.getNoEditReason());
791            return;
792        }
793
794        if (CmsDomUtil.hasClass(CmsContainerElement.CLASS_GROUP_CONTAINER_ELEMENT_MARKER, element.getElement())) {
795            openGroupEditor((CmsGroupContainerElementPanel)element);
796        } else {
797            m_controller.setContentEditing(true);
798            m_controller.disableInlineEditing(element);
799            m_controller.getContentEditorHandler().openDialog(element, inline, wasNew);
800            element.removeHighlighting();
801        }
802    }
803
804    /**
805     * Triggers creation/editing of a new content after an option has been selected.
806     *
807     * @param option the type option selected by the user
808     * @param reloadId the id of the element to be reloaded after editing
809     * @param postCreateHandler the post-create handler  (for assigning categories or similar)
810     */
811    public void openEditorForNewListContent(
812        CmsListElementCreationOption option,
813        String reloadId,
814        String postCreateHandler) {
815
816        I_CmsEditableData editableData = new I_CmsEditableData() {
817
818            public String getContextId() {
819
820                return null;
821            }
822
823            public String getEditId() {
824
825                return null;
826            }
827
828            public String getElementId() {
829
830                return null;
831            }
832
833            public String getElementLanguage() {
834
835                return null;
836            }
837
838            public String getElementName() {
839
840                return null;
841            }
842
843            public I_CmsEditableDataExtensions getExtensions() {
844
845                return null;
846            }
847
848            public String getNewLink() {
849
850                return option.getNewLink();
851            }
852
853            public String getNewTitle() {
854
855                return null;
856            }
857
858            public String getNoEditReason() {
859
860                return null;
861            }
862
863            public String getPostCreateHandler() {
864
865                return postCreateHandler;
866            }
867
868            public String getSitePath() {
869
870                return null;
871            }
872
873            public CmsUUID getStructureId() {
874
875                return CmsCoreProvider.get().getStructureId();
876            }
877
878            public boolean hasEditHandler() {
879
880                return false;
881            }
882
883            public boolean hasResource() {
884
885                return false;
886            }
887
888            public boolean isUnreleasedOrExpired() {
889
890                return false;
891            }
892
893            public void setSitePath(String sitePath) {
894
895                // no-op
896
897            }
898        };
899
900        CmsContainerpageController.get().getContentEditorHandler().openDialog(
901            editableData,
902            true/*isNew*/,
903            reloadId /*dependingElementId*/,
904            null /*mode*/,
905            null /*handlerData*/);
906    }
907
908    /**
909     * Opens the elements info dialog.<p>
910     */
911    public void openElementsInfo() {
912
913        CmsResourceInfoDialog.load(
914            CmsCoreProvider.get().getStructureId(),
915            true,
916            CmsContainerpageController.get().getData().getDetailId(),
917            new HashMap<String, String>(),
918            new CloseHandler<PopupPanel>() {
919
920                public void onClose(CloseEvent<PopupPanel> event) {
921
922                    deactivateCurrentButton();
923                    activateSelection();
924                }
925
926            });
927    }
928
929    /**
930     * Opens the dialog for adding a new list content.
931     *
932     * @param structureId the structure id of the container element
933     * @param listAddMetadata the list-add metadata read from the container element
934     */
935    public void openListAddDialog(CmsUUID structureId, String listAddMetadata) {
936
937        CmsRpcAction<CmsListElementCreationDialogData> action = new CmsRpcAction<CmsListElementCreationDialogData>() {
938
939            @Override
940            public void execute() {
941
942                start(0, false);
943                CmsContainerpageHandler.this.m_controller.getContainerpageService().getListElementCreationOptions(
944                    structureId,
945                    listAddMetadata,
946                    this);
947
948            }
949
950            @Override
951            protected void onResponse(CmsListElementCreationDialogData result) {
952
953                stop(false);
954                final CmsUploadPopup[] popupArray = {null};
955                if (result.isUpload()) {
956                    I_CmsUploadContext context = new I_CmsUploadContext() {
957
958                        public void onUploadFinished(List<String> uploadedFiles) {
959
960                            popupArray[0].hide();
961                            CmsContainerpageController.get().reloadElements(
962                                Arrays.asList("" + structureId),
963                                DO_NOTHING);
964                        }
965                    };
966                    CmsUploadPopup popup = new CmsUploadPopup(
967                        result.getUploadFolder(),
968                        result.getPostCreateHandler(),
969                        context,
970                        result.getListInfo());
971                    popupArray[0] = popup;
972                    popup.center();
973                } else if (result.getOptions().size() == 1) {
974                    // skip the selection dialog, immediately create and edit the content
975                    openEditorForNewListContent(
976                        result.getOptions().get(0),
977                        "" + structureId,
978                        result.getPostCreateHandler());
979                } else {
980                    // "0 options" case is handled by the dialog
981                    CmsListAddDialog dialog = new CmsListAddDialog(
982                        structureId,
983                        result,
984                        option -> openEditorForNewListContent(option, "" + structureId, result.getPostCreateHandler()));
985                    dialog.center();
986                }
987            }
988        };
989        action.execute();
990
991    }
992
993    /**
994     * Opens the lock report for the given element.<p>
995     *
996     * @param element the element
997     */
998    public void openLockReportForElement(final CmsContainerPageElementPanel element) {
999
1000        CmsLockReportDialog.openDialogForResource(null, element.getStructureId(), new Command() {
1001
1002            public void execute() {
1003
1004                m_controller.reloadElements(
1005                    new String[] {element.getStructureId().toString()},
1006                    () -> { /*do nothing*/});
1007            }
1008        }, null);
1009    }
1010
1011    /**
1012     * Opens the model select dialog for the given new element.<p>
1013     *
1014     * @param element the element widget
1015     * @param modelResources the available resource models
1016     */
1017    public void openModelResourceSelect(
1018        final CmsContainerPageElementPanel element,
1019        List<CmsModelResourceInfo> modelResources) {
1020
1021        I_CmsModelSelectHandler handler = new I_CmsModelSelectHandler() {
1022
1023            public void onModelSelect(CmsUUID modelStructureId) {
1024
1025                m_controller.createAndEditNewElement(element, modelStructureId);
1026            }
1027        };
1028        String title = org.opencms.gwt.client.Messages.get().key(
1029            org.opencms.gwt.client.Messages.GUI_MODEL_SELECT_TITLE_0);
1030        String message = org.opencms.gwt.client.Messages.get().key(
1031            org.opencms.gwt.client.Messages.GUI_MODEL_SELECT_MESSAGE_0);
1032        CmsModelSelectDialog dialog = new CmsModelSelectDialog(handler, modelResources, title, message);
1033        dialog.center();
1034    }
1035
1036    /**
1037     * @see org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuHandler#refreshResource(org.opencms.util.CmsUUID)
1038     */
1039    public void refreshResource(CmsUUID structureId) {
1040
1041        if (!m_controller.hasPageChanged()) {
1042            m_controller.resetPage();
1043            return;
1044        }
1045        StringBuffer message = new StringBuffer();
1046        message.append("<p>" + Messages.get().key(Messages.GUI_DIALOG_RELOAD_TEXT_0) + "</p>");
1047        message.append("<p>" + Messages.get().key(Messages.GUI_DIALOG_SAVE_QUESTION_0) + "</p>");
1048        CmsConfirmDialog dialog = new CmsConfirmDialog(
1049            Messages.get().key(Messages.GUI_DIALOG_RELOAD_TITLE_0),
1050            message.toString());
1051        dialog.setOkText(Messages.get().key(Messages.GUI_BUTTON_SAVE_TEXT_0));
1052        dialog.setHandler(new I_CmsConfirmDialogHandler() {
1053
1054            public void onClose() {
1055
1056                // do nothing
1057            }
1058
1059            public void onOk() {
1060
1061                m_controller.saveContainerpage();
1062            }
1063        });
1064        dialog.center();
1065
1066    }
1067
1068    /**
1069     * Re-initializes the inline editing.<p>
1070     */
1071    public void reInitInlineEditing() {
1072
1073        m_controller.reInitInlineEditing();
1074    }
1075
1076    /**
1077     * Reloads the content for the given element and all related elements.<p>
1078     *
1079     * @param elementIds the element id's
1080     * @param callback the callback to execute after reloading
1081     */
1082    public void reloadElements(String[] elementIds, Runnable callback) {
1083
1084        m_controller.reloadElements(elementIds, callback);
1085    }
1086
1087    /**
1088     * Removes the given container-page element.<p>
1089     *
1090     * @param element the element
1091     *
1092     */
1093    public void removeElement(CmsContainerPageElementPanel element) {
1094
1095        m_controller.removeElement(element);
1096    }
1097
1098    /**
1099     * Removes the given container-page element.<p>
1100     *
1101     * @param element the element
1102     * @param removeMode the element remove mode
1103     *
1104     */
1105    public void removeElement(CmsContainerPageElementPanel element, ElementRemoveMode removeMode) {
1106
1107        m_controller.removeElement(element, removeMode);
1108    }
1109
1110    /**
1111     * Replaces the given element with another content while keeping it's settings.<p>
1112     *
1113     * @param element the element to replace
1114     * @param elementId the id of the replacing content
1115     * @param callback the callback to execute after replacing the element
1116     */
1117    public void replaceElement(CmsContainerPageElementPanel element, String elementId, Runnable callback) {
1118
1119        m_controller.replaceElement(element, elementId, callback);
1120    }
1121
1122    /**
1123     * Shows list collector direct edit buttons (old direct edit style), if present.<p>
1124     */
1125    public void resetEditableListButtons() {
1126
1127        m_controller.resetEditButtons();
1128    }
1129
1130    /**
1131     * Resets the container-page to it's previous state.<p>
1132     */
1133    public void resetPage() {
1134
1135        CmsConfirmDialog dialog = new CmsConfirmDialog(
1136            Messages.get().key(Messages.GUI_DIALOG_RESET_TITLE_0),
1137            "<p>" + Messages.get().key(Messages.GUI_DIALOG_PAGE_RESET_0) + "</p>");
1138        dialog.setCloseText(Messages.get().key(Messages.GUI_BUTTON_CANCEL_TEXT_0));
1139        dialog.setOkText(Messages.get().key(Messages.GUI_BUTTON_DISCARD_TEXT_0));
1140        dialog.setHandler(new I_CmsConfirmDialogHandler() {
1141
1142            /**
1143             * @see org.opencms.gwt.client.ui.I_CmsCloseDialogHandler#onClose()
1144             */
1145            public void onClose() {
1146
1147                deactivateCurrentButton();
1148                activateSelection();
1149            }
1150
1151            /**
1152             * @see org.opencms.gwt.client.ui.I_CmsConfirmDialogHandler#onOk()
1153             */
1154            public void onOk() {
1155
1156                m_controller.resetPage();
1157            }
1158        });
1159        dialog.center();
1160    }
1161
1162    /**
1163     * Saves the favorite list.<p>
1164     *
1165     * @param clientIds the client id's of the list's elements
1166     *
1167     * @see org.opencms.ade.containerpage.client.CmsContainerpageController#saveFavoriteList(java.util.List)
1168     */
1169    public void saveFavoriteList(List<String> clientIds) {
1170
1171        m_controller.saveFavoriteList(clientIds);
1172    }
1173
1174    /**
1175     * Saves the current state of the container-page.<p>
1176     */
1177    public void savePage() {
1178
1179        m_controller.saveContainerpage();
1180
1181        deactivateCurrentButton();
1182        activateSelection();
1183    }
1184
1185    /**
1186     * Sets the currently active tool-bar button.<p>
1187     *
1188     * @param button the button
1189     */
1190    public void setActiveButton(I_CmsToolbarButton button) {
1191
1192        m_activeButton = button;
1193        setEditButtonsVisible((button == null) || m_editor.getSelection().equals(button));
1194    }
1195
1196    /**
1197     * Sets the edit button visible.<p>
1198     *
1199     * @param visible the visibility
1200     */
1201    public void setEditButtonsVisible(boolean visible) {
1202
1203        if (visible) {
1204            m_editButtonVibility.setValue(
1205                org.opencms.ade.containerpage.client.ui.css.I_CmsLayoutBundle.INSTANCE.containerpageCss().editButtonsVisible());
1206        } else {
1207            m_editButtonVibility.setValue(
1208                org.opencms.ade.containerpage.client.ui.css.I_CmsLayoutBundle.INSTANCE.containerpageCss().editButtonsInvisible());
1209        }
1210    }
1211
1212    /**
1213     * Shows resource information for a given element.<p>
1214     *
1215     * @param element the element for which to show the information
1216     */
1217    public void showElementInfo(final CmsContainerPageElementPanel element) {
1218
1219        CmsUUID structureId;
1220        if (element.isModelGroup() && !element.getModelGroupId().isNullUUID()) {
1221            structureId = element.getModelGroupId();
1222        } else {
1223            structureId = element.getStructureId();
1224        }
1225        I_CmsDropContainer dropContainer = element.getParentTarget();
1226        Map<String, String> contextParams = new HashMap<>();
1227        if (dropContainer instanceof CmsContainerPageContainer) {
1228            CmsContainerPageContainer cnt = (CmsContainerPageContainer)dropContainer;
1229            String containerId = cnt.getContainerId();
1230            String elemId = element.getId();
1231            contextParams.put(CmsGwtConstants.ATTR_ELEMENT_ID, elemId);
1232            contextParams.put(CmsGwtConstants.ATTR_CONTAINER_ID, containerId);
1233            String pageRootPath = CmsStringUtil.joinPaths(
1234                CmsCoreProvider.get().getSiteRoot(),
1235                CmsCoreProvider.get().getUri());
1236            contextParams.put(CmsGwtConstants.ATTR_PAGE_ROOT_PATH, pageRootPath);
1237        }
1238        CmsResourceInfoDialog.load(structureId, true, null, contextParams, new CloseHandler<PopupPanel>() {
1239
1240            public void onClose(CloseEvent<PopupPanel> event) {
1241
1242                reloadElements(new String[] {element.getId()}, () -> {/*do nothing*/});
1243            }
1244        });
1245    }
1246
1247    /**
1248     * Shows a page overlay preventing user actions.<p>
1249     */
1250    public void showPageOverlay() {
1251
1252        if (m_overlay == null) {
1253            m_overlay = new SimplePanel();
1254            m_overlay.setStyleName(I_CmsLayoutBundle.INSTANCE.dialogCss().popupOverlay());
1255            Style style = m_overlay.getElement().getStyle();
1256            style.setWidth(100, Unit.PCT);
1257            style.setHeight(100, Unit.PCT);
1258            style.setPosition(Position.FIXED);
1259        }
1260        RootPanel.get().add(m_overlay);
1261    }
1262
1263    /**
1264     * Toggles the tool-bars visibility.<p>
1265     *
1266     * @param buttonLeft the selection button absolute left position, needed to show the leave preview button in the same location
1267     */
1268    public void showPreview(int buttonLeft) {
1269
1270        UrlBuilder location = Window.Location.createUrlBuilder();
1271        location.setParameter(CmsGwtConstants.PARAM_DISABLE_DIRECT_EDIT, Boolean.toString(true));
1272        location.setParameter(CmsGwtConstants.PARAM_BUTTON_LEFT, Integer.toString(buttonLeft));
1273        CmsUUID detailId = CmsContainerpageController.get().getData().getDetailId();
1274        if (detailId != null) {
1275            // current URL may no longer be valid because the field mapped to URL name may have been edited.
1276            CmsRpcAction<String> action = new CmsRpcAction<String>() {
1277
1278                @Override
1279                public void execute() {
1280
1281                    start(0, false);
1282                    CmsCoreProvider.getVfsService().getDetailName(detailId, CmsCoreProvider.get().getLocale(), this);
1283                }
1284
1285                @Override
1286                protected void onResponse(String name) {
1287
1288                    stop(false);
1289                    String path = Window.Location.getPath();
1290                    path = path.replaceFirst("/[^/]+(/?)$", "/" + name + "$1");
1291                    location.setPath(path);
1292                    Window.Location.assign(location.buildString());
1293                }
1294            };
1295            action.execute();
1296
1297        } else {
1298            Window.Location.assign(location.buildString());
1299        }
1300    }
1301
1302    /**
1303     * Shows the publish dialog.<p>
1304     */
1305    public void showPublishDialog() {
1306
1307        if (m_controller.hasPageChanged()) {
1308
1309            StringBuffer warningMessage = new StringBuffer();
1310            warningMessage.append("<p>" + Messages.get().key(Messages.GUI_DIALOG_PUBLISH_NOT_SAVED_0) + "</p>");
1311            warningMessage.append("<p>" + Messages.get().key(Messages.GUI_DIALOG_SAVE_QUESTION_0) + "</p>");
1312
1313            CmsAcceptDeclineCancelDialog leavingDialog = new CmsAcceptDeclineCancelDialog(
1314                Messages.get().key(Messages.GUI_DIALOG_NOT_SAVED_TITLE_0),
1315                warningMessage.toString());
1316            leavingDialog.setAcceptText(Messages.get().key(Messages.GUI_BUTTON_SAVE_TEXT_0));
1317            leavingDialog.setDeclineText(Messages.get().key(Messages.GUI_BUTTON_DISCARD_TEXT_0));
1318            leavingDialog.setCloseText(Messages.get().key(Messages.GUI_BUTTON_RETURN_TEXT_0));
1319
1320            leavingDialog.setHandler(new I_CmsAcceptDeclineCancelHandler() {
1321
1322                /**
1323                 * @see org.opencms.gwt.client.ui.I_CmsAcceptDeclineCancelHandler#onAccept()
1324                 */
1325                public void onAccept() {
1326
1327                    m_controller.saveContainerpage(new Runnable() {
1328
1329                        public void run() {
1330
1331                            openPublish();
1332                        }
1333                    });
1334                }
1335
1336                /**
1337                 * @see org.opencms.gwt.client.ui.I_CmsCloseDialogHandler#onClose()
1338                 */
1339                public void onClose() {
1340
1341                    deactivateCurrentButton();
1342                    activateSelection();
1343                }
1344
1345                /**
1346                 * @see org.opencms.gwt.client.ui.I_CmsAcceptDeclineCancelHandler#onDecline()
1347                 */
1348                public void onDecline() {
1349
1350                    openPublish();
1351                }
1352            });
1353            leavingDialog.center();
1354        } else {
1355            openPublish();
1356        }
1357    }
1358
1359    /**
1360     * @see org.opencms.gwt.client.ui.A_CmsToolbarHandler#transformSingleEntry(org.opencms.util.CmsUUID, org.opencms.gwt.shared.CmsContextMenuEntryBean)
1361     */
1362    @Override
1363    public I_CmsContextMenuEntry transformSingleEntry(CmsUUID structureId, CmsContextMenuEntryBean menuEntryBean) {
1364
1365        String name = menuEntryBean.getName();
1366        if (name == null) {
1367            return super.transformSingleEntry(structureId, menuEntryBean);
1368        }
1369        if (name.equals(CmsGwtConstants.TEMPLATECONTEXT_MENU_PLACEHOLDER)) {
1370            return createTemplateContextSelectionMenuEntry(structureId);
1371        } else if ((menuEntryBean.getParams() != null)
1372            && menuEntryBean.getParams().containsKey(CmsGwtConstants.PREFILL_MENU_PLACEHOLDER)) {
1373            // hack: this comes before the template contexts option in the context menu order, so we have it ready when we get there
1374            m_prefill = menuEntryBean;
1375            return null;
1376        } else if (name.equals(CmsGwtConstants.ACTION_EDITSMALLELEMENTS)) {
1377            return createToggleEditSmallElementsMenuEntry();
1378        } else if (name.equals(CmsGwtConstants.ACTION_SELECTELEMENTVIEW)) {
1379            return createElementViewSelectionMenuEntry();
1380        } else if (name.equals(CmsGwtConstants.ACTION_SHOWLOCALE)) {
1381            return createShowLocaleMenuEntry();
1382        } else if (name.equals(CmsGwtConstants.ACTION_VIEW_ONLINE)) {
1383            return createViewOnlineEntry();
1384        } else if (name.equals(CmsPreview.class.getName())) {
1385            return null;
1386        } else {
1387            return super.transformSingleEntry(structureId, menuEntryBean);
1388        }
1389    }
1390
1391    /**
1392     * @see org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuHandler#unlockResource(org.opencms.util.CmsUUID)
1393     */
1394    public void unlockResource(CmsUUID structureId) {
1395
1396        // only unlock the container page, if nothing has changed yet
1397        if (!m_controller.hasPageChanged()) {
1398            m_controller.unlockContainerpage();
1399        }
1400    }
1401
1402    /**
1403     * Updates the clip board elements is necessary.<p>
1404     *
1405     * @param elements the elements data
1406     */
1407    public void updateClipboard(Map<String, CmsContainerElementData> elements) {
1408
1409        if (m_editor.getClipboard().isOpen()) {
1410            for (CmsContainerElementData elementData : elements.values()) {
1411                m_editor.getClipboard().replaceFavoriteItem(
1412                    m_controller.getContainerpageUtil().createListItem(elementData));
1413                m_editor.getClipboard().replaceRecentItem(
1414                    m_controller.getContainerpageUtil().createListItem(elementData));
1415            }
1416        }
1417    }
1418
1419    /**
1420     * Creates the element view selection menu entry, returns <code>null</code> in case no other views available.<p>
1421     *
1422     * @return the menu entry
1423     */
1424    protected I_CmsContextMenuEntry createElementViewSelectionMenuEntry() {
1425
1426        List<CmsElementViewInfo> elementViews = m_controller.getData().getElementViews();
1427        if (elementViews.size() > 1) {
1428            CmsContextMenuEntry parentEntry = new CmsContextMenuEntry(this, null, new I_CmsContextMenuCommand() {
1429
1430                public void execute(
1431                    CmsUUID innerStructureId,
1432                    I_CmsContextMenuHandler handler,
1433                    CmsContextMenuEntryBean bean) {
1434
1435                    // do nothing
1436                }
1437
1438                public A_CmsContextMenuItem getItemWidget(
1439                    CmsUUID innerStructureId,
1440                    I_CmsContextMenuHandler handler,
1441                    CmsContextMenuEntryBean bean) {
1442
1443                    return null;
1444                }
1445
1446                public boolean hasItemWidget() {
1447
1448                    return false;
1449                }
1450
1451            });
1452            CmsContextMenuEntryBean parentBean = new CmsContextMenuEntryBean();
1453
1454            parentBean.setLabel(Messages.get().key(Messages.GUI_SELECT_ELEMENT_VIEW_0));
1455            parentBean.setActive(true);
1456            parentBean.setVisible(true);
1457            parentEntry.setBean(parentBean);
1458            List<I_CmsContextMenuEntry> viewEntries = new ArrayList<I_CmsContextMenuEntry>();
1459            for (CmsElementViewInfo viewInfo : elementViews) {
1460                if (viewInfo.isRoot()) {
1461                    viewEntries.add(
1462                        createMenuEntryForElementView(
1463                            viewInfo,
1464                            m_controller.matchRootView(viewInfo.getElementViewId()),
1465                            this));
1466                }
1467            }
1468
1469            parentEntry.setSubMenu(viewEntries);
1470            return parentEntry;
1471        } else {
1472            return null;
1473        }
1474    }
1475
1476    /**
1477     * Creates a menu entry based on a structure id and action without anything else.<p>
1478     *
1479     * @param structureId the structure id
1480     * @param action the action for the menu entry
1481     *
1482     * @return the new menu entry
1483     */
1484    protected CmsContextMenuEntry createRawMenuEntry(CmsUUID structureId, final Runnable action) {
1485
1486        CmsContextMenuEntry entry = new CmsContextMenuEntry(this, structureId, new I_CmsContextMenuCommand() {
1487
1488            public void execute(
1489                CmsUUID innerStructureId,
1490                I_CmsContextMenuHandler handler,
1491                CmsContextMenuEntryBean bean) {
1492
1493                if (action != null) {
1494                    action.run();
1495                }
1496            }
1497
1498            public A_CmsContextMenuItem getItemWidget(
1499                CmsUUID innerStructureId,
1500                I_CmsContextMenuHandler handler,
1501                CmsContextMenuEntryBean bean) {
1502
1503                return null;
1504            }
1505
1506            public boolean hasItemWidget() {
1507
1508                return false;
1509            }
1510
1511        });
1512        return entry;
1513    }
1514
1515    /**
1516     * Creates the template context selection entry for the context menu.<p>
1517     *
1518     * @param structureId the structure id of the page
1519     *
1520     * @return the new context menu entry
1521     */
1522    protected I_CmsContextMenuEntry createTemplateContextSelectionMenuEntry(CmsUUID structureId) {
1523
1524        final CmsTemplateContextInfo info = m_controller.getData().getTemplateContextInfo();
1525        if ((info.getCookieName() != null) && info.shouldShowTemplateContextContextMenuEntry()) {
1526            CmsContextMenuEntry parentEntry = new CmsContextMenuEntry(this, structureId, new I_CmsContextMenuCommand() {
1527
1528                public void execute(
1529                    CmsUUID innerStructureId,
1530                    I_CmsContextMenuHandler handler,
1531                    CmsContextMenuEntryBean bean) {
1532
1533                    // do nothing
1534                }
1535
1536                public A_CmsContextMenuItem getItemWidget(
1537                    CmsUUID innerStructureId,
1538                    I_CmsContextMenuHandler handler,
1539                    CmsContextMenuEntryBean bean) {
1540
1541                    return null;
1542                }
1543
1544                public boolean hasItemWidget() {
1545
1546                    return false;
1547                }
1548
1549            });
1550            CmsContextMenuEntryBean parentBean = new CmsContextMenuEntryBean();
1551
1552            String parentLabel = info.getMenuLabel();
1553            if (parentLabel == null) {
1554                parentLabel = org.opencms.gwt.client.Messages.get().key(
1555                    org.opencms.gwt.client.Messages.GUI_TEMPLATE_CONTEXT_PARENT_0);
1556            }
1557            parentBean.setLabel(parentLabel);
1558            parentBean.setActive(true);
1559            parentBean.setVisible(true);
1560            parentEntry.setBean(parentBean);
1561
1562            Map<String, String> contextNames = info.getContextLabels();
1563
1564            List<I_CmsContextMenuEntry> templateContextEntries = new ArrayList<I_CmsContextMenuEntry>();
1565            for (Map.Entry<String, String> entry : contextNames.entrySet()) {
1566                final String key = entry.getKey();
1567                final String label = entry.getValue();
1568                if (info.hasClientVariants(key)) {
1569                    CmsContextMenuEntry singleContextEntry = createRawMenuEntry(structureId, DO_NOTHING);
1570                    boolean showCheckbox = Objects.equal(info.getSelectedContext(), entry.getKey());
1571                    decorateMenuEntry(singleContextEntry, label, showCheckbox);
1572                    List<I_CmsContextMenuEntry> variantEntries = new ArrayList<I_CmsContextMenuEntry>();
1573                    CmsContextMenuEntry editVariantEntry = createMenuEntryForTemplateContext(
1574                        info.getCookieName(),
1575                        key,
1576                        org.opencms.ade.containerpage.client.Messages.get().key(
1577                            org.opencms.ade.containerpage.client.Messages.GUI_TEMPLATE_CONTEXT_NO_VARIANT_0),
1578                        false,
1579                        this,
1580                        structureId);
1581                    variantEntries.add(editVariantEntry);
1582                    Map<String, CmsClientVariantInfo> variants = info.getClientVariants(key);
1583                    for (CmsClientVariantInfo variant : variants.values()) {
1584                        CmsContextMenuEntry currentVariantEntry = createRawMenuEntry(
1585                            structureId,
1586                            new ClientVariantSelectAction(key, variant));
1587                        decorateMenuEntry(currentVariantEntry, variant.getNiceName(), false);
1588                        variantEntries.add(currentVariantEntry);
1589                    }
1590                    singleContextEntry.setSubMenu(variantEntries);
1591                    templateContextEntries.add(singleContextEntry);
1592
1593                } else {
1594
1595                    CmsContextMenuEntry menuEntry = createMenuEntryForTemplateContext(
1596                        info.getCookieName(),
1597                        key,
1598                        label,
1599                        Objects.equal(key, info.getSelectedContext()),
1600                        this,
1601                        structureId);
1602                    templateContextEntries.add(menuEntry);
1603                }
1604            }
1605            String autoLabel = org.opencms.gwt.client.Messages.get().key(
1606                org.opencms.gwt.client.Messages.GUI_TEMPLATE_CONTEXT_NONE_0);
1607            if (info.getDefaultLabel() != null) {
1608                autoLabel = info.getDefaultLabel();
1609            }
1610            templateContextEntries.add(
1611                createMenuEntryForTemplateContext(
1612                    info.getCookieName(),
1613                    null,
1614                    autoLabel,
1615                    Objects.equal(null, info.getSelectedContext()),
1616                    this,
1617                    structureId));
1618            if ((m_prefill != null) && (info.getSelectedContext() != null)) {
1619                String name = m_prefill.getName();
1620                I_CmsContextMenuCommand command = null;
1621                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(name)) {
1622                    command = getContextMenuCommands().get(name);
1623                }
1624                CmsContextMenuEntry entry = new CmsContextMenuEntry(this, structureId, command);
1625                entry.setBean(m_prefill);
1626                templateContextEntries.add(entry);
1627            }
1628            parentEntry.setSubMenu(templateContextEntries);
1629
1630            return parentEntry;
1631
1632        } else {
1633            return null;
1634        }
1635    }
1636
1637    /**
1638     * Creates the context menu entry for enabling or disabling editing of small elements.<p>
1639     *
1640     * @return the created context menu entry
1641     */
1642    protected I_CmsContextMenuEntry createToggleEditSmallElementsMenuEntry() {
1643
1644        final CmsSmallElementsHandler smallElementsHandler = m_controller.getSmallElementsHandler();
1645        final boolean isActive = smallElementsHandler.areSmallElementsEditable();
1646        CmsContextMenuEntryBean entryBean = new CmsContextMenuEntryBean();
1647        String baseMessage = Messages.get().key(Messages.GUI_EDIT_SMALL_ELEMENTS_0);
1648        String msgEdit = baseMessage;
1649        String msgDisable = baseMessage;
1650        String label = isActive ? msgDisable : msgEdit;
1651        entryBean.setLabel(label);
1652        entryBean.setActive(smallElementsHandler.hasSmallElements());
1653        entryBean.setVisible(true);
1654        I_CmsInputCss inputCss = I_CmsInputLayoutBundle.INSTANCE.inputCss();
1655        entryBean.setIconClass(isActive ? inputCss.checkBoxImageChecked() : inputCss.checkBoxImageUnchecked());
1656        I_CmsContextMenuCommand command = new I_CmsContextMenuCommand() {
1657
1658            public void execute(CmsUUID structureId, I_CmsContextMenuHandler handler, CmsContextMenuEntryBean bean) {
1659
1660                smallElementsHandler.setEditSmallElements(!isActive, true);
1661            }
1662
1663            public A_CmsContextMenuItem getItemWidget(
1664                CmsUUID structureId,
1665                I_CmsContextMenuHandler handler,
1666                CmsContextMenuEntryBean bean) {
1667
1668                return null;
1669            }
1670
1671            public boolean hasItemWidget() {
1672
1673                return false;
1674            }
1675        };
1676        CmsContextMenuEntry entry = new CmsContextMenuEntry(this, null, command);
1677        entry.setBean(entryBean);
1678        return entry;
1679    }
1680
1681    /**
1682     * Creates the view online entry, if an online link is available.<p>
1683     *
1684     * @return the menu entry or null, if not available
1685     */
1686    protected I_CmsContextMenuEntry createViewOnlineEntry() {
1687
1688        final String onlineLink = m_controller.getData().getOnlineLink();
1689        CmsContextMenuEntry entry = null;
1690        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(onlineLink)) {
1691            I_CmsContextMenuCommand command = new I_CmsContextMenuCommand() {
1692
1693                public void execute(
1694                    CmsUUID structureId,
1695                    I_CmsContextMenuHandler handler,
1696                    CmsContextMenuEntryBean bean) {
1697
1698                    Window.open(onlineLink, "opencms-online", null);
1699                }
1700
1701                public A_CmsContextMenuItem getItemWidget(
1702                    CmsUUID structureId,
1703                    I_CmsContextMenuHandler handler,
1704                    CmsContextMenuEntryBean bean) {
1705
1706                    return null;
1707                }
1708
1709                public boolean hasItemWidget() {
1710
1711                    return false;
1712                }
1713            };
1714            entry = new CmsContextMenuEntry(this, null, command);
1715            CmsContextMenuEntryBean entryBean = new CmsContextMenuEntryBean();
1716            entryBean.setLabel(Messages.get().key(Messages.GUI_VIEW_ONLINE_0));
1717            entryBean.setActive(true);
1718            entryBean.setVisible(true);
1719            entry.setBean(entryBean);
1720        }
1721        return entry;
1722    }
1723
1724    /**
1725     * Fills in label and checkbox of a menu entry.<p>
1726     *
1727     * @param entry the menu entry
1728     * @param name the label
1729     * @param checked true if checkbox should be shown
1730     */
1731    protected void decorateMenuEntry(CmsContextMenuEntry entry, String name, boolean checked) {
1732
1733        CmsContextMenuEntryBean bean = new CmsContextMenuEntryBean();
1734        bean.setLabel(name);
1735        bean.setActive(true);
1736        bean.setVisible(true);
1737        I_CmsInputCss inputCss = I_CmsInputLayoutBundle.INSTANCE.inputCss();
1738        bean.setIconClass(checked ? inputCss.checkBoxImageChecked() : "");
1739        entry.setBean(bean);
1740    }
1741
1742    /**
1743     * Helper method for getting the error message for a locking error.<p>
1744     *
1745     * @param lockInfo the lock information
1746     * @return the error message
1747     */
1748    protected String getLockErrorMessage(CmsLockInfo lockInfo) {
1749
1750        switch (lockInfo.getState()) {
1751            case changed:
1752                return Messages.get().key(Messages.ERR_LOCK_RESOURCE_CHANGED_BY_1, lockInfo.getUser());
1753            case locked:
1754                return Messages.get().key(Messages.ERR_LOCK_RESOURCE_LOCKED_BY_1, lockInfo.getUser());
1755            case other:
1756                return lockInfo.getErrorMessage();
1757            case success:
1758            default:
1759                return "";
1760        }
1761    }
1762
1763    /**
1764     * Helper method for getting the error message box title for a locking error.<p>
1765     *
1766     * @param lockInfo the lock information
1767     * @return the error message box title
1768     */
1769    protected String getLockErrorTitle(CmsLockInfo lockInfo) {
1770
1771        switch (lockInfo.getState()) {
1772            case changed:
1773                return Messages.get().key(Messages.ERR_LOCK_TITLE_RESOURCE_CHANGED_0);
1774            case locked:
1775                return Messages.get().key(Messages.ERR_LOCK_TITLE_RESOURCE_LOCKED_0);
1776            case other:
1777            case success:
1778            default:
1779                return Messages.get().key(Messages.GUI_LOCK_FAIL_0);
1780        }
1781    }
1782
1783    /**
1784     * Opens the publish dialog without changes check.<p>
1785     */
1786    protected void openPublish() {
1787
1788        HashMap<String, String> params = Maps.newHashMap();
1789        params.put(CmsPublishOptions.PARAM_CONTAINERPAGE, "" + CmsCoreProvider.get().getStructureId());
1790        params.put(CmsPublishOptions.PARAM_START_WITH_CURRENT_PAGE, "");
1791        params.put(CmsPublishOptions.PARAM_DETAIL, "" + m_controller.getData().getDetailId());
1792        CmsPublishDialog.showPublishDialog(params, new CloseHandler<PopupPanel>() {
1793
1794            /**
1795             * @see com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt.event.logical.shared.CloseEvent)
1796             */
1797            public void onClose(CloseEvent<PopupPanel> event) {
1798
1799                deactivateCurrentButton();
1800                activateSelection();
1801
1802            }
1803        }, new Runnable() {
1804
1805            public void run() {
1806
1807                openPublish();
1808            }
1809
1810        }, m_controller.getContentEditorHandler());
1811    }
1812
1813    /**
1814     * Sets the element view.<p>
1815     *
1816     * @param elementView the element view
1817     * @param nextAction the action to execute after setting the view
1818     */
1819    protected void setElementView(CmsElementViewInfo elementView, Runnable nextAction) {
1820
1821        m_controller.setElementView(elementView, nextAction);
1822    }
1823
1824    /**
1825     * Creates the menu entry for a single element view.<p>
1826     *
1827     * @param elementView the element view
1828     * @param isActive if the group is the currently active group
1829     * @param handler the menu handler
1830     *
1831     * @return the menu entry
1832     */
1833    private CmsContextMenuEntry createMenuEntryForElementView(
1834        final CmsElementViewInfo elementView,
1835        boolean isActive,
1836        I_CmsContextMenuHandler handler) {
1837
1838        CmsContextMenuEntry menuEntry = new CmsContextMenuEntry(handler, null, new I_CmsContextMenuCommand() {
1839
1840            public void execute(
1841                CmsUUID innerStructureId,
1842                I_CmsContextMenuHandler innerHandler,
1843                CmsContextMenuEntryBean bean) {
1844
1845                setElementView(elementView, null);
1846            }
1847
1848            public A_CmsContextMenuItem getItemWidget(
1849                CmsUUID innerStructureId,
1850                I_CmsContextMenuHandler innerHandler,
1851                CmsContextMenuEntryBean bean) {
1852
1853                return null;
1854            }
1855
1856            public boolean hasItemWidget() {
1857
1858                return false;
1859            }
1860        });
1861        CmsContextMenuEntryBean bean = new CmsContextMenuEntryBean();
1862        bean.setLabel(elementView.getTitle());
1863
1864        I_CmsInputCss inputCss = I_CmsInputLayoutBundle.INSTANCE.inputCss();
1865        bean.setIconClass(isActive ? inputCss.checkBoxImageChecked() : "");
1866        bean.setActive(!isActive);
1867        bean.setVisible(true);
1868        menuEntry.setBean(bean);
1869        return menuEntry;
1870
1871    }
1872
1873    /**
1874     * Creates a context menu entry for selecting a template context.<p>
1875     *
1876     * @param cookieName the name of the cookie
1877     * @param value the value of the cookie
1878     * @param label the text for the menu entry
1879     * @param isActive true if context is currently active
1880     * @param handler the context menu handler
1881     * @param structureId the current page's structure id
1882     *
1883     * @return the created context menu entry
1884     */
1885    private CmsContextMenuEntry createMenuEntryForTemplateContext(
1886        final String cookieName,
1887        final String value,
1888        String label,
1889        boolean isActive,
1890        I_CmsContextMenuHandler handler,
1891        CmsUUID structureId) {
1892
1893        CmsContextMenuEntry menuEntry = new CmsContextMenuEntry(handler, structureId, new I_CmsContextMenuCommand() {
1894
1895            public void execute(
1896                CmsUUID innerStructureId,
1897                I_CmsContextMenuHandler innerHandler,
1898                CmsContextMenuEntryBean bean) {
1899
1900                changeTemplateContextManually(cookieName, value);
1901            }
1902
1903            public A_CmsContextMenuItem getItemWidget(
1904                CmsUUID innerStructureId,
1905                I_CmsContextMenuHandler innerHandler,
1906                CmsContextMenuEntryBean bean) {
1907
1908                return null;
1909            }
1910
1911            public boolean hasItemWidget() {
1912
1913                return false;
1914            }
1915        });
1916        CmsContextMenuEntryBean bean = new CmsContextMenuEntryBean();
1917        bean.setLabel(label);
1918
1919        I_CmsInputCss inputCss = I_CmsInputLayoutBundle.INSTANCE.inputCss();
1920        bean.setIconClass(isActive ? inputCss.checkBoxImageChecked() : "");
1921        bean.setActive(true);
1922        bean.setVisible(true);
1923        menuEntry.setBean(bean);
1924        return menuEntry;
1925
1926    }
1927
1928    /**
1929     * Creates the real entries for the  "Show locale" option.<p>
1930     *
1931     * @return the real entry
1932     */
1933    private I_CmsContextMenuEntry createShowLocaleMenuEntry() {
1934
1935        Map<String, CmsLocaleLinkBean> localeLinkBeans = CmsContainerpageController.get().getData().getLocaleLinkBeans();
1936        if ((localeLinkBeans == null) || localeLinkBeans.isEmpty()) {
1937            return null;
1938        }
1939
1940        CmsContextMenuEntry parentEntry = new CmsContextMenuEntry(this, null, new I_CmsContextMenuCommand() {
1941
1942            public void execute(
1943                CmsUUID innerStructureId,
1944                I_CmsContextMenuHandler handler,
1945                CmsContextMenuEntryBean bean) {
1946
1947                // do nothing
1948            }
1949
1950            public A_CmsContextMenuItem getItemWidget(
1951                CmsUUID innerStructureId,
1952                I_CmsContextMenuHandler handler,
1953                CmsContextMenuEntryBean bean) {
1954
1955                return null;
1956            }
1957
1958            public boolean hasItemWidget() {
1959
1960                return false;
1961            }
1962
1963        });
1964        CmsContextMenuEntryBean parentBean = new CmsContextMenuEntryBean();
1965
1966        parentBean.setLabel(
1967            org.opencms.ade.containerpage.client.Messages.get().key(
1968                org.opencms.ade.containerpage.client.Messages.GUI_SHOW_LOCALE_0));
1969        parentBean.setActive(true);
1970        parentBean.setVisible(true);
1971        parentEntry.setBean(parentBean);
1972        List<I_CmsContextMenuEntry> subEntries = Lists.newArrayList();
1973
1974        for (Map.Entry<String, CmsLocaleLinkBean> entry : localeLinkBeans.entrySet()) {
1975            String label = entry.getKey();
1976            final CmsLocaleLinkBean linkBean = entry.getValue();
1977            CmsContextMenuEntry childEntry = new CmsContextMenuEntry(this, null, new I_CmsContextMenuCommand() {
1978
1979                public void execute(
1980                    CmsUUID structureId,
1981                    I_CmsContextMenuHandler handler,
1982                    CmsContextMenuEntryBean bean) {
1983
1984                    if (linkBean.getError() != null) {
1985                        CmsNotification.get().sendAlert(Type.WARNING, linkBean.getError());
1986                    } else if (linkBean.getLink() != null) {
1987                        Window.Location.assign(linkBean.getLink());
1988                    }
1989                }
1990
1991                public A_CmsContextMenuItem getItemWidget(
1992                    CmsUUID structureId,
1993                    I_CmsContextMenuHandler handler,
1994                    CmsContextMenuEntryBean bean) {
1995
1996                    return null;
1997                }
1998
1999                public boolean hasItemWidget() {
2000
2001                    return false;
2002                }
2003            });
2004            CmsContextMenuEntryBean childBean = new CmsContextMenuEntryBean();
2005            childBean.setLabel(label);
2006            childBean.setActive(true);
2007            childBean.setVisible(true);
2008            childEntry.setBean(childBean);
2009            subEntries.add(childEntry);
2010        }
2011        parentEntry.setSubMenu(subEntries);
2012        if (subEntries.isEmpty()) {
2013            return null;
2014        } else {
2015            return parentEntry;
2016        }
2017    }
2018
2019    /**
2020     * Returns the page leaving dialog.<p>
2021     *
2022     * @return the page leaving dialog
2023     */
2024    private CmsAcceptDeclineCancelDialog getLeaveDialog() {
2025
2026        StringBuffer message = new StringBuffer();
2027        message.append("<p>" + Messages.get().key(Messages.GUI_DIALOG_LEAVE_NOT_SAVED_0) + "</p>");
2028        message.append("<p>" + Messages.get().key(Messages.GUI_DIALOG_SAVE_QUESTION_0) + "</p>");
2029
2030        CmsAcceptDeclineCancelDialog leavingDialog = new CmsAcceptDeclineCancelDialog(
2031            Messages.get().key(Messages.GUI_DIALOG_NOT_SAVED_TITLE_0),
2032            message.toString());
2033        leavingDialog.setAcceptText(Messages.get().key(Messages.GUI_BUTTON_SAVE_TEXT_0));
2034        leavingDialog.setDeclineText(Messages.get().key(Messages.GUI_BUTTON_DISCARD_TEXT_0));
2035        leavingDialog.setCloseText(Messages.get().key(Messages.GUI_BUTTON_RETURN_TEXT_0));
2036        return leavingDialog;
2037    }
2038
2039    /**
2040     * Opens the group-container element editor.<p>
2041     *
2042     * @param groupContainer the group-container element
2043     */
2044    private void openGroupEditor(CmsGroupContainerElementPanel groupContainer) {
2045
2046        m_controller.startEditingGroupcontainer(groupContainer, groupContainer.isGroupContainer());
2047    }
2048}