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.ade.contenteditor.client.Messages;
032import org.opencms.gwt.client.ui.CmsScrollPanel;
033import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
034import org.opencms.gwt.client.ui.input.CmsCheckBox;
035import org.opencms.gwt.client.util.CmsClientStringUtil;
036import org.opencms.gwt.client.util.CmsDomUtil;
037
038import java.util.Iterator;
039import java.util.LinkedList;
040import java.util.List;
041import java.util.Map;
042
043import com.google.gwt.core.client.GWT;
044import com.google.gwt.dom.client.Element;
045import com.google.gwt.dom.client.Style.Unit;
046import com.google.gwt.event.dom.client.FocusEvent;
047import com.google.gwt.event.dom.client.FocusHandler;
048import com.google.gwt.event.logical.shared.ValueChangeEvent;
049import com.google.gwt.event.logical.shared.ValueChangeHandler;
050import com.google.gwt.event.shared.HandlerRegistration;
051import com.google.gwt.user.client.ui.Composite;
052import com.google.gwt.user.client.ui.FlowPanel;
053import com.google.gwt.user.client.ui.SimplePanel;
054
055/**
056 * Provides a widget for a standard HTML form for a group of radio buttons.<p>
057 *
058 * Regarding widget configuration, see <code>{@link org.opencms.acacia.client.widgets.CmsSelectConfigurationParser}</code>.<p>
059 *
060 * */
061public class CmsMultiSelectWidget extends Composite implements I_CmsEditWidget {
062
063    /** Configuration parameter to indicate the multi-select needs to be activated by a check box. */
064    public static final String CONFIGURATION_REQUIRES_ACTIVATION = "|requiresactivation";
065
066    /** Default value of rows to be shown. */
067    private static final int DEFAULT_ROWS_SHOWN = 10;
068
069    /** The main panel of this widget. */
070    FlowPanel m_panel = new FlowPanel();
071
072    /** The scroll panel around the multi-selections. */
073    CmsScrollPanel m_scrollPanel;
074
075    /** Activation button.*/
076    private CmsCheckBox m_activation;
077
078    /** Value of the activation. */
079    private boolean m_active = true;
080
081    /** List of all check boxes button. */
082    private List<CmsCheckBox> m_checkboxes;
083
084    /** The default check boxes set in xsd. */
085    private List<CmsCheckBox> m_defaultCheckBox;
086
087    /** Value of the requiresactivation. */
088    private boolean m_requiresactivation;
089
090    /** The parameter set from configuration.*/
091    private int m_rowsToShow = DEFAULT_ROWS_SHOWN;
092
093    /**
094     * Constructs an OptionalTextBox with the given caption on the check.<p>
095     * @param config the configuration string.
096     */
097    public CmsMultiSelectWidget(String config) {
098
099        FlowPanel main = new FlowPanel();
100        m_scrollPanel = GWT.create(CmsScrollPanel.class);
101        // add separate style to the panel.
102        m_scrollPanel.addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().radioButtonPanel());
103
104        if (config.contains(CONFIGURATION_REQUIRES_ACTIVATION)) {
105            config = config.replace(CONFIGURATION_REQUIRES_ACTIVATION, "");
106            m_requiresactivation = true;
107        }
108        CmsSelectConfigurationParser parser = new CmsSelectConfigurationParser(config);
109        // generate a list of all radio button.
110        m_defaultCheckBox = new LinkedList<CmsCheckBox>();
111        m_checkboxes = new LinkedList<CmsCheckBox>();
112        if (m_requiresactivation) {
113
114            buildActivationButton();
115            SimplePanel activation = new SimplePanel(m_activation);
116            activation.addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().radioButtonPanel());
117            activation.getElement().getStyle().setMarginBottom(5, Unit.PX);
118            main.add(activation);
119        }
120        FocusHandler focusHandler = new FocusHandler() {
121
122            public void onFocus(FocusEvent event) {
123
124                CmsDomUtil.fireFocusEvent(CmsMultiSelectWidget.this);
125            }
126        };
127
128        for (Map.Entry<String, String> entry : parser.getOptions().entrySet()) {
129            CmsCheckBox checkbox = new CmsCheckBox(entry.getValue());
130            checkbox.setInternalValue(entry.getKey());
131            if (parser.getDefaultValues().contains(entry.getKey())) {
132                m_defaultCheckBox.add(checkbox);
133            }
134            checkbox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
135
136                public void onValueChange(ValueChangeEvent<Boolean> event) {
137
138                    fireChangeEvent();
139
140                }
141
142            });
143            // add a separate style each checkbox .
144            checkbox.addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().checkboxlabel());
145            checkbox.getButton().addFocusHandler(focusHandler);
146            m_checkboxes.add(checkbox);
147            // add the checkbox to the panel.
148            m_panel.add(checkbox);
149
150        }
151        // All composites must call initWidget() in their constructors.
152        m_scrollPanel.add(m_panel);
153        m_scrollPanel.setResizable(false);
154
155        int inputHeight = CmsClientStringUtil.parseInt(I_CmsLayoutBundle.INSTANCE.constants().css().inputHeight());
156
157        int height = (m_rowsToShow * inputHeight) + 6;
158        if (m_checkboxes.size() < m_rowsToShow) {
159            height = (m_checkboxes.size() * inputHeight) + 6;
160        }
161        m_scrollPanel.setDefaultHeight(height);
162        m_scrollPanel.setHeight(height + "px");
163        main.add(m_scrollPanel);
164        initWidget(main);
165        if (m_requiresactivation) {
166            setAllCheckboxEnabled(false);
167        }
168
169    }
170
171    /**
172     * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler)
173     */
174    public HandlerRegistration addFocusHandler(FocusHandler handler) {
175
176        return addDomHandler(handler, FocusEvent.getType());
177    }
178
179    /**
180     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
181     */
182    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
183
184        return addHandler(handler, ValueChangeEvent.getType());
185    }
186
187    /**
188     * Represents a value change event.<p>
189     *
190     */
191    public void fireChangeEvent() {
192
193        ValueChangeEvent.fire(this, generateValue());
194    }
195
196    /**
197     * @see com.google.gwt.user.client.ui.HasValue#getValue()
198     */
199    public String getValue() {
200
201        return generateValue();
202    }
203
204    /**
205     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#isActive()
206     */
207    public boolean isActive() {
208
209        return m_active;
210    }
211
212    /**
213     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#onAttachWidget()
214     */
215    public void onAttachWidget() {
216
217        super.onAttach();
218    }
219
220    /**
221     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#owns(com.google.gwt.dom.client.Element)
222     */
223    public boolean owns(Element element) {
224
225        // TODO implement this in case we want the delete behavior for optional fields
226        return false;
227
228    }
229
230    /**
231     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setActive(boolean)
232     */
233    public void setActive(boolean active) {
234
235        // check if the value has changed. If there is no change do nothing.
236        if (m_active == active) {
237            return;
238        }
239        // set the new value.
240        m_active = active;
241        // Iterate over all checkboxes.
242        for (CmsCheckBox checkbox : m_checkboxes) {
243            // set the checkbox active / inactive.
244            checkbox.setEnabled(active);
245            // if this widget is set inactive.
246            if (active) {
247                // select the default value if set.
248                if (m_defaultCheckBox != null) {
249                    Iterator<CmsCheckBox> it = m_defaultCheckBox.iterator();
250                    while (it.hasNext()) {
251                        it.next().setChecked(active);
252                    }
253                }
254            }
255        }
256        // fire value change event.
257        if (active) {
258            fireChangeEvent();
259        }
260
261    }
262
263    /**
264     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setName(java.lang.String)
265     */
266    public void setName(String name) {
267
268        // no input field so nothing to do
269
270    }
271
272    /**
273     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object)
274     */
275    public void setValue(String value) {
276
277        setValue(value, false);
278
279    }
280
281    /**
282     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean)
283     */
284    public void setValue(String value, boolean fireEvents) {
285
286        String[] values;
287        if ((value != null) && (value != "")) {
288            if (value.contains(",")) {
289                values = value.split(",");
290            } else {
291                values = new String[] {value};
292            }
293            for (CmsCheckBox checkbox : m_checkboxes) {
294                checkbox.setChecked(false);
295                for (int j = 0; j < values.length; j++) {
296                    if (checkbox.getInternalValue().equals(values[j])) {
297                        checkbox.setChecked(true);
298                    }
299                }
300            }
301
302        }
303
304        // fire change event.
305        if (fireEvents) {
306            fireChangeEvent();
307        }
308
309    }
310
311    /**
312     * Sets the checkboxes enabled or disabled.<p>
313     *
314     * @param value if it should be enabled or disabled
315     */
316    protected void setAllCheckboxEnabled(boolean value) {
317
318        for (CmsCheckBox checkbox : m_checkboxes) {
319            // set the checkbox active / inactive.
320            checkbox.setEnabled(value);
321        }
322    }
323
324    /**
325     * Adds a button to activate or deactivate the selection.<p>
326     */
327    private void buildActivationButton() {
328
329        m_activation = new CmsCheckBox(Messages.get().key(Messages.GUI_MULTISELECT_ACTIVATE_0));
330
331        m_activation.addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().checkboxlabel());
332        m_activation.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
333
334            public void onValueChange(ValueChangeEvent<Boolean> event) {
335
336                setAllCheckboxEnabled(event.getValue().booleanValue());
337
338            }
339        });
340    }
341
342    /**
343     * Generate a string with all selected checkboxes separated with ','.
344     *
345     * @return a string with all selected checkboxes
346     * */
347    private String generateValue() {
348
349        String result = "";
350        for (CmsCheckBox checkbox : m_checkboxes) {
351            if (checkbox.isChecked()) {
352                result += checkbox.getInternalValue() + ",";
353            }
354        }
355        if (result.contains(",")) {
356            result = result.substring(0, result.lastIndexOf(","));
357        }
358        return result;
359    }
360}