OptionGroup

Ausgabe von Class Attributen

git-svn-id: https://svn.libreccm.org/ccm/trunk@2478 8810af33-2d31-482b-a856-94f89814c4df
master
quasi 2013-12-10 15:24:59 +00:00
parent 8a7131a612
commit a62d12d63a
1 changed files with 323 additions and 326 deletions

View File

@ -39,380 +39,377 @@ import org.apache.log4j.Logger;
/** /**
* A class representing any widget that contains a list options. * A class representing any widget that contains a list options.
* *
* @author Karl Goldstein * @author Karl Goldstein
* @author Uday Mathur * @author Uday Mathur
* @author Rory Solomon * @author Rory Solomon
* @author Michael Pih * @author Michael Pih
* @version $Id: OptionGroup.java 738 2005-09-01 12:36:52Z sskracic $ */ * @version $Id: OptionGroup.java 738 2005-09-01 12:36:52Z sskracic $
*/
public abstract class OptionGroup extends Widget 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();
}
};
/** public final boolean isCompound() {
* The XML element to be used by individual options belonging to this return true;
* group. This variable has to be initialized by every subclass of }
* OptionGroup. // this is only used for single selection option groups
* LEGACY: An abstract method would be the better design, but changing it private final static String TOO_MANY_OPTIONS_SELECTED =
* would break the API. */ "Only one option may be selected by default on this option group.";
protected String m_xmlElement;
// 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; public void clearOptions() {
private boolean m_isDisabled = false; Assert.isUnlocked(this);
private boolean m_isReadOnly = false; 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 public void addOption(Option opt, PageState ps) {
private RequestLocal m_requestOptions = new RequestLocal() { addOption(opt, ps, false);
@Override }
public Object initialValue(PageState ps) {
return new ArrayList();
}
};
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 public void prependOption(Option opt, PageState ps) {
private final static String TOO_MANY_OPTIONS_SELECTED = addOption(opt, ps, true);
"Only one option may be selected by default on this option group."; }
/** The ParameterModel for mutliple OptionGroups is always an array public void removeOption(Option opt) {
* parameter */ removeOption(opt, null);
protected OptionGroup(ParameterModel model) { }
super(model);
m_options = new ArrayList();
m_selected = new ArrayList();
}
/** /**
* Returns an Iterator of all the default Options in this group. * Adds a new option for the scope of the current request, or to the page as
*/ * a whole if there is no current request.
public Iterator getOptions() { *
return m_options.iterator(); * @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);
/** if (prepend == true) {
* Returns an Iterator of all the default Options in this group, list.add(0, opt);
* plus any request-specific options. } else {
*/ list.add(opt);
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();
}
public void clearOptions() { public void removeOption(Option opt, PageState ps) {
Assert.isUnlocked(this); ArrayList list = m_options;
m_options = new ArrayList(); if (ps == null) {
} Assert.isUnlocked(this);
} else {
list = (ArrayList) m_requestOptions.get(ps);
}
list.remove(opt);
}
/** public void removeOption(String key) {
* Adds a new option. removeOption(key, null);
* @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 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);
}
/** Iterator i = list.iterator();
* Adds a new option.at the beginning of the list Option o = null;
* @param opt The {@link Option} to be added. Note: the argument while (i.hasNext()) {
* is modified and associated with this OptionGroup, regardless of o = (Option) i.next();
* what its group was. if (o.getValue().equals(key)) {
*/ list.remove(o);
public void prependOption(Option opt) { break;
addOption(opt, null, true); }
} }
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);
/** Option otherOption = new Option(OTHER_OPTION, label);
* Adds a new option for the scope of the current request, or addOption(otherOption);
* 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 );
if(prepend == true) { final ParameterModel model = getParameterModel();
list.add(0, opt);
} else {
list.add(opt);
}
}
if (1 == height) {
TextField field =
new TextField(model.getName() + ".other");
field.setSize(width);
public void removeOption(Option opt, PageState ps) { m_otherOption = field;
ArrayList list = m_options; } else {
if (ps == null) { TextArea area =
Assert.isUnlocked(this); new TextArea(model.getName() + ".other");
} else { area.setCols(width);
list = (ArrayList)m_requestOptions.get(ps); area.setRows(height);
}
list.remove(opt);
}
public void removeOption(String key) { m_otherOption = area;
removeOption(key, null); }
}
/** if (null != m_form) {
* Removes the first option whose key is isEqual m_otherOption.setForm(m_form);
* 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);
}
Iterator i = list.iterator(); if (m_isDisabled) {
Option o = null; m_otherOption.setDisabled();
while ( i.hasNext() ) { }
o = (Option) i.next(); if (m_isReadOnly) {
if ( o.getValue().equals(key) ) { m_otherOption.setReadOnly();
list.remove(o); }
break; }
}
}
} setParameterModel(new ParameterModelWrapper(model) {
@Override
public ParameterData createParameterData(final HttpServletRequest request,
Object defaultValue,
boolean isSubmission) {
/** final String[] values =
* Add an "Other (please specify)" type option to the widget request.getParameterValues(getName());
* String[] otherValues =
* @param hasOtherOption true is the widget has an "Other" option request.getParameterValues(getName() + ".other");
* @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);
Option otherOption = new Option( OTHER_OPTION, label ); String other = (null == otherValues) ? null : otherValues[0];
addOption( otherOption );
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 ) { s_log.debug("createParameterData in OptionGroup");
TextField field =
new TextField( model.getName() + ".other" );
field.setSize( width );
m_otherOption = field; return super.createParameterData(new HttpServletRequestWrapper(request) {
} else { @Override
TextArea area = public String[] getParameterValues(String key) {
new TextArea( model.getName() + ".other" ); if (s_log.isDebugEnabled()) {
area.setCols( width ); s_log.debug("Getting values for " + key);
area.setRows( height ); }
m_otherOption = area; if (model.getName().equals(key)) {
} return values;
}
return super.getParameterValues(key);
}
}, defaultValue, isSubmission);
}
if( null != m_form ) { private void replaceOther(String[] values, String other) {
m_otherOption.setForm( m_form ); }
});
}
if( m_isDisabled ) { /**
m_otherOption.setDisabled(); * Make an option selected by default. Updates the parameter model for the
} * option group accordingly.
if( m_isReadOnly ) { *
m_otherOption.setReadOnly(); * @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 * make an option selected by default
public ParameterData createParameterData( final HttpServletRequest request, *
Object defaultValue, * @param option the option to be added to the by-default-selected set.
boolean isSubmission ) { */
public void setOptionSelected(Option option) {
setOptionSelected(option.getValue());
}
final String[] values = @Override
request.getParameterValues( getName() ); public Object clone() throws CloneNotSupportedException {
String[] otherValues = OptionGroup cloned = (OptionGroup) super.clone();
request.getParameterValues( getName() + ".other" ); 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 ) { @Override
for( int i = 0; i < values.length; i++ ) { public void setDisabled() {
if( OTHER_OPTION.equals( values[i] ) ) { m_isDisabled = true;
values[i] = other;
}
}
}
s_log.debug( "createParameterData in OptionGroup" ); if (null != m_otherOption) {
m_otherOption.setDisabled();
}
return super.createParameterData( new HttpServletRequestWrapper( request ) { super.setDisabled();
@Override }
public String[] getParameterValues( String key ) {
if( s_log.isDebugEnabled() ) {
s_log.debug( "Getting values for " + key );
}
if( model.getName().equals( key ) ) { @Override
return values; public void setReadOnly() {
} m_isReadOnly = true;
return super.getParameterValues( key );
}
}, defaultValue, isSubmission );
}
private void replaceOther( String[] values, String other ) { if (null != m_otherOption) {
} m_otherOption.setReadOnly();
} ); }
}
/** Make an option selected by default. Updates the parameter super.setReadOnly();
* 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() );
}
}
/** make an option selected by default @Override
* @param option the option to be added to the by-default-selected set. public void setForm(Form form) {
*/ m_form = form;
public void setOptionSelected(Option option) { if (null != m_otherOption) {
setOptionSelected(option.getValue()); m_otherOption.setForm(form);
} }
@Override super.setForm(form);
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;
}
/** /**
* Is this a multiple (and not single) selection option group? * Generates the DOM for the select widget <p>Generates DOM fragment: <p><pre><code>&lt;bebop:* name=... [onXXX=...]&gt;
* 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
* <p>Generates DOM fragment:
* <p><pre><code>&lt;bebop:* name=... [onXXX=...]&gt;
* &lt;bebop:option name=... [selected]&gt; option value &lt;/bebop:option%gt; * &lt;bebop:option name=... [selected]&gt; option value &lt;/bebop:option%gt;
* ... * ...
* &lt;/bebop:*select&gt;</code></pre> * &lt;/bebop:*select&gt;</code></pre>
*/ */
@Override @Override
public void generateWidget( PageState state, Element parent ) { public void generateWidget(PageState state, Element parent) {
Element optionGroup = Element optionGroup =
parent.newChildElement( getElementTag(), BEBOP_XML_NS ); parent.newChildElement(getElementTag(), BEBOP_XML_NS);
optionGroup.addAttribute( "name", getName() ); optionGroup.addAttribute("name", getName());
if ( isMultiple() ) { optionGroup.addAttribute("class", getName().replace(".", " "));
optionGroup.addAttribute( "multiple", "multiple" ); if (isMultiple()) {
} optionGroup.addAttribute("multiple", "multiple");
exportAttributes( optionGroup ); }
exportAttributes(optionGroup);
for ( Iterator i = getOptions(state); i.hasNext(); ) { for (Iterator i = getOptions(state); i.hasNext();) {
Option o = (Option) i.next(); Option o = (Option) i.next();
o.generateXML( state, optionGroup ); o.generateXML(state, optionGroup);
} }
if( null != m_otherOption ) { if (null != m_otherOption) {
m_otherOption.generateXML(state, optionGroup); m_otherOption.generateXML(state, optionGroup);
} }
} }
} }