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.acacia.client.widgets;
029
030import org.opencms.acacia.client.css.I_CmsWidgetsLayoutBundle;
031import org.opencms.acacia.shared.CmsEntity;
032import org.opencms.ade.contenteditor.client.CmsContentEditor;
033import org.opencms.ade.contenteditor.client.I_CmsEntityChangeListener;
034import org.opencms.ade.contenteditor.client.css.I_CmsLayoutBundle;
035import org.opencms.gwt.client.ui.input.CmsFilterSelectBox;
036import org.opencms.gwt.client.util.CmsDebugLog;
037
038import java.util.Map.Entry;
039
040import com.google.gwt.dom.client.Element;
041import com.google.gwt.event.dom.client.FocusEvent;
042import com.google.gwt.event.dom.client.FocusHandler;
043import com.google.gwt.event.logical.shared.ValueChangeEvent;
044import com.google.gwt.event.logical.shared.ValueChangeHandler;
045import com.google.gwt.event.shared.HandlerRegistration;
046import com.google.gwt.user.client.ui.Composite;
047
048/**
049 * Select widget which uses other values from the content as select options.<p>
050 *
051 * This works as follows: The widget is given a configuration consisting of three pipe-separated OpenCms content value paths.
052 * The first path is used to select a set of nested content values. The second and third paths are relative to the first path
053 * and are used to select a select option and a select option display text from the nested contents matching the first path.
054 * Note that if you omit indexes on a component of the first path, all indexes will be matched.
055 *
056 * The widget attaches event listeners to the editor so it can dynamically update the list of select options when the content changes.
057 */
058public class CmsFormatterSelectWidget extends Composite implements I_CmsEditWidget, I_CmsHasDisplayDirection {
059
060    /** The global select box. */
061    protected CmsFilterSelectBox m_selectBox = new CmsFilterSelectBox();
062
063    /** Value of the activation. */
064    private boolean m_active = true;
065
066    /** The removed options. */
067    private CmsSelectConfigurationParser m_optionsAllRemoved;
068
069    /** The default options. */
070    private CmsSelectConfigurationParser m_optionsDefault;
071
072    /** Path components of the path used to select the option value. */
073    private String[] m_valuePath;
074
075    /**
076     * Creates a new widget instance.<p>
077     *
078     * @param configuration the widget configuration
079     */
080    public CmsFormatterSelectWidget(String configuration) {
081
082        String[] configParts = configuration.split("\\|\\|");
083        if (configParts.length != 3) {
084            CmsDebugLog.consoleLog("There were " + configParts.length + " configuration parts. 3 were expected.");
085        }
086        m_valuePath = splitPath(configParts[0]);
087        m_optionsDefault = new CmsSelectConfigurationParser(configParts[1]);
088        m_optionsAllRemoved = new CmsSelectConfigurationParser(configParts[2]);
089
090        // Place the check above the box using a vertical panel.
091        m_selectBox.addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().selectBoxPanel());
092        m_selectBox.setPopupResize(false);
093        // add some styles to parts of the selectbox.
094        m_selectBox.getOpener().addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().selectBoxSelected());
095        m_selectBox.getSelectorPopup().addStyleName(I_CmsLayoutBundle.INSTANCE.globalWidgetCss().selectBoxPopup());
096        m_selectBox.addValueChangeHandler(new ValueChangeHandler<String>() {
097
098            public void onValueChange(ValueChangeEvent<String> event) {
099
100                fireChangeEvent();
101
102            }
103
104        });
105
106        update(CmsContentEditor.getEntity());
107        initWidget(m_selectBox);
108    }
109
110    /**
111     * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler)
112     */
113    public HandlerRegistration addFocusHandler(FocusHandler handler) {
114
115        return addDomHandler(handler, FocusEvent.getType());
116    }
117
118    /**
119     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
120     */
121    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
122
123        return addHandler(handler, ValueChangeEvent.getType());
124    }
125
126    /**
127     * Represents a value change event.<p>
128     * Please edit the blog entry text.
129     */
130    public void fireChangeEvent() {
131
132        ValueChangeEvent.fire(this, m_selectBox.getFormValueAsString());
133
134    }
135
136    /**
137     * @see org.opencms.acacia.client.widgets.I_CmsHasDisplayDirection#getDisplayingDirection()
138     */
139    public Direction getDisplayingDirection() {
140
141        return m_selectBox.displayingAbove() ? Direction.above : Direction.below;
142    }
143
144    /**
145     * @see com.google.gwt.user.client.ui.HasValue#getValue()
146     */
147    public String getValue() {
148
149        return m_selectBox.getFormValueAsString();
150    }
151
152    /**
153     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#isActive()
154     */
155    public boolean isActive() {
156
157        return m_active;
158    }
159
160    /**
161     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#onAttachWidget()
162     */
163    public void onAttachWidget() {
164
165        super.onAttach();
166    }
167
168    /**
169     * @see com.google.gwt.user.client.ui.Widget#onLoad()
170     */
171    @Override
172    public void onLoad() {
173
174        update(CmsContentEditor.getEntity());
175
176        CmsContentEditor.addEntityChangeListener(new I_CmsEntityChangeListener() {
177
178            public void onEntityChange(CmsEntity entity) {
179
180                update(CmsContentEditor.getEntity());
181            }
182        }, null);
183    }
184
185    /**
186     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#owns(com.google.gwt.dom.client.Element)
187     */
188    public boolean owns(Element element) {
189
190        return getElement().isOrHasChild(element);
191
192    }
193
194    /**
195     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setActive(boolean)
196     */
197    public void setActive(boolean active) {
198
199        // check if value change. If not do nothing.
200        if (m_active == active) {
201            return;
202        }
203        // set new value.
204        m_active = active;
205        // set the new value to the selectbox.
206        m_selectBox.setEnabled(active);
207        // fire change event if necessary.
208        if (active) {
209            fireChangeEvent();
210        }
211
212    }
213
214    /**
215     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setName(java.lang.String)
216     */
217    public void setName(String name) {
218
219        // no input field so nothing to do
220
221    }
222
223    /**
224     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object)
225     */
226    public void setValue(String value) {
227
228        setValue(value, false);
229
230    }
231
232    /**
233     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean)
234     */
235    public void setValue(String value, boolean fireEvents) {
236
237        m_selectBox.setFormValueAsString(value);
238        if (fireEvents) {
239            fireChangeEvent();
240        }
241
242    }
243
244    /**
245     * Updates the select options from the given entity.<p>
246     *
247     * @param entity a top-level content entity
248     */
249    public void update(CmsEntity entity) {
250
251        String removeAllFlag = CmsEntity.getValueForPath(entity, m_valuePath);
252
253        boolean allRemoved = Boolean.valueOf(removeAllFlag).booleanValue();
254
255        replaceOptions(allRemoved ? m_optionsAllRemoved : m_optionsDefault);
256    }
257
258    /**
259     * Replaces the select options with the given options.<p>
260     *
261     * @param parser the configuration parser
262     */
263    private void replaceOptions(CmsSelectConfigurationParser parser) {
264
265        String oldValue = m_selectBox.getFormValueAsString();
266        // set the help info first!!
267        for (Entry<String, String> helpEntry : parser.getHelpTexts().entrySet()) {
268            m_selectBox.setTitle(helpEntry.getKey(), helpEntry.getValue());
269        }
270        //set value and option to the combo box.
271        m_selectBox.setItems(parser.getOptions());
272        //if one entrance is declared for default.
273        if (parser.getDefaultValue() != null) {
274            //set the declared value selected.
275            m_selectBox.selectValue(parser.getDefaultValue());
276        }
277        m_selectBox.setFormValueAsString(oldValue);
278    }
279
280    /**
281     * Splits a path into components.<p>
282     *
283     * @param path the path to split
284     * @return the path components
285     */
286    private String[] splitPath(String path) {
287
288        path = path.replaceAll("^/", "").replaceAll("/$", "");
289        return path.split("/");
290    }
291
292}