diff --git a/ccm-core/src/com/arsdigita/bebop/form/OptionGroup.java b/ccm-core/src/com/arsdigita/bebop/form/OptionGroup.java index c22b82750..ae7993801 100755 --- a/ccm-core/src/com/arsdigita/bebop/form/OptionGroup.java +++ b/ccm-core/src/com/arsdigita/bebop/form/OptionGroup.java @@ -38,381 +38,378 @@ import org.apache.log4j.Logger; /** * A class representing any widget that contains a list options. - * - * @author Karl Goldstein - * @author Uday Mathur - * @author Rory Solomon - * @author Michael Pih - * @version $Id: OptionGroup.java 738 2005-09-01 12:36:52Z sskracic $ */ + * + * @author Karl Goldstein + * @author Uday Mathur + * @author Rory Solomon + * @author Michael Pih + * @version $Id: OptionGroup.java 738 2005-09-01 12:36:52Z sskracic $ + */ public abstract class OptionGroup extends Widget - implements BebopConstants { + implements BebopConstants { - private static final Logger s_log = Logger.getLogger( OptionGroup.class ); + private static final Logger s_log = Logger.getLogger(OptionGroup.class); + /** + * The XML element to be used by individual options belonging to this group. + * This variable has to be initialized by every subclass of OptionGroup. + * LEGACY: An abstract method would be the better design, but changing it + * would break the API. + */ + protected String m_xmlElement; + // this only needs to be an ArrayList for multiple selection option groups + private ArrayList m_selected; + private ArrayList m_options; + private Widget m_otherOption = null; + private Form m_form = null; + private boolean m_isDisabled = false; + private boolean m_isReadOnly = false; + public static final String OTHER_OPTION = "__other__"; + // request-local copy of selected elements, options + private RequestLocal m_requestOptions = new RequestLocal() { + @Override + public Object initialValue(PageState ps) { + return new ArrayList(); + } + }; - /** - * The XML element to be used by individual options belonging to this - * group. This variable has to be initialized by every subclass of - * OptionGroup. - * LEGACY: An abstract method would be the better design, but changing it - * would break the API. */ - protected String m_xmlElement; + public final boolean isCompound() { + return true; + } + // this is only used for single selection option groups + private final static String TOO_MANY_OPTIONS_SELECTED = + "Only one option may be selected by default on this option group."; - // this only needs to be an ArrayList for multiple selection option groups - private ArrayList m_selected; + /** + * The ParameterModel for mutliple OptionGroups is always an array parameter + */ + protected OptionGroup(ParameterModel model) { + super(model); + m_options = new ArrayList(); + m_selected = new ArrayList(); + } - private ArrayList m_options; + /** + * Returns an Iterator of all the default Options in this group. + */ + public Iterator getOptions() { + return m_options.iterator(); + } - private Widget m_otherOption = null; + /** + * Returns an Iterator of all the default Options in this group, plus any + * request-specific options. + */ + public Iterator getOptions(PageState ps) { + ArrayList allOptions = new ArrayList(); + allOptions.addAll(m_options); + ArrayList requestOptions = (ArrayList) m_requestOptions.get(ps); + for (Iterator i = requestOptions.iterator(); i.hasNext();) { + Object obj = i.next(); + if (!allOptions.contains(obj)) { + allOptions.add(obj); + } + } + return allOptions.iterator(); + } - private Form m_form = null; - private boolean m_isDisabled = false; - private boolean m_isReadOnly = false; + public void clearOptions() { + Assert.isUnlocked(this); + m_options = new ArrayList(); + } - public static final String OTHER_OPTION = "__other__"; + /** + * Adds a new option. + * + * @param opt The {@link Option} to be added. Note: the argument is modified + * and associated with this OptionGroup, regardless of what its group was. + */ + public void addOption(Option opt) { + addOption(opt, null, false); + } - // request-local copy of selected elements, options - private RequestLocal m_requestOptions = new RequestLocal() { - @Override - public Object initialValue(PageState ps) { - return new ArrayList(); - } - }; + public void addOption(Option opt, PageState ps) { + addOption(opt, ps, false); + } - public final boolean isCompound() { - return true; - } + /** + * Adds a new option.at the beginning of the list + * + * @param opt The {@link Option} to be added. Note: the argument is modified + * and associated with this OptionGroup, regardless of what its group was. + */ + public void prependOption(Option opt) { + addOption(opt, null, true); + } - // this is only used for single selection option groups - private final static String TOO_MANY_OPTIONS_SELECTED = - "Only one option may be selected by default on this option group."; + public void prependOption(Option opt, PageState ps) { + addOption(opt, ps, true); + } - /** The ParameterModel for mutliple OptionGroups is always an array - * parameter */ - protected OptionGroup(ParameterModel model) { - super(model); - m_options = new ArrayList(); - m_selected = new ArrayList(); - } + public void removeOption(Option opt) { + removeOption(opt, null); + } - /** - * Returns an Iterator of all the default Options in this group. - */ - public Iterator getOptions() { - return m_options.iterator(); - } + /** + * Adds a new option for the scope of the current request, or to the page as + * a whole if there is no current request. + * + * @param opt The {@link Option} to be added. Note: the argument is modified + * and associated with this OptionGroup, regardless of what its group was. + * @param ps the current page state. if ps is null, adds option to the + * default option list. + * @param prepend If true, prepend option to the list instead of appending + * it + */ + public void addOption(Option opt, PageState ps, boolean prepend) { + ArrayList list = m_options; + if (ps == null) { + Assert.isUnlocked(this); + } else { + list = (ArrayList) m_requestOptions.get(ps); + } + opt.setGroup(this); - /** - * Returns an Iterator of all the default Options in this group, - * plus any request-specific options. - */ - public Iterator getOptions(PageState ps) { - ArrayList allOptions = new ArrayList(); - allOptions.addAll(m_options); - ArrayList requestOptions = (ArrayList)m_requestOptions.get(ps); - for (Iterator i = requestOptions.iterator(); i.hasNext(); ) { - Object obj = i.next(); - if (!allOptions.contains(obj)) { - allOptions.add(obj); - } - } - return allOptions.iterator(); - } + if (prepend == true) { + list.add(0, opt); + } else { + list.add(opt); + } + } - public void clearOptions() { - Assert.isUnlocked(this); - m_options = new ArrayList(); - } + public void removeOption(Option opt, PageState ps) { + ArrayList list = m_options; + if (ps == null) { + Assert.isUnlocked(this); + } else { + list = (ArrayList) m_requestOptions.get(ps); + } + list.remove(opt); + } - /** - * Adds a new option. - * @param opt The {@link Option} to be added. Note: the argument - * is modified and associated with this OptionGroup, regardless of - * what its group was. - */ - public void addOption(Option opt) { - addOption(opt, null, false); - } + public void removeOption(String key) { + removeOption(key, null); + } - public void addOption(Option opt, PageState ps) { - addOption(opt, ps, false); - } + /** + * Removes the first option whose key is isEqual to the key that is passed + * in. + */ + public void removeOption(String key, PageState ps) { + // This is not an entirely efficient technique. A more + // efficient solution is to switch to using a HashMap. + ArrayList list = m_options; + if (ps == null) { + Assert.isUnlocked(this); + } else { + list = (ArrayList) m_requestOptions.get(ps); + } - /** - * Adds a new option.at the beginning of the list - * @param opt The {@link Option} to be added. Note: the argument - * is modified and associated with this OptionGroup, regardless of - * what its group was. - */ - public void prependOption(Option opt) { - addOption(opt, null, true); - } + Iterator i = list.iterator(); + Option o = null; + while (i.hasNext()) { + o = (Option) i.next(); + if (o.getValue().equals(key)) { + list.remove(o); + break; + } + } - public void prependOption(Option opt, PageState ps) { - addOption(opt, ps, true); - } + } - public void removeOption(Option opt) { - removeOption(opt, null); - } + /** + * Add an "Other (please specify)" type option to the widget + * + * @param hasOtherOption true is the widget has an "Other" option + * @param width The width, in characters, of the "Other" entry area + * @param height The height, in characters, of the "Other" entry area. If + * this is 1 then a TextField is used. Otherwise a TextArea is used. + */ + public void addOtherOption(String label, int width, int height) { + Assert.isUnlocked(this); - /** - * Adds a new option for the scope of the current request, or - * to the page as a whole if there is no current request. - * - * @param opt The {@link Option} to be added. Note: the argument - * is modified and associated with this OptionGroup, regardless of - * what its group was. - * @param ps the current page state. if ps is null, adds option to the - * default option list. - * @param prepend If true, prepend option to the list instead of appending it - */ - public void addOption(Option opt, PageState ps, boolean prepend) { - ArrayList list = m_options; - if (ps == null) { - Assert.isUnlocked(this); - } else { - list = (ArrayList)m_requestOptions.get(ps); - } - opt.setGroup( this ); + Option otherOption = new Option(OTHER_OPTION, label); + addOption(otherOption); - if(prepend == true) { - list.add(0, opt); - } else { - list.add(opt); - } - } + final ParameterModel model = getParameterModel(); + if (1 == height) { + TextField field = + new TextField(model.getName() + ".other"); + field.setSize(width); - public void removeOption(Option opt, PageState ps) { - ArrayList list = m_options; - if (ps == null) { - Assert.isUnlocked(this); - } else { - list = (ArrayList)m_requestOptions.get(ps); - } - list.remove(opt); - } + m_otherOption = field; + } else { + TextArea area = + new TextArea(model.getName() + ".other"); + area.setCols(width); + area.setRows(height); - public void removeOption(String key) { - removeOption(key, null); - } + m_otherOption = area; + } - /** - * Removes the first option whose key is isEqual - * to the key that is passed in. - */ - public void removeOption(String key, PageState ps) { - // This is not an entirely efficient technique. A more - // efficient solution is to switch to using a HashMap. - ArrayList list = m_options; - if (ps == null) { - Assert.isUnlocked(this); - } else { - list = (ArrayList)m_requestOptions.get(ps); - } + if (null != m_form) { + m_otherOption.setForm(m_form); - Iterator i = list.iterator(); - Option o = null; - while ( i.hasNext() ) { - o = (Option) i.next(); - if ( o.getValue().equals(key) ) { - list.remove(o); - break; - } - } + if (m_isDisabled) { + m_otherOption.setDisabled(); + } + if (m_isReadOnly) { + m_otherOption.setReadOnly(); + } + } - } + setParameterModel(new ParameterModelWrapper(model) { + @Override + public ParameterData createParameterData(final HttpServletRequest request, + Object defaultValue, + boolean isSubmission) { - /** - * Add an "Other (please specify)" type option to the widget - * - * @param hasOtherOption true is the widget has an "Other" option - * @param width The width, in characters, of the "Other" entry area - * @param height The height, in characters, of the "Other" entry area. If - * this is 1 then a TextField is used. Otherwise a TextArea is used. - */ - public void addOtherOption( String label, int width, int height ) { - Assert.isUnlocked(this); + final String[] values = + request.getParameterValues(getName()); + String[] otherValues = + request.getParameterValues(getName() + ".other"); - Option otherOption = new Option( OTHER_OPTION, label ); - addOption( otherOption ); + String other = (null == otherValues) ? null : otherValues[0]; - final ParameterModel model = getParameterModel(); + if (null != values) { + for (int i = 0; i < values.length; i++) { + if (OTHER_OPTION.equals(values[i])) { + values[i] = other; + } + } + } - if( 1 == height ) { - TextField field = - new TextField( model.getName() + ".other" ); - field.setSize( width ); + s_log.debug("createParameterData in OptionGroup"); - m_otherOption = field; - } else { - TextArea area = - new TextArea( model.getName() + ".other" ); - area.setCols( width ); - area.setRows( height ); + return super.createParameterData(new HttpServletRequestWrapper(request) { + @Override + public String[] getParameterValues(String key) { + if (s_log.isDebugEnabled()) { + s_log.debug("Getting values for " + key); + } - m_otherOption = area; - } + if (model.getName().equals(key)) { + return values; + } + return super.getParameterValues(key); + } + }, defaultValue, isSubmission); + } - if( null != m_form ) { - m_otherOption.setForm( m_form ); + private void replaceOther(String[] values, String other) { + } + }); + } - if( m_isDisabled ) { - m_otherOption.setDisabled(); - } - if( m_isReadOnly ) { - m_otherOption.setReadOnly(); - } - } + /** + * Make an option selected by default. Updates the parameter model for the + * option group accordingly. + * + * @param value the value of the option to be added to the + * by-default-selected set. + */ + public void setOptionSelected(String value) { + Assert.isUnlocked(this); + if (!isMultiple()) { + // only one option may be selected + // to this selected list better be empty + Assert.isTrue(m_selected.size() == 0, TOO_MANY_OPTIONS_SELECTED); + m_selected.add(value); + getParameterModel().setDefaultValue(value); + } else { + m_selected.add(value); + getParameterModel().setDefaultValue(m_selected.toArray()); + } + } - setParameterModel( new ParameterModelWrapper( model ) { - @Override - public ParameterData createParameterData( final HttpServletRequest request, - Object defaultValue, - boolean isSubmission ) { + /** + * make an option selected by default + * + * @param option the option to be added to the by-default-selected set. + */ + public void setOptionSelected(Option option) { + setOptionSelected(option.getValue()); + } - final String[] values = - request.getParameterValues( getName() ); - String[] otherValues = - request.getParameterValues( getName() + ".other" ); + @Override + public Object clone() throws CloneNotSupportedException { + OptionGroup cloned = (OptionGroup) super.clone(); + cloned.m_options = (ArrayList) m_options.clone(); + cloned.m_selected = + (ArrayList) m_selected.clone(); + return cloned; + } - String other = ( null == otherValues ) ? null : otherValues[0]; + /** + * Is this a multiple (and not single) selection option group? Note that + * this should really be declared abstract, but we can't because it used to + * be in the direct subclass Select and making it abstract could break other + * subclasses that don't declare isMultiple. So we have a trivial + * implementation instead. + * + * @return true if this OptionGroup can have more than one selected option; + * false otherwise. + */ + public boolean isMultiple() { + return true; + } - if( null != values ) { - for( int i = 0; i < values.length; i++ ) { - if( OTHER_OPTION.equals( values[i] ) ) { - values[i] = other; - } - } - } + @Override + public void setDisabled() { + m_isDisabled = true; - s_log.debug( "createParameterData in OptionGroup" ); + if (null != m_otherOption) { + m_otherOption.setDisabled(); + } - return super.createParameterData( new HttpServletRequestWrapper( request ) { - @Override - public String[] getParameterValues( String key ) { - if( s_log.isDebugEnabled() ) { - s_log.debug( "Getting values for " + key ); - } + super.setDisabled(); + } - if( model.getName().equals( key ) ) { - return values; - } - return super.getParameterValues( key ); - } - }, defaultValue, isSubmission ); - } + @Override + public void setReadOnly() { + m_isReadOnly = true; - private void replaceOther( String[] values, String other ) { - } - } ); - } + if (null != m_otherOption) { + m_otherOption.setReadOnly(); + } - /** Make an option selected by default. Updates the parameter - * model for the option group accordingly. - * @param value the value of the option to be added to the - * by-default-selected set. */ - public void setOptionSelected(String value) { - Assert.isUnlocked(this); - if (!isMultiple()) { - // only one option may be selected - // to this selected list better be empty - Assert.isTrue(m_selected.size() == 0, TOO_MANY_OPTIONS_SELECTED); - m_selected.add(value); - getParameterModel().setDefaultValue( value ); - } else { - m_selected.add(value); - getParameterModel().setDefaultValue( m_selected.toArray() ); - } - } + super.setReadOnly(); + } - /** make an option selected by default - * @param option the option to be added to the by-default-selected set. - */ - public void setOptionSelected(Option option) { - setOptionSelected(option.getValue()); - } + @Override + public void setForm(Form form) { + m_form = form; + if (null != m_otherOption) { + m_otherOption.setForm(form); + } - @Override - public Object clone() throws CloneNotSupportedException { - OptionGroup cloned = (OptionGroup)super.clone(); - cloned.m_options = (ArrayList) m_options.clone(); - cloned.m_selected = - (ArrayList) m_selected.clone(); - return cloned; - } + super.setForm(form); + } - /** - * Is this a multiple (and not single) selection option group? - * Note that this should really be declared abstract, but we can't - * because it used to be in the direct subclass Select and making - * it abstract could break other subclasses that don't declare - * isMultiple. So we have a trivial implementation instead. - * - * @return true if this OptionGroup can have more than one - * selected option; false otherwise. - */ - public boolean isMultiple() { - return true; - } - - @Override - public void setDisabled() { - m_isDisabled = true; - - if( null != m_otherOption ) { - m_otherOption.setDisabled(); - } - - super.setDisabled(); - } - - @Override - public void setReadOnly() { - m_isReadOnly = true; - - if( null != m_otherOption ) { - m_otherOption.setReadOnly(); - } - - super.setReadOnly(); - } - - @Override - public void setForm( Form form ) { - m_form = form; - if( null != m_otherOption ) { - m_otherOption.setForm(form); - } - - super.setForm( form ); - } - - /** - * Generates the DOM for the select widget - *

Generates DOM fragment: - *

<bebop:* name=... [onXXX=...]>
+	/**
+	 * Generates the DOM for the select widget 

Generates DOM fragment:

<bebop:* name=... [onXXX=...]>
      *   <bebop:option name=... [selected]> option value </bebop:option%gt;
-     * ...
-     * </bebop:*select>
- */ - @Override - public void generateWidget( PageState state, Element parent ) { - Element optionGroup = - parent.newChildElement( getElementTag(), BEBOP_XML_NS ); - optionGroup.addAttribute( "name", getName() ); - if ( isMultiple() ) { - optionGroup.addAttribute( "multiple", "multiple" ); - } - exportAttributes( optionGroup ); + * ... + * </bebop:*select>
+ */ + @Override + public void generateWidget(PageState state, Element parent) { + Element optionGroup = + parent.newChildElement(getElementTag(), BEBOP_XML_NS); + optionGroup.addAttribute("name", getName()); + optionGroup.addAttribute("class", getName().replace(".", " ")); + if (isMultiple()) { + optionGroup.addAttribute("multiple", "multiple"); + } + exportAttributes(optionGroup); - for ( Iterator i = getOptions(state); i.hasNext(); ) { - Option o = (Option) i.next(); - o.generateXML( state, optionGroup ); - } + for (Iterator i = getOptions(state); i.hasNext();) { + Option o = (Option) i.next(); + o.generateXML(state, optionGroup); + } - if( null != m_otherOption ) { - m_otherOption.generateXML(state, optionGroup); - } - } + if (null != m_otherOption) { + m_otherOption.generateXML(state, optionGroup); + } + } }