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.gwt.client.ui.input;
029
030import org.opencms.gwt.client.I_CmsHasInit;
031import org.opencms.gwt.client.ui.I_CmsAutoHider;
032import org.opencms.gwt.client.ui.css.I_CmsInputLayoutBundle;
033import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
034import org.opencms.gwt.client.ui.input.form.CmsWidgetFactoryRegistry;
035import org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetFactory;
036import org.opencms.gwt.client.util.CmsDomUtil;
037import org.opencms.util.CmsPair;
038import org.opencms.util.CmsStringUtil;
039
040import java.util.ArrayList;
041import java.util.HashSet;
042import java.util.LinkedHashMap;
043import java.util.List;
044import java.util.Map;
045import java.util.Set;
046
047import com.google.common.base.Optional;
048import com.google.gwt.event.dom.client.FocusEvent;
049import com.google.gwt.event.dom.client.FocusHandler;
050import com.google.gwt.event.dom.client.HasFocusHandlers;
051import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
052import com.google.gwt.event.logical.shared.ValueChangeEvent;
053import com.google.gwt.event.logical.shared.ValueChangeHandler;
054import com.google.gwt.event.shared.HandlerRegistration;
055import com.google.gwt.user.client.ui.Composite;
056import com.google.gwt.user.client.ui.FlowPanel;
057import com.google.gwt.user.client.ui.Panel;
058
059/**
060 * A form widget consisting of a group of checkboxes.<p>
061 *
062 * @since 8.0.0
063 *
064 */
065public class CmsMultiCheckBox extends Composite
066implements I_CmsFormWidget, I_CmsHasInit, HasValueChangeHandlers<String>, HasFocusHandlers {
067
068    /** The type string for this widget. */
069    public static final String WIDGET_TYPE = "multicheck";
070
071    /** The list of checkboxes. */
072    protected List<CmsCheckBox> m_checkboxes = new ArrayList<CmsCheckBox>();
073
074    /** Error display for this widget. */
075    protected CmsErrorWidget m_error = new CmsErrorWidget();
076
077    /** The select options of the multi check box. */
078    protected Map<String, String> m_items = new LinkedHashMap<String, String>();
079
080    /** Panel which contains all the components of the widget. */
081    protected Panel m_panel = new FlowPanel();
082
083    /**
084     * Constructs a new checkbox group from a list of string pairs.<p>
085     *
086     * The first string of every pair is the value of the checkbox, the second string is the label.
087     *
088     * @param items a list of pairs of strings.
089     */
090    public CmsMultiCheckBox(List<CmsPair<String, String>> items) {
091
092        super();
093        init(CmsPair.pairsToMap(items));
094    }
095
096    /**
097     * Constructs a new checkbox group from a map from strings to strings.<p>
098     *
099     * The keys of the map are used as the selection values of the checkboxes, while the value
100     * for a given key in the map is used as the label for the checkbox which is displayed to the user.
101     *
102     * @param items the map of checkbox options
103     */
104    public CmsMultiCheckBox(Map<String, String> items) {
105
106        super();
107        init(items);
108    }
109
110    /**
111     * Initializes this class.<p>
112     */
113    public static void initClass() {
114
115        // registers a factory for creating new instances of this widget
116        CmsWidgetFactoryRegistry.instance().registerFactory(WIDGET_TYPE, new I_CmsFormWidgetFactory() {
117
118            /**
119             * @see org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetFactory#createWidget(java.util.Map, com.google.common.base.Optional)
120             */
121            public I_CmsFormWidget createWidget(Map<String, String> widgetParams, Optional<String> defaultValue) {
122
123                return new CmsMultiCheckBox(widgetParams);
124            }
125        });
126    }
127
128    /**
129     * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler)
130     */
131    public HandlerRegistration addFocusHandler(FocusHandler handler) {
132
133        return addDomHandler(handler, FocusEvent.getType());
134    }
135
136    /**
137     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
138     */
139    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
140
141        return addHandler(handler, ValueChangeEvent.getType());
142    }
143
144    /**
145     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getApparentValue()
146     */
147    public String getApparentValue() {
148
149        return getFormValueAsString();
150    }
151
152    /**
153     * Returns a list of all checkboxes.<p>
154     *
155     * @return a list of checkboxes
156     * */
157    public List<CmsCheckBox> getCheckboxes() {
158
159        return m_checkboxes;
160    }
161
162    /**
163     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getFieldType()
164     */
165    public FieldType getFieldType() {
166
167        return I_CmsFormWidget.FieldType.STRING_LIST;
168    }
169
170    /**
171     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getFormValue()
172     */
173    public Object getFormValue() {
174
175        return new ArrayList<String>(getSelected());
176    }
177
178    /**
179     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getFormValueAsString()
180     */
181    public String getFormValueAsString() {
182
183        List<String> selected = new ArrayList<String>(getSelected());
184        return CmsStringUtil.listAsString(selected, "|");
185
186    }
187
188    /**
189     * Returns the set of values of the selected checkboxes.<p>
190     *
191     * @return a set of strings
192     */
193    public Set<String> getSelected() {
194
195        Set<String> result = new HashSet<String>();
196        int i = 0;
197        for (Map.Entry<String, String> entry : m_items.entrySet()) {
198            String key = entry.getKey();
199            CmsCheckBox checkBox = m_checkboxes.get(i);
200            if (checkBox.isChecked()) {
201                result.add(key);
202            }
203            i += 1;
204        }
205        return result;
206    }
207
208    /**
209     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#isEnabled()
210     */
211    public boolean isEnabled() {
212
213        boolean result = true;
214        for (CmsCheckBox checkbox : m_checkboxes) {
215            if (!checkbox.isEnabled()) {
216                result = false;
217            }
218        }
219        return result;
220    }
221
222    /**
223     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#reset()
224     */
225    public void reset() {
226
227        for (CmsCheckBox checkbox : m_checkboxes) {
228            checkbox.setChecked(false);
229        }
230    }
231
232    /**
233     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setAutoHideParent(org.opencms.gwt.client.ui.I_CmsAutoHider)
234     */
235    public void setAutoHideParent(I_CmsAutoHider autoHideParent) {
236
237        // nothing to do
238    }
239
240    /**
241     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setEnabled(boolean)
242     */
243    public void setEnabled(boolean enabled) {
244
245        for (CmsCheckBox checkbox : m_checkboxes) {
246            checkbox.setEnabled(enabled);
247        }
248    }
249
250    /**
251     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setErrorMessage(java.lang.String)
252     */
253    public void setErrorMessage(String errorMessage) {
254
255        m_error.setText(errorMessage);
256    }
257
258    /**
259     * Sets the value of the widget.<p>
260     *
261     * @param value the new value
262     */
263    @SuppressWarnings("unchecked")
264    public void setFormValue(Object value) {
265
266        if (value instanceof List<?>) {
267            List<String> keys = (List<String>)value;
268            Set<String> keySet = new HashSet<String>(keys);
269            int i = 0;
270            for (Map.Entry<String, String> entry : m_items.entrySet()) {
271                String key = entry.getKey();
272                CmsCheckBox checkbox = m_checkboxes.get(i);
273                checkbox.setChecked(keySet.contains(key));
274                i += 1;
275            }
276        }
277    }
278
279    /**
280     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setFormValueAsString(java.lang.String)
281     */
282    public void setFormValueAsString(String formValue) {
283
284        if (formValue == null) {
285            formValue = "";
286        }
287        List<String> values = CmsStringUtil.splitAsList(formValue, "|");
288        setFormValue(values);
289    }
290
291    /**
292     * Enables or disables italics display in the checkbox labels.<p>
293     *
294     * @param weak true if italics display should be enabled
295     */
296    public void setTextWeak(boolean weak) {
297
298        String style = I_CmsInputLayoutBundle.INSTANCE.inputCss().weakText();
299        if (weak) {
300            addStyleName(style);
301        } else {
302            removeStyleName(style);
303        }
304
305    }
306
307    /**
308     * Fires the value change event for the widget.<p>
309     *
310     * @param newValue the new value
311     */
312    protected void fireValueChanged(String newValue) {
313
314        ValueChangeEvent.fire(this, newValue);
315    }
316
317    /**
318     * Initializes the widget given a map of select options.<p>
319     *
320     * The keys of the map are the values of the select options, while the values of the map
321     * are the labels which should be used for the checkboxes.
322     *
323     * @param items the map of select options
324     */
325    protected void init(Map<String, String> items) {
326
327        initWidget(m_panel);
328        m_items = new LinkedHashMap<String, String>(items);
329        m_panel.setStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().multiCheckBox());
330        m_panel.addStyleName(I_CmsLayoutBundle.INSTANCE.generalCss().textMedium());
331        FocusHandler focusHandler = new FocusHandler() {
332
333            public void onFocus(FocusEvent event) {
334
335                CmsDomUtil.fireFocusEvent(CmsMultiCheckBox.this);
336            }
337        };
338        for (Map.Entry<String, String> entry : items.entrySet()) {
339            String value = entry.getValue();
340            CmsCheckBox checkbox = new CmsCheckBox(value);
341            // wrap the check boxes in FlowPanels to arrange them vertically
342            FlowPanel checkboxWrapper = new FlowPanel();
343            checkboxWrapper.add(checkbox);
344            checkbox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
345
346                public void onValueChange(ValueChangeEvent<Boolean> valueChanged) {
347
348                    fireValueChanged(getFormValueAsString());
349                }
350            });
351            checkbox.getButton().addFocusHandler(focusHandler);
352            m_panel.add(checkboxWrapper);
353            m_checkboxes.add(checkbox);
354        }
355        m_panel.add(m_error);
356    }
357
358}