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.util.CmsPair;
037
038import java.util.LinkedHashMap;
039import java.util.List;
040import java.util.Map;
041import java.util.Map.Entry;
042
043import com.google.gwt.dom.client.Element;
044import com.google.gwt.event.dom.client.FocusEvent;
045import com.google.gwt.event.dom.client.FocusHandler;
046import com.google.gwt.event.logical.shared.ValueChangeEvent;
047import com.google.gwt.event.logical.shared.ValueChangeHandler;
048import com.google.gwt.event.shared.HandlerRegistration;
049import com.google.gwt.json.client.JSONArray;
050import com.google.gwt.json.client.JSONBoolean;
051import com.google.gwt.json.client.JSONObject;
052import com.google.gwt.json.client.JSONParser;
053import com.google.gwt.json.client.JSONString;
054import com.google.gwt.user.client.ui.Composite;
055import com.google.gwt.user.client.ui.RootPanel;
056
057/**
058 * Select widget for display types.
059 * In case the widget is configured to match display types, only formatters of a specific type may be selected at the same time.<p>
060 */
061public class CmsDisplayTypeSelectWidget extends Composite implements I_CmsEditWidget, I_CmsHasDisplayDirection {
062
063    /** The no filter string. */
064    private static final String NO_FILTER = "###no-filter###";
065
066    /** The global select box. */
067    protected CmsFilterSelectBox m_selectBox = new CmsFilterSelectBox();
068
069    /** Flag indicating the widget is configured to match types. */
070    boolean m_matchTypes;
071
072    /** The available select options, un-filtered. */
073    Map<String, CmsPair<String, String>> m_options;
074
075    /** Value of the activation. */
076    private boolean m_active = true;
077
078    /** The current filter type. */
079    private String m_filterType;
080
081    /** Path components of the path used to select the option value. */
082    private String[] m_valuePath;
083
084    /** The empty option label. */
085    private String m_emptyLabel;
086
087    /**
088     * Creates a new widget instance.<p>
089     *
090     * @param configuration the widget configuration
091     */
092    public CmsDisplayTypeSelectWidget(String configuration) {
093
094        JSONObject config = (JSONObject)JSONParser.parseStrict(configuration);
095        String path = ((JSONString)config.get("valuePath")).stringValue();
096        m_valuePath = splitPath(path);
097        m_matchTypes = ((JSONBoolean)config.get("matchTypes")).booleanValue();
098        m_emptyLabel = ((JSONString)config.get("emptyLabel")).stringValue();
099        JSONArray opts = (JSONArray)config.get("options");
100        m_options = new LinkedHashMap<String, CmsPair<String, String>>();
101        for (int i = 0; i < opts.size(); i++) {
102            JSONObject opt = (JSONObject)opts.get(i);
103            String value = ((JSONString)opt.get("value")).stringValue();
104            String label = ((JSONString)opt.get("label")).stringValue();
105            String displayType = ((JSONString)opt.get("displayType")).stringValue();
106            m_options.put(value, new CmsPair<String, String>(label, displayType));
107        }
108
109        // Place the check above the box using a vertical panel.
110        m_selectBox.addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().selectBoxPanel());
111        m_selectBox.setPopupResize(false);
112        // add some styles to parts of the selectbox.
113        m_selectBox.getOpener().addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().selectBoxSelected());
114        m_selectBox.getSelectorPopup().addStyleName(I_CmsLayoutBundle.INSTANCE.globalWidgetCss().selectBoxPopup());
115        m_selectBox.addValueChangeHandler(new ValueChangeHandler<String>() {
116
117            public void onValueChange(ValueChangeEvent<String> event) {
118
119                fireChangeEvent();
120
121            }
122
123        });
124
125        update(CmsContentEditor.getEntity());
126        initWidget(m_selectBox);
127    }
128
129    /**
130     * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler)
131     */
132    public HandlerRegistration addFocusHandler(FocusHandler handler) {
133
134        return addDomHandler(handler, FocusEvent.getType());
135    }
136
137    /**
138     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
139     */
140    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
141
142        return addHandler(handler, ValueChangeEvent.getType());
143    }
144
145    /**
146     * Represents a value change event.<p>
147     * Please edit the blog entry text.
148     */
149    public void fireChangeEvent() {
150
151        ValueChangeEvent.fire(this, m_selectBox.getFormValueAsString());
152
153    }
154
155    /**
156     * @see org.opencms.acacia.client.widgets.I_CmsHasDisplayDirection#getDisplayingDirection()
157     */
158    public Direction getDisplayingDirection() {
159
160        return m_selectBox.displayingAbove() ? Direction.above : Direction.below;
161    }
162
163    /**
164     * @see com.google.gwt.user.client.ui.HasValue#getValue()
165     */
166    public String getValue() {
167
168        return m_selectBox.getFormValueAsString();
169    }
170
171    /**
172     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#isActive()
173     */
174    public boolean isActive() {
175
176        return m_active;
177    }
178
179    /**
180     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#onAttachWidget()
181     */
182    public void onAttachWidget() {
183
184        super.onAttach();
185    }
186
187    /**
188     * @see com.google.gwt.user.client.ui.Widget#onLoad()
189     */
190    @Override
191    public void onLoad() {
192
193        if (m_matchTypes) {
194            update(CmsContentEditor.getEntity());
195
196            CmsContentEditor.addEntityChangeListener(new I_CmsEntityChangeListener() {
197
198                public void onEntityChange(CmsEntity entity) {
199
200                    boolean attached = RootPanel.getBodyElement().isOrHasChild(getElement());
201                    if (attached) {
202                        update(CmsContentEditor.getEntity());
203                    }
204                }
205            }, null);
206        }
207    }
208
209    /**
210     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#owns(com.google.gwt.dom.client.Element)
211     */
212    public boolean owns(Element element) {
213
214        return getElement().isOrHasChild(element);
215
216    }
217
218    /**
219     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setActive(boolean)
220     */
221    public void setActive(boolean active) {
222
223        // check if value change. If not do nothing.
224        if (m_active == active) {
225            return;
226        }
227        // set new value.
228        m_active = active;
229        // set the new value to the selectbox.
230        m_selectBox.setEnabled(active);
231        // fire change event if necessary.
232        if (active) {
233            fireChangeEvent();
234        }
235
236    }
237
238    /**
239     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setName(java.lang.String)
240     */
241    public void setName(String name) {
242
243        // no input field so nothing to do
244
245    }
246
247    /**
248     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object)
249     */
250    public void setValue(String value) {
251
252        setValue(value, false);
253
254    }
255
256    /**
257     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean)
258     */
259    public void setValue(String value, boolean fireEvents) {
260
261        m_selectBox.setFormValueAsString(value);
262        if (fireEvents) {
263            fireChangeEvent();
264        }
265
266    }
267
268    /**
269     * Updates the select options from the given entity.<p>
270     *
271     * @param entity a top-level content entity
272     */
273    public void update(CmsEntity entity) {
274
275        String filterType = NO_FILTER;
276        if (m_matchTypes) {
277            List<Object> values = CmsEntity.getValuesForPath(entity, m_valuePath);
278            if (values.size() > 1) {
279                String firstValue = (String)values.get(0);
280                CmsPair<String, String> val = m_options.get(firstValue);
281                if (val != null) {
282                    filterType = val.getSecond();
283                }
284            }
285        }
286
287        if (!filterType.equals(m_filterType)) {
288            boolean noFilter = NO_FILTER.equals(filterType);
289            Map<String, String> items = new LinkedHashMap<String, String>();
290            // add empty option
291            items.put("", m_emptyLabel);
292            for (Entry<String, CmsPair<String, String>> optEntry : m_options.entrySet()) {
293                if (noFilter || filterType.equals(optEntry.getValue().getSecond())) {
294                    items.put(optEntry.getKey(), optEntry.getValue().getFirst());
295                }
296            }
297            replaceItems(items);
298        }
299        m_filterType = filterType;
300    }
301
302    /**
303     * Replaces the select items with the given items.<p>
304     *
305     * @param items the select items
306     */
307    private void replaceItems(Map<String, String> items) {
308
309        String oldValue = m_selectBox.getFormValueAsString();
310        //set value and option to the combo box.
311        m_selectBox.setItems(items);
312        if (items.containsKey(oldValue)) {
313            m_selectBox.setFormValueAsString(oldValue);
314        }
315    }
316
317    /**
318     * Splits a path into components.<p>
319     *
320     * @param path the path to split
321     * @return the path components
322     */
323    private String[] splitPath(String path) {
324
325        path = path.replaceAll("^/", "").replaceAll("/$", "");
326        return path.split("/");
327    }
328
329}