001/* 002 * File : $Source: /home/cvs/OpenCms-v8/src/org/opencms/widgets/CmsSelectGroupWidget.java,v $ 003 * Date : $Date: 2010-07-23 08:29:34 $ 004 * Version: $Revision: 1.1 $ 005 * 006 * This library is part of OpenCms - 007 * the Open Source Content Management System 008 * 009 * Copyright (C) 2002 - 2009 Alkacon Software (http://www.alkacon.com) 010 * 011 * This library is free software; you can redistribute it and/or 012 * modify it under the terms of the GNU Lesser General Public 013 * License as published by the Free Software Foundation; either 014 * version 2.1 of the License, or (at your option) any later version. 015 * 016 * This library is distributed in the hope that it will be useful, 017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 * Lesser General Public License for more details. 020 * 021 * For further information about Alkacon Software, please see the 022 * company website: http://www.alkacon.com 023 * 024 * For further information about OpenCms, please see the 025 * project website: http://www.opencms.org 026 * 027 * You should have received a copy of the GNU Lesser General Public 028 * License along with this library; if not, write to the Free Software 029 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 030 */ 031 032package org.opencms.widgets; 033 034import org.opencms.file.CmsGroup; 035import org.opencms.file.CmsObject; 036import org.opencms.file.CmsResource; 037import org.opencms.i18n.CmsMessages; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.main.OpenCms; 041import org.opencms.security.CmsOrganizationalUnit; 042import org.opencms.util.CmsMacroResolver; 043import org.opencms.util.CmsStringUtil; 044import org.opencms.workplace.CmsWorkplace; 045import org.opencms.xml.types.A_CmsXmlContentValue; 046 047import java.util.ArrayList; 048import java.util.Iterator; 049import java.util.List; 050import java.util.Locale; 051import java.util.Map; 052import java.util.regex.Pattern; 053import java.util.regex.PatternSyntaxException; 054 055import org.apache.commons.logging.Log; 056 057/** 058 * Provides a widget for group selection multi select boxes.<p> 059 * 060 * This widget is configurable with the following options:<p> 061 * <ul> 062 * <li><code>groupfilter</code>: regular expression to filter available groups</li> 063 * <li><code>groups</code>: comma separated list of group names to show in the select box. <b>Note</b>: 064 * if this configuration option if used, 065 * <code>groupfilter</code> and <code>includesubous</code> are <i>not</i> considered anymore.</li> 066 * <li><code>includesubous</code>: boolean flag to indicate if sub OUs should be scanned for groups to select</li> 067 * <li><code>oufqn</code>: the fully qualified name of the OU to read the groups from</li> 068 * </ul> 069 * To map the selected group to a permission to set, use the following mapping configuration:<p> 070 * <code><mapping element="..." mapto="permission:GROUP:+r+v|GROUP.ALL_OTHERS:|GROUP.Projectmanagers:+r+v+w+c" /></code><p> 071 * This means that the +r+v permission is written for the principal <code>GROUP</code> on the resource. 072 * Additionally two permissions are written as default: for <code>ALL_OTHERS</code>, no allowed permission is set, 073 * for <code>Projectmanagers</code>, "+r+v+w+c" is set.<p> 074 * 075 * @author Mario Jaeger 076 * 077 * @version $Revision: 1.1 $ 078 * 079 * @since 8.0.2 080 */ 081public class CmsMultiSelectGroupWidget extends CmsSelectGroupWidget { 082 083 /** Configuration parameter name to use all available groups as default. */ 084 public static final String CONFIGURATION_DEFAULT_ALL = "defaultall"; 085 086 /** The log object for this class. */ 087 private static final Log LOG = CmsLog.getLog(CmsMultiSelectGroupWidget.class); 088 089 /** Indicates if used html code is a multi selection list or a list of checkboxes. */ 090 private boolean m_asCheckBoxes; 091 092 /** Flag indicating if to use all available groups as default. */ 093 private boolean m_defaultAllAvailable; 094 095 /** Indicates if sub OUs should be included when reading the groups. */ 096 private boolean m_includeSubOus; 097 098 /** The fully qualified name of the OU to read the groups from. */ 099 private String m_ouFqn; 100 101 /** Flag to indicate if the multi-select needs to be activated by a check box. */ 102 private boolean m_requiresActivation; 103 104 /** 105 * Creates a new group select widget.<p> 106 */ 107 public CmsMultiSelectGroupWidget() { 108 109 // empty constructor is required for class registration 110 super(); 111 } 112 113 /** 114 * Creates a group select widget with the specified select options.<p> 115 * 116 * @param configuration the configuration (possible options) for the group select box 117 */ 118 public CmsMultiSelectGroupWidget(String configuration) { 119 120 super(configuration); 121 } 122 123 /** 124 * Creates a select widget with the select options specified in the given configuration List.<p> 125 * 126 * The list elements must be of type <code>{@link CmsSelectWidgetOption}</code>.<p> 127 * 128 * @param configuration the configuration (possible options) for the select widget 129 * @param asCheckboxes indicates if used html code is a multi selection list or a list of checkboxes 130 * 131 * @see CmsSelectWidgetOption 132 */ 133 public CmsMultiSelectGroupWidget(String configuration, boolean asCheckboxes) { 134 135 super(configuration); 136 m_asCheckBoxes = asCheckboxes; 137 } 138 139 /** 140 * @see org.opencms.widgets.I_CmsADEWidget#getConfiguration(org.opencms.file.CmsObject, org.opencms.xml.types.A_CmsXmlContentValue, org.opencms.i18n.CmsMessages, org.opencms.file.CmsResource, java.util.Locale) 141 */ 142 @Override 143 public String getConfiguration( 144 CmsObject cms, 145 A_CmsXmlContentValue schemaType, 146 CmsMessages messages, 147 CmsResource resource, 148 Locale contentLocale) { 149 150 String result = ""; 151 CmsDummyWidgetDialog widgetDialog = new CmsDummyWidgetDialog(schemaType.getLocale(), messages); 152 widgetDialog.setResource(resource); 153 List<CmsSelectWidgetOption> options = parseSelectOptions(cms, widgetDialog, schemaType); 154 Iterator<CmsSelectWidgetOption> it = options.iterator(); 155 int i = 0; 156 while (it.hasNext()) { 157 CmsSelectWidgetOption option = it.next(); 158 if (i > 0) { 159 result += "|"; 160 } 161 result += option.toString(); 162 i++; 163 } 164 if (m_requiresActivation) { 165 result += "|" + CmsMultiSelectWidget.CONFIGURATION_REQUIRES_ACTIVATION; 166 } 167 return result; 168 } 169 170 /** 171 * @see org.opencms.widgets.I_CmsWidget#getDialogIncludes(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog) 172 */ 173 @Override 174 public String getDialogIncludes(CmsObject cms, I_CmsWidgetDialog widgetDialog) { 175 176 return getJSIncludeFile(CmsWorkplace.getSkinUri() + "components/widgets/multiselector.js"); 177 } 178 179 /** 180 * @see org.opencms.widgets.I_CmsWidget#getDialogWidget(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 181 */ 182 @Override 183 public String getDialogWidget(CmsObject cms, I_CmsWidgetDialog widgetDialog, I_CmsWidgetParameter param) { 184 185 String id = param.getId(); 186 StringBuffer result = new StringBuffer(16); 187 String height = getHeight(); 188 List<CmsSelectWidgetOption> options = parseSelectOptions(cms, widgetDialog.getMessages(), param); 189 result.append("<td class=\"xmlTd\">"); 190 // the configured select widget height start element 191 if (m_asCheckBoxes && CmsStringUtil.isNotEmptyOrWhitespaceOnly(height)) { 192 result.append("<div style=\"height: " + height + "; overflow: auto;\">"); 193 } 194 if (!m_asCheckBoxes) { 195 if (m_requiresActivation) { 196 result.append( 197 "<input style=\"vertical-align:middle;\" type=\"checkbox\" id=\"check" 198 + id 199 + "\" name=\"check" 200 + id 201 + "\"" 202 + "onclick=toggleMultiSelectWidget(this);" 203 + " />"); 204 result.append(" <label style=\"vertical-align:middle;\" for=\"check" + id + "\">"); 205 result.append(widgetDialog.getMessages().key(Messages.GUI_MULTISELECT_ACTIVATE_0)); 206 result.append("</label> "); 207 // adding hidden input with the current value, because disabled select box value won't be submitted 208 result.append("<input type='hidden' name='").append(id).append("' id='").append(id).append("' value='"); 209 List<String> values = getSelectedValues(cms, param); 210 if (values.size() > 0) { 211 result.append(values.get(0)); 212 for (int i = 1; i < values.size(); i++) { 213 result.append(",").append(values.get(i)); 214 } 215 } 216 result.append("' />"); 217 id = "display" + id; 218 } 219 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(height)) { 220 result.append("<select style=\"height: " + height + ";\" multiple size='"); 221 } else { 222 result.append("<select multiple size='"); 223 } 224 result.append(options.size()); 225 result.append("' style=\"vertical-align:middle;\" class=\"xmlInput"); 226 if (param.hasError()) { 227 result.append(" xmlInputError"); 228 } 229 result.append("\" "); 230 if (m_requiresActivation) { 231 result.append("disabled=\"true\" "); 232 } 233 result.append("name=\""); 234 result.append(id); 235 result.append("\" id=\""); 236 result.append(id); 237 result.append("\">"); 238 } 239 240 // get select box options from default value String 241 List<String> selected = getSelectedValues(cms, param); 242 Iterator<CmsSelectWidgetOption> i = options.iterator(); 243 while (i.hasNext()) { 244 CmsSelectWidgetOption option = i.next(); 245 // create the option 246 if (!m_asCheckBoxes) { 247 result.append("<option value=\""); 248 result.append(option.getValue()); 249 result.append("\""); 250 if (selected.contains(option.getValue())) { 251 result.append(" selected=\"selected\""); 252 } 253 result.append(">"); 254 result.append(option.getOption()); 255 result.append("</option>"); 256 } else { 257 result.append("<input type='checkbox' name='"); 258 result.append(id); 259 result.append("' value='"); 260 result.append(option.getValue()); 261 result.append("'"); 262 if (selected.contains(option.getValue())) { 263 result.append(" checked"); 264 } 265 result.append(">"); 266 result.append(option.getOption()); 267 result.append("<br>"); 268 } 269 } 270 if (!m_asCheckBoxes) { 271 result.append("</select>"); 272 } 273 // the configured select widget height end element 274 if (m_asCheckBoxes && CmsStringUtil.isNotEmptyOrWhitespaceOnly(height)) { 275 result.append("</div>"); 276 } 277 result.append("</td>"); 278 279 return result.toString(); 280 } 281 282 /** 283 * @see org.opencms.widgets.I_CmsADEWidget#getWidgetName() 284 */ 285 @Override 286 public String getWidgetName() { 287 288 return CmsMultiSelectGroupWidget.class.getName(); 289 } 290 291 /** 292 * @see org.opencms.widgets.I_CmsWidget#newInstance() 293 */ 294 @Override 295 public I_CmsWidget newInstance() { 296 297 return new CmsMultiSelectGroupWidget(getConfiguration()); 298 } 299 300 /** 301 * @see org.opencms.widgets.A_CmsWidget#setConfiguration(java.lang.String) 302 */ 303 @Override 304 public void setConfiguration(String configuration) { 305 306 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(configuration)) { 307 int asCheckBoxesIndex = configuration.indexOf(CmsMultiSelectWidget.CONFIGURATION_ASCHECKBOXES); 308 if (asCheckBoxesIndex != -1) { 309 // the height is set 310 String asCheckBoxes = configuration.substring( 311 asCheckBoxesIndex + CmsMultiSelectWidget.CONFIGURATION_ASCHECKBOXES.length() + 1); 312 if (asCheckBoxes.indexOf('|') != -1) { 313 // cut eventual following configuration values 314 asCheckBoxes = asCheckBoxes.substring(0, asCheckBoxes.indexOf('|')); 315 } 316 m_asCheckBoxes = Boolean.parseBoolean(asCheckBoxes); 317 } 318 int reqiresActivationIndex = configuration.indexOf(CmsMultiSelectWidget.CONFIGURATION_REQUIRES_ACTIVATION); 319 if (reqiresActivationIndex != -1) { 320 // the height is set 321 String requiresActivation = configuration.substring( 322 reqiresActivationIndex + CmsMultiSelectWidget.CONFIGURATION_REQUIRES_ACTIVATION.length() + 1); 323 if (requiresActivation.indexOf('|') != -1) { 324 // cut eventual following configuration values 325 requiresActivation = requiresActivation.substring(0, requiresActivation.indexOf('|')); 326 } 327 m_requiresActivation = Boolean.parseBoolean(requiresActivation); 328 } 329 } 330 super.setConfiguration(configuration); 331 } 332 333 /** 334 * @see org.opencms.widgets.A_CmsWidget#setEditorValue(org.opencms.file.CmsObject, java.util.Map, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 335 */ 336 @Override 337 public void setEditorValue( 338 CmsObject cms, 339 Map<String, String[]> formParameters, 340 I_CmsWidgetDialog widgetDialog, 341 I_CmsWidgetParameter param) { 342 343 CmsMultiSelectWidget.setMultiSelectEditorValue(cms, formParameters, widgetDialog, param); 344 } 345 346 /** 347 * @see org.opencms.widgets.CmsSelectGroupWidget#parseSelectOptions(org.opencms.file.CmsObject, org.opencms.i18n.CmsMessages, org.opencms.widgets.I_CmsWidgetParameter) 348 */ 349 @Override 350 protected List<CmsSelectWidgetOption> parseSelectOptions( 351 CmsObject cms, 352 CmsMessages messages, 353 I_CmsWidgetParameter param) { 354 355 // only create options if not already done 356 if (getSelectOptions() == null) { 357 // parse widget configuration 358 parseConfiguration(cms, messages); 359 List<CmsSelectWidgetOption> result = new ArrayList<CmsSelectWidgetOption>(); 360 361 if (isUseGroupNames()) { 362 // a list of group names is configured, show them 363 for (Iterator<String> i = getGroupNames().iterator(); i.hasNext();) { 364 String groupName = i.next(); 365 try { 366 // ensure that only existing groups are available in the select box 367 CmsGroup group = cms.readGroup(getOuFqn() + groupName); 368 result.add( 369 new CmsSelectWidgetOption(group.getName(), m_defaultAllAvailable, group.getSimpleName())); 370 } catch (CmsException e) { 371 // error reading the group by name, simply skip it 372 } 373 } 374 } else { 375 // read the groups from an optionally configured OU and filter them if configured 376 try { 377 List<CmsGroup> groups = OpenCms.getOrgUnitManager().getGroups(cms, getOuFqn(), isIncludeSubOus()); 378 for (Iterator<CmsGroup> i = groups.iterator(); i.hasNext();) { 379 CmsGroup group = i.next(); 380 if (isUseGroupFilter()) { 381 // check if group name matches the given regular expression 382 if (!getGroupFilter().matcher(group.getSimpleName()).matches()) { 383 continue; 384 } 385 } 386 result.add( 387 new CmsSelectWidgetOption(group.getName(), m_defaultAllAvailable, group.getSimpleName())); 388 } 389 } catch (CmsException e) { 390 // error reading the groups 391 } 392 393 } 394 setSelectOptions(result); 395 } 396 return getSelectOptions(); 397 } 398 399 /** 400 * @see org.opencms.widgets.A_CmsSelectWidget#parseSelectOptions(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 401 */ 402 @Override 403 protected List<CmsSelectWidgetOption> parseSelectOptions( 404 CmsObject cms, 405 I_CmsWidgetDialog widgetDialog, 406 I_CmsWidgetParameter param) { 407 408 return parseSelectOptions(cms, widgetDialog.getMessages(), param); 409 } 410 411 /** 412 * Returns the configured group filter to match groups to show in the select box.<p> 413 * 414 * @return the configured group filter to match groups to show in the select box 415 */ 416 private Pattern getGroupFilter() { 417 418 return m_groupFilter; 419 } 420 421 /** 422 * Returns the configured group names to show in the select box.<p> 423 * 424 * @return configured group names to show in the select box 425 */ 426 private List<String> getGroupNames() { 427 428 return m_groupNames; 429 } 430 431 /** 432 * Returns the fully qualified name of the OU to read the groups from.<p> 433 * 434 * @return the fully qualified name of the OU to read the groups from 435 */ 436 private String getOuFqn() { 437 438 return m_ouFqn; 439 } 440 441 /** 442 * Returns if sub OUs should be considered when filtering the groups.<p> 443 * 444 * @return <code>true</code> if sub OUs should be considered, otherwise <code>false</code> 445 */ 446 private boolean isIncludeSubOus() { 447 448 return m_includeSubOus; 449 } 450 451 /** 452 * Returns if a group filter is configured to match groups to show in the select box.<p> 453 * 454 * @return <code>true</code> if a group filter is configured, otherwise <code>false</code> 455 */ 456 private boolean isUseGroupFilter() { 457 458 return getGroupFilter() != null; 459 } 460 461 /** 462 * Returns if group names are configured to show in the select box.<p> 463 * 464 * @return <code>true</code> if group names are configured, otherwise <code>false</code> 465 */ 466 private boolean isUseGroupNames() { 467 468 return getGroupNames() != null; 469 } 470 471 /** 472 * Parses the widget configuration string.<p> 473 * 474 * @param cms the current users OpenCms context 475 * @param widgetDialog the dialog of this widget 476 */ 477 private void parseConfiguration(CmsObject cms, CmsMessages widgetDialog) { 478 479 String configString = CmsMacroResolver.resolveMacros(getConfiguration(), cms, widgetDialog); 480 Map<String, String> config = CmsStringUtil.splitAsMap(configString, "|", "="); 481 // get the list of group names to show 482 String groups = config.get(CONFIGURATION_GROUPS); 483 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(groups)) { 484 m_groupNames = CmsStringUtil.splitAsList(groups, ',', true); 485 } 486 // get the regular expression to filter the groups 487 String filter = config.get(CONFIGURATION_GROUPFILTER); 488 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(filter)) { 489 try { 490 m_groupFilter = Pattern.compile(filter); 491 } catch (PatternSyntaxException e) { 492 // log pattern syntax errors 493 LOG.error(Messages.get().getBundle().key(Messages.LOG_ERR_WIDGET_SELECTGROUP_PATTERN_1, filter)); 494 } 495 } 496 // get the OU to read the groups from 497 m_ouFqn = config.get(CONFIGURATION_OUFQN); 498 if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_ouFqn)) { 499 m_ouFqn = ""; 500 } else if (!m_ouFqn.endsWith(CmsOrganizationalUnit.SEPARATOR)) { 501 m_ouFqn += CmsOrganizationalUnit.SEPARATOR; 502 } 503 // set the flag to include sub OUs 504 m_includeSubOus = Boolean.parseBoolean(config.get(CONFIGURATION_INCLUDESUBOUS)); 505 m_defaultAllAvailable = Boolean.parseBoolean(config.get(CONFIGURATION_DEFAULT_ALL)); 506 } 507}