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.Messages;
032import org.opencms.gwt.client.ui.I_CmsAutoHider;
033import org.opencms.gwt.client.ui.input.form.CmsWidgetFactoryRegistry;
034import org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetFactory;
035import org.opencms.gwt.client.util.CmsMessages;
036import org.opencms.util.CmsPair;
037import org.opencms.util.CmsStringUtil;
038
039import java.util.HashMap;
040import java.util.Iterator;
041import java.util.List;
042import java.util.Map;
043
044import com.google.common.base.Optional;
045import com.google.gwt.dom.client.Style.Unit;
046
047/**
048 * Widget for selecting one of multiple items from a drop-down list which opens
049 * after the user clicks on the widget.<p>
050 *
051 * @since 8.5.0
052 *
053 */
054public class CmsMultiSelectBox extends A_CmsSelectBox<CmsMultiSelectCell> implements I_CmsHasInit, I_CmsHasGhostValue {
055
056    /** The key for the text which should be displayed in the opener if no option is available. */
057    public static final String NO_SELECTION_OPENER_TEXT = "%NO_SELECTION_OPENER_TEXT%";
058
059    /** The key for the text which should be displayed if no option is available. */
060    public static final String NO_SELECTION_TEXT = "%NO_SELECTION_TEXT%";
061
062    /** Text metrics key. */
063    private static final String TM_OPENER_LABEL = "OpenerLabel";
064
065    /** The widget type identifier. */
066    private static final String WIDGET_TYPE = "multiselectbox";
067
068    /** The ghost value. */
069    protected String m_ghostValue;
070
071    /** The widget displayed in the opener. */
072    protected CmsLabel m_openerWidget;
073
074    /** A map from select options to their label texts. */
075    private Map<String, String> m_items;
076
077    /***/
078    private CmsMultiSelectCell m_multiSelectCell;
079
080    /** The text which should be displayed in the opener if there is no selection. */
081    private String m_noSelectionOpenerText;
082
083    /** The text which should be displayed if there is no selection. */
084    private String m_noSelectionText;
085
086    /** A map of titles for the select options which should  be displayed on mouseover. */
087    private Map<String, String> m_titles = new HashMap<String, String>();
088
089    /**
090     * Default constructor.<p>
091     */
092    public CmsMultiSelectBox() {
093
094        m_items = new HashMap<String, String>();
095    }
096
097    /**
098     * Creates a new select box, with the option of adding a "not selected" choice.<p>
099     *
100     * @param items the map of select options
101     * @param addNullOption if true, a "not selected" option will be added to the select box
102     */
103    public CmsMultiSelectBox(Map<String, String> items, boolean addNullOption) {
104
105        m_items = new HashMap<String, String>(items);
106        m_multiSelectCell.getElement().getStyle().setWidth(100, Unit.PCT);
107        if (m_items.containsKey(NO_SELECTION_TEXT)) {
108            m_noSelectionText = m_items.get(NO_SELECTION_TEXT);
109            m_noSelectionOpenerText = m_items.get(NO_SELECTION_OPENER_TEXT);
110            if (m_noSelectionOpenerText == null) {
111                m_noSelectionOpenerText = m_noSelectionText;
112            }
113            m_items.remove(NO_SELECTION_TEXT);
114            m_items.remove(NO_SELECTION_OPENER_TEXT);
115        }
116        if (addNullOption) {
117            String text = Messages.get().key(Messages.GUI_SELECTBOX_EMPTY_SELECTION_0);
118            m_items.put("", text);
119        }
120        if (addNullOption) {
121            selectValue("");
122        }
123    }
124
125    /**
126     * Initializes this class.<p>
127     */
128    public static void initClass() {
129
130        // registers a factory for creating new instances of this widget
131        CmsWidgetFactoryRegistry.instance().registerFactory(WIDGET_TYPE, new I_CmsFormWidgetFactory() {
132
133            /**
134             * @see org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetFactory#createWidget(java.util.Map, com.google.common.base.Optional)
135             */
136            public I_CmsFormWidget createWidget(Map<String, String> widgetParams, Optional<String> defaultValue) {
137
138                Map<String, CmsPair<String, Boolean>> entries = new HashMap<String, CmsPair<String, Boolean>>();
139                String label = "Select";
140                if (widgetParams.containsKey("label")) {
141                    label = widgetParams.get("label");
142                    widgetParams.remove("label");
143                }
144                for (Map.Entry<String, String> entry : widgetParams.entrySet()) {
145                    entries.put(entry.getKey(), CmsPair.create(entry.getValue(), Boolean.FALSE));
146                }
147                CmsMultiSelectCell cell = new CmsMultiSelectCell(entries);
148                cell.setOpenerText(label);
149                CmsMultiSelectBox box = new CmsMultiSelectBox();
150                box.addOption(cell);
151                return box;
152            }
153        });
154    }
155
156    /**
157     * Adds a new selection cell.<p>
158     *
159     * @param cell the new selection cell
160     */
161    @Override
162    public void addOption(CmsMultiSelectCell cell) {
163
164        m_multiSelectCell = cell;
165        super.addOption(cell);
166    }
167
168    /**
169     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getApparentValue()
170     */
171    public String getApparentValue() {
172
173        String val = getFormValueAsString();
174        if (val == null) {
175            val = m_ghostValue;
176        }
177        return val;
178
179    }
180
181    /**
182     * Returns all CmsCheckBoxes used.<p>
183     * @return a list of CmsCheckBoxes
184     */
185    public List<CmsCheckBox> getCheckboxes() {
186
187        return m_multiSelectCell.getCheckbox();
188    }
189
190    /**
191     * @see org.opencms.gwt.client.ui.input.A_CmsSelectBox#getFormValueAsString()
192     */
193    @Override
194    public String getFormValueAsString() {
195
196        String result = "";
197        List<CmsCheckBox> checkBox = m_multiSelectCell.getCheckbox();
198        Iterator<CmsCheckBox> it = checkBox.iterator();
199        while (it.hasNext()) {
200            CmsCheckBox chbox = it.next();
201            if (chbox.isChecked()) {
202                result += chbox.getText() + "|";
203            }
204        }
205        if (result.length() > 0) {
206            result = result.substring(0, result.lastIndexOf("|"));
207        }
208        return result;
209    }
210
211    /**
212     * @see org.opencms.gwt.client.ui.input.A_CmsSelectBox#selectValue(java.lang.String)
213     */
214    @Override
215    public void selectValue(String value) {
216
217        super.selectValue(value);
218        updateStyle();
219    }
220
221    /**
222     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setAutoHideParent(org.opencms.gwt.client.ui.I_CmsAutoHider)
223     */
224    public void setAutoHideParent(I_CmsAutoHider autoHideParent) {
225
226        // nothing to do
227
228    }
229
230    /**
231     * @see org.opencms.gwt.client.ui.input.A_CmsSelectBox#setFormValueAsString(java.lang.String)
232     */
233    @Override
234    public void setFormValueAsString(String value) {
235
236        String[] values = value.split("\\|");
237        List<CmsCheckBox> checkBox = m_multiSelectCell.getCheckbox();
238        for (String value2 : values) {
239            Iterator<CmsCheckBox> it = checkBox.iterator();
240            int y = 0;
241            while (it.hasNext()) {
242                CmsCheckBox chbox = it.next();
243                if (chbox.getText().equals(value2)) {
244                    m_multiSelectCell.get(y).setChecked(true);
245                }
246                y++;
247            }
248        }
249
250    }
251
252    /**
253     * @see org.opencms.gwt.client.ui.input.I_CmsHasGhostValue#setGhostMode(boolean)
254     */
255    public void setGhostMode(boolean ghostMode) {
256
257        // do nothing for now
258
259    }
260
261    /**
262     * @see org.opencms.gwt.client.ui.input.I_CmsHasGhostValue#setGhostValue(java.lang.String, boolean)
263     */
264    public void setGhostValue(String value, boolean ghostMode) {
265
266        if (value == null) {
267            value = "";
268        }
269        String otherOptionText = m_items.get(value);
270        String message = m_noSelectionText != null
271        ? m_noSelectionText
272        : Messages.get().key(Messages.GUI_SELECTBOX_EMPTY_SELECTION_1);
273        message = CmsMessages.formatMessage(message, otherOptionText);
274        //setTextForNullSelection(message);
275        m_ghostValue = value;
276        updateCells();
277        if (ghostMode) {
278            selectValue("");
279        }
280    }
281
282    /**
283     * Sets the text that is used for the "not selected" option.<p>
284     *
285     * @param text the text which should be used for the "not selected" option
286     */
287    public void setTextForNullSelection(String text) {
288
289        // do nothing if there's no null option
290        CmsMultiSelectCell cell = m_selectCells.get("");
291        if (cell == null) {
292            return;
293        }
294        cell.setTitle(text);
295        // if the null option is selected, we still need to update the opener
296        if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_selectedValue)) {
297            selectValue("");
298        }
299    }
300
301    /**
302     * Sets the title for a select option.<p>
303     *
304     * Note: This will only affect select options added *after* calling this method!
305     *
306     * @param option the select option value
307     * @param title the new title for the option
308     */
309    public void setTitle(String option, String title) {
310
311        m_titles.put(option, title);
312    }
313
314    /**
315     * @see org.opencms.gwt.client.ui.input.A_CmsSelectBox#truncateOpener(java.lang.String, int)
316     */
317    @Override
318    public void truncateOpener(String prefix, int width) {
319
320        m_openerWidget.truncate(prefix + '_' + TM_OPENER_LABEL, width);
321    }
322
323    /**
324     * Updates a single select cell.<p>
325     *
326     * @param cell the select cell to update
327     */
328    public void updateCell(CmsMultiSelectCell cell) {
329
330        // do nothing
331    }
332
333    /**
334     * Updates the select cells.<p>
335     */
336    public void updateCells() {
337
338        for (CmsMultiSelectCell cell : m_selectCells.values()) {
339            updateCell(cell);
340        }
341    }
342
343    /**
344     * @see org.opencms.gwt.client.ui.input.A_CmsSelectBox#createUnknownOption(java.lang.String)
345     */
346    @Override
347    protected CmsMultiSelectCell createUnknownOption(String value) {
348
349        /*CmsLabelSelectCell cell = new CmsMultiSelectCell(value, value);
350        return cell;*/
351        // ERROR comes in time
352        return null;
353
354    }
355
356    /**
357     * Helper method to get the title for a given select option.<p>
358     *
359     * @param option the select option value
360     * @param defaultValue the value to return when no title for the value was found
361     *
362     * @return the title for the select option
363     */
364    protected String getTitle(String option, String defaultValue) {
365
366        if ((option != null) && m_titles.containsKey(option)) {
367            return m_titles.get(option);
368        }
369        return defaultValue;
370    }
371
372    /**
373     * @see org.opencms.gwt.client.ui.input.A_CmsSelectBox#initOpener()
374     */
375    @Override
376    protected void initOpener() {
377
378        m_openerWidget = new CmsLabel();
379        m_openerWidget.addStyleName(CSS.selectBoxOpener());
380        m_opener.add(m_openerWidget);
381    }
382
383    /**
384     * @see com.google.gwt.user.client.ui.Widget#onLoad()
385     */
386    @Override
387    protected void onLoad() {
388
389        super.onLoad();
390        updateStyle();
391    }
392
393    /**
394     * @see org.opencms.gwt.client.ui.input.A_CmsSelectBox#updateOpener(java.lang.String)
395     */
396    @Override
397    protected void updateOpener(String newValue) {
398
399        CmsLabel label = m_openerWidget;
400        CmsMultiSelectCell cell = m_selectCells.get(newValue);
401        String openerText = cell.getOpenerText();
402        label.setText(openerText);
403        label.setTitle(getTitle(cell.getValue(), openerText));
404    }
405
406    /**
407     * This method should be used to make changes to the CSS style of the select box when the value changes.<p>
408     */
409    protected void updateStyle() {
410
411        // do nothing
412    }
413
414}