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("<input style=\"vertical-align:middle;\" type=\"checkbox\" id=\"check" 197 + id 198 + "\" name=\"check" 199 + id 200 + "\"" 201 + "onclick=toggleMultiSelectWidget(this);" 202 + " />"); 203 result.append(" <label style=\"vertical-align:middle;\" for=\"check" + id + "\">"); 204 result.append(widgetDialog.getMessages().key(Messages.GUI_MULTISELECT_ACTIVATE_0)); 205 result.append("</label> "); 206 // adding hidden input with the current value, because disabled select box value won't be submitted 207 result.append("<input type='hidden' name='").append(id).append("' id='").append(id).append("' value='"); 208 List<String> values = getSelectedValues(cms, param); 209 if (values.size() > 0) { 210 result.append(values.get(0)); 211 for (int i = 1; i < values.size(); i++) { 212 result.append(",").append(values.get(i)); 213 } 214 } 215 result.append("' />"); 216 id = "display" + id; 217 } 218 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(height)) { 219 result.append("<select style=\"height: " + height + ";\" multiple size='"); 220 } else { 221 result.append("<select multiple size='"); 222 } 223 result.append(options.size()); 224 result.append("' style=\"vertical-align:middle;\" class=\"xmlInput"); 225 if (param.hasError()) { 226 result.append(" xmlInputError"); 227 } 228 result.append("\" "); 229 if (m_requiresActivation) { 230 result.append("disabled=\"true\" "); 231 } 232 result.append("name=\""); 233 result.append(id); 234 result.append("\" id=\""); 235 result.append(id); 236 result.append("\">"); 237 } 238 239 // get select box options from default value String 240 List<String> selected = getSelectedValues(cms, param); 241 Iterator<CmsSelectWidgetOption> i = options.iterator(); 242 while (i.hasNext()) { 243 CmsSelectWidgetOption option = i.next(); 244 // create the option 245 if (!m_asCheckBoxes) { 246 result.append("<option value=\""); 247 result.append(option.getValue()); 248 result.append("\""); 249 if (selected.contains(option.getValue())) { 250 result.append(" selected=\"selected\""); 251 } 252 result.append(">"); 253 result.append(option.getOption()); 254 result.append("</option>"); 255 } else { 256 result.append("<input type='checkbox' name='"); 257 result.append(id); 258 result.append("' value='"); 259 result.append(option.getValue()); 260 result.append("'"); 261 if (selected.contains(option.getValue())) { 262 result.append(" checked"); 263 } 264 result.append(">"); 265 result.append(option.getOption()); 266 result.append("<br>"); 267 } 268 } 269 if (!m_asCheckBoxes) { 270 result.append("</select>"); 271 } 272 // the configured select widget height end element 273 if (m_asCheckBoxes && CmsStringUtil.isNotEmptyOrWhitespaceOnly(height)) { 274 result.append("</div>"); 275 } 276 result.append("</td>"); 277 278 return result.toString(); 279 } 280 281 /** 282 * @see org.opencms.widgets.I_CmsADEWidget#getWidgetName() 283 */ 284 @Override 285 public String getWidgetName() { 286 287 return CmsMultiSelectGroupWidget.class.getName(); 288 } 289 290 /** 291 * @see org.opencms.widgets.I_CmsWidget#newInstance() 292 */ 293 @Override 294 public I_CmsWidget newInstance() { 295 296 return new CmsMultiSelectGroupWidget(getConfiguration()); 297 } 298 299 /** 300 * @see org.opencms.widgets.A_CmsWidget#setConfiguration(java.lang.String) 301 */ 302 @Override 303 public void setConfiguration(String configuration) { 304 305 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(configuration)) { 306 int asCheckBoxesIndex = configuration.indexOf(CmsMultiSelectWidget.CONFIGURATION_ASCHECKBOXES); 307 if (asCheckBoxesIndex != -1) { 308 // the height is set 309 String asCheckBoxes = configuration.substring(asCheckBoxesIndex 310 + CmsMultiSelectWidget.CONFIGURATION_ASCHECKBOXES.length() 311 + 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(reqiresActivationIndex 322 + CmsMultiSelectWidget.CONFIGURATION_REQUIRES_ACTIVATION.length() 323 + 1); 324 if (requiresActivation.indexOf('|') != -1) { 325 // cut eventual following configuration values 326 requiresActivation = requiresActivation.substring(0, requiresActivation.indexOf('|')); 327 } 328 m_requiresActivation = Boolean.parseBoolean(requiresActivation); 329 } 330 } 331 super.setConfiguration(configuration); 332 } 333 334 /** 335 * @see org.opencms.widgets.A_CmsWidget#setEditorValue(org.opencms.file.CmsObject, java.util.Map, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 336 */ 337 @Override 338 public void setEditorValue( 339 CmsObject cms, 340 Map<String, String[]> formParameters, 341 I_CmsWidgetDialog widgetDialog, 342 I_CmsWidgetParameter param) { 343 344 CmsMultiSelectWidget.setMultiSelectEditorValue(cms, formParameters, widgetDialog, param); 345 } 346 347 /** 348 * @see org.opencms.widgets.CmsSelectGroupWidget#parseSelectOptions(org.opencms.file.CmsObject, org.opencms.i18n.CmsMessages, org.opencms.widgets.I_CmsWidgetParameter) 349 */ 350 @Override 351 protected List<CmsSelectWidgetOption> parseSelectOptions( 352 CmsObject cms, 353 CmsMessages messages, 354 I_CmsWidgetParameter param) { 355 356 // only create options if not already done 357 if (getSelectOptions() == null) { 358 // parse widget configuration 359 parseConfiguration(cms, messages); 360 List<CmsSelectWidgetOption> result = new ArrayList<CmsSelectWidgetOption>(); 361 362 if (isUseGroupNames()) { 363 // a list of group names is configured, show them 364 for (Iterator<String> i = getGroupNames().iterator(); i.hasNext();) { 365 String groupName = i.next(); 366 try { 367 // ensure that only existing groups are available in the select box 368 CmsGroup group = cms.readGroup(getOuFqn() + groupName); 369 result.add(new CmsSelectWidgetOption( 370 group.getName(), 371 m_defaultAllAvailable, 372 group.getSimpleName())); 373 } catch (CmsException e) { 374 // error reading the group by name, simply skip it 375 } 376 } 377 } else { 378 // read the groups from an optionally configured OU and filter them if configured 379 try { 380 List<CmsGroup> groups = OpenCms.getOrgUnitManager().getGroups(cms, getOuFqn(), isIncludeSubOus()); 381 for (Iterator<CmsGroup> i = groups.iterator(); i.hasNext();) { 382 CmsGroup group = i.next(); 383 if (isUseGroupFilter()) { 384 // check if group name matches the given regular expression 385 if (!getGroupFilter().matcher(group.getSimpleName()).matches()) { 386 continue; 387 } 388 } 389 result.add(new CmsSelectWidgetOption( 390 group.getName(), 391 m_defaultAllAvailable, 392 group.getSimpleName())); 393 } 394 } catch (CmsException e) { 395 // error reading the groups 396 } 397 398 } 399 setSelectOptions(result); 400 } 401 return getSelectOptions(); 402 } 403 404 /** 405 * @see org.opencms.widgets.A_CmsSelectWidget#parseSelectOptions(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 406 */ 407 @Override 408 protected List<CmsSelectWidgetOption> parseSelectOptions( 409 CmsObject cms, 410 I_CmsWidgetDialog widgetDialog, 411 I_CmsWidgetParameter param) { 412 413 return parseSelectOptions(cms, widgetDialog.getMessages(), param); 414 } 415 416 /** 417 * Returns the configured group filter to match groups to show in the select box.<p> 418 * 419 * @return the configured group filter to match groups to show in the select box 420 */ 421 private Pattern getGroupFilter() { 422 423 return m_groupFilter; 424 } 425 426 /** 427 * Returns the configured group names to show in the select box.<p> 428 * 429 * @return configured group names to show in the select box 430 */ 431 private List<String> getGroupNames() { 432 433 return m_groupNames; 434 } 435 436 /** 437 * Returns the fully qualified name of the OU to read the groups from.<p> 438 * 439 * @return the fully qualified name of the OU to read the groups from 440 */ 441 private String getOuFqn() { 442 443 return m_ouFqn; 444 } 445 446 /** 447 * Returns if sub OUs should be considered when filtering the groups.<p> 448 * 449 * @return <code>true</code> if sub OUs should be considered, otherwise <code>false</code> 450 */ 451 private boolean isIncludeSubOus() { 452 453 return m_includeSubOus; 454 } 455 456 /** 457 * Returns if a group filter is configured to match groups to show in the select box.<p> 458 * 459 * @return <code>true</code> if a group filter is configured, otherwise <code>false</code> 460 */ 461 private boolean isUseGroupFilter() { 462 463 return getGroupFilter() != null; 464 } 465 466 /** 467 * Returns if group names are configured to show in the select box.<p> 468 * 469 * @return <code>true</code> if group names are configured, otherwise <code>false</code> 470 */ 471 private boolean isUseGroupNames() { 472 473 return getGroupNames() != null; 474 } 475 476 /** 477 * Parses the widget configuration string.<p> 478 * 479 * @param cms the current users OpenCms context 480 * @param widgetDialog the dialog of this widget 481 */ 482 private void parseConfiguration(CmsObject cms, CmsMessages widgetDialog) { 483 484 String configString = CmsMacroResolver.resolveMacros(getConfiguration(), cms, widgetDialog); 485 Map<String, String> config = CmsStringUtil.splitAsMap(configString, "|", "="); 486 // get the list of group names to show 487 String groups = config.get(CONFIGURATION_GROUPS); 488 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(groups)) { 489 m_groupNames = CmsStringUtil.splitAsList(groups, ',', true); 490 } 491 // get the regular expression to filter the groups 492 String filter = config.get(CONFIGURATION_GROUPFILTER); 493 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(filter)) { 494 try { 495 m_groupFilter = Pattern.compile(filter); 496 } catch (PatternSyntaxException e) { 497 // log pattern syntax errors 498 LOG.error(Messages.get().getBundle().key(Messages.LOG_ERR_WIDGET_SELECTGROUP_PATTERN_1, filter)); 499 } 500 } 501 // get the OU to read the groups from 502 m_ouFqn = config.get(CONFIGURATION_OUFQN); 503 if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_ouFqn)) { 504 m_ouFqn = ""; 505 } else if (!m_ouFqn.endsWith(CmsOrganizationalUnit.SEPARATOR)) { 506 m_ouFqn += CmsOrganizationalUnit.SEPARATOR; 507 } 508 // set the flag to include sub OUs 509 m_includeSubOus = Boolean.parseBoolean(config.get(CONFIGURATION_INCLUDESUBOUS)); 510 m_defaultAllAvailable = Boolean.parseBoolean(config.get(CONFIGURATION_DEFAULT_ALL)); 511 } 512}