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 * <li><code>fullnames</code>: boolean flag to indicate whether the full names of groups (including organizational unit) should be shown 069 * </ul> 070 * To map the selected group to a permission to set, use the following mapping configuration:<p> 071 * <code><mapping element="..." mapto="permission:GROUP:+r+v|GROUP.ALL_OTHERS:|GROUP.Projectmanagers:+r+v+w+c" /></code><p> 072 * This means that the +r+v permission is written for the principal <code>GROUP</code> on the resource. 073 * Additionally two permissions are written as default: for <code>ALL_OTHERS</code>, no allowed permission is set, 074 * for <code>Projectmanagers</code>, "+r+v+w+c" is set.<p> 075 * 076 * @author Mario Jaeger 077 * 078 * @version $Revision: 1.1 $ 079 * 080 * @since 8.0.2 081 */ 082public class CmsMultiSelectGroupWidget extends CmsSelectGroupWidget { 083 084 /** Configuration parameter name to use all available groups as default. */ 085 public static final String CONFIGURATION_DEFAULT_ALL = "defaultall"; 086 087 /** The log object for this class. */ 088 private static final Log LOG = CmsLog.getLog(CmsMultiSelectGroupWidget.class); 089 090 /** Indicates if used html code is a multi selection list or a list of checkboxes. */ 091 private boolean m_asCheckBoxes; 092 093 /** Flag indicating if to use all available groups as default. */ 094 private boolean m_defaultAllAvailable; 095 096 /** Indicates if sub OUs should be included when reading the groups. */ 097 private boolean m_includeSubOus; 098 099 /** The fully qualified name of the OU to read the groups from. */ 100 private String m_ouFqn; 101 102 /** Flag to indicate if the multi-select needs to be activated by a check box. */ 103 private boolean m_requiresActivation; 104 105 /** If true, show full group names (with OU) in the widget, and simple names otherwise. */ 106 private boolean m_useFullNames; 107 108 /** Configuration option to show full group names including OU.*/ 109 protected static final String CONFIGURATION_FULLNAMES = "fullnames"; 110 111 /** 112 * Creates a new group select widget.<p> 113 */ 114 public CmsMultiSelectGroupWidget() { 115 116 // empty constructor is required for class registration 117 super(); 118 } 119 120 /** 121 * Creates a group select widget with the specified select options.<p> 122 * 123 * @param configuration the configuration (possible options) for the group select box 124 */ 125 public CmsMultiSelectGroupWidget(String configuration) { 126 127 super(configuration); 128 } 129 130 /** 131 * Creates a select widget with the select options specified in the given configuration List.<p> 132 * 133 * The list elements must be of type <code>{@link CmsSelectWidgetOption}</code>.<p> 134 * 135 * @param configuration the configuration (possible options) for the select widget 136 * @param asCheckboxes indicates if used html code is a multi selection list or a list of checkboxes 137 * 138 * @see CmsSelectWidgetOption 139 */ 140 public CmsMultiSelectGroupWidget(String configuration, boolean asCheckboxes) { 141 142 super(configuration); 143 m_asCheckBoxes = asCheckboxes; 144 } 145 146 /** 147 * @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) 148 */ 149 @Override 150 public String getConfiguration( 151 CmsObject cms, 152 A_CmsXmlContentValue schemaType, 153 CmsMessages messages, 154 CmsResource resource, 155 Locale contentLocale) { 156 157 String result = ""; 158 CmsDummyWidgetDialog widgetDialog = new CmsDummyWidgetDialog(schemaType.getLocale(), messages); 159 widgetDialog.setResource(resource); 160 List<CmsSelectWidgetOption> options = parseSelectOptions(cms, widgetDialog, schemaType); 161 Iterator<CmsSelectWidgetOption> it = options.iterator(); 162 int i = 0; 163 while (it.hasNext()) { 164 CmsSelectWidgetOption option = it.next(); 165 if (i > 0) { 166 result += "|"; 167 } 168 result += option.toString(); 169 i++; 170 } 171 if (m_requiresActivation) { 172 result += "|" + CmsMultiSelectWidget.CONFIGURATION_REQUIRES_ACTIVATION; 173 } 174 return result; 175 } 176 177 /** 178 * @see org.opencms.widgets.I_CmsWidget#getDialogIncludes(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog) 179 */ 180 @Override 181 public String getDialogIncludes(CmsObject cms, I_CmsWidgetDialog widgetDialog) { 182 183 return getJSIncludeFile(CmsWorkplace.getSkinUri() + "components/widgets/multiselector.js"); 184 } 185 186 /** 187 * @see org.opencms.widgets.I_CmsWidget#getDialogWidget(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 188 */ 189 @Override 190 public String getDialogWidget(CmsObject cms, I_CmsWidgetDialog widgetDialog, I_CmsWidgetParameter param) { 191 192 String id = param.getId(); 193 StringBuffer result = new StringBuffer(16); 194 String height = getHeight(); 195 List<CmsSelectWidgetOption> options = parseSelectOptions(cms, widgetDialog.getMessages(), param); 196 result.append("<td class=\"xmlTd\">"); 197 // the configured select widget height start element 198 if (m_asCheckBoxes && CmsStringUtil.isNotEmptyOrWhitespaceOnly(height)) { 199 result.append("<div style=\"height: " + height + "; overflow: auto;\">"); 200 } 201 if (!m_asCheckBoxes) { 202 if (m_requiresActivation) { 203 result.append( 204 "<input style=\"vertical-align:middle;\" type=\"checkbox\" id=\"check" 205 + id 206 + "\" name=\"check" 207 + id 208 + "\"" 209 + "onclick=toggleMultiSelectWidget(this);" 210 + " />"); 211 result.append(" <label style=\"vertical-align:middle;\" for=\"check" + id + "\">"); 212 result.append(widgetDialog.getMessages().key(Messages.GUI_MULTISELECT_ACTIVATE_0)); 213 result.append("</label> "); 214 // adding hidden input with the current value, because disabled select box value won't be submitted 215 result.append("<input type='hidden' name='").append(id).append("' id='").append(id).append("' value='"); 216 List<String> values = getSelectedValues(cms, param); 217 if (values.size() > 0) { 218 result.append(values.get(0)); 219 for (int i = 1; i < values.size(); i++) { 220 result.append(",").append(values.get(i)); 221 } 222 } 223 result.append("' />"); 224 id = "display" + id; 225 } 226 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(height)) { 227 result.append("<select style=\"height: " + height + ";\" multiple size='"); 228 } else { 229 result.append("<select multiple size='"); 230 } 231 result.append(options.size()); 232 result.append("' style=\"vertical-align:middle;\" class=\"xmlInput"); 233 if (param.hasError()) { 234 result.append(" xmlInputError"); 235 } 236 result.append("\" "); 237 if (m_requiresActivation) { 238 result.append("disabled=\"true\" "); 239 } 240 result.append("name=\""); 241 result.append(id); 242 result.append("\" id=\""); 243 result.append(id); 244 result.append("\">"); 245 } 246 247 // get select box options from default value String 248 List<String> selected = getSelectedValues(cms, param); 249 Iterator<CmsSelectWidgetOption> i = options.iterator(); 250 while (i.hasNext()) { 251 CmsSelectWidgetOption option = i.next(); 252 // create the option 253 if (!m_asCheckBoxes) { 254 result.append("<option value=\""); 255 result.append(option.getValue()); 256 result.append("\""); 257 if (selected.contains(option.getValue())) { 258 result.append(" selected=\"selected\""); 259 } 260 result.append(">"); 261 result.append(option.getOption()); 262 result.append("</option>"); 263 } else { 264 result.append("<input type='checkbox' name='"); 265 result.append(id); 266 result.append("' value='"); 267 result.append(option.getValue()); 268 result.append("'"); 269 if (selected.contains(option.getValue())) { 270 result.append(" checked"); 271 } 272 result.append(">"); 273 result.append(option.getOption()); 274 result.append("<br>"); 275 } 276 } 277 if (!m_asCheckBoxes) { 278 result.append("</select>"); 279 } 280 // the configured select widget height end element 281 if (m_asCheckBoxes && CmsStringUtil.isNotEmptyOrWhitespaceOnly(height)) { 282 result.append("</div>"); 283 } 284 result.append("</td>"); 285 286 return result.toString(); 287 } 288 289 /** 290 * @see org.opencms.widgets.I_CmsADEWidget#getWidgetName() 291 */ 292 @Override 293 public String getWidgetName() { 294 295 return CmsMultiSelectGroupWidget.class.getName(); 296 } 297 298 /** 299 * @see org.opencms.widgets.I_CmsWidget#newInstance() 300 */ 301 @Override 302 public I_CmsWidget newInstance() { 303 304 return new CmsMultiSelectGroupWidget(getConfiguration()); 305 } 306 307 /** 308 * @see org.opencms.widgets.A_CmsWidget#setConfiguration(java.lang.String) 309 */ 310 @Override 311 public void setConfiguration(String configuration) { 312 313 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(configuration)) { 314 int asCheckBoxesIndex = configuration.indexOf(CmsMultiSelectWidget.CONFIGURATION_ASCHECKBOXES); 315 if (asCheckBoxesIndex != -1) { 316 // the height is set 317 String asCheckBoxes = configuration.substring( 318 asCheckBoxesIndex + CmsMultiSelectWidget.CONFIGURATION_ASCHECKBOXES.length() + 1); 319 if (asCheckBoxes.indexOf('|') != -1) { 320 // cut eventual following configuration values 321 asCheckBoxes = asCheckBoxes.substring(0, asCheckBoxes.indexOf('|')); 322 } 323 m_asCheckBoxes = Boolean.parseBoolean(asCheckBoxes); 324 } 325 int reqiresActivationIndex = configuration.indexOf(CmsMultiSelectWidget.CONFIGURATION_REQUIRES_ACTIVATION); 326 if (reqiresActivationIndex != -1) { 327 // the height is set 328 String requiresActivation = configuration.substring( 329 reqiresActivationIndex + CmsMultiSelectWidget.CONFIGURATION_REQUIRES_ACTIVATION.length() + 1); 330 if (requiresActivation.indexOf('|') != -1) { 331 // cut eventual following configuration values 332 requiresActivation = requiresActivation.substring(0, requiresActivation.indexOf('|')); 333 } 334 m_requiresActivation = Boolean.parseBoolean(requiresActivation); 335 } 336 } 337 super.setConfiguration(configuration); 338 } 339 340 /** 341 * @see org.opencms.widgets.A_CmsWidget#setEditorValue(org.opencms.file.CmsObject, java.util.Map, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 342 */ 343 @Override 344 public void setEditorValue( 345 CmsObject cms, 346 Map<String, String[]> formParameters, 347 I_CmsWidgetDialog widgetDialog, 348 I_CmsWidgetParameter param) { 349 350 CmsMultiSelectWidget.setMultiSelectEditorValue(cms, formParameters, widgetDialog, param); 351 } 352 353 /** 354 * @see org.opencms.widgets.CmsSelectGroupWidget#parseSelectOptions(org.opencms.file.CmsObject, org.opencms.i18n.CmsMessages, org.opencms.widgets.I_CmsWidgetParameter) 355 */ 356 @Override 357 protected List<CmsSelectWidgetOption> parseSelectOptions( 358 CmsObject cms, 359 CmsMessages messages, 360 I_CmsWidgetParameter param) { 361 362 // only create options if not already done 363 if (getSelectOptions() == null) { 364 // parse widget configuration 365 parseConfiguration(cms, messages); 366 List<CmsSelectWidgetOption> result = new ArrayList<CmsSelectWidgetOption>(); 367 368 if (isUseGroupNames()) { 369 // a list of group names is configured, show them 370 for (Iterator<String> i = getGroupNames().iterator(); i.hasNext();) { 371 String groupName = i.next(); 372 try { 373 // ensure that only existing groups are available in the select box 374 CmsGroup group = cms.readGroup(getOuFqn() + groupName); 375 result.add( 376 new CmsSelectWidgetOption(group.getName(), m_defaultAllAvailable, getGroupLabel(group))); 377 } catch (CmsException e) { 378 // error reading the group by name, simply skip it 379 } 380 } 381 } else { 382 // read the groups from an optionally configured OU and filter them if configured 383 try { 384 List<CmsGroup> groups = OpenCms.getOrgUnitManager().getGroups(cms, getOuFqn(), isIncludeSubOus()); 385 for (Iterator<CmsGroup> i = groups.iterator(); i.hasNext();) { 386 CmsGroup group = i.next(); 387 if (isUseGroupFilter()) { 388 // check if group name matches the given regular expression 389 if (!getGroupFilter().matcher(group.getSimpleName()).matches()) { 390 continue; 391 } 392 } 393 result.add( 394 new CmsSelectWidgetOption(group.getName(), m_defaultAllAvailable, getGroupLabel(group))); 395 } 396 } catch (CmsException e) { 397 // error reading the groups 398 } 399 400 } 401 setSelectOptions(result); 402 } 403 return getSelectOptions(); 404 } 405 406 /** 407 * @see org.opencms.widgets.A_CmsSelectWidget#parseSelectOptions(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 408 */ 409 @Override 410 protected List<CmsSelectWidgetOption> parseSelectOptions( 411 CmsObject cms, 412 I_CmsWidgetDialog widgetDialog, 413 I_CmsWidgetParameter param) { 414 415 return parseSelectOptions(cms, widgetDialog.getMessages(), param); 416 } 417 418 /** 419 * Returns the configured group filter to match groups to show in the select box.<p> 420 * 421 * @return the configured group filter to match groups to show in the select box 422 */ 423 private Pattern getGroupFilter() { 424 425 return m_groupFilter; 426 } 427 428 /** 429 * Gets the label to show for a group. 430 * 431 * @param group a group available for selection 432 * @return the label to display to the user for the group 433 */ 434 private String getGroupLabel(CmsGroup group) { 435 436 return m_useFullNames ? group.getName() : group.getSimpleName(); 437 } 438 439 /** 440 * Returns the configured group names to show in the select box.<p> 441 * 442 * @return configured group names to show in the select box 443 */ 444 private List<String> getGroupNames() { 445 446 return m_groupNames; 447 } 448 449 /** 450 * Returns the fully qualified name of the OU to read the groups from.<p> 451 * 452 * @return the fully qualified name of the OU to read the groups from 453 */ 454 private String getOuFqn() { 455 456 return m_ouFqn; 457 } 458 459 /** 460 * Returns if sub OUs should be considered when filtering the groups.<p> 461 * 462 * @return <code>true</code> if sub OUs should be considered, otherwise <code>false</code> 463 */ 464 private boolean isIncludeSubOus() { 465 466 return m_includeSubOus; 467 } 468 469 /** 470 * Returns if a group filter is configured to match groups to show in the select box.<p> 471 * 472 * @return <code>true</code> if a group filter is configured, otherwise <code>false</code> 473 */ 474 private boolean isUseGroupFilter() { 475 476 return getGroupFilter() != null; 477 } 478 479 /** 480 * Returns if group names are configured to show in the select box.<p> 481 * 482 * @return <code>true</code> if group names are configured, otherwise <code>false</code> 483 */ 484 private boolean isUseGroupNames() { 485 486 return getGroupNames() != null; 487 } 488 489 /** 490 * Parses the widget configuration string.<p> 491 * 492 * @param cms the current users OpenCms context 493 * @param widgetDialog the dialog of this widget 494 */ 495 private void parseConfiguration(CmsObject cms, CmsMessages widgetDialog) { 496 497 String configString = CmsMacroResolver.resolveMacros(getConfiguration(), cms, widgetDialog); 498 Map<String, String> config = CmsStringUtil.splitAsMap(configString, "|", "="); 499 // get the list of group names to show 500 String groups = config.get(CONFIGURATION_GROUPS); 501 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(groups)) { 502 m_groupNames = CmsStringUtil.splitAsList(groups, ',', true); 503 } 504 // get the regular expression to filter the groups 505 String filter = config.get(CONFIGURATION_GROUPFILTER); 506 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(filter)) { 507 try { 508 m_groupFilter = Pattern.compile(filter); 509 } catch (PatternSyntaxException e) { 510 // log pattern syntax errors 511 LOG.error(Messages.get().getBundle().key(Messages.LOG_ERR_WIDGET_SELECTGROUP_PATTERN_1, filter)); 512 } 513 } 514 // get the OU to read the groups from 515 m_ouFqn = config.get(CONFIGURATION_OUFQN); 516 if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_ouFqn)) { 517 m_ouFqn = ""; 518 } else if (!m_ouFqn.endsWith(CmsOrganizationalUnit.SEPARATOR)) { 519 m_ouFqn += CmsOrganizationalUnit.SEPARATOR; 520 } 521 m_useFullNames = Boolean.parseBoolean(config.get(CmsMultiSelectGroupWidget.CONFIGURATION_FULLNAMES)); 522 // set the flag to include sub OUs 523 m_includeSubOus = Boolean.parseBoolean(config.get(CONFIGURATION_INCLUDESUBOUS)); 524 m_defaultAllAvailable = Boolean.parseBoolean(config.get(CONFIGURATION_DEFAULT_ALL)); 525 } 526}