Kategorienfilter arbeitet jetzt korrekt (durchsucht nur die ausgewählte Kategorie)

git-svn-id: https://svn.libreccm.org/ccm/trunk@2448 8810af33-2d31-482b-a856-94f89814c4df
master
jensp 2013-11-22 09:22:30 +00:00
parent 818b0785cf
commit 7f79f1da6a
7 changed files with 258 additions and 289 deletions

View File

@ -25,5 +25,5 @@ com.arsdigita.cms.contenttypes.generic_contact.address.hide_country.format=[bool
com.arsdigita.cms.contenttypes.generic_contact.contact_entry_keys.title=Select available contact entry types com.arsdigita.cms.contenttypes.generic_contact.contact_entry_keys.title=Select available contact entry types
com.arsdigita.cms.contenttypes.generic_contact.contact_entry_keys.purpose=Select available contact entry types and define display order com.arsdigita.cms.contenttypes.generic_contact.contact_entry_keys.purpose=Select available contact entry types and define display order
com.arsdigita.cms.contenttypes.generic_contact.contact_entry_keys.example=contact_type,office_hours,phone_office,phone_private,phone_mobile,email,fax,im,www com.arsdigita.cms.contenttypes.generic_contact.contact_entry_keys.example=contacttype,visitingHours,phoneOffice,phonePrivate,phoneMobile,email,fax,im,www
com.arsdigita.cms.contenttypes.generic_contact.contact_entry_keys.format=[string] com.arsdigita.cms.contenttypes.generic_contact.contact_entry_keys.format=[string]

View File

@ -34,8 +34,9 @@ import java.math.BigDecimal;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
/** /**
* An extension of {@link ItemSearch} for use in a popup search window. The display of results is altered so that * An extension of {@link ItemSearch} for use in a popup search window. The display of results is
* selecting a result closes the window & passes the id of the selected item back to the opener. * altered so that selecting a result closes the window & passes the id of the selected item back
* to the opener.
* *
* @author Stanislav Freidin (sfreidin@arsdigita.com) * @author Stanislav Freidin (sfreidin@arsdigita.com)
* @version $Id: ItemSearchPopup.java 1397 2006-11-29 14:10:38Z sskracic $ * @version $Id: ItemSearchPopup.java 1397 2006-11-29 14:10:38Z sskracic $

View File

@ -18,7 +18,6 @@
*/ */
package com.arsdigita.bebop.form; package com.arsdigita.bebop.form;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.TooManyListenersException; import java.util.TooManyListenersException;
@ -48,29 +47,27 @@ import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element; import com.arsdigita.xml.Element;
/** /**
* <p>A class representing a widget in the graphical representation of * <p>
* a form.</p> * A class representing a widget in the graphical representation of a form.</p>
* *
* <p>A widget may correspond to a standard HTML form element, or to a * <p>
* more specific element or set of elements, such as a date widget * A widget may correspond to a standard HTML form element, or to a more specific element or set of
* that allows input of month, day and year (and possibly time as * elements, such as a date widget that allows input of month, day and year (and possibly time as
* well).</p> * well).</p>
* *
* <p>This class and its subclasses provide methods to set all element * <p>
* attributes except for <code>VALUE</code>, which is typically * This class and its subclasses provide methods to set all element attributes except for
* dependent on the request. At the time of a request, a widget * <code>VALUE</code>, which is typically dependent on the request. At the time of a request, a
* object merges a dynamically specified value or set of values with * widget object merges a dynamically specified value or set of values with its own set of
* its own set of persistent attributes to render the final HTML for * persistent attributes to render the final HTML for the widget. Other dynamic attributes may be
* the widget. Other dynamic attributes may be associated with the * associated with the form component via a <code>WidgetPeer</code> associated with the widget.</p>
* form component via a <code>WidgetPeer</code> associated with the
* widget.</p>
* *
* @author Karl Goldstein * @author Karl Goldstein
* @author Uday Mathur * @author Uday Mathur
* @author Rory Solomon * @author Rory Solomon
* @version $Id: Widget.java 1537 2007-03-23 15:33:34Z chrisgilbert23 $ * @version $Id: Widget.java 1537 2007-03-23 15:33:34Z chrisgilbert23 $
*/ */
public abstract class Widget extends BlockStylable implements Cloneable, public abstract class Widget extends BlockStylable implements Cloneable,
BebopConstants { BebopConstants {
private static final Logger s_log = Logger.getLogger(Widget.class); private static final Logger s_log = Logger.getLogger(Widget.class);
@ -80,7 +77,9 @@ public abstract class Widget extends BlockStylable implements Cloneable,
private ParameterListener m_forwardParameter = null; private ParameterListener m_forwardParameter = null;
private PrintListener m_printListener; private PrintListener m_printListener;
private Form m_form; private Form m_form;
/** The optional (localized) label (or title) of this widget. */ /**
* The optional (localized) label (or title) of this widget.
*/
private GlobalizedMessage m_label; private GlobalizedMessage m_label;
private ValidationGuard m_guard = null; private ValidationGuard m_guard = null;
@ -96,29 +95,29 @@ public abstract class Widget extends BlockStylable implements Cloneable,
static final String ON_KEY_UP = "onKeyUp"; static final String ON_KEY_UP = "onKeyUp";
/** /**
* Returns true if the widget consists of multiple HTML elements. * Returns true if the widget consists of multiple HTML elements.
*/ */
public abstract boolean isCompound(); public abstract boolean isCompound();
/** /**
* Returns a string naming the type of this widget. Must be implemented by * Returns a string naming the type of this widget. Must be implemented by subclasses
* subclasses
*/ */
protected abstract String getType(); protected abstract String getType();
/** /**
* Constructs a new widget. * Constructs a new widget.
* *
*/ */
protected Widget(String name) { protected Widget(String name) {
this( new StringParameter(name) ); this(new StringParameter(name));
} }
/** /**
* Constructs a new widget. * Constructs a new widget.
* *
* <p>Each new widget is associated with a ParameterModel describing * <p>
* the data object(s) submitted from the widget. * Each new widget is associated with a ParameterModel describing the data object(s) submitted
* from the widget.
*/ */
protected Widget(ParameterModel model) { protected Widget(ParameterModel model) {
Assert.exists(model, ParameterModel.class); Assert.exists(model, ParameterModel.class);
@ -128,12 +127,11 @@ public abstract class Widget extends BlockStylable implements Cloneable,
protected ParameterListener createParameterListener() { protected ParameterListener createParameterListener() {
return new ParameterListener() { return new ParameterListener() {
public void validate(ParameterEvent evt) public void validate(ParameterEvent evt)
throws FormProcessException { throws FormProcessException {
fireValidation(new ParameterEvent fireValidation(new ParameterEvent(Widget.this, evt.getParameterData()));
(Widget.this, evt.getParameterData())); }
} };
};
} }
public void setValidateInvisible(boolean value) { public void setValidateInvisible(boolean value) {
@ -146,19 +144,19 @@ public abstract class Widget extends BlockStylable implements Cloneable,
} }
protected void fireValidation(ParameterEvent evt) protected void fireValidation(ParameterEvent evt)
throws FormProcessException { throws FormProcessException {
Assert.isLocked(this); Assert.isLocked(this);
PageState ps = evt.getPageState(); PageState ps = evt.getPageState();
if ((!validateInvisible() && !ps.isVisibleOnPage(this)) || if ((!validateInvisible() && !ps.isVisibleOnPage(this)) || ((m_guard != null) && m_guard.
((m_guard != null) && m_guard.shouldValidate(ps))) { shouldValidate(ps))) {
return; return;
} }
for (Iterator it = for (Iterator it
m_listeners.getListenerIterator(ParameterListener.class); = m_listeners.getListenerIterator(ParameterListener.class);
it.hasNext(); ) { it.hasNext();) {
((ParameterListener) it.next()).validate(evt); ((ParameterListener) it.next()).validate(evt);
} }
} }
@ -181,86 +179,79 @@ public abstract class Widget extends BlockStylable implements Cloneable,
/** /**
* Test for existens of a particular type of ValidationListener * Test for existens of a particular type of ValidationListener
* *
* @param listener Subtype of ParameterListern which is tested for * @param listener Subtype of ParameterListern which is tested for
* @return true if subtype is in the list * @return true if subtype is in the list
*/ */
public boolean hasValidationListener(ParameterListener listener) { public boolean hasValidationListener(ParameterListener listener) {
Assert.exists(listener, "ParameterListener"); Assert.exists(listener, "ParameterListener");
return this.getParameterModel().hasParameterListener(listener); return this.getParameterModel().hasParameterListener(listener);
// return (m_listeners.getListenerCount(listener.getClass()) > 0); // return (m_listeners.getListenerCount(listener.getClass()) > 0);
} }
/** /**
* Adds a print listener for this widget. Only one print listener can be * Adds a print listener for this widget. Only one print listener can be set for a widget, since
* set for a widget, since the <code>PrintListener</code> is expected to * the <code>PrintListener</code> is expected to modify the target of the
* modify the target of the <code>PrintEvent</code>. * <code>PrintEvent</code>.
*
* @param listener the print listener * @param listener the print listener
* @throws IlegalArgumentException <code>listener</code> is null * @throws IlegalArgumentException <code>listener</code> is null
* @throws TooManyListenersException a print listener has previously been * @throws TooManyListenersException a print listener has previously been added
* added
* @pre listener != null * @pre listener != null
*/ */
public void addPrintListener(PrintListener listener) public void addPrintListener(PrintListener listener)
throws TooManyListenersException, IllegalArgumentException throws TooManyListenersException, IllegalArgumentException {
{ if (listener == null) {
if ( listener == null ) {
throw new IllegalArgumentException("Argument listener can not be null"); throw new IllegalArgumentException("Argument listener can not be null");
} }
if ( m_printListener != null ) { if (m_printListener != null) {
throw new TooManyListenersException(); throw new TooManyListenersException();
} }
m_printListener = listener; m_printListener = listener;
} }
/** /**
* Set the print listener for this widget. Since there can only * Set the print listener for this widget. Since there can only be one print listener for a
* be one print listener for a widget, this lets you just set it * widget, this lets you just set it and avoid writing a try/catch block for
* and avoid writing a try/catch block for * "TooManyListenersException". Any existing listener will be overwritten.
* "TooManyListenersException". Any existing listener will be
* overwritten.
* *
* @param listener the print listener * @param listener the print listener
* @throws IlegalArgumentException <code>listener</code> is null * @throws IlegalArgumentException <code>listener</code> is null
* @pre listener != null */ * @pre listener != null
*/
public void setPrintListener(PrintListener listener) public void setPrintListener(PrintListener listener)
throws IllegalArgumentException throws IllegalArgumentException {
{ if (listener == null) {
if ( listener == null ) {
throw new IllegalArgumentException("Argument listener can not be null"); throw new IllegalArgumentException("Argument listener can not be null");
} }
m_printListener = listener; m_printListener = listener;
} }
/** /**
* Remove a previously added print listener. If <code>listener</code> is * Remove a previously added print listener. If <code>listener</code> is not the listener that
* not the listener that has been added with {@link #addPrintListener * has been added with {@link #addPrintListener
* addPrintListener}, an IllegalArgumentException will be thrown. * addPrintListener}, an IllegalArgumentException will be thrown.
* @param listener the listener that had been added with *
* <code>addPrintListener</code> * @param listener the listener that had been added with <code>addPrintListener</code>
* @throws IllegalArgumentException <code>listener</code> is not the * @throws IllegalArgumentException <code>listener</code> is not the currently registered print
* currently registered print listener or is <code>null</code>. * listener or is <code>null</code>.
* @pre listener != null * @pre listener != null
*/ */
public void removePrintListener(PrintListener listener) public void removePrintListener(PrintListener listener)
throws IllegalArgumentException throws IllegalArgumentException {
{ if (listener == null) {
if ( listener == null ) {
throw new IllegalArgumentException("listener can not be null"); throw new IllegalArgumentException("listener can not be null");
} }
if ( listener != m_printListener ) { if (listener != m_printListener) {
throw new IllegalArgumentException("listener is not registered with this widget"); throw new IllegalArgumentException("listener is not registered with this widget");
} }
m_printListener = null; m_printListener = null;
} }
/** /**
* Registers the ParameterModel of this Widget with the containing Form. This method is * Registers the ParameterModel of this Widget with the containing Form. This method is used by
* used by the Bebop framework and should not be used by application developers. * the Bebop framework and should not be used by application developers.
*/ */
public void register(Form form, FormModel model) { public void register(Form form, FormModel model) {
model.addFormParam(getParameterModel()); model.addFormParam(getParameterModel());
@ -269,9 +260,8 @@ public abstract class Widget extends BlockStylable implements Cloneable,
} }
/** /**
* Sets the Form Object for this Widget. This method will throw an * Sets the Form Object for this Widget. This method will throw an exception if the _form
* exception if the _form pointer is already set. To explicity * pointer is already set. To explicity change the m_form pointer the developer must first call
* change the m_form pointer the developer must first call
* setForm(null) * setForm(null)
* *
* @param form The <code>Form</code> Object for this Widget * @param form The <code>Form</code> Object for this Widget
@ -279,86 +269,76 @@ public abstract class Widget extends BlockStylable implements Cloneable,
*/ */
public void setForm(final Form form) { public void setForm(final Form form) {
if (m_form != null && form != null) { if (m_form != null && form != null) {
throw new IllegalStateException("Form "+form.getName()+" already set for "+getName()); throw new IllegalStateException("Form " + form.getName() + " already set for "
+ getName());
} }
m_form = form; m_form = form;
} }
/** /**
* Gets the Form Object for this Widget. Throws an exception if * Gets the Form Object for this Widget. Throws an exception if the Widget doesn't belong to a
* the Widget doesn't belong to a form. * form.
* *
* @return the {@link Form} Object for this Widget. * @return the {@link Form} Object for this Widget.
* @post return != null * @post return != null
*/ */
public Form getForm() throws RuntimeException { public Form getForm() throws RuntimeException {
if (m_form == null) { if (m_form == null) {
throw new RuntimeException throw new RuntimeException("Widget " + this + " (" + getName() + ") "
("Widget " + this + " (" + getName() + ") " + + "isn't associated with any Form");
"isn't associated with any Form");
} }
return m_form; return m_form;
} }
/** /**
* Sets the <tt>ONFOCUS</tt> attribute for the HTML tags that compose * Sets the <tt>ONFOCUS</tt> attribute for the HTML tags that compose this element.
* this element.
*/ */
public void setOnFocus(String javascriptCode) { public void setOnFocus(String javascriptCode) {
setAttribute(ON_FOCUS,javascriptCode); setAttribute(ON_FOCUS, javascriptCode);
} }
/** /**
* Sets the <tt>ONBLUR</tt> attribute for the HTML tags that compose * Sets the <tt>ONBLUR</tt> attribute for the HTML tags that compose this element.
* this element.
*/ */
public void setOnBlur(String javascriptCode) { public void setOnBlur(String javascriptCode) {
setAttribute(ON_BLUR,javascriptCode); setAttribute(ON_BLUR, javascriptCode);
} }
/** /**
* Sets the <tt>ONSELECT</tt> attribute for the HTML tags that compose * Sets the <tt>ONSELECT</tt> attribute for the HTML tags that compose this element.
* this element.
*/ */
public void setOnSelect(String javascriptCode) { public void setOnSelect(String javascriptCode) {
setAttribute(ON_SELECT,javascriptCode); setAttribute(ON_SELECT, javascriptCode);
} }
/** /**
* Sets the <tt>ONCHANGE</tt> attribute for the HTML tags that compose * Sets the <tt>ONCHANGE</tt> attribute for the HTML tags that compose this element.
* this element.
*/ */
public void setOnChange(String javascriptCode) { public void setOnChange(String javascriptCode) {
setAttribute(ON_CHANGE,javascriptCode); setAttribute(ON_CHANGE, javascriptCode);
} }
/** /**
* Sets the <tt>ON_KEY_UP</tt> attribute for the HTML tags that compose * Sets the <tt>ON_KEY_UP</tt> attribute for the HTML tags that compose this element.
* this element. *
**/ */
public void setOnKeyUp(String javascriptCode) { public void setOnKeyUp(String javascriptCode) {
setAttribute(ON_KEY_UP, javascriptCode); setAttribute(ON_KEY_UP, javascriptCode);
} }
/** /**
* Sets the default value in the parameter model for this element. This * Sets the default value in the parameter model for this element. This is a static property and
* is a static property and this method should not be invoked at request time * this method should not be invoked at request time (not even in a PrintListener).
* (not even in a PrintListener).
*/ */
public void setDefaultValue(Object value) { public void setDefaultValue(Object value) {
m_parameterModel.setDefaultValue(value); m_parameterModel.setDefaultValue(value);
} }
/** /**
* Marks this widget as readonly, which has the effect of * Marks this widget as readonly, which has the effect of preventing the user from modifying the
* preventing the user from modifying the widget's contents. * widget's contents. This method can only be called on unlocked widgets.
* This method can only be called on unlocked widgets.
*/ */
public void setReadOnly() { public void setReadOnly() {
Assert.isUnlocked(this); Assert.isUnlocked(this);
@ -366,10 +346,9 @@ public abstract class Widget extends BlockStylable implements Cloneable,
} }
/** /**
* Marks this widget as disabled, which has the effect of preventing the * Marks this widget as disabled, which has the effect of preventing the widget's value being
* widget's value being submitted with the form, and will typically cause * submitted with the form, and will typically cause the widget to be 'grayed out' on the form.
* the widget to be 'grayed out' on the form. This method can only be * This method can only be called on unlocked widgets.
* called on unlocked widgets.
*/ */
public void setDisabled() { public void setDisabled() {
Assert.isUnlocked(this); Assert.isUnlocked(this);
@ -378,8 +357,9 @@ public abstract class Widget extends BlockStylable implements Cloneable,
/** /**
* Sets a popup hint for the widget. * Sets a popup hint for the widget.
* @deprecated refactor to use a GlobalizedMessage instead and use *
* setHint(GlobalizedMessage hint) * @deprecated refactor to use a GlobalizedMessage instead and use setHint(GlobalizedMessage
* hint)
*/ */
public void setHint(String hint) { public void setHint(String hint) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
@ -391,7 +371,7 @@ public abstract class Widget extends BlockStylable implements Cloneable,
*/ */
public void setHint(GlobalizedMessage hint) { public void setHint(GlobalizedMessage hint) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
setAttribute("hint", (String)hint.localize() ); setAttribute("hint", (String) hint.localize());
} }
/** /**
@ -408,13 +388,12 @@ public abstract class Widget extends BlockStylable implements Cloneable,
return m_label; return m_label;
} }
/** /**
* Gets the default value in the parameter model for this element. * Gets the default value in the parameter model for this element.
*/ */
public String getDefaultValue() { public String getDefaultValue() {
Object o = m_parameterModel.getDefaultValue(); Object o = m_parameterModel.getDefaultValue();
if (o==null) { if (o == null) {
return null; return null;
} }
return o.toString(); return o.toString();
@ -425,42 +404,40 @@ public abstract class Widget extends BlockStylable implements Cloneable,
} }
/** /**
* The "pass in" property determines whether the value for this * The "pass in" property determines whether the value for this parameter is generally passed in
* parameter is generally passed in from the outside. If this property * from the outside. If this property is <code>true</code>, the model always tries to get the
* is <code>true</code>, the model always tries to get the parameter * parameter value from the request, no matter whether the request is the initial request or a
* value from the request, no matter whether the request is the initial * submission of the form to which the widget belongs.
* request or a submission of the form to which the widget belongs.
* *
* <p> If this property is <code>false</code>, the parameter value is * <p>
* only read from the request if it is a submission of the form * If this property is <code>false</code>, the parameter value is only read from the request if
* containing the widget. * it is a submission of the form containing the widget.
* *
* <p> By default, this property is <code>false</code>. * <p>
* By default, this property is <code>false</code>.
* *
* @return <code>true</code> if an attempt should always be made to * @return <code>true</code> if an attempt should always be made to retrieve the parameter value
* retrieve the parameter value from the request. * from the request.
*/ */
public final boolean isPassIn() { public final boolean isPassIn() {
return getParameterModel().isPassIn(); return getParameterModel().isPassIn();
} }
/** /**
* Set whether this parameter should be treated as a "pass in" * Set whether this parameter should be treated as a "pass in" parameter. This is a static
* parameter. This is a static property of the ParameterModel * property of the ParameterModel and this method should not be invoked at request-time.
* and this method should not be invoked at request-time.
* *
* @see #isPassIn * @see #isPassIn
* @param v <code>true</code> if this parameter is a pass in parameter. * @param v <code>true</code> if this parameter is a pass in parameter.
*/ */
public final void setPassIn(boolean v) { public final void setPassIn(boolean v) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
getParameterModel().setPassIn(v); getParameterModel().setPassIn(v);
} }
/** /**
* The ParameterModel is normally set via the constructors. This method is only * The ParameterModel is normally set via the constructors. This method is only rarely needed.
* rarely needed. Please note that the previous ParameterModel and all its * Please note that the previous ParameterModel and all its listeners will be lost.
* listeners will be lost.
*/ */
public final void setParameterModel(ParameterModel parameterModel) { public final void setParameterModel(ParameterModel parameterModel) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
@ -468,11 +445,10 @@ public abstract class Widget extends BlockStylable implements Cloneable,
} }
/** /**
* Allows access to underlying parameterModel. The ParameterModel contains * Allows access to underlying parameterModel. The ParameterModel contains static
* static (request-independent) properties of a Widget such as its name, * (request-independent) properties of a Widget such as its name, default value and its
* default value and its listeners. The ParameterModel can not be modified * listeners. The ParameterModel can not be modified once Page.lock() has been invoked (not even
* once Page.lock() has been invoked (not even in a PrintListener). This is done * in a PrintListener). This is done after the Page has been built, normally at server startup.
* after the Page has been built, normally at server startup.
*/ */
public final ParameterModel getParameterModel() { public final ParameterModel getParameterModel() {
return m_parameterModel; return m_parameterModel;
@ -480,23 +456,23 @@ public abstract class Widget extends BlockStylable implements Cloneable,
/** /**
* <p> * <p>
* This method creates the DOM for the widget. The method is called * This method creates the DOM for the widget. The method is called by the Bebop framework and
* by the Bebop framework and should not be invoked by application * should not be invoked by application developers.
* developers.
* </p> * </p>
* *
* <p> * <p>
* The method first fires the print event allowing application developers to set * The method first fires the print event allowing application developers to set certain
* certain properties of the Widget at request time in a PrintListener. * properties of the Widget at request time in a PrintListener. The methods generateWidget and
* The methods generateWidget and
* generateErrors will then be invoked to generate either of the following * generateErrors will then be invoked to generate either of the following
* </p> * </p>
* *
* <p><code>&lt;bebop:formErrors message=...> * <p>
* <code>&lt;bebop:formErrors message=...>
* &lt;/bebop:formErrors></code> * &lt;/bebop:formErrors></code>
* </p> * </p>
* *
* <p><code>&lt;bebop:formWidget name=... type=... value=... [onXXX=...]> * <p>
* <code>&lt;bebop:formWidget name=... type=... value=... [onXXX=...]>
* &lt;/bebop:formWidget></code> * &lt;/bebop:formWidget></code>
* </p> * </p>
* *
@ -513,13 +489,13 @@ public abstract class Widget extends BlockStylable implements Cloneable,
protected Widget firePrintEvent(PageState state) { protected Widget firePrintEvent(PageState state) {
Widget w = this; Widget w = this;
if ( m_printListener != null ) { if (m_printListener != null) {
try { try {
w = (Widget) this.clone(); w = (Widget) this.clone();
w.setForm(m_form); w.setForm(m_form);
m_printListener.prepare(new PrintEvent(this, state, w)); m_printListener.prepare(new PrintEvent(this, state, w));
} catch ( CloneNotSupportedException e ) { } catch (CloneNotSupportedException e) {
// FIXME: Failing silently here isn't so great // FIXME: Failing silently here isn't so great
// It probably indicates a serious programming error // It probably indicates a serious programming error
w = this; w = this;
@ -528,34 +504,39 @@ public abstract class Widget extends BlockStylable implements Cloneable,
return w; return w;
} }
/** The XML tag. /**
* @return The tag to be used for the top level DOM element * The XML tag.
* generated for this type of Widget. */ *
protected String getElementTag() * @return The tag to be used for the top level DOM element generated for this type of Widget.
{ */
protected String getElementTag() {
return BEBOP_FORMWIDGET; return BEBOP_FORMWIDGET;
} }
/** /**
* Generates the DOM for the given widget. * Generates the DOM for the given widget.
* <p>Generates DOM fragment: * <p>
* <p><code>&lt;bebop:formWidget name=... type=... value=... [onXXX=...]> * Generates DOM fragment:
* &lt;/bebop:formWidget></code> */ * <p>
protected void generateWidget ( PageState state, Element parent ) { * <code>&lt;bebop:formWidget name=... type=... value=... [onXXX=...]>
* &lt;/bebop:formWidget></code>
*/
protected void generateWidget(PageState state, Element parent) {
Element widget = parent.newChildElement(getElementTag(), BEBOP_XML_NS); Element widget = parent.newChildElement(getElementTag(), BEBOP_XML_NS);
widget.addAttribute("type", getType()); widget.addAttribute("type", getType());
widget.addAttribute("name", getName()); widget.addAttribute("name", getName());
if (m_label != null) if (m_label != null) {
widget.addAttribute("label", widget.addAttribute("label",
(String)m_label.localize(state.getRequest())); (String) m_label.localize(state.getRequest()));
}
exportAttributes(widget); exportAttributes(widget);
String value = null; String value = null;
ParameterData p = getParameterData(state); ParameterData p = getParameterData(state);
if ( p != null ) { if (p != null) {
value = p.marshal(); value = p.marshal();
} }
if ( value == null ) { if (value == null) {
value = ""; value = "";
} }
widget.addAttribute("value", value); widget.addAttribute("value", value);
@ -563,28 +544,28 @@ public abstract class Widget extends BlockStylable implements Cloneable,
/** /**
* Generates the XML for the given widget * Generates the XML for the given widget
* <p>Generates XML fragment: * <p>
* <p><code>&lt;bebop:formErrors message=... id=name> * Generates XML fragment:
* <p>
* <code>&lt;bebop:formErrors message=... id=name>
* &lt;/bebop:formErrors></code> * &lt;/bebop:formErrors></code>
*/ */
protected void generateErrors (PageState state, Element parent) { protected void generateErrors(PageState state, Element parent) {
Iterator i = getErrors(state); Iterator i = getErrors(state);
while (i.hasNext()) { while (i.hasNext()) {
Element errors = parent.newChildElement(BEBOP_FORMERRORS, BEBOP_XML_NS); Element errors = parent.newChildElement(BEBOP_FORMERRORS, BEBOP_XML_NS);
errors.addAttribute("message", errors.addAttribute("message",
(String) ((GlobalizedMessage) (String) ((GlobalizedMessage) i.next()).localize(state.getRequest())
i.next()).localize(state.getRequest()) );
);
errors.addAttribute("id", getName()); errors.addAttribute("id", getName());
} }
} }
/** /**
* Get the value associated with this widget in the request described by * Get the value associated with this widget in the request described by <code>ps</code>. The
* <code>ps</code>. The type of the returned object depends on the * type of the returned object depends on the <code>ParameterModel</code> underlying this
* <code>ParameterModel</code> underlying this widget. This method is * widget. This method is typically called in a FormProcessListener to access the value that was
* typically called in a FormProcessListener to access the value that was
* submitted for a Widget in the Form. * submitted for a Widget in the Form.
* *
* @param ps describes the request currently being processed * @param ps describes the request currently being processed
@ -599,45 +580,43 @@ public abstract class Widget extends BlockStylable implements Cloneable,
// check if value is in session // check if value is in session
HttpSession session = ps.getRequest().getSession(false); HttpSession session = ps.getRequest().getSession(false);
if (session != null) { if (session != null) {
data = session.getAttribute(getName()); data = session.getAttribute(getName());
} }
} else { } else {
data = p.getValue(); data = p.getValue();
} }
return (data==null) ? getDefaultValue() : data; return (data == null) ? getDefaultValue() : data;
} }
/** /**
* Set the value of the parameter associated with this widget to a new * Set the value of the parameter associated with this widget to a new value. The exact type of
* value. The exact type of <code>value</code> depends on the * <code>value</code> depends on the <code>ParameterModel</code> underlying the widget. This
* <code>ParameterModel</code> underlying the widget. This method is * method is typically called in a FormInitListener to initialize the value of a Widget in the
* typically called in a FormInitListener to initialize the value of * Form at request time.
* a Widget in the Form at request time.
* *
* @pre ps != null * @pre ps != null
* @post value == getValue(ps) * @post value == getValue(ps)
* *
* @throws IllegalStateExeption the form to which the widget belongs has * @throws IllegalStateExeption the form to which the widget belongs has not been processed yet.
* not been processed yet.
*/ */
public void setValue(PageState ps, Object value) public void setValue(PageState ps, Object value)
throws IllegalStateException { throws IllegalStateException {
Assert.exists(ps, "PageState"); Assert.exists(ps, "PageState");
ParameterData p = getParameterData(ps); ParameterData p = getParameterData(ps);
// set value in session if it is being held - allows // set value in session if it is being held - allows
// updates in wizard forms where init is not called each // updates in wizard forms where init is not called each
// step // step
HttpSession session = ps.getRequest().getSession(false); HttpSession session = ps.getRequest().getSession(false);
if (session != null && session.getAttribute(getName()) != null) { if (session != null && session.getAttribute(getName()) != null) {
session.setAttribute(getName(), value); session.setAttribute(getName(), value);
} }
if (p!=null) { if (p != null) {
p.setValue(value); p.setValue(value);
} else { } else {
throw new IllegalStateException("Cannot set value for widget '" + throw new IllegalStateException("Cannot set value for widget '" + getName()
getName() + "': corresponding form '" + "': corresponding form '"
+ getForm().getName() + getForm().getName()
+ "' has not been processed yet."); + "' has not been processed yet.");
} }
@ -646,7 +625,7 @@ public abstract class Widget extends BlockStylable implements Cloneable,
protected Iterator getErrors(PageState ps) { protected Iterator getErrors(PageState ps) {
Assert.exists(ps, "PageState"); Assert.exists(ps, "PageState");
FormData f = getForm().getFormData(ps); FormData f = getForm().getFormData(ps);
if (f!=null) { if (f != null) {
return f.getErrors(getName()); return f.getErrors(getName());
} }
return Collections.EMPTY_LIST.iterator(); return Collections.EMPTY_LIST.iterator();
@ -666,11 +645,10 @@ public abstract class Widget extends BlockStylable implements Cloneable,
} }
/** /**
* Respond to an incoming request by calling <code>respond</code> on the * Respond to an incoming request by calling <code>respond</code> on the form to which the
* form to which the widget belongs. This method is called * widget belongs. This method is called by the Bebop framework and should not be invoked by
* by the Bebop framework and should not be invoked by application * application developers. It is somewhat questionable that this method should ever be called,
* developers. It is somewhat questionable that * rather than having {@link
* this method should ever be called, rather than having {@link
* Form#respond Form.respond()} called directly. * Form#respond Form.respond()} called directly.
* *
* @pre state != null * @pre state != null
@ -688,8 +666,8 @@ public abstract class Widget extends BlockStylable implements Cloneable,
} }
/** /**
* Specify a Widget.ValidationGuard implementation to use to determine if * Specify a Widget.ValidationGuard implementation to use to determine if this widget should run
* this widget should run its validation listeners. * its validation listeners.
* *
* @param guard the Widget.ValidationGuard. * @param guard the Widget.ValidationGuard.
*/ */
@ -699,10 +677,11 @@ public abstract class Widget extends BlockStylable implements Cloneable,
} }
/** /**
* Inner interface used to determine if the validation listeners should be * Inner interface used to determine if the validation listeners should be run for this widget
* run for this widget or not. * or not.
*/ */
public interface ValidationGuard { public interface ValidationGuard {
boolean shouldValidate(PageState ps); boolean shouldValidate(PageState ps);
} }

View File

@ -25,8 +25,8 @@ import com.arsdigita.web.Web;
import com.arsdigita.xml.Element; import com.arsdigita.xml.Element;
/** /**
* *
* *
*/ */
public class SiteBanner extends SimpleComponent { public class SiteBanner extends SimpleComponent {

View File

@ -65,7 +65,7 @@ public class ApplicationNavigationModel implements NavigationModel {
} }
private NavigationModel getNavigationModel() { private NavigationModel getNavigationModel() {
NavigationModel model = (NavigationModel)s_model.get(); NavigationModel model = (NavigationModel)s_model.get();
if (model != null) { if (model != null) {
if (s_log.isDebugEnabled()) { if (s_log.isDebugEnabled()) {
s_log.debug("Using cached model " + model.getClass().getName()); s_log.debug("Using cached model " + model.getClass().getName());

View File

@ -3,9 +3,7 @@ package com.arsdigita.navigation.ui.object;
import com.arsdigita.categorization.Category; import com.arsdigita.categorization.Category;
import com.arsdigita.categorization.CategoryCollection; import com.arsdigita.categorization.CategoryCollection;
import com.arsdigita.domain.DomainObjectFactory; import com.arsdigita.domain.DomainObjectFactory;
import com.arsdigita.persistence.CompoundFilter;
import com.arsdigita.persistence.DataCollection; import com.arsdigita.persistence.DataCollection;
import com.arsdigita.persistence.FilterFactory;
import com.arsdigita.persistence.SessionManager; import com.arsdigita.persistence.SessionManager;
import com.arsdigita.xml.Element; import com.arsdigita.xml.Element;
import java.util.ArrayList; import java.util.ArrayList;
@ -59,28 +57,32 @@ public class CategoryFilter {
public void applyFilter(final DataCollection objects) { public void applyFilter(final DataCollection objects) {
if (!values.isEmpty()) { if (!values.isEmpty()) {
final FilterFactory filterFactory = objects.getFilterFactory(); //final FilterFactory filterFactory = objects.getFilterFactory();
final CompoundFilter compoundFilter = filterFactory.and(); //final CompoundFilter compoundFilter = filterFactory.and();
final List<String> categoryIds = new ArrayList<String>();
for (String value : values) { for (String value : values) {
if (multiple) { if (multiple) {
//When using multiple search we assume text input for now //When using multiple search we assume text input for now
if (catNameToCatId.containsKey(value)) { if (catNameToCatId.containsKey(value)) {
final com.arsdigita.persistence.Filter filter = filterFactory.in( // final com.arsdigita.persistence.Filter filter = filterFactory.in(
"parent.id", "com.arsdigita.categorization.objectIDsInSubtree"); // "parent.id", "com.arsdigita.categorization.objectIDsInSubtree");
//filter.set("categoryID", value); // filter.set("categoryID", catNameToCatId.get(value));
filter.set("categoryID", catNameToCatId.get(value)); // compoundFilter.addFilter(filter);
compoundFilter.addFilter(filter); categoryIds.add(catNameToCatId.get(value));
} }
} else { } else {
//Otherwise, we assume that we get the ID of a single category //Otherwise, we assume that we get the ID of a single category
final com.arsdigita.persistence.Filter filter = filterFactory.in( // final com.arsdigita.persistence.Filter filter = filterFactory.in(
"parent.id", "com.arsdigita.categorization.objectIDsInSubtree"); // "parent.id", "com.arsdigita.categorization.objectIDsInSubtree");
filter.set("categoryID", value); // filter.set("categoryID", value);
compoundFilter.addFilter(filter); // compoundFilter.addFilter(filter);
categoryIds.add(value);
} }
} }
objects.addFilter(compoundFilter); final com.arsdigita.persistence.Filter filter = objects.addInSubqueryFilter("parent.id", "com.arsdigita.categorization.objectIDsInMultipleSubtrees");
filter.set("categoryIDs", categoryIds);
//objects.addFilter(compoundFilter);
} }
} }
@ -180,6 +182,7 @@ public class CategoryFilter {
} }
public void setValue(final String value) { public void setValue(final String value) {
values.clear();
if ((value != null) && !value.isEmpty()) { if ((value != null) && !value.isEmpty()) {
final String[] tokens = value.split(separator); final String[] tokens = value.split(separator);
for (String token : tokens) { for (String token : tokens) {
@ -187,5 +190,4 @@ public class CategoryFilter {
} }
} }
} }
} }

View File

@ -12,66 +12,55 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
/** /**
* <p> An object list variant which can be filtered and sorted by the visitor of * <p> An object list variant which can be filtered and sorted by the visitor of the website. The
* the website. The available filters and sort options are added in a JSP * available filters and sort options are added in a JSP template. There are three kinds of filters
* template. There are three kinds of filters yet: </p> <dl> * yet: </p> <dl>
* <dt><code>TextFilter</code></dt> <dd>This filter filters the object list * <dt><code>TextFilter</code></dt> <dd>This filter filters the object list using a user provided
* using a user provided string, which is put into the * string, which is put into the
* <code>WHERE</code> clause with * <code>WHERE</code> clause with
* <code>LIKE</code> operator. You might use this filter to allow the visitor to * <code>LIKE</code> operator. You might use this filter to allow the visitor to filter an object
* filter an object list for items with a specific name.</dd> * list for items with a specific name.</dd>
* <dt><code>SelectFilter</code></dt> <dd>This filter traverses through the * <dt><code>SelectFilter</code></dt> <dd>This filter traverses through the objects displayed by the
* objects displayed by the list and determines all distinct values of a * list and determines all distinct values of a property. The visitor can choose one of this values,
* property. The visitor can choose one of this values, and the displayed list * and the displayed list will only contain items which where the property has the selected
* will only contain items which where the property has the selected value.</dd> * value.</dd>
* <dt><code>CompareFilter</code></dt> <dd>This filter also provides selectable * <dt><code>CompareFilter</code></dt> <dd>This filter also provides selectable options. But these
* options. But these options can be configured by the developer in the * options can be configured by the developer in the template.</dd> </dl> <p> If there is more than
* template.</dd> </dl> <p> If there is more than one filter, the values of all * one filter, the values of all filters are combined using
* filters are combined using * <code>AND</code>. </p> <p> This object list class was developed for displaying list of items from
* <code>AND</code>. </p> <p> This object list class was developed for * the Sci modules (SciPublications and SciOrganization). For example, we use this list to provide
* displaying list of items from the Sci modules (SciPublications and * lists of publications which be filtered for publications from a specific year, for a specific
* SciOrganization). For example, we use this list to provide lists of * author and for a specific title. The list can be sorted by the titles of the publications, the
* publications which be filtered for publications from a specific year, for a * years of the publications and the (surnames of the) authors of the publications. </p> <p> As an
* specific author and for a specific title. The list can be sorted by the * example how to use this object list in a JSP template here are the relevant parts from the
* titles of the publications, the years of the publications and the (surnames * template for the publication list: </p>
* of the) authors of the publications. </p> <p> As an example how to use this
* object list in a JSP template here are the relevant parts from the template
* for the publication list: </p>
* <pre> * <pre>
* {@code * {@code
* ... * ...
* <define:component name="itemList" * <define:component name="itemList"
* classname="com.arsdigita.navigation.ui.object.CustomizableObjectList"/> * classname="com.arsdigita.navigation.ui.object.CustomizableObjectList"/>
* ... * ...
* <jsp:scriptlet> * <jsp:scriptlet>
* CustomizableObjectList objList = (CustomizableObjectList) itemList; * CustomizableObjectList objList = (CustomizableObjectList) itemList; objList.setDefinition(new
* objList.setDefinition(new CMSDataCollectionDefinition()); * CMSDataCollectionDefinition()); objList.setRenderer(new CMSDataCollectionRenderer());
* objList.setRenderer(new CMSDataCollectionRenderer());
* objList.getDefinition().setObjectType("com.arsdigita.cms.contenttypes.Publication"); * objList.getDefinition().setObjectType("com.arsdigita.cms.contenttypes.Publication");
* objList.getDefinition().setDescendCategories(false); * objList.getDefinition().setDescendCategories(false); objList.addTextFilter("title", "title");
* objList.addTextFilter("title", "title"); * objList.addTextFilter("authors.surname", "author"); objList.addSelectFilter("yearOfPublication",
* objList.addTextFilter("authors.surname", "author"); * "year", true, true, true, true); objList.addSortField("title", "title asc");
* objList.addSelectFilter("yearOfPublication", "year", true, true, true, true); * objList.addSortField("yearAsc", "yearOfPublication asc"); objList.addSortField("yearDesc",
* objList.addSortField("title", "title asc"); * "yearOfPublication desc"); objList.addSortField("authors", "authors.surname asc,
* objList.addSortField("yearAsc", "yearOfPublication asc"); * authors.givenname asc");
* objList.addSortField("yearDesc", "yearOfPublication desc");
* objList.addSortField("authors", "authors.surname asc, authors.givenname asc");
* objList.getDefinition().addOrder(objList.getOrder(request.getParameter("sort"))); * objList.getDefinition().addOrder(objList.getOrder(request.getParameter("sort")));
* *
* objList.getRenderer().setPageSize(20); * objList.getRenderer().setPageSize(20); objList.getRenderer().setSpecializeObjects(true);
* objList.getRenderer().setSpecializeObjects(true);
* *
* </jsp:scriptlet> * </jsp:scriptlet>
* ... * ... }
* }
* </pre> <p> You may notice the line * </pre> <p> You may notice the line
* <code>objList.getDefinition().addOrder(objList.getOrder(request.getParameter("sort")));</code>. * <code>objList.getDefinition().addOrder(objList.getOrder(request.getParameter("sort")));</code>.
* This line may looks a bit weird to you. The reason is that it is not possible * This line may looks a bit weird to you. The reason is that it is not possible to access the
* to access the * <code>DataCollectionDefinition</code> from the methods in this class. If you try call the
* <code>DataCollectionDefinition</code> from the methods in this class. If you * <code>addOrder()</code> from within this class you will cause an locking error. </p>
* try call the
* <code>addOrder()</code> from within this class you will cause an locking
* error. </p>
* *
* @author Jens Pelzetter * @author Jens Pelzetter
* @version $Id$ * @version $Id$
@ -85,16 +74,16 @@ public class CustomizableObjectList extends ComplexObjectList {
private static final Logger logger = Logger.getLogger( private static final Logger logger = Logger.getLogger(
CustomizableObjectList.class); CustomizableObjectList.class);
/** /**
* The filters for the list. We use an {@link LinkedHashMap} here to * The filters for the list. We use an {@link LinkedHashMap} here to preserve the insertation
* preserve the insertation order. * order.
* *
*/ */
private final Map<String, Filter> filters = private final Map<String, Filter> filters =
new LinkedHashMap<String, Filter>(); new LinkedHashMap<String, Filter>();
private CategoryFilter categoryFilter; private CategoryFilter categoryFilter;
/** /**
* The available sort fields. We use an {@link LinkedHashMap} here to * The available sort fields. We use an {@link LinkedHashMap} here to preserve the insertation
* preserve the insertation order. * order.
* *
*/ */
private final Map<String, String> sortFields = private final Map<String, String> sortFields =
@ -123,12 +112,11 @@ public class CustomizableObjectList extends ComplexObjectList {
* @param allOptionIsDefault Is the all option the default? * @param allOptionIsDefault Is the all option the default?
* @param propertyIsNumeric Is the property to filter numeric? * @param propertyIsNumeric Is the property to filter numeric?
* @return The new filter. Options can be added to the filter by calling the * @return The new filter. Options can be added to the filter by calling the
* {@link CompareFilter#addOption(java.lang.String, java.lang.String)} or * {@link CompareFilter#addOption(java.lang.String, java.lang.String)} or the
* the
* {@link CompareFilter#addOption(java.lang.String, com.arsdigita.navigation.ui.object.CompareFilter.Operators, java.lang.String)} * {@link CompareFilter#addOption(java.lang.String, com.arsdigita.navigation.ui.object.CompareFilter.Operators, java.lang.String)}
* method. * method.
* @see CompareFilter#CompareFilter(java.lang.String, java.lang.String, * @see CompareFilter#CompareFilter(java.lang.String, java.lang.String, boolean, boolean,
* boolean, boolean, boolean) * boolean)
* *
*/ */
public CompareFilter addCompareFilter(final String property, public CompareFilter addCompareFilter(final String property,
@ -158,8 +146,8 @@ public class CustomizableObjectList extends ComplexObjectList {
* @param allOptionIsDefault Is the all option the default. * @param allOptionIsDefault Is the all option the default.
* @param propertyIsNumeric Is the property numeric? * @param propertyIsNumeric Is the property numeric?
* @see SelectFilter#SelectFilter(java.lang.String, java.lang.String, * @see SelectFilter#SelectFilter(java.lang.String, java.lang.String,
* com.arsdigita.navigation.ui.object.CustomizableObjectList, boolean, * com.arsdigita.navigation.ui.object.CustomizableObjectList, boolean, boolean, boolean,
* boolean, boolean, boolean) * boolean)
*/ */
public void addSelectFilter(final String property, public void addSelectFilter(final String property,
final String label, final String label,
@ -212,9 +200,8 @@ public class CustomizableObjectList extends ComplexObjectList {
/** /**
* This overwritten version of the * This overwritten version of the
* <code>getObjects</code> method evaluates the parameters in HTTP request * <code>getObjects</code> method evaluates the parameters in HTTP request for the filters and
* for the filters and creates an appropriate SQL filter and sets this * creates an appropriate SQL filter and sets this filter.
* filter.
* *
* @param request * @param request
* @param response * @param response
@ -281,10 +268,9 @@ public class CustomizableObjectList extends ComplexObjectList {
/** /**
* <p> Generates the XML for the list. The root element for the list is * <p> Generates the XML for the list. The root element for the list is
* <code>customizableObjectList</code>. The available filters are put into a * <code>customizableObjectList</code>. The available filters are put into a
* <code>filters</code> element. </p> <p> The available sort fields are put * <code>filters</code> element. </p> <p> The available sort fields are put into a
* into a * <code>sortFields</code> element. This element has also an attribute indicating the current
* <code>sortFields</code> element. This element has also an attribute * selected sort field. </p>
* indicating the current selected sort field. </p>
* *
* @param request * @param request
* @param response * @param response
@ -331,12 +317,14 @@ public class CustomizableObjectList extends ComplexObjectList {
if (categoryFilter != null) { if (categoryFilter != null) {
final String value = Globalization.decodeParameter(request, categoryFilter.getLabel()); final String value = Globalization.decodeParameter(request, categoryFilter.getLabel());
if ((value != null) && !value.isEmpty()) { if ((value == null) || value.isEmpty()) {
categoryFilter.setValue("");
} else {
categoryFilter.setValue(value); categoryFilter.setValue(value);
} }
} }
if (!filters.isEmpty() || (categoryFilter != null)) { if (!filters.isEmpty() || (categoryFilter != null)) {
final Element controls = content.newChildElement("filterControls"); final Element controls = content.newChildElement("filterControls");
controls.addAttribute("customName", m_customName); controls.addAttribute("customName", m_customName);
@ -372,5 +360,4 @@ public class CustomizableObjectList extends ComplexObjectList {
return content; return content;
} }
} }