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 GmbH & Co. KG, 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.workplace.editors;
029
030import org.opencms.file.CmsFile;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsPropertyDefinition;
033import org.opencms.file.CmsResource;
034import org.opencms.file.CmsResourceFilter;
035import org.opencms.i18n.CmsLocaleManager;
036import org.opencms.jsp.CmsJspActionElement;
037import org.opencms.main.CmsException;
038import org.opencms.main.CmsLog;
039import org.opencms.util.CmsStringUtil;
040import org.opencms.workplace.CmsDialog;
041import org.opencms.workplace.CmsWorkplaceSettings;
042import org.opencms.xml.page.CmsXmlPage;
043import org.opencms.xml.page.CmsXmlPageFactory;
044
045import java.util.ArrayList;
046import java.util.Collections;
047import java.util.Iterator;
048import java.util.List;
049import java.util.Locale;
050
051import javax.servlet.http.HttpServletRequest;
052import javax.servlet.http.HttpServletResponse;
053import javax.servlet.jsp.JspException;
054import javax.servlet.jsp.PageContext;
055
056import org.apache.commons.logging.Log;
057
058/**
059 * Provides methods for the editor elements dialog.<p>
060 *
061 * The following files use this class:
062 * <ul>
063 * <li>/jsp/editors/dialogs/elements.html
064 * </ul>
065 * <p>
066 *
067 * @since 6.0.0
068 */
069public class CmsDialogElements extends CmsDialog {
070
071    /** Value for the action: update the elements of the page. */
072    public static final int ACTION_UPDATE_ELEMENTS = 210;
073
074    /** The dialog type. */
075    public static final String DIALOG_TYPE = "elementselector";
076
077    /** Request parameter value for the action: update the elements of the page. */
078    public static final String DIALOG_UPDATE_ELEMENTS = "updateelements";
079
080    /** Prefix for the html input field for the body. */
081    public static final String PREFIX_PARAM_BODY = "element-";
082
083    /** The log object for this class. */
084    private static final Log LOG = CmsLog.getLog(CmsDialogElements.class);
085
086    /** Stores the element to change to after an element update operation. */
087    private String m_changeElement;
088
089    /** List used to store information of all possible elements of the page. */
090    private List<CmsDialogElement> m_elementList;
091
092    /** The element locale. */
093    private Locale m_elementLocale;
094
095    // Special parameters used by this dialog
096    /** The element language parameter. */
097    private String m_paramElementlanguage;
098
099    /** The element name parameter. */
100    private String m_paramElementname;
101
102    /** The temporary file parameter. */
103    private String m_paramTempFile;
104
105    /**
106     * Public constructor.<p>
107     *
108     * @param jsp an initialized JSP action element
109     */
110    public CmsDialogElements(CmsJspActionElement jsp) {
111
112        super(jsp);
113        m_changeElement = "";
114    }
115
116    /**
117     * Public constructor with JSP variables.<p>
118     *
119     * @param context the JSP page context
120     * @param req the JSP request
121     * @param res the JSP response
122     */
123    public CmsDialogElements(PageContext context, HttpServletRequest req, HttpServletResponse res) {
124
125        this(new CmsJspActionElement(context, req, res));
126        m_changeElement = "";
127    }
128
129    /**
130     * Creates a list of possible elements of a template from the template property "template-elements"
131     * and the elements available in the provided xmlPage.<p>
132     *
133     * @param cms the CmsObject
134     * @param xmlPage the resource to read the elements from
135     * @param xmlPageUri the URI of the resource to read the template property from
136     * @param locale the current element locale
137     * @return the list of elements in a String array with element name, nice name (if present) and mandatory flag
138     */
139    public static List<CmsDialogElement> computeElements(
140        CmsObject cms,
141        CmsXmlPage xmlPage,
142        String xmlPageUri,
143        Locale locale) {
144
145        List<CmsDialogElement> result = new ArrayList<CmsDialogElement>();
146
147        if (xmlPage != null) {
148            List<String> elementNames = xmlPage.getNames(locale);
149
150            Iterator<String> i = elementNames.iterator();
151            while (i.hasNext()) {
152                String name = i.next();
153                CmsDialogElement element = new CmsDialogElement(name, null, false, false, true);
154                result.add(element);
155            }
156        }
157
158        String currentTemplate = null;
159        try {
160            currentTemplate = cms.readPropertyObject(
161                xmlPageUri,
162                CmsPropertyDefinition.PROPERTY_TEMPLATE,
163                true).getValue();
164        } catch (CmsException e) {
165            if (LOG.isWarnEnabled()) {
166                LOG.warn(e.getLocalizedMessage(), e);
167            }
168        }
169        if ((currentTemplate != null) && (currentTemplate.length() > 0)) {
170            // template found, check template-elements property
171            String elements = null;
172            try {
173                // read the property from the template file
174                elements = cms.readPropertyObject(
175                    currentTemplate,
176                    CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS,
177                    false).getValue(null);
178            } catch (CmsException e) {
179                if (LOG.isWarnEnabled()) {
180                    LOG.warn(e.getLocalizedMessage(), e);
181                }
182            }
183            if (elements != null) {
184                // elements are defined on template file, merge with available elements
185                List<String> tokens = CmsStringUtil.splitAsList(elements, ',', true);
186                Iterator<String> it = tokens.iterator();
187                while (it.hasNext()) {
188                    String currentElement = it.next();
189                    String niceName = null;
190                    boolean mandatory = false;
191                    int sepIndex = currentElement.indexOf("|");
192                    if (sepIndex != -1) {
193                        // nice name found for current element, extract it
194                        niceName = currentElement.substring(sepIndex + 1);
195                        currentElement = currentElement.substring(0, sepIndex);
196                    }
197                    if (currentElement.endsWith("*")) {
198                        // element is mandatory
199                        mandatory = true;
200                        currentElement = currentElement.substring(0, currentElement.length() - 1);
201                    }
202
203                    CmsDialogElement element = new CmsDialogElement(currentElement, niceName, mandatory, true, false);
204                    if (result.contains(element)) {
205                        element.setExisting(true);
206                        result.remove(element);
207                    }
208                    result.add(element);
209                }
210            }
211        }
212
213        Collections.sort(result);
214        return result;
215    }
216
217    /**
218     * Creates a list of possible elements of a template from the template property "template-elements"
219     * and the elements available in the provided resource file.<p>
220     *
221     * @param cms the CmsObject
222     * @param xmlPageUri the resource to read the elements from
223     * @param locale the current element locale
224     * @return the list of elements in a String array with element name, nice name (if present) and mandatory flag
225     */
226    public static List<CmsDialogElement> computeElements(CmsObject cms, String xmlPageUri, Locale locale) {
227
228        CmsXmlPage page = null;
229        try {
230            // read the xmlpage file
231            CmsFile pageFile = cms.readFile(xmlPageUri, CmsResourceFilter.IGNORE_EXPIRATION);
232            page = CmsXmlPageFactory.unmarshal(cms, pageFile);
233        } catch (CmsException e) {
234            LOG.warn(Messages.get().getBundle().key(Messages.LOG_READ_XMLPAGE_FAILED_1, xmlPageUri), e);
235            // xmlpage will be null, only "template-elements" property on template will be checked
236        }
237        return computeElements(cms, page, xmlPageUri, locale);
238    }
239
240    /**
241     * Updates the enabled/diabled status of all elements of the current page.<p>
242     *
243     * @throws JspException if there is an error including the error page
244     */
245    public void actionUpdateElements() throws JspException {
246
247        try {
248            List<CmsDialogElement> elementList = computeElements();
249            CmsFile file = getCms().readFile(getParamTempfile(), CmsResourceFilter.IGNORE_EXPIRATION);
250            CmsXmlPage page = CmsXmlPageFactory.unmarshal(getCms(), file);
251            boolean foundMandatory = false;
252            m_changeElement = "";
253            Iterator<CmsDialogElement> i = elementList.iterator();
254            while (i.hasNext()) {
255                // get the current list element
256                CmsDialogElement element = i.next();
257                if (element.isMandantory()
258                    || element.getName().equals(getParamElementname())
259                    || Boolean.valueOf(
260                        getJsp().getRequest().getParameter(PREFIX_PARAM_BODY + element.getName())).booleanValue()) {
261                    if (!element.isExisting()) {
262                        // create element in order to enable it properly
263                        page.addValue(element.getName(), getElementLocale());
264                    }
265                    page.setEnabled(element.getName(), getElementLocale(), true);
266                    if (element.isMandantory() && !foundMandatory) {
267                        m_changeElement = element.getName();
268                        foundMandatory = true;
269                    }
270                } else {
271                    if (element.isExisting()) {
272                        // remove element if it is already existing
273                        page.removeValue(element.getName(), getElementLocale());
274                    }
275                }
276            }
277            // write the temporary file
278            file.setContents(page.marshal());
279            getCms().writeFile(file);
280            // set the javascript functions which should be executed
281            if (page.isEnabled(getParamElementname(), getElementLocale())) {
282                m_changeElement = getParamElementname();
283            } else if (!foundMandatory) {
284                if (elementList.size() > 0) {
285                    m_changeElement = elementList.get(0).getName();
286                }
287            }
288        } catch (Throwable e) {
289            // show error dialog
290            setParamMessage(Messages.get().getBundle(getLocale()).key(Messages.ERR_UPDATE_ELEMENTS_0));
291            includeErrorpage(this, e);
292        }
293    }
294
295    /**
296     * Builds the html String for a form list of all possible page elements.<p>
297     *
298     * @return the html String for a form list
299     */
300    public String buildElementList() {
301
302        StringBuffer retValue = new StringBuffer(512);
303        retValue.append("<table border=\"0\">\n");
304        retValue.append("<tr>\n");
305        retValue.append(
306            "\t<td class=\"textbold\" unselectable=\"on\">"
307                + key(Messages.GUI_EDITOR_DIALOG_ELEMENTS_PAGEELEMENT_0)
308                + "</td>\n");
309        retValue.append("\t<td class=\"textbold\" unselectable=\"on\">&nbsp;&nbsp;"
310            + key(Messages.GUI_EDITOR_DIALOG_ELEMENTS_ENABLED_0)
311            + "&nbsp;&nbsp;</td>\n");
312        retValue.append("</tr>\n");
313        retValue.append("<tr><td colspan=\"2\"><span style=\"height: 6px;\"></span></td></tr>\n");
314
315        try {
316
317            // get the list of all possible elements
318            List<CmsDialogElement> elementList = computeElements();
319
320            // get all present bodies from the temporary file
321            CmsFile file = getCms().readFile(getParamTempfile(), CmsResourceFilter.IGNORE_EXPIRATION);
322            CmsXmlPage page = CmsXmlPageFactory.unmarshal(getCms(), file);
323
324            // show all possible elements
325            Iterator<CmsDialogElement> i = elementList.iterator();
326            while (i.hasNext()) {
327                // get the current list element
328                CmsDialogElement element = i.next();
329                // build an element row
330                retValue.append("<tr>\n");
331                retValue.append("\t<td style=\"white-space: nowrap;\" unselectable=\"on\">" + element.getNiceName());
332                retValue.append("</td>\n");
333                retValue.append("\t<td class=\"textcenter\" unselectable=\"on\"><input type=\"checkbox\" name=\"");
334                retValue.append(PREFIX_PARAM_BODY);
335                retValue.append(element.getName());
336                retValue.append("\" value=\"true\"");
337
338                if ((!page.hasValue(element.getName(), getElementLocale()) && element.isMandantory())
339                    || page.isEnabled(element.getName(), getElementLocale())) {
340                    retValue.append(" checked=\"checked\"");
341                }
342                if (element.isMandantory() || element.getName().equals(getParamElementname())) {
343                    retValue.append(" disabled=\"disabled\"");
344                }
345                retValue.append(">");
346                retValue.append("<script >registerElement(\"");
347
348                retValue.append(element.getName());
349                retValue.append("\", ");
350                retValue.append(page.isEnabled(element.getName(), getElementLocale()));
351                retValue.append(");</script>");
352
353                retValue.append("</td>\n");
354                retValue.append("</tr>\n");
355            }
356
357        } catch (CmsException e) {
358            // should usually never happen
359            if (LOG.isInfoEnabled()) {
360                LOG.info(e.getLocalizedMessage(), e);
361            }
362        }
363
364        retValue.append("</table>\n");
365        return retValue.toString();
366    }
367
368    /**
369     * Creates a list of possible elements of a template from the template property "template-elements".<p>
370     *
371     * @return the list of elements in a String array with element name, nice name (if present) and mandatory flag
372     */
373    public List<CmsDialogElement> computeElements() {
374
375        if (m_elementList == null) {
376            m_elementList = computeElements(getCms(), getParamTempfile(), getElementLocale());
377        }
378        return m_elementList;
379    }
380
381    /**
382     * Returns the element name that has to be changed.<p>
383     *
384     * @return the element name that has to be changed
385     */
386    public String getChangeElement() {
387
388        return m_changeElement;
389    }
390
391    /**
392     * Returns the current element locale.<p>
393     *
394     * @return the current element locale
395     */
396    public Locale getElementLocale() {
397
398        if (m_elementLocale == null) {
399            m_elementLocale = CmsLocaleManager.getLocale(getParamElementlanguage());
400        }
401        return m_elementLocale;
402    }
403
404    /**
405     * Returns the current element language.<p>
406     *
407     * @return the current element language
408     */
409    public String getParamElementlanguage() {
410
411        return m_paramElementlanguage;
412    }
413
414    /**
415     * Returns the current element name.<p>
416     *
417     * @return the current element name
418     */
419    public String getParamElementname() {
420
421        return m_paramElementname;
422    }
423
424    /**
425     * Returns the name of the temporary file.<p>
426     *
427     * @return the name of the temporary file
428     */
429    public String getParamTempfile() {
430
431        return m_paramTempFile;
432    }
433
434    /**
435     * Sets the current element language.<p>
436     *
437     * @param elementLanguage the current element language
438     */
439    public void setParamElementlanguage(String elementLanguage) {
440
441        m_paramElementlanguage = elementLanguage;
442    }
443
444    /**
445     * Sets the current element name.<p>
446     *
447     * @param elementName the current element name
448     */
449    public void setParamElementname(String elementName) {
450
451        m_paramElementname = elementName;
452    }
453
454    /**
455     * Sets the name of the temporary file.<p>
456     *
457     * @param fileName the name of the temporary file
458     */
459    public void setParamTempfile(String fileName) {
460
461        m_paramTempFile = fileName;
462    }
463
464    /**
465     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
466     */
467    @Override
468    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
469
470        // fill the parameter values in the get/set methods
471        fillParamValues(request);
472        // set the dialog type
473        setParamDialogtype(DIALOG_TYPE);
474        // set the action for the JSP switch
475        if (DIALOG_UPDATE_ELEMENTS.equals(getParamAction())) {
476            setAction(ACTION_UPDATE_ELEMENTS);
477        } else {
478            setAction(ACTION_DEFAULT);
479            // build title for delete dialog
480            setParamTitle(key(
481                Messages.GUI_EDITOR_DIALOG_ELEMENTS_TITLE_1,
482                new Object[] {CmsResource.getName(getParamResource())}));
483        }
484    }
485}