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