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.widgets;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsProperty;
033import org.opencms.file.CmsPropertyDefinition;
034import org.opencms.file.CmsResource;
035import org.opencms.i18n.CmsMessages;
036import org.opencms.json.JSONArray;
037import org.opencms.json.JSONException;
038import org.opencms.json.JSONObject;
039import org.opencms.loader.CmsTemplateLoaderFacade;
040import org.opencms.main.CmsException;
041import org.opencms.main.CmsLog;
042import org.opencms.main.OpenCms;
043import org.opencms.util.CmsStringUtil;
044import org.opencms.workplace.CmsDialog;
045import org.opencms.workplace.CmsWorkplaceMessages;
046import org.opencms.xml.containerpage.I_CmsFormatterBean;
047import org.opencms.xml.types.A_CmsXmlContentValue;
048import org.opencms.xml.types.CmsXmlDisplayFormatterValue;
049
050import java.util.ArrayList;
051import java.util.Arrays;
052import java.util.Collections;
053import java.util.Comparator;
054import java.util.HashSet;
055import java.util.List;
056import java.util.Locale;
057import java.util.Set;
058
059import org.apache.commons.logging.Log;
060
061import com.google.common.collect.Sets;
062
063/**
064 * Widget to select a type and formatter combination.<p>
065 */
066public class CmsDisplayTypeSelectWidget extends CmsSelectWidget {
067
068    /**
069     * Formatter option comparator, sorting by type name and rank.<p>
070     */
071    class FormatterComparator implements Comparator<FormatterOption> {
072
073        /**
074         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
075         */
076        public int compare(FormatterOption o1, FormatterOption o2) {
077
078            return o1.m_typeName.equals(o2.m_typeName) ? o2.m_rank - o1.m_rank : o1.m_typeName.compareTo(o2.m_typeName);
079        }
080    }
081
082    /**
083     * Formatter select option.<p>
084     */
085    class FormatterOption {
086
087        /** the display type. */
088        String m_displayType;
089
090        /** The option key. */
091        String m_key;
092
093        /** The option label. */
094        String m_label;
095
096        /** The formatter rank. */
097        int m_rank;
098
099        /** The type name. */
100        String m_typeName;
101
102        /**
103         * Constructor.<p>
104         *
105         * @param key the option key
106         * @param typeName the type name
107         * @param displayType the display type
108         * @param label the option label
109         * @param rank the formatter rank
110         */
111        FormatterOption(String key, String typeName, String displayType, String label, int rank) {
112
113            m_key = key;
114            m_typeName = typeName;
115            m_displayType = displayType;
116            m_label = label;
117            m_rank = rank;
118        }
119    }
120
121    /** The match display types key. */
122    public static final String MATCH_TYPES_KEY = "matchTypes";
123
124    /** The logger instance for this class. */
125    private static final Log LOG = CmsLog.getLog(CmsDisplayTypeSelectWidget.class);
126
127    /** The display types split regex. */
128    private static final String TYPES_SPLITTER = " *, *";
129
130    /** The display container type configuration. */
131    private String m_displayContainerTypeConfig;
132
133    /** Flag indicating display types should be matched. */
134    private boolean m_matchTypes;
135
136    /** The configuration String. */
137    private String m_config;
138
139    /**
140     * @see org.opencms.widgets.A_CmsSelectWidget#getConfiguration()
141     */
142    @Override
143    public String getConfiguration() {
144
145        return m_config;
146    }
147
148    /**
149     * @see org.opencms.widgets.A_CmsSelectWidget#getConfiguration(org.opencms.file.CmsObject, org.opencms.xml.types.A_CmsXmlContentValue, org.opencms.i18n.CmsMessages, org.opencms.file.CmsResource, java.util.Locale)
150     */
151    @Override
152    public String getConfiguration(
153        CmsObject cms,
154        A_CmsXmlContentValue schemaType,
155        CmsMessages messages,
156        CmsResource resource,
157        Locale contentLocale) {
158
159        List<FormatterOption> options = getFormatterOptions(cms, resource);
160        JSONObject config = new JSONObject();
161        try {
162            String path;
163            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(schemaType.getPath())) {
164                path = CmsStringUtil.joinPaths(schemaType.getPath(), schemaType.getName());
165            } else {
166                path = schemaType.getName();
167            }
168
169            config.put("valuePath", path);
170            config.put("matchTypes", m_matchTypes);
171            config.put("emptyLabel", messages.key(Messages.GUI_DISPLAYTYPE_SELECT_0));
172            JSONArray optionArray = new JSONArray();
173            for (FormatterOption option : options) {
174                JSONObject opt = new JSONObject();
175                try {
176                    opt.put("value", option.m_key);
177                    opt.put("label", option.m_label);
178                    opt.put("displayType", option.m_displayType);
179                    optionArray.put(opt);
180                } catch (JSONException e) {
181                    LOG.error(e.getLocalizedMessage(), e);
182                }
183            }
184            config.put("options", optionArray);
185        } catch (JSONException e) {
186            LOG.error(e.getLocalizedMessage(), e);
187        }
188        return config.toString();
189    }
190
191    /**
192     * @see org.opencms.widgets.CmsSelectWidget#getWidgetName()
193     */
194    @Override
195    public String getWidgetName() {
196
197        return CmsDisplayTypeSelectWidget.class.getName();
198    }
199
200    /**
201     * @see org.opencms.widgets.CmsSelectWidget#newInstance()
202     */
203    @Override
204    public I_CmsWidget newInstance() {
205
206        return new CmsDisplayTypeSelectWidget();
207    }
208
209    /**
210     * @see org.opencms.widgets.A_CmsSelectWidget#setConfiguration(java.lang.String)
211     */
212    @Override
213    public void setConfiguration(String configuration) {
214
215        m_config = configuration;
216        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(configuration)) {
217            String[] conf = configuration.split("\\|");
218            for (int i = 0; i < conf.length; i++) {
219                if (MATCH_TYPES_KEY.equals(conf[i])) {
220                    m_matchTypes = true;
221                } else {
222                    m_displayContainerTypeConfig = conf[i];
223                }
224
225            }
226        }
227    }
228
229    /**
230     * @see org.opencms.widgets.A_CmsSelectWidget#parseSelectOptions(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter)
231     */
232    @Override
233    protected List<CmsSelectWidgetOption> parseSelectOptions(
234        CmsObject cms,
235        I_CmsWidgetDialog widgetDialog,
236        I_CmsWidgetParameter param) {
237
238        CmsResource resource = null;
239        List<CmsSelectWidgetOption> result = new ArrayList<CmsSelectWidgetOption>();
240        try {
241            if (widgetDialog instanceof CmsDummyWidgetDialog) {
242                resource = ((CmsDummyWidgetDialog)widgetDialog).getResource();
243            } else if (widgetDialog instanceof CmsDialog) {
244                String sitePath = ((CmsDialog)widgetDialog).getParamResource();
245                if (sitePath != null) {
246
247                    resource = cms.readResource(sitePath);
248
249                }
250            }
251            for (FormatterOption option : getFormatterOptions(cms, resource)) {
252                result.add(new CmsSelectWidgetOption(option.m_key, false, option.m_label));
253            }
254        } catch (Exception e) {
255            LOG.error(e.getLocalizedMessage(), e);
256        }
257        return result;
258    }
259
260    /**
261     * Evaluates the display type of the given formatter.<p>
262     *
263     * @param formatter the formatter configuration bean
264     *
265     * @return the display type
266     */
267    private String getDisplayType(I_CmsFormatterBean formatter) {
268
269        return formatter.getDisplayType();
270    }
271
272    /**
273     * Returns the available formatter options.<p>
274     *
275     * @param cms the cms context
276     * @param resource the edited resource
277     *
278     * @return the formatter options
279     */
280    private List<FormatterOption> getFormatterOptions(CmsObject cms, CmsResource resource) {
281
282        List<FormatterOption> options = new ArrayList<FormatterOption>();
283        Set<String> containerTypes = new HashSet<>();
284        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_displayContainerTypeConfig)) {
285            String types = null;
286
287            if (CmsPropertyDefinition.PROPERTY_TEMPLATE_DISPLAY_TYPES.equals(m_displayContainerTypeConfig)) {
288                try {
289                    CmsProperty prop = cms.readPropertyObject(
290                        resource,
291                        CmsPropertyDefinition.PROPERTY_TEMPLATE_DISPLAY_TYPES,
292                        true);
293                    String propValue = prop.getValue();
294                    if (!CmsStringUtil.isEmptyOrWhitespaceOnly(propValue)) {
295                        types = propValue;
296                    } else {
297                        // look up template property
298                        try {
299                            CmsTemplateLoaderFacade loaderFacade = OpenCms.getResourceManager().getTemplateLoaderFacade(
300                                cms,
301                                null,
302                                resource,
303                                CmsPropertyDefinition.PROPERTY_TEMPLATE);
304                            CmsResource template = loaderFacade.getLoaderStartResource();
305                            if (template != null) {
306                                prop = cms.readPropertyObject(
307                                    template,
308                                    CmsPropertyDefinition.PROPERTY_TEMPLATE_DISPLAY_TYPES,
309                                    false);
310                                propValue = prop.getValue();
311                                if (!CmsStringUtil.isEmptyOrWhitespaceOnly(propValue)) {
312                                    types = propValue;
313                                }
314                            }
315                        } catch (Exception ex) {
316                            LOG.debug(ex.getMessage(), ex);
317                        }
318                    }
319                } catch (CmsException e) {
320                    LOG.warn(e.getLocalizedMessage(), e);
321                }
322            } else {
323                types = m_displayContainerTypeConfig;
324            }
325            if (types != null) {
326                containerTypes.addAll(Arrays.asList(types.split(TYPES_SPLITTER)));
327            }
328        }
329        CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(cms, resource.getRootPath());
330
331        if (config != null) {
332            Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
333            for (I_CmsFormatterBean formatter : config.getDisplayFormatters(cms)) {
334                if (!containerTypes.isEmpty()) {
335                    if (Sets.intersection(containerTypes, formatter.getContainerTypes()).isEmpty()) {
336                        continue;
337                    }
338                }
339                for (String typeName : formatter.getResourceTypeNames()) {
340                    String label = formatter.getNiceName(wpLocale)
341                        + " ("
342                        + CmsWorkplaceMessages.getResourceTypeName(wpLocale, typeName)
343                        + ")";
344                    options.add(
345                        new FormatterOption(
346                            typeName + CmsXmlDisplayFormatterValue.SEPARATOR + formatter.getId(),
347                            typeName,
348                            getDisplayType(formatter),
349                            label,
350                            formatter.getRank()));
351                }
352            }
353        }
354        Collections.sort(options, new FormatterComparator());
355        return options;
356    }
357}