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}