001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://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.ui;
029
030import org.opencms.ade.containerpage.client.CmsContainerpageController;
031import org.opencms.ade.containerpage.client.CmsContainerpageController.I_ReloadHandler;
032import org.opencms.ade.containerpage.client.Messages;
033import org.opencms.ade.containerpage.client.ui.groupeditor.CmsInheritanceContainerEditor;
034import org.opencms.ade.containerpage.shared.CmsContainerElement;
035import org.opencms.ade.containerpage.shared.CmsContainerElement.ModelGroupState;
036import org.opencms.ade.containerpage.shared.CmsContainerElementData;
037import org.opencms.ade.containerpage.shared.CmsElementSettingsConfig;
038import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
039import org.opencms.ade.containerpage.shared.CmsFormatterConfigCollection;
040import org.opencms.gwt.client.CmsCoreProvider;
041import org.opencms.gwt.client.ui.CmsFieldSet;
042import org.opencms.gwt.client.ui.contextmenu.CmsContextMenuButton;
043import org.opencms.gwt.client.ui.contextmenu.CmsDialogContextMenuHandler;
044import org.opencms.gwt.client.ui.css.I_CmsInputLayoutBundle;
045import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
046import org.opencms.gwt.client.ui.input.CmsCheckBox;
047import org.opencms.gwt.client.ui.input.CmsMultiCheckBox;
048import org.opencms.gwt.client.ui.input.CmsSelectBox;
049import org.opencms.gwt.client.ui.input.CmsSelectComboBox;
050import org.opencms.gwt.client.ui.input.I_CmsFormField;
051import org.opencms.gwt.client.ui.input.I_CmsFormWidget;
052import org.opencms.gwt.client.ui.input.form.A_CmsFormFieldPanel;
053import org.opencms.gwt.client.ui.input.form.CmsBasicFormField;
054import org.opencms.gwt.client.ui.input.form.CmsDialogFormHandler;
055import org.opencms.gwt.client.ui.input.form.CmsFieldTooltip;
056import org.opencms.gwt.client.ui.input.form.CmsFieldTooltip.Data;
057import org.opencms.gwt.client.ui.input.form.CmsFieldsetFormFieldPanel;
058import org.opencms.gwt.client.ui.input.form.CmsForm;
059import org.opencms.gwt.client.ui.input.form.CmsFormDialog;
060import org.opencms.gwt.client.ui.input.form.CmsFormRow;
061import org.opencms.gwt.client.ui.input.form.CmsInfoBoxFormFieldPanel;
062import org.opencms.gwt.client.ui.input.form.CmsWidgetFactoryRegistry;
063import org.opencms.gwt.client.ui.input.form.I_CmsFormSubmitHandler;
064import org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetMultiFactory;
065import org.opencms.gwt.client.ui.input.form.I_CmsHasPlaceholder;
066import org.opencms.gwt.client.util.CmsDomUtil;
067import org.opencms.gwt.shared.CmsAdditionalInfoBean;
068import org.opencms.gwt.shared.CmsCoreData.AdeContext;
069import org.opencms.gwt.shared.CmsGwtConstants;
070import org.opencms.gwt.shared.CmsListInfoBean;
071import org.opencms.gwt.shared.CmsTemplateContextInfo;
072import org.opencms.util.CmsStringUtil;
073import org.opencms.util.CmsUUID;
074import org.opencms.xml.content.CmsXmlContentProperty;
075
076import java.util.ArrayList;
077import java.util.Collections;
078import java.util.HashMap;
079import java.util.LinkedHashMap;
080import java.util.List;
081import java.util.Map;
082import java.util.Map.Entry;
083import java.util.Set;
084
085import com.google.common.base.Optional;
086import com.google.common.base.Supplier;
087import com.google.common.collect.Maps;
088import com.google.gwt.dom.client.Style;
089import com.google.gwt.dom.client.Style.Unit;
090import com.google.gwt.event.logical.shared.ValueChangeEvent;
091import com.google.gwt.event.logical.shared.ValueChangeHandler;
092import com.google.gwt.user.client.ui.FlowPanel;
093import com.google.gwt.user.client.ui.Widget;
094
095/**
096 * The element settings dialog.<p>
097 */
098public class CmsElementSettingsDialog extends CmsFormDialog implements I_CmsFormWidgetMultiFactory {
099
100    /**
101     * A panel which adds icons with tooltips containing the field description to the rows.<p>
102     */
103    public static class FieldPanel extends CmsFieldsetFormFieldPanel {
104
105        /**
106         * Creates a new instance.<p>
107         *
108         * @param info the list info bean for an element
109         * @param legend the legend for the fieldset
110         */
111        public FieldPanel(CmsListInfoBean info, String legend) {
112
113            super(info, legend);
114        }
115
116        /**
117         * @see org.opencms.gwt.client.ui.input.form.A_CmsFormFieldPanel#createRow(org.opencms.gwt.client.ui.input.I_CmsFormField)
118         */
119        @Override
120        protected CmsFormRow createRow(I_CmsFormField field) {
121
122            final String htmlDesc = field.getDescription();
123            CmsFormRow row = createRow(
124                field.getLabel(),
125                A_CmsFormFieldPanel.NO_DESCRIPTION,
126                (Widget)field.getWidget(),
127                htmlDesc,
128                true);
129            return row;
130        }
131
132    }
133
134    /**
135     * Exception for the case where no formatter configuration is available.<p>
136     */
137    public static class NoFormatterException extends Exception {
138
139        /** uid. */
140        private static final long serialVersionUID = -5735428472483535958L;
141
142        /**
143         * Creates a new instance.<p>
144         */
145        public NoFormatterException() {
146
147            // nothing here
148        }
149    }
150
151    /** The model group options. */
152    protected enum GroupOption {
153
154        /** The copy elements option. */
155        copy(Messages.get().key(Messages.GUI_MODEL_GROUP_OPTION_COPY_0)),
156
157        /** The disabled option. */
158        disabled(Messages.get().key(Messages.GUI_MODEL_GROUP_OPTION_DISABLED_0)),
159
160        /** The reuse option. */
161        reuse(Messages.get().key(Messages.GUI_MODEL_GROUP_OPTION_REUSE_0));
162
163        /** The option label. */
164        private String m_label;
165
166        /**
167         * Constructor.<p>
168         *
169         * @param label the label
170         */
171        GroupOption(String label) {
172
173            m_label = label;
174        }
175
176        /**
177         * Returns the option label.<p>
178         *
179         * @return the option label
180         */
181        protected String getLabel() {
182
183            return m_label;
184        }
185    }
186
187    /** The container page controller. */
188    CmsContainerpageController m_controller;
189
190    /** Checkbox to set the 'model group' status. */
191    CmsSelectBox m_modelGroupSelect;
192
193    /** The template context changed flag. */
194    private boolean m_changedContext;
195
196    /** The current container id. */
197    private String m_containerId;
198
199    /** The template context info. */
200    private CmsTemplateContextInfo m_contextInfo;
201
202    /** The template context widget. */
203    private CmsMultiCheckBox m_contextsWidget;
204
205    /** Checkbox to set the 'createNew' status. */
206    private CmsCheckBox m_createNewCheckBox;
207
208    /** The element data bean. */
209    private CmsContainerElementData m_elementBean;
210
211    /** The element panel. */
212    private CmsContainerPageElementPanel m_elementWidget;
213
214    /** Id of currently selected formatter. */
215    private String m_formatter;
216
217    /** The formatter select widget. */
218    private CmsSelectBox m_formatterSelect;
219
220    /** The break up model group checkbox. */
221    private CmsCheckBox m_modelGroupBreakUp;
222
223    /** The original formatter key. */
224    private String m_originalFormatter;
225
226    /** Setting presets. */
227    private Map<String, String> m_presets;
228
229    /** The element setting values. */
230    private Map<String, String> m_settings;
231
232    /**
233     * Constructor.<p>
234     *
235     * @param controller the container page controller
236     * @param elementWidget the element panel
237     * @param settingsConfig the element setting configuration
238     * @param settingPresets the presets for settings
239     *
240     * @throws NoFormatterException if no formatter configuration is found for the element
241     */
242    public CmsElementSettingsDialog(
243        CmsContainerpageController controller,
244        CmsContainerPageElementPanel elementWidget,
245        CmsElementSettingsConfig settingsConfig,
246        Map<String, String> settingPresets)
247    throws NoFormatterException {
248
249        super(Messages.get().key(Messages.GUI_PROPERTY_DIALOG_TITLE_0), new CmsForm(false), null);
250        setAnimationEnabled(false);
251        setUseAnimation(false);
252        addStyleName(I_CmsLayoutBundle.INSTANCE.elementSettingsDialogCss().elementSettingsDialog());
253        m_presets = settingPresets != null ? settingPresets : new HashMap<String, String>();
254        CmsContainerElementData elementBean = settingsConfig.getElementData();
255        m_elementWidget = elementWidget;
256        m_controller = controller;
257        m_elementBean = elementBean;
258        m_contextInfo = m_controller.getData().getTemplateContextInfo();
259        m_containerId = m_elementWidget.getParentTarget().getContainerId();
260        CmsListInfoBean infoBean = new CmsListInfoBean();
261        infoBean.setResourceState(settingsConfig.getState());
262        infoBean.setTitle(elementBean.getTitle());
263        infoBean.setSubTitle(elementBean.getSitePath());
264        infoBean.setResourceType(elementBean.getResourceType());
265        infoBean.setBigIconClasses(elementBean.getBigIconClasses());
266        m_settings = elementBean.getSettings();
267        A_CmsFormFieldPanel formFieldPanel = null;
268        CmsFormatterConfig currentFormatterConfig = m_elementBean.getFormatterConfig(m_containerId);
269        if (currentFormatterConfig == null) {
270            throw new NoFormatterException();
271        }
272        for (CmsAdditionalInfoBean addInfo : settingsConfig.getAdditionalInfo()) {
273            infoBean.addAdditionalInfo(addInfo.getName(), addInfo.getValue(), addInfo.getStyle());
274        }
275        // infoBean.addAdditionalInfo(Messages.get().key(Messages.GUI_ADDINFO_FORMATTER_PATH_0), formatterPath);
276        I_CmsDropContainer dropContainer = elementWidget.getParentTarget();
277        if (dropContainer instanceof CmsContainerPageContainer) {
278            CmsContainerPageContainer cpc = (CmsContainerPageContainer)dropContainer;
279            String type = cpc.getContainerType();
280            String name = cpc.getContainerId();
281            infoBean.addAdditionalInfo(Messages.get().key(Messages.GUI_ADDINFO_FORMATTER_CONTAINER_0), name);
282            infoBean.addAdditionalInfo(Messages.get().key(Messages.GUI_ADDINFO_FORMATTER_CONTAINER_TYPE_0), type);
283        }
284
285        boolean isEditableModelGroup = CmsCoreProvider.get().getUserInfo().isDeveloper()
286            && m_controller.getData().isModelGroup();
287        boolean hasGroupTypeOption = isEditableModelGroup
288            && ((m_controller.getModelGroupElementId() == null)
289                || CmsContainerpageController.getServerId(elementBean.getClientId()).equals(
290                    m_controller.getModelGroupElementId()))
291            && !m_elementWidget.hasModelGroupParent();
292
293        boolean isDeveloper = CmsCoreProvider.get().getUserInfo().isDeveloper();
294        m_originalFormatter = currentFormatterConfig.getKeyOrId();
295
296        if (m_contextInfo.shouldShowElementTemplateContextSelection()
297            || isDeveloper
298            || m_elementBean.hasAlternativeFormatters(m_containerId)) {
299            CmsFieldsetFormFieldPanel fieldSetPanel = new FieldPanel(
300                infoBean,
301                Messages.get().key(Messages.GUI_SETTINGS_LEGEND_0));
302            formFieldPanel = fieldSetPanel;
303            if (m_elementBean.hasAlternativeFormatters(m_containerId)) {
304                CmsFieldSet formatterFieldset = new CmsFieldSet();
305                // insert as first field-set after the element info box
306                fieldSetPanel.getMainPanel().insert(formatterFieldset, 1);
307                formatterFieldset.setLegend(Messages.get().key(Messages.GUI_FORMATTERS_LEGEND_0));
308                formatterFieldset.getElement().getStyle().setMarginTop(10, Style.Unit.PX);
309                LinkedHashMap<String, String> formatters = new LinkedHashMap<String, String>();
310                CmsElementSettingsFormatterWidget formatterWidget = new CmsElementSettingsFormatterWidget();
311                m_formatterSelect = formatterWidget.getFormatterSelect();
312                CmsFormatterConfigCollection formattersForContainer = m_elementBean.getFormatters().get(m_containerId);
313                for (CmsFormatterConfig formatter : formattersForContainer) {
314                    formatters.put(formatter.getKeyOrId(), formatter.getLabel());
315                    m_formatterSelect.setTitle(formatter.getKeyOrId(), formatter.getJspRootPath());
316                }
317                m_formatterSelect.setItems(formatters);
318                String currentFormatterValue = m_elementBean.getFormatterConfig(m_containerId).getKeyOrId();
319                m_formatter = currentFormatterValue;
320                m_formatterSelect.selectValue(currentFormatterValue);
321                m_formatterSelect.addValueChangeHandler(new ValueChangeHandler<String>() {
322
323                    public void onValueChange(ValueChangeEvent<String> event) {
324
325                        onFormatterChange(event.getValue());
326                    }
327                });
328
329                // set up formatter help tooltip
330                final FlowPanel help = formatterWidget.getHelp();
331                for (String style : CmsFormRow.ICON_STYLES) {
332                    help.addStyleName(style);
333                }
334                final Map<String, CmsFieldTooltip.Data> tooltips = Maps.newHashMap();
335                for (CmsFormatterConfig formatterConfig : formattersForContainer) {
336                    String description = formatterConfig.getDescription();
337                    if (description == null) {
338                        description = formatterConfig.getLabel();
339                    }
340                    tooltips.put(formatterConfig.getKeyOrId(), new Data(help, description, true));
341                }
342                Supplier<CmsFieldTooltip.Data> tooltipProvider = new Supplier<CmsFieldTooltip.Data>() {
343
344                    @SuppressWarnings("synthetic-access")
345                    public Data get() {
346
347                        return tooltips.get(m_formatter);
348                    }
349                };
350                CmsFormRow.installTooltipEventHandlers(help, tooltipProvider);
351                formatterFieldset.add(formatterWidget);
352            }
353            if (m_controller.getData().isModelPage() || isEditableModelGroup) {
354                CmsFieldSet modelGroupFieldSet = new CmsFieldSet();
355                modelGroupFieldSet.setLegend(Messages.get().key(Messages.GUI_CREATE_NEW_LEGEND_0
356
357                ));
358                modelGroupFieldSet.getElement().getStyle().setMarginTop(10, Unit.PX);
359
360                if (hasGroupTypeOption) {
361                    addModelGroupSettings(elementBean, elementWidget, modelGroupFieldSet);
362                }
363                if (!elementWidget.isModelGroup() && !hasGroupTypeOption) {
364                    if (!isEditableModelGroup || settingsConfig.isCopyGroup()) {
365                        addCreateNewCheckbox(elementBean, modelGroupFieldSet);
366                    }
367                }
368                if (modelGroupFieldSet.getWidgetCount() > 0) {
369                    fieldSetPanel.getMainPanel().insert(modelGroupFieldSet, 1);
370                }
371
372            } else if (elementWidget.isModelGroup()) {
373                CmsFieldSet modelGroupFieldSet = new CmsFieldSet();
374                modelGroupFieldSet.setLegend(Messages.get().key(Messages.GUI_CREATE_NEW_LEGEND_0
375
376                ));
377                modelGroupFieldSet.getElement().getStyle().setMarginTop(10, Unit.PX);
378                m_modelGroupBreakUp = new CmsCheckBox(Messages.get().key(Messages.GUI_MODEL_GROUP_BREAK_UP_0));
379                m_modelGroupBreakUp.setDisplayInline(false);
380                m_modelGroupBreakUp.getElement().getStyle().setMarginTop(7, Style.Unit.PX);
381                modelGroupFieldSet.add(m_modelGroupBreakUp);
382                fieldSetPanel.getMainPanel().insert(modelGroupFieldSet, 1);
383            }
384
385            if (m_contextInfo.shouldShowElementTemplateContextSelection()) {
386                String templateContexts = m_settings.get(CmsTemplateContextInfo.SETTING);
387                if (templateContexts == null) {
388                    templateContexts = CmsStringUtil.listAsString(
389                        new ArrayList<String>(
390                            CmsContainerpageController.get().getData().getTemplateContextInfo().getContextLabels().keySet()),
391                        "|");
392                } else if (templateContexts.equals(CmsTemplateContextInfo.EMPTY_VALUE)) {
393                    // translate "none" to an empty selection
394                    templateContexts = "";
395                }
396                m_settings.put(CmsTemplateContextInfo.SETTING, templateContexts);
397
398                CmsFieldSet contextsFieldset = new CmsFieldSet();
399                contextsFieldset.setLegend(m_contextInfo.getSettingDefinition().getNiceName());
400                contextsFieldset.getElement().getStyle().setMarginTop(10, Style.Unit.PX);
401                m_contextsWidget = new CmsMultiCheckBox(
402                    CmsStringUtil.splitOptions(m_contextInfo.getSettingDefinition().getWidgetConfiguration()));
403                for (CmsCheckBox checkbox : m_contextsWidget.getCheckboxes()) {
404                    Style checkboxStyle = checkbox.getElement().getStyle();
405                    checkbox.getButton().getElement().getStyle().setFontWeight(Style.FontWeight.NORMAL);
406                    checkboxStyle.setMarginTop(7, Style.Unit.PX);
407                }
408                m_contextsWidget.setFormValueAsString(m_settings.get(CmsTemplateContextInfo.SETTING));
409                m_contextsWidget.addValueChangeHandler(new ValueChangeHandler<String>() {
410
411                    public void onValueChange(ValueChangeEvent<String> event) {
412
413                        setTemplateContextChanged(true);
414                    }
415                });
416                contextsFieldset.add(m_contextsWidget);
417                fieldSetPanel.getMainPanel().add(contextsFieldset);
418            }
419        } else {
420            formFieldPanel = new CmsInfoBoxFormFieldPanel(infoBean);
421        }
422
423        CmsUUID serverId = null;
424        if (elementBean.isModelGroup()) {
425            serverId = elementBean.getModelGroupId();
426        } else {
427            String id = CmsContainerpageController.getServerId(elementBean.getClientId());
428            if (CmsUUID.isValidUUID(id) && !(new CmsUUID(id).isNullUUID())) {
429                serverId = new CmsUUID(id);
430            }
431        }
432        if (serverId != null) {
433            CmsContextMenuButton menuButton = new CmsContextMenuButton(
434                serverId,
435                new CmsDialogContextMenuHandler(),
436                AdeContext.resourceinfo);
437            menuButton.addStyleName(I_CmsLayoutBundle.INSTANCE.listItemWidgetCss().permaVisible());
438            formFieldPanel.getInfoWidget().addButton(menuButton);
439        }
440
441        getForm().setWidget(formFieldPanel);
442        formFieldPanel.addStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().formGradientBackground());
443        I_CmsFormSubmitHandler submitHandler = new I_CmsFormSubmitHandler() {
444
445            /**
446             * @see org.opencms.gwt.client.ui.input.form.I_CmsFormSubmitHandler#onSubmitForm(org.opencms.gwt.client.ui.input.form.CmsForm, java.util.Map, java.util.Set)
447             */
448            public void onSubmitForm(
449                CmsForm formParam,
450                final Map<String, String> fieldValues,
451                Set<String> editedFields) {
452
453                submitForm(formParam, fieldValues, editedFields);
454            }
455        };
456        CmsDialogFormHandler formHandler = new CmsDialogFormHandler();
457        formHandler.setSubmitHandler(submitHandler);
458        getForm().setFormHandler(formHandler);
459        formHandler.setDialog(this);
460        renderSettingsForm(
461            m_elementBean.getSettingConfig(m_containerId),
462            m_elementBean.getFormatterConfig(m_containerId).getNestedFormatterPrefixes());
463    }
464
465    /**
466     * @see org.opencms.gwt.client.ui.input.form.CmsFormDialog#center()
467     */
468    @Override
469    public void center() {
470
471        show();
472    }
473
474    /**
475     * @see org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetMultiFactory#createFormWidget(java.lang.String, java.util.Map, com.google.common.base.Optional)
476     */
477    public I_CmsFormWidget createFormWidget(
478        String key,
479        Map<String, String> widgetParams,
480        Optional<String> defaultValue) {
481
482        if (CmsSelectBox.WIDGET_TYPE.equals(key) || CmsSelectComboBox.WIDGET_TYPE.equals(key)) {
483            if ((defaultValue != null) && defaultValue.isPresent() && widgetParams.containsKey(defaultValue.get())) {
484                key = key + CmsSelectBox.NOTNULL_SUFFIX;
485            }
486            Map<String, String> newParams = new HashMap<>();
487            newParams.putAll(widgetParams);
488            newParams.put(CmsSelectBox.OPTION_RESIZABLE, "false");
489            widgetParams = newParams;
490        }
491
492        return CmsWidgetFactoryRegistry.instance().createFormWidget(key, widgetParams, defaultValue);
493    }
494
495    /**
496     * @see com.google.gwt.user.client.ui.PopupPanel#setPopupPosition(int, int)
497     */
498    @Override
499    public void setPopupPosition(int left, int top) {
500
501        // positioning handled via CSS
502    }
503
504    /**
505     * @see org.opencms.gwt.client.ui.input.form.CmsFormDialog#show()
506     */
507    @Override
508    public void show() {
509
510        super.show();
511        // positioning handled by CSS
512        getElement().getStyle().clearPosition();
513        getElement().getStyle().clearLeft();
514        getElement().getStyle().clearTop();
515
516    }
517
518    /**
519     * Returns if the template context has been changed.<p>
520     *
521     * @return <code>true</code> if the template context has been changed
522     */
523    boolean isTemplateContextChanged() {
524
525        return m_changedContext;
526    }
527
528    /**
529     * Handles the formatter selection changes.<p>
530     *
531     * @param formatterId the formatter id
532     */
533    void onFormatterChange(String formatterId) {
534
535        m_formatter = formatterId;
536        CmsFormatterConfig config = m_elementBean.getFormatters().get(m_containerId).get(formatterId);
537        renderSettingsForm(config.getSettingConfig(), config.getNestedFormatterPrefixes());
538    }
539
540    /**
541     * Renders the settings form.<p>
542     *
543     * @param settingsConfig the settings configuration
544     * @param nestedFormatterPrefixes the nested formatter prefixes
545     */
546    void renderSettingsForm(
547        Map<String, CmsXmlContentProperty> settingsConfig,
548        Map<String, String> nestedFormatterPrefixes) {
549
550        Map<String, String> presets = m_presets;
551        if (presets == null) {
552            presets = new HashMap<String, String>();
553        }
554        List<String> groups = new ArrayList<String>(getForm().getGroups());
555        for (String group : groups) {
556            getForm().removeGroup(group);
557        }
558
559        CmsFieldsetFormFieldPanel formFieldPanel = null;
560        if (getForm().getWidget() instanceof CmsFieldsetFormFieldPanel) {
561            formFieldPanel = ((CmsFieldsetFormFieldPanel)getForm().getWidget());
562        }
563        if ((formFieldPanel != null) && (nestedFormatterPrefixes != null) && !nestedFormatterPrefixes.isEmpty()) {
564            for (Entry<String, String> entry : nestedFormatterPrefixes.entrySet()) {
565                CmsFieldSet fieldSet = new CmsFieldSet();
566                fieldSet.setLegend(entry.getValue());
567                fieldSet.getElement().getStyle().setMarginTop(10, Style.Unit.PX);
568                formFieldPanel.addGroupFieldSet(entry.getKey(), fieldSet);
569            }
570        }
571        // using LinkedHashMap to preserve the order
572        Map<String, I_CmsFormField> formFields = new LinkedHashMap<String, I_CmsFormField>();
573        for (CmsXmlContentProperty propConfig : settingsConfig.values()) {
574            if (m_presets.containsKey(propConfig.getName())) {
575                // settings configured as presets on the container are not user-editable
576                continue;
577            }
578            CmsBasicFormField currentField = CmsBasicFormField.createField(
579                propConfig,
580                propConfig.getName(),
581                this,
582                Collections.<String, String> emptyMap(),
583                false);
584            if (currentField.getWidget() instanceof I_CmsHasPlaceholder) {
585                if (!CmsStringUtil.isEmpty(propConfig.getPlaceholder())) {
586                    ((I_CmsHasPlaceholder)currentField.getWidget()).setPlaceholder(propConfig.getPlaceholder());
587                }
588            }
589            formFields.put(propConfig.getName(), currentField);
590
591        }
592        for (I_CmsFormField field : formFields.values()) {
593
594            String fieldId = field.getId();
595            CmsXmlContentProperty propDef = settingsConfig.get(fieldId);
596            // skip hidden fields
597            if (!CmsGwtConstants.HIDDEN_SETTINGS_WIDGET_NAME.equals(propDef.getWidget())) {
598                String initialValue = m_settings.get(fieldId);
599                if (initialValue == null) {
600
601                    initialValue = propDef.getDefault();
602                }
603                String group = "";
604                if ((nestedFormatterPrefixes != null) && !nestedFormatterPrefixes.isEmpty()) {
605                    for (String prefix : nestedFormatterPrefixes.keySet()) {
606                        if (fieldId.startsWith(prefix)) {
607                            group = prefix;
608                            break;
609                        }
610                    }
611                }
612
613                getForm().addField(group, field, initialValue);
614            }
615        }
616        getForm().render();
617    }
618
619    /**
620     * Sets the template context changed flag.<p>
621     * @param changed the template context changed flag
622     */
623    void setTemplateContextChanged(boolean changed) {
624
625        m_changedContext = changed;
626    }
627
628    /**
629     * Submits the settings form.<p>
630     *
631     * @param formParam the form
632     * @param fieldValues the field values
633     * @param editedFields the changed fields
634     */
635    void submitForm(CmsForm formParam, final Map<String, String> fieldValues, Set<String> editedFields) {
636
637        String modelGroupId = null;
638
639        if (CmsInheritanceContainerEditor.getInstance() != null) {
640            CmsInheritanceContainerEditor.getInstance().onSettingsEdited();
641        }
642        if (m_contextsWidget != null) {
643            String newTemplateContexts = m_contextsWidget.getFormValueAsString();
644            if ((newTemplateContexts == null) || "".equals(newTemplateContexts)) {
645                newTemplateContexts = CmsTemplateContextInfo.EMPTY_VALUE;
646                // translate an empty selection to "none"
647            }
648            fieldValues.put(CmsTemplateContextInfo.SETTING, newTemplateContexts);
649        }
650        final boolean hasFormatterChanges;
651        if (m_formatterSelect != null) {
652            fieldValues.put(
653                CmsFormatterConfig.getSettingsKeyForContainer(m_containerId),
654                m_formatterSelect.getFormValueAsString());
655            hasFormatterChanges = true;
656        } else {
657            hasFormatterChanges = false;
658            if (m_originalFormatter != null) {
659                // in case there is only 1 formatter, we still want to send the formatter key to the server to avoid cases
660                // where the element is removed because no default formatter can be found in the active sitemap config.
661                fieldValues.put(CmsFormatterConfig.getSettingsKeyForContainer(m_containerId), m_originalFormatter);
662            }
663        }
664        if (m_createNewCheckBox != null) {
665            m_elementWidget.setCreateNew(m_createNewCheckBox.isChecked());
666            fieldValues.put(CmsContainerElement.CREATE_AS_NEW, Boolean.toString(m_createNewCheckBox.isChecked()));
667        }
668        if (m_modelGroupSelect != null) {
669            GroupOption group = GroupOption.valueOf(m_modelGroupSelect.getFormValueAsString());
670            switch (group) {
671                case disabled:
672                    fieldValues.put(CmsContainerElement.MODEL_GROUP_STATE, ModelGroupState.noGroup.name());
673                    fieldValues.put(CmsContainerElement.USE_AS_COPY_MODEL, Boolean.toString(false));
674                    break;
675                case copy:
676                    fieldValues.put(CmsContainerElement.MODEL_GROUP_STATE, ModelGroupState.isModelGroup.name());
677                    fieldValues.put(CmsContainerElement.USE_AS_COPY_MODEL, Boolean.toString(true));
678                    break;
679                case reuse:
680                    fieldValues.put(CmsContainerElement.MODEL_GROUP_STATE, ModelGroupState.isModelGroup.name());
681                    fieldValues.put(CmsContainerElement.USE_AS_COPY_MODEL, Boolean.toString(false));
682                    break;
683                default:
684                    break;
685            }
686            if (group != GroupOption.disabled) {
687                modelGroupId = CmsContainerpageController.getServerId(m_elementBean.getClientId());
688            }
689        }
690
691        if ((m_modelGroupBreakUp != null) && m_modelGroupBreakUp.isChecked()) {
692            fieldValues.put(CmsContainerElement.MODEL_GROUP_STATE, ModelGroupState.noGroup.name());
693        }
694
695        final Map<String, String> filteredFieldValues = new HashMap<String, String>();
696        for (Map.Entry<String, String> entry : fieldValues.entrySet()) {
697            String key = entry.getKey();
698            String value = entry.getValue();
699            if ((value != null) && (value.length() > 0)) {
700                filteredFieldValues.put(key, value);
701            }
702        }
703        final String changeModelGroupId = modelGroupId;
704        I_ReloadHandler reloadHandler = new I_ReloadHandler() {
705
706            CmsContainerPageElementPanel m_newElement;
707            CmsContainerPageElementPanel m_oldElement;
708
709            @Override
710            public void finish() {
711
712                if (isTemplateContextChanged()) {
713                    // if the context multiselect box isn't displayed, of course it can't change values,
714                    // and this code won't be executed.
715                    CmsContainerpageController.get().handleChangeTemplateContext(
716                        m_newElement,
717                        filteredFieldValues.get(CmsTemplateContextInfo.SETTING));
718                }
719                if (hasFormatterChanges) {
720                    updateCss();
721                }
722                if (m_newElement.getElement().getInnerHTML().contains(CmsGwtConstants.FORMATTER_RELOAD_MARKER)
723                    && !CmsContainerpageController.get().isGroupcontainerEditing()) {
724                    CmsContainerpageController.get().reloadPage();
725                }
726                if (m_modelGroupSelect != null) {
727                    m_controller.setModelGroupElementId(changeModelGroupId);
728                }
729                m_controller.sendElementEditedSettings(m_newElement, m_oldElement);
730            }
731
732            @Override
733            public void onReload(CmsContainerPageElementPanel oldElement, CmsContainerPageElementPanel newElement) {
734
735                m_oldElement = oldElement;
736                m_newElement = newElement;
737            }
738
739        };
740        m_controller.reloadElementWithSettings(
741            m_elementWidget,
742            m_elementBean.getClientId(),
743            filteredFieldValues,
744            reloadHandler);
745    }
746
747    /**
748     * Updates the CSS resources for the selected formatter.<p>
749     */
750    void updateCss() {
751
752        String formatterId = m_formatterSelect.getFormValueAsString();
753        CmsFormatterConfig formatter = m_elementBean.getFormatters().get(m_containerId).get(formatterId);
754        Set<String> cssResources = formatter.getCssResources();
755        for (String cssResource : cssResources) {
756            CmsDomUtil.ensureStyleSheetIncluded(cssResource);
757        }
758        if (formatter.hasInlineCss()) {
759            ensureInlineCss(formatterId, formatter.getInlineCss());
760        }
761    }
762
763    /**
764     * Adds the create new checkbox to the given field set.<p>
765     *
766     * @param elementBean the element bean
767     * @param fieldSet the field set
768     */
769    private void addCreateNewCheckbox(CmsContainerElementData elementBean, CmsFieldSet fieldSet) {
770
771        m_createNewCheckBox = new CmsCheckBox(Messages.get().key(Messages.GUI_CREATE_NEW_LABEL_0));
772        m_createNewCheckBox.setDisplayInline(false);
773        m_createNewCheckBox.getElement().getStyle().setMarginTop(7, Style.Unit.PX);
774        m_createNewCheckBox.setChecked(elementBean.isCreateNew());
775        fieldSet.add(m_createNewCheckBox);
776    }
777
778    /**
779     * Adds the model group settings fields to the given field set.<p>
780     *
781     * @param elementBean the element bean
782     * @param elementWidget the element widget
783     * @param fieldSet the field set
784     */
785    private void addModelGroupSettings(
786        CmsContainerElementData elementBean,
787        CmsContainerPageElementPanel elementWidget,
788        CmsFieldSet fieldSet) {
789
790        Map<String, String> groupOptions = new LinkedHashMap<String, String>();
791        groupOptions.put(GroupOption.disabled.name(), GroupOption.disabled.getLabel());
792        groupOptions.put(GroupOption.copy.name(), GroupOption.copy.getLabel());
793        groupOptions.put(GroupOption.reuse.name(), GroupOption.reuse.getLabel());
794        m_modelGroupSelect = new CmsSelectBox(groupOptions);
795        if (elementWidget.isModelGroup()) {
796            if (Boolean.valueOf(elementBean.getSettings().get(CmsContainerElement.USE_AS_COPY_MODEL)).booleanValue()) {
797                m_modelGroupSelect.selectValue(GroupOption.copy.name());
798            } else {
799                m_modelGroupSelect.selectValue(GroupOption.reuse.name());
800            }
801        }
802        CmsFormRow selectRow = new CmsFormRow();
803        selectRow.getLabel().setText(Messages.get().key(Messages.GUI_USE_AS_MODEL_GROUP_LABEL_0));
804        selectRow.getWidgetContainer().add(m_modelGroupSelect);
805        fieldSet.add(selectRow);
806    }
807
808    /**
809     * Ensures the CSS snippet with the given ID is present.<p>
810     *
811     * @param formatterId the ID
812     * @param cssContent the CSS snippet
813     */
814    private native void ensureInlineCss(String formatterId, String cssContent)/*-{
815        var styles = $wnd.document.styleSheets;
816        for (var i = 0; i < styles.length; i++) {
817            // IE uses the owningElement property
818            var styleNode = styles[i].owningElement ? styles[i].owningElement
819                    : styles[i].ownerNode;
820            if (styleNode != null && styleNode.rel == formatterId) {
821                // inline css is present
822                return;
823            }
824        }
825        // include inline css into head
826        var headID = $wnd.document.getElementsByTagName("head")[0];
827        var cssNode = $wnd.document.createElement('style');
828        cssNode.type = 'text/css';
829        cssNode.rel = formatterId;
830        if (cssNode.styleSheet) {
831            // in case of IE
832            cssNode.styleSheet.cssText = cssContent;
833        } else {
834            // otherwise
835            cssNode.appendChild(document.createTextNode(cssContent));
836        }
837        headID.appendChild(cssNode);
838    }-*/;
839}