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.sitemap.client.edit;
029
030import org.opencms.ade.sitemap.client.Messages;
031import org.opencms.gwt.client.property.A_CmsPropertyEditor;
032import org.opencms.gwt.client.property.I_CmsPropertyEditorHandler;
033import org.opencms.gwt.client.ui.input.I_CmsFormWidget;
034import org.opencms.gwt.client.ui.input.I_CmsHasGhostValue;
035import org.opencms.gwt.client.ui.input.form.A_CmsFormFieldPanel;
036import org.opencms.gwt.client.ui.input.form.CmsBasicFormField;
037import org.opencms.gwt.client.ui.input.form.CmsInfoBoxFormFieldPanel;
038import org.opencms.gwt.shared.property.CmsClientProperty;
039import org.opencms.gwt.shared.property.CmsPathValue;
040import org.opencms.util.CmsStringUtil;
041import org.opencms.xml.content.CmsXmlContentProperty;
042
043import java.util.ArrayList;
044import java.util.Arrays;
045import java.util.Collections;
046import java.util.List;
047import java.util.Map;
048
049import com.google.gwt.user.client.ui.Widget;
050
051/**
052 * Sitemap entry editor class for the navigation mode.<p>
053 *
054 * @since 8.0.0
055 */
056public class CmsNavModePropertyEditor extends A_CmsPropertyEditor {
057
058    /** The 'split mode' to use for rendering fields. For some property fields, we may want to render two fields, one for the folder and one for the index.html, and this enum is used to tell the rendering function which we are currently rendering. */
059    enum SplitMode {
060        /** The property is not split. */
061        none,
062
063        /** The property is split, and we are rendering the field for the parent folder. */
064        parent,
065
066        /** The property is split, and we are rendering the field for the index.html. */
067        child;
068    }
069
070    /**
071    * Creates a new instance.<p>
072    *
073    * @param propertyConfig the property configuration
074    * @param handler the entry editor handler
075    */
076    public CmsNavModePropertyEditor(
077        Map<String, CmsXmlContentProperty> propertyConfig,
078        I_CmsPropertyEditorHandler handler) {
079
080        super(propertyConfig, handler);
081    }
082
083    /**
084     * @see org.opencms.gwt.client.property.A_CmsPropertyEditor#buildFields()
085     */
086    @Override
087    public void buildFields() {
088
089        Map<String, CmsClientProperty> ownProps = m_handler.getOwnProperties();
090        Map<String, CmsClientProperty> defaultFileProps = m_handler.getDefaultFileProperties();
091
092        String entryId = m_handler.getId().toString();
093        String defaultFileId = toStringOrNull(m_handler.getDefaultFileId());
094        boolean splitTitle = false;
095        String navText = "";
096        String title = "";
097        for (String key : Arrays.asList(CmsClientProperty.PROPERTY_NAVTEXT, CmsClientProperty.PROPERTY_TITLE)) {
098            CmsClientProperty prop = ownProps.get(key);
099            if (prop != null) {
100                String value = prop.getEffectiveValue();
101                if (value == null) {
102                    value = "";
103                }
104                if (CmsClientProperty.PROPERTY_NAVTEXT.equals(key)) {
105                    navText = value;
106                } else {
107                    title = value;
108                }
109            }
110        }
111        // if we have both a folder and a default file and either the navtext is different from the title,
112        // or the title is empty, split title field into two fields, one for the folder and one for the default file
113        splitTitle = (defaultFileId != null) && !(navText.equals(title) || "".equals(title));
114
115        List<String> keys = new ArrayList<String>(m_propertyConfig.keySet());
116        moveToTop(keys, CmsClientProperty.PROPERTY_NAVTEXT);
117        moveToTop(keys, CmsClientProperty.PROPERTY_DESCRIPTION);
118        moveToTop(keys, CmsClientProperty.PROPERTY_TITLE);
119        for (String propName : keys) {
120            if (splitTitle && CmsClientProperty.PROPERTY_TITLE.equals(propName)) {
121                for (SplitMode mode : Arrays.asList(SplitMode.parent, SplitMode.child)) {
122                    buildSimpleField(entryId, defaultFileId, ownProps, defaultFileProps, propName, mode);
123                }
124            } else {
125                buildSimpleField(entryId, defaultFileId, ownProps, defaultFileProps, propName, SplitMode.none);
126            }
127
128        }
129    }
130
131    /**
132     * @see org.opencms.gwt.client.property.A_CmsPropertyEditor#setupFieldContainer()
133     */
134    @Override
135    protected void setupFieldContainer() {
136
137        m_form.setWidget(new CmsInfoBoxFormFieldPanel(m_handler.getPageInfo()));
138    }
139
140    /**
141     * Builds a single form field.<p>
142     *
143    
144     * @param entryId the entry id
145     * @param defaultFileId the default file id
146     * @param ownProps the entry's own properties
147     * @param defaultFileProps the default file properties
148     * @param propName the property name
149     */
150    private void buildSimpleField(
151        String entryId,
152        String defaultFileId,
153        Map<String, CmsClientProperty> ownProps,
154        Map<String, CmsClientProperty> defaultFileProps,
155        String propName,
156        SplitMode splitMode) {
157
158        CmsXmlContentProperty propDef = m_propertyConfig.get(propName);
159        CmsClientProperty fileProp = defaultFileProps == null ? null : defaultFileProps.get(propName);
160        CmsClientProperty ownProp = ownProps.get(propName);
161        CmsPathValue pathValue = null;
162        if (splitMode == SplitMode.parent) {
163            if (ownProp != null) {
164                pathValue = ownProp.getPathValue().prepend(entryId + "/" + propName);
165            } else {
166                pathValue = new CmsPathValue(
167                    "",
168                    entryId + "/" + propName + "/" + CmsClientProperty.PATH_STRUCTURE_VALUE);
169            }
170        } else if (splitMode == SplitMode.child) {
171            if (fileProp != null) {
172                pathValue = fileProp.getPathValue().prepend(defaultFileId + "/" + propName);
173            } else {
174                pathValue = new CmsPathValue(
175                    "",
176                    defaultFileId + "/" + propName + "/" + CmsClientProperty.PATH_STRUCTURE_VALUE);
177            }
178        } else {
179            if (!CmsClientProperty.isPropertyEmpty(fileProp)) {
180                pathValue = fileProp.getPathValue().prepend(defaultFileId + "/" + propName);
181            } else if (!CmsClientProperty.isPropertyEmpty(ownProp)) {
182                pathValue = ownProp.getPathValue().prepend(entryId + "/" + propName);
183            } else {
184                String targetId = null;
185                if (propDef.isPreferFolder() || (m_handler.getDefaultFileId() == null)) {
186                    targetId = entryId;
187                } else {
188                    targetId = m_handler.getDefaultFileId().toString();
189                }
190                pathValue = new CmsPathValue(
191                    "",
192                    targetId + "/" + propName + "/" + CmsClientProperty.PATH_STRUCTURE_VALUE);
193            }
194        }
195        boolean alwaysAllowEmpty = !propName.equals(CmsClientProperty.PROPERTY_NAVTEXT);
196        //CHECK: should we really generally allow empty fields other than NavText to be empty?
197
198        CmsBasicFormField field = CmsBasicFormField.createField(
199            propDef,
200            pathValue.getPath(),
201            this,
202            Collections.<String, String> emptyMap(),
203            alwaysAllowEmpty);
204        CmsClientProperty inheritedProperty = m_handler.getInheritedProperty(propName);
205        String inherited = (inheritedProperty == null) ? null : inheritedProperty.getEffectiveValue();
206        if (inheritedProperty != null) {
207            String message = Messages.get().key(
208                Messages.GUI_PROPERTY_ORIGIN_2,
209                inheritedProperty.getOrigin(),
210                inherited);
211            ((Widget)field.getWidget()).setTitle(message);
212        }
213        I_CmsFormWidget w = field.getWidget();
214        // model binding not necessary here
215        String initialValue = pathValue.getValue();
216
217        boolean ghost = CmsStringUtil.isEmptyOrWhitespaceOnly(pathValue.getValue());
218        if (w instanceof I_CmsHasGhostValue) {
219            ((I_CmsHasGhostValue)w).setGhostValue(inherited, ghost);
220            if (ghost) {
221                initialValue = null;
222            }
223        }
224        if (ghost && (inheritedProperty != null)) {
225            String message = org.opencms.gwt.client.Messages.get().key(
226                org.opencms.gwt.client.Messages.GUI_ORIGIN_INHERITED_1,
227                inheritedProperty.getOrigin());
228            field.getLayoutData().put("info", message);
229        }
230        if (splitMode == SplitMode.parent) {
231            field.getLayoutData().put(A_CmsFormFieldPanel.LAYOUT_TAG, Messages.get().key(Messages.GUI_TAG_FOLDER_0));
232        } else if (splitMode == SplitMode.child) {
233
234            String path = m_handler.getDefaultFilePath();
235            int slashPos = path.lastIndexOf("/");
236            String name = slashPos > -1 ? path.substring(slashPos + 1) : path;
237            if (!name.toLowerCase().endsWith(".html")) {
238                name = "index.html";
239            }
240            field.getLayoutData().put(A_CmsFormFieldPanel.LAYOUT_TAG, name);
241        }
242
243        m_form.addField(m_form.getWidget().getDefaultGroup(), field, initialValue);
244    }
245
246    /**
247     * Moves the given property name to the top of the keys if present.<p>
248     *
249     * @param keys the list of keys
250     * @param propertyName the property name to move
251     */
252    private void moveToTop(List<String> keys, String propertyName) {
253
254        if (keys.contains(propertyName)) {
255            keys.remove(propertyName);
256            keys.add(0, propertyName);
257        }
258    }
259
260    /**
261     * Helper method which converts an object to a string and returns null if it is null.<p>
262     *
263     * @param obj the object for which to return the string
264     *
265     * @return the string representation or null
266     */
267    private String toStringOrNull(Object obj) {
268
269        return obj == null ? null : obj.toString();
270    }
271
272}