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            && ((m_controller.getModelGroupElementId() == null)
287                || CmsContainerpageController.getServerId(elementBean.getClientId()).equals(
288                    m_controller.getModelGroupElementId()));
289        boolean isDeveloper = CmsCoreProvider.get().getUserInfo().isDeveloper();
290        m_originalFormatter = currentFormatterConfig.getKeyOrId();
291
292        if (m_contextInfo.shouldShowElementTemplateContextSelection()
293            || isDeveloper
294            || m_elementBean.hasAlternativeFormatters(m_containerId)) {
295            CmsFieldsetFormFieldPanel fieldSetPanel = new FieldPanel(
296                infoBean,
297                Messages.get().key(Messages.GUI_SETTINGS_LEGEND_0));
298            formFieldPanel = fieldSetPanel;
299            if (m_elementBean.hasAlternativeFormatters(m_containerId)) {
300                CmsFieldSet formatterFieldset = new CmsFieldSet();
301                // insert as first field-set after the element info box
302                fieldSetPanel.getMainPanel().insert(formatterFieldset, 1);
303                formatterFieldset.setLegend(Messages.get().key(Messages.GUI_FORMATTERS_LEGEND_0));
304                formatterFieldset.getElement().getStyle().setMarginTop(10, Style.Unit.PX);
305                LinkedHashMap<String, String> formatters = new LinkedHashMap<String, String>();
306                CmsElementSettingsFormatterWidget formatterWidget = new CmsElementSettingsFormatterWidget();
307                m_formatterSelect = formatterWidget.getFormatterSelect();
308                CmsFormatterConfigCollection formattersForContainer = m_elementBean.getFormatters().get(m_containerId);
309                for (CmsFormatterConfig formatter : formattersForContainer) {
310                    formatters.put(formatter.getKeyOrId(), formatter.getLabel());
311                    m_formatterSelect.setTitle(formatter.getKeyOrId(), formatter.getJspRootPath());
312                }
313                m_formatterSelect.setItems(formatters);
314                String currentFormatterValue = m_elementBean.getFormatterConfig(m_containerId).getKeyOrId();
315                m_formatter = currentFormatterValue;
316                m_formatterSelect.selectValue(currentFormatterValue);
317                m_formatterSelect.addValueChangeHandler(new ValueChangeHandler<String>() {
318
319                    public void onValueChange(ValueChangeEvent<String> event) {
320
321                        onFormatterChange(event.getValue());
322                    }
323                });
324
325                // set up formatter help tooltip
326                final FlowPanel help = formatterWidget.getHelp();
327                for (String style : CmsFormRow.ICON_STYLES) {
328                    help.addStyleName(style);
329                }
330                final Map<String, CmsFieldTooltip.Data> tooltips = Maps.newHashMap();
331                for (CmsFormatterConfig formatterConfig : formattersForContainer) {
332                    String description = formatterConfig.getDescription();
333                    if (description == null) {
334                        description = formatterConfig.getLabel();
335                    }
336                    tooltips.put(formatterConfig.getKeyOrId(), new Data(help, description, true));
337                }
338                Supplier<CmsFieldTooltip.Data> tooltipProvider = new Supplier<CmsFieldTooltip.Data>() {
339
340                    @SuppressWarnings("synthetic-access")
341                    public Data get() {
342
343                        return tooltips.get(m_formatter);
344                    }
345                };
346                CmsFormRow.installTooltipEventHandlers(help, tooltipProvider);
347                formatterFieldset.add(formatterWidget);
348            }
349            if (m_controller.getData().isModelPage() || isEditableModelGroup) {
350                CmsFieldSet modelGroupFieldSet = new CmsFieldSet();
351                modelGroupFieldSet.setLegend(Messages.get().key(Messages.GUI_CREATE_NEW_LEGEND_0
352
353                ));
354                modelGroupFieldSet.getElement().getStyle().setMarginTop(10, Unit.PX);
355
356                if (isEditableModelGroup && !elementWidget.hasModelGroupParent()) {
357                    addModelGroupSettings(elementBean, elementWidget, modelGroupFieldSet);
358                } else if (!elementWidget.isModelGroup()) {
359                    addCreateNewCheckbox(elementBean, modelGroupFieldSet);
360                }
361                if (modelGroupFieldSet.getWidgetCount() > 0) {
362                    fieldSetPanel.getMainPanel().insert(modelGroupFieldSet, 1);
363                }
364
365            } else if (elementWidget.isModelGroup()) {
366                CmsFieldSet modelGroupFieldSet = new CmsFieldSet();
367                modelGroupFieldSet.setLegend(Messages.get().key(Messages.GUI_CREATE_NEW_LEGEND_0
368
369                ));
370                modelGroupFieldSet.getElement().getStyle().setMarginTop(10, Unit.PX);
371                m_modelGroupBreakUp = new CmsCheckBox(Messages.get().key(Messages.GUI_MODEL_GROUP_BREAK_UP_0));
372                m_modelGroupBreakUp.setDisplayInline(false);
373                m_modelGroupBreakUp.getElement().getStyle().setMarginTop(7, Style.Unit.PX);
374                modelGroupFieldSet.add(m_modelGroupBreakUp);
375                fieldSetPanel.getMainPanel().insert(modelGroupFieldSet, 1);
376            }
377
378            if (m_contextInfo.shouldShowElementTemplateContextSelection()) {
379                String templateContexts = m_settings.get(CmsTemplateContextInfo.SETTING);
380                if (templateContexts == null) {
381                    templateContexts = CmsStringUtil.listAsString(
382                        new ArrayList<String>(
383                            CmsContainerpageController.get().getData().getTemplateContextInfo().getContextLabels().keySet()),
384                        "|");
385                } else if (templateContexts.equals(CmsTemplateContextInfo.EMPTY_VALUE)) {
386                    // translate "none" to an empty selection
387                    templateContexts = "";
388                }
389                m_settings.put(CmsTemplateContextInfo.SETTING, templateContexts);
390
391                CmsFieldSet contextsFieldset = new CmsFieldSet();
392                contextsFieldset.setLegend(m_contextInfo.getSettingDefinition().getNiceName());
393                contextsFieldset.getElement().getStyle().setMarginTop(10, Style.Unit.PX);
394                m_contextsWidget = new CmsMultiCheckBox(
395                    CmsStringUtil.splitOptions(m_contextInfo.getSettingDefinition().getWidgetConfiguration()));
396                for (CmsCheckBox checkbox : m_contextsWidget.getCheckboxes()) {
397                    Style checkboxStyle = checkbox.getElement().getStyle();
398                    checkbox.getButton().getElement().getStyle().setFontWeight(Style.FontWeight.NORMAL);
399                    checkboxStyle.setMarginTop(7, Style.Unit.PX);
400                }
401                m_contextsWidget.setFormValueAsString(m_settings.get(CmsTemplateContextInfo.SETTING));
402                m_contextsWidget.addValueChangeHandler(new ValueChangeHandler<String>() {
403
404                    public void onValueChange(ValueChangeEvent<String> event) {
405
406                        setTemplateContextChanged(true);
407                    }
408                });
409                contextsFieldset.add(m_contextsWidget);
410                fieldSetPanel.getMainPanel().add(contextsFieldset);
411            }
412        } else {
413            formFieldPanel = new CmsInfoBoxFormFieldPanel(infoBean);
414        }
415
416        CmsUUID serverId = null;
417        if (elementBean.isModelGroup()) {
418            serverId = elementBean.getModelGroupId();
419        } else {
420            String id = CmsContainerpageController.getServerId(elementBean.getClientId());
421            if (CmsUUID.isValidUUID(id) && !(new CmsUUID(id).isNullUUID())) {
422                serverId = new CmsUUID(id);
423            }
424        }
425        if (serverId != null) {
426            CmsContextMenuButton menuButton = new CmsContextMenuButton(
427                serverId,
428                new CmsDialogContextMenuHandler(),
429                AdeContext.resourceinfo);
430            menuButton.addStyleName(I_CmsLayoutBundle.INSTANCE.listItemWidgetCss().permaVisible());
431            formFieldPanel.getInfoWidget().addButton(menuButton);
432        }
433
434        getForm().setWidget(formFieldPanel);
435        formFieldPanel.addStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().formGradientBackground());
436        I_CmsFormSubmitHandler submitHandler = new I_CmsFormSubmitHandler() {
437
438            /**
439             * @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)
440             */
441            public void onSubmitForm(
442                CmsForm formParam,
443                final Map<String, String> fieldValues,
444                Set<String> editedFields) {
445
446                submitForm(formParam, fieldValues, editedFields);
447            }
448        };
449        CmsDialogFormHandler formHandler = new CmsDialogFormHandler();
450        formHandler.setSubmitHandler(submitHandler);
451        getForm().setFormHandler(formHandler);
452        formHandler.setDialog(this);
453        renderSettingsForm(
454            m_elementBean.getSettingConfig(m_containerId),
455            m_elementBean.getFormatterConfig(m_containerId).getNestedFormatterPrefixes());
456    }
457
458    /**
459     * @see org.opencms.gwt.client.ui.input.form.CmsFormDialog#center()
460     */
461    @Override
462    public void center() {
463
464        show();
465    }
466
467    /**
468     * @see org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetMultiFactory#createFormWidget(java.lang.String, java.util.Map, com.google.common.base.Optional)
469     */
470    public I_CmsFormWidget createFormWidget(
471        String key,
472        Map<String, String> widgetParams,
473        Optional<String> defaultValue) {
474
475        if (CmsSelectBox.WIDGET_TYPE.equals(key) || CmsSelectComboBox.WIDGET_TYPE.equals(key)) {
476            if ((defaultValue != null) && defaultValue.isPresent() && widgetParams.containsKey(defaultValue.get())) {
477                key = key + CmsSelectBox.NOTNULL_SUFFIX;
478            }
479            Map<String, String> newParams = new HashMap<>();
480            newParams.putAll(widgetParams);
481            newParams.put(CmsSelectBox.OPTION_RESIZABLE, "false");
482            widgetParams = newParams;
483        }
484
485        return CmsWidgetFactoryRegistry.instance().createFormWidget(key, widgetParams, defaultValue);
486    }
487
488    /**
489     * @see com.google.gwt.user.client.ui.PopupPanel#setPopupPosition(int, int)
490     */
491    @Override
492    public void setPopupPosition(int left, int top) {
493
494        // positioning handled via CSS
495    }
496
497    /**
498     * @see org.opencms.gwt.client.ui.input.form.CmsFormDialog#show()
499     */
500    @Override
501    public void show() {
502
503        super.show();
504        // positioning handled by CSS
505        getElement().getStyle().clearPosition();
506        getElement().getStyle().clearLeft();
507        getElement().getStyle().clearTop();
508
509    }
510
511    /**
512     * Returns if the template context has been changed.<p>
513     *
514     * @return <code>true</code> if the template context has been changed
515     */
516    boolean isTemplateContextChanged() {
517
518        return m_changedContext;
519    }
520
521    /**
522     * Handles the formatter selection changes.<p>
523     *
524     * @param formatterId the formatter id
525     */
526    void onFormatterChange(String formatterId) {
527
528        m_formatter = formatterId;
529        CmsFormatterConfig config = m_elementBean.getFormatters().get(m_containerId).get(formatterId);
530        renderSettingsForm(config.getSettingConfig(), config.getNestedFormatterPrefixes());
531    }
532
533    /**
534     * Renders the settings form.<p>
535     *
536     * @param settingsConfig the settings configuration
537     * @param nestedFormatterPrefixes the nested formatter prefixes
538     */
539    void renderSettingsForm(
540        Map<String, CmsXmlContentProperty> settingsConfig,
541        Map<String, String> nestedFormatterPrefixes) {
542
543        Map<String, String> presets = m_presets;
544        if (presets == null) {
545            presets = new HashMap<String, String>();
546        }
547        List<String> groups = new ArrayList<String>(getForm().getGroups());
548        for (String group : groups) {
549            getForm().removeGroup(group);
550        }
551
552        CmsFieldsetFormFieldPanel formFieldPanel = null;
553        if (getForm().getWidget() instanceof CmsFieldsetFormFieldPanel) {
554            formFieldPanel = ((CmsFieldsetFormFieldPanel)getForm().getWidget());
555        }
556        if ((formFieldPanel != null) && (nestedFormatterPrefixes != null) && !nestedFormatterPrefixes.isEmpty()) {
557            for (Entry<String, String> entry : nestedFormatterPrefixes.entrySet()) {
558                CmsFieldSet fieldSet = new CmsFieldSet();
559                fieldSet.setLegend(entry.getValue());
560                fieldSet.getElement().getStyle().setMarginTop(10, Style.Unit.PX);
561                formFieldPanel.addGroupFieldSet(entry.getKey(), fieldSet);
562            }
563        }
564        // using LinkedHashMap to preserve the order
565        Map<String, I_CmsFormField> formFields = new LinkedHashMap<String, I_CmsFormField>();
566        for (CmsXmlContentProperty propConfig : settingsConfig.values()) {
567            if (m_presets.containsKey(propConfig.getName())) {
568                // settings configured as presets on the container are not user-editable
569                continue;
570            }
571            CmsBasicFormField currentField = CmsBasicFormField.createField(
572                propConfig,
573                propConfig.getName(),
574                this,
575                Collections.<String, String> emptyMap(),
576                false);
577            formFields.put(propConfig.getName(), currentField);
578
579        }
580        for (I_CmsFormField field : formFields.values()) {
581
582            String fieldId = field.getId();
583            CmsXmlContentProperty propDef = settingsConfig.get(fieldId);
584            // skip hidden fields
585            if (!CmsGwtConstants.HIDDEN_SETTINGS_WIDGET_NAME.equals(propDef.getWidget())) {
586                String initialValue = m_settings.get(fieldId);
587                if (initialValue == null) {
588
589                    initialValue = propDef.getDefault();
590                }
591                String group = "";
592                if ((nestedFormatterPrefixes != null) && !nestedFormatterPrefixes.isEmpty()) {
593                    for (String prefix : nestedFormatterPrefixes.keySet()) {
594                        if (fieldId.startsWith(prefix)) {
595                            group = prefix;
596                            break;
597                        }
598                    }
599                }
600
601                getForm().addField(group, field, initialValue);
602            }
603        }
604        getForm().render();
605    }
606
607    /**
608     * Sets the template context changed flag.<p>
609     * @param changed the template context changed flag
610     */
611    void setTemplateContextChanged(boolean changed) {
612
613        m_changedContext = changed;
614    }
615
616    /**
617     * Submits the settings form.<p>
618     *
619     * @param formParam the form
620     * @param fieldValues the field values
621     * @param editedFields the changed fields
622     */
623    void submitForm(CmsForm formParam, final Map<String, String> fieldValues, Set<String> editedFields) {
624
625        String modelGroupId = null;
626
627        if (CmsInheritanceContainerEditor.getInstance() != null) {
628            CmsInheritanceContainerEditor.getInstance().onSettingsEdited();
629        }
630        if (m_contextsWidget != null) {
631            String newTemplateContexts = m_contextsWidget.getFormValueAsString();
632            if ((newTemplateContexts == null) || "".equals(newTemplateContexts)) {
633                newTemplateContexts = CmsTemplateContextInfo.EMPTY_VALUE;
634                // translate an empty selection to "none"
635            }
636            fieldValues.put(CmsTemplateContextInfo.SETTING, newTemplateContexts);
637        }
638        final boolean hasFormatterChanges;
639        if (m_formatterSelect != null) {
640            fieldValues.put(
641                CmsFormatterConfig.getSettingsKeyForContainer(m_containerId),
642                m_formatterSelect.getFormValueAsString());
643            hasFormatterChanges = true;
644        } else {
645            hasFormatterChanges = false;
646            if (m_originalFormatter != null) {
647                // in case there is only 1 formatter, we still want to send the formatter key to the server to avoid cases
648                // where the element is removed because no default formatter can be found in the active sitemap config.
649                fieldValues.put(CmsFormatterConfig.getSettingsKeyForContainer(m_containerId), m_originalFormatter);
650            }
651        }
652        if (m_createNewCheckBox != null) {
653            m_elementWidget.setCreateNew(m_createNewCheckBox.isChecked());
654            fieldValues.put(CmsContainerElement.CREATE_AS_NEW, Boolean.toString(m_createNewCheckBox.isChecked()));
655        }
656        if (m_modelGroupSelect != null) {
657            GroupOption group = GroupOption.valueOf(m_modelGroupSelect.getFormValueAsString());
658            switch (group) {
659                case disabled:
660                    fieldValues.put(CmsContainerElement.MODEL_GROUP_STATE, ModelGroupState.noGroup.name());
661                    fieldValues.put(CmsContainerElement.USE_AS_COPY_MODEL, Boolean.toString(false));
662                    break;
663                case copy:
664                    fieldValues.put(CmsContainerElement.MODEL_GROUP_STATE, ModelGroupState.isModelGroup.name());
665                    fieldValues.put(CmsContainerElement.USE_AS_COPY_MODEL, Boolean.toString(true));
666                    break;
667                case reuse:
668                    fieldValues.put(CmsContainerElement.MODEL_GROUP_STATE, ModelGroupState.isModelGroup.name());
669                    fieldValues.put(CmsContainerElement.USE_AS_COPY_MODEL, Boolean.toString(false));
670                    break;
671                default:
672                    break;
673            }
674            if (group != GroupOption.disabled) {
675                modelGroupId = CmsContainerpageController.getServerId(m_elementBean.getClientId());
676            }
677        }
678
679        if ((m_modelGroupBreakUp != null) && m_modelGroupBreakUp.isChecked()) {
680            fieldValues.put(CmsContainerElement.MODEL_GROUP_STATE, ModelGroupState.noGroup.name());
681        }
682
683        final Map<String, String> filteredFieldValues = new HashMap<String, String>();
684        for (Map.Entry<String, String> entry : fieldValues.entrySet()) {
685            String key = entry.getKey();
686            String value = entry.getValue();
687            if ((value != null) && (value.length() > 0)) {
688                filteredFieldValues.put(key, value);
689            }
690        }
691        final String changeModelGroupId = modelGroupId;
692        I_ReloadHandler reloadHandler = new I_ReloadHandler() {
693
694            CmsContainerPageElementPanel m_oldElement;
695            CmsContainerPageElementPanel m_newElement;
696
697            @Override
698            public void finish() {
699
700                if (isTemplateContextChanged()) {
701                    // if the context multiselect box isn't displayed, of course it can't change values,
702                    // and this code won't be executed.
703                    CmsContainerpageController.get().handleChangeTemplateContext(
704                        m_newElement,
705                        filteredFieldValues.get(CmsTemplateContextInfo.SETTING));
706                }
707                if (hasFormatterChanges) {
708                    updateCss();
709                }
710                if (m_newElement.getElement().getInnerHTML().contains(CmsGwtConstants.FORMATTER_RELOAD_MARKER)
711                    && !CmsContainerpageController.get().isGroupcontainerEditing()) {
712                    CmsContainerpageController.get().reloadPage();
713                }
714                if (m_modelGroupSelect != null) {
715                    m_controller.setModelGroupElementId(changeModelGroupId);
716                }
717                m_controller.sendElementEditedSettings(m_newElement, m_oldElement);
718            }
719
720            @Override
721            public void onReload(CmsContainerPageElementPanel oldElement, CmsContainerPageElementPanel newElement) {
722                m_oldElement = oldElement;
723                m_newElement = newElement;
724            }
725
726        } ;
727        m_controller.reloadElementWithSettings(
728            m_elementWidget,
729            m_elementBean.getClientId(),
730            filteredFieldValues,
731            reloadHandler);
732    }
733
734    /**
735     * Updates the CSS resources for the selected formatter.<p>
736     */
737    void updateCss() {
738
739        String formatterId = m_formatterSelect.getFormValueAsString();
740        CmsFormatterConfig formatter = m_elementBean.getFormatters().get(m_containerId).get(formatterId);
741        Set<String> cssResources = formatter.getCssResources();
742        for (String cssResource : cssResources) {
743            CmsDomUtil.ensureStyleSheetIncluded(cssResource);
744        }
745        if (formatter.hasInlineCss()) {
746            ensureInlineCss(formatterId, formatter.getInlineCss());
747        }
748    }
749
750    /**
751     * Adds the create new checkbox to the given field set.<p>
752     *
753     * @param elementBean the element bean
754     * @param fieldSet the field set
755     */
756    private void addCreateNewCheckbox(CmsContainerElementData elementBean, CmsFieldSet fieldSet) {
757
758        m_createNewCheckBox = new CmsCheckBox(Messages.get().key(Messages.GUI_CREATE_NEW_LABEL_0));
759        m_createNewCheckBox.setDisplayInline(false);
760        m_createNewCheckBox.getElement().getStyle().setMarginTop(7, Style.Unit.PX);
761        m_createNewCheckBox.setChecked(elementBean.isCreateNew());
762        fieldSet.add(m_createNewCheckBox);
763    }
764
765    /**
766     * Adds the model group settings fields to the given field set.<p>
767     *
768     * @param elementBean the element bean
769     * @param elementWidget the element widget
770     * @param fieldSet the field set
771     */
772    private void addModelGroupSettings(
773        CmsContainerElementData elementBean,
774        CmsContainerPageElementPanel elementWidget,
775        CmsFieldSet fieldSet) {
776
777        Map<String, String> groupOptions = new LinkedHashMap<String, String>();
778        groupOptions.put(GroupOption.disabled.name(), GroupOption.disabled.getLabel());
779        groupOptions.put(GroupOption.copy.name(), GroupOption.copy.getLabel());
780        groupOptions.put(GroupOption.reuse.name(), GroupOption.reuse.getLabel());
781        m_modelGroupSelect = new CmsSelectBox(groupOptions);
782        if (elementWidget.isModelGroup()) {
783            if (Boolean.valueOf(elementBean.getSettings().get(CmsContainerElement.USE_AS_COPY_MODEL)).booleanValue()) {
784                m_modelGroupSelect.selectValue(GroupOption.copy.name());
785            } else {
786                m_modelGroupSelect.selectValue(GroupOption.reuse.name());
787            }
788        }
789        CmsFormRow selectRow = new CmsFormRow();
790        selectRow.getLabel().setText(Messages.get().key(Messages.GUI_USE_AS_MODEL_GROUP_LABEL_0));
791        selectRow.getWidgetContainer().add(m_modelGroupSelect);
792        fieldSet.add(selectRow);
793    }
794
795    /**
796     * Ensures the CSS snippet with the given ID is present.<p>
797     *
798     * @param formatterId the ID
799     * @param cssContent the CSS snippet
800     */
801    private native void ensureInlineCss(String formatterId, String cssContent)/*-{
802                var styles = $wnd.document.styleSheets;
803                for (var i = 0; i < styles.length; i++) {
804                        // IE uses the owningElement property
805                        var styleNode = styles[i].owningElement ? styles[i].owningElement
806                                        : styles[i].ownerNode;
807                        if (styleNode != null && styleNode.rel == formatterId) {
808                                // inline css is present
809                                return;
810                        }
811                }
812                // include inline css into head
813                var headID = $wnd.document.getElementsByTagName("head")[0];
814                var cssNode = $wnd.document.createElement('style');
815                cssNode.type = 'text/css';
816                cssNode.rel = formatterId;
817                if (cssNode.styleSheet) {
818                        // in case of IE
819                        cssNode.styleSheet.cssText = cssContent;
820                } else {
821                        // otherwise
822                        cssNode.appendChild(document.createTextNode(cssContent));
823                }
824                headID.appendChild(cssNode);
825    }-*/;
826}