Removed several depcrecated classes from ccm-core, especially the complete Bebop UI kit.

pull/28/head
Jens Pelzetter 2022-03-23 20:22:41 +01:00
parent abe48a650d
commit b681c769b9
323 changed files with 73 additions and 57010 deletions

View File

@ -18,13 +18,10 @@
*/
package org.librecms;
import com.arsdigita.bebop.form.DHTMLEditor;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.configuration.Configuration;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.configuration.Setting;
import org.libreccm.core.UnexpectedErrorException;
import java.util.ArrayList;
import java.util.Arrays;
@ -602,42 +599,6 @@ public class CMSConfig {
this.useStreamlinedCreation = useStreamlinedCreation;
}
public DHTMLEditor.Config getDHTMLEditorConfig() {
if (dhtmlEditorConfig.size() < 2) {
return DHTMLEditor.Config.STANDARD;
} else {
return new DHTMLEditor.Config(dhtmlEditorConfig.get(0),
dhtmlEditorConfig.get(1));
}
}
public List<String> getDhtmlEditorConfig() {
return new ArrayList<>(dhtmlEditorConfig);
}
public void setDhtmlEditorConfig(final List<String> dhtmlEditorConfig) {
this.dhtmlEditorConfig = new ArrayList<>(dhtmlEditorConfig);
}
public List<String> getDhtmlEditorPlugins() {
return new ArrayList<>(dhtmlEditorPlugins);
}
public void setDhtmlEditorPlugins(final List<String> dhtmlEditorPlugins) {
this.dhtmlEditorPlugins = new ArrayList<>(dhtmlEditorPlugins);
}
public List<String> getDhtmlEditorHiddenButtons() {
return new ArrayList<>(dhtmlEditorHiddenButtons);
}
public void setDhtmlEditorHiddenButtons(
final List<String> dhtmlEditorHiddenButtons) {
this.dhtmlEditorHiddenButtons
= new ArrayList<>(dhtmlEditorHiddenButtons);
}
public boolean isHideAdminTabs() {
return hideAdminTabs;
}

View File

@ -18,7 +18,6 @@
*/
package org.librecms.contenttypes;
import com.arsdigita.bebop.FormSection;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -34,7 +33,7 @@ import java.lang.annotation.Target;
@Deprecated
public @interface AuthoringKit {
Class<? extends FormSection> createComponent();
Class<Object> createComponent();
AuthoringStep[] steps();

View File

@ -18,7 +18,6 @@
*/
package org.librecms.contenttypes;
import com.arsdigita.bebop.FormSection;
import java.util.ArrayList;
import java.util.Collections;
@ -36,7 +35,7 @@ public class AuthoringKitInfo {
* The create component (the form used to collect the mandatory data for the
* content type).
*/
private Class<? extends FormSection> createComponent;
private Class<Object> createComponent;
/**
* The authoring steps of the authoring kit.
@ -47,12 +46,12 @@ public class AuthoringKitInfo {
authoringSteps = new ArrayList<>();
}
public Class<? extends FormSection> getCreateComponent() {
public Class<Object> getCreateComponent() {
return createComponent;
}
public void setCreateComponent(
final Class<? extends FormSection> createComponent) {
final Class<Object> createComponent) {
this.createComponent = createComponent;
}

View File

@ -20,16 +20,17 @@ package org.librecms.util;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.kernel.KernelConfig;
import com.arsdigita.util.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.configuration.ConfigurationManager;
@ -43,7 +44,7 @@ import org.libreccm.l10n.GlobalizationHelper;
public class LanguageUtil {
private static final Logger LOGGER = LogManager.
getLogger(LanguageUtil.class);
getLogger(LanguageUtil.class);
@Inject
private GlobalizationHelper globalizationHelper;
@ -51,16 +52,20 @@ public class LanguageUtil {
/**
* Mapping from the ISO639-1 2-letter codes to the ISO639-2 3-letter codes
*/
private static final String ISO639_2LA_3LA = "com.arsdigita.cms.util.iso639rev";
private static final String ISO639_2LA_3LA
= "com.arsdigita.cms.util.iso639rev";
private static final ResourceBundle LANG_3LA = ResourceBundle.getBundle(
ISO639_2LA_3LA);
ISO639_2LA_3LA);
/**
* Mapping from the ISO639-1 2-letter codes to the full descriptive name
*/
private static final String ISO639_2LA_FULL = "com.arsdigita.cms.util.iso639full";
private static final String ISO639_2LA_FULL
= "com.arsdigita.cms.util.iso639full";
private static final ResourceBundle LANG_FULL = ResourceBundle.getBundle(
ISO639_2LA_FULL);
ISO639_2LA_FULL);
@Inject
private ConfigurationManager confManager;
@ -70,11 +75,11 @@ public class LanguageUtil {
@PostConstruct
private void init() {
final KernelConfig kernelConfig = confManager.findConfiguration(
KernelConfig.class);
KernelConfig.class);
supportedLanguages = kernelConfig.getSupportedLanguages()
.stream()
.map(language -> new Locale(language))
.collect(Collectors.toList());
.stream()
.map(language -> new Locale(language))
.collect(Collectors.toList());
}
public GlobalizedMessage globalizedLanguageName(final String key) {
@ -92,34 +97,8 @@ public class LanguageUtil {
*/
public List<String> getSupportedLanguages2LA() {
return getSupportedLanguages().stream()
.map(locale -> locale.getLanguage())
.collect(Collectors.toList());
}
/**
* Returns the collection of all supported languages. Each entry is a pair
* of 2 letter code as key and three letter code as value.
*
* @return all supported languages
*/
public List<Pair> getSupportedLanguages3LA() {
return getSupportedLanguages().stream()
.map(locale -> new Pair(locale.getLanguage(),
locale.getISO3Language()))
.collect(Collectors.toList());
}
/**
* Returns the collection of all supported languages. Each entry is a pair
* of 2 letter code as key and full language name as a value.
*
* @return all supported languages
*/
public List<Pair> getSupportedLanguagesFull() {
return getSupportedLanguages().stream()
.map(locale -> new Pair(locale.getLanguage(),
getLangFull(locale)))
.collect(Collectors.toList());
.map(locale -> locale.getLanguage())
.collect(Collectors.toList());
}
/**
@ -127,8 +106,9 @@ public class LanguageUtil {
* code.
*
* @param lang
*
* @return three letter code for the two letter code. If the resource is not
* found then the key itself is returned.
* found then the key itself is returned.
*/
public String getLang3LA(final String lang) {
String threeLA;
@ -137,7 +117,7 @@ public class LanguageUtil {
threeLA = (new Locale(lang)).getISO3Language();
} catch (MissingResourceException ex) {
LOGGER.warn("No 3 letter code for \"{}\" available via "
+ "Locale#getISO3Language.",
+ "Locale#getISO3Language.",
lang);
LOGGER.warn(ex);
@ -164,12 +144,12 @@ public class LanguageUtil {
* @param lang 2 letter language code
*
* @return full language name for the given two letter code If the resource
* is not found then the key itself is returned.
* is not found then the key itself is returned.
*/
public String getLangFull(final Locale lang) {
// Lookup language name via java.util.Locale
String fullName = (lang.getDisplayLanguage(
globalizationHelper.getNegotiatedLocale()));
globalizationHelper.getNegotiatedLocale()));
if (lang.getLanguage().equals(fullName)) {
// If that fails
@ -192,30 +172,4 @@ public class LanguageUtil {
return getLangFull(new Locale(lang));
}
/**
* Takes in a list of 2 letter codes and converts into 3 letter codes. Each
* entry is pair of 2 letter code as key and 3 letter code as value.
*
* @param list
* @return
*/
public List<Pair> convertTo3LA(final List<String> list) {
return list.stream()
.map(lang2Code -> new Pair(lang2Code, getLang3LA(lang2Code)))
.collect(Collectors.toList());
}
public List<Pair> convertToFull(final List<String> list) {
return list.stream()
.map(lang2Code -> new Pair(lang2Code, getLangFull(lang2Code)))
.collect(Collectors.toList());
}
public List<Pair> convertToG11N(final List<String> list) {
return list.stream()
.map(lang2Code -> new Pair(lang2Code,
globalizedLanguageName(lang2Code)))
.collect(Collectors.toList());
}
}

View File

@ -1,112 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import java.util.Iterator;
import com.arsdigita.bebop.event.ChangeEvent;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.bebop.event.EventListenerList;
import com.arsdigita.util.Assert;
import com.arsdigita.util.Lockable;
/**
* A standard implementation of <code>SingleSelectionModel</code> and
* <code>Lockable</code>. Those wishing to define a SingleSelectionModel will
* ordinarily want to extend this class.
*
* jensp: Added generics and Java 8 streams instead of using an iterator.
*
* @param <T> The type managed by the parameter model.
*
* @author Unknown
* @author Jens Pelzetter (jensp)
*/
public abstract class AbstractSingleSelectionModel<T>
implements SingleSelectionModel<T>, Lockable {
private final EventListenerList m_listeners;
private boolean m_locked;
/**
* Creates a new AbstractSingleSelectionModel.
*/
public AbstractSingleSelectionModel() {
m_listeners = new EventListenerList();
}
/**
* Returns <code>true</code> if there is a selected element.
*
* @param state the state of the current request
*
* @return <code>true</code> if there is a selected component;
* <code>false</code> otherwise.
*/
@Override
public boolean isSelected(final PageState state) {
return getSelectedKey(state) != null;
}
@Override
public abstract T getSelectedKey(final PageState state);
@Override
public abstract void setSelectedKey(final PageState state, final T key);
@Override
public void clearSelection(final PageState state) {
setSelectedKey(state, null);
}
// Selection change events
@Override
public void addChangeListener(final ChangeListener changeListener) {
Assert.isUnlocked(this);
m_listeners.add(ChangeListener.class, changeListener);
}
@Override
public void removeChangeListener(final ChangeListener changeListener) {
Assert.isUnlocked(this);
m_listeners.remove(ChangeListener.class, changeListener);
}
protected void fireStateChanged(final PageState state) {
final ChangeEvent event = new ChangeEvent(this, state);
final Iterator<ChangeListener> iterator = m_listeners
.getListenerIterator(ChangeListener.class);
while(iterator.hasNext()) {
iterator.next().stateChanged(event);
}
}
// implement Lockable
@Override
public void lock() {
m_locked = true;
}
@Override
public final boolean isLocked() {
return m_locked;
}
}

View File

@ -1,93 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.globalization.GlobalizedMessage;
/**
* A link that runs its action listeners when it is clicked. The target of the
* link is the {@link Page} in which the action link is contained.
*
* <p> Typically, an action link is used in the following way:
* <pre>
* ActionLink l = new ActionLink("Send email to everybody");
* l.addActionListener(new ActionListener() {
* public void actionPerformed(ActionEvent e) {
* System.out.println("Link was clicked.");
* ... figure out who everybody is and send them email ...
* }
* });
* </pre>
*
* <p>See {@link BaseLink} for a description of all Bebop Link classes
* and suggestions for using them.
*
* @author David Lutterkort
* @version $Id$ */
public class ActionLink extends ControlLink {
/**
* The value for the XML type attribute for an {@link ActionLink}.
*/
protected static final String TYPE_ACTION = "action";
/**
* Constructs a new ActionLink. The link encapsulates
* the child component (usually either a label or an image).
*
* @param child the component to be turned into a link
*/
public ActionLink(Component child) {
super(child);
setTypeAttr(TYPE_ACTION);
}
/**
* Constructs a new ActionLink with the given string label.
*
* @param label the string label for the link
*/
public ActionLink(GlobalizedMessage label) {
this(new Label(label));
}
/**
* Constructs a new ActionLink with the given string label.
*
* @param label the string label for the link
* @deprecated refactor to use @see ActionLink(GlobalizedMessage label)
*/
public ActionLink(String label) {
this(new Label(label));
}
/**
* Sets the page state's control event. Should be overridden by child
* classes. By default, the link does not receive any control events.
*
* @param s the current page state
*/
@Override
public void setControlEvent(PageState s) {
s.setControlEvent(this);
}
}

View File

@ -1,578 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.PrintEvent;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.Assert;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.xml.Element;
import java.util.TooManyListenersException;
/**
* The parent of all Bebop Link classes, this class represents a URL on a page.
* It may contain a label, an image, or any other component.
*
* <p>
* The following table lists all Bebop Link classes and suggests when they might
* be used.
* <p>
* <table BORDER=3>
* <tr>
* <th>Link Class</th>
* <th>Usage</th>
* </tr>
* <tr>
* <td>{@link BaseLink}</td>
* <td>Parent class of Bebop Link classes. Extend this class to build your own
* Link class.</td>
* </tr>
* <tr>
* <td>{@link Link}</td>
* <td>Link class that manages its own URL variables. Session information is
* added to the target URL for this type.</td>
* </tr>
* <tr>
* <td>{@link ExternalLink}</td>
* <td>Link that does not encode the URL with any session information. Used for
* a link to a page outside the site.</td>
* </tr>
* <tr>
* <td>{@link ControlLink}</td>
* <td> Used for references within its own page (often as fields in a table
* header for sorting a column).</td>
* </tr>
* <tr>
* <td>{@link ActionLink}</td>
* <td>Sets its own control event and runs its own
* {@link com.arsdigita.bebop.event.ActionListener}s. When the link is clicked,
* the code in the Listener's <tt>actionPerformed</tt> method runs.</td>
* </tr>
* <tr>
* <td>{@link ToggleLink}</td>
* <td>A link that turns into label when it is selected and turns back into a
* link when it is unselected.</td>
* </tr>
* </table>
*
* @version $Id: BaseLink.java 998 2005-11-15 22:27:13Z sskracic $
*/
public abstract class BaseLink extends DescriptiveComponent
implements Cloneable {
/**
* The name of the attribute used in XML to indicate which type of link this
* link represents.
*/
private final static String TYPE_ATTR = "type";
private final static String HREF_NO_JAVASCRIPT = "href_no_javascript";
private final static String HREF = "href";
/**
* Component used to display the link. Typically a Label, may be e.g. an
* image as well.
*/
protected Component m_child;
/**
* Property to store the url the Link points to.
*/
protected String m_url;
// Use the parent class' property!
// /** Property to store informational text for the user about the Link, e.g.
// * how to use it, or when to use it (or not to use it). */
// private GlobalizedMessage m_hint;
protected String m_noJavascriptURL = null;
private PrintListener m_printListener;
private String m_sConfirmMsg = "";
private GlobalizedMessage m_confirmMsg;
/**
* Constructor creates a link taking url as the target and display it to the
* user at the same time. It is the only allowed way to present the user
* with a not globlized information. The implementation currently miss-uses
* the Label component to display just a not globalized String which is
* deprecated.
*
* @param url
*
* @deprecated use BaseLink(Component,url) instead with a Label using a
* GlobalizedMessage instead
*/
public BaseLink(final String url) {
this(new Label(url), url);
}
/**
* Constructor
*
* @param child display component (Label, Image, etc.)
* @param url URL to point at
*/
public BaseLink(final Component child, final String url) {
super();
m_url = url;
m_child = child;
}
/**
* Constructor.
*
* @param child display component (Label, Image, etc.)
* @param listener PrintListener, may be used to change either the Display
* text or the url within a locked page.
*/
public BaseLink(final Component child, final PrintListener listener) {
this(child, "");
try {
addPrintListener(listener);
} catch (TooManyListenersException e) {
// Can't happen
throw new UncheckedWrapperException("Too many listeners: " + e
.getMessage(), e);
}
}
/**
* Constructor.
*
* @param listener
*/
public BaseLink(final PrintListener listener) {
this("", listener);
}
// DEPRECATED constructors
/**
* Constructor.
*
* @param label as text
* @param url
*
* @deprecated use BaseLink(Component,url) instead with a Label using a
* GlobalizedMessage instead
*/
public BaseLink(final String label, final String url) {
this(new Label(label), url);
}
/**
* Constructor.
*
* @param label as text
* @param listener PrintListener, may be used to change either the Display
* text or the url within a locked page.
*
* @deprecated use BaseLink(Component,listener) instead with a Label using a
* GlobalizedMessage instead
*/
public BaseLink(final String label, final PrintListener listener) {
this(new Label(label), listener);
}
// Class Methods
/**
* Clone.
*
* @return The clone of the object.
*
* @throws CloneNotSupportedException If cloning is not supported.
*/
@Override
public Object clone() throws CloneNotSupportedException {
final BaseLink result = (BaseLink) super.clone();
result.m_printListener = null;
return result;
}
/**
* Adds a print listener. Since the <code>PrintListener</code> is expected
* to modify the target of the <code>PrintEvent</code>, only one print
* listener can be set for a link.
*
* @param listener The print listener. Must not <code>null</code>.
*
* @throws IllegalArgumentException if <code>listener</code> is null.
* @throws TooManyListenersException if a print listener has previously been
* added.
*/
public void addPrintListener(final PrintListener listener)
throws IllegalStateException, TooManyListenersException {
if (listener == null) {
throw new IllegalArgumentException(
"Argument listener can not be null");
}
if (m_printListener != null) {
throw new TooManyListenersException(
"Too many listeners. Can only have one");
}
m_printListener = listener;
}
/**
* Removes a previously added print listener. If the passed in
* <code>listener</code> is not the listener that was added with
* {@link #addPrintListener addPrintListener}, an IllegalArgumentException
* will be thrown.
*
* @param listener The listener that was previously added with
* <code>addPrintListener</code>. Must not be
* <code>null</code>.
*
* @throws IllegalArgumentException if <code>listener</code> is not the
* currently registered print listener or
* is <code>null</code>.
*/
public void removePrintListener(final PrintListener listener)
throws IllegalArgumentException {
if (listener == null) {
throw new IllegalArgumentException("listener can not be null");
}
if (listener != m_printListener) {
throw new IllegalArgumentException(
"listener is not registered with this widget");
}
m_printListener = null;
}
/**
* Execute the {@link PrintListener} assigned to the link.
*
* @param state The current page state
*
* @return The base link after all {@link PrintListener} have been executed.
*/
protected BaseLink firePrintEvent(final PageState state) {
BaseLink l = this;
if (m_printListener != null) {
try {
l = (BaseLink) this.clone();
m_printListener.prepare(new PrintEvent(this, state, l));
} catch (CloneNotSupportedException e) {
l = this;
throw new UncheckedWrapperException(e);
}
}
return l;
}
/**
* Retrieves the label component used to display the Link. Typically a
* Label, but may be an other type, e.g. an Image, as well.
*
* @return Component used to display the Link.
*/
public final Component getChild() {
return m_child;
}
public void setChild(final Component child) {
Assert.isUnlocked(this);
m_child = child;
}
/**
* Use a GlobalizedMessage to be used to display the link. It's primary
* purpose is to hide the parent class method to prevent its usage because
* Labels and GlobalizedMessages are used here differently (a
* GlobalizedMessage is here not directly used as a Label by specifying it
* as an attribute, inside a Label component).
*
* @param message The text to show.
*/
@Override
public void setLabel(final GlobalizedMessage message) {
Assert.isUnlocked(this);
Label label = new Label(message);
setChild((Component) label);
}
/**
* Get the target of the link.
*
* @return The target URL of the link.
*/
public final String getTarget() {
return m_url;
}
public final void setTarget(final String url) {
Assert.isUnlocked(this);
m_url = url;
}
/**
* Sets the type of link this link represents.
*
* @param type the type of link
*/
protected void setTypeAttr(final String type) {
Assert.isUnlocked(this);
setAttribute(TYPE_ATTR, type);
}
/**
* Generate the URL for the link.
*
* @param state The current {@link PageState}.
* @param parent The parent element of the link.
*/
protected abstract void generateURL(final PageState state,
final Element parent);
/**
* Generates a DOM fragment:
*
* <pre>
* &lt;bebop:link href="..." type="..." %bebopAttr;/&gt;
* </pre>
*
* The {@code href} attribute contains the target the link should point to.
* The {@code type} attribute is used to give more fine grained control over
* which kind of link this element represents. The types are {@code link}
* for a {@code Link}, {@code control} for a {@link ControlLink}. There may
* be additional attributes depending on what type of link this link
* represents.
*
* @see ControlLink#generateXML
*
* @param state The current {@link PageState}.
* @param parent The XML element to attach the XML to.
*/
@Override
public void generateXML(final PageState state, final Element parent) {
if (isVisible(state)) {
BaseLink target = firePrintEvent(state);
Element link = parent.newChildElement("bebop:link", BEBOP_XML_NS);
target.generateURL(state, link);
target.exportConfirmAttributes(state, link);
//setup the link without javascript
target.setupNoJavascriptURL(state, link);
target.exportAttributes(link);
target.generateExtraXMLAttributes(state, link);
target.generateDescriptionXML(state, link);
target.getChild().generateXML(state, link);
}
}
/**
*
* @param state
* @param sUrl
*
* @return
*/
private String getAbsoluteUrl(final PageState state, final String sUrl) {
String sReturn = "";
if ((sUrl.indexOf(":") != -1) || sUrl.indexOf("/") == 0) {
//if sUrl contains a ":" or begins with a "/", then it is an absolute URL
sReturn = sUrl;
} else {
//otherwise, it is a relative URL, so we need to make it an absolute URL
//get the current URL
String sThisURL = "";
try {
sThisURL = state.stateAsURL();
} catch (java.io.IOException ioe) {
//ignore
}
//trim the current URL back to the last "/" character
int iIndex = sThisURL.lastIndexOf("/");
//if there is no "/" character, then assume we are at server root
if (iIndex == -1) {
sReturn = "/" + sUrl;
} else {
sReturn = sThisURL.substring(0, iIndex) + "/" + sUrl;
}
}
return sReturn;
}
/**
* Sets up no-JavaScript fallback HTML
*
* @param state The current {@link PageState}.
* @param link The link element.
*/
protected void setupNoJavascriptURL(final PageState state,
final Element link) {
String sURL = null;
if (m_sConfirmMsg.length() > 0
|| (m_confirmMsg != null && m_confirmMsg.localize().toString()
.length() > 0)) {
//if we want the confirm link, create the link
String sOkUrl = getAbsoluteUrl(state, link.getAttribute(HREF));
String sCancelUrl = null;
try {
sCancelUrl = state.stateAsURL();
} catch (java.io.IOException e) {
Assert.fail("Could not get current page state as URL");
}
if (m_sConfirmMsg.length() > 0) {
sURL = ConfirmPage.getConfirmUrl(m_sConfirmMsg, sOkUrl,
sCancelUrl);
} else if (m_confirmMsg != null) {
sURL = ConfirmPage.getConfirmUrl(m_confirmMsg.localize()
.toString(), sOkUrl, sCancelUrl);
}
} else {
//don't want confirm link--just no javascript link
if (m_noJavascriptURL == null) {
//get the generatedURL and make it the default noJavaScript link
sURL = link.getAttribute(HREF);
} else {
sURL = m_noJavascriptURL;
}
}
link.addAttribute(HREF_NO_JAVASCRIPT, sURL);
exportAttributes(link);
}
/**
* Adds type-specific XML attributes to the XML element representing this
* link. Subclasses should override this method if they introduce more
* attributes than the ones {@link #generateXML generateXML} produces by
* default.
*
* @param state The current request
* @param link The XML element representing this link
*/
protected void generateExtraXMLAttributes(final PageState state,
final Element link) {
}
/**
* Sets onClick event and <em>disables the javascript-based double-click
* protection for this link</em>. Not for confirmation messages; Should call
* setConfirmation for that.
*
* @param value The confirmation link. To not use the value
* {@code return confirm(} with this method.
*
* @see #setConfirmation
*/
public void setOnClick(final String value) {
//should not use this method to set confirmation messages--should
//use setConfirmation() instead, or else the javascript will break
if (value != null) {
Assert.isTrue(!value.toLowerCase().startsWith("return confirm("),
"Do not use setOnClick() to set confirmation messages. "
+ "Use setCofirmation() instead.");
}
setAttribute(ON_CLICK, value);
}
/**
* Forces the user to click through a confirmation dialog before this link
* is followed. The user is prompted with the specified message. If the user
* does not does not confirm, the link is not followed. The current
* implementation uses the JavaScript confirm function and the onClick
* attribute. If JavaScript is not enabled in the client browser, this
* method will redirect the browser to a Bebop confirmation page rather than
* use a JavaScript confirmation. Subsequent calls to setOnClick will undo
* the effect of this method.
*
* @param message the confirmation message presented to the user. This
* message cannot have an apostrophe or back slash.
*
* @deprecated Use setConfirmation(final GlobalizedMessage msg) instead
*/
public void setConfirmation(final String message) {
//make sure that the message doesn't have any apostrophe's
//or back slashes
if (Assert.isEnabled()) {
final boolean isGoodMessage = message.indexOf("'") == -1 && message
.indexOf("\\") == -1;
Assert.isTrue(isGoodMessage,
"confirmation message cannot contain apostrophe or back slash");
}
m_sConfirmMsg = message;
}
/**
* Set a GlobalizedMessage as confirmation message
*
* @param msg The text to show for confirming.
*/
public void setConfirmation(final GlobalizedMessage msg) {
m_confirmMsg = msg;
}
/**
* Generate XML output for confirmation links
*
* @param state PageState
* @param link Parent element
*/
private void exportConfirmAttributes(final PageState state,
final Element link) {
// If a confirmation message is set
if (m_sConfirmMsg.length() > 0 || m_confirmMsg != null) {
// then add the needed attributes to link
link.addAttribute("confirm", "confirm");
// If m_sConfirmMsg is not empty
if (m_sConfirmMsg.length() > 0) {
// then set the onclick attribute for the link with the static message
link.addAttribute(ON_CLICK, "return confirm(\\'" + m_sConfirmMsg
+ "\\');");
// else if m_configMsg is set
} else if (m_confirmMsg != null) {
//then set the onclick attribute for the link with a globalized message
link.addAttribute(ON_CLICK, "return confirm(\\'" + m_confirmMsg
.localize() + "\\');");
}
}
}
public final void setNoJavascriptTarget(final String sURL) {
Assert.isUnlocked(this);
m_noJavascriptURL = sURL;
}
public final String getNoJavascriptTarget() {
return m_noJavascriptURL;
}
}

View File

@ -1,52 +0,0 @@
/*
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.util.Assert;
/**
* The base page class for use with the PageFactory
* class. It sets two attributes on the XML tag for
* the bebop:page, namely <code>application</code>
* and <code>id</code>. The values for these two
* tags correspond to the parameters passed to the
* PageFactory.buildPage method.
* <p>
* This class is intended to be subclassed to provide
* the page infrastructure required by a project, for
* example, adding some navigation components.
* The SimplePage class provides a easy implementation
* whereby the navigation components can be specified
* in the enterprise.init file.
*/
public class BasePage extends Page {
public BasePage(String application,
Label title,
String id) {
super(title, new SimpleContainer());
Assert.exists(application, "application name");
setAttribute("application", application);
if (id != null) {
setAttribute("id", id);
}
}
}

View File

@ -1,324 +0,0 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.page.PageTransformer;
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.templating.PresentationManager;
import com.arsdigita.util.UncheckedWrapperException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.configuration.Configuration;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.configuration.Setting;
import java.util.stream.Collectors;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Configuration(
descBundle = "com.arsdigita.bebop.BebopConfig",
descKey = "description",
titleKey = "title"
)
public final class BebopConfig {
@Setting(
descKey = "presenterClassName.desc",
labelKey = "presenterClassName.label"
)
private String presenterClassName = PageTransformer.class.getName();
@Setting(
descKey = "basePageClassName.desc",
labelKey = "basePageClassName.label"
)
private String basePageClassName = "";
@Setting(
descKey = "tidyConfigFile.desc",
labelKey = "tidyConfigFile.label"
)
private String tidyConfigFile
= "com/arsdigita/bebop/parameters/tidy.properties";
@Setting(
descKey = "fancyErrors.desc",
labelKey = "fancyErrors.label"
)
private Boolean fancyErrors = false;
@Setting(
descKey = "dcpOnButtons.desc",
labelKey = "dcpOnButtons.label"
)
private Boolean dcpOnButtons = true;
@Setting(
descKey = "dcpOnLinks.desc",
labelKey = "dcpOnLinks.label"
)
private Boolean dcpOnLinks = false;
@Setting(
descKey = "treeSelectEnabled.desc",
labelKey = "treeSelectEnabled.label"
)
private Boolean treeSelectEnabled = false;
@Setting(
descKey = "dhtmlEditors.desc",
labelKey = "dhtmlEditors.label"
)
private Set<String> dhtmlEditors = new HashSet<>(
Arrays.asList(new String[]{BebopConstants.BEBOP_XINHAEDITOR,
BebopConstants.BEBOP_FCKEDITOR,
BebopConstants.BEBOP_DHTMLEDITOR,
BebopConstants.BEBOP_CCMEDITOR,
BebopConstants.BEBOP_TINYMCE_EDITOR}));
@Setting(
descKey = "defaultDhtmlEditor.desc",
labelKey = "defaultDhtmlEditor.label"
)
private String defaultDhtmlEditor = BebopConstants.BEBOP_TINYMCE_EDITOR;
@Setting(
descKey = "dhtmlEditorSrcFile.desc",
labelKey = "dhtmlEditorSrcFile.label"
)
// private String dhtmlEditorSrcFile = "/ccm-editor/ccm-editor-loader.js";
private String dhtmlEditorSrcFile = "/webjars/tinymce/4.8.2/tinymce.js";
@Setting(
descKey = "showClassName.desc",
labelKey = "showClassName.label"
)
private Boolean showClassName = false;
public static BebopConfig getConfig() {
final ConfigurationManager confManager = CdiUtil.createCdiUtil()
.findBean(ConfigurationManager.class);
return confManager.findConfiguration(BebopConfig.class);
}
public String getPresenterClassName() {
return presenterClassName;
}
@SuppressWarnings("unchecked")
public Class<PresentationManager> getPresenterClass() {
try {
return (Class<PresentationManager>) Class.
forName(presenterClassName);
} catch (ClassNotFoundException ex) {
throw new UncheckedWrapperException(ex);
}
}
public void setPresenterClassName(final String presenterClassName) {
this.presenterClassName = presenterClassName;
}
public void setPresenterClass(
final Class<PresentationManager> presenterClass) {
setPresenterClassName(presenterClass.getName());
}
public String getBasePageClassName() {
return basePageClassName;
}
@SuppressWarnings("unchecked")
public Class<BasePage> getBasePageClass() {
try {
return (Class<BasePage>) Class.forName(basePageClassName);
} catch (ClassNotFoundException ex) {
throw new UncheckedWrapperException(ex);
}
}
public void setBasePageClassName(final String basePageClassName) {
this.basePageClassName = basePageClassName;
}
public void setBasePageClass(final Class<BasePage> basePageClass) {
setBasePageClassName(basePageClass.getName());
}
public String getTidyConfigFile() {
return tidyConfigFile;
}
public void setTidyConfigFile(final String tidyConfigFile) {
this.tidyConfigFile = tidyConfigFile;
}
public Boolean getFancyErrors() {
return fancyErrors;
}
public void setFancyErrors(final Boolean fancyErrors) {
this.fancyErrors = fancyErrors;
}
public Boolean getDcpOnButtons() {
return dcpOnButtons;
}
public void setDcpOnButtons(final Boolean dcpOnButtons) {
this.dcpOnButtons = dcpOnButtons;
}
public Boolean getDcpOnLinks() {
return dcpOnLinks;
}
public void setDcpOnLinks(final Boolean dcpOnLinks) {
this.dcpOnLinks = dcpOnLinks;
}
public Boolean isTreeSelectEnabled() {
return treeSelectEnabled;
}
public void setTreeSelectEnabled(final Boolean treeSelectEnabled) {
this.treeSelectEnabled = treeSelectEnabled;
}
public Set<String> getDhtmlEditors() {
return new HashSet<>(dhtmlEditors);
}
public void setDhtmlEditors(final Set<String> dhtmlEditors) {
this.dhtmlEditors = dhtmlEditors;
}
public String getDefaultDhtmlEditor() {
return defaultDhtmlEditor;
}
public void setDefaultDhtmlEditor(final String defaultDhtmlEditor) {
this.defaultDhtmlEditor = defaultDhtmlEditor;
}
public String getDhtmlEditorSrcFile() {
return dhtmlEditorSrcFile;
}
public void setDhtmlEditorSrcFile(final String dhtmlEditorSrcFile) {
this.dhtmlEditorSrcFile = dhtmlEditorSrcFile;
}
public Boolean getShowClassName() {
return showClassName;
}
public void setShowClassName(final Boolean showClassName) {
this.showClassName = showClassName;
}
@Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + Objects.hashCode(tidyConfigFile);
hash = 89 * hash + Objects.hashCode(fancyErrors);
hash = 89 * hash + Objects.hashCode(dcpOnButtons);
hash = 89 * hash + Objects.hashCode(dcpOnLinks);
hash = 89 * hash + Objects.hashCode(treeSelectEnabled);
hash = 89 * hash + Objects.hashCode(dhtmlEditors);
hash = 89 * hash + Objects.hashCode(defaultDhtmlEditor);
hash = 89 * hash + Objects.hashCode(dhtmlEditorSrcFile);
hash = 89 * hash + Objects.hashCode(showClassName);
return hash;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof BebopConfig)) {
return false;
}
final BebopConfig other = (BebopConfig) obj;
if (!Objects.equals(tidyConfigFile, other.getTidyConfigFile())) {
return false;
}
if (!Objects.equals(defaultDhtmlEditor, other.getDefaultDhtmlEditor())) {
return false;
}
if (!Objects.equals(dhtmlEditorSrcFile, other.getDhtmlEditorSrcFile())) {
return false;
}
if (!Objects.equals(fancyErrors, other.getFancyErrors())) {
return false;
}
if (!Objects.equals(dcpOnButtons, other.getDcpOnButtons())) {
return false;
}
if (!Objects.equals(dcpOnLinks, other.getDcpOnLinks())) {
return false;
}
if (!Objects.equals(treeSelectEnabled, other.isTreeSelectEnabled())) {
return false;
}
if (!Objects.equals(dhtmlEditors, other.getDhtmlEditors())) {
return false;
}
return Objects.equals(showClassName, other.getShowClassName());
}
@Override
public String toString() {
return String.format(
"%s{ "
+ "tidyConfigFile = %s, "
+ "fancyErrors = %b, "
+ "dcpOnButtons = %b, "
+ "dcpOnLinks = %b, "
+ "treeSelectEnabled = %b, "
+ "dhtmlEditors = { %s }, "
+ "defaultDhtmlEditor = %s, "
+ "dhtmlEditorSrcFile = %s, "
+ "showClassName = %b"
+ " }",
super.toString(),
tidyConfigFile,
fancyErrors,
dcpOnButtons,
dcpOnLinks,
treeSelectEnabled,
dhtmlEditors.stream().collect(Collectors.joining(", ")),
defaultDhtmlEditor,
dhtmlEditorSrcFile,
showClassName);
}
}

View File

@ -1,168 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import java.util.Iterator;
import com.arsdigita.xml.Element;
import com.arsdigita.bebop.form.Hidden;
// This interface contains the XML element name of this class
// in a constant which is used when generating XML
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.bebop.util.PanelConstraints;
/**
* A container that prints its components in one row, either horizontally or
* vertically.
*
* @author David Lutterkort
* @version $Id: BoxPanel.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class BoxPanel extends SimpleContainer
implements BebopConstants, PanelConstraints {
/** Specifies that components should be laid out left to right. */
public final static int HORIZONTAL = 1;
/** Specifies that components should be laid out top to bottom. */
public final static int VERTICAL = 2;
/** XML attribute for width */
private static final String WIDTH_ATTR = "width";
/** XML attribute wether to draw a border. */
private static final String BORDER_ATTR = "border";
/** Property to whether to draw a HORIZONTAL or VERTICAL box panel. */
private int m_axis;
/** Property to store whether to to center alignment. */
private boolean m_centering;
/**
* Constructor, creates a box panel that lays out its components from
* top to bottom. The components are not centered.
*/
public BoxPanel() {
this(VERTICAL);
}
/**
* Constructor, creates a box panel that lays out its components in the given
* direction. The components are not centered.
*
* @param axis the axis to use to lay out the components
*/
public BoxPanel(int axis) {
this(axis, false);
}
/**
* Creates a box panel that lays out its components in the given
* direction and centers them if that is specified.
*
* @param axis the axis to use to lay out the components
* @param centering <code>true</code> if the layout should be centered
*/
public BoxPanel(int axis, boolean centering) {
m_axis = axis;
m_centering = centering;
}
// Instance methods
/**
* Sets the width attribute of the box panel. The given width should be in
* a form that is legal as the <code>width</code> attribute of an HTML
* <code>table</code> element.
*
* @param w the width of the box panel
*/
public void setWidth(String w) {
setAttribute(WIDTH_ATTR, w);
}
// /**
// * Sets whether a border should be drawn.
// *
// * @param isBorder <code>true</code> if a border should be drawn
// * @deprecated Use {@link #setBorder(int border)} instead.
// */
// public void setBorder(boolean isBorder) {
// if (isBorder) {
// setAttribute(BORDER_ATTR, "1");
// } else {
// setAttribute(BORDER_ATTR, "0");
// }
// }
/**
*
* Sets the width of the border to draw around the components. This value
* will be used for the <code>border</code> attribute in an HTML
* <code>table</code> element.
*
* @param border the width of the border
*/
public void setBorder(int border) {
setAttribute(BORDER_ATTR, String.valueOf(border));
}
/**
* Adds nodes for the panel and its child components to be rendered,
* usually in a table. Any hidden widgets directly contained in the box
* panel are added directly to <code>parent</code> and are not in any
* of the cells that the box panel generates.
*
* <p>Generates DOM fragment:
* <p><code>&lt;bebop:boxPanel [width=...] border=... center... axis...>
* &lt;bebop:cell> cell contents &lt;/bebop:cell>
* &lt;/bebop:boxPanel></code>
*
* @param parent
*/
@Override
public void generateXML(PageState state, Element parent) {
if (isVisible(state)) {
Element panel = parent.newChildElement(BEBOP_BOXPANEL, BEBOP_XML_NS);
// or: rowPanel/columPanel?
panel.addAttribute("center", String.valueOf(m_centering));
panel.addAttribute("axis", String.valueOf(m_axis));
exportAttributes(panel);
for (Iterator i = children(); i.hasNext();) {
Component c = (Component) i.next();
if (c.isVisible(state)) {
if (c instanceof Hidden) {
c.generateXML(state, parent);
} else {
Element cell = panel.newChildElement(BEBOP_CELL, BEBOP_XML_NS);
c.generateXML(state, cell);
}
}
}
}
}
}

View File

@ -1,574 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.form.Hidden;
import com.arsdigita.bebop.util.Attributes;
import com.arsdigita.bebop.util.PanelConstraints;
import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* A container that prints its components in a table. Each child is printed
* in its own table cell. The number of columns can be specified in the
* constructor. The components are put into the table in the order in which
* they were added to the <code>ColumnPanel</code> by filling the table one row
* at a time (filling each row from left to right), from the top of the table
* to the bottom.
*
* <p> The position of the component within the cell can be influenced with the
* following constraints.
* <TABLE border=0>
* <tr>
* <TD nowrap valign="top">Horizontal alignment</TD>
* <Td valign="top">Use <code>LEFT</code>, <code>CENTER</code>, or
* <code>RIGHT</code>.</td></tr>
* <tr>
* <td nowrap valign="top">Vertical alignment</td>
* <td valign="top">Use <code>TOP</code>, <code>MIDDLE</code>, or
* <code>BOTTOM</code>.</td></tr>
* <tr>
* <td nowrap valign="top">Full width</td>
* <td valign="top">Use <code>FULL_WIDTH</code> to instruct the panel to
* put the component in a row by itself, spanning the full width of the
* table.</td></tr>
* <tr>
* <td nowrap valign="top">Inserting children</td>
* <td valign="top">Use <code>INSERT</code> to instruct the panel to
* insert the corresponding component, assuming that it will also be
* laid out by a <code>ColumnPanel</code> with the same number of
* columns.</td></tr>
* </TABLE>
*
* <p>Constraints can be combined by OR-ing them together. For example, to print
* a component in a row of its own, left-aligned, at the bottom of its cell,
* use the constraint <code>FULL_WIDTH | LEFT | BOTTOM</code>.
*
* <p> Using the <code>INSERT</code> constraint fuses the current ColumnPanel
* with the panel of the child to which the constraint is applied. For example,
* consider a {@link Form} that is to have a 2-column format with labels in the
* left column and widgets in the right column. If a {@link FormSection} is
* added to the form, it should be included seamlessly into the parent form.
* To do this, set the <code>INSERT</code> constraint when the {@link
* FormSection} is added to the <code>ColumnPanel</code> of the {@link Form}. At
* the same time, tell the <code>ColumnPanel</code> used to lay out the {@link
* FormSection} that it is to be inserted into another panel.
*
* <P>The following pseudo-code illustrates the example. (It assumes that
* Form and FormSection are decorators of the ColumnPanel.)
*
* <pre style="background: #cccccc">
*
* Form form = new Form(new ColumnPanel(2));
* FormSection sec = new FormSection(new ColumnPanel(2, true));
*
* sec.add(new Label("Basic Item Metadata"), ColumnPanel.FULL_WIDTH);
* sec.add(new Label("Title:"), ColumnPanel.RIGHT);
* sec.add(new Text("title"));
*
* form.add(sec, ColumnPanel.INSERT);
* </pre>
*
* @author David Lutterkort
* @version $Id: ColumnPanel.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class ColumnPanel extends SimpleContainer
implements PanelConstraints {
/** An empty constraint corresponding to the default */
private static final Constraint DEFAULT_CONSTRAINT = new Constraint();
/** The number of columns in the panel */
private int m_nCols;
/** Explicitly registered constraints for child components. Maps
* <code>Components</code>s to <code>Constraints</code> */
private Map m_constraints;
/** Is this panel inserted in another one ? If so, do not produce
* &lt;table&gt; tags */
private boolean m_inserted;
/** Border attributes */
private Attributes m_border;
private Attributes m_padFrame;
private Attributes m_pad;
private String[] m_columnWidth;
// Instance methods
/**
* Creates a table panel with the specified number of columns.
*
* @param nCols number of columns in the panel
*/
public ColumnPanel(int nCols) {
this(nCols, false);
makeBorder();
makePadFrame();
makePad();
}
/**
* Creates a table panel with the specified number of columns that will
* be printed as a direct child of a <code>ColumnPanel</code>
* with the same number of columns.
* @see #setInserted
*
* @param nCols number of columns in the panel
* @param inserted <code>true</code> if this panel
* is to be printed as a direct child of a
* <code>ColumnPanel</code> with the same number of
* columns
*/
public ColumnPanel(int nCols, boolean inserted) {
m_nCols = nCols;
setInserted(inserted);
m_constraints = new HashMap();
m_columnWidth=new String[nCols];
}
/**
* Adds a component, specifying its constraints.
*
* @param c the component to add
* @param constraints the constraints for this component
*/
@Override
public void add(Component c, int constraints) {
super.add(c);
setConstraint(c, constraints);
}
/**
* Sets whether this panel will be printed inside a
* <code>ColumnPanel</code> with the same number of columns. If
* <code>inserted</code> is true, no &lt;table&gt; tags will be produced
* to enclose the child components.
* @param inserted <code>true</code> if this panel is to be printed
* inside a <code>ColumnPanel</code> with the same number of columns
*/
public void setInserted(boolean inserted) {
Assert.isUnlocked(this);
m_inserted = inserted;
}
/**
* Determines whether this panel is to be inserted into another panel.
* @return <code>true</code> if this panel is to be inserted
* into another panel; <code>false</code> otherwise.
*
* @see #setInserted
*/
public final boolean isInserted() {
return m_inserted;
}
/**
* Returns the number of columns for this ColumnPanel
* @return the number of columns
*
*/
public final int getNumCols() {
return m_nCols;
}
/**
* Adds child components as a subtree under table-style nodes. If any of the
* direct children are hidden form widgets, they are added directly to
* <code>parent</code> rather than included in any of the
* <code>cell</code> elements of the panel.
*
* <p>Generates a DOM fragment:
* <p><code><pre>
* &lt;bebop:pad>
* [&lt;bebop:padFrame>]
* [&lt;bebop:border>]
* &lt;bebop:panelRow>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* ...
* &lt;/bebop:panelRow>
* &lt;bebop:panelRow>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* ...
* &lt;/bebop:panelRow>
* [&lt;/bebop:border>]
* [&lt;/bebop:padFrame>]
* &lt;/bebop:boxPanel></pre></code>
* @param state the current page state
* @param parent the parent element for these child components
*/
@Override
public void generateXML(PageState state, Element parent) {
if ( isVisible(state) ) {
Element panel = parent.newChildElement("bebop:columnPanel", BEBOP_XML_NS);
exportAttributes(panel);
// parent.addContent(panel);
generateChildren(state, parent, generateTopNodes(panel));
}
}
// Border attributes
private void makeBorder() {
if ( m_border == null ) {
m_border = new Attributes();
m_border.setAttribute("cellspacing", "0");
m_border.setAttribute("cellpadding", "4");
m_border.setAttribute("border", "0");
m_border.setAttribute("width", "100%");
}
}
/**
*
*
* @param c
*/
public void setBorderColor(String c) {
makeBorder();
m_border.setAttribute("bgcolor", c);
}
/**
*
*
* @param w
*/
public void setBorderWidth(String w) {
makeBorder();
m_border.setAttribute("cellpadding", w);
}
public void setColumnWidth(int col, String width) {
m_columnWidth[col-1]=width;
}
/**
*
*
* @param b
*/
public void setBorder(boolean b) {
if (b) {
makeBorder();
} else {
m_border = null;
}
}
// Pad and Padframe attributes
private void makePadFrame() {
if (m_padFrame == null) {
m_padFrame = new Attributes();
m_padFrame.setAttribute("cellspacing", "0");
m_padFrame.setAttribute("cellpadding", "6");
m_padFrame.setAttribute("border", "0");
m_padFrame.setAttribute("width", "100%");
}
}
/**
*
*
*/
private void makePad() {
if ( m_pad == null ) {
m_pad = new Attributes();
m_pad.setAttribute("cellspacing", "0");
m_pad.setAttribute("cellpadding", "2");
m_pad.setAttribute("border", "0");
m_pad.setAttribute("width", "100%");
}
}
/**
*
*
* @param c
*/
public void setPadColor(String c) {
makePadFrame();
makePad();
m_padFrame.setAttribute("bgcolor", c);
m_pad.setAttribute("bgcolor", c);
}
/**
*
*
* @param w
*/
public void setWidth(String w) {
makePadFrame();
m_padFrame.setAttribute("width", w);
}
/**
*
*
* @param w
*/
public void setPadFrameWidth(String w) {
makePadFrame();
m_padFrame.setAttribute("cellpadding", w);
}
/**
*
*
* @param border
*/
public void setPadBorder(boolean border) {
makePad();
if(border) {
m_pad.setAttribute("border", "1");
} else {
m_pad.setAttribute("border", "0");
}
}
/**
*
*
* @param padding
*/
public void setPadCellPadding(String padding) {
makePad();
m_pad.setAttribute("cellpadding", padding);
}
/**
* add top tags (will translate to opening/closing),
* including display styles
*/
private Element generateTopNodes(Element parent) {
// FIXME: set background color, border effects, cell spacing etc.
if (isInserted()) {
return parent;
}
String l_class = getClassAttr();
if (m_border != null) {
Element border = parent.newChildElement("bebop:border",BEBOP_XML_NS);
if (l_class != null) {
m_border.setAttribute("class", l_class);
}
m_border.exportAttributes(border);
// parent.addContent(border);
parent=border; // nest the rest inside border
}
if ( m_padFrame != null ) {
Element padFrame = parent.newChildElement("bebop:padFrame", BEBOP_XML_NS);
if (l_class != null) {
m_padFrame.setAttribute("class", l_class);
}
m_padFrame.exportAttributes(padFrame);
// parent.addContent(padFrame);
parent=padFrame; // nest the rest in padFrame
}
Element pad = parent.newChildElement("bebop:pad", BEBOP_XML_NS);
if (l_class != null) {
m_pad.setAttribute("class", l_class);
}
m_pad.exportAttributes(pad);
// parent.addContent(pad);
return pad;
}
/**
* Lay out the child components using constraints registered for them,
* generating a DOM tree and extending another.
*
* @param state represents the state of the current request
* @param hiddenParent the element to which hiddens are added
* @param parent the element to which ordinary rows and cells are added
*/
private void generateChildren(PageState state, Element hiddenParent,
Element parent) {
// Count the number of components printed in the current row
int rowLen = m_nCols + 1; // Force generation of first row
Element row = null;
Element cell = null;
for (Iterator i = children(); i.hasNext(); ) {
Component c = (Component) i.next();
if ( c.isVisible(state) ) {
if ( c instanceof Hidden ) {
c.generateXML(state, hiddenParent);
} else {
if ( isInsert(c) ) {
c.generateXML(state, parent);
rowLen = m_nCols + 1; // Force generation of new row
} else {
if ( rowLen >= m_nCols || isFullWidth(c)) {
rowLen = 0;
row = parent.newChildElement("bebop:panelRow", BEBOP_XML_NS);
// parent.addContent(row);
}
cell = row.newChildElement("bebop:cell", BEBOP_XML_NS);
// row.addContent(cell);
if ( m_columnWidth[rowLen] != null ) {
cell.addAttribute("width", m_columnWidth[rowLen]);
}
getConstraint(c).exportAttributes(cell, m_nCols);
c.generateXML(state, cell);
rowLen++;
if ( isFullWidth(c) ) {
// Force a new row if c was full width
rowLen = m_nCols + 1;
}
}
}
}
}
}
/**
* Sets the constraint for one child component.
* @param c the child component
* @param constraints the constraints to add
*/
public void setConstraint(Component c, int constraints) {
Assert.isUnlocked(this);
m_constraints.put(c, new Constraint(constraints));
}
/**
* Get the constraint object for a component. If no constraints have been
* set explicitly, return a default constraint object.
*
* @post return != null
*/
private Constraint getConstraint(Component c) {
Constraint result = (Constraint) m_constraints.get(c);
if ( result == null ) {
return DEFAULT_CONSTRAINT;
} else {
return result;
}
}
private boolean isInsert(Component c) {
return getConstraint(c).isInsert();
}
private boolean isFullWidth(Component c) {
return getConstraint(c).isFullWidth();
}
// Inner class(es)
/**
* Represent the constraints for one child component
*/
private static class Constraint {
private boolean m_fullWidth;
private boolean m_insert;
private String m_alignment; // for print
private String m_halign; // for generateXML
private String m_valign; // for generateXML
public Constraint() {
this(0);
}
public Constraint(int constraints) {
StringBuilder s = new StringBuilder();
if ( (constraints & (LEFT|CENTER|RIGHT)) != 0 ) {
s.append(" align=\"");
if ( (constraints & LEFT) != 0) {
s.append(m_halign = "left");
} else if ( (constraints & CENTER) != 0) {
s.append(m_halign = "center");
} else if ( (constraints & RIGHT) != 0) {
s.append(m_halign = "right");
}
s.append("\" ");
} else {
m_halign = null;
}
if ( (constraints & (TOP|MIDDLE|BOTTOM)) != 0 ) {
s.append(" valign=\"");
if ( (constraints & TOP) != 0) {
s.append(m_valign = "top");
} else if ( (constraints & MIDDLE) != 0) {
s.append(m_valign = "middle");
} else if ( (constraints & BOTTOM) != 0) {
s.append(m_valign = "bottom");
}
s.append("\" ");
} else {
m_valign = null;
}
m_alignment = s.toString();
m_fullWidth = (constraints & FULL_WIDTH) != 0;
m_insert = (constraints & INSERT) != 0;
}
public final boolean isFullWidth() {
return m_fullWidth;
}
public final boolean isInsert() {
return m_insert;
}
public final String getAlignment() {
return m_alignment;
}
public final String getHAlign() {
return m_halign;
}
public final String getVAlign() {
return m_valign;
}
public void exportAttributes(Element cell, int nCols) {
String halign = getHAlign();
String valign = getVAlign();
if (halign != null) {
cell.addAttribute("align" , halign);
}
if (valign != null) {
cell.addAttribute("valign", valign);
}
if ( isFullWidth() ) {
cell.addAttribute("colspan", Integer.toString(nCols));
}
}
}
}

View File

@ -1,64 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.util.Assert;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
// Stacktraces is a support tool to use in a specifically difficult development
// situation. It is abundant in production and for normal development work and
// it provved to have funny side effects in a production environment. So it is
// commented out here but kept for further references.
// import com.arsdigita.developersupport.StackTraces;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Completable.
*
* @author <a href="mailto:rhs@mit.edu">rhs@mit.edu</a>
**/
public abstract class Completable implements Component {
private ArrayList m_completionListeners = new ArrayList();
public Completable() {
// See note above!
// if ( s_log.isDebugEnabled() ) {
// StackTraces.captureStackTrace(this);
// }
}
public void addCompletionListener(ActionListener listener) {
Assert.isUnlocked(this);
m_completionListeners.add(listener);
}
protected void fireCompletionEvent(PageState ps) {
ActionEvent evt = new ActionEvent(this, ps);
for (Iterator it = m_completionListeners.iterator(); it.hasNext(); ) {
ActionListener listener = (ActionListener) it.next();
listener.actionPerformed(evt);
}
}
}

View File

@ -1,387 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import java.util.Iterator;
import com.arsdigita.util.Lockable;
import com.arsdigita.xml.Element;
/**
* The common interface implemented by all Bebop components.
*
* During its lifetime, a component receives the following calls
* from the containing page.
*
* <ul>
* <li> During initialization/creation of the containing page:
* <ul>
* <li> {@link #register(Page)} is called to register
* state parameters that need to be preserved between requests to
* the same page.
* </li>
* <li> {@link #register(Form, FormModel)} is called if
* the component is contained
* in a {@link Form} or {@link FormSection}. Typically, only form
* widgets like text controls have parameters that need to be
* registered with the <code>FormSection</code>.
* </li>
* <li> {@link Lockable#lock lock} is called to lock the component and
* inform it that no further structural modifications will be
* made.
* </li>
* </ul>
* </li>
* <li> For each request made to the containing page:
* <ul>
* <li> If the request originated from
* this component, {@link #respond(PageState) respond} is called.
* </li>
* <li> To produce output, {@link #generateXML(PageState, Element) generateXML} is
* called to produce XML output that will be transformed by the
* templating system.
* </li>
* </ul>
* </li>
* </ul>
*
*
* <h4><a name="visibility">Visibility</a></h4>
*
* <p>A component can be either <i>visible</i> or
* <i>invisible</i>. Invisible components do not produce any output and
* containers should be careful to completely hide their presence. The
* visibility of a component can be influenced in a number of ways:
* <UL>
* <LI>When a
* component is first added to the hierarchy of a {@link Page}, it is
* visible.</LI>
* <LI> A component's default (request-independent) visibility can be changed
* with a call to {@link Page#setVisibleDefault
* Page.setVisibleDefault} during setup of the page.</LI>
* <LI>A component
* can be made visible or invisible during the serving of a request with a
* call to {@link #setVisible setVisible}.</LI>
* </UL>
* <p> The {@link Page} makes sure that the visibility of components is
* preserved across repeated requests to the same page.
*
* <h4><a name="standard">Standard Attributes</a></h4>
* <p> Each component supports a few standard attributes that are copied
* through to the output when producing either HTML or XML
* output. These attributes are not used internally in any way, and setting
* them is entirely optional.
*
* <p> The standard attributes appear in the output as attributes in
* the element generated from this component. They correspond directly to
* properties with setters and getters. The standard attributes are as folows.
* <center><table cellspacing=5 cellpadding=2 border=0>
* <tr>
* <th>Attribute</th> <th>Java property</th> <th>Purpose</th>
* </tr>
* <tr>
* <td valign='top'><tt>id</tt></td>
* <td valign='top'>
* <tt>{@link #getIdAttr getIdAttr}/{@link #setIdAttr setIdAttr}</tt>
* </td>
* <td>Use to uniquely identify a component within the page. Uniqueness is
* not enforced. The <tt>id</tt> attribute allows stylesheet designers to
* access individual components.</td>
* </tr>
* <tr>
* <td valign='top'><tt>class</tt></td>
* <td valign='top'><tt>{@link #getClassAttr()}/{@link
* #setClassAttr(String)}</tt></td>
*
* <td>Use as the generic name for a
* component. For example, if you have a UserInfoDisplay
* component, the class attribute can be used to name the
* component "UserInfoDisplay" so that a generic template rule
* can style all UserInfoDisplay components.</td>
*
* </tr>
* <tr>
* <td valign='top'><tt>style</tt></td>
* <td valign='top'><tt>{@link #getStyleAttr getStyleAttr}/{@link
* #setStyleAttr setStyleAttr}</tt></td>
* <td>Use to add CSS style to an individual element.</td>
* </tr>
*
* </table></center>
*
* <h4><a name="caveat">Caveat: Race Conditions</a></h4>
* <p>
* When extending any <code>Component</code>, honor the
* <em>Lockable</em> contract indicated by <code>extends {@link
* com.arsdigita.util.Lockable}</code>. Beware that member variables
* are not inherently threadsafe, because you may be circumventing
* the contract. For variables that might be different for each
* request, use {@link RequestLocal}. If you must add member
* variables in the derived class, as a minimum be sure to safeguard
* any write access to instance variables with {@link
* com.arsdigita.util.Assert#assertNotLocked}.
* </p>
* @author David Lutterkort
* @author Stanislav Freidin
* @author Rory Solomon
*
* @version $Id$
*/
public interface Component extends Lockable {
/**
* The XML namespace used by all the Bebop components.
*/
String BEBOP_XML_NS =
"http://www.arsdigita.com/bebop/1.0";
/**
* The name for the class attribute.
* @see #setClassAttr(String)
* @see <a href="Component#standard">Standard Attributes</a>
*/
String CLASS = "class";
/**
* The name for the style attribute.
* @see #setStyleAttr(String)
* @see <a href="Component#standard">Standard Attributes</a>
*/
String STYLE = "style";
/**
* The name for the ID attribute.
* @see #setIdAttr
* @see <a href="Component#standard">Standard Attributes</a>
*/
String ID = "id";
// HTML 4 event names
/**
* The onClick event.
*/
String ON_CLICK = "onclick";
/**
* <p>Adds a DOM subtree representing this component under the given
* parent node. Uses the request values stored in <code>state</code>.</p>
*
* @param state represents the current request
* @param parent the node under which the DOM subtree should be added
*
* @pre state != null
* @pre parent != null
*/
void generateXML(PageState state, Element parent);
/**
* <p>Responds to the request. This method is only called if the request
* was made from a link or form that the component put on the page in the
* {@link PageState#stateAsURL} previous request.</p>
*
* <p>No output should be generated on the HTTP response. The component
* can store intermediate results in the <code>state</code> by calling
* {@link PageState#setAttribute setAttribute}.</p>
*
* <p> This method is called before any output is printed to the HTTP
* response so that the component can forward to a different page and
* thereby commit the response.</p>
*
* @param state represents the current request
*
* @pre state != null
*/
void respond(PageState state)
throws javax.servlet.ServletException;
/**
* Returns an iterator over the children of this component. If the
* component has no children, returns an empty (not
* <code>null</code>) iterator.
*
* @return an iterator over the children of this component.
*
* @post return != null
*/
Iterator children();
/**
* Registers state parameters for the page with its model.
*
* A simple component with a state parameter <code>param</code> would do
* the following in the body of this method:
* <pre>
* p.addComponent(this);
* p.addComponentStateParam(this, param);
* </pre>
*
* You should override this method to set the default visibility
* of your component:
*
* <pre>
* public void register(Page p) {
* super.register(p);
* p.setVisibleDefault(childNotInitiallyShown,false);
* p.setVisibleDefault(anotherChild, false);
* }
* </pre>
*
* Always call <code>super.register</code> when you override
* <code>register</code>. Otherwise your component may
* malfunction and produce errors like "Widget ... isn't
* associated with any Form"
*
* @param p
* @pre p != null
*/
void register(Page p);
/**
* Registers form parameters with the form model for this
* form. This method is only important for {@link FormSection form
* sections} and {@link com.arsdigita.bebop.form.Widget widgets}
* (components that have a connection to an HTML form). Other
* components can implement it as a no-op.
*
* @param f
* @param m
* @pre f != null
* @pre m != null
*/
void register(Form f, FormModel m);
/* Properties that will get copied straight to the output,
both in HTML and in XML
*/
/**
* Gets the class attribute.
*
* @return the class attribute.
*
* @see #setClassAttr(String)
* @see <a href="Component#standard">Standard Attributes</a>
*/
String getClassAttr();
/**
* Sets the class attribute.
* @param theClass a valid <a
* href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Name">XML name</a>
* @see <a href="Component#standard">Standard Attributes</a>
* @see #getClassAttr
*/
void setClassAttr(String theClass);
/**
* Gets the style attribute.
*
* @return the style attribute.
*
* @see #setStyleAttr
* @see <a href="Component#standard">Standard Attributes</a>
*/
String getStyleAttr();
/**
* Sets the style attribute. <code>style</code> should be a valid CSS
* style, because its value will be copied verbatim to the output and
* appear as a <tt>style</tt> attribute in the top level XML or HTML
* output element.
*
* @param style a valid CSS style description for use in the
* <tt>style</tt> attribute of an HTML tag
* @see <a href="Component#standard">Standard Attributes</a>
*/
void setStyleAttr(String style);
/**
* Gets the <tt>id</tt> attribute.
*
* @return the id attribute.
*
* @see <a href="Component#standard">Standard Attributes</a>
* @see #setIdAttr(String id)
*/
String getIdAttr();
/**
* Sets the <tt>id</tt> attribute. <code>id</code>
* should be an <a
* href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Name">XML name</a>
* that is unique within the {@link Page Page} in which this component is
* contained. The value of <code>id</code> is copied literally to the
* output and not used for internal processing.
*
* @param id a valid XML identifier
* @see <a href="Component#standard">Standard Attributes</a>
*/
void setIdAttr(String id);
/**
* Supplies a key for making parameter names unique. To be used
* instead of the component's index (see <a
* href="PageModel#componentPrefix">Component Prefix</a>).
* To avoid collision with indexOf, it
* should (1) be a legal fragment of a cgi parameter, (2) differ from "g",
* and (3) not start with a digit.
*
* @param key
* @return
*/
Component setKey(String key);
/**
* Retrieves the programmer-supplied key. Normally, there is no
* such key and the method returns null.
*
* @return the programmer-supplied key.
*/
String getKey();
/**
* Determines whether the component is visible in the request
* represented by <code>state</code>.
* @see #setVisible setVisible
* @see <a href="Component.html#visibility">Description of Visibility
* above</a>
*
*
* @param state represents the current request
* @return <code>true</code> if the component is visible; <code>false</code>
* otherwise.
* @pre state != null
*/
boolean isVisible(PageState state);
/**
* Changes the visibility of the component. The component will keep the
* visibility that is set with this method in subsequent requests to this page.
*
* @param state represents the current request
* @param v <code>true</code> if the component should be visible
* @pre state != null
* @see <a href="Component.html#visibility">Description of Visibility
* above</a>
*/
void setVisible(PageState state, boolean v);
}

View File

@ -1,68 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
/**
* Encapsulates the selection of a single object from many
* possibilities. Similar to {@link SingleSelectionModel SingleSelectionModel},
* but ties a component to the selection.
*
* <p> A call to the {@link #getComponent getComponent} method returns a
* component that can be used to display the current selection.
*
* @author David Lutterkort
* @author Stanislav Freidin
* @param <T>
*/
public interface ComponentSelectionModel<T> extends SingleSelectionModel<T> {
/**
* Returns the component that should be used to output the currently
* selected element.
*
* @param state the state of the current request
* @return the component used to output the selected element.
*/
Component getComponent(PageState state);
/**
* Return the selected object. The concrete type of the returned object
* depends on the implementation of the model.
*
* @param state represents the state of the current request
* @return the selected object
*/
//Object getElement(PageState state);
/**
* Return an iterator over all the components that can possibly be used
* in rendering selected objects. If one component may be used to render
* various objects, for example for displaying detail information about
* each of a number of objects of the same type, the component needs to
* occur only once in the iterator.
*
* @return an iterator of components listing all the components that can
* may be used in displaying selected objects
*/
//Iterator components();
}

View File

@ -1,198 +0,0 @@
/*
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.PrintEvent;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.web.ParameterMap;
import com.arsdigita.web.RedirectSignal;
import com.arsdigita.web.URL;
/**
* A Bebop Confirmation Page which should be mounted at ConfirmPage.CONFIRM_URL by the BebopMapDispatcher.
* This page takes three URL parameters:
* <ul>
* <li>A confirmation message with variable name ConfirmPage.CONFIRM_MSG_VAR
* <li>An OK URL with variable name ConfirmPage.OK_URL_VAR
* <li>A Cancel URL with variable name ConfirmPage.CANCEL_URL_VAR
* </ul>
* The page displays a form asking the confirmation message passed in. If the user hits <i>OK</i>,
* Then the page redirects to the OK URL. Otherwise, if the user hits <i>Cancel<i/>,
* The page redirects to the Cancel URL.
* @author Bryan Che
*/
public class ConfirmPage extends Page {
private StringParameter m_ConfirmMsgParam;
private StringParameter m_OkUrlParam;
private StringParameter m_CancelUrlParam;
private RequestLocal m_ConfirmMsgRL;
private RequestLocal m_OkUrlRL;
private RequestLocal m_CancelUrlRL;
//URL at which to mount this page
public static final String CONFIRM_URL = "BEBOP-confirmation-page";
//URL variable names
private static final String CONFIRM_MSG_VAR = "confirm-msg";
private static final String OK_URL_VAR = "ok-url";
private static final String CANCEL_URL_VAR = "cancel-url";
public ConfirmPage() {
super();
m_ConfirmMsgParam = new StringParameter(CONFIRM_MSG_VAR);
m_OkUrlParam = new StringParameter(OK_URL_VAR);
m_CancelUrlParam = new StringParameter(CANCEL_URL_VAR);
//add global state params
addGlobalStateParam(m_ConfirmMsgParam);
addGlobalStateParam(m_OkUrlParam);
addGlobalStateParam(m_CancelUrlParam);
//initialize RequestLocals for the URL params
m_ConfirmMsgRL = new RequestLocal() {
protected Object initialValue(PageState ps) {
return ps.getValue(m_ConfirmMsgParam);
}
};
m_OkUrlRL = new RequestLocal() {
protected Object initialValue(PageState ps) {
return ps.getValue(m_OkUrlParam);
}
};
m_CancelUrlRL = new RequestLocal() {
protected Object initialValue(PageState ps) {
return ps.getValue(m_CancelUrlParam);
}
};
//set the title
buildTitle();
//add the form
ConfirmForm cf = new ConfirmForm(m_ConfirmMsgRL, m_OkUrlRL, m_CancelUrlRL);
add(cf);
lock();
}
/**
* Returns a URL (minus "http://" string and server name) at which to access the ConfirmPage
* with the given Confirmation Message, OK URL, and Cancel URL.
* @param sConfirmMsg the Confirmation message to display on the page
* @param sOkUrl the URL to which to redirect if the user hits <i>OK</i>
* @param sCancelUrl the URL to which to redirect if the user hits <i>Cancel</i>
* @return URL at which to access the ConfirmPage
*/
public static String getConfirmUrl(String sConfirmMsg, String sOkUrl, String sCancelUrl) {
final ParameterMap params = new ParameterMap();
params.setParameter(CONFIRM_MSG_VAR, sConfirmMsg);
params.setParameter(OK_URL_VAR, sOkUrl);
params.setParameter(CANCEL_URL_VAR, sCancelUrl);
return URL.there("/" + CONFIRM_URL, params).toString();
}
protected void buildTitle() {
class ConfirmPagePrintListener implements PrintListener {
public void prepare(PrintEvent e) {
Label label = (Label) e.getTarget();
PageState ps = e.getPageState();
label.setLabel((String)m_ConfirmMsgRL.get(ps));
}
}
setTitle(new Label(new ConfirmPagePrintListener()));
}
private class ConfirmFormPrintListener implements PrintListener {
private RequestLocal m_RL;
ConfirmFormPrintListener(RequestLocal ConfirmMsgRL) {
m_RL = ConfirmMsgRL;
}
public void prepare(PrintEvent e) {
Label label = (Label) e.getTarget();
PageState ps = e.getPageState();
label.setLabel((String)m_RL.get(ps) );
}
}
private class ConfirmForm extends Form implements FormInitListener, FormProcessListener {
private Label m_ConfirmMsgLabel;
private Submit m_OkButton;
private Submit m_CancelButton;
private RequestLocal m_OkRL;
private RequestLocal m_CancelRL;
private String m_sOkUrl = null;
private String m_sCancelUrl = null;
public ConfirmForm(RequestLocal ConfirmMsgRL, RequestLocal OkUrlRL, RequestLocal CancelUrlRL) {
super("ConfirmForm");
m_ConfirmMsgLabel = new Label(new ConfirmFormPrintListener(ConfirmMsgRL));
this.add(m_ConfirmMsgLabel);
m_OkButton = new Submit("OK");
m_OkButton.setButtonLabel("OK");
this.add(m_OkButton);
m_OkRL = OkUrlRL;
m_CancelButton = new Submit("Cancel");
m_CancelButton.setButtonLabel("Cancel");
this.add(m_CancelButton);
m_CancelRL = CancelUrlRL;
this.addInitListener(this);
this.addProcessListener(this);
}
public void init(FormSectionEvent e) {
PageState ps = e.getPageState();
//initialize the OK and Cancel URL's
m_sOkUrl = (String) m_OkRL.get(ps);
m_sCancelUrl = (String) m_CancelRL.get(ps);
}
public void process(FormSectionEvent e) {
PageState ps = e.getPageState();
if (m_OkButton.isSelected(ps)) {
throw new RedirectSignal(m_sOkUrl, true);
} else {
throw new RedirectSignal(m_sCancelUrl, false);
}
}
}
}

View File

@ -1,123 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
/**
* The common interface that is implemented by all Bebop containers.
*
* The Container interface extends the Component interface. A container is
* simply a component that contains other components.
*
* @author David Lutterkort
* @author Uday Mathur
* @version $Id: Container.java 287 2005-02-22 00:29:02Z sskracic $
* */
public interface Container extends Component {
/**
* Adds a component to this container.
*
* @param pc component to add to this container
* @pre pc != null
*/
void add(Component pc);
/**
* Adds a component with the specified layout constraints to this
* container. Layout constraints are defined in each layout container as
* static ints. To specify multiple constraints, uses bitwise OR.
*
* @param pc component to add to this container
*
* @param constraints layout constraints (a
* bitwise OR of static ints in the particular layout)
*
* @pre c != null
*/
void add(Component c, int constraints);
/**
* Returns <code>true</code> if this list contains the specified element.
* More formally, returns <code>true</code> if and only if this list
* contains at least
* one element e such that (o==null ? e==null : o.equals(e)).
* <P>
* This method returns <code>true</code> only if the object has been
* directly added to this container. If this container contains another
* container that contains this object, this method returns
* <code>false</code>.
*
* @param o element whose presence in this container is to be tested
*
* @return <code>true</code> if this container contains the specified
* object directly; <code>false</code> otherwise.
* @pre o != null
*/
boolean contains(Object o);
/**
* Gets the component
* at the specified position. Each call to the add method increments
* the index. Since the user has no control over the index of added
* components (other than counting each call to the add method),
* this method should be used in conjunction with indexOf.
*
* @param index the index of the item to be retrieved from this
* container
*
* @return the component at the specified position in this container.
*
* @pre index >= 0 && index < size()
* @post return != null */
Component get(int index);
/**
*
*
* @param pc component to search for
*
* @return the index in this list of the first occurrence of
* the specified element, or -1 if this list does not contain this
* element.
*
* @pre pc != null
* @post contains(pc) implies (return >= 0 && return < size())
* @post ! contains(pc) implies return == -1
*/
int indexOf(Component pc);
/**
* Returns <code>true</code> if the container contains no components.
*
* @return <code>true</code> if this container contains no components;
* <code>false</code> otherwise.
* @post return == ( size() == 0 )
*/
boolean isEmpty();
/**
* Returns the number of elements in this container. This does not
* recursively count components that are indirectly contained in this container.
*
* @return the number of components directly in this container.
* @post size() >= 0
*/
int size();
}

View File

@ -1,197 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import java.io.IOException;
import java.util.ArrayList;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element;
/**
* A link back to the page in which it is contained. The control link captures
* and preserves the current state of the page, and possibly any control events
* that have been set. It is most useful inside a {@link
* com.arsdigita.bebop.list.ListCellRenderer} or a {@link
* com.arsdigita.bebop.table.TableCellRenderer}, where the list or table has
* already set up the events 'tight' for the control link to do the right thing.
*
* <p>
* <b>Warning:</b> Even though a control link lets you add action listeners,
* they are not run unless you override {@link #setControlEvent
* setControlEvent}. If you need this behavior, you should use an {@link
* ActionLink}. A control link is hardly ever useful unless it is contained in
* an event-generating component like {@link List} or {@link Table}.
*
* <p>
* <b>Example:</b> A control link is mainly useful to send events to other
* components. For example, the following control link will cause a control
* event <tt>delete</tt> with associated value <tt>42</tt> to be sent to the
* component <tt>fooComponent</tt> when the user clicks on it:
*
* <pre>
* ControlLink l = new ControlLink("click here") {
* public void setControlEvent(PageState s) {
* s.setControlEvent(fooComponent, "delete", 42);
* }
* };
* </pre>
*
* <p>
* This requires that <tt>fooComponent</tt> is part of the page hierarchy. The
* control link <tt>l</tt> does not have to be part of the page hierarchy, and
* may be generated on the fly. (See {@link PageState} for details on control
* events.)
*
* <p>
* See {@link BaseLink} for a description of all Bebop Link classes.
*
* @author Stanislav Freidin
* @author David Lutterkort
* @version $Id: ControlLink.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class ControlLink extends BaseLink {
/**
* The XML type attribute for a {@link ControlLink}.
*/
protected final String TYPE_CONTROL = "control";
/**
* A list of all action listeners. The list is instantiated lazily, and will
* therefore be null in most applications.
*/
private ArrayList m_actionListeners;
/**
* Constructs a new ControlLink. The link will encapsulates the child
* component (which should be a label or an image).
*
* @param child the component that will be turned into a link
*/
public ControlLink(Component child) {
super(child, "");
setTypeAttr(TYPE_CONTROL);
}
/**
* Constructs a new ControlLink with the given string label.
*
* @param label the string label for the link
*/
public ControlLink(String label) {
this(new Label(label));
}
/**
* Adds an <code>ActionListener</code>, which will be run when
* {@link#respond respond} is called.
*
* @param listener The listener to add.
*
* @see #respond respond
*/
public void addActionListener(ActionListener listener) {
Assert.isUnlocked(this);
if (m_actionListeners == null) {
m_actionListeners = new ArrayList();
}
m_actionListeners.add(listener);
}
/**
* Removes a previously added <code>ActionListener</code>.
*
* @param listener The listener to remove.
*
* @see #addActionListener addActionListener
*/
public void removeActionListener(ActionListener listener) {
Assert.isUnlocked(this);
if (m_actionListeners == null) {
return;
}
m_actionListeners.remove(listener);
}
/**
* Fires an <code>ActionEvent</code>, which causes all registered
* <code>ActionListener</code>s to be run. The source of the event is the
* <code>TabbedPane</code>.
*
* @param state the current page state
*
* @see #respond respond
*/
protected void fireActionEvent(PageState state) {
ActionEvent e = null;
if (m_actionListeners == null) {
return;
}
for (int i = 0; i < m_actionListeners.size(); i++) {
if (e == null) {
e = new ActionEvent(this, state);
}
((ActionListener) m_actionListeners.get(i)).actionPerformed(e);
}
}
/**
* Responds to the incoming request. Fires the <code>ActionEvent</code>.
*
* @param state the current page state
*/
@Override
public void respond(PageState state) {
fireActionEvent(state);
}
/**
* Generates the URL for a link and sets it as the "href" attribute of the
* parent.
*
* @param state the current page state
* @param parent the parent element
*/
@Override
protected void generateURL(PageState state, Element parent) {
setControlEvent(state);
try {
parent.addAttribute("href", state.stateAsURL());
} catch (IOException e) {
parent.addAttribute("href", "");
}
exportAttributes(parent);
state.clearControlEvent();
}
/**
* Sets the page state's control event. Should be overridden by child
* classes. By default, the link receives no control events whatsoever.
*
* @param ps the current page state
*/
// FIXME: Why is this not protected ?
public void setControlEvent(PageState ps) {
return;
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.parameters.ParameterModel;
/**
* @see SingleSelectionModel
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @author unknown
*/
public class DefaultSingleSelectionModel<T>
extends AbstractSingleSelectionModel<T> {
private final RequestLocal m_key;
public DefaultSingleSelectionModel() {
super();
m_key = new RequestLocal();
}
@Override
@SuppressWarnings("unchecked")
public T getSelectedKey(final PageState state) {
return (T) m_key.get(state);
}
@Override
public ParameterModel getStateParameter() {
return null;
}
@Override
public void setSelectedKey(final PageState state, final T key) {
if (key == null) {
if (getSelectedKey(state) != null) {
m_key.set(state, null);
fireStateChanged(state);
}
} else if (!key.equals(getSelectedKey(state))) {
m_key.set(state, key);
fireStateChanged(state);
}
}
}

View File

@ -1,110 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.xml.Element;
/**
* A (Simple) Component with various descriptive information, specifically 'hints'
* with explanations about it's proper usage. These hints provide a kind of
* online manual.
*
* @author Peter Boy (pb@zes.uni-bremen.de)
* @version $Id: TextStylable.java 287 2005-02-22 00:29:02Z sskracic $
*/
abstract public class DescriptiveComponent extends SimpleComponent {
/** Property to store informational text for the user about the Link, e.g.
* how to use it, or when to use it (or not to use it). */
private GlobalizedMessage m_hint; //= GlobalizationUtil.globalize("bebop.hint.no_entry_yet");
/** Property to store a (localized) label (or title) of this widget. A
* label is the text (name) displayed for the user to identify and
* distinguish the various elements on the screem. */
private GlobalizedMessage m_label;
/**
* Sets a popup hint for the component. It usually contains some explanation
* for the user about the component, how to use, why it is there, etc.
*
* @param hint GlobalizedMessage object with the information text.
*/
public void setHint(GlobalizedMessage hint) {
m_hint = hint;
}
/**
* Retrieve the popup hint for the component. It is specifically meant for
* client classes which have to generate the xml on their own and can not
* use the generateDescriptionXML method provided.
*
* @return popup hint message for the component
*/
public GlobalizedMessage getHint() {
return m_hint;
}
/**
* Sets a popup hint for the Link. It usually contains some explanation for
* the user about the link, how to use, why it is there, etc.
*
* @param label GlobalizedMessage object with the text to identify and
* distinguish the component.
*/
public void setLabel(GlobalizedMessage label) {
m_label = label;
}
/**
* Retrieve the label for the component. It is specifically meant for
* client classes which have to generate the XML on their own and can not
* use the generateDescriptionXML method provided.
*
* @return popup hint message for the component
*/
public GlobalizedMessage getLabel() {
return m_label;
}
/**
* Generates a (J)DOM fragment for clients to include into their generated
* XML.
*
* @param state The current page state.
* @param parent the XML Element instance to add the attributes managed by
* by this class
*/
protected void generateDescriptionXML(final PageState state,
final Element parent) {
if (m_label != null) {
parent.addAttribute("label", (String) m_label.localize());
}
if (m_hint != null) {
parent.addAttribute("hint", (String) m_hint.localize());
}
// Do we need this?
//exportAttributes(parent);
}
}

View File

@ -1,92 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.xml.Element;
import java.util.Iterator;
/**
* Delimited dimensional navbar.
*
* @author Michael Pih
* @version $Revision$ $Date$
* @version $Id$
*/
public class DimensionalNavbar extends SimpleContainer {
private final static String BEBOP_XML_NS = "http://www.arsdigita.com/bebop/1.0";
public final static String LEFT = "left";
public final static String RIGHT = "right";
public final static String CENTER = "center";
private String m_startTag;
private String m_endTag;
private String m_delimiter;
private String m_align;
public DimensionalNavbar() {
super();
setAlign(RIGHT);
}
public void setStartTag(String s) {
m_startTag = s;
}
public void setEndTag(String s) {
m_endTag = s;
}
public void setDelimiter(String s) {
m_delimiter = s;
}
public void setAlign(String s) {
if ( s.equals(LEFT) || s.equals(RIGHT) || s.equals(CENTER) ) {
m_align = s;
} else {
throw new IllegalArgumentException
("Align must be DimensionalNavbar.RIGHT, " +
"DimensionalNavbar.LEFT, or DimensionalNavbar.CENTER");
}
}
public void generateXML(PageState state, Element parent) {
Element navbar = parent.newChildElement("bebop:dimensionalNavbar",
BEBOP_XML_NS);
navbar.addAttribute("startTag", m_startTag);
navbar.addAttribute("endTag", m_endTag);
navbar.addAttribute("delimiter", m_delimiter);
navbar.addAttribute("align", m_align);
exportAttributes(navbar);
Iterator children = children();
Component child;
while ( children.hasNext() ) {
child = (Component) children.next();
child.generateXML(state, navbar);
}
}
}

View File

@ -1,55 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.xml.Element;
/**
* A component that gets its text entirely from a single XSL element.
*
* @author Sameer Ajmani
* @version $Id$
**/
public class ElementComponent extends SimpleComponent {
private String m_name;
private String m_uri;
/**
* Constructs an ElementComponent that uses the element with the given
* name under the given XSL namespace URI.
*
* @param name the name of the element to use
* @param uri the URI of the XSL namespace
**/
public ElementComponent(String name, String uri) {
m_name = name;
m_uri = uri;
}
/**
* Constructs a new element with the name and namespace given in this
* component's constructor, and adds the element to the parent element.
* @param state the current page state
* @param parent the parent element for this new element
**/
public void generateXML(PageState state, Element parent) {
parent.newChildElement(m_name, m_uri);
}
}

View File

@ -1,146 +0,0 @@
/*
* Copyright (C) 2014 Peter Boy, University of Bremen. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import static com.arsdigita.bebop.Component.BEBOP_XML_NS;
import com.arsdigita.bebop.event.PrintEvent;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.xml.Element;
/**
* Injects arbitrary content as a String into the xml output. It is not for
* any semantic type of data und it is not localizable. Specifically it is
* meant for data as Javascript and alike.
*
* It generates some fixed string to be included in the XML output.
*
* It resembles the Label methods for String parameters and currently
* generates the same XML attributes in order to avoid any need to modify the
* themes.
*
* @author pb
*/
public class Embedded extends SimpleComponent {
private final String m_content;
/** The setting for output escaping affects how markup in the
* <code>content</code> is handled.
* <UL><LI>If output escaping is in effect (true), &lt;b>example&lt;/b>
* will appear literally.</LI>
* <LI>If output escaping is disabled, &lt;b>example&lt;/b> appears as the
* String "example" in bold (i.e. retaining the markup.</LI></UL>
* Default is false. */
private boolean m_escaping = false; // default for a primitive
private PrintListener m_printListener;
/**
* Default constructor creates a new <code>Embedded</code> with the empty
* content.
*
* @param content
*/
public Embedded() {
m_content = "";
}
/**
* Constructor creates a new <code>Embedded</code> with the specified
* (fixed) content.
*
* @param content
*/
public Embedded(String content) {
m_content = content;
}
/**
* Constructor creates a new <code>Embedded</code> with the specified
* content and output escaping turned on if <code>escaping</code> is
* <code>true</code>.
*
* The setting for output escaping affects how markup in the
* <code>content</code> is handled. For example: <UL><LI>If output escaping
* is in effect, &lt;b>content&lt;/b> will appear literally.</LI> <LI>If
* output escaping is disabled, &lt;b>content&lt;/b> appears as the String
* "context" in bold.</LI></UL>
*
* @param content the content to inject into the output.
* @param escaping <code>true</code> if output escaping will be in effect;
* <code>false</code> if output escaping will be disabled
*/
public Embedded(String content, boolean escaping) {
m_content = content;
m_escaping = escaping;
}
/**
* Generates the (J)DOM fragment for a embedded.
* <p><pre>
* &lt;bebop:link href="..." type="..." %bebopAttr;/>
* </pre>
*
* @param state The current {@link PageState}.
* @param parent The XML element to attach the XML to.
*/
@Override
public void generateXML(PageState state, Element parent) {
if (!isVisible(state)) {
return;
}
Embedded target = firePrintEvent(state);
Element content = parent.newChildElement("bebop:label", BEBOP_XML_NS);
target.exportAttributes(content);
if (!target.m_escaping) {
content.addAttribute("escape", "yes");
} else {
content.addAttribute("escape", "no");
}
content.setText(m_content);
}
/**
*
* @param state
* @return
*/
protected Embedded firePrintEvent(PageState state) {
Embedded e = this;
if (m_printListener != null) {
try {
e = (Embedded) this.clone();
m_printListener.prepare(new PrintEvent(this, state, e));
} catch (CloneNotSupportedException nse) {
throw new RuntimeException(
"Couldn't clone Embedded for PrintListener. "
+ "This probably indicates a serious programming error: "
+ nse.getMessage());
}
}
return e;
}
}

View File

@ -1,64 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.PrintListener;
/**
* A link to an external (non-ACS) site. Does not propagate ACS-specific
* URL parameters.
*
* <p>See {@link BaseLink} for a description
* of all Bebop Link classes.
*
* @version $Id: ExternalLink.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class ExternalLink extends Link {
public ExternalLink(Component child, String url) {
super(child, url);
}
public ExternalLink(Component child, PrintListener l) {
super(child, l);
}
public ExternalLink(String label, String url) {
super(label, url);
}
public ExternalLink(String label, PrintListener l) {
super(label, l);
}
public ExternalLink(PrintListener l) {
super(l);
}
/**
* Processes the URL for this link after the print listener runs.
*
* @param state the current page state
* @param url the original URL
*
* @return the original, unchanged URL.
**/
protected String prepareURL(PageState state, String url) {
return url;
}
}

View File

@ -1,560 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.form.Hidden;
import javax.servlet.ServletException;
import com.arsdigita.bebop.util.Traversal;
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.web.URL;
import com.arsdigita.web.Web;
import com.arsdigita.web.RedirectSignal;
import com.arsdigita.util.Assert;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.xml.Element;
import com.arsdigita.globalization.GlobalizedMessage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Iterator;
/**
* Represents the visual structure of an HTML form. Forms can be constructed with a Container
* argument to specify the type of layout this form will adhere to. The default is a column panel.
*
* <p>
* As an example, a form that accepts a first and last name may be set up as follows:
*
* <pre style="background: #cccccc">
* public class MyForm extends Form implements FormProcessListener {
*
* private Text m_firstName; private Text m_lastName;
*
* public MyForm() { super("myform"); add(new Label("First Name:")); m_firstName = new
* Text("firstName"); m_firstName.setDefaultValue("John"); add(m_firstName);
*
* add(new Label("Last Name:")); m_lastName = new Text("lastName");
* m_lastName.setDefaultValue("Doe"); m_lastName.addValidationListener(new NotNullValidationListener
* ("The last name")); add(m_lastName);
*
* add(new Submit("save", "Save")); addProcessListener(this); }
*
* public void process(FormSectionEvent e) { PageState s = e.getPageState();
*
* System.out.println("You are " + m_firstName.getValue(s) + " " + m_lastName.getValue(s)); } }
* </pre>
*
* <p>
* This form automatically checks that the user supplied a last name. Only then does it call the
* <code>process</code> method, which prints the user-supplied values.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Stas Freidin
* @author Rory Solomon
* @author David Lutterkort
*
*/
public class Form extends FormSection implements BebopConstants {
/**
* Internal logger instance to faciliate debugging. Enable logging output by editing
* /WEB-INF/conf/log4j.properties int hte runtime environment and set
* com.arsdigita.bebop.Form=DEBUG by uncommenting or adding the line.
*/
private static final Logger LOGGER = LogManager.getLogger(Form.class);
/**
* Constant for specifying a <code>get</code> submission method for this form. See the <a href=
* "http://www.w3.org/TR/html4/interact/forms.html#submit-format">W3C HTML specification</a> for
* a description of what this attribute does.
*/
public final static String GET = "get";
/**
* Constant for specifying a <code>post</code> submission method for this form. See the <a href=
* "http://www.w3.org/TR/html4/interact/forms.html#submit-format">W3C HTML specification</a> for
* a description of what this attribute does.
*/
public final static String POST = "post";
/**
* The name of the <code>name</code> attribute for the form.
*/
private final static String NAME = "name";
/**
* The name of the <code>method</code> attribute for the form.
*/
private final static String METHOD = "method";
private String m_action;
private boolean m_processInvisible;
/**
* Hold the FormData for one request.
*/
private RequestLocal m_formData;
/**
* Determines whether or not a form is 'redirecting', meaning that it will clear the control
* event and redirect to the resulting state after form processing, so that a page reload won't
* cause the form to be resubmitted.
*/
private boolean m_isRedirecting = false;
/**
* Constructs a new form with the specified name. At the time of creation, instantiates a new
* form model for the form and instantiates a default ColumnPanel to contain the components.
*
* @param name the name of the form
*/
public Form(String name) {
this(name, new GridPanel(2));
}
/**
* Constructs a new form with the specified name and container. At the time of creation,
* instantiates a new form model for the form and replaces the default ColumnPanel with the
* specified container as the implicit container of the components.
*
* @param name the name attribute of the form
* @param panel the implicit container that will hold the components
*/
public Form(String name, Container panel) {
super(panel, new FormModel(name));
initFormData();
setName(name);
setProcessInvisible(false);
addMagicTag();
}
/**
* Writes the output to a DOM to be used with the XSLT template to produce the appropriate
* output. If the form is not visible, no output is generated.
*
* <p>
* Generates a DOM fragment:
* <p>
* <code><pre>
* &lt;bebop:form action=%url; %bebopAttr;>
* .. XML for panel ..
* .. XML for page state ..
* &lt;/bebop:form>
* </pre></code>
*
* @param s the page state used to determine the values of form widgets and page state
* attributes
* @param parent the XML element to which the form adds its XML representation
*
* @see PageState#generateXML
*/
@Override
public void generateXML(PageState s, Element parent) {
if (isVisible(s)) {
Element form = generateXMLSansState(s, parent);
s.setControlEvent(this);
s.generateXML(form, getModel().getParametersToExclude());
s.clearControlEvent();
}
}
/**
* Generates the XML representing the form and its widgets, but not the state information from
* <code>s</code>.
*
* @param s represents the curent request
* @param parent
*
* @return the top-level element for the form
*/
protected Element generateXMLSansState(PageState s, Element parent) {
Element form = parent.newChildElement("bebop:form", BEBOP_XML_NS);
// Encode the URL with the servlet session information;
// do not use DispatcherHelper.encodeURL because the
// ACS global parameters are provided via the FormData.
String url = null;
if (m_action == null) {
final URL requestURL = Web.getWebContext().getRequestURL();
if (requestURL == null) {
url = s.getRequest().getRequestURI();
} else {
url = requestURL.getRequestURI();
}
} else {
url = m_action;
}
form.addAttribute("action", s.getResponse().encodeURL(url));
exportAttributes(form);
m_panel.generateXML(s, form);
generateErrors(s, form);
return form;
}
/**
*
* @param ps
* @param parent
*/
protected void generateErrors(PageState ps, Element parent) {
for (Iterator it = getFormData(ps).getErrors(); it.hasNext();) {
Element errors = parent.newChildElement(BEBOP_FORMERRORS,
BEBOP_XML_NS);
Object msg = it.next();
if (msg == null) {
errors.addAttribute("message", "Unknown error");
} else {
errors.addAttribute("message",
(String) ((GlobalizedMessage) msg).localize(ps.getRequest()));
}
errors.addAttribute("id", getName());
}
}
/**
* <p>
* Determine whether or not this Form will redirect after its process listeners are fired.</p>
*
* @return
*/
public boolean isRedirecting() {
return m_isRedirecting;
}
/**
* Setting the redirecting flag will cause the Form to clear the control event and redirect back
* to the current URL, after firing all process listeners. Doing so means that a user reload
* will not cause the form to be resubmitted. The default value for this flag is false.
*
* @param isRedirecting
*/
public void setRedirecting(boolean isRedirecting) {
Assert.isUnlocked(this);
m_isRedirecting = isRedirecting;
}
/**
* Responds to the request by processing this form with the HTTP request given in
* <code>state</code>.
*
* @see #process process(...)
*
* @param state represents the current request
*
* @throws javax.servlet.ServletException
*/
@Override
public void respond(PageState state) throws ServletException {
final FormData data = process(state);
if (m_isRedirecting && data.isValid()) {
state.clearControlEvent();
throw new RedirectSignal(state.toURL(), true);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Methods to set the HTML attributes of the FORM element
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* Sets the <code>name</code> attribute for the form.
*
* @param name the name for the form
*
* @pre ! isLocked()
*/
public void setName(String name) {
Assert.isUnlocked(this);
setAttribute(NAME, name);
}
/**
* Gets the <code>name</code> attribute for this form.
*
* @return the name for this form.
*/
public String getName() {
return (String) getAttribute(NAME);
}
/**
* Sets the <code>enctype</code> attribute used in the <code>form</code> element. No encoding
* type is specified by default.
*
* @param encType the encoding type
*
* @pre ! isLocked()
*/
public void setEncType(String encType) {
Assert.isUnlocked(this);
setAttribute("enctype", encType);
}
/**
* Sets the <code>onSubmit</code> attribute used in the <code>form</code> element. No onsubmit
* handler is specified by default.
*
* @param javascriptCode the javascript code associated with this attribute
*
* @pre ! isLocked()
*/
public void setOnSubmit(String javascriptCode) {
Assert.isUnlocked(this);
setAttribute("onSubmit", javascriptCode);
}
/**
* Sets the <code>ONRESET</code> attribute used in the <code>FORM</code> element. No onreset
* handler is specified by default.
*
* @param javascriptCode the javascript code associated with this attribute
*
* @pre ! isLocked()
*/
public void setOnReset(String javascriptCode) {
Assert.isUnlocked(this);
setAttribute("onReset", javascriptCode);
}
/**
* Sets the HTTP method used to submit the form.
*
* @param method either <code>GET</code> or <code>POST</code>
*
* @pre ! isLocked()
*/
public void setMethod(String method) {
Assert.isUnlocked(this);
setAttribute(METHOD, method);
}
private String getMethod() {
return getAttribute(METHOD);
}
/**
* Returns true if form processing is turned on when the form is invisible.
*
* @return true if the form listeners should be processed even when the form is not visible on
* the page, false otherwise
*/
protected boolean getProcessInvisible() {
return m_processInvisible;
}
/**
* Turns form processing on/off when the form is invisible.
*
* @param processInvisible true if the form listeners should be processed even when the form is
* not visible on the page
*/
protected void setProcessInvisible(boolean processInvisible) {
m_processInvisible = processInvisible;
}
/**
* Sets the URL for the form's <code>action</code> attribute. This is the URL to which
* submissions will be sent when the user clicks a submit button on the form. By default, the
* action is <code>null</code>, instructing the form to set the action to the URL of the page in
* which it is used. If the action is set to a different URL, none of the listeners registered
* with this form will be run.
*
* @param action the URL to submit this form to
*
* @pre ! isLocked()
*/
public void setAction(String action) {
Assert.isUnlocked(this);
m_action = action;
}
/**
* Returns the URL for the form's <code>action</code> attribute.
*
* @return the URL to which to submit this form.
*
* @see #setAction setAction
*/
public final String getAction() {
return m_action;
}
/**
* Processes this form, creating a <code>FormData</code> object. Runs the right set of init,
* validation, and process listeners, depending on whether this is an initial request to the
* form and whether the form submission was valid. Submission listeners are always run.
*
* @see #getFormData
*
* @param state represents the current request
*
* @return the values extracted from the HTTP request contained in <code>state</code>.
*
* @throws com.arsdigita.bebop.FormProcessException
* @pre state != null
* @post return != null
*/
@Override
public FormData process(PageState state) throws FormProcessException {
Assert.exists(state, "PageState");
FormData result = new FormData(getModel(), state.getRequest());
setFormData(state, result);
// Unless invisible form processing is turned on, don't run any
// listeners if this form is not visible.
// if (getProcessInvisible() || state.isVisibleOnPage(this)) {
getModel().process(state, result);
// }
return result;
}
/**
* Returns the form data constructed by the {@link #process
* process} method for the request described by <code>state</code>. Processes the form if it has
* not already been processed.
*
* @param state describes the current request
*
* @return the values extracted from the HTTP request contained in <code>state</code>, or
* <code>null</code> if the form has not been processed yet.
*
* @pre state != null
* @post return != null
*/
public FormData getFormData(PageState state) {
return (FormData) m_formData.get(state);
}
/**
* Adds a Hidden Tag to this form so that our controller can determine if this is an initial
* request.
*/
protected void addMagicTag() {
Hidden h = new Hidden(getModel().getMagicTagName());
h.setDefaultValue("visited");
add(h);
}
/**
* Traverses the components contained in this form, collecting parameterModels and Listeners
* into this form's FormModel.
*/
protected void traverse() {
Traversal formRegistrar = new Traversal() {
@Override
protected void act(Component c) {
if (c == Form.this) {
return;
}
if (c instanceof Form) {
throw new IllegalStateException("Forms cannot contain other Forms");
}
c.register(Form.this, getModel());
}
};
formRegistrar.preorder(this);
}
/**
* Adds this form to the page and traverses the components contained in this form, collecting
* parameterModels and Listeners into this form's FormModel.
*
* @param p page in which to register this form
*/
@Override
public void register(Page p) {
traverse();
p.addComponent(this);
}
/**
* TODO
*
* @param model
*/
public void excludeParameterFromExport(ParameterModel model) {
getModel().excludeFormParameterFromExport(model);
}
/**
* Initialize <code>m_formData</code> so that accessing the per-request form data forces the
* form to be processed on the first access and caches the form data for subsequent requests.
*/
private void initFormData() {
m_formData = new RequestLocal() {
@Override
protected Object initialValue(PageState s) {
// TODO: We need to come up with the right strategy for
// how we deal with FormProcessExceptions. Are they fatal
// ? Do we just add them to the form validation errors ?
try {
return process(s);
} catch (FormProcessException e) {
LOGGER.error("Form Process exception", e);
throw new UncheckedWrapperException("Form Process error: "
+ e.getMessage(), e);
}
}
};
}
/**
* Converts to a String.
*
* @return a human-readable representation of <code>this</code>.
*/
@Override
public String toString() {
return super.toString() + " " + "[" + getName() + "," + getAction() + "," + getMethod()
+ "," + isRedirecting() + "]";
}
/**
* Protected access to set the formdata request local. This method is required if a subclass
* wishes to override the process method.
*
* @param state
* @param data
*/
protected void setFormData(PageState state, FormData data) {
m_formData.set(state, data);
}
}

View File

@ -1,832 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import com.arsdigita.bebop.parameters.ParameterData;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.util.Assert;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.URLRewriter;
/**
* Manages the data associated with forms and other remote sources.
* <p>The basic task of a <code>FormData</code> object is to transform
* a set of key-value string pairs into a validated set of Java data
* objects for use in subsequent processing. In most cases the original
* data is an HTTP request.
* <p>To perform the transformation, a separate instance of
* <code>FormModel</code> is used to specify the name and basic data
* type of each expected parameter in the set, as well as any
* additional validation steps required. The <code>FormData</code>
* stores both the transformed data objects and any validation
* error messages associated with an individual parameter or the
* form as a whole. Once the data has been validated, individual data
* objects may be queried from a <code>FormData</code> using the
* standard <code>get</code> method of the <code>Map</code> interface.
*
* <p><code>FormData</code> objects may also be used to control the
* entire lifecycle of self-validating forms, which report errors to
* the user in the context of the form itself, rather than on a
* separate page.
*
* <p>See the Forms API Developer Guide for details on using the
* <code>FormData</code> class.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Stas Freidin
* @version $Id: FormData.java 287 2005-02-22 00:29:02Z sskracic $ */
public class FormData implements Map, Cloneable {
private HashMap m_parameterDataValues = new HashMap();
private LinkedList m_formErrors;
private FormModel m_model;
private Locale m_locale;
private boolean m_isTransformed;
private boolean m_isValid;
private boolean m_isSubmission;
/**
* Ensure that no one can create this object from outside the package
* without supplying meaningful parameters
*/
private FormData() {}
/**
* Constructs a new <code>FormData</code> object containing the
* transformed and validated query parameters from an HTTP request.
*
* @param model a <code>FormModel</code> describing the parameters
* and validation constraints for this request
*
* @param request an HTTP request object passed from the servlet
* container
*
* @pre model != null
* @pre request != null
*
* @throws FormProcessException if an error occurs.
*/
public FormData(FormModel model, HttpServletRequest request)
throws FormProcessException {
this(model, request, Locale.getDefault());
}
/**
* Constructs a new <code>FormData</code> object containing the
* transformed and validated query parameters from an HTTP request.
*
* @param model a <code>FormModel</code> describing the parameters
* and validation constraints for this request
*
* @param request an HTTP request object passed from the servlet
* container
*
* @param isSubmission <code>true</code> if the request should be treated
* as a form submission by the user
*
* @pre model != null
* @pre request != null
*
* @throws FormProcessException if an error occurs.
*/
public FormData(FormModel model, HttpServletRequest request,
boolean isSubmission)
throws FormProcessException {
this(model, request, Locale.getDefault(), isSubmission);
}
/**
* Constructs a new <code>FormData</code> object containing the
* transformed and validated query parameters from an HTTP request.
*
* @param model a <code>FormModel</code> describing the parameters
* and validation constraints for this request
*
* @param request an HTTP request object passed from the servlet
* container
*
* @param isSubmission <code>true</code> if the request should be treated
* as a form submission by the user
*
* @param fallback a fallback FormData object. If a value for
* a parameter in the form model <code>model</code> is not in
* the current request parameters, the <code>fallback</code> object is
* searched.
*
* @pre model != null
* @pre request != null
*
* @throws FormProcessException if an error occurs
*/
public FormData(FormModel model, HttpServletRequest request,
boolean isSubmission, FormData fallback)
throws FormProcessException {
this(model, request, Locale.getDefault(), isSubmission, fallback);
}
/**
* Constructs a new <code>FormData</code> object containing the
* transformed and validated query parameters from an HTTP request.
* Error messages are provided in the specified locale.
*
* @param model A <code>FormModel</code> describing the parameters
* and validation constraints for this request.
*
* @param request An HTTP request object passed from the servlet
* container.
*
* @param locale The locale for which all error messages will be
* prepared. This may be used in a multilingual environment to
* tailor the output to the preferences or geographic location of
* individual users on a per-request basis.
*
* @pre model != null
* @pre request != null
* @pre locale != null
*
* @throws FormProcessException if an error occurs
*/
public FormData(FormModel model, HttpServletRequest request, Locale locale)
throws FormProcessException {
this(model, request, locale,
request.getParameter(model.getMagicTagName()) != null);
}
/**
* Constructs a new <code>FormData</code> object containing the
* transformed and validated query parameters from an HTTP request.
* Error messages are provided in the specified locale.
*
* @param model A <code>FormModel</code> describing the parameters
* and validation constraints for this request.
*
* @param request An HTTP request object passed from the servlet
* container.
*
* @param locale The locale for which all error messages will be
* prepared. This may be used in a multilingual environment to
* tailor the output to the preferences or geographic location of
* individual users on a per-request basis.
*
* @param isSubmission <code>true</code> if the request should be treated
* as a form submission by the user.
*
* @throws FormProcessException if an error occurs
* @pre model != null
* @pre request != null
* @pre locale != null
*/
public FormData(FormModel model, HttpServletRequest request,
Locale locale, boolean isSubmission)
throws FormProcessException {
this(model, request, locale, isSubmission, null);
}
/**
* Constructs a new <code>FormData</code> object containing the
* transformed and validated query parameters from an HTTP request.
* Error messages are provided in the specified locale.
*
* @param model A <code>FormModel</code> describing the parameters
* and validation constraints for this request.
*
* @param request An HTTP request object passed from the servlet
* container.
*
* @param locale The locale for which all error messages will be
* prepared. This may be used in a multilingual environment to
* tailor the output to the preferences or geographic location of
* individual users on a per-request basis.
*
* @param isSubmission <code>true</code> if the request should be treated
* as a form submission by the user.
*
* @param fallback a fallback FormData object. If a value for
* a parameter in the form model <code>model</code> is not in
* the current request parameters, the <code>fallback</code> object is
* searched.
*
* @throws FormProcessException if an error occurs
* @pre model != null
* @pre request != null
* @pre locale != null
*/
public FormData(FormModel model, HttpServletRequest request,
Locale locale, boolean isSubmission,
FormData fallback)
throws FormProcessException {
Assert.exists(model, "FormModel");
Assert.exists(request, "HttpServletRequest");
Assert.exists(locale, "Locale");
m_locale = locale;
m_model = model;
m_isTransformed = false;
m_isSubmission = isSubmission;
m_isValid = m_isSubmission;
createParameterData(request, fallback);
Iterator params = URLRewriter.getGlobalParams(request).iterator();
while (params.hasNext()) {
ParameterData param = (ParameterData)params.next();
setParameter(param.getModel().getName(), param);
}
}
/**
* Validates this <code>FormData</code> object according to its form model.
* If the <code>FormData</code> is already valid, does nothing.
*
* @param state describes the current page state
* @pre state != null
*/
public void validate(PageState state) {
if (isValid()) {
return;
}
m_isValid = true;
if (m_formErrors != null) {
m_formErrors.clear();
}
m_model.validate(state, this);
}
/**
* Validates this <code>FormData</code> object against its form model,
* regardless of whether the object is currently valid.
*
* @param state describes the current page state
* @pre state != null
*/
public void forceValidate(PageState state) {
invalidate();
validate(state);
}
/**
* Reports a validation error on the form as a whole.
*
* @param message a String of the error message
* @pre message != null
* @deprecated refactor and use addError(GlobalizedMessage) instead
*/
public void addError(String message) {
addError(new GlobalizedMessage(message));
}
/**
* Reports a validation error on the form as a whole.
* Uses a GlobalizedMessage for inklusion
*
* @param message the error message
* @pre message != null
*/
public void addError(GlobalizedMessage message) {
if (m_formErrors == null) {
m_formErrors = new LinkedList();
}
m_formErrors.add(message);
m_isValid = false;
}
/**
* Adds an error message to the ParameterData object associated with
* the parameter model identified by <code>name</code>.
*
* @param name the name of the parameter model to whose
* ParameterData the error message will be added
*
* @param message the text of the error message to add
*
* @pre name != null
* @pre message != null
* @deprecated use addError(String name, GlobalizedMessage message) instead
*/
public void addError(String name, String message) {
ParameterData parameter;
if (!m_parameterDataValues.containsKey(name)) {
throw new IllegalArgumentException
("Attempt to set Error in Non-Existant ParameterData");
}
parameter = (ParameterData) m_parameterDataValues.get(name);
parameter.addError(message);
m_isValid = false;
}
/**
* Adds an error message to the ParameterData object associated with
* the parameter model identified by <code>name</code>.
*
* @param name the name of the parameter model to whose
* ParameterData the error message will be added
*
* @param message the text of the error message to add
*
* @pre name != null
* @pre message != null
*/
public void addError(String name, GlobalizedMessage message) {
ParameterData parameter;
if (!m_parameterDataValues.containsKey(name)) {
throw new IllegalArgumentException
("Attempt to set Error in Non-Existant ParameterData");
}
parameter = (ParameterData) m_parameterDataValues.get(name);
parameter.addError(message);
m_isValid = false;
}
/**
* Returns the errors associated with the specified parameter.
*
* @param name the name of the parameter whose errors we are interested in
*
* @return an iterator of errors. Each error is just a string for
* now.
*
* @pre name != null
* @post return != null
*/
public Iterator getErrors(String name) {
ParameterData parameter
= (ParameterData)m_parameterDataValues.get(name);
if (parameter == null) {
return Collections.EMPTY_LIST.iterator();
}
return parameter.getErrors();
}
/**
* Returns an iterator over all the errors on this form that are not
* associated with any particular parameter. Such errors may have
* been generated by a FormValidationListener.
*
* @return an iterator over error messages.
* @post return != null
*/
public Iterator getErrors() {
if (m_formErrors == null) {
return Collections.EMPTY_LIST.iterator();
}
return m_formErrors.iterator();
}
/**
* Returns an iterator over all of the errors on this form.
* This includes both errors associated with particular parameters
* and errors associated with the form as a whole.
*
* @return an iterator over all error messages.
* @post return != null
*/
public Iterator getAllErrors() {
return new Iterator() {
private Iterator params, paramErrors, formErrors;
{
params = m_parameterDataValues.values().iterator();
paramErrors = Collections.EMPTY_LIST.iterator();
formErrors = getErrors();
}
private void seekToNextError() {
while (! paramErrors.hasNext() && params.hasNext()) {
paramErrors
= ((ParameterData)params.next()).getErrors();
}
}
@Override
public boolean hasNext() {
seekToNextError();
return paramErrors.hasNext() || formErrors.hasNext();
}
@Override
public Object next() throws NoSuchElementException {
seekToNextError();
if (paramErrors.hasNext()) {
return paramErrors.next();
}
// An error will be thrown if !formErrors.hasNext()
return formErrors.next();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Gets the specified ParameterData object.
*
* @param name the name of the parameterModel to retrieve
* @return the parameter data object specified.
*
*/
public ParameterData getParameter(String name) {
return (ParameterData)m_parameterDataValues.get(name);
}
/**
* Sets the ParameterData object identified by the name in this FormData
* Object.
*
* @param name the name of the parameterModel
* @param value
*/
public void setParameter(String name, ParameterData value) {
m_parameterDataValues.put(name,value);
}
/**
* Returns a collection of all the <code>ParameterData</code> objects.
*
* @return a collection of all the <code>ParameterData</code> objects.
*/
public final Collection getParameters() {
return m_parameterDataValues.values();
}
/**
* Determines whether this request represents a submission event.
*
* @return <code>true</code> if this request represents a submission event;
* <code>false</code> if it represents an initialization event.
*/
public final boolean isSubmission() {
return m_isSubmission;
}
/**
* Determines whether the key-value string pairs in the
* request have been transformed into Java data objects.
*
* @return <code>true</code> if the key-value string pairs have been
* transformed into Java data objects;
* <code>false</code> otherwise.
*
*/
public final boolean isTransformed() {
return m_isTransformed;
}
/**
* Determines whether any errors were found during validation of
* a form submission.
* @return <code>true</code> if no errors were found; <code>false</code>
* otherwise.
*
*/
public final boolean isValid() {
return m_isValid;
}
/**
* Sets isValid to <code>false</code>. We do not allow programmers
* to manually toggle the isValid value to <code>true</code>.
* Hence this method takes no
* arguments and only sets isValid flag to false
* @deprecated Use invalidate() instead
*/
public void setInvalid() {
invalidate();
}
/**
* Set isValid to <code>false</code>. We do not allow programmers
* to manually toggle the isValid value to <code>true</code>.
*/
public final void invalidate() {
m_isValid = false;
}
// --- private helper methods to initialize object ---
/**
* Sets the value of a parameter within the associated ParameterData
* object
*
* @param name Name of the parameterModel whose ParameterData object
* we are setting
*
* @param value Value to assign the ParmeterData object
*
*/
private void setParameterValue(String name, Object value) {
ParameterData parameter = (ParameterData) m_parameterDataValues.get(name);
if (parameter != null) {
parameter.setValue(value);
} else {
throw new IllegalArgumentException("Parameter " + name +
" does not exist");
}
}
/**
* Iterate through parameterModels extracting values from the
* request, and transforming the value according to the parameter
* model This code incorporates
* ParameterModel.createParameterData(request)
*
* @param request the HttpServletRequest
* @param fallback a fallback FormData object. If any parameter
* in the form model does not have a value in the request,
* try to locate its value in the fallback object.
*/
private void createParameterData(HttpServletRequest request,
FormData fallback)
throws FormProcessException {
ParameterModel parameterModel;
ParameterData parameterData;
Iterator parameters = m_model.getParameters();
while (parameters.hasNext()) {
parameterModel = (ParameterModel) parameters.next();
// createParamterData automagically handles default values
// and errors in tranformation.
Object defaultValue = null;
if (fallback != null) {
parameterData =
fallback.getParameter(parameterModel.getName());
if (parameterData != null) {
defaultValue = parameterData.getValue();
}
}
// specify a default from the fallback
parameterData =
parameterModel.createParameterData(request,
defaultValue,
isSubmission());
Assert.exists(parameterData);
setParameter(parameterModel.getName(), parameterData);
}
m_isTransformed=true;
}
// --- Public methods to satisfy Map interface ---
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean containsKey(Object key) {
return m_parameterDataValues.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
// this is very expensive with ParameterData
throw new UnsupportedOperationException();
}
/*
* This is just plain wrong. Either you pretend to be a Map of
* things, or you are a Map of ParameterData-s.
*/
@Override
public Set entrySet() {
return m_parameterDataValues.entrySet();
}
/**
* Returns the value contained by the ParameterData object named
* by <code>key</code>.
* If no key is found, throws IllegalArgumentException.
* @param key the parameter data object to retrieve
* @return the value in the specified parameter data object.
* @throws java.lang.IllegalArgumentException thrown when the key
* is not a valid parameter.
*/
@Override
public Object get(Object key) throws IllegalArgumentException {
ParameterData p = getParameter((String)key);
if (p != null) {
return p.getValue();
}
throw new IllegalArgumentException("parameter " + key +
" not part of the form model");
}
/**
* @param m
* @return
* @deprecated Use get(m.getName()) instead, and then manually check
* for model identity
*/
public Object get(ParameterModel m) {
ParameterData p = getParameter(m.getName());
return ( p.getModel() == m ) ? p : null;
}
/**
* Retrieves a date object for the specified parameter name.
* @param key the object to retrieve
* @return a date object for the specified parameter name.
*
*/
public Date getDate(Object key) {
return (Date) get(key);
}
/**
* Retrieves an integer object for the specified parameter name.
* @param key the object to retrieve
* @return an integer object for the specified parameter name.
**/
public Integer getInteger(Object key) {
return (Integer) get(key);
}
/**
* Retrieves a String object for the specified parameter name.
* @param key the object to retrieve
* @return a string object for the specified parameter name.
**/
public String getString(Object key) {
return (String) get(key);
}
@Override
public boolean isEmpty() {
return m_parameterDataValues.isEmpty();
}
@Override
public Set keySet() {
return m_parameterDataValues.keySet();
}
@Override
public Object put(Object key, Object value) {
Object previousValue = get(key);
setParameterValue((String)key, value);
m_isValid = false;
return previousValue;
}
@Override
public void putAll(Map t) {
for (Iterator i = t.keySet().iterator(); i.hasNext(); ) {
String key = (String) i.next();
setParameterValue(key, t.get(key));
}
m_isValid = false;
}
/**
*
* @param key
* @return
*/
@Override
public Object remove(Object key) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
return m_parameterDataValues.size();
}
@Override
public Collection values() {
throw new UnsupportedOperationException();
}
/**
*
* @return
* @throws CloneNotSupportedException
*/
@Override
public Object clone() throws CloneNotSupportedException {
FormData result = (FormData) super.clone();
result.m_parameterDataValues = new HashMap();
for (Iterator i= m_parameterDataValues.keySet().iterator();
i.hasNext(); ) {
Object key = i.next();
ParameterData val = (ParameterData) m_parameterDataValues.get(key);
result.m_parameterDataValues.put(key, val.clone());
}
if (m_formErrors != null) {
result.m_formErrors = (LinkedList) m_formErrors.clone();
}
return result;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
for (Iterator i = getAllErrors(); i.hasNext();) {
s.append(i.next()).append(System.getProperty("line.separator"));
}
return s.toString();
}
/**
* Converts to a String.
* The method {@link #toString()} returns all errors.
*
* @return a human-readable representation of <code>this</code>.
*/
public String asString() {
String newLine = System.getProperty("line.separator");
StringBuilder to = new StringBuilder();
to.append(super.toString() + " = {" + newLine);
//Map
to.append("m_parameterDataValues = ")
.append(m_parameterDataValues).append(",").append(newLine);
//LinkedList
to.append("m_formErrors = " + m_formErrors + "," + newLine);
//FormModel
to.append("m_model = " + m_model + "," + newLine);
to.append("m_locale = " + m_locale + "," + newLine);
to.append("m_isTransformed = " + m_isTransformed + "," + newLine);
to.append("m_isValid = " + m_isValid + "," + newLine);
to.append("m_isSubmission = " + m_isSubmission + newLine);
to.append("}");
return to.toString();
}
}

View File

@ -1,552 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.EventListenerList;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.FormSubmissionListener;
import com.arsdigita.bebop.event.FormValidationListener;
import com.arsdigita.bebop.parameters.ParameterData;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.util.Assert;
import com.arsdigita.util.Lockable;
import com.arsdigita.util.URLRewriter;
import com.arsdigita.web.RedirectSignal;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* A container for two classes of
* objects: <tt>ParameterModels</tt> and <tt>ValidationListeners</tt>.</p>
* <ul>
* <li><tt>ParameterModels</tt> are associated
* with the data objects that the user submits with the form.</li>
* <li><tt>ValidationListeners</tt> provide custom
* cross-checking of parameter values.</li>
* </ul>
* <p>Instances of this class provide a specification for transforming a
* set of key-value string pairs into a set of validated Java data
* objects.
* A single instance of this
* class can handle all submissions to a particular form.
* <p>The most common usage for this class is
* is to use a private variable in a servlet to store the
* model, and to construct it in the servlet <code>init</code> method.
* That way, the model persists for the lifetime of the servlet, reducing
* the memory and processing overhead for each request.
* <p>See the
* Forms API Developer Guide for details on using the
* <code>FormModel</code> class.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Stas Freidin
* @author Rory Solomon
*/
public class FormModel implements Lockable {
private static final Logger LOGGER = LogManager.getLogger(FormModel.class);
private static final String MAGIC_TAG_PREFIX = "form.";
private String m_name = null;
private List m_parameterModels = null;
private List m_parametersToExclude = null;
private boolean m_locked = false;
private boolean m_defaultOverridesNull;
protected EventListenerList m_listenerList;
/**
* Constructs a new form model.
*
* @param name a URL-encoded keyword used to identify this form model
* */
public FormModel(String name) {
this(name, false);
}
/**
* Construct a new form model. The <code>defaultOverridesNull</code>
* parameter is passed on to all parameter models that are added to the
* form model. If it is <code>true</code>, the parameter model will use
* the default value whenever it would normally set the parameter's value
* to null, for example if the parameter is missing from the request. If
* this value is <code>false</code>, the default parameter value will
* only be used if the request being processed is not a submission, but
* an initial request for the form model.
*
* <p> This method is only package-friendly since it is only useful to
* the Page class. Everybody else should be happy with the public
* constructor.
*
* @param name a URL-encoded keyword used to identify this form model
*
* @param defaultOverridesNull <code>true</code> if the default value for
* parameters should be used whenever the value would be
* <code>null</code> ordinarily.
*/
FormModel(String name, boolean defaultOverridesNull) {
Assert.exists(name, "Name");
m_parameterModels = new LinkedList();
m_parametersToExclude = new LinkedList();
m_listenerList = new EventListenerList();
m_name = name;
m_defaultOverridesNull = defaultOverridesNull;
m_parameterModels.addAll(URLRewriter.getGlobalModels());
}
/**
* Returns the name of this form model.
*
* @return a URL-encoded keyword used to identify requests
* conforming to this form model.
* */
public final String getName() {
return m_name;
}
public final void setName(String name) {
m_name = name;
}
String getMagicTagName() {
return MAGIC_TAG_PREFIX + getName();
}
/**
* Adds a parameter model to the form model. The parameter model
* should be fully configured before adding it to the form model.
*
* @param parameter a parameter model object
* */
public final void addFormParam(ParameterModel parameter) {
Assert.exists(parameter, "Parameter");
Assert.isUnlocked(this);
parameter.setDefaultOverridesNull(m_defaultOverridesNull);
m_parameterModels.add(parameter);
if( LOGGER.isDebugEnabled() ) {
LOGGER.debug( "Added parameter: " + parameter.getName() + "[" +
parameter.getClass().getName() + "]" );
}
}
/**
* Adds a parameter model to the list of parameters that should
* not be exported when the form is rendered. Useful examples
* of this are for forms that loop back on themselves such as
* search forms or a control bar. The parameter model
* should be fully configured and have been added to the form model
* before adding it to the list of items to exclude
*
* @param parameter a parameter model object
* */
public final void excludeFormParameterFromExport(ParameterModel parameter) {
Assert.exists(parameter, "Parameter");
Assert.isUnlocked(this);
m_parametersToExclude.add(parameter);
}
/**
* Determines whether the form model contains the specified parameter
* model.
* @param p the parameter model to check for
* @return <code>true</code> if the form model contains the specified
* parameter model; <code>false</code> otherwise.
*/
public final boolean containsFormParam(ParameterModel p) {
Assert.exists(p, "Parameter");
return m_parameterModels.contains(p);
}
/**
* Returns an iterator over the parameter models contained within
* the form model.
*
* @return an iterator over the parameter models contained within
* the form model.
* */
public final Iterator getParameters() {
return m_parameterModels.iterator();
}
/**
* Returns an iterator over the parameter models that are
* contained within the form model but should not be exported
* as part of the form's state. This is important for situations
* where the form loops back on itself (e.g. a ControlBar or
* a Search form).
*/
public final Iterator getParametersToExclude() {
return m_parametersToExclude.iterator();
}
/**
* Adds a listener that is called as soon as the {@link FormData} has been
* initialized with the request parameters, but before any of the init,
* validation, or process listeners are run. The listener's
* <code>submitted</code> method may throw a
* <code>FormProcessException</code> to signal that any further
* processing of the form should be aborted.
*
* @param listener a <code>FormSubmissionListener</code> value
*/
public void addSubmissionListener(FormSubmissionListener listener) {
Assert.exists(listener, "Submission Listener");
m_listenerList.add(FormSubmissionListener.class, listener);
}
/**
* Adds a validation listener, implementing a custom validation
* check that applies to the form as a whole. Useful for checks
* that require examination of the values of more than one parameter.
*
* @param listener an instance of a class that implements the
* <code>FormValidationListener</code> interface
* */
public void addValidationListener(FormValidationListener listener) {
Assert.exists(listener, "FormValidationListener");
Assert.isUnlocked(this);
m_listenerList.add(FormValidationListener.class, listener);
}
/**
* Adds a listener for form initialization events.
* <p>Initialization events occur when a form is initially
* requested by the user, but not when the form is subsequently
* submitted. They typically
* perform actions such as querying the database for existed values
* to set up an edit form or obtaining a sequence value to set up a
* create form.
* @param listener an instance of a class that implements the
* <code>FormInitListener</code> interface
* */
public void addInitListener(FormInitListener listener) {
Assert.exists(listener, "FormInitListener");
Assert.isUnlocked(this);
m_listenerList.add(FormInitListener.class, listener);
}
/**
* Adds a listener for form processing events. <p>Process events
* only occur after a form submission has been successfully
* validated. They are typically used to perform a database
* transaction or other operation based on the submitted data.
* <p>Process listeners are executed in the order in which they are
* added.
*
* @param listener an instance of a class that implements the
* <code>FormProcessListener</code> interface
* */
public void addProcessListener(FormProcessListener listener) {
Assert.exists(listener, "FormProcessListener");
Assert.isUnlocked(this);
m_listenerList.add(FormProcessListener.class, listener);
}
/**
* Creates a new FormData object that is populated with default values
* (for an initial request) or values from the request (for
* a submission).
* <P>If this is a submission, validates the data and (if the
* data is valid) calls the process listeners. Returns a FormData object.
*
* @param state the PageState object holding request-specific information
* @return a FormData object.
* */
public FormData process(PageState state) throws FormProcessException {
Assert.isLocked(this);
boolean isSubmission =
state.getRequest().getParameter(getMagicTagName()) != null;
return process(state, isSubmission);
}
/**
* Creates a new FormData object that is populated with default values
* (for an initial request) or values from the request (for a
* submission).
* <P>If this is a submission, validates the data and (if the
* data is valid) calls the process listeners. Returns a FormData object.
*
* @param state the PageState object holding request specific information
* @param isSubmission <code>true</code> if the request is a submission;
* <code>false</code> if this is the first request to the form data.
*/
public FormData process(PageState state, boolean isSubmission)
throws FormProcessException {
Assert.isLocked(this);
FormData data = new FormData(this, state.getRequest(), isSubmission);
try {
process(state, data);
} finally {
}
return data;
}
/**
* Do the work for the public process method. Uses the
* prepopulated <code>FormData</code> and runs listeners on it as
* needed.
*
* @throws FormProcessException if an error occurs
*/
void process(final PageState state, final FormData data)
throws FormProcessException {
LOGGER.debug("Processing the form model");
final FormSectionEvent e = new FormSectionEvent(this, state, data);
if (data.isSubmission()) {
LOGGER.debug("The request is a form submission; running " +
"submission listeners");
try {
fireSubmitted(e);
} catch (FormProcessException fpe) {
LOGGER.debug("A FormProcessException was thrown while firing " +
"submit; aborting further processing");
return;
} finally {
}
try {
LOGGER.debug("Validating parameters");
fireParameterValidation(e);
LOGGER.debug("Validating form");
fireFormValidation(e);
} finally {
}
if (data.isValid()) {
LOGGER.debug("The form data is valid; running process " +
"listeners");
try {
fireFormProcess(e);
} catch (FormProcessException fpe) {
LOGGER.debug("A FormProcessException was thrown while " +
"initializing the form; storing the error", fpe);
data.addError("Initialization Aborted: " + fpe.getMessages());
} finally {
}
} else {
LOGGER.debug("The form data was not valid; this form " +
"will not run its process listeners");
}
} else {
LOGGER.debug("The request is not a form submission; " +
"running init listeners");
try {
fireFormInit(e);
} catch (FormProcessException fpe) {
LOGGER.debug("A FormProcessException was thrown while " +
"initializing the form; storing the error", fpe);
data.addError("Initialization Aborted: " + fpe.getMessages());
} finally {
}
}
}
protected void fireSubmitted(FormSectionEvent e)
throws FormProcessException {
Assert.exists(e.getFormData(), "FormData");
Assert.isLocked(this);
FormProcessException delayedException = null;
Iterator i = m_listenerList.getListenerIterator(FormSubmissionListener.class);
while (i.hasNext()) {
try {
((FormSubmissionListener) i.next()).submitted(e);
} catch (FormProcessException ex) {
delayedException = ex;
}
}
if ( delayedException != null ) {
throw delayedException;
}
}
/**
* Calls a form initialization listener.
*
* @param e a FormSectionEvent originating from the form
*/
protected void fireFormInit(FormSectionEvent e) throws FormProcessException {
Assert.exists(e.getFormData(), "FormData");
Assert.isLocked(this);
Iterator i = m_listenerList.getListenerIterator(FormInitListener.class);
while (i.hasNext()) {
((FormInitListener) i.next()).init(e);
}
}
/**
* Private helper method that validates the individual parameters by
* calling ParameterValidationListeners from the individual
* parameterModels.
*
* @param e a FormSectionEvent originating from the form
* */
protected void fireParameterValidation(FormSectionEvent e) {
FormData data = e.getFormData();
Assert.exists(data, "FormData");
Iterator parameters = getParameters();
ParameterModel parameterModel;
ParameterData parameterData;
while (parameters.hasNext()) {
parameterModel = (ParameterModel) parameters.next();
parameterData = (ParameterData) data.getParameter(parameterModel.getName());
try {
parameterData.validate();
if (!parameterData.isValid()) {
data.invalidate();
}
} catch (FormProcessException fpe) {
data.addError("Processing Listener Error: " + fpe.getMessage());
}
}
}
/**
* Private helper method. Validates the form by calling
* FormValidationListeners
*
* @param e a FormSectionEvent originating from the Form
* */
private void fireFormValidation(FormSectionEvent e) {
FormData data = e.getFormData();
Assert.exists(data, "FormData");
Iterator i = m_listenerList.getListenerIterator(FormValidationListener.class);
while (i.hasNext()) {
try {
((FormValidationListener) i.next()).validate(e);
} catch (FormProcessException fpe) {
data.addError(fpe.getMessage());
}
}
}
/**
* Call form process listeners. <p>Form processing is performed
* <em>after</em> the form has been validated.</p>
*
* @param e a FormSectionEvent originating from the form
* */
private void fireFormProcess(FormSectionEvent e)
throws FormProcessException {
Assert.exists(e.getFormData(), "FormData");
if (!e.getFormData().isValid()) {
throw new IllegalStateException("Request data must be valid " + "prior to running processing filters.");
}
Iterator i = m_listenerList.getListenerIterator(FormProcessListener.class);
RedirectSignal redirect = null;
while (i.hasNext()) {
try {
((FormProcessListener) i.next()).process(e);
} catch( RedirectSignal signal ) {
if( LOGGER.isDebugEnabled() ) {
LOGGER.debug( "Delaying redirect to " +
signal.getDestinationURL() );
}
if( null != redirect ) {
LOGGER.error( "Non-deterministic redirect. Ignoring earlier occurrence.", redirect );
}
redirect = signal;
}
}
if( null != redirect ) throw redirect;
}
/**
* Call form validation listeners. Listeners that encounter
* validation errors report them directly to the
* <code>FormData</code> object. <p>Form validation is performed
* <em>after</em> the initial transformation of key-value string
* pairs into Java data objects is complete.
*
* @param state the page state for this request
*
* @param data the FormData object to validate
*
* @pre data != null
* */
void validate(PageState state, FormData data) {
Assert.exists(data, "FormData");
if (!data.isTransformed()) {
throw new IllegalStateException("Request data must be transformed " + "prior to running validation filters.");
}
fireParameterValidation(new FormSectionEvent(this, state, data));
fireFormValidation(new FormSectionEvent(this, state, data));
}
/**
* Merge the parameterModels and Listeners from the supplied
* FormModel into the current FormModel. This method is useful when
* registering FormSections in Forms.
*
* @param m The FormModel to be merged into this FormModel
* */
void mergeModel(FormModel m) {
Assert.isUnlocked(this);
Assert.exists(m, "FormSection's FormModel");
m_parameterModels.addAll(m.m_parameterModels);
m_listenerList.addAll(m.m_listenerList);
}
/**
* Locks this FormModel and all of its ParameterModels.
* */
public void lock() {
for (Iterator i = getParameters(); i.hasNext(); ) {
((ParameterModel) i.next()).lock();
}
m_locked = true;
}
/**
* Checks whether this FormModel is locked.
*
* @return <code>true</code> if this FormModel is locked;
* <code>false</code> otherwise.
* */
public final boolean isLocked() {
return m_locked;
}
}

View File

@ -1,181 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.globalization.GlobalizedMessage;
import javax.servlet.ServletException;
/**
* This class represents exceptions that occur within the processing methods
* of any of the form event listeners. Typically the code will catch specific
* exceptions such as <code>SQLException</code> and rethrow them as instances
* of this class to pass the message to the controller in a standard fashion.
*
* <p>Since this class is a subclass of <code>ServletException</code>, servlets
* that do form processing within a <code>doPost</code> or <code>doGet</code>
* methods do not need to explicitly catch instances of this class. However,
* they may wish to do so for special error reporting to the user, or to notify
* the webmaster via e-mail of the problem.
*
* @version $Id$
*/
public class FormProcessException extends ServletException {
/** Globalized version of the exception message, intended for output in the UI */
private GlobalizedMessage m_globalizedMessage;
/**
* Constructor using a String as message presented to the user.
* @param message
* @deprecated Use FormProcessException(GlobalizedMessage) instead. The
* error message for the user should always be globalized so it
* can be transformed to the current users requested language.
*/
public FormProcessException(String message) {
super(message);
}
/**
* Constructor using both types of messages which may be presented to the
* user. It's a kind of fallback just in kind we really need a non-
* globalized message. Usage is strongly discouraged.
* @param message
* @param globalizedMessage
*/
public FormProcessException(String message,
GlobalizedMessage globalizedMessage) {
super(message);
m_globalizedMessage = globalizedMessage;
}
/**
* Constructor using a GlobalizedMessage as the error text presented to the
* user. Using this constructor is the strongly recommended way!
*
* @param globalizedMessage
*/
public FormProcessException(GlobalizedMessage globalizedMessage) {
super();
m_globalizedMessage = globalizedMessage;
}
/**
*
* @param message
* @param rootCause
* @deprecated use FormProcessException(String,GlobalizedMessage,Throwable)
* instead
*/
public FormProcessException(String message,
Throwable rootCause) {
super(message, rootCause);
}
public FormProcessException(String message,
GlobalizedMessage globalizedMessage,
Throwable rootCause) {
super(message, rootCause);
m_globalizedMessage = globalizedMessage;
}
public FormProcessException(Throwable rootCause) {
super(rootCause);
}
/**
* Add a globalized version of the exception message just in case a non-
* globalized message enabled constructor has been used.
*
* @param globalizedMessage the globalized message intended for output in UI
*/
public void setGlobalizedMessage(GlobalizedMessage globalizedMessage) {
m_globalizedMessage = globalizedMessage;
}
/**
* Retrieve the globalized version of the exception message, intended for
* use in the UI widgets.
* The standard non-globalizatin enabled exception message is for use in
* log entries only!
*
* @return the globalized message intended for output in UI
*/
GlobalizedMessage getGlobalizedMessage() {
return m_globalizedMessage;
}
/**
* In addition to printing the stack trace for this exception, also prints
* the stack trace for the root cause, if any. This is a workaround for
* those implementations of {@link ServletException} that don't implement
* <code>printStackTrace</code> correctly. If you happen to use an
* implementation that does, the stack trace for the root cause may be
* printed twice, which is not that big of a deal in the grand scheme of
* things.
*/
@Override
public void printStackTrace() {
super.printStackTrace();
if (getRootCause() != null) {
System.err.print("Root cause: ");
getRootCause().printStackTrace();
}
}
/**
* @param s
* @see #printStackTrace()
*/
@Override
public void printStackTrace(java.io.PrintStream s) {
super.printStackTrace(s);
if (getRootCause() != null) {
s.println("Root cause: ");
getRootCause().printStackTrace(s);
}
}
/**
* @param s
* @see #printStackTrace()
*/
@Override
public void printStackTrace(java.io.PrintWriter s) {
super.printStackTrace(s);
if (getRootCause() != null) {
s.println("Root cause: ");
getRootCause().printStackTrace(s);
}
}
/**
* <p>Returns the concatenation of {@link #getMessage()} and {@link
* #getRootCause()}.<code>getMessage()</code>.</p>
* @return
**/
public String getMessages() {
StringBuilder result = new StringBuilder(getMessage());
if ( getRootCause() != null ) {
result.append(" (root cause: ")
.append(getRootCause().getMessage())
.append(")");
}
return result.toString();
}
}

View File

@ -1,811 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.EventListenerList;
import com.arsdigita.bebop.event.FormCancelListener;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.FormSubmissionListener;
import com.arsdigita.bebop.event.FormValidationListener;
import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Iterator;
/**
* A standalone section of a <code>Form</code>. A <code>FormSection</code>
* contains other Bebop components, most importantly <code>Widgets</code> and
* associated listeners. It serves two purposes:
* <UL>
* <LI>Divides a form into visual sections</LI>
* <LI>Serves as a container for form fragments that can function by themselves
* and can be dropped into other forms</LI>
* </UL>
* <p>
* Since a <code>FormSection</code> has its own init, validation, and process
* listeners, it can do all of its processing without any intervention from the
* enclosing form.
*
* Although a <code>FormSection</code> contains all the same pieces that a
* <code>Form</code> does, it can only be used if it is added directly or
* indirectly to a <code>Form</code>. <code>FormSection</code>s that are not
* contained in a <code>Form</code> do not exhibit any useful behavior.
*
* @see Form
* @see FormModel
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Stas Freidin
* @author Rory Solomon
* @author David Lutterkort
*/
public class FormSection extends DescriptiveComponent implements Container {
/**
* Internal logger instance to faciliate debugging. Enable logging output by
* editing /WEB-INF/conf/log4j.properties int the runtime environment and
* set com.arsdigita.subsite.FormSection=DEBUG by uncommenting or adding the
* line.
*/
private static final Logger LOGGER = LogManager.getLogger(FormSection.class);
/**
* Underlying <code>FormModel</code> that stores the parameter models for
* all the widgets in this form section.
*/
protected FormModel m_formModel;
/**
* The container to which all children are added. A <code>ColumnPanel</code>
* by default.
*/
protected Container m_panel;
/**
* Contains all the listeners that were added with the various
* addXXXListener methods. We maintain our own list of listeners, so that we
* can re-send the events the FormModel generates, but with us as the
* source, not the FormModel.
*/
private EventListenerList m_listeners;
/**
* Listeners we attach to the FormModel to forward form model events to our
* listeners with the right source
*/
private FormSubmissionListener m_forwardSubmission;
private FormInitListener m_forwardInit;
private FormValidationListener m_forwardValidation;
private FormProcessListener m_forwardProcess;
/**
* Constructs a new form section. Sets the implicit layout Container of this
* <code>FormSection</code> to two column <code>ColumnPanel</code> by
* calling the 1-argument constructor.
*
*/
public FormSection() {
this(new ColumnPanel(2, true));
}
/**
* Constructs a new form section. Sets the form model of this
* <code>FormSection</code> to a new, anonymous FormModel.
*
* @param panel
*
*/
public FormSection(Container panel) {
this(panel, new FormModel("anonymous"));
}
/**
* Constructs a new form section. Sets the implicit layout Container of this
* <code>FormSection</code> to <code>panel</code>. Sets the form model of
* this <code>FormSection</code> to <code>model</code>.
*
* @param panel the container within this form section that holds the
* components that are added to the form section with calls to
* the <code>add</code> methods
*
* @param model the form model for this form section
*
*/
protected FormSection(Container panel, FormModel model) {
super();
m_panel = panel;
m_formModel = model;
m_listeners = new EventListenerList();
}
/**
* Adds a listener that is called as soon as the {@link FormData} has been
* initialized with the request parameters but before any of the init,
* validation, or process listeners are run. The listener's
* <code>submitted</code> method may throw a
* <code>FormProcessException</code> to signal that any further processing
* of the form should be aborted.
*
* @param listener a submission listener to run every time the form is
* submitted
*
* @see FormModel#addSubmissionListener
* @pre listener != null
*/
public void addSubmissionListener(FormSubmissionListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Adding submission listener " + listener + " to "
+ this);
}
Assert.exists(listener, "Submission Listener");
Assert.isUnlocked(this);
forwardSubmission();
m_listeners.add(FormSubmissionListener.class, listener);
}
/**
* Removes the specified submission listener from the list of submission
* listeners (if it had previously been added).
*
* @param listener the submission listener to remove
*/
public void removeSubmissionListener(FormSubmissionListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Removing submission listener " + listener + " from "
+ this);
}
Assert.exists(listener, "Submission Listener");
Assert.isUnlocked(this);
m_listeners.remove(FormSubmissionListener.class, listener);
}
/**
* Calls the <code>submitted</code> method on all registered submission
* listeners.
*
* @param e the event to pass to the listeners
*
* @throws FormProcessException if one of the listeners throws such an
* exception.
*/
protected void fireSubmitted(FormSectionEvent e)
throws FormProcessException {
Assert.exists(e.getFormData(), "FormData");
FormProcessException delayedException = null;
Iterator i = m_listeners.getListenerIterator(
FormSubmissionListener.class);
while (i.hasNext()) {
final FormSubmissionListener listener = (FormSubmissionListener) i.
next();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Firing submission listener " + listener);
}
try {
listener.submitted(e);
} catch (FormProcessException ex) {
LOGGER.debug(ex);
delayedException = ex;
}
}
if (delayedException != null) {
throw delayedException;
}
}
/**
*
*/
protected void forwardSubmission() {
if (m_forwardSubmission == null) {
m_forwardSubmission = createSubmissionListener();
getModel().addSubmissionListener(m_forwardSubmission);
}
}
/**
* Creates the submission listener that forwards submission events to this
* form section.
*
* @return a submission listener that forwards submission events to this
* form section.
*/
protected FormSubmissionListener createSubmissionListener() {
return new FormSubmissionListener() {
@Override
public void submitted(FormSectionEvent e)
throws FormProcessException {
fireSubmitted(new FormSectionEvent(FormSection.this,
e.getPageState(),
e.getFormData()));
}
};
}
/**
* Adds a listener for form initialization events. Initialization events
* occur when a form is initially requested by the user, but not when the
* form is subsequently submitted. They typically perform actions such as
* querying the database for existing values to set up an edit form, or
* obtaining a sequence value to set up a create form.
*
* @param listener an instance of a class that implements the
* <code>FormInitListener</code> interface
*
*/
public void addInitListener(FormInitListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Adding init listener " + listener + " to " + this);
}
Assert.exists(listener, "FormInitListener");
Assert.isUnlocked(this);
forwardInit();
m_listeners.add(FormInitListener.class, listener);
}
/**
* Removes the specified init listener from the list of init listeners (if
* it had previously been added).
*
* @param listener the init listener to remove
*/
public void removeInitListener(FormInitListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Removing init listener " + listener + " from " + this);
}
Assert.exists(listener, "Init Listener");
Assert.isUnlocked(this);
m_listeners.remove(FormInitListener.class, listener);
}
/**
* Calls the <code>init</code> method on all registered init listeners.
*
* @param e the event to pass to the listeners
*
* @throws FormProcessException if one of the listeners throws such an
* exception.
*/
protected void fireInit(FormSectionEvent e) throws FormProcessException {
Assert.exists(e.getFormData(), "FormData");
Assert.isLocked(this);
Iterator i = m_listeners.getListenerIterator(FormInitListener.class);
while (i.hasNext()) {
final FormInitListener listener = (FormInitListener) i.next();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Firing init listener " + listener);
}
listener.init(e);
}
}
/**
*
*/
protected void forwardInit() {
if (m_forwardInit == null) {
m_forwardInit = createInitListener();
getModel().addInitListener(m_forwardInit);
}
}
/**
* Creates the init listener that forwards init events to this form section.
*
* @return an init listener that forwards init events to this form section.
*/
protected FormInitListener createInitListener() {
return new FormInitListener() {
@Override
public void init(FormSectionEvent e)
throws FormProcessException {
fireInit(new FormSectionEvent(FormSection.this,
e.getPageState(),
e.getFormData()));
}
};
}
/**
* Creates the cancel listener that forwards cancel events to this form
* section
*
* @return an cancel listener
*/
protected FormCancelListener createCancelListener() {
return new FormCancelListener() {
@Override
public void cancel(FormSectionEvent e) throws FormProcessException {
fireCancel(new FormSectionEvent(FormSection.this,
e.getPageState(),
e.getFormData()));
}
};
}
/**
* Adds a validation listener, implementing a custom validation check that
* applies to the form as a whole. Useful for checks that require
* examination of the values of more than one parameter.
*
* @param listener an instance of a class that implements the
* <code>FormValidationListener</code> interface
*
*/
public void addValidationListener(FormValidationListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Adding validation listener " + listener + " to "
+ this);
}
Assert.exists(listener, "FormValidationListener");
Assert.isUnlocked(this);
forwardValidation();
m_listeners.add(FormValidationListener.class, listener);
}
/**
* Removes the specified validation listener from the list of validation
* listeners (if it had previously been added).
*
* @param listener a validation listener
*/
public void removeValidationListener(FormValidationListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Removing validation listener " + listener + " from "
+ this);
}
Assert.exists(listener, "Validation Listener");
Assert.isUnlocked(this);
m_listeners.remove(FormValidationListener.class, listener);
}
/**
* Calls the <code>validate</code> method on all registered validation
* listeners.
*
* @param e the event to pass to the listeners
*/
protected void fireValidate(FormSectionEvent e) {
FormData data = e.getFormData();
Assert.exists(data, "FormData");
Iterator i = m_listeners.getListenerIterator(
FormValidationListener.class);
while (i.hasNext()) {
try {
final FormValidationListener listener
= (FormValidationListener) i.next();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Firing validation listener " + listener);
}
listener.validate(e);
} catch (FormProcessException fpe) {
LOGGER.debug(fpe);
data.addError(fpe.getGlobalizedMessage());
}
}
}
protected void forwardValidation() {
if (m_forwardValidation == null) {
m_forwardValidation = createValidationListener();
getModel().addValidationListener(m_forwardValidation);
}
}
/**
* Create the validation listener that forwards validation events to this
* form section.
*
* @return a validation listener that forwards validation events to this
* form section.
*/
protected FormValidationListener createValidationListener() {
return new FormValidationListener() {
@Override
public void validate(FormSectionEvent e) {
fireValidate(new FormSectionEvent(FormSection.this,
e.getPageState(),
e.getFormData()));
}
};
}
/**
* Adds a listener for form processing events.
* <p>
* Process events only occur after a form submission has been successfully
* validated. They are typically used to perform a database transaction or
* other operation based on the submitted data.
* <p>
* Process listeners are executed in the order in which they are added.
*
* @param listener an instance of a class that implements the
* <code>FormProcessListener</code> interface
*
*/
public void addProcessListener(final FormProcessListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Adding process listener " + listener + " to " + this);
}
Assert.exists(listener, "FormProcessListener");
Assert.isUnlocked(this);
forwardProcess();
m_listeners.add(FormProcessListener.class, listener);
}
/**
* Removes the specified process listener from the list of process listeners
* (if it had previously been added).
*
* @param listener the process listener to remove
*/
public void removeProcessListener(FormProcessListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Removing process listener " + listener + " from "
+ this);
}
Assert.exists(listener, "Process Listener");
Assert.isUnlocked(this);
m_listeners.remove(FormProcessListener.class, listener);
}
protected void forwardProcess() {
if (m_forwardProcess == null) {
m_forwardProcess = createProcessListener();
getModel().addProcessListener(m_forwardProcess);
}
}
protected FormProcessListener createProcessListener() {
return new FormProcessListener() {
@Override
public void process(FormSectionEvent e)
throws FormProcessException {
fireProcess(new FormSectionEvent(FormSection.this,
e.getPageState(),
e.getFormData()));
}
};
}
/**
* Calls the <code>process</code> method on all registered process
* listeners.
*
* @param e the event to pass to the listeners
*
* @throws FormProcessException if one of the listeners throws such an
* exception.
*/
protected void fireProcess(FormSectionEvent e)
throws FormProcessException {
Assert.exists(e.getFormData(), "FormData");
Iterator i = m_listeners.getListenerIterator(FormProcessListener.class);
while (i.hasNext()) {
final FormProcessListener listener = (FormProcessListener) i.next();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Firing process listener " + listener);
}
listener.process(e);
}
}
/**
* Since a form section cannot be processed, always throws an error.
* (Processing of form sections is done by the form in which the section is
* contained.)
*
* @param data
*
* @return
*
* @throws javax.servlet.ServletException because processing a form section
* is not meaningful.
*/
public FormData process(PageState data)
throws javax.servlet.ServletException {
throw new UnsupportedOperationException();
}
/**
* Adds a listener for form cancellation events. Cancellation listeners are
* typically used to clean-up page state and potentially intermediate
* changes to the database.
*
* @param listener an instance of a class that implements the
* <code>FormCancelListener</code> interface
*
*/
public void addCancelListener(FormCancelListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Adding cancel listener " + listener + " to " + this);
}
Assert.exists(listener, "FormCancelListener");
Assert.isUnlocked(this);
m_listeners.add(FormCancelListener.class, listener);
}
/**
* Removes the specified cancellation listener from the list of cancellation
* listeners (if it had previously been added).
*
* @param listener the cancellation listener to remove
*/
public void removeCancelListener(FormCancelListener listener) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Removing cancel listener " + listener + " from "
+ this);
}
Assert.exists(listener, "Cancel Listener");
Assert.isUnlocked(this);
m_listeners.remove(FormCancelListener.class, listener);
}
/**
* Calls the <code>cancel</code> method on all registered cancellation
* listeners.
*
* @param e the event to pass to the listeners
*
* @throws FormProcessException if one of the listeners throws such an
* exception.
*/
protected void fireCancel(FormSectionEvent e)
throws FormProcessException {
Assert.exists(e.getFormData(), "FormData");
Iterator i = m_listeners.getListenerIterator(FormCancelListener.class);
while (i.hasNext()) {
final FormCancelListener listener = (FormCancelListener) i.next();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Firing cancel listener " + listener);
}
listener.cancel(e);
}
}
/**
* Traverses the children this FormSection, collecting parameter models and
* listeners into the supplied FormModel. Sets implicit pointers of widgets
* in this FormSection to the supplied Form.
*
* @param f pointer to the form that is set inside Widgets within this
* FormSection
* @param m the FormModel in which to merge ParameterModels and Listeners
*
*/
@Override
public void register(Form f, FormModel m) {
m.mergeModel(getModel());
}
/**
* Accessor method for this form's FormModel.
*
* @return FormModel The model of this form.
*
*/
protected final FormModel getModel() {
return m_formModel;
}
/**
* Locks this FormSection, its FormModel, and the implicit Container.
*
*/
@Override
public void lock() {
m_formModel.lock();
m_panel.lock();
super.lock();
}
@Override
public void respond(PageState state) throws javax.servlet.ServletException {
//call listeners here.
throw new UnsupportedOperationException();
}
/**
* Returns the implicit Container of this FormSection.
*
* This must not be final, because MetaFrom needs to override it.
*
* @return
*/
public Container getPanel() {
return m_panel;
}
/**
* Returns an iterator over the children of this component. If the component
* has no children, returns an empty iterator (not <code>null</code> !).
*
* @post return != null
*
*/
@Override
public Iterator children() {
return m_panel.children();
}
/**
* Builds an XML subtree for this component under the specified
* <code>parent</code>. Uses the request values stored in
* <code>state</code>.</p>
*
* <p>
* This method generates DOM to be used with the XSLT template to produce
* the appropriate output.</p>
*
* @param pageState the state of the current page
* @param parent the node that will be used to write to
*
*/
@Override
public void generateXML(PageState pageState, Element parent) {
if (isVisible(pageState)) {
m_panel.generateXML(pageState, parent);
}
}
// Container methods
/**
* Adds a component to this container.
*
* @param pc the component to add to this container
*
*/
@Override
public void add(Component pc) {
m_panel.add(pc);
}
/**
* Adds a component with the specified layout constraints to this container.
* Layout constraints are defined in each layout container as static ints.
* Use a bitwise OR to specify multiple constraints.
*
* @param pc the component to add to this container
* @param constraints layout constraints (a bitwise OR of static ints in the
* particular layout)
*/
@Override
public void add(Component pc, int constraints) {
m_panel.add(pc, constraints);
}
/**
* Returns <code>true</code> if this list contains the specified element.
* More formally, returns true if and only if this list contains at least
* one element e such that (o==null ? e==null : o.equals(e)).
*
* This method returns <code>true</code> only if the component has been
* directly added to this container. If this container contains another
* container that contains this component, this method returns
* <code>false</code>.
*
* @param o element whose presence in this container is to be tested
*
* @return <code>true</code> if this Container contains the specified
* component directly; <code>false</code> otherwise.
*
*
*/
@Override
public boolean contains(Object o) {
return m_panel.contains(o);
}
/**
* Returns the Component at the specified position. Each call to add()
* increments the index. This method should be used in conjunction with
* indexOf
*
* @param index The index of the item to be retrieved from this Container.
* Since the user has no control over the index of added
* components (other than counting each call to add), this
* method should be used in conjunction with indexOf.
*
* @return the component at the specified position in this container
*
*/
@Override
public Component get(int index) {
return (Component) m_panel.get(index);
}
/**
*
*
*
* @param pc component to search for
*
* @return the index in this list of the first occurrence of the specified
* element, or -1 if this list does not contain this element.
*
*/
@Override
public int indexOf(Component pc) {
return m_panel.indexOf(pc);
}
/**
* Determines whether the container contains any components.
*
* @return <code>true</code> if this container contains no components
* <code>false</code> otherwise.
*
*/
@Override
public boolean isEmpty() {
return m_panel.isEmpty();
}
/**
* Returns the number of elements in this container. This does not
* recursively count the components indirectly contained in this container.
*
* @return the number of components directly in this container.
*
*/
@Override
public int size() {
return m_panel.size();
}
}

View File

@ -1,192 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.form.Widget;
import com.arsdigita.bebop.parameters.BooleanParameter;
import com.arsdigita.bebop.util.Traversal;
import com.arsdigita.xml.Element;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* The FormStep class modifies the behavior of FormSection with respect to
* listener firing. Instead of firing init listeners the first time the
* enclosing form is displayed on the page, the FormStep class fires init
* listeners the first time the FormStep itself is displayed on the page. The
* process, validate, and submission listeners are then fired on every
* submission following the one in which the init listeners were fired. This
* behavior is useful when used in conjunction with {@link MultiStepForm} or its
* subclasses to provide initialization in later steps of a multi step form that
* depends on the values entered in earlier steps.
*
* updated chris.gilbert@westsussex.gov.uk - support for session based wizards
* (which enable use of actionlinks in wizard)
*
* @see Wizard
* @see MultiStepForm
*
* @author <a href="mailto:rhs@mit.edu">rhs@mit.edu</a>
*
*/
public class FormStep extends FormSection {
private final static Logger LOGGER = LogManager.getLogger(FormStep.class);
private Form m_form = null;
// cg - changed to using a parameter that is stored in pagestate so that if there are links
// within the form then the init status of the steps is not lost
// private Hidden m_initialized;
private BooleanParameter m_initialized;
/**
* Constructs a new FormStep with the given name. The name must uniquely
* identify this FormStep within it's enclosing Form.
*
* @param name A name that uniquely identifies this FormStep within it's
* enclosing Form.
*
*/
public FormStep(String name) {
addInitialized(name);
}
/**
* Constructs a new FormStep with the given name. The name must uniquely
* identify this FormStep within it's enclosing Form.
*
* @param name A name that uniquely identifies this FormStep within it's
* enclosing Form.
* @param panel The container used to back this FormStep.
*
*/
public FormStep(String name, Container panel) {
super(panel);
addInitialized(name);
}
protected FormStep(String name, Container panel, FormModel model) {
super(panel, model);
addInitialized(name);
}
public void register(Page p) {
super.register(p);
p.addComponentStateParam(this, m_initialized);
Traversal trav = new Traversal() {
protected void act(Component c) {
if (c instanceof Widget) {
((Widget) c).setValidateInvisible(false);
}
}
};
trav.preorder(this);
}
public void register(Form form, FormModel model) {
super.register(form, model);
m_form = form;
}
private void addInitialized(String name) {
// m_initialized = new Hidden(new BooleanParameter(name));
// add(m_initialized);
m_initialized = new BooleanParameter(name);
m_initialized.setDefaultValue(Boolean.FALSE);
}
public boolean isInitialized(PageState ps) {
// Object init = m_initialized.getValue(ps);
Boolean init = (Boolean) ps.getValue(m_initialized);
if (init == null) {
LOGGER.debug("init for step " + m_initialized.getName()
+ " is null. returning true");
// happens if step state is stored in session -
// form containing this step clears session
// info when processed, but fireProcess invoked
// on this step AFTER form is processed. At that point,
// the step has been initialised because we are on the
// final process at the end of the steps
//
init = Boolean.TRUE;
}
return init.booleanValue();
}
private void setInitialized(PageState ps) {
//m_initialized.setValue(ps, Boolean.TRUE);
ps.setValue(m_initialized, Boolean.TRUE);
}
// Turn off forwarding of init events.
protected FormInitListener createInitListener() {
return new FormInitListener() {
public void init(FormSectionEvent evt) {
}
};
}
protected void fireSubmitted(FormSectionEvent evt)
throws FormProcessException {
if (isInitialized(evt.getPageState())) {
super.fireSubmitted(evt);
}
}
protected void fireValidate(FormSectionEvent evt) {
if (isInitialized(evt.getPageState())) {
super.fireValidate(evt);
}
}
protected void fireProcess(FormSectionEvent evt)
throws FormProcessException {
LOGGER.debug("fireprocess invoked on Formstep " + m_initialized
.getName());
if (isInitialized(evt.getPageState())) {
super.fireProcess(evt);
}
}
public void generateXML(PageState ps, Element parent) {
if (!isInitialized(ps)) {
FormData fd = m_form.getFormData(ps);
try {
fireInit(new FormSectionEvent(this, ps, fd));
setInitialized(ps);
} catch (FormProcessException ex) {
LOGGER.debug("initialization aborted", ex);
fd.addError("Initialization Aborted: " + ex.getMessages());
}
}
super.generateXML(ps, parent);
}
}

View File

@ -1,344 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.bebop.util.PanelConstraints;
import com.arsdigita.bebop.form.Hidden;
import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* <p>A container that prints its components in a table. Each child is
* printed in its own table cell. The number of columns can be
* specified in the constructor. The components are put into the table
* in the order in which they were added to the <code>GridPanel</code>
* by filling the table one row
* at a time (filling each row from left to right), from the top of the table
* to the bottom.</p>
*
* <p>The position of the component within the cell can be influenced
* with the following constraints.</p>
*
* <TABLE border=0>
* <tr>
* <TD nowrap valign="top">Horizontal alignment</TD>
* <Td valign="top">Use <code>LEFT</code>, <code>CENTER</code>, or
* <code>RIGHT</code>.</td></tr>
* <tr>
* <td nowrap valign="top">Vertical alignment</td>
* <td valign="top">Use <code>TOP</code>, <code>MIDDLE</code>, or
* <code>BOTTOM</code>.</td></tr>
* <tr>
* <td nowrap valign="top">Full width</td>
* <td valign="top">Use <code>FULL_WIDTH</code> to instruct the panel to put
* the component in a row by itself, spanning the full width of the
* table.</td></tr>
* <tr>
* <td nowrap valign="top">Inserting children</td>
* <td valign="top">Use <code>INSERT</code> to instruct the panel to
* insert the corresponding component, assuming that it will also be
* laid out by a <code>ColumnPanel</code> with the same number of
* columns.</td></tr>
* </TABLE>
*
* </dl>
*
* <p>Constraints can be combined by
* ORing them together. For example, to print a component in a row of its
* own, left-aligned, at the bottom of its cell, use the constraint
* <code>FULL_WIDTH | LEFT | BOTTOM</code>.</p>
*
* <p>Using the <code>INSERT</code> constraint fuses the current
* <code>GridPanel</code> with the panel of the child to which the
* constraint is applied. For example, consider a {@link Form}, that
* is to have a 2-column format with labels in the left column
* and widgets in the right column. If a {@link FormSection} is added to
* the form, it should be included seamlessly into the parent
* form. To do this, set the <code>INSERT</code>
* constraint when the {@link FormSection} is added to the {@link
* Form}'s <code>GridPanel</code>. At the same time, tell the
* <code>GridPanel</code> used to lay out the {@link FormSection}
* that it is is to be inserted into another panel.
* The following
* pseudo-code illustrates the example. (It assumes that Form and
* FormSection are decorators of the GridPanel.)</p>
*
* <blockquote><pre>
* Form form = new Form(new GridPanel(2));
* FormSection sec = new FormSection(new GridPanel(2, true));
* // "true" in the above constructor tells the GridPanel it is inserted.
*
* sec.add(new Label("Basic Item Metadata"), GridPanel.FULL_WIDTH);
* sec.add(new Label("Title:"), GridPanel.RIGHT);
* sec.add(new Text("title"));
*
* form.add(sec, GridPanel.INSERT);
* </pre></blockquote>
*
* @see BoxPanel
* @see SplitPanel
* @author David Lutterkort
* @author Stanislav Freidin
* @author Justin Ross
* @version $Id: GridPanel.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class GridPanel extends SimpleContainer
implements BebopConstants, PanelConstraints {
private static final ChildConstraint DEFAULT_CONSTRAINT
= new ChildConstraint();
private int m_numColumns;
/*
* Explicitly registered constraints for child components. Maps
* <code>Components</code>s to <code>Constraints</code>
*/
private Map m_childConstraintMap;
/*
* Is this panel inserted in another one? If so, do not produce
* &lt;table&gt; tags.
*/
private boolean m_isInserted;
/**
* Creates a table panel with the specified number of columns.
*
* @param numColumns the number of columns in the panel
*/
public GridPanel(int numColumns) {
this(numColumns, false);
}
/**
* Creates a table panel with the specified number of columns and
* indicates whether the panel is inserted.
*
* @param numColumns the number of columns in the panel
* @param isInserted <code>true</code> if this panel is to be
* printed as a direct child of a <code>GridPanel</code>
* with the same number of columns
* @see #setInserted
*/
public GridPanel(int numColumns, boolean isInserted) {
m_numColumns = numColumns;
setInserted(isInserted);
m_childConstraintMap = new HashMap();
}
/**
* Adds a component, specifying constraints.
* @param component the component to add
* @param constraints the constraints for the component
*/
public void add(Component component, int constraints) {
super.add(component);
m_childConstraintMap.put(component, new ChildConstraint(constraints));
}
/**
* Sets whether this panel will be printed inside a
* <code>GridPanel</code> with the same number of columns. If
* <code>inserted</code> is <code>true</code>, no &lt;table&gt; tags will be
* produced to enclose the child components.
* @param <code>true</code> if this panel is to be printed
* inside a GridPanel with the same number of columns
*
*/
public void setInserted(boolean isInserted) {
Assert.isUnlocked(this);
m_isInserted = isInserted;
}
/**
* Determines whether this panel is to be inserted into another panel.
* @return <code>true</code> if this panel is to be inserted into another panel;
* <code>false</code> otherwise.
* @see #setInserted
*/
public final boolean isInserted() {
return m_isInserted;
}
/**
* Adds child components as a subtree under table-style nodes. If any of the
* direct children are hidden form widgets, they are added directly to
* <code>parent</code> rather than included in any of the
* <code>cell</code> elements of the panel.
*
* <p>Generates a DOM fragment:
* <p><code><pre>
* &lt;bebop:gridPanel>
* &lt;bebop:panelRow>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* ...
* &lt;/bebop:panelRow>
* &lt;bebop:panelRow>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* ...
* &lt;/bebop:panelRow>
* &lt;/bebop:gridPanel></pre></code>
*
* @param pageState
* @param parent
*/
@Override
public void generateXML(PageState pageState, Element parent) {
if (isVisible(pageState)) {
if (isInserted()) {
generateChildren(pageState, parent);
} else {
Element panel = parent.newChildElement(BEBOP_GRIDPANEL, BEBOP_XML_NS);
exportAttributes(panel);
generateChildren(pageState, panel);
}
}
}
/*
* Lay out the child components using constraints registered for them,
* generating a DOM tree and extending another.
*/
private void generateChildren(PageState pageState, Element parent) {
int positionInRow = 0;
boolean newRowRequested = true; // First time through we want a new row.
Element row = null;
Element cell = null;
ChildConstraint constraint = null;
Iterator iter = children();
while (iter.hasNext()) {
Component child = (Component)iter.next();
if (child.isVisible(pageState)) {
if (child instanceof Hidden) {
child.generateXML(pageState, parent);
} else {
constraint = getChildConstraint(child);
if (constraint.m_isInsert) {
child.generateXML(pageState, parent);
newRowRequested = true;
} else {
if (positionInRow >= m_numColumns
|| constraint.m_isFullWidth
|| newRowRequested) {
positionInRow = 0;
row = parent.newChildElement(BEBOP_PANELROW, BEBOP_XML_NS);
if (constraint.m_isFullWidth) {
// If the column was full width, we
// want a new row in the next iteration.
newRowRequested = true;
} else if (newRowRequested) {
// Reset to off.
newRowRequested = false;
}
}
cell = row.newChildElement(BEBOP_CELL, BEBOP_XML_NS);
child.generateXML(pageState, cell);
constraint.exportCellAttributes(cell, m_numColumns);
positionInRow++;
}
}
}
}
}
/*
* Helper stuff
*/
private ChildConstraint getChildConstraint(Component component) {
ChildConstraint constraint =
(ChildConstraint)m_childConstraintMap.get(component);
if (constraint == null) {
constraint = DEFAULT_CONSTRAINT;
}
return constraint;
}
private static class ChildConstraint {
public boolean m_isFullWidth;
public boolean m_isInsert;
public String m_horizontalAlignment;
public String m_verticalAlignment;
public ChildConstraint() {
this(0);
}
public ChildConstraint(int constraints) {
if ((constraints & LEFT) != 0) {
m_horizontalAlignment = "left";
} else if ((constraints & CENTER) != 0) {
m_horizontalAlignment = "center";
} else if ((constraints & RIGHT) != 0) {
m_horizontalAlignment = "right";
} else {
m_horizontalAlignment = null;
}
if ((constraints & TOP) != 0) {
m_verticalAlignment = "top";
} else if ((constraints & MIDDLE) != 0) {
m_verticalAlignment = "middle";
} else if ((constraints & BOTTOM) != 0) {
m_verticalAlignment = "bottom";
} else {
m_verticalAlignment = null;
}
m_isFullWidth = (constraints & FULL_WIDTH) != 0;
m_isInsert = (constraints & INSERT) != 0;
}
public void exportCellAttributes(Element cell, int numColumns) {
if (m_horizontalAlignment != null) {
cell.addAttribute("align", m_horizontalAlignment);
}
if (m_verticalAlignment != null) {
cell.addAttribute("valign", m_verticalAlignment);
}
if (m_isFullWidth) {
cell.addAttribute("colspan", Integer.toString(numColumns));
}
}
}
}

View File

@ -1,191 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.xml.Element;
import com.arsdigita.util.Assert;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.bebop.event.PrintEvent;
/**
* A simple wrapper class for images.
*
* @author David Lutterkort
* @author Stanislav Freidin
*
* @version $Id$
*/
public class Image extends DescriptiveComponent {
private final String IMAGE_URL = "src";
private final String ALT = "alt";
private final String HEIGHT = "height";
private final String WIDTH = "width";
private final String BORDER = "border";
private PrintListener m_printListener;
public Image(String imageURL, String alt) {
super();
setImageURL(imageURL);
setAlt(alt);
}
public Image(String imageURL) {
this(imageURL, "");
}
/**
* Creates a new <code>Image</code> that uses the print listener
* to generate output.
*
* @param l the print listener used to produce output
*/
public Image(PrintListener l) {
this("");
addPrintListener(l);
}
public void setImageURL(String imageURL) {
Assert.isUnlocked(this);
setAttribute(IMAGE_URL, imageURL);
}
public void setAlt(String alt) {
Assert.isUnlocked(this);
setAttribute(ALT, alt);
}
/**
*
*
* @param height
*/
public void setHeight(String height) {
Assert.isUnlocked(this);
setAttribute(HEIGHT, height);
}
/**
*
*
* @param width
*/
public void setWidth(String width) {
Assert.isUnlocked(this);
setAttribute(WIDTH, width);
}
/**
*
*
* @param border
*/
public void setBorder(String border) {
Assert.isUnlocked(this);
setAttribute(BORDER, border);
}
/**
* Adds a print listener. Only one print listener can be set for an
* image, since the <code>PrintListener</code> is expected to modify the
* target of the <code>PrintEvent</code>.
* @param listener the print listener
* @throws IllegalArgumentException if <code>listener</code> is null.
* @throws IllegalStateException if a print listener has previously been
* added.
* @pre listener != null */
public void addPrintListener(PrintListener listener)
throws IllegalStateException, IllegalArgumentException
{
if ( listener == null ) {
throw new IllegalArgumentException
("Argument listener can not be null");
}
if ( m_printListener != null ) {
throw new IllegalStateException
("Too many listeners. Can only have one");
}
m_printListener = listener;
}
/**
* Removes a previously added print listener. If <code>listener</code> is
* not the listener that was added with {@link #addPrintListener
* addPrintListener}, an IllegalArgumentException will be thrown.
* @param listener the listener that was previously added with
* <code>addPrintListener</code>
* @throws IllegalArgumentException if <code>listener</code> is not the
* currently registered print listener or is <code>null</code>.
* @pre listener != null
*/
public void removePrintListener(PrintListener listener)
throws IllegalArgumentException
{
if ( listener == null ) {
throw new IllegalArgumentException("listener can not be null");
}
if ( listener != m_printListener ) {
throw new IllegalArgumentException
("listener is not registered with this widget");
}
m_printListener = null;
}
/**
* Writes the output to a DOM to be used with the XSLT template
* to produce the appropriate output.
*
* <p>Generates DOM fragment:
* <p><code><pre>
* &lt;bebop:image [src=...] [alt=...] [height=...]
* [width=...] [border=...]/>
* </pre></code>
*
* @param parent the XML element to which the form adds its XML representation
* */
@Override
public void generateXML(PageState state, Element parent) {
if ( ! isVisible(state) ) {
return;
}
Image target = firePrintEvent(state);
Element image = parent.newChildElement ("bebop:image", BEBOP_XML_NS);
target.exportAttributes(image);
}
protected Image firePrintEvent(PageState state) {
Image i = this;
if ( m_printListener != null ) {
try {
i = (Image) this.clone();
m_printListener.prepare(new PrintEvent(this, state, i));
} catch ( CloneNotSupportedException e ) {
// FIXME: Failing silently here isn't so great
// It probably indicates a serious programming error
i = this;
}
}
return i;
}
}

View File

@ -1,447 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.PrintEvent;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.util.Assert;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.xml.Element;
/**
* A text label displayed to the user for information about and identification
* of certain parts of the screen. Therefore the label has to use a
* GlobalizedMessage for the information presented.
*
* A Label is meant to provide semantically relevant information and may not be
* used for fixed arbitrary Text. Use Embedded instead.
*
* (Previous usage: can be used to generate either some static, fixed
* text or a new text string for every request.)
*
* To modify the information with an already locked label use the {@link
* #setLabel(String,PageState)} method which can adjust for each request.
*
* @author David Lutterkort
* @version $Id: Label.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class Label extends DescriptiveComponent implements Cloneable {
public static final String BOLD = "b";
public static final String ITALIC = "i";
// the default label
private GlobalizedMessage m_label;
// a requestlocal set of labels (to avoid printlisteners)
private final RequestLocal m_requestLabel = new RequestLocal();
private String m_fontWeight;
/** The setting for output escaping affects how markup in the
* <code>content</code> is handled.
* <UL><LI>If output escaping is in effect (true), &lt;b>example&lt;/b>
* will appear literally.</LI>
* <LI>If output escaping is disabled, &lt;b>example&lt;/b> appears as the
* String "example" in bold (i.e. retaining the markup.</LI></UL>
* Default is false. */
private boolean m_escaping = false; // default for a primitive anyway
private PrintListener m_printListener;
/**
* Constructor creates a new <code>Label</code> with empty text.
*/
public Label() {
// A kind of fallback (or a hack) here. Parameter label is taken as
// a key for some (unknown) Resource bundle. Because GlobalizedMessage
// will not find a corrresponding message it will display the key
// itself, 'faking' a globalized message.
m_label = new GlobalizedMessage(" ");
}
/**
* Creates a new <code>Label</code> with the specified (fixed) text.
*
* @param label the text to display
* @deprecated refactor to use Label(GlobalizedMessage label) instead
*/
public Label(String label) {
this(label, true);
}
/**
* Creates a new <code>Label</code> with the specified text and
* output escaping turned on if <code>escaping</code> is <code>true</code>.
*
* The setting for output escaping affects how markup in the
* <code>label</code> is handled. For example:
* <UL><LI>If output escaping is in effect, &lt;b>text&lt;/b> will appear
* literally.</LI>
* <LI>If output escaping is disabled, &lt;b>text&lt;/b> appears as the
* word "text" in bold.</LI></UL>
*
* @param label the text to display
* @param escaping <code>true</code> if output escaping will be in effect;
* <code>false</code> if output escaping will be disabled
*
* @deprecated refactor to Label(GlobalizedMessage label, boolean escaping)
* instead
*/
public Label(String label, boolean escaping) {
setLabel(label);
setOutputEscaping(escaping);
}
/**
* <p> Creates a new label with the specified text. </p>
*
* @param label the text to display
*/
public Label(GlobalizedMessage label) {
this(label, true);
}
/**
* Creates a new label with the specified text as GlobalizedMessage
* and fontweight.
*
* @param label The text to display as GlobalizedMessage
* @param fontWeight The fontWeight e.g., Label.BOLD. Whether it has any
* effect depends on the theme! Take it just as a hint.
*/
public Label(GlobalizedMessage label, String fontWeight) {
this(label, true);
m_fontWeight = fontWeight;
}
/**
* <p> Creates a new label with the specified text as GlobalizedMessage
* and output escaping turned on if <code>escaping</code> is
* <code>true</code>. </p>
*
* @param label the text to display as GlobalizedMessage
* @param escaping Whether or not to perform output escaping
*/
public Label(GlobalizedMessage label, boolean escaping) {
setLabel(label);
setOutputEscaping(escaping);
}
/**
* Creates a new <code>Label</code> that uses the print listener to
* generate output.
*
* @param l the print listener used to produce output
*/
public Label(PrintListener l) {
this();
addPrintListener(l);
}
/**
* Creates a new label with the specified text and fontweight.
*
* @param label The text to display
* @param fontWeight The fontWeight e.g., Label.BOLD
*
* @deprecated without direct replacement. Refactor to use
* Label(GlobalizedMEssage) instead and modify the theme to
* use proper text marking. (Or use setFontWeight separately.
*/
public Label(String label, String fontWeight) {
this(label, true);
m_fontWeight = fontWeight;
}
/**
* Provides the Label as Text, localized for the current request.
*
* Although it is not recommended, this method may be overridden to
* dynamically generate the text of the label. Overriding code may need
* the page state.
* <p>
* If possible, derived classes should override {@link #getLabel()} instead,
* which is called from this method. As long as we don't have a static
* method to obtain ApplicationContext, this is a way to get the
* RequestContext (to determine the locale). When ApplicationContext gets
* available, that will become the suggested way for overriding code to get
* context.
*
* @param state the current page state
* @return the string produced for this label
*/
public String getLabel(PageState state) {
return (String) getGlobalizedMessage(state).localize(state.getRequest());
}
// /**
// * .
// *
// * This method may be overridden to dynamically generate the default text of
// * the label.
// *
// * @return the string produced for this label.
// *
// * @deprecated Use {@link #getGlobalizedMessage()}
// */
// Conflicts with Super's getLabel message of type GlobalizedMessage. But isn't
// needed anyway. Should deleted as soon as the refactoring of Label is
// completed (i.e. any string Label ironed out).
// public String getLabel() {
// return getGlobalizedMessage().getKey();
// }
/**
* <p> This should really be getLabel(), but since it was marked STABLE I
* can't change its return type. </p>
*
* @return the default label to display.
*/
public GlobalizedMessage getGlobalizedMessage() {
return getGlobalizedMessage(null);
}
/**
* <p> This should really be getLabel(), but since it was marked STABLE I
* can't change its return type. </p>
*
* @param state the current PageState
* @return the label to display for this request, or if state is null, the
* default label
*/
public GlobalizedMessage getGlobalizedMessage(PageState state) {
if (state != null) {
GlobalizedMessage dynlabel =
(GlobalizedMessage) m_requestLabel.get(state);
if (dynlabel != null) {
return dynlabel;
}
}
return m_label;
}
/**
* Sets new default text for this Label.
*
* @param label The new label text; will be used as a key into the current
* ResourceBundle if possible, or displayed literally.
* @deprecated refactor to use
* @see setLabel(GlobalizedMessage) instead!
*/
public void setLabel(String label) {
setLabel(label, null);
}
/**
* Sets new request-specific text for this Label to use on this request. If
* state is null, then sets the default text instead.
*
* @param label The new label text; will be used as a key into the current
* ResourceBundle if possible, or displayed literally.
* @param state the page state
* @pre state == null implies !isLocked()
* @deprecated refactor to use
* @see setLabel(GlobalizedMessage, PageState) instead!
*/
public void setLabel(String label, PageState state) {
if (label == null || label.length() == 0) {
label = " ";
}
// A kind of fallback (or a hack) here. Parameter label is taken as
// a key for some (unknown) Resource bundle. Because GlobalizedMessage
// will not find a corrresponding message it will display the key
// itself, 'faking' a globalized message.
setLabel(new GlobalizedMessage(label), state);
}
/**
* Sets the text for this label using a GlobalizedMessage.
*
* @param label The GlobalizedMessage containing the label text or the
* lookup key to use in the ResourceBundle
* @param state the current page state; if null, sets the default text for
* all requests.
* @pre state == null implies !isLocked()
*/
public void setLabel(GlobalizedMessage label, PageState state) {
if (state == null) {
Assert.isUnlocked(this);
m_label = label;
} else {
m_requestLabel.set(state, label);
}
}
/**
* Sets the default text for this Label.
*
* Overwrites parent's method an therefore prevents the usage of parent's
* label methods (which are attributes, but here it is the content).
*
* @param label The GlobalizedMessage containing the label text or the
* lookup key to use in the ResourceBundle
*/
@Override
public void setLabel(GlobalizedMessage label) {
setLabel(label, null);
}
public final boolean getOutputEscaping() {
return m_escaping;
}
/**
* Controls whether output is escaped during transformation, by default
* true. If true, it will be printed literally, and the user will see
* &lt;b&gt;. When false, the browser will interpret as a bold tag.
*
* @param escaping
*/
public final void setOutputEscaping(boolean escaping) {
m_escaping = escaping;
}
public final String getFontWeight() {
return m_fontWeight;
}
public void setFontWeight(String fontWeight) {
Assert.isUnlocked(this);
m_fontWeight = fontWeight;
}
/**
* Adds a print listener. Only one print listener can be set for a label,
* since the <code>PrintListener</code> is expected to modify the target
* of the <code>PrintEvent</code>.
*
* @param listener the print listener
* @throws IllegalArgumentException if <code>listener</code> is null.
* @throws IllegalStateException if a print listener has previously been
* added.
* @pre listener != null
*/
public void addPrintListener(PrintListener listener)
throws IllegalStateException, IllegalArgumentException {
if (listener == null) {
throw new IllegalArgumentException("Argument listener can not be null");
}
if (m_printListener != null) {
throw new IllegalStateException("Too many listeners. Can only have one");
}
m_printListener = listener;
}
/**
* Removes a previously added print listener. If <code>listener</code> is
* not the listener that was added with {@link #addPrintListener
* addPrintListener}, an IllegalArgumentException will be thrown.
*
* @param listener the listener that was added with
* <code>addPrintListener</code>
* @throws IllegalArgumentException if <code>listener</code> is not the
* currently registered print listener or is <code>null</code>.
* @pre listener != null
*/
public void removePrintListener(PrintListener listener)
throws IllegalArgumentException {
if (listener == null) {
throw new IllegalArgumentException("listener can not be null");
}
if (listener != m_printListener) {
throw new IllegalArgumentException("listener is not registered with this widget");
}
m_printListener = null;
}
/**
* Generates the (J)DOM fragment for a label.
* <p><pre>
* &lt;bebop:link href="..." type="..." %bebopAttr;/>
* </pre>
*
* @param state The current {@link PageState}.
* @param parent The XML element to attach the XML to.
*/
@Override
public void generateXML(PageState state, Element parent) {
if (!isVisible(state)) {
return;
}
Label target = firePrintEvent(state);
Element label = parent.newChildElement("bebop:label", BEBOP_XML_NS);
target.exportAttributes(label);
target.generateDescriptionXML(state, label);
String weight = target.getFontWeight();
if (weight != null && weight.length() > 0) {
label.addAttribute("weight", weight);
}
if (!target.m_escaping) {
label.addAttribute("escape", "yes");
} else {
label.addAttribute("escape", "no");
}
String key = getGlobalizedMessage()
.getKey()
.substring(getGlobalizedMessage()
.getKey().lastIndexOf(".") + 1);
// This if clause is needed to prevent printing of keys if the
// GlobalizedMessage was created from a String by this class
if(!key.equals(target.getLabel(state))) {
label.addAttribute("key", key);
}
/*
* This may break with normal JDOM. We may need to have a node for
* the case where there is no weight. The problem comes in that
* setText *may* kill the other content in the node. It will kill
* the other text, so it may be a good idea anyways.
*/
label.setText(target.getLabel(state));
}
/**
*
* @param state
* @return
*/
protected Label firePrintEvent(PageState state) {
Label l = this;
if (m_printListener != null) {
try {
l = (Label) this.clone();
m_printListener.prepare(new PrintEvent(this, state, l));
} catch (CloneNotSupportedException e) {
throw new RuntimeException(
"Couldn't clone Label for PrintListener. "
+ "This probably indicates a serious programming error: "
+ e.getMessage());
}
}
return l;
}
}

View File

@ -1,332 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.arsdigita.xml.Element;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.util.Assert;
import com.arsdigita.web.URL;
import com.arsdigita.web.ParameterMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* A URL on a page. May contain a label, an image, or any other component. A
* Link is a BaseLink that manages URL variables.
*
* <p>
* <b>Example:</b> The common usage for a Link component is illustrated in the
* code fragment below:
*
* <pre>
* Page p = new Page("Link Example");
* Link link = new Link(new Label(GlobalizedMessage),"path/to/target/");
* link.setVar("foo","1");
* p.add(link);
* </pre>
*
* <p>
* The target of the link above will be rendered in HTML as:
* <tt>href="path/to/target/?foo=1"</tt>
* If either the link text or the URL needs to be changed for a link within a
* locked page, a {@link PrintListener} should be used.
*/
public class Link extends BaseLink {
private static final Logger LOGGER = LogManager
.getLogger(ParameterMap.class);
private static final String FRAME_TARGET_ATTR = "target";
private URL m_webURL = null;
private ParameterMap m_params = new ParameterMap();
/**
* The value for the XML type attribute for a plain link.
*/
protected final String TYPE_LINK = "link";
/**
* <p>
* Passing this value to {@link #setTargetFrame setTargetFrame} will create
* a link that opens a new browser window whenever it is clicked.
* </p>
*
* @see #setTargetFrame
*/
public static final String NEW_FRAME = "_blank";
/**
* initialization steps common to all constructors
*/
private void init() {
setTypeAttr(TYPE_LINK);
}
/**
* Constructor creates a link taking url as the target and display it to the
* user at the same time. It is the only allowed way to present the user
* with a not globlized information. The implementation currently miss-uses
* the Label component to display just a not globalized String which is
* deprecated.
*
* @param url
*
* @deprecated use BaseLink(Component,url) instead with a Label using a
* GlobalizedMessage instead
*/
public Link(final String url) {
super(new Label(url), url);
}
/**
* Constructor, creates a link with a globalized label or an image as label.
*
* @param child The <tt>Component</tt> parameter in this constructor is
* usually a {@link Label} or {@link Image}.
* @param url Starting with release 5.2, this method prefixes the
* passed-in url with the path to the CCM dispatcher. Code
* using this constructor should not prefix <code>url</code>
* with the webapp context path or the dispatcher servlet path.
*
* The vast majority of CCM UI code expects to link through the dispatcher.
* Code that does not should use the <code>Link</code> constructor taking a
* <code>URL</code>.
*
* @see #Link(String,URL)
*/
public Link(Component child, String url) {
super(child, url);
init();
}
/**
* Constructors with <tt>PrintListener</tt> parameters allow for a
* {@link PrintListener} to be set for the Link, without the need to make a
* separate call to the <tt>addPrintListener</tt> method. PrintListeners are
* a convenient way to alter underlying Link attributes such as Link text or
* target URL within a locked page on a per request basis.
*
* @param child
* @param l
*/
public Link(Component child, PrintListener l) {
super(child, l);
init();
}
/**
* Constructors with <tt>PrintListener</tt> parameters allow for a
* {@link PrintListener} to be set for the Link, without the need to make a
* separate call to the <tt>addPrintListener</tt> method. PrintListeners are
* a convenient way to alter underlying Link attributes such as Link text or
* target URL within a locked page on a per request basis.
*
* @deprecated refactor to use Link(Component,PrintListener) to provide a
* globalized label for the link.
*/
public Link(String label, PrintListener l) {
super(label, l);
init();
}
/**
* Constructors with <tt>PrintListener</tt> parameters allow for a
* {@link PrintListener} to be set for the Link, without the need to make a
* separate call to the <tt>addPrintListener</tt> method. PrintListeners are
* a convenient way to alter underlying Link attributes such as Link text or
* target URL within a locked page on a per request basis.
*
* @param listener PrintListener, may be used to change either the Display
* text or the url within a locked page.
*/
public Link(PrintListener listener) {
super(listener);
init();
}
/**
* <p>
* This constructor is a common one for a Link component, as it allows for
* the Link text and the target URL to be set at the same time during
* construction.</p>
*
* <p>
* Starting with release 5.2, this method prefixes the passed-in
* <code>url</code> with the path to the CCM dispatcher. Code using this
* constructor should not prefix <code>url</code> with the webapp context
* path or the dispatcher servlet path.</p>
*
* <p>
* The vast majority of CCM UI code expects to link through the dispatcher.
* Code that does not should use the <code>Link</code> constructor taking a
* <code>URL</code>.</p>
*
* @see #Link(String,URL)
* @deprecated refactor to use Link(Component,PrintListener) to provide a
* globalized label for the link.
*/
public Link(String label, String url) {
super(label, url);
init();
}
/**
* <p>
* Constructs a Link using a <code>URL</code>. When this constructor is
* used, the method {@link #setVar(String,String)} and its deprecated
* equivalent have no effect on the resulting hyperlink. Instead, use the
* <code>ParameterMap</code> argument to <code>URL</code>.</p>
*
* @see com.arsdigita.web.URL
* @see com.arsdigita.web.ParameterMap
* @param label a <code>String</code> of label text
* @param url a <code>URL</code> for the link's target
*
* @deprecated refactor to use Link(Component,URL) to provide a globalized
* label for the link.
*/
public Link(String label, URL url) {
super(label, url.toString());
init();
m_webURL = url;
}
@Override
public Object clone() throws CloneNotSupportedException {
Link result = (Link) super.clone();
result.m_params = (ParameterMap) m_params.clone();
return result;
}
/**
* Sets a query variable and its value. Overwrites any values that may have
* been set previously under the specified name.
* <p>
* All the variables set with this method are appended to the query string
* in the URL that is output for this <code>Link</code>.
*
* @param name the name of the query
* @param value the value for the query
*
* @pre name != null
*/
public void setVar(String name, String value) {
Assert.isUnlocked(this);
m_params.setParameter(name, value);
}
// No longer used anywhere in the code base
// /**
// * Set a query variable and its value
// * @deprecated use {@link #setVar setVar}
// */
// public void addURLVars(String name, String value) {
// setVar(name, value);
// }
/**
*
* @return may be this method should be deprecated as well as addURLVars?
*/
public String getURLVarString() {
return m_params.toString();
}
/**
* <p>
* Get the "target" attribute of the link, which determines which browser
* frame will load the new page when this link is clicked.</p>
*/
public String getTargetFrame() {
return getAttribute(FRAME_TARGET_ATTR);
}
/**
* <p>
* Set the "target" attribute of the link, which determines which browser
* frame will load the new page when this link is clicked.</p>
*/
public void setTargetFrame(String frameName) {
setAttribute(FRAME_TARGET_ATTR, frameName);
}
/**
*
* @param state
* @param parent
*/
protected void generateURL(PageState state, Element parent) {
parent.addAttribute("href", prepareURL(state, getTarget()));
exportAttributes(parent);
}
/**
* Processes the URL for this link after the print listener runs.
*
* @param location the original URL
*
* @return the URL appended with ACS-specific URL parameters.
*/
protected String prepareURL(final PageState state, String location) {
final HttpServletRequest req = state.getRequest();
final HttpServletResponse resp = state.getResponse();
if (m_webURL == null) {
m_params.runListeners(req);
if (location.startsWith("/")) {
location = URL.getDispatcherPath() + location;
}
if (location.indexOf("?") == -1) {
// m_params adds the "?" as needed.
return resp.encodeURL(location + m_params);
} else {
// The location already includes a query string, so
// append to it without including a "?".
if (location.endsWith("&")) {
return resp.encodeURL(location + m_params.getQueryString());
} else {
return resp.encodeURL(location + "&" + m_params
.getQueryString());
}
}
} else {
return m_webURL.toString();
}
}
}

View File

@ -1,877 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletException;
import com.arsdigita.bebop.list.ListModel;
import com.arsdigita.bebop.list.ListModelBuilder;
import com.arsdigita.bebop.list.ListCellRenderer;
import com.arsdigita.bebop.list.DefaultListCellRenderer;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.ChangeEvent;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.bebop.event.EventListenerList;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.util.Assert;
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.xml.Element;
/**
* A <code>List</code>, similar to a <code>javax.swing.JList</code>, that keeps
* track of a sequence of items and selections of one or more of these items. A
* separate model, {@link ListModel}, is used to represent the items in the
* list.
*
* @see ListModel
* @see ListModelBuilder
* @see com.arsdigita.bebop.list.ListCellRenderer
* @author David Lutterkort
* @version $Id: List.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class List extends SimpleComponent implements BebopConstants {
/**
* The name of the StringParameter that the list uses to keep track of which
* item is selected.
*/
public static final String SELECTED = "sel";
/**
* The name of the event the list sets when producing links that change
* which item is selected.
*/
public static final String SELECT_EVENT = "s";
/**
* The model builder for this list. Is used to produce a new model for each
* request served by this <code>List</code>.
*
* @see #setListModelBuilder
* @see ArrayListModelBuilder
* @see MapListModelBuilder
*/
private ListModelBuilder m_modelBuilder;
private RequestLocal m_model;
/**
* The renderer used to format list items.
*
* @see DefaultListCellRenderer
*/
private ListCellRenderer m_renderer;
private EventListenerList m_listeners;
private SingleSelectionModel m_selection;
private ChangeListener m_changeListener;
private Component m_emptyView;
private boolean m_stateParamsAreRegistered;
/**
* <p>
* Vertical List layout.</p>
*
*/
public static final int VERTICAL = 0;
/**
* <p>
* Horizontal List layout.</p>
*
*/
public static final int HORIZONTAL = 1;
private int m_layout = VERTICAL;
/**
* Creates a new <code>List</code> that uses the specified list model
* builder to generate per-request {@link ListModel ListModels}.
*
* @param b the model builder used for this list
*
* @pre b != null
*/
public List(ListModelBuilder b) {
this();
m_modelBuilder = b;
m_emptyView = null;
}
/**
* Creates an empty <code>List</code>.
*/
public List() {
// Force the use of the 'right' constructor
this((SingleSelectionModel) null);
m_selection = new ParameterSingleSelectionModel(new StringParameter(
SELECTED));
}
/**
* Create an empty <code>List</code>.
*/
public List(SingleSelectionModel selection) {
// This is the real constructor. All other constructors must call it
// directly or indirectly
super();
m_renderer = new DefaultListCellRenderer();
m_listeners = new EventListenerList();
m_selection = selection;
setListData(new Object[0]);
initListModel();
m_emptyView = null;
m_stateParamsAreRegistered = true;
}
/**
* Creates a new <code>List</code> from an array of objects. Uses an
* internal {@link ListModelBuilder}. Each {@link ListModel} that is built
* will iterate through the entries of the object, returning the objects
* from calls to {@link ListModel#getElement} and the corresponding index,
* which is converted to a <code>String</code> from calls to {@link
* ListModel#getKey}.
*
* @param values an array of items
*
* @pre values != null
* @see #setListData(Object[] v)
*/
public List(Object[] values) {
this();
setListData(values);
}
/**
* Creates a new <code>List</code> from a map. Uses an internal {@link
* ListModelBuilder}. Each {@link ListModel} that is built will iterate
* through the entries in <code>map</code> in the order in which they are
* returned by <code>map.entrySet().iterator()</code>. Calls to {@link
* ListModel#getElement} return one value in <code>map</code>. Calls to
* {@link ListModel#getElement} return the corresponding key, which is
* converted to a <code>String</code> by calling <code>toString()</code> on
* the key.
*
* @param map a key-value mapping for the list items
*
* @pre map != null
*/
public List(Map map) {
this();
setListData(map);
}
/**
* Registers this <code>List</code> and its state parameter(s) with the
* specified page.
*
* @param p the page this list is contained in
*
* @pre p != null
* @pre ! isLocked()
*/
public void register(Page p) {
Assert.isUnlocked(this);
if (m_selection.getStateParameter() != null) {
p.addComponentStateParam(this, m_selection.getStateParameter());
}
}
/**
* Responds to a request in which this <code>List</code> was the targetted
* component. Calls to this method should only be made through links
* generated by this list.
*
* <p>
* Determines the new selected element and fires a {@link
* ChangeEvent} if it has changed. After that, fires an {@link
* ActionEvent}.
*
* @param state the state of the current request
*
* @throws ServletException if the control event is unknown.
* @pre state != null
* @see #fireStateChanged fireStateChanged
* @see #fireActionEvent fireActionEvent
*/
public void respond(PageState state) throws ServletException {
String event = state.getControlEventName();
if (SELECT_EVENT.equals(event)) {
setSelectedKey(state, state.getControlEventValue());
} else {
throw new ServletException("Unknown event '" + event + "'");
}
fireActionEvent(state);
}
/**
* Allow subclasses to override how the layout is determined.
*
* @param list
*/
protected void exportLayoutAttribute(final Element list) {
if (m_layout == VERTICAL) {
list.addAttribute("layout", "vertical");
} else {
list.addAttribute("layout", "horizontal");
}
}
protected String getTagName() {
return BEBOP_LIST;
}
protected String getTagXMLNS() {
return BEBOP_XML_NS;
}
/**
* Generates XML representing the items in the list. The items are formatted
* using a {@link ListCellRenderer}. <code>generateXML</code> is called on
* each component returned by the renderer.
*
* <p>
* The XML that is generated has the following form:
* <pre>
* &lt;bebop:list mode="single" %bebopAttr;>
* &lt;bebop:cell [selected="selected"] key="itemKey">
* ... XML generated for component returned by renderer ...
* &lt;/bebop:cell>
* ... more &lt;bebop:cell> elements, one for each list item ...
* &lt;/bebop:list></pre>
*
* @param state the state of the current request
* @param parent the element into which XML is generated
*
* @pre state != null
* @pre parent != null
* @see com.arsdigita.bebop.list.ListCellRenderer
*/
public void generateXML(PageState state, Element parent) {
if (!isVisible(state)) {
return;
}
ListModel m = getModel(state);
// Check if there are items in the list
if (m.next()) {
// The list has items
Element list = parent.newChildElement(getTagName(), getTagXMLNS());
exportAttributes(list);
// if (m_layout == VERTICAL) {
// list.addAttribute("layout", "vertical");
// } else {
// list.addAttribute("layout", "horizontal");
// }
exportLayoutAttribute(list);
Component c;
Object selKey;
if (getStateParamsAreRegistered()) {
selKey = getSelectedKey(state);
} else {
selKey = null;
}
int i = 0;
do {
Element item = list.newChildElement(BEBOP_CELL, BEBOP_XML_NS);
String key = m.getKey();
Assert.exists(key);
// Converting both keys to String for comparison
// since ListModel.getKey returns a String
boolean selected = (selKey != null) && key.equals(selKey
.toString());
item.addAttribute("key", key);
if (selected) {
item.addAttribute("selected", "selected");
}
if (getStateParamsAreRegistered()) {
state.setControlEvent(this, SELECT_EVENT, key);
}
c = getCellRenderer().getComponent(this, state, m.getElement(),
key, i, selected);
c.generateXML(state, item);
i += 1;
} while (m.next());
} else {
// The list has no items
if (m_emptyView != null) {
// Display the empty view
m_emptyView.generateXML(state, parent);
} else {
// For compatibility reasons, generate an empty
// list element. In the future, this should go away
Element list = parent.newChildElement(BEBOP_LIST, BEBOP_XML_NS);
exportAttributes(list);
}
}
state.clearControlEvent();
}
/**
* <p>
* Retrieve the current List layout.</p>
*
* @return List.VERTICAL or List.HORIZONTAL
*
*/
public int getLayout() {
return m_layout;
}
/**
* <p>
* Set the current List layout.</p>
*
* @param layout New layout value, must be List.VERTICAL or List.HORIZONTAL
*
*/
public void setLayout(int layout) {
Assert.isUnlocked(this);
Assert.isTrue((layout == VERTICAL) || (layout == HORIZONTAL),
"Invalid layout code passed to setLayout");
m_layout = layout;
}
/**
* This method is part of a mechanism to freakishly allow List's to be used
* as parent classes for components that do not have their state params
* registered with the page. An example of a situation like this is Form
* ErrorDisplay being used in a Metaform
*/
public void setStateParamsAreRegistered(boolean val) {
m_stateParamsAreRegistered = val;
}
public boolean getStateParamsAreRegistered() {
return m_stateParamsAreRegistered;
}
/**
* Returns the renderer currently used for rendering list items.
*
* @return the current list cell renderer.
*
* @see #setCellRenderer setCellRenderer
* @see com.arsdigita.bebop.list.ListCellRenderer
*/
public final ListCellRenderer getCellRenderer() {
return m_renderer;
}
/**
* Sets the cell renderer to be used when generating output with or
* {@link #generateXML generateXML}.
*
* @param r a <code>ListCellRenderer</code> value
*
* @pre r != null
* @pre ! isLocked()
* @see com.arsdigita.bebop.list.ListCellRenderer
*/
public final void setCellRenderer(ListCellRenderer r) {
Assert.isUnlocked(this);
m_renderer = r;
}
/**
* Returns the model builder currently used to build each request-specific
* {@link ListModel}.
*
* @return a <code>ListModelBuilder</code> value.
*
* @see #setModelBuilder setModelBuilder
* @see ListModelBuilder
*/
public final ListModelBuilder getModelBuilder() {
return m_modelBuilder;
}
/**
* Sets the model builder used to build each request-specific
* {@link ListModel}.
*
* @param b a <code>ListModelBuilder</code> value
*
* @pre ! isLocked()
* @see ListModelBuilder
*/
public final void setModelBuilder(ListModelBuilder b) {
Assert.isUnlocked(this);
m_modelBuilder = b;
}
/**
* Sets the empty view component, which is shown if there are no items in
* the list. This component must be stateless. For example, it could be an
* Image or a Label.
*
* @param c the new empty view component
*/
public final void setEmptyView(Component c) {
Assert.isUnlocked(this);
m_emptyView = c;
}
/**
* Gets the empty view component. The empty view component is shown if there
* are no items in the list.
*
* @return the empty view component.
*/
public final Component getEmptyView() {
return m_emptyView;
}
/**
* Initialize the private <code>m_model</code> variable. The initial value
* is what the model builder returns for the state.
*/
private void initListModel() {
m_model = new RequestLocal() {
protected Object initialValue(PageState s) {
return getModelBuilder().makeModel(List.this, s);
}
};
}
/**
* Gets the list model used in processing the request represented by
* <code>state</code>.
*
* @param state the state of the current request
*
* @return the list model used in processing the request represented by
* <code>state</code>.
*/
public ListModel getModel(PageState state) {
return (ListModel) m_model.get(state);
}
/**
* Sets the list to use for the values in <code>values</code>. Each {@link
* ListModel} that is built will iterate through the entries of the object,
* returning the objects from calls to {@link ListModel#getElement} and the
* corresponding index, which is converted to a <code>String</code> from
* calls to {@link ListModel#getKey}.
*
* @param values an array of items
*
* @pre values != null
* @pre ! isLocked()
*/
public void setListData(Object[] values) {
Assert.isUnlocked(this);
m_modelBuilder = new ArrayListModelBuilder(values);
}
/**
* Sets the list to use the entries in <code>map</code>. Each {@link
* ListModel} that is built will iterate through the entries in
* <code>map</code> in the order in which they are returned by
* <code>map.entrySet().iterator()</code>. Calls to {@link
* ListModel#getElement} return one value in <code>map</code>. Calls to
* {@link ListModel#getElement} return the corresponding key, which is
* converted to a <code>String</code> by calling <code>toString()</code> on
* the key.
*
* @param map a key-value mapping for the list items
*
* @pre map != null
* @pre ! isLocked()
*/
public void setListData(Map map) {
Assert.isUnlocked(this);
m_modelBuilder = new MapListModelBuilder(map);
}
/**
* Gets the selection model. The model keeps track of which list item is
* currently selected, and can be used to manipulate the selection
* programmatically.
*
* @return the model used by the list to keep track of the selected list
* item.
*/
public final SingleSelectionModel getSelectionModel() {
return m_selection;
}
/**
* Sets the selection model that the list uses to keep track of the
* currently selected list item.
*
* @param m the new selection model
*
* @pre m != null
* @pre ! isLocked()
*/
public final void setSelectionModel(SingleSelectionModel m) {
Assert.isUnlocked(this);
if (m_changeListener != null) {
// Transfer the change listener
m_selection.removeChangeListener(m_changeListener);
m.addChangeListener(m_changeListener);
}
m_selection = m;
}
/**
* Gets the key for the selected list item. This will only be a valid key if
* {@link #isSelected isSelected} is <code>true</code>.
*
* @param state the state of the current request
*
* @return the key for the selected list item.
*
* @pre isSelected(state)
*/
public Object getSelectedKey(PageState state) {
return m_selection.getSelectedKey(state);
}
/**
* Sets the selection to the one with the specified key. If <code>key</code>
* was not already selected, fires the {@link
* ChangeEvent}.
*
* @param state the state of the current request
* @param key the key for the selected list item
*
* @see #fireStateChanged fireStateChanged
*/
public void setSelectedKey(PageState state, String key) {
m_selection.setSelectedKey(state, key);
}
/**
* Returns <code>true</code> if one of the list items is currently selected.
*
* @param state the state of the current request
*
* @return <code>true</code> if one of the list items is selected
* <code>false</code> otherwise.
*/
public boolean isSelected(PageState state) {
return m_selection.isSelected(state);
}
/**
* Clears the selection in the request represented by <code>state</code>.
*
* @param state the state of the current request
*
* @post ! isSelected(state)
*/
public void clearSelection(PageState state) {
m_selection.clearSelection(state);
}
/**
* Creates the change listener that is used for forwarding change events
* fired by the selection model to change listeners registered with the
* list. The returned change listener refires the event with the list,
* rather than the selection model, as source.
*
* @return the change listener used internally by the list.
*/
protected ChangeListener createChangeListener() {
return new ChangeListener() {
public void stateChanged(ChangeEvent e) {
fireStateChanged(e.getPageState());
}
};
}
/**
* Adds a change listener. A change event is fired whenever the selected
* list item changes during the processing of a request. The change event
* that listeners receive names the list as the source.
*
* @param l the change listener to run when the selected item changes in a
* request
*
* @pre ! isLocked()
*/
public void addChangeListener(ChangeListener l) {
Assert.isUnlocked(this);
if (m_changeListener == null) {
m_changeListener = createChangeListener();
m_selection.addChangeListener(m_changeListener);
}
m_listeners.add(ChangeListener.class, l);
}
/**
* Removes a change listener. The listener should have been previously added
* with {@link #addChangeListener addChangeListener}, although no error is
* signalled if the change listener is not found among the list's listeners.
*
* @param l the change listener to remove from the list
*/
public void removeChangeListener(ChangeListener l) {
Assert.isUnlocked(this);
m_listeners.remove(ChangeListener.class, l);
}
/**
* Fires a change event to signal that the selected list item has changed in
* the request represented by <code>state</code>. The source of the event is
* the list.
*
* @param state the state of the current request
*/
protected void fireStateChanged(PageState state) {
Iterator i = m_listeners.getListenerIterator(ChangeListener.class);
ChangeEvent e = null;
while (i.hasNext()) {
if (e == null) {
e = new ChangeEvent(this, state);
}
((ChangeListener) i.next()).stateChanged(e);
}
}
// Action events
/**
* Adds an action listener. This method is run whenever
* {@link #respond respond} is called on the list. This gives clients a way
* to track mouse clicks received by the list.
*
* @param 1 the action listener to add
*
* @pre l != null
* @pre ! isLocked()
* @see #respond respond
*/
public void addActionListener(ActionListener l) {
Assert.isUnlocked(this);
m_listeners.add(ActionListener.class, l);
}
/**
* Removes a previously added action listener.
*
* @param 1 the action listener to remove
*
* @see #addActionListener addActionListener
*/
public void removeActionListener(ActionListener l) {
Assert.isUnlocked(this);
m_listeners.remove(ActionListener.class, l);
}
/**
* Fires an action event signalling that the list received the request
* submission. All registered action listeners are run. The source of the
* event is the list.
*
* @param state the state of the current request
*
* @pre state != null
* @see #respond respond
*/
protected void fireActionEvent(PageState state) {
Iterator i = m_listeners.getListenerIterator(ActionListener.class);
ActionEvent e = null;
while (i.hasNext()) {
if (e == null) {
e = new ActionEvent(this, state);
}
((ActionListener) i.next()).actionPerformed(e);
}
}
// ListModelBuilder for maps
/**
* Build list models from a map. The list models use the result of
* <code>toString()</code> called on the key of the map entries as their
* keys and return the associated value as the element for the list items
* the list model iterates over.
*/
private static class MapListModelBuilder implements ListModelBuilder {
private Map m_map;
private boolean m_locked;
public MapListModelBuilder() {
this(Collections.EMPTY_MAP);
}
public MapListModelBuilder(Map m) {
m_map = m;
}
public ListModel makeModel(List l, PageState state) {
return new ListModel() {
private Iterator i = m_map.entrySet().iterator();
private Map.Entry e = null;
public boolean next() {
if (!i.hasNext()) {
e = null;
return false;
}
e = (Map.Entry) i.next();
return true;
}
public Object getElement() {
checkState();
return e.getValue();
}
public String getKey() {
checkState();
return e.getKey().toString();
}
private void checkState() {
if (e == null) {
throw new IllegalStateException(
"No valid current item. "
+ "Model is either before first item or after last item");
}
}
};
}
public void lock() {
m_locked = true;
}
public final boolean isLocked() {
return m_locked;
}
}
// ListModelBuilder for arrays
/**
* Build list models from an array of values. The list models use the index
* of the array entries, converted to a <code>String</code>, as the key for
* the list items and the array values as their elements.
*/
private static class ArrayListModelBuilder implements ListModelBuilder {
private Object[] m_values;
private boolean m_locked;
public ArrayListModelBuilder() {
this(new Object[0]);
}
public ArrayListModelBuilder(Object[] values) {
m_values = values;
}
public ListModel makeModel(List l, PageState state) {
return new ListModel() {
private int i = -1;
public boolean next() {
i += 1;
return (i < m_values.length);
}
public Object getElement() {
checkState();
return m_values[i];
}
public String getKey() {
checkState();
return String.valueOf(i);
}
private void checkState() {
if (i < 0) {
throw new IllegalStateException(
"Before first item. Call next() first.");
}
if (i >= m_values.length) {
throw new IllegalStateException(
"After last item. Model exhausted.");
}
}
};
}
public void lock() {
m_locked = true;
}
public final boolean isLocked() {
return m_locked;
}
}
/**
* A {@link ListModel} that has no rows.
*/
public static final ListModel EMPTY_MODEL = new ListModel() {
public boolean next() {
return false;
}
public String getKey() {
throw new IllegalStateException("ListModel is empty");
}
public Object getElement() {
throw new IllegalStateException("ListModel is empty");
}
};
}

View File

@ -1,92 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import static com.arsdigita.bebop.Component.*;
import java.util.Iterator;
import com.arsdigita.xml.Element;
/**
* A container that outputs its components in a &lt;list&gt;. Each child is
* printed in its own list item. The components are put into the list in the
* order in which they were added to the <code>ListPanel</code>, progressing
* from top to bottom.
*
* <p>
* ListPanels can be ordered or unordered.</p>
*
* @author Christian Brechb&uuml;hler (christian@arsdigita.com)
*
* @version $Id$
*
*/
public class ListPanel extends SimpleContainer {
public static final boolean ORDERED = true;
public static final boolean UNORDERED = false;
private boolean m_ordered;
/**
* Creates a simple list.
*
* @param ordered <code>true</code> is an ordered (numbered) list;
* <code>false</code> is an unordered (bulleted) list
*
*/
public ListPanel(boolean ordered) {
m_ordered = ordered;
}
/**
* Adds child components as a subtree under list-item nodes.
* <p>
* Generates a DOM fragment:
* <p>
* <pre>
* &lt;bebop:listPanel>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* ...
* &lt;/bebop:list></pre></p>
*
* @param state the state of the current request
* @param parent the node under which this subtree will be added
*/
public void generateXML(PageState state, Element parent) {
if (isVisible(state)) {
Element list = parent.newChildElement("bebop:listPanel",
BEBOP_XML_NS);
list.addAttribute("ordered", String.valueOf(m_ordered));
exportAttributes(list);
// generate XML for children
for (Iterator i = children(); i.hasNext();) {
Component c = (Component) i.next();
Element item = list.newChildElement("bebop:cell", BEBOP_XML_NS);
c.generateXML(state, item);
}
}
}
}

View File

@ -1,228 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import java.util.Map;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.util.Assert;
import com.arsdigita.util.Lockable;
/**
* A simple implementation of a {@link ComponentSelectionModel}. Uses a map to
* bind keys to components.
* <P>
* This class also encapsulates a {@link SingleSelectionModel}, which is useful
* if the {@link SingleSelectionModel} comes from a {@link List} or similar
* class.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @author David Lutterkort
* @author Stanislav Freidin
*/
public class MapComponentSelectionModel<T> implements ComponentSelectionModel<T>,
Lockable {
private SingleSelectionModel<T> m_selModel;
private Map<T, Component> m_components;
private boolean m_locked;
/**
* Constructs a new MapSingleSelectionModel, using selModel as the inner
* selection model and encapsulating the components map.
*
* @param selModel the single selection model to use to determine the
* currently selected key/component
* @param components the map of components that can be selected. The map is
* stored by reference. Therefore, changes to the map will
* affect the MapComponentSelectionModel instance.
*/
public MapComponentSelectionModel(final SingleSelectionModel<T> selModel,
final Map<T, Component> components
) {
m_components = components;
m_selModel = selModel;
m_locked = false;
}
/**
* Constructs a new MapSingleSelectionModel, using a
* DefaultSingleSelectionModel selection model and encapsulating the
* components map.
*
* @param components the map of components that can be selected. The map is
* stored by reference. Therefore, changes to the map will
* affect the MapComponentSelectionModel instance.
*/
public MapComponentSelectionModel(final Map<T, Component> components) {
this(new DefaultSingleSelectionModel<>(), components);
}
/**
* Retrieves the internal SingleSelectionModel.
*
* @return the internal SingleSelectionModel.
*/
public final SingleSelectionModel<T> getSingleSelectionModel() {
return m_selModel;
}
/**
* Retrieves the internal Map of components. Deprecate ???
*
* @return the internal map of components.
*/
public final Map<T, Component> getComponentsMap() {
return m_components;
}
/**
* Returns the component that should be used to output the currently
* selected element.
*
* @param state the state of the current request
*
* @return the component used to output the selected element.
*/
@Override
public Component getComponent(final PageState state) {
if (!isSelected(state)) {
return null;
}
return m_components.get((m_selModel.getSelectedKey(state)));
}
/**
* Adds another key-component mapping to the model. Passthrough to the
* underlying Map.
*
* @param key the key for the mapping
* @param component the component for the mapping
*/
public void add(final T key, final Component component) {
Assert.isUnlocked(this);
m_components.put(key, component);
}
// Passthrough to SingleSelectionModel
/**
* Returns <code>true</code> if there is a selected element.
*
* @param state the state of the current request
*
* @return <code>true</code> if there is a selected component
* <code>false</code> otherwise.
*/
@Override
public boolean isSelected(final PageState state) {
return m_selModel.isSelected(state);
}
/**
* Returns the key that identifies the selected element.
*
* @param state a <code>PageState</code> value
*
* @return a <code>String</code> value.
*/
@Override
public T getSelectedKey(final PageState state) {
return m_selModel.getSelectedKey(state);
}
/**
* Sets the selected key. If <code>key</code> is not in the collection of
* objects underlying this model, an <code>IllegalArgumentException</code>
* is thrown.
*
* @param state the state of the current request
*
* @throws IllegalArgumentException if the supplied <code>key</code> cannot
* be selected in the context of the
* current request.
*/
@Override
public void setSelectedKey(final PageState state, final T key) {
m_selModel.setSelectedKey(state, key);
}
/**
* Clears the selection.
*
* @param state the state of the current request
*
* @post ! isSelected(state)
*/
@Override
public void clearSelection(final PageState state) {
m_selModel.clearSelection(state);
}
/**
* Adds a change listener to the model. The listener's
* <code>stateChanged</code> is called whenever the selected key changes.
*
* @param changeListener a listener to notify when the selected key changes
*/
@Override
public void addChangeListener(final ChangeListener changeListener) {
Assert.isUnlocked(this);
m_selModel.addChangeListener(changeListener);
}
/**
* Removes a change listener from the model.
*
* @param changeListener the listener to remove
*/
@Override
public void removeChangeListener(final ChangeListener changeListener) {
Assert.isUnlocked(this);
m_selModel.removeChangeListener(changeListener);
}
/**
* Returns the state parameter that will be used to keep track of the
* currently selected key. Typically, the implementing class will simply
* call:<br>
* <code><pre>return new StringParameter("foo");</pre></code> This method
* may return null if a state parameter is not appropriate in the context of
* the implementing class.
*
* @return the state parameter to use to keep track of the currently
* selected component.
*/
@Override
public ParameterModel getStateParameter() {
return m_selModel.getStateParameter();
}
// implement Lockable
@Override
public final void lock() {
m_locked = true;
}
@Override
public final boolean isLocked() {
return m_locked;
}
}

View File

@ -1,188 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.util.Traversal;
import com.arsdigita.xml.Element;
/**
* A form that is instantiated on a per-request basis. This class
* functions as a placeholder and decorator of the request-specific form
* in a Bebop {@link Page}.
*
* <p> Subclasses only need to override {@link #buildForm buildForm} to
* return the request-specific form. The meta form takes care of
* interfacing that form with the normal control flow of serving a Bebop
* <code>Page</code>. The meta form will fool the request-specific forms
* into thinking that they are part of a static Bebop <code>Page</code>.
* The properties of the meta form should be used to initialize the
* correspoding properties of the request-specific form whenever
* possible. These properties include <code>name</code>,
* <code>method</code>, and <code>encType</code>.
*
* <p> Listeners can be added directly to the meta form and are run
* whenever the corresponding listeners would be run on an ordinary
* form. The source of the <code>FormSectionEvent</code> will be the meta
* form.
*
* @author Stas Freidin
* @author David Lutterkort
*/
public abstract class MetaForm extends Form {
private RequestLocal m_dynamicForm;
/**
* Constructs a new meta form.
*
* @param name the name of the form
*/
public MetaForm(String name) {
super(name);
m_dynamicForm = new RequestLocal() {
protected Object initialValue(PageState s) {
Form result = buildForm(s);
result.getModel().mergeModel(getModel());
// form isn't part of the page, so it is invisible
// on the page (vacuously). We should consider it
// visible iff the static container MetaForm is visible.
result.setProcessInvisible(
MetaForm.this.getProcessInvisible() ||
s.isVisibleOnPage(MetaForm.this));
result.traverse();
Traversal t = new Traversal() {
public void act(Component c) {
c.lock();
}
};
t.preorder(result);
return result;
}
};
}
/**
* Retrieves the form for the request represented by
* <code>state</code>. If the form hasn't been built
* yet, calls {@link #buildForm buildForm} to build the
* form.
*
* @param state describes the current request
* @return a custom-built form for this request.
* @pre state != null
* @post return != null
*/
protected Form getDynamicForm(PageState state) {
return (Form) m_dynamicForm.get(state);
}
/**
* Builds the dynamic form. Subclasses should override this method to
* build the form based on the request represented by <code>state</code>.
*
* @param state describes the current request
* @return the form to be used for this request.
* @pre state != null
* @post return != null
*/
public abstract Form buildForm(PageState state);
/**
* Force a rebuilding and updating of the dynamic form. Calls
* <code>buildForm</code> again and sets the dynamic form to the form
* returned by it.
*
* @param s describes the current request
*/
public void rebuildForm(PageState s) {
m_dynamicForm.set(s, m_dynamicForm.initialValue(s));
}
/**
* Returns the form data constructed by {@link #process process} for the
* request described by <code>state</code>. If the form for this request
* hasn't been built yet, calls {@link #buildForm buildForm}.
*
* @param state describes the current request
* @return the values extracted from the HTTP request contained
* in <code>state</code>, or <code>null</code> if the form has not
* yet been processed.
* @pre state != null
*/
public FormData getFormData(PageState state) {
return getDynamicForm(state).getFormData(state);
}
/**
* Generates the XML representing the form and its widgets, but not
* the state information, from <code>s</code>. The XML generation is
* delegated to the request-specific form by calling {@link
* #generateXMLSansState generateXMLSansState} on it.
*
* @param s represents the curent request
* @return the top-level element for the form.
*/
protected Element generateXMLSansState(PageState s, Element parent) {
return getDynamicForm(s).generateXMLSansState(s, parent);
}
/**
* Processes the request-specific form for the request represented by
* <code>state</code>.
*
* @param state describes the current request
* @return the form data extracted from the current request.
* @pre state != null
* @post return != null
* @see Form#process Form.process(...)
* @see FormModel#process FormModel.process(...)
*/
public FormData process(PageState state)
throws FormProcessException {
if (state.isVisibleOnPage(this))
return getDynamicForm(state).process(state);
return null; // XXX is this ok ?
}
/**
* Do nothing; the dynamic form will take care of the tag.
*/
protected void addMagicTag() {
return;
}
/**
* Not implemented because meta forms currently don't support mixing static and
* dynamic widgets.
* @throws UnsupportedOperationException
*/
public void add(Component pc, int constraints) {
throw new UnsupportedOperationException("Not implemented");
}
/**
* Not implemented.
* @throws UnsupportedOperationException
*/
public Container getPanel() {
throw new UnsupportedOperationException("Not implemented");
}
}

View File

@ -1,188 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.ChangeEvent;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.util.Assert;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.Iterator;
/**
* ModalContainer is a container that manages visibility for a set of
* components. It allows only one of its children to be visible. One of its
* children can be selected as the default visible component. If none is
* selected the child with index equal to zero is used. The modal container sets
* the appropriate default and PageState-based visibility for its children.
*
* @author Archit Shah
*
*/
public class ModalContainer extends SimpleContainer implements Resettable {
private static final Logger LOGGER = LogManager.getLogger(
ModalContainer.class);
private int m_default = 0;
private ArrayList m_changeListeners = new ArrayList();
public ModalContainer() {
super();
}
public ModalContainer(String tagName,
String xmlns) {
super(tagName, xmlns);
}
/**
* Registers state parameters for the page with its model.
*
* Used here to set the visibility of the component.
*
* The super class' method is empty, so the rule "Always call
* <code>super.register</code> when you override <code>register</code>
* doessn't apply here.
*
* @pre p != null
* @param p
*/
@Override
public void register(Page p) {
Assert.isUnlocked(this);
Iterator it = children();
while (it.hasNext()) {
// guaranteed to have at least one child
Component child = (Component) it.next();
if (m_default != indexOf(child)) {
p.setVisibleDefault(child, false);
}
}
}
public void setDefaultComponent(Component c) {
Assert.isUnlocked(this);
if (!contains(c)) {
add(c);
}
m_default = indexOf(c);
}
public Component getDefaultComponent() {
return get(m_default);
}
public void setVisibleComponent(PageState state, Component c) {
LOGGER.debug("changing visibility");
Component old = getVisibleComponent(state);
try {
old.setVisible(state, false);
} catch (NullPointerException e) {
// rare(?) situation where something messes with the
// visibility of the components. don't have to do anything
}
c.setVisible(state, true);
if (old != c) {
Iterator listeners = m_changeListeners.iterator();
while (listeners.hasNext()) {
ChangeListener l = (ChangeListener) listeners.next();
l.stateChanged(new ChangeEvent(this, state));
}
}
}
public Component getVisibleComponent(PageState state) {
Iterator it = children();
while (it.hasNext()) {
Component c = (Component) it.next();
if (c.isVisible(state)) {
return c;
}
}
return null;
}
/**
* Makes the next component in a wizard sequence visible while hiding all
* other components.
*
*/
public void next(PageState state) {
setVisibleComponent(state,
get(indexOf(getVisibleComponent(state)) + 1));
}
/**
* Makes the previous component in a wizard sequence visible while hiding
* all other components.
*
*/
public void previous(PageState state) {
setVisibleComponent(state,
get(indexOf(getVisibleComponent(state)) - 1));
}
/**
* Makes the component specified by index visible
*
* @param state
* @param index 0 based index of component
*/
public void jumpTo(PageState state, int index) {
setVisibleComponent(state, get(index));
}
/**
* Makes the specified component visible
*
*/
public void jumpTo(PageState state, Component comp) {
setVisibleComponent(state, get(indexOf(comp)));
}
/**
* Resets the container to display the default component.
*
*/
public void reset(PageState state) {
setVisibleComponent(state, getDefaultComponent());
}
/**
* Adds a listener that is called whenever this container's mode (i.e.,
* visible component) is changed using setVisibleComponent().
*
*/
public void addModeChangeListener(ChangeListener cl) {
Assert.isUnlocked(this);
m_changeListeners.add(cl);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,173 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.list.ListModel;
import com.arsdigita.bebop.list.ListModelBuilder;
import com.arsdigita.bebop.list.ListCellRenderer;
import com.arsdigita.util.LockableImpl;
import com.arsdigita.xml.Element;
import com.arsdigita.globalization.GlobalizedMessage;
import java.util.Iterator;
/**
* Displays validation errors for the page. These might have occured due to validation listeners on
* some state parameters within the page.
*
* @author Stanislav Freidin
* @version $Id: PageErrorDisplay.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class PageErrorDisplay extends List {
private static final String COLOR = "color";
/**
* Constructs a new <code>PageErrorDisplay</code>.
*/
public PageErrorDisplay() {
this(new PageErrorModelBuilder());
}
/**
* Constructs a new <code>PageErrorDisplay</code> from the errors supplied by a list model
* builder.
*
* @param builder the {@link ListModelBuilder} that will supply the errors
*
*/
protected PageErrorDisplay(ListModelBuilder builder) {
super(builder);
setCellRenderer(new LabelCellRenderer());
setTextColor("red");
setClassAttr("pageErrorDisplay");
}
/**
* Sets the HTML color of the error messages.
*
* @param c An HTML color, such as "#99CCFF" or "red"
*/
public void setTextColor(String c) {
setAttribute(COLOR, c);
}
/**
* Gets the HTML color of the error messages.
*
* @return the HTML color of the error messages.
*/
public String getTextColor() {
return getAttribute(COLOR);
}
/**
* Determines if there are errors to display.
*
* @param state the current page state
*
* @return <code>true</code> if there are any errors to display; <code>false</code> otherwise.
*/
protected boolean hasErrors(PageState state) {
return (state.getErrors().hasNext());
}
/**
* Generates the XML for this component. If the state has no errors in it, does not generate any
* XML.
*
* @param state the current page state
* @param parent the parent XML element
*/
public void generateXML(PageState state, Element parent) {
if (hasErrors(state)) {
super.generateXML(state, parent);
}
}
// A private class which builds a ListModel based on form errors
private static class PageErrorModelBuilder extends LockableImpl
implements ListModelBuilder {
public PageErrorModelBuilder() {
super();
}
public ListModel makeModel(List l, PageState state) {
return new StringIteratorModel(state.getErrors());
}
}
// A ListModel which generates items based on an Iterator
protected static class StringIteratorModel implements ListModel {
private Iterator m_iter;
private GlobalizedMessage m_error;
private int m_i;
public StringIteratorModel(Iterator iter) {
m_iter = iter;
m_error = null;
m_i = 0;
}
public boolean next() {
if (!m_iter.hasNext()) {
m_i = 0;
return false;
}
m_error = (GlobalizedMessage) m_iter.next();
++m_i;
return true;
}
private void checkState() {
if (m_i == 0) {
throw new IllegalStateException(
"next() has not been called succesfully"
);
}
}
public Object getElement() {
checkState();
return m_error;
}
public String getKey() {
checkState();
return Integer.toString(m_i);
}
}
// A ListCellRenderer that renders labels
private static class LabelCellRenderer implements ListCellRenderer {
public Component getComponent(List list, PageState state, Object value,
String key, int index, boolean isSelected) {
return new Label((GlobalizedMessage) value);
}
}
}

View File

@ -1,291 +0,0 @@
/*
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.util.UncheckedWrapperException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* <p>The <code>PageFactory</code> provides a framework for
* instantiating instances of the Bebop <code>Page</code> class in a
* project- and application-independant manner.</p>
*
* <h3>History</h3>
*
* <p>The traditional approach to writing bebop applications is to
* subclass the com.arsdigita.bebop.Page, adding various components to
* provide navigation & layout and writing custom XSL for styling
* purposes.</p>
*
* <p>The problem of this approach is that when multiple applications
* are combined to form a complete site, is it difficult to produce an
* integrated navigation infrastructure & uniform styling across all
* pages. In addition, by placing application specific functionality
* in a subclass of Page, the ability to reuse & embed applications
* within each other is hampered since Page objects cannot be
* nested.</p>
*
* <h3>Use Case</h3>
*
* <p>The PageFactory addresses the following situations</p>
*
* <ol>
* <li>It is common for all pages on a site to have a particular
* structure. ie, header, footer, left sidebar & main content area. </li>
*
* <li>It is desirable to customize page structure without making code changes
* to individual applications. </li>
* </ol>
*
* <h3>Example Usage</h3>
*
* <p>The point of interaction for PageFactory is typically in the
* application's Dispatcher class. Rather than invoking the Page
* constructor (ie <code>new Page(title)</code>), applications call
* <code>PageFactory.buildPage(title, "appname")</code> This method
* will return an instance of Page with the currently configured
* navigation components added.</p>
*
* <p>The two compulsory arguments to the <code>buildPage</code>
* method are the name of the application (ie, 'forum', 'cms'), and
* the page title (either as a String or Label object). The
* application name is used as key in both the enterprise.init file
* configuration & the XSL templates. There is optionally a third
* string <code>id</code> parameter which provides a unique identifier
* for the page within the application. If the page class is a
* subclass of ApplicationPage this will be used to set the XML
* <code>id</code> attribute.</p>
*
* <p>Consider the following example (based loosely on the Simple
* Survey application):</p>
*
* <pre>
* package com.arsdigita.simplesurvey.dispatcher;
*
* import com.arsdigita.simplesurvey.ui.IndexPanel;
* import com.arsdigita.simplesurvey.ui.AdminPanel;
* import com.arsdigita.simplesurvey.ui.SurveySelectionModel;
* import com.arsdigita.bebop.BigDecimalParameter;
* import com.arsdigita.bebop.page.BebopMapDispatcher;
*
* public class Dispatcher extends BebopMapDispatcher {
*
* public Dispatcher() {
* Page index = buildIndexPage();
* Page admin = buildAdminPage();
*
*
* addPage("index.jsp",index);
* addPage("", index);
* addPage("admin/index.jsp",index);
* addPage("admin", index);
* }
*
* private Page buildIndexPage() {
* SurveySelectionModel survey =
* new SurveySelectionModel(new BigDecimalParameter("survey"));
*
* Page page = PageFactory.buildPage("simplesurvey",
* "Simple Survey",
* "index");
* page.add(IndexPanel(survey));
* page.addGlobalStateParam(survey.getStateParameter());
* page.lock();
* return page;
* }
*
* private Page buildAdminPage() {
* SurveySelectionModel survey =
* new SurveySelectionModel(new BigDecimalParameter("survey"));
*
* Page page = PageFactory.buildPage("simplesurvey",
* "Simple Survey Administration",
* "admin");
* page.add(AdminPanel(survey));
* page.addGlobalStateParam(survey.getStateParameter());
* page.lock();
* return page;
* }
*
* }
* </pre>
*
* <h3>Updating existing applications</h3>
*
* <p>The process of updating existing applications to make use of the
* PageFactory varies according to the complexity of the application
* in question.</p>
*
* <p>In the simplest case where an application has not subclassed the
* Page class, then it is just a case of replacing calls to <code>new
* Page(title)</code> with <code>PageFactory.buildPage("appname",
* title)</code>.</p>
*
* <p>When an application has subclassed Page, then the initial
* approach is to change the subclass in question so that it derives
* from SimpleContainer instead of Page. Any calls to the
* <code>addGlobalStateParam</code> or <code>addRequestListener</code>
* methods can be moved from the constructor into the
* <code>register</code> method where there will be direct access to
* the <code>Page</code> object.</p>
*
* <h3>Configuring the page factory</h3>
*
* <p>The <code>com.arsdigita.bebop.base_page</code> system property
* may be used to specify the full name of a subclass of Page which
* provides the constructor signature detailed in the
* <code>setPageClass</code> method. If omitted it defaults to
* <code>BasePage</code>.</p>
*
* <p>The <code>com.arsdigita.ui</code> package provides an
* alternative subclass called <code>SimplePage</code> which supports
* specification.</p>
*
* @see com.arsdigita.bebop.BasePage
*/
public class PageFactory {
private static Class s_page;
private static Constructor s_cons;
private static boolean initialized = false;
static void init() {
if (initialized) {
return;
}
setPageClass(BebopConfig.getConfig().getBasePageClass());
}
/**
* Sets the page class to instantiate. The
* class should have a public constructor that
* takes three arguments. The first 'String'
* argument is the name of the application, the
* second 'Label' is the page title, and the
* third (optionally null) argument is a page
* id (unique string with this application).
*
* The common case is to inherit from ApplicationPage
* and pass these three arguments straight through
* to its constructor.
*
* @param page the page class
*/
public static void setPageClass(Class page) {
try {
s_cons = page.getConstructor(new Class[] {
String.class, Label.class, String.class
});
s_page = page;
initialized = true;
} catch (NoSuchMethodException ex) {
throw new UncheckedWrapperException(
"cannot find constructor " + s_page.getName() +
"(String application, Label title, String id)",
ex
);
} catch (SecurityException ex) {
throw new UncheckedWrapperException(
"cannot retrieve constructor for " + s_page.getName(),
ex
);
}
}
/**
* Instantiates a new instance of the Page class.
*
* @param application the application name
* @param title the page title
* @return a subclass of com.arsdigita.bebop.Page
*/
public static Page buildPage(String application,
String title) {
return buildPage(application, new Label(title));
}
/**
* Instantiates a new instance of the Page class,
* with the optional unique page id string.
*
* @param application the application name
* @param title the page title
* @param id the page id within the application
* @return a subclass of com.arsdigita.bebop.Page
*/
public static Page buildPage(String application,
String title,
String id) {
return buildPage(application, new Label(title), id);
}
/**
* Instantiates a new instance of the Page class.
*
* @param application the application name
* @param title the label for the page title
* @return a subclass of com.arsdigita.bebop.Page
*/
public static Page buildPage(String application,
Label title) {
return buildPage(application, title, null);
}
/**
* Instantiates a new instance of the Page class,
* with the optional unique page id string.
*
* @param application the application name
* @param title the label for the page title
* @param id the page id within the application
* @return a subclass of com.arsdigita.bebop.Page
*/
public static Page buildPage(String application,
Label title,
String id) {
init();
Page page = null;
try {
page = (Page)s_cons.newInstance(new Object[] {
application, title, id
});
} catch (InstantiationException ex) {
throw new UncheckedWrapperException(
"cannot instantiate page class " + s_page.getName(), ex
);
} catch (IllegalArgumentException ex) {
throw new UncheckedWrapperException(
"cannot instantiate page class " + s_page.getName(), ex
);
} catch (IllegalAccessException ex) {
throw new UncheckedWrapperException(
"constructor for page class " + s_page.getName() +
" is not public", ex
);
} catch (InvocationTargetException ex) {
throw new UncheckedWrapperException(
"cannot instantiate page class " + s_page.getName(), ex
);
}
return page;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
/**
* A model builder for
* the {@link Paginator} component.
*
* <p>The {@link #getTotalSize(Paginator, PageState)} method of this
* class is called during the generation of page links for a
* <code>Paginator</code> component. When using a
* <code>Paginator</code> component with a {@link List} or a {@link
* Table}, you can achieve greater flexibility in terms of caching and
* performance by having the model builder implement this interface.
*
* <p>Unlike other model builder classes in Bebop, there is no
* PaginationModel class, as this would only be an <code>int</code>.
*
* @see Paginator
*
* @author Phong Nguyen
* @version $Id$
* @since 4.6.10
**/
public interface PaginationModelBuilder {
// $Change: 44247 $
// $Revision$
// $DateTime: 2004/08/16 18:10:38 $
// $Author$
/**
* Returns the total number of results to paginate.
*
* @param paginator the Paginator instance that invoked this method
* @param state the current page state
* @return the total number of results to paginate.
**/
int getTotalSize(Paginator paginator, PageState state);
/**
* Determines whether the paginator should be visible in the request
* represented by <code>state</code>.
* This should normally delegate to the isVisible method of the
* associated displayed component.
*
* @return <code>true</code> if the paginator is visible in the request;
* <code>false</code> otherwise.
*
* @param state represents the current request
* @return <code>true</code> if the component is visible; <code>false</code>
* otherwise.
* @pre state != null
*/
boolean isVisible(PageState state);
}

View File

@ -1,518 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.list.ListModel;
import com.arsdigita.bebop.list.ListModelBuilder;
import com.arsdigita.bebop.parameters.IntegerParameter;
import com.arsdigita.bebop.util.GlobalizationUtil;
import com.arsdigita.util.LockableImpl;
import com.arsdigita.xml.Element;
/**
* A pagination component used to select different page views from a list of
* items.
*
* <p>In most cases, this component will be used with either a {@link
* List} or a {@link Table}. Here is an example on how to use this pagination
* component with a Table:
*
* <blockquote><pre><code>
* Table myTable = new Table(new myTableModelBuilder(),
* new DefaultTableColumnModel());
* Paginator pgntr = new Paginator((PaginationModelBuilder) myTable.getModelBuilder(), 10);
*
* Page p = new Page();
* p.add(pgntr);
* p.add(myTable);
* </code></pre></blockquote>
*
* <p>The model builder that is used in
* <code>myTable</code> was designed to also implement the {@link PaginationModelBuilder}
* interface. With both interfaces being implemented by the same class, it is
* much easier to cache the results of operations performed on the {@link com.arsdigita.persistence.DataQuery}
* used to generate the results.
*
* <blockquote><pre><code>
* public class myTableModelBuilder extends LockableImpl
* implements TableModelBuilder, PaginatedModelBuilder {
*
* private RequestLocal m_query;
*
* public myTableModelBuilder() {
* super();
* m_query = new RequestLocal();
* }
*
* private getDataQuery(PageState state) {
* // returns the DataQuery used to generate rows for the table
* }
*
* public int getTotalSize(Paginator pgntr, PageState state) {
* DataQuery query = getDataQuery(state);
* query.setRange(new Integer(pgntr.getFirst(state)),
* new Integer(pgntr.getLast(state) + 1));
* m_query.set(state, query);
* return (int) query.size();
* }
*
* public TableModel makeModel(Table table, PageState state) {
* return new myTableModel(table, state, (DataQuery) m_query.get(state));
* }
* }
* </code></pre></blockquote>
*
* <p>Subclasses that wish to render the page links in a different format will
* override the {@link #buildPaginationDisplay()} method. The implementation of
* this method must set the selection model used to retrieve the page number by
* calling the {@link
* #setPageNumSelectionModel(SingleSelectionModel)} method. Aside from changing
* the display, this pagination component will hide itself if
* {@link PaginationModelBuilder#getTotalSize(Paginator, PageState)} is less
* than the page size (i.e., a single page can be used to display the entire
* results). This default behavior can be changed by calling {@link #setHiddenIfSinglePage(boolean)}
* with
* <code>false</code>.
*
* @see PaginationModelBuilder
*
* @author Phong Nguyen
* @version $Id$
* @since 4.6.10
*
*/
public class Paginator extends SimpleContainer implements Resettable {
// $Change: 44247 $
// $Revision$
// $DateTime: 2004/08/16 18:10:38 $
// $Author$
// The builder which returns the total number of items to
// paginate.
private PaginationModelBuilder m_builder;
// The selection model that returns the selected page number. The
// contained ParameterModel should be a StringParameter, since
// this is the default for List and Table.
private SingleSelectionModel m_pageNumModel;
// The selection model that returns the number of items to display
// for one page.
private SingleSelectionModel m_pageSizeModel;
// This is used to determine if this component should be hidden
// when there is only a single page to display. Defaults to true.
private boolean m_hiddenIfSinglePage;
// A label that contains a space, "&nbsp;". This is used to insert
// spaces between the page links from within the list's
// generateXML() method.
private BoxPanel m_spacePanel;
private Label m_space;
// defined in List.java
private static final String _SELECT_EVENT = "s";
/**
* Constructor.
*
* @param builder The builder used to retrieve the total number of results
* to paginate.
* @param defaultPageSize The default number of results to display on each
* page.
*
*/
public Paginator(PaginationModelBuilder builder, int defaultPageSize) {
super();
m_builder = builder;
m_hiddenIfSinglePage = true;
// Create the selection model which returns the size of one
// page and set its default value.
IntegerParameter sizeParam = new IntegerParameter("ps");
sizeParam.setDefaultValue(new Integer(defaultPageSize));
sizeParam.setDefaultOverridesNull(true);
m_pageSizeModel = new ParameterSingleSelectionModel(sizeParam);
// Builds the display for rendering page links, this also sets
// the page number selection model.
buildPaginationDisplay();
}
/**
* Builds the display for rendering the page links. Subclasses can override
* this method to provide a different rendering of the page links. If this
* is the case, make sure that the {@link
* #setPageNumSelectionModel(SingleSelectionModel)} method is called to set
* the selection model for retrieving the selected page number.
*
*/
protected void buildPaginationDisplay() {
PaginatorList list = new PaginatorList(new PageListModelBuilder(this, getPaginationModelBuilder()));
setPageNumSelectionModel(list.getSelectionModel());
// This is used within the list's generateXML() method to
// insert spaces between the page links.
m_space = new Label("&nbsp;", false);
m_spacePanel = new BoxPanel(BoxPanel.HORIZONTAL);
m_spacePanel.add(m_space);
BoxPanel display = new BoxPanel(BoxPanel.HORIZONTAL);
display.add(new Label(GlobalizationUtil.globalize("bebop.page")));
display.add(list);
display.add(m_space);
add(display);
}
/**
* Sets the selection model that is used for returning the selected page
* number. Subclasses that override the {@link
* #buildPaginationDisplay()} method will need to call this method.
*
* @param pageNumModel The selection model used for returning the selected
* page number.
*
*/
protected void setPageNumSelectionModel(SingleSelectionModel pageNumModel) {
m_pageNumModel = pageNumModel;
}
/**
* Returns the selected page number.
*
* @param state Represents the current state of the request.
* @return The selected page number.
*
*/
public int getSelectedPageNum(PageState state) {
String pageNum = (String) m_pageNumModel.getSelectedKey(state);
if (pageNum == null) {
m_pageNumModel.setSelectedKey(state, "1");
return 1;
}
return Integer.parseInt(pageNum);
}
/**
* Sets the selected page number.
*
* @param state Represents the current state of the request.
* @param pageNum The number of the page to set as selected.
*
*/
public void setSelectedPageNum(PageState state, int pageNum) {
m_pageNumModel.setSelectedKey(state, String.valueOf(pageNum));
}
/**
* Returns the number of items to display per page.
*
* @param state Represents the current state of the request.
* @return The number of items to display per page.
*
*/
public int getPageSize(PageState state) {
return ((Integer) m_pageSizeModel.getSelectedKey(state)).intValue();
}
/**
* Sets the number of items to display per page.
*
* @param state Represents the current state of the request.
* @param pageSize The number of items to display per page.
*
*/
public void setPageSize(PageState state, int pageSize) {
m_pageSizeModel.setSelectedKey(state, new Integer(pageSize));
}
/**
* This returns the total number of pages that will be displayed by this
* paginator.
*
* @param state The page state
*/
public int getTotalPages(PageState state) {
int totalSize = m_builder.getTotalSize(this, state);
int pageSize = getPageSize(state);
int minSize = totalSize / pageSize;
if (minSize * pageSize == totalSize) {
return minSize;
} else {
return minSize + 1;
}
}
/**
* Returns the number of the first item to display.
*
* @param state Represents the current state of the request.
* @return The number of the first item to display.
*
*/
public int getFirst(PageState state) {
return ((getSelectedPageNum(state) - 1) * getPageSize(state)) + 1;
}
/**
* Returns the number of the last item to display.
*
* @param state Represents the current state of the request.
* @return The number of teh last item to display.
*
*/
public int getLast(PageState state) {
// NOTE: If the returned integer is used for
// DataQuery.setRange(int, int), then it needs to be
// incremented by 1.
return (getSelectedPageNum(state) * getPageSize(state));
}
/**
* Returns the builder that is used to retrieve the total number of items to
* paginate.
*
* @return The builder used to compute the total number of items to
* paginate.
*
*/
public PaginationModelBuilder getPaginationModelBuilder() {
return m_builder;
}
/**
* Specifies whether this component is hidden if there is only a single page
* of items to display.
*
* @return Returns
* <code>true</code> if this component is hidden when there is only a single
* page to view.
*
*/
public boolean isHiddenIfSinglePage() {
return m_hiddenIfSinglePage;
}
/**
* Sets whether or not this component should be hidden if there is only a
* single page of items to display.
*
* @param isHidden By default, this component will be hidden when there is
* only a single page to display. Set this to
* <code>false</code> if this is not the desired effect.
*
*/
public void setHiddenIfSinglePage(boolean isHidden) {
m_hiddenIfSinglePage = isHidden;
}
/**
* Returns
* <code>true</code> if this component is visible. This component will not
* be visible if the paginator model builder's isVisible method reports
* false. If this component is set to be hidden when there is only a single
* page to display, then the total page size returned from the {@link PaginationModelBuilder}
* object must be greater than the number of items per page.
*
* @param state Represents the current state of the request.
* @return Returns
* <code>true</code> if this component is visible.
*
* @see #getPageSize(PageState)
* @see PaginationModelBuilder#getTotalSize(Paginator, PageState)
*
*/
@Override
public boolean isVisible(PageState state) {
return (super.isVisible(state)
&& m_builder.isVisible(state)
&& ((!m_hiddenIfSinglePage)
|| m_builder.getTotalSize(this, state) > getPageSize(state)));
}
/**
* Register the page size selection model.
*
* @param p The page to register with.
*
*/
@Override
public void register(Page p) {
super.register(p);
p.setVisibleDefault(m_spacePanel, false);
p.addComponentStateParam(this, m_pageSizeModel.getStateParameter());
}
/**
* Resets this component by clearing the selected page.
*
* @param state Represents the current state of the request.
*
*/
public void reset(PageState state) {
m_pageNumModel.clearSelection(state);
}
/**
* This class was added to provide greater flexibility in displaying the
* page links. Links can be displayed in a space separated list to support
* wrapping or in a table with a fixed number of page links per row. By
* default the page links will be rendered inside a one-cell table. If the
* number of page links to display per line is specified, then each page
* link will be rendered in it's own cell.
*
*/
private class PaginatorList extends List {
public PaginatorList(ListModelBuilder builder) {
super(builder);
}
/**
* If the number of page links to display per line is specified then the
* generated xml will be similar to that of a Table. Else, it will be
* similar to a simple container.
*
* @param state Represents the current state of the request.
* @param parent The element to which to attach the XML.
*
*/
@Override
public void generateXML(PageState state, Element parent) {
if (!this.isVisible(state)) {
return;
}
// maybe display the Previous arrow
if (getSelectedPageNum(state) > 1) {
state.setControlEvent(this, _SELECT_EVENT,
Integer.toString(getSelectedPageNum(state) - 1));
(new ControlLink(new Label("<"))).generateXML(state, parent);
(new Label(" ")).generateXML(state, parent);
state.setControlEvent(this, _SELECT_EVENT,
Integer.toString(getSelectedPageNum(state) - 1));
(new ControlLink(new Label(GlobalizationUtil.globalize("bebop.previous")))).generateXML(state, parent);
(new Label(" ")).generateXML(state, parent);
}
ListModel m = getModel(state);
Object selKey = getSelectedKey(state);
Component c;
int i = 0;
while (m.next()) {
String key = m.getKey();
// Converting both keys to String for comparison
// since ListModel.getKey returns a String
boolean selected = (selKey != null) && (key != null)
&& selKey.toString().equals(key.toString());
state.setControlEvent(this, _SELECT_EVENT, m.getKey());
c = getCellRenderer().getComponent(this, state, m.getElement(),
m.getKey(), i, selected);
c.generateXML(state, parent);
m_space.generateXML(state, parent);
i += 1;
}
// maybe display the next arrow
if (getSelectedPageNum(state) < getTotalPages(state)) {
state.setControlEvent(this, _SELECT_EVENT,
Integer.toString(getSelectedPageNum(state) + 1));
(new Label(" ")).generateXML(state, parent);
(new ControlLink(new Label(GlobalizationUtil.globalize("bebop.next")))).generateXML(state, parent);
(new Label(" ")).generateXML(state, parent);
state.setControlEvent(this, _SELECT_EVENT,
Integer.toString(getSelectedPageNum(state) + 1));
(new ControlLink(new Label(">"))).generateXML(state, parent);
}
state.clearControlEvent();
}
}
/**
* A list model builder for the pagination list.
*
*/
private class PageListModelBuilder extends LockableImpl
implements ListModelBuilder {
Paginator m_paginator;
PaginationModelBuilder m_builder;
public PageListModelBuilder(Paginator paginator,
PaginationModelBuilder builder) {
super();
m_paginator = paginator;
m_builder = builder;
}
public ListModel makeModel(List list, PageState state) {
return new PageListModel(m_builder.getTotalSize(m_paginator, state),
getPageSize(state),
getSelectedPageNum(state));
}
}
/**
* A list model for the pagination list which is used to generate the text
* for the page links.
*
*/
private class PageListModel extends LockableImpl
implements ListModel {
int m_totalSize;
int m_pageSize;
int m_pageCount;
int m_current;
public PageListModel(int totalSize, int pageSize, int current) {
super();
m_totalSize = totalSize;
m_pageSize = pageSize;
m_pageCount = 0;
m_current = current;
}
public boolean next() {
if (m_pageCount * m_pageSize < m_totalSize) {
m_pageCount += 1;
return true;
}
return false;
}
public Object getElement() {
/*
* TODO: Remove or relocate this int begin = ((m_pageCount-1) *
* m_pageSize) + 1; int end = (m_pageCount) * m_pageSize; if (end >
* m_totalSize) { end = m_totalSize; } return "" + begin + "-" +
* end;
*/
if (Math.abs(m_current - m_pageCount) <= 5
|| m_pageCount == 1
|| m_pageCount * m_pageSize >= m_totalSize) {
return Integer.toString(m_pageCount);
} else {
return ".";
}
}
public String getKey() {
return Integer.toString(m_pageCount);
}
}
}

View File

@ -1,125 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.util.Assert;
/**
* An implementation of {@link SingleSelectionModel} that uses a state parameter
* for managing the currently selected key.
* <p>
*
* A typical use case for this class is as follows.
* <blockquote>
* <pre>
* <code>
* public TheConstructor() {
* m_parameter = new StringParameter("my_key");
* m_sel = new ParameterSingleSelectionModel(m_parameter);
* }
*
* public void register(Page p) {
* p.addComponent(this);
* p.addComponentStateParam(this, m_param);
* }
* </code>
* </pre>
* </blockquote>
*
* jensp 2016-02-26: Added generics
*
* @param <T> Generics parameter
*
* @author Stanislav Freidin
* @author Jens Pelzetter
*
*/
public class ParameterSingleSelectionModel<T>
extends AbstractSingleSelectionModel<T> {
private final ParameterModel m_parameter;
/**
* Constructs a new ParameterSingleSelectionModel.
*
* @param m the parameter model that will be used to keep track of the
* currently selected key
*/
public ParameterSingleSelectionModel(ParameterModel m) {
super();
m_parameter = m;
}
/**
* Returns the key that identifies the selected element.
*
* @param state a <code>PageState</code> value
*
* @return a <code>String</code> value.
*/
@Override
@SuppressWarnings("unchecked")
public T getSelectedKey(final PageState state) {
final FormModel model = state.getPage().getStateModel();
if (model.containsFormParam(m_parameter)) {
return (T) state.getValue(m_parameter);
} else {
return null;
}
}
@Override
public final ParameterModel getStateParameter() {
return m_parameter;
}
/**
* Set the selected key.
*
* @param state represents the state of the current request
* @param newKey the new selected key
*/
@Override
public void setSelectedKey(final PageState state, final Object newKey) {
final Object oldKey = getSelectedKey(state);
if (Assert.isEnabled()) {
final FormModel model = state.getPage().getStateModel();
Assert.isTrue(model.containsFormParam(m_parameter),
String.format(
"Parameter %s is not part of the FormModel.",
m_parameter.getName()));
}
state.setValue(m_parameter, newKey);
if (newKey == null && oldKey == null) {
return;
}
if (newKey != null && newKey.equals(oldKey)) {
return;
}
fireStateChanged(state);
}
}

View File

@ -1,815 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ChangeEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSubmissionListener;
import com.arsdigita.bebop.list.DefaultListCellRenderer;
import com.arsdigita.bebop.list.ListModelBuilder;
import com.arsdigita.bebop.list.ListModel;
import com.arsdigita.bebop.util.GlobalizationUtil;
import com.arsdigita.util.Assert;
import com.arsdigita.util.LockableImpl;
import com.arsdigita.util.SequentialMap;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.form.FormErrorDisplay;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.globalization.GlobalizedMessage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
/**
* Maintains a set of forms that are used when editing the
* properties of some object. The component maintains a single
* display pane and a list of forms that are selectable by links.
* <p>
* By default, the component looks something like this:
* <blockquote><pre><code>
* +----------------+
* | |
* | Display Pane |
* | |
* +----------------+
* [link to form1]
* [link to form2]
* [link to form3]
* </code></pre></blockquote>
*
* When the user clicks on a link, the display pane is hidden and the
* corresponding form is shown.
*
* <blockquote><pre><code>
* Enter foo: [ ]
* Enter bar: [ ]
*
* [Save] [Cancel]
* </code></pre></blockquote>
*
* When the user clicks the Save or Cancel button on the form, the form
* is hidden and the display pane (with its list of links)
* is shown once again.
* <p>
* The simple usage pattern for this class is as follows:
*
* <blockquote><pre><code>
* PropertyEditor editor = new PropertyEditor();
* editor.setDisplayComponent(new FooComponent());
* NameEditForm n = new NameEditForm();
* editor.add("name", "Edit Name", n, n.getCancelButton());
* AddressEditForm a = new AddressEditForm();
* editor.add("address", "Edit Address", a, a.getCancelButton());
* </code></pre></blockquote>
*
* The <code>PropertyEditor</code> will automatically add the right
* listeners to the forms.
* <p>
* This class is used extensively in the default authoring kit steps,
* especially <code>PageEdit</code> and <code>TextPageBody</code> in CMS.
* <p>
* <b>Advanced Usage</b>:<br>
* The <code>PropertyEditor</code> may be used to maintain
* visibility of any components, not just forms. The
* {@link #addComponent(String, String, Component)} method
* can be used to add an arbitrary component to the editor. The
* component will be shown in the list of links, along with other components
* and/or forms. The component will be shown as usual when the user clicks
* on a link. However, you must be sure to include a call to
* {@link #showDisplayPane(PageState)} when the component needs to be hidden.
* <p>
* In addition, it is possible to manually generate {@link ActionLink}s
* that will display the right components in the editor. The
* {@link #addComponent(String, Component)} method can be used to add
* a component to the <code>PropertyEditor</code> without automatically
* generating the link for it. The {@link #addVisibilityListener(ActionLink, String)}
* method can then be used to add an appropriate {@link ActionListener} to any
* {@link ActionLink}. For example:
*
* <blockquote><pre><code>// Add a form
* Form fooForm = new FooForm();
* editor.addComponent(FOO_FORM, fooForm);
* editor.addListeners(fooForm, fooForm.getCancelButton());
* // Create a link that shows the form
* fooLink = new ActionLink("Edit the Foo property");
* editor.addVisibilityListener(fooLink, FOO_FORM);</code></pre></blockquote>
*
* Note that the visibility of the form will be handled automatically. There
* is no need to show or hide it manually. This approach allows
* greater flexibility in placing links on a page. The links may be
* part of the editor's display pane, but they do not have to be.
* <p>
* <b>More-advanced Usage</b>:<br>
* The <code>PropertyEditor</code> is backed by a
* {@link PropertyEditorModel} through a {@link PropertyEditorModelBuilder}.
* Therefore, the <code>PropertyEditor</code> is a model-backed component,
* as described in the Bebop tutorials. This means that the list
* of properties for the editor could be generated dynamically during
* each request. The {@link #setModelBuilder(PropertyEditorModelBuilder)} method
* can be used to set a specialized {@link PropertyEditorModelBuilder} for the
* editor. In order to write the model builder, you may choose to extend the
* protected inner classes {@link PropertyEditor.DefaultModelBuilder} and
* {@link PropertyEditor.DefaultModel}. It is also possible to write the model
* builder and the corresponding model from scratch. However, most people won't
* need to do this.
* <p>
* For example, <code>SecurityPropertyEditor</code> uses a custom
* {@link PropertyEditorModelBuilder} in order to hide the links for properties
* which the web user is not allowed to edit.
* <p>
*
* @author Stanislav Freidin
* @version $Id: PropertyEditor.java 1638 2007-09-17 11:48:34Z chrisg23 $
*/
public class PropertyEditor extends SimpleContainer {
private SequentialMap m_forms;
private SequentialMap m_labels;
private Component m_display;
private Container m_displayPane;
private List m_list;
private PropertyEditorModelBuilder m_builder;
private RequestLocal m_model;
private java.util.List m_additionalDisplayComponents = new ArrayList();
/**
* Constructs a new, empty <code>PropertyEditor</code>.
* The {@link #setDisplayComponent(Component)} method must be called before
* this component is locked.
*/
public PropertyEditor() {
this(null);
}
/**
* Constructs a new <code>PropertyEditor</code> with the given
* display component. The pane defaults to a {@link
* com.arsdigita.bebop.SimpleContainer}.
*
* @param display the display component
*/
public PropertyEditor(Component display) {
this(display, new SimpleContainer());
}
/**
* Constructs a new <code>PropertyEditor</code> with the given
* display component and display pane.
*
* @param display the display component
* @param pane the display pane. The caller should pass in a
* freshly allocated Container.
*/
public PropertyEditor(Component display, Container pane) {
super();
setClassAttr("propertyEditor");
m_forms = new SequentialMap();
m_labels = new SequentialMap();
m_display = null;
m_displayPane = pane;
super.add(m_displayPane);
m_list = new List();
m_list.setCellRenderer(new IdentityCellRenderer());
// Change listener: reset visibility
// Should a ComponentSelectionModel be used here instead ? It's tempting,
// but there doesn't seem to be a real need for it
m_list.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
PageState state = e.getPageState();
// Get the visible component
Component c = null;
if ( !m_list.isSelected(state) ) {
// Select the display pane
c = m_displayPane;
} else {
c = getComponent(getSelectedComponentKey(state));
}
// Iterate over the forms
for(Iterator i = m_forms.values().iterator(); i.hasNext(); ) {
Component f = (Component)i.next();
f.setVisible(state, (f == c));
}
m_displayPane.setVisible(state, (m_displayPane == c));
}
});
// Don't add the list yet; add it when we add the display
// component
if(display != null)
setDisplayComponent(display);
// Prepare the model builder
setModelBuilder(new DefaultModelBuilder());
m_model = new RequestLocal() {
@Override
protected Object initialValue(PageState s) {
return getModelBuilder().makeModel(PropertyEditor.this, s);
}
};
}
/** Set the display component visible by default, and the
* form(s) invisible by default.
*/
@Override
public void register(Page p) {
Assert.exists(m_display, "display component");
p.setVisibleDefault(m_displayPane, true);
for(Iterator i = m_forms.values().iterator(); i.hasNext(); ) {
p.setVisibleDefault((Component)i.next(), false);
}
}
/**
* Hides the form(s) and shows the display pane.
*
* @param state the page state
*/
public void showDisplayPane(PageState state) {
m_list.clearSelection(state);
}
/**
* Shows the component that is identified by the specified key.
*
* @param state the page state
* @param key
*/
public void showComponent(PageState state, String key) {
m_list.setSelectedKey(state, key);
}
/**
* Returns the key of the currently visible component, or null if
* the display pane is currently visible.
* @param state the page state
*
* @return the key of the currently visible component, or null if the
* display pane is visible.
*/
public String getSelectedComponentKey(PageState state) {
return (String)m_list.getSelectedKey(state);
}
/**
* add an additional component below the list of links
* @param c
*/
public void addDisplayComponent(Component c) {
m_additionalDisplayComponents.add(c);
}
/**
* Adds the display component if it has not been added already.
*
* @param c the display component to add
*/
public void setDisplayComponent(Component c) {
if(m_display != null) {
throw new IllegalStateException("Display component has already been set");
}
m_displayPane.add(c);
m_displayPane.add(m_list);
Iterator it = m_additionalDisplayComponents.iterator();
while (it.hasNext()) {
m_displayPane.add((Component)it.next());
}
m_display = c;
}
/**
* Adds a component to the property editor. The component will be
* completely invisible. It is up to the user to call
* {@link #showComponent(PageState, String)} to display the component and to
* call {@link #showDisplayPane(PageState)} when the component needs to be hidden.
*
* @param key the symbolic key for the component (must be unique
* for this <code>PropertyEditor</code>)
* @param c the component
*/
public void addComponent(String key, Component c) {
m_forms.put(key, c);
super.add(c);
}
/**
* Adds a component to the list of links. It is up to the component to
* correctly call {@link #showDisplayPane(PageState)} when it is done.
*
* @param key the symbolic key for the component (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link
* @param c the component
* @deprecated use addComponent(String,GlobalizedMessage,Component) instead
*/
public void addComponent(String key, String label, Component c) {
addComponent(key, c);
m_labels.put(key, label);
}
/**
* Adds a component to the list of links. It is up to the component to
* correctly call {@link #showDisplayPane(PageState)} when it is done.
*
* @param key the symbolic key for the component (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link
* @param c the component
*/
public void addComponent(String key, GlobalizedMessage label, Component c) {
addComponent(key, c);
m_labels.put(key, label);
}
/**
* Adds a form to the set of forms that can be used to edit the
* properties.
*
* @param key the symbolic key for the form (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link
* @param form the form component
* @deprecated use add(String,GlobalizedMessage,Form) instead.
*/
public void add(String key, String label, Form form) {
addComponent(key, label, form);
addProcessListener(form);
}
/**
* Adds a form to the set of forms that can be used to edit the
* properties.
*
* @param key the symbolic key for the form (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link
* @param form the form component
*/
public void add(String key, GlobalizedMessage label, Form form) {
addComponent(key, label, form);
addProcessListener(form);
}
/**
* Adds a form to the set of forms that can be used to edit the
* properties.
*
* @param key the symbolic key for the form (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link
* @param form the form component
* @param cancelButton the Cancel button on the form
* @deprecated use add(String,GlobalizedMessage,Form,Submit) instead.
*/
public void add(String key, String label, Form form, Submit cancelButton) {
add(key, label, form);
addListeners(form, cancelButton);
}
/**
* Adds a form to the set of forms that can be used to edit the
* properties.
*
* @param key the symbolic key for the form (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link
* @param form the form component
* @param cancelButton the Cancel button on the form
*/
public void add(String key, GlobalizedMessage label, Form form, Submit cancelButton) {
add(key, label, form);
addListeners(form, cancelButton);
}
/**
* Adds a form to the set of forms that can be used to edit the
* properties.
*
* @param key the symbolic key for the form (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link
* @param formSection the form component
*
* @pre !(formSection instanceof Form)
* @deprecated use add(String,GlobalizedMessage,FormSection) instead.
*/
public void add(String key, String label, FormSection formSection) {
if (formSection instanceof Form) {
throw new IllegalArgumentException("formSection is an instance of Form");
}
Form form = new Form("property" + key);
form.add(new FormErrorDisplay(form), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
form.add(formSection);
form.setMethod(Form.POST);
form.setEncType("multipart/form-data");
add(key, label , form);
}
/**
* Adds a form to the set of forms that can be used to edit the
* properties.
*
* @param key the symbolic key for the form (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link
* @param formSection the form component
*
* @pre !(formSection instanceof Form)
*/
public void add(String key, GlobalizedMessage label, FormSection formSection) {
if (formSection instanceof Form) {
throw new IllegalArgumentException("formSection is an instance of Form");
}
Form form = new Form("property" + key);
form.add(new FormErrorDisplay(form), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
form.add(formSection);
form.setMethod(Form.POST);
form.setEncType("multipart/form-data");
add(key, label , form);
}
/**
* Adds a form to the set of forms that can be used to edit the properties.
*
* @param key the symbolic key for the form (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link
* @param formSection the form component
* @param cancelButton the Cancel button on the form
* @deprecated use add(String,GlobalizedMessage,FormSection,Submit) instead.
*/
public void add(String key,
String label,
FormSection formSection,
Submit cancelButton) {
Form form = new Form("property" + key);
form.add(new FormErrorDisplay(form), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
form.add(formSection);
form.setMethod(Form.POST);
form.setEncType("multipart/form-data");
add(key, label , form, cancelButton);
}
/**
* Adds a form to the set of forms that can be used to edit the
* properties.
*
* @param key the symbolic key for the form (must be unique
* for this <code>PropertyEditor</code>)
* @param label the label for the link as a GlobalizedMessage
* @param formSection the form component
* @param cancelButton the Cancel button on the form
*/
public void add(String key,
GlobalizedMessage label,
FormSection formSection,
Submit cancelButton) {
Form form = new Form("property" + key);
form.add(new FormErrorDisplay(form), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
form.add(formSection);
form.setMethod(Form.POST);
form.setEncType("multipart/form-data");
add(key, label , form, cancelButton);
}
/**
* Retrieves the component at the specified key.
*
* @param key the key of the component to retrieve
* @return a component that has been added to this
* <code>PropertyEditor</code> at the specified key, or null
* if no such component exists.
*/
public Component getComponent(String key) {
return (Component)m_forms.get(key);
}
/**
* Adds a submission listener to the form that will hide all components
* and show the display pane. This method should be used to add
* submission listeners to forms that are buried deep inside some
* component and are not members of this <code>PropertyEditor</code>.
*
* @param form the form
* @param cancelButton the Cancel button on the form
*/
public void addCancelListener(FormSection form, Submit cancelButton) {
// Add a different submission listener for each form since the
// cancel button may be different
final Submit theButton = cancelButton;
form.addSubmissionListener(new FormSubmissionListener() {
@Override
public void submitted(FormSectionEvent e) throws FormProcessException {
PageState state = e.getPageState();
if(theButton.isSelected(state)) {
showDisplayPane(state);
throw new FormProcessException(
"Submission Cancelled",
GlobalizationUtil.globalize("bebop.cancel.msg"));
}
}
});
}
/**
* Adds a process listener to the form that will hide all components
* and show the display pane. This method should be used to add
* process listeners to forms that are buried deep inside some
* component and are not members of this <code>PropertyEditor</code>.
*
* @param form the form
*/
public void addProcessListener(FormSection form) {
form.addProcessListener(new FormProcessListener() {
@Override
public void process(FormSectionEvent e) throws FormProcessException {
PageState state = e.getPageState();
showDisplayPane(state);
}
});
}
/**
* Adds all required listeners to the form to ensure that
* if the form is either submitted successfully or cancelled,
* the display pane will be shown. This method should be used
* to add listeners to forms that are buried deep inside some
* component, and are not members of this <code>PropertyEditor</code>.
*
* @param form the form
* @param cancelButton the Cancel button on the form
*/
public void addListeners(FormSection form, Submit cancelButton) {
addCancelListener(form, cancelButton);
addProcessListener(form);
}
/**
* This method can be used to add an {@link ActionListener} to any
* {@link ActionLink}, causing the action link to show the specified
* component when it is clicked. For example, this method may be useful
* if the {@link ActionLink} that is supposed to show the component is
* buried somewhere deep within the UI.
*
* @param l the {@link ActionLink}
* @param key the key of the component that will be shown when the link
* is clicked, as specified in the
* {@link #addComponent(String, Component)} method
* @see #addComponent(String, Component)
*/
public void addVisibilityListener(ActionLink l, String key) {
final String t_key = key;
l.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showComponent(e.getPageState(), t_key);
}
});
}
/**
* Returns the {@link List} that contains all the links.
* @return the {@link List} that contains all the links.
*/
public List getList() {
return m_list;
}
/**
* Returns the {@link PropertyEditorModelBuilder} that supplies this
* property editor with its {@link PropertyEditorModel} during each
* request.
*
* @return the {@link PropertyEditorModelBuilder} for this component.
*/
protected final PropertyEditorModelBuilder getModelBuilder() {
return m_builder;
}
/**
* Sets the {@link PropertyEditorModelBuilder} that will supply this
* property editor with its {@link PropertyEditorModel} during each
* request.
* @param b the property editor model builder
*/
protected final void setModelBuilder(PropertyEditorModelBuilder b) {
Assert.isUnlocked(this);
m_builder = b;
m_list.setModelBuilder(new BuilderAdapter(this));
}
/**
* Returns the {@link PropertyEditorModel} in use during the current
* request.
*
* @param s represents the current request
* @return the {@link PropertyEditorModel} that supplies the properties
* for the current request.
*/
protected final PropertyEditorModel getModel(PageState s) {
return (PropertyEditorModel)m_model.get(s);
}
/**
* Returns the display component.
* @return the display component.
*/
public Component getDisplayComponent() {
return m_display;
}
/**
* Returns the display pane (component + list).
* @return the display pane (component + list).
*/
public Container getDisplayPane() {
return m_displayPane;
}
/**
* Returns the map of labels.
* @return the map of labels.
*/
protected SequentialMap getLabelsMap() {
return m_labels;
}
/**
* Locks this component.
*/
@Override
public void lock() {
getModelBuilder().lock();
super.lock();
}
/**
* Renders the components generated by the model directly
*/
protected static class IdentityCellRenderer extends DefaultListCellRenderer {
@Override
public Component getComponent(List list, PageState state, Object value,
String key, int index, boolean isSelected) {
return (Component)value;
}
}
/**
* Default implementation of the {@link PropertyEditorModelBuilder}.
* Takes in a SequentialMap of key->label, and constructs a ControlLink for each
* label.
*/
protected static class DefaultModelBuilder
extends LockableImpl implements PropertyEditorModelBuilder {
public DefaultModelBuilder() {
super();
}
/**
* Return an iterator of all properties of the specified property
* editor. These properties should be passed into the constructor
* of the {@link PropertyEditor.DefaultModel}
* @param p
* @return
*/
protected Iterator getProperties(PropertyEditor p) {
return p.getLabelsMap().entrySet().iterator();
}
/**
* Construct a {@link PropertyEditorModel} for the current
* request.
*/
@Override
public PropertyEditorModel makeModel(PropertyEditor p, PageState s) {
return new DefaultModel(getProperties(p));
}
}
/**
* Internal class with default implementation of the {@link PropertyEditorModel}.
* Takes in an iterator of key->label pairs, and constructs a ControlLink
* for each label.
*/
protected static class DefaultModel implements PropertyEditorModel {
protected Iterator m_iter;
protected Map.Entry m_entry;
public DefaultModel(Iterator iter) {
m_iter = iter;
m_entry = null;
}
@Override
public boolean next() {
if(!m_iter.hasNext()) {
m_entry = null;
return false;
}
m_entry = (Map.Entry)m_iter.next();
return true;
}
/**
* Actually retrieve action link and label. Will be executed at each
* request to ensure proper localization.
* @return
*/
@Override
public Component getComponent() {
Assert.exists(m_entry);
if ( m_entry.getValue() instanceof GlobalizedMessage ) {
ControlLink l = new ControlLink(new
Label((GlobalizedMessage)m_entry.getValue()));
l.setClassAttr("actionLink");
return l;
} else {
ControlLink l = new ControlLink(new Label((String)m_entry.getValue()));
l.setClassAttr("actionLink");
return l;
}
}
@Override
public Object getKey() {
Assert.exists(m_entry);
return m_entry.getKey();
}
}
/**
* Adapts a {@link PropertyEditorModelBuilder} to a {@link ListModelBuilder}
*/
private static final class BuilderAdapter extends LockableImpl
implements ListModelBuilder {
private final PropertyEditor m_parent;
public BuilderAdapter(PropertyEditor parent) {
super();
m_parent = parent;
}
@Override
public ListModel makeModel(List l, PageState state) {
return new ModelAdapter(m_parent.getModel(state));
}
}
/**
* Adapts a {@link PropertyEditorModel} to a {@link ListModel}
*/
private static final class ModelAdapter implements ListModel {
private final PropertyEditorModel m_model;
public ModelAdapter(PropertyEditorModel model) {
m_model = model;
}
@Override
public boolean next() { return m_model.next(); }
@Override
public Object getElement() { return m_model.getComponent(); }
@Override
public String getKey() { return m_model.getKey().toString(); }
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
/**
* Provides properties for the {@link PropertyEditor} during
* each request. This class is intended for advanced users only.
*
* @author Stanislav Freidin
* @version $Id: PropertyEditorModel.java 287 2005-02-22 00:29:02Z sskracic $
* @see PropertyEditorModelBuilder
*/
public interface PropertyEditorModel {
/**
* Advances to the next property, if possible.
*
* @return <code>false</code> if there are no more properties;
* <code>true</code> otherwise.
*/
boolean next();
/**
* Returns the component that should act as a "button" for editing the
* property. Typically, this method returns a {@link ControlLink}
* of some sort. When the link is clicked, the {@link PropertyEditor}
* will display the pane for editing the property.
*
* @return a component (usually a {@link ControlLink}) that will act
* as the "button" for editing the property.
*/
Component getComponent();
/**
* Returns the unique key of the current property, usually
* a simple String.
*
* @return the key of the current property.
*/
Object getKey();
}

View File

@ -1,42 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.util.Lockable;
/**
* Generates a {@link PropertyEditorModel} for the {@link PropertyEditor}
* during each request. This class is intended for advanced users only.
*
* @author Stanislav Freidin
* @version $Id: PropertyEditorModelBuilder.java 287 2005-02-22 00:29:02Z sskracic $
* @see PropertyEditor
*/
public interface PropertyEditorModelBuilder extends Lockable {
/**
* Constructs a {@link PropertyEditorModel} for the current request.
* @param p the parent {@link PropertyEditor}
* @param s represents the current request
* @return the {@link PropertyEditorModel} for the current request.
*/
PropertyEditorModel makeModel(PropertyEditor p, PageState s);
}

View File

@ -1,66 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.globalization.GlobalizedMessage;
/**
* An abstraction that the
* {@link PropertySheet} class uses to display a
* 2-column table of label-value pairs.
*
* @author Stanislav Freidin
* @version $Id: PropertySheetModel.java 287 2005-02-22 00:29:02Z sskracic $
* @see PropertySheetModelBuilder
*/
public interface PropertySheetModel {
/**
* Advances to the next property, if possible.
*
* @return <code>false</code> if there are no more properties;
* <code>true</code> otherwise.
*/
boolean nextRow();
/**
* Returns the label for the current property.
*
* @return the current label.
* @deprecated use getGlobalizedLabel() instead
*/
String getLabel();
/**
* Returns the GlobalizedMessage for the current property
* @return the current GlobalizedMessage
*/
GlobalizedMessage getGlobalizedLabel();
/**
* Returns the string representation of the current property.
*
* @return the current value formatted as a string.
*/
String getValue();
}

View File

@ -1,142 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* A variable whose value is local to each request. Objects that need to store
* values that change in every request should declare them to be
* <code>RequestLocal</code>. These variables hold their values only during a
* duration of a request. They get reinitialized by a call to {@link
* #initialValue(PageState)} for every new HTTP request.
*
* <p> For example, a class that wants to implement a request local property
* <code>foo</code> would do the following:</p>
*
* <pre>
* public class SomeClass {
* private RequestLocal m_foo;
*
* public SomeClass() {
* m_foo = new RequestLocal() {
* protected Object initialValue(PageState s) {
* // Foo could be a much more complicated value
* return s.getRequestURI();
* }
* };
* }
*
* public String getFoo(PageState s) {
* return (String) m_foo.get(s);
* }
*
* public void setFoo(PageState s, String v) {
* m_foo.set(s, v);
* }
* }
* </pre>
*
* @author David Lutterkort
* @version $Id$
*/
public class RequestLocal {
private static final String ATTRIBUTE_KEY =
"com.arsdigita.bebop.RequestLocal";
// Fetch the map used to store RequestLocals, possibly creating it along the
// way
private Map getMap(HttpServletRequest request) {
// This lock is paranoid. We can remove it if we know that only one
// thread will be touching a request object at a time. (Seems likely,
// but, like I said, I'm paranoid.)
synchronized (request) {
Map result = (Map)request.getAttribute(ATTRIBUTE_KEY);
result = (Map)request.getAttribute(ATTRIBUTE_KEY);
if (result == null) {
result = new HashMap();
request.setAttribute(ATTRIBUTE_KEY, result);
}
return result;
}
}
/**
* Returns the value to be used during the request represented by
* <code>state</code>. This method is called at most once per request,
* the first time the value of this <code>RequestLocal</code> is
* requested with {@link #get get}. <code>RequestLocal</code> must be
* subclassed, and this method must be overridden. Typically, an
* anonymous inner class will be used.
*
*
* @param state represents the current state of the request
* @return the initial value for this request local variable.
*/
protected Object initialValue(PageState state) {
return null;
}
/**
* Returns the request-specific value for this variable for the request
* associated with <code>state</code>.
*
* @param state represents the current state of the request
* @return the value for this request local variable.
*/
public Object get(PageState state) {
Map map = getMap(state.getRequest());
Object result = map.get(this);
if ( result == null && !map.containsKey(this) ) {
result = initialValue(state);
set(state, result);
}
return result;
}
/**
* Sets a new value for the request local variable and associates it with
* the request represented by <code>state</code>.
*
* @param state represents the current state of the request
* @param value the new value for this request local variable
*/
public void set(PageState state, Object value) {
set(state.getRequest(), value);
}
/**
* <p>Sets a new value for the request local variable and associates it with
* the request represented by <code>request</code></p>
*
* <p>This method is intended for use when a Dispatcher needs to assign some
* value to a RequestLocal for Bebop Page processing before Page processing
* begins.</p>
*
* @param request represents the current request
* @param value the new value for this request local variable
*/
public void set(HttpServletRequest request, Object value) {
getMap(request).put(this, value);
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.PageState;
/**
*
* Interface that should be implemented by components that have
* state parameters that need to be reset when the component is shown
* to the user. The details of when the reset method is called are left
* to the application programmer.
*
* @version $Id$
*/
public interface Resettable {
/**
* Resets the state of the component to its original
* appearance.
*
* @param state the page state
*/
void reset(PageState state);
}

View File

@ -1,82 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.bebop.util.GlobalizationUtil;
/**
* A form section with two buttons (Save and Cancel) aligned to
* the right.
*
* @author Stanislav Freidin
* @author Sören Bernstein <quasi@quasiweb.de>
* @version $Id: SaveCancelSection.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class SaveCancelSection extends FormSection {
private Submit m_saveWidget, m_cancelWidget;
/**
* Constructs a new SaveCancelSection.
*/
public SaveCancelSection() {
super(new BoxPanel(BoxPanel.HORIZONTAL, false));
BoxPanel panel = (BoxPanel)getPanel();
panel.setWidth("2%");
createWidgets();
add(m_saveWidget, BoxPanel.RIGHT);
add(m_cancelWidget, BoxPanel.RIGHT);
}
public SaveCancelSection(Container c) {
super(c);
createWidgets();
add(m_saveWidget);
add(m_cancelWidget);
}
private void createWidgets() {
m_saveWidget = new Submit("save");
m_saveWidget.setButtonLabel(GlobalizationUtil.globalize("bebop.save"));
m_cancelWidget = new Submit("cancel");
m_cancelWidget.setButtonLabel(GlobalizationUtil.globalize("bebop.cancel"));
}
/**
* Gets the Save button.
* @return the Save button.
*/
public Submit getSaveButton() {
return m_saveWidget;
}
/**
* Gets the Cancel button.
* @return the Cancel button.
*/
public Submit getCancelButton() {
return m_cancelWidget;
}
}

View File

@ -1,297 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import static com.arsdigita.bebop.Component.*;
import static com.arsdigita.bebop.util.BebopConstants.*;
import com.arsdigita.xml.Element;
import com.arsdigita.util.Assert;
import com.arsdigita.bebop.util.BebopConstants;
import java.util.Iterator;
/**
* Generates a list of segments. Each segment consists of a header (which could
* be any Bebop component) and a body (which, likewise, could be any component).
* The entire <code>SegmentedPanel</code> look roughly like this:
*
* <blockquote><pre><code>
* ----------------------
* Header 1
* ----------------------
* Body 1
* More Body 1
* Even more Body 1
* ----------------------
* Header 2
* ----------------------
* Body 2
* More Body 2
* Even more Body 2
* </code></pre></blockquote>
*
* Typically, the body of each segment will be a {@link SimpleContainer} which
* contains many other components
* <p>
* The XML generated by this component looks something like this:
* <blockquote><pre><code>
* &lt;bebop:segmentedPanel&gt;
* &lt;bebop:segment id="foo"&gt;
* &lt;bebop:segmentHeader&gt;
* &lt;aRandomHeaderComponent/&gt;
* &lt;anotherRandomHeaderComponent/&gt;
* ...
* &lt;/bebop:segmentHeader&gt;
* &lt;bebop:segmentBody&gt;
* &lt;aRandomBodyComponent&gt;
* &lt;anotherRandomBodyComponent&gt;
* ...
* &lt;/bebop:segmentBody&gt;
* &lt;/bebop:segment&gt;
* ...
* &lt;/bebop:segmentedPanel&gt;
* </code></pre></blockquote>
*
* @see #generateXML(PageState, Element)
*
* @author Michael Pih
* @version $Id$
*/
public class SegmentedPanel extends SimpleContainer
implements BebopConstants {
public static final String HEADER_CLASS = "seg-header";
/**
* Construct a new <code>SegmentedPanel</code>
*/
public SegmentedPanel() {
super();
}
/**
* Construct a new <code>SegmentedPanel</code>
*
* @param idAttr the XSL ID attribute for this container
* @see SimpleComponent#setIdAttr(String)
*/
public SegmentedPanel(String idAttr) {
this();
setIdAttr(idAttr);
}
/**
* Add a segment to this container
*
* @param header the component that will act as the header
* @param body the component that will act as the body
* @return the new segment
*/
public Segment addSegment(Component header, Component body) {
Segment s = new Segment(header, body);
add(s);
return s;
}
/**
* Add a segment to this container.
*
* @param segmentID the XSL ID attribute for the new segment.
* @param header the component that will act as the header.
* @param body the component that will act as the body
* @return the new segment
*/
public Segment addSegment(String segmentID, Component header, Component body) {
Segment s = addSegment(header, body);
s.setIdAttr(segmentID);
return s;
}
/**
* Add a segment to this container.
*
* @param segmentID the XSL ID attribute for the new segment. The XSL
* template for this component will render the correct header based on the
* ID attribute
* @param body the component that will act as the body
* @return the new segment
*/
public Segment addSegment(String segmentID, Component body) {
return addSegment(segmentID, null, body);
}
/**
* Add and return a new empty segment.
*
* @return a new empty segment that is part of the panel.
*/
public Segment addSegment() {
Segment result = new Segment();
add(result);
return result;
}
/**
* Generate the XML for this component, as described above
*
* @param state represents the page state for the current request
* @param parent the parent XML element
*/
@Override
public void generateXML(PageState state, Element parent) {
if (isVisible(state)) {
Element panel = parent.
newChildElement(BEBOP_SEG_PANEL, BEBOP_XML_NS);
exportAttributes(panel);
super.generateXML(state, panel);
}
}
/**
* A single Segment within this container
*/
public static class Segment extends SimpleContainer {
private SimpleContainer m_header;
private SimpleContainer m_body;
/**
* Construct an empty <code>Segment</code>
*/
public Segment() {
this(null, null);
}
/**
* Construct a new <code>Segment</code>
*
* @param header the component which will act as the header; the XSL
* class attribute for the component will be set to
* {@link #HEADER_CLASS}. Typically, this component will be a
* {@link Label}
* @param body the component which represents the body of the segment,
* Typically, this component will be a {@link SimpleContainer} or a
* panel of some sort
*/
public Segment(Component header, Component body) {
super();
if (header != null) {
addHeader(header);
}
if (body != null) {
add(body);
}
}
/**
* Construct a new <code>Segment</code> with no header
*
* @param body the component which represents the body of the segment,
* Typically, this component will be a {@link SimpleContainer} or a
* panel of some sort
*/
public Segment(Component body) {
this(null, body);
}
/**
* Add a header component.
*
* @param c an additional header component
*/
public void addHeader(Component c) {
Assert.isUnlocked(this);
if (m_header == null) {
m_header = new SimpleContainer(BEBOP_SEG_HEADER, BEBOP_XML_NS);
super.add(m_header);
}
m_header.add(c);
}
/**
* Add a component to the body of this segment
*
* @param c
*/
@Override
public void add(Component c) {
Assert.isUnlocked(this);
if (m_body == null) {
m_body = new SimpleContainer(BEBOP_SEG_BODY, BEBOP_XML_NS);
super.add(m_body);
}
m_body.add(c);
}
/**
* Add a component to the body of this segment
*
* @param c
*/
@Override
public void add(Component c, int constraints) {
add(c);
}
// @Override
// public boolean isVisible(final PageState state) {
// boolean result = super.isVisible(state);
//
// if (m_header != null) {
// result = result && m_header.isVisible(state);
//
// final Iterator children = m_header.children();
// while (children.hasNext()) {
// final Component component = (Component) children.next();
// result = result && component.isVisible(state);
// }
// }
//
// if (m_body != null) {
// result = result && m_body.isVisible(state);
//
// final Iterator children = m_body.children();
// while (children.hasNext()) {
// final Component component = (Component) children.next();
// result = result && component.isVisible(state);
// }
// }
//
// return result;
// }
/**
* Generate the XML for this segment
*
* @param state the current page state
* @param parent the parent XML element
*/
@Override
public void generateXML(PageState state, Element parent) {
if (isVisible(state)) {
Element seg = parent.
newChildElement(BEBOP_SEGMENT, BEBOP_XML_NS);
exportAttributes(seg);
super.generateXML(state, seg);
}
}
}
}

View File

@ -1,30 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import javax.servlet.ServletException;
/**
*
*
* @version $Id: SessionExpiredException.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class SessionExpiredException extends ServletException {
}

View File

@ -1,368 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import java.util.Collections;
import java.util.Iterator;
import com.arsdigita.bebop.util.Attributes;
import com.arsdigita.kernel.KernelConfig;
import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element;
/**
* A simple implementation of the Component interface.
*
*
* @author David Lutterkort
* @author Stanislav Freidin
* @author Rory Solomon
* @author Uday Mathur
*
* @version $Id: SimpleComponent.java 1498 2007-03-19 16:22:15Z apevec $
*/
public class SimpleComponent extends Completable
implements Component, Cloneable {
private boolean m_locked;
/**
* The Attribute object is protected to make it easier for the Form Builder
* service to persist the SimpleComponent. Locking violation is not a
* problem since if the SimpleComponent is locked then the Attribute object
* will also be locked.
*/
protected Attributes m_attr;
private String m_key = null; // name mangling key
/**
* Clones a component. The clone is not locked and has its own set of
* attributes.
*
* @return the clone of a component.
*
* @throws java.lang.CloneNotSupportedException If cloning is not supported.
*/
@Override
public Object clone() throws CloneNotSupportedException {
SimpleComponent result = (SimpleComponent) super.clone();
if (m_attr != null) {
result.m_attr = (Attributes) m_attr.clone();
}
result.m_locked = false;
return result;
}
/**
* Registers state parameters for the page with its model. Documentation
* from Interface Componment:
*
* A simple component with a state parameter <code>param</code> would do the
* following in the body of this method:
* <pre>
* p.addComponent(this);
* p.addComponentStateParam(this, param);
* </pre>
*
* You should override this method to set the default visibility of your
* component:
*
* <pre>
* public void register(Page p) {
* super.register(p);
* p.setVisibleDefault(childNotInitiallyShown,false);
* p.setVisibleDefault(anotherChild, false);
* }
* </pre>
*
* Always call <code>super.register</code> when you override
* <code>register</code>. Otherwise your component may malfunction and
* produce errors like "Widget ... isn't associated with any Form"
*
* @param p
*/
@Override
public void register(Page p) {
return;
}
/**
* Registers form parameters with the form model for this form. This method
* is only important for {@link FormSection form sections} and
* {@link com.arsdigita.bebop.form.Widget widgets} (components that have a
* connection to an HTML form). Other components can implement it as a
* no-op.
*
* @param f The form the register.
* @param m The form model to use with the form.
*
*/
@Override
public void register(Form f, FormModel m) {
return;
}
/**
* Does processing that is special to the component receiving the click.
*
* @param state The current page state
*
* @throws javax.servlet.ServletException If an error occurs.
*/
@Override
public void respond(PageState state)
throws javax.servlet.ServletException {
}
@Override
public Iterator children() {
return Collections.EMPTY_LIST.iterator();
}
/**
* Adds [J]DOM nodes for this component. Specifically for base class
* SimpleComponent, does nothing.
*
* @param state The current page state.
* @param p The parent element. All elements generated in the method will
* be child elements of {@code p}.
*/
@Override
public void generateXML(PageState state, Element p) {
return;
}
@Override
public final boolean isLocked() {
return m_locked;
}
@Override
public void lock() {
if (m_attr != null) {
m_attr.lock();
}
m_locked = true;
}
/**
* Unlocks this component. Package visibility is intentional; the only time
* a component should be unlocked is when it's pooled and gets locked
* because it's put into a page. It needs to be unlocked when the instance
* is recycled.
*/
void unlock() {
m_locked = false;
}
/* Working with standard component attributes */
/**
* Gets the class attribute.
*
* @return the class attribute.
*/
@Override
public String getClassAttr() {
return getAttribute(CLASS);
}
/**
* Sets the class attribute.
*
* @param theClass a valid <a
* href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Name">XML name</a>
*/
@Override
public void setClassAttr(String theClass) {
Assert.isUnlocked(this);
setAttribute(CLASS, theClass);
}
/**
* Gets the style attribute.
*
* @return the style attribute.
*/
@Override
public String getStyleAttr() {
return getAttribute(STYLE);
}
/**
* Sets the style attribute. <code>style</code> should be a valid CSS style,
* since its value will be copied verbatim to the output and appear as a
* <tt>style</tt> attribute in the top level XML or HTML output element.
*
* @param style a valid CSS style description for use in the
* <tt>style</tt> attribute of an HTML tag
*
* @see <a href="#standard">Standard Attributes</a>
*/
@Override
public void setStyleAttr(String style) {
Assert.isUnlocked(this);
setAttribute(STYLE, style);
}
/**
* Gets the <tt>id</tt> attribute.
*
* @return the <tt>id</tt> attribute.
*
* @see #setIdAttr(String id)
*/
@Override
public String getIdAttr() {
return getAttribute(ID);
}
/**
* Sets the <tt>id</tt> attribute. <code>id</code> should be an <a
* href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Name">XML name</a>
* that is unique within the {@link Page Page} in which this component is
* contained. The value of <code>id</code> is copied literally to the output
* and not used for internal processing.
*
* @param id a valid XML identifier
*
* @see <a href="#standard">Standard Attributes</a>
*/
@Override
public void setIdAttr(String id) {
Assert.isUnlocked(this);
setAttribute(ID, id);
}
/* Methods for attribute management */
/**
* Sets an attribute. Overwrites any old values. These values are used to
* generate attributes for the top level XML or HTML element that is output
* from this component with {@link #generateXML generateXML}.
*
* @param name attribute name, case insensitive
* @param value new attribute value
*/
final protected void setAttribute(String name, String value) {
Assert.isUnlocked(this);
if (m_attr == null) {
m_attr = new Attributes();
}
m_attr.setAttribute(name, value);
}
/**
* Gets the value of an attribute.
*
*
* @param name attribute name, case insensitive
*
* @return the string value previously set with {@link #setAttribute
* setAttribute}, or <code>null</code> if none was set.
*
* @see #setAttribute
*/
final protected String getAttribute(String name) {
return (m_attr == null) ? null : m_attr.getAttribute(name);
}
/**
* Adds the attributes set with {@link #setAttribute setAttribute} to the
* element <code>target</code>. The attributes set with
* <code>exportAttributes</code> overwrite attributes with identical names
* that <code>target</code> might already have.
*
* @param target element to which attributes are added
*
* @see #setAttribute
*/
final protected void exportAttributes(com.arsdigita.xml.Element target) {
if (m_attr != null) {
m_attr.exportAttributes(target);
}
if (KernelConfig.getConfig().isDebugEnabled() || BebopConfig.getConfig()
.getShowClassName()) {
target.addAttribute("bebop:classname", getClass().getName(),
BEBOP_XML_NS);
}
}
/**
* Returns <code>true</code> if any attributes have been set.
*
* @return <code>true</code> if any attributes have been set;
* <code>false</code> otherwise.
*/
final protected boolean hasAttributes() {
return m_attr != null;
}
/*
* Set an arbitrary meta data attribute on the component.
* The name of the attribute in the XML will be prefixed
* with the string 'metadata.'
*/
final public void setMetaDataAttribute(String name, String value) {
setAttribute("metadata." + name, value);
}
final public String getMetaDataAttribute(String name) {
return getAttribute("metadata." + name);
}
/**
* Supplies a key for parameter name mangling.
*
* @param key the key to mangle
*
* @return This component.
*/
@Override
public Component setKey(String key) {
Assert.isUnlocked(this);
if (key.charAt(0) >= 0 && key.charAt(0) <= 9) {
throw new IllegalArgumentException("key \"" + key
+ "\" must not start with a digit.");
}
m_key = key;
return this;
}
/**
* Retrieves a key for parameter name mangling.
*
* @return a key for parameter name mangling.
*/
@Override
public final String getKey() {
return m_key;
}
@Override
public boolean isVisible(PageState s) {
return s.isVisible(this);
}
@Override
public void setVisible(PageState s, boolean v) {
s.setVisible(this, v);
}
}

View File

@ -1,267 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element;
/**
* A basic implementation of the {@link Container} interface which, by default,
* renders all of its children directly, without wrapping them in any kind of
* tag.
*
* However, the {@link #SimpleContainer(String, String)} constructor and/or the
* {@link #setTag(String)} method can be used to cause the container to wrap
* the XML for its children in an arbitrary tag. This functionality is useful
* for XSL templating.
*
* For example, a template rule might be written to arrange the children of this
* component in paragraphs:
*
* <blockquote><pre><code>
* // Java Code:
* m_container = new SimpleContainer("cms:foo", CMS_XML_NS);
*
* // XSL code:
* &lt;xsl:template match="cms:foo"&gt;
* &lt;xsl:for-each select="*"&gt;
* &lt;p&gt;
* &lt;xsl:apply-templates select="."/&gt;
* &lt;/p&gt;
* &lt;/xsl:for-each&gt;
* &lt;/xsl:template&gt;
* </code></pre></blockquote>
*
* @author David Lutterkort
* @author Stanislav Freidin
* @author Rory Solomon
* @author Uday Mathur
*
* @version $Id: SimpleContainer.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class SimpleContainer extends SimpleComponent implements Container {
private List m_components;
private String m_tag, m_ns;
/**
* Constructs a new, empty <code>SimpleContainer</code>.
*/
public SimpleContainer() {
this(null, null);
}
/**
* Constructs a new, empty <code>SimpleContainer</code> that will
* wrap its children in the specified tag.
*
* @param tag the name of the XML element that will be used to wrap the
* children of this container
* @param ns the namespace for the tag
*/
public SimpleContainer(String tag, String ns) {
super();
m_components = new ArrayList();
m_tag = tag;
m_ns = ns;
}
/**
* Adds a component to this container.
*
* @param pc the component to be added
*/
public void add(Component pc) {
Assert.isUnlocked(this);
m_components.add(pc);
}
/**
* Adds a component to this container.
*
* @param pc the component to be added
* @param constraints this parameter is ignored. Child classes should
* override the add method if they wish to provide special handling
* of constraints.
*/
public void add(Component c, int constraints) {
add(c);
}
/**
* Determines membership.
* @return <code>true</code> if the specified object is in this container;
* <code>false</code> otherwise.
* @param o the object type, typically a component. Type
* Object allows slicker code when o comes from any kind of collection.
*/
public boolean contains(Object o) {
return m_components.contains(o);
}
/**
* Determines whether the container is empty.
*
* @return <code>false</code> if the container has any children;
* <code>true</code> otherwise.
*/
public boolean isEmpty() {
return m_components.isEmpty();
}
/**
*
*
*
*/
public int indexOf(Component pc) {
return m_components.indexOf(pc);
}
/**
* Returns the number of children inside this container.
* @return the number of children inside this container.
*/
public int size() {
return m_components.size();
}
/**
*
*
*
*/
public Component get(int index) {
return (Component) m_components.get(index);
}
/**
* Returns all the components of this container.
* @return all the components of this container.
*/
@Override
public Iterator children() {
return m_components.iterator();
}
/**
* Sets the XML tag that will be used to wrap the children of
* this container.
*
* @param tag the XML tag, or null if children will not be wrapped
* in any manner.
*/
protected final void setTag(String tag) {
Assert.isUnlocked(this);
m_tag = tag;
}
/**
* Sets the XML namespace for the tag that will be used to wrap
* the children of this container.
*
* @param ns the XML namespace
*/
protected final void setNamespace(String ns) {
Assert.isUnlocked(this);
m_ns = ns;
}
/**
* Retrieves the name of the XML tag that will be used to
* wrap the child components.
*
* @return the name of the XML tag that will be used to
* wrap the child components, or null if no tag was specified.
*/
public final String getTag() {
return m_tag;
}
/**
* Retrieves the name of the XML namespace for the tag that will be used to
* wrap the child components.
*
* @return the name of the XML namespace for the tag that will be used to
* wrap the child components, or null if no namespace was specified.
*/
public final String getNamespace() {
return m_ns;
}
/**
* Generates the containing element. It is added with this
* component's tag below the specified parent element. If the passed in
* element is null, the method
* passes through p.
* @param p the parent XML element
* @return the element to which the children will be added.
*/
protected Element generateParent(Element p) {
String tag = getTag();
if (tag == null) {
return p;
}
Element parent = p.newChildElement(tag, getNamespace());
exportAttributes(parent);
return parent;
}
/**
* Generates the XML for this container. If the tag property
* is nonempty, wraps the children in the specified XML tag.
*
* @param state represents the current request
* @param p the parent XML element
* @see #setTag(String)
* @see #setNamespace(String)
*/
public void generateChildrenXML(PageState state, Element p) {
for (Iterator i = children(); i.hasNext(); ) {
Component c = (Component) i.next();
// XXX this seems to be a redundant vis check
if ( c.isVisible(state) ) {
c.generateXML(state, p);
}
}
}
/**
* Generates the XML for this container. If the tag property
* is nonempty, wraps the children in the specified XML tag.
*
* @param state represents the current request
* @param p the parent XML element
* @see #setTag(String)
* @see #setNamespace(String)
*/
@Override
public void generateXML(PageState state, Element p) {
if ( isVisible(state) ) {
Element parent = generateParent(p);
generateChildrenXML(state, parent);
}
}
}

View File

@ -1,116 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.bebop.parameters.ParameterModel;
/**
* Encapsulates the selection of a single object from many
* possibilities. The <code>SingleSelectionModel</code> allows components to
* communicate selections without tying the component that manages the
* selection in the user interface (for example a {@link List}) to the
* components that consume the selection (such as an edit form that needs
* to know which object should be edited).
*
* <p> Selections are identified by a key, which must identify the
* underlying object uniquely among all objects that could possibly be
* selected. For objects stored in a database, this is usually a suitable
* representation of the object's primary key. The model relies on the
* key's <code>equals</code> method to compare keys, and requires that the
* key's <code>toString</code> method produces a representation of the key
* that can be used in URL strings and hidden form controls.
*
* Edit for CCM NG: Added generics.
*
* @param <T> Type for the key
*
* @author David Lutterkort
* @author Jens Pelzetter
*/
public interface SingleSelectionModel<T> {
/**
* Returns <code>true</code> if there is a selected element.
*
* @param state the state of the current request
* @return <code>true</code> if there is a selected component;
* <code>false</code> otherwise.
*/
boolean isSelected(PageState state);
/**
* Returns the key that identifies the selected element.
*
* @param state a <code>PageState</code> value
* @return a <code>String</code> value.
*/
T getSelectedKey(PageState state);
/**
* Sets the selected key. If <code>key</code> is not in the collection of
* objects underlying this model, an
* <code>IllegalArgumentException</code> is thrown.
*
* @param state the state of the current request
* @param key the selected key
* @throws IllegalArgumentException if the supplied <code>key</code> can not
* be selected in the context of the current request.
*/
void setSelectedKey(PageState state, T key);
/**
* Clears the selection.
*
* @param state the state of the current request
*/
void clearSelection(PageState state);
/**
* Adds a change listener to the model. The listener's
* <code>stateChanged</code> method is called whenever the selected key changes.
*
* @param changeListener a listener to notify when the selected key changes
*/
void addChangeListener(ChangeListener changeListener);
/**
* Removes a change listener from the model.
*
* @param changeListener the listener to remove
*/
void removeChangeListener(ChangeListener changeListener);
/**
* Returns the state parameter that will be used to keep track
* of the currently selected key. Typically, the implementing
* class will simply call:
*
* {@code return new StringParameter("foo");}
*
* This method may return null if a state parameter is not
* appropriate in the context of the implementing class.
*
* @return the state parameter to use to keep
* track of the currently selected component, or
* null if a state parameter is not appropriate.
*/
ParameterModel getStateParameter();
}

View File

@ -1,523 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop;
import static com.arsdigita.bebop.Component.*;
import com.arsdigita.bebop.parameters.IntegerParameter;
import com.arsdigita.util.Assert;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.xml.Element;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import javax.servlet.ServletException;
/* FIXME: Add methods for using images in the tab strip */
/**
* A tabbed pane that lets the user switch between components by clicking on a
* given title in the tab strip.
* <p>
* Tabs (components) are added using the {@link #addTab addTab} method. Each
* entry consists of a label (which is a string) and the {@link Component} that
* is displayed if the user clicks on the label.
* <p>
* There is always exactly one component that is currently visible, the
* component that is returned by {@link #getCurrentPane}. Without user
* interaction, this is the default pane -- that was set by
* {@link #setDefaultPane} -- or, if none has been set, the first component that
* was added to the <code>TabbedPane</code>.
* <p>
*
* @author David Lutterkort
* @author Stanislav Freidin
* @author Uday Mathur
* @version $Id$
*/
public class TabbedPane extends SimpleContainer {
private static final String CURRENT_PANE = "pane";
/**
* The name for the event to change the selected pane. The value is the
* index of the pane
*/
private static final String SELECT_EVENT = "select";
private Pane m_defaultPane;
private IntegerParameter m_currentPaneParam;
private List m_actionListeners;
private static final Logger LOGGER = LogManager.getLogger(TabbedPane.class
.getName());
/**
* Constructs an empty TabbedPane.
*/
public TabbedPane() {
m_currentPaneParam = new IntegerParameter(CURRENT_PANE);
}
/**
* Registers with the specified root container. Adds a state parameter to
* keep track of the visible component to the page.
*
* @param p the root container to register with
*
* @pre p != null
*/
public void register(Page p) {
Assert.isUnlocked(this);
p.addComponentStateParam(this, m_currentPaneParam);
// if there is no default pane, then set it to the first one
// in the list
Iterator i = children();
if (!i.hasNext()) {
LOGGER.warn("TabbedPane registered with no panes");
} else if (m_defaultPane == null) {
setDefaultPaneIndex(0);
}
while (i.hasNext()) {
Pane pane = (Pane) i.next();
p.setVisibleDefault(pane.getComponent(), pane == m_defaultPane);
}
}
/**
* Adds a new pane to the dialog. Assigns a rather unhelpful default label
* (the pane number) to the component. Use {@link #addTab addTab} instead.
*
* @pre pc != null
*/
public void add(Component pc) {
addTab(String.valueOf(size()), pc);
}
/**
* Adds a new pane with layout constraints to the dialog. Ignores the
* constraints. Assigns a rather unhelpful default label (the pane number)
* to the component. Use {@link #addTab
* addTab} instead.
*
* @pre pc != null
*/
public void add(Component pc, int constraints) {
add(pc);
}
/**
* Adds a tab and its associated component.
*
* @param label the text to display in the tab strip
* @param c the component to display when the user clicks on the
* <code>label</code> in the tab strip
*
* @pre label != null && c != null
*/
public void addTab(Component label, Component c) {
Assert.isUnlocked(this);
super.add(new Pane(label, c));
}
/**
* Adds a tab and its associated component.
*
* @param label the text to display in the tab strip
* @param c the component to display when the user clicks on the
* <code>label</code> in the tab strip
*
* @pre label != null && c != null
*/
public void addTab(String label, Component c) {
addTab(new Label(label), c);
}
/**
* Adds an <code>ActionListener</code>, which is run whenever {@link
* #respond respond} is called.
*
* @param 1 the action listener
*
* @pre l != null
* @pre ! isLocked()
* @see #respond respond
*/
public void addActionListener(ActionListener l) {
Assert.isUnlocked(this);
if (m_actionListeners == null) {
m_actionListeners = new ArrayList();
}
m_actionListeners.add(l);
}
/**
* Removes a previously added <code>ActionListener</code>.
*
* @param 1 the action listener to remove
*
* @see #addActionListener addActionListener
*/
public void removeActionListener(ActionListener l) {
Assert.isUnlocked(this);
if (m_actionListeners == null) {
return;
}
m_actionListeners.remove(l);
}
/**
* Fires an <code>ActionEvent</code>. All registered
* <code>ActionListener</code>s are run. The source of the event is the
* <code>TabbedPane</code>.
*
* @param state the current page state
*
* @pre state != null
* @see #respond respond
*/
protected void fireActionEvent(PageState state) {
ActionEvent e = null;
if (m_actionListeners == null) {
return;
}
for (Iterator i = m_actionListeners.iterator(); i.hasNext();) {
if (e == null) {
e = new ActionEvent(this, state);
}
((ActionListener) i.next()).actionPerformed(e);
}
}
/**
* Sets the index of the default pane, which is visible until the user
* clicks on another label in the tab strip.
*
* @param i the index of the default pane
*/
protected void setDefaultPaneIndex(int i) {
m_currentPaneParam.setDefaultValue(new Integer(i));
m_defaultPane = (Pane) get(i);
}
/**
* Sets the default pane, which is visible until the user clicks on another
* label in the tab strip.
*
* @param pane the component to display as the default pane
*
* @pre findPane(pane) != -1
*/
public void setDefaultPane(Component pane)
throws IllegalArgumentException {
Assert.isUnlocked(this);
setDefaultPaneIndex(findPaneSafe(pane));
}
/**
* Show or hide a particular tab
*
* @param s the page state
* @param i the index of the tab
* @param v if true, shows the tab. Otherwise, hides the tab
*/
public void setTabVisible(PageState s, int i, boolean v) {
get(i).setVisible(s, v);
}
/**
* Show or hide a particular tab
*
* @param s the page state
* @param c the body of the tab
* @param v if true, shows the tab. Otherwise, hides the tab
*/
public void setTabVisible(PageState s, Component c, boolean v) {
int i = findPaneSafe(c);
setTabVisible(s, i, v);
}
/**
* Determine if a particular tab is visible
*
* @param s the page state
* @param i the index of the tab
*/
public boolean isTabVisible(PageState s, int i) {
return get(i).isVisible(s);
}
/**
* Determine if a particular tab is visible
*
* @param s the page state
* @param c the body of the tab
*/
public boolean isTabVisible(PageState s, Component c) {
int i = findPaneSafe(c);
return isTabVisible(s, i);
}
/**
* Find the pane whose body is the specified component
*
* @param c the component
*
* @return the pane index on success, -1 if no such pane exists
*/
protected int findPane(Component c) {
int index = 0;
for (Iterator i = children(); i.hasNext(); index++) {
Pane p = (Pane) i.next();
if (p.getComponent() == c) {
return index;
}
}
return -1;
}
private int findPaneSafe(Component c) {
int i = findPane(c);
if (i == -1) {
throw new IllegalArgumentException(
"Pane not part of this tabbed dialog");
}
return i;
}
/**
* Gets the default pane. If no default pane has been set explicitly, the
* first pane is returned.
*
* @return the default pane, or <code>null</code> if there are no panes.
*/
public Component getDefaultPane() {
return m_defaultPane.getComponent();
}
/**
* Gets the pane with the specified label.
*
* @return the pane with the specified label, or <code>null</code> if a pane
* with that label does not exist.
*/
public Component getPane(Component label) {
for (Iterator i = children(); i.hasNext();) {
Pane p = (Pane) i.next();
if (p.getLabel().equals(label)) {
return p.getComponent();
}
}
return null;
}
/**
* Gets the pane with the specified key in its label. Returns null if a pane
* with that label does not exist. This function exists for backward
* compatibility.
*
* @return the pane with the specified label, or <code>null</code> if a pane
* with that label does not exist.
*/
public Component getPane(String label) {
for (Iterator i = children(); i.hasNext();) {
Pane p = (Pane) i.next();
Component pLabel = p.getLabel();
if (pLabel instanceof Label
&& ((Label) pLabel).getLabel().equals(label)) {
return p.getComponent();
}
}
return null;
}
/**
* Gets the currently visible pane.
*
* @pre data != null
*/
public Component getCurrentPane(PageState data) {
return getCurrent(data).getComponent();
}
/**
* Get the currently visible <code>Pane</code>, the tab label together with
* its component.
*/
private Pane getCurrent(PageState data) {
Integer i = (Integer) data.getValue(m_currentPaneParam);
if (i == null) {
if (m_defaultPane != null) {
return m_defaultPane;
} else {
return (Pane) get(0);
}
}
return (Pane) get(i.intValue());
}
public void setSelectedIndex(PageState state, int index) {
if (index != getSelectedIndex(state)) {
getCurrentPane(state).setVisible(state, false);
state.setValue(m_currentPaneParam, new Integer(index));
getCurrentPane(state).setVisible(state, true);
}
}
public int getSelectedIndex(PageState state) {
Integer current = (Integer) state.getValue(m_currentPaneParam);
if (current == null) {
return -1;
}
return current.intValue();
}
/**
* Builds a DOM representing the header for the tab strip. Marks the current
* pane.
*/
protected void generateTabs(PageState data, Element parent) {
Element strip = parent.newChildElement("bebop:tabStrip", BEBOP_XML_NS);
exportAttributes(strip);
Pane current = getCurrent(data);
strip.addAttribute("selected", current.getComponent().getClass()
.getName());
Iterator tabs;
int i;
for (tabs = children(), i = 0; tabs.hasNext(); i++) {
Pane pane = (Pane) tabs.next();
// Skip hidden tabs
if (!pane.isVisible(data)) {
continue;
}
data.setControlEvent(this, SELECT_EVENT, String.valueOf(i));
Element tab = strip.newChildElement("bebop:tab", BEBOP_XML_NS);
if (pane == current) {
tab.addAttribute("current", "t");
} else {
try {
tab.addAttribute("href", data.stateAsURL());
} catch (java.io.IOException ioe) {
// stateAsURL failed => this node gets neither href nor current
//TODO cat.error("cannot get stateAsURL from "+data);
}
}
String key = ((Label) pane.getLabel()).getGlobalizedMessage()
.getKey();
tab.addAttribute("key", key.substring(key.lastIndexOf(".") + 1));
pane.getLabel().generateXML(data, tab);
}
data.clearControlEvent();
}
/**
* Services the request by building a DOM tree with the tabs themselves and
* then the included page.
* <p>
* Generates a DOM fragment:
* <p>
* <code><pre>
* &lt;bebop:tabbedPane>
* &lt;bebop:tabStrip>
* &lt;bebop:tab [href="..."] [current="t|f"]> .. label .. &lt;/bebop:tab>
* &lt;bebop:tab [href="..."] [current="t|f"]> .. label .. &lt;/bebop:tab>
* &lt;bebop:tab [href="..."] [current="t|f"]> .. label .. &lt;/bebop:tab>
* &lt;/bebop:tabStrip>
* &lt;bebop:currentPane>
* ... contentes ..
* &lt;/bebop:currentPane>
* &lt;/bebop:tabbedPane>
* </pre></code>
*/
public void generateXML(PageState state, Element parent) {
if (isVisible(state) && !isEmpty()) {
Element tabbed = parent.newChildElement("bebop:tabbedPane",
BEBOP_XML_NS);
generateTabs(state, tabbed);
exportAttributes(tabbed);
Element pane = tabbed.newChildElement("bebop:currentPane",
BEBOP_XML_NS);
exportAttributes(pane);
getCurrentPane(state).generateXML(state, pane);
}
}
/**
* Notifies the <code>TabbedPane</code> that one of the tabs has been
* selected. Changes the currently visible pane and runs all the {@link
* ActionListener ActionListeners}.
* <p>
* The <code>respond</code> method on the now-visible component is
* <em>not</em> called.
*
* @pre state != null
*/
public void respond(PageState state)
throws ServletException {
String event = state.getControlEventName();
if (SELECT_EVENT.equals(event)) {
String value = state.getControlEventValue();
setSelectedIndex(state, Integer.parseInt(value));
} else {
throw new ServletException("Received unknown control event " + event);
}
fireActionEvent(state);
}
/**
* Associates a label with the component
*/
private class Pane extends SimpleContainer {
private Component m_label;
private Component m_component;
public Pane(Component label, Component c) {
m_label = label;
super.add(label);
m_component = c;
super.add(c);
}
public final Component getLabel() {
return m_label;
}
public final Component getComponent() {
return m_component;
}
}
}

View File

@ -1,115 +0,0 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.bebop;
import com.arsdigita.bebop.event.PrintEvent;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.xml.Element;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class Text extends SimpleComponent {
private String text;
private boolean outputEscaped;
private PrintListener printListener;
public Text() {
this("");
}
public Text(final String text) {
this.text = text;
outputEscaped = true;
}
public Text(final PrintListener printListener) {
this();
this.printListener = printListener;
}
public String getText() {
return text;
}
public void setText(final String text) {
this.text = text;
}
public boolean isOutputEscaped() {
return outputEscaped;
}
public void setOutputEscaped(final boolean outputEscaped) {
this.outputEscaped = outputEscaped;
}
public void setPrintListener(final PrintListener printListener) {
if (printListener == null) {
throw new IllegalArgumentException("PrintListener can't be null");
}
this.printListener = printListener;
}
@Override
public void generateXML(final PageState state, final Element parent) {
if (!isVisible(state)) {
return;
}
final Text target = firePrintEvent(state);
final Element textElem = parent.newChildElement("bebop:text",
BEBOP_XML_NS);
target.exportAttributes(textElem);
if (outputEscaped) {
textElem.addAttribute("escape", "no");
} else {
textElem.addAttribute("escape", "yes");
}
textElem.setText(target.getText());
}
protected Text firePrintEvent(final PageState state) {
final Text component;
if (printListener == null) {
component = this;
} else {
try {
component = (Text) this.clone();
printListener.prepare(new PrintEvent(this, state, component));
} catch (CloneNotSupportedException ex) {
throw new UncheckedWrapperException(
"Could not clone Text component for PrintListener. "
+ "This propaby indicates a serious programming error.");
}
}
return component;
}
}

View File

@ -1,51 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.PageState;
/**
* A component-defined event. Components usually fire an
* <code>ActionEvent</code> to indicate that they were the ones receiving
* the click in a user's submission, for example, a form might use an
* <code>ActionEvent</code> to signal that it has been submitted.
*
* @see ActionListener
* @see java.awt.event.ActionEvent
*
* @author David Lutterkort
*
* @version $Id$
*/
public class ActionEvent extends PageEvent {
/**
* Construct an <code>ActionEvent</code>.
*
* @param source the component that originated the event
* @param state the state of the containing page under the current
* request
*/
public ActionEvent(Component source, PageState state) {
super(source, state);
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import java.util.EventListener;
/**
* The listener interface for receiving action events. The class that is
* interested in processing an action event implements this interface, and
* the object created with that class is registered with a component, using
* the component's addActionListener method. When the action event occurs,
* that object's actionPerformed method is invoked.
*
* @see ActionEvent
* @see java.awt.event.ActionListener
*
* @author David Lutterkort
*
* @version $Id$
*/
public interface ActionListener extends EventListener {
/**
* Invoked when an action has been performed.
*
* @pre e != null
*/
void actionPerformed(ActionEvent e);
}

View File

@ -1,33 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.PageState;
/**
* This class will be
* renamed to SelectionEvent.
*/
public class ChangeEvent extends PageEvent {
public ChangeEvent(Object source, PageState state) {
super(source, state);
}
}

View File

@ -1,30 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import java.util.EventListener;
/**
* This class will be
* renamed to SelectionListener.
*/
public interface ChangeListener extends EventListener {
void stateChanged(ChangeEvent e);
}

View File

@ -1,130 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Convenience extensions to {@link javax.swing.event.EventListenerList
* Swing's <code>EventListenerList</code>}.
*
*/
public class EventListenerList extends javax.swing.event.EventListenerList {
private static final long serialVersionUID = -1930203818146602205L;
/**
* Append all the event listeners from <code>l</code>.
*
* @param list The list of listeners to copy from
*
* @pre l != null
*/
public void addAll(final EventListenerList list) {
if ( list.listenerList.length == 0 ) {
return;
}
Object[] tmp = new Object[listenerList.length + list.listenerList.length];
System.arraycopy(listenerList, 0, tmp, 0, listenerList.length);
System.arraycopy(list.listenerList, 0,
tmp, listenerList.length, list.listenerList.length);
listenerList = tmp;
}
/**
* Return an iterator over all event listeners of class <code>t</code>.
* This iterator replaces the for loop mentioned in the documentation for
* {@link javax.swing.event.EventListenerList Swing's
* <code>EventListenerList</code>}.
*
* @param <T>
* @param type The class of the event listeners that should be returned
* @return
*
* @pre t != null
* */
public <T> Iterator<T> getListenerIterator(final Class<T> type) {
return new EventListenerIterator<>(type);
}
private class EventListenerIterator<T> implements Iterator<T> {
/**
* The listener we will return with the next call to next().
* listener[_next] is always a class object of type t, unless all
* matching listeners have been returned, in which case _next
* is -1
* */
private final int count;
private int next;
private final Class<T> type;
EventListenerIterator(Class<T> type) {
count = getListenerList().length;
next = -2;
this.type = type;
findNext();
}
@Override
public boolean hasNext() {
return (next < count);
}
@Override
@SuppressWarnings("unchecked")
public T next() throws NoSuchElementException {
if ( ! hasNext() ) {
throw new NoSuchElementException("Iterator exhausted");
}
int result = next;
findNext();
return (T) getListenerList()[result+1];
}
@Override
public void remove() throws UnsupportedOperationException {
throw new UnsupportedOperationException("Removal not supported");
}
/**
* Advance <code>_next</code> so that either <code>_next == -1</code>
* if all listeners of class <code>_t</code> have been returned in the
* enclosing <code>EventListenerList</code>, or that
* <code>getListenersList()[_next] == _t</code> and
* <code>getListenersList()[_next+1]</code> (the corresponding listener
* object) has not been returned yet by <code>next()</code>.
* */
private void findNext() {
for (int i = next+2; i<count; i+=2) {
if (getListenerList()[i] == type) {
next = i;
return;
}
}
next = count;
}
}
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.FormProcessException;
import java.util.EventListener;
/**
* Defines the interface for a class that performs cleanup after
* cancelling out of a form
*
* @author Kevin Scaldeferri
* @version $Id$
*/
public interface FormCancelListener extends EventListener {
/**
* Performs any necessary cleanup after a user cancels out of
* a form
*
* <p>Implementations of this method are responsible for catching
* specific exceptions that may occur during processing, and either
* handling them internally or rethrowing them as instances of
* <code>FormProcessException</code> to be handled by the calling
* procedure.
*/
void cancel(FormSectionEvent e) throws FormProcessException;
}

View File

@ -1,52 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.FormProcessException;
import java.util.EventListener;
/**
* Defines the interface for initializing a form with default values.
* Typical implementations of this interface query the database to
* set up an "edit" form, or obtain an id from a sequence to initialize
* a "create" form.
*
* @author Karl Goldstein
* @author Uday Mathur
* @version $Id$
*/
public interface FormInitListener extends EventListener {
/**
* Initializes a FormData object already populated with values from
* the request.
*
* @param date The form data containing data included with this
* request. The initializer may require knowledge of form or
* parameter properties.
*
* @param request The HTTP request associated with the
* initialization event. This supplied so that the initializer may
* rely on contextual information, such information extracted from
* headers or cookies or an associated <code>HttpSession</code>
* object.
* */
void init(FormSectionEvent e) throws FormProcessException;
}

View File

@ -1,69 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.FormProcessException;
import java.util.EventListener;
/**
* Defines the interface for a class that performs a processing step
* on valid data.
*
* @author Karl Goldstein
* @author Uday Mathur
* @version $Id$
*/
public interface FormProcessListener extends EventListener {
/**
* Performs a processing step on the data in the
* <code>FormData</code> object.
*
* <p>Implementations of this method are responsible for catching
* specific exceptions that may occur during processing, and either
* handling them internally or rethrowing them as instances of
* <code>FormProcessException</code> to be handled by the calling
* procedure.
*
* <p>Implementations of this method cannot assume success or
* failure of other FormProcessListeners associated with a
* particular FormModeel. Each implementation must act independently
*
* @param model The form model describing the structure and properties
* of the form data included with this request.
*
* @param data The container for all data objects associated with
* the request. String values for all parameters specified in the
* form model are converted to Java data objects and validated
* before processing occurs.
*
* @param request The HTTP request information from which the form
* data was extracted. Note that the request object is supplied
* only in case the processing step requires contextual information
* (information extracted from cookies or the peer address, for
* example) or needs to modify session properties.
*
* @param response The HTTP response that will be returned to the
* user. The processing step may require access to this object to
* set cookies or handle errors. */
void process(FormSectionEvent e) throws FormProcessException;
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.FormData;
import com.arsdigita.bebop.PageState;
/**
* An event originating from a form. <code>FormSectionEvent</code>s are
* used to notify listeners that values in a form should be initilialized,
* validated or processed.
*
* @author David Lutterkort
*
* @version $Id$
*
* @see FormInitListener
* @see FormValidationListener
* @see FormProcessListener
*/
public class FormSectionEvent extends PageEvent {
private final FormData _formData;
/**
* Get the form data for to the form that fired the event in the current
* request.
*
* @return form data
*/
public final FormData getFormData() {
return _formData;
}
/**
* Construct a <code>FormSectionEvent</code>.
*
* @param source the form model that fired the event
* @param state the state of the enclosing page
* @param formData the form data constructed so far
*/
public FormSectionEvent(Object source,
PageState state,
FormData formData) {
super(source, state);
_formData = formData;
}
}

View File

@ -1,49 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import java.util.EventListener;
import com.arsdigita.bebop.FormProcessException;
/**
* The listener called just before a form starts examining a
* submission. This listener can throw a {@link FormProcessException} to
* indicate that any further processing of the submission should be
* aborted. This usually leaves the corresponding {@link
* com.arsdigita.bebop.FormData FormData} object in an undefined
* state.
*
* @author David Lutterkort
* @version $Id$
*/
public interface FormSubmissionListener extends EventListener {
/**
* This method gets called as soon as the <code>FormData</code> for a
* form has been filled with the request parameters. The values in the
* <code>FormData</code> are transformed but not validated.
*
* @param e the event encapsulating form data, page state and event source
* @throws FormProcessException to signal that further processing of the
* form should be aborted.
*/
void submitted(FormSectionEvent e) throws FormProcessException;
}

View File

@ -1,62 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.FormProcessException;
import java.util.EventListener;
/**
* Defines the interface for a class that implements a validation check
* on a set of form data.
*
* @author Karl Goldstein
* @author Uday Mathur
* @version $Id$
*/
public interface FormValidationListener extends EventListener {
/**
* Performs a validation check on the specified <tt>FormData</tt>
* object, involving any number of parameters.
*
* <p>The check is always performed after all HTTP request
* parameters have been converted to data objects and stored in the
* FormData object.
*
* <p>If a validation error is encountered, the <tt>setError</tt>
* method of the <tt>FormData</tt> object may be used to set an
* error message for reporting back to the user.
*
* <p>This method is responsible for catching any exceptions that
* may occur during the validation. These exceptions may either
* be handled internally, or if they are unrecoverable may be
* rethrown as instances of <code>FormProcessException</code>.
*
* @param e FormSectionEvent containing the FormData as well as the
* PageState.
* Clients may access the PageState by executing something like
* PageState state = fse.getPageState();
* Method getFormData() allows access to the Form's data.
*
* @exception FormProcessException ff the data does not pass the check.
*/
void validate(FormSectionEvent e) throws FormProcessException;
}

View File

@ -1,57 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.PageState;
import java.util.EventObject;
/**
* The base class for all page related events. All page related events
* should be derived from this class, since it defines a standard way to
* get at the source of the event and at the state of the page under the
* request that is currently being processed.
*
* @author David Lutterkort
*
* @version $Id$
*/
public class PageEvent extends EventObject {
private PageState _state;
/**
* Construct a new <code>PageEvent</code>.
* @param source the object firing the event, usually a {@link
* com.arsdigita.bebop.Component <code>Component</code>}.
* @param state the state of the page under the current request
*/
public PageEvent(Object source, PageState state) {
super(source);
_state = state;
}
/**
* Get the state of the page under the request in which the event was fired
*/
public final PageState getPageState() {
return _state;
}
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.ParameterData;
import java.util.EventObject;
/**
* An event connected to a request parameter.
*
* @author David Lutterkort
*
* @version $Id$
*
* @see ParameterListener
* @see com.arsdigita.bebop.parameters.ParameterModel
* @see com.arsdigita.bebop.parameters.ParameterData
*/
public class ParameterEvent extends EventObject {
/* The request specific data about the event */
private ParameterData m_data;
private PageState m_state;
/**
* Construct a <code>ParameterEvent</code>
*
* @param source the object that originated the event
* @param data the data for the parameter from the current request
**/
public ParameterEvent(Object source, ParameterData data) {
super(source);
m_data = data;
m_state = PageState.getPageState();
}
/**
* Get the request specific data about the parameter.
**/
public final ParameterData getParameterData() {
return m_data;
}
/**
*
**/
public PageState getPageState() {
return m_state;
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.FormProcessException;
import java.util.EventListener;
/**
* Defines the interface for a class that validates the values of a
* single parameter.
*
* @author Karl Goldstein
* @author Uday Mathur
* @version $Id$ */
public interface ParameterListener extends EventListener {
/**
* Performs a validation check on the data objects associated with a
* specific parameter. Validate should call
* ParameterData.addError() with a message regarding the nature
* of the error.
* @param e
* @throws com.arsdigita.bebop.FormProcessException
*/
void validate(ParameterEvent e) throws FormProcessException;
}

View File

@ -1,63 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.PageState;
/**
* An event originating from a component. <code>PrintEvent</code>s are
* fired just before the <code>source</code> component is output either as
* part of an XML document or as part of an HTML page.
*
* @see PrintListener
*
* @author Uday Mathur
* @author David Lutterkort
*
* @version $Id$
*
*/
public class PrintEvent extends PageEvent {
private Object m_target;
/**
* Construct a <code>PrintEvent</code>
*
* @param source the object that originated the event
* @param data the data for the parameter from the current request
* @pre source != null
* @pre target != null
*/
public PrintEvent(Object source, PageState state, Object target) {
super(source, state);
m_target = target;
}
/**
* Get the target object, the one that can be freely modified by print
* listeners. Initially, the target is an unlocked clone of the source of
* the event.
* @post return != null
*/
public final Object getTarget() {
return m_target;
}
}

View File

@ -1,79 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import java.util.EventListener;
/**
* Listeners of this class are called just before a {@link com.arsdigita.bebop.Component} is
* about to be output, either in the form of an XML element, or by printing
* its HTML representation. The {@link #prepare prepare method} of the
* listener can make modifications to the {@link PrintEvent#getTarget
* target} of the event. The target will then be used to produce output
* instead of the source.
* <p>
* {@link PrintEvent PrintEvents} are <i>unicast</i> events, which means
* that components should only permit the registration of one
* <code>PrintListener</code>. Since the <code>PrintListener</code> is
* expected to modify the target, allowing multiple listeners to modify the
* target of one event would make it impossible to predict the resulting
* target component, since an individual listener can not know which
* listeners have run before it and which ones will run after it.
* <p>
* As an example consider the following code:
* <pre>
* Label l = new Label("Default text");
* l.addPrintListener( new PrintListener {
* private static final BigDecimal ONE = new BigDecimal(1);
* private BigDecimal count = new BigDecimal(0);
* public void prepare(PrintEvent e) {
* Label t = e.getTarget();
* synchronized (count) {
* count.add(ONE);
* }
* t.setLabel("Call no." + count + " since last server restart");
* }
* });</pre>
* Adding the label <code>l</code> to a page will lead to a label that
* changes in every request and print how many times the containing label
* has been called.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author David Lutterkort
* @version $Id$
*/
public interface PrintListener extends EventListener {
/**
* Prepare the target component returned by {@link PrintEvent#getTarget
* e.getTarget()} for output. The target component is an unlocked clone
* of the source of the event and can be freely modified within this
* method.
*
* @param e Event containing the page state, the source and the target of
* the event
*
* @see PrintEvent
*/
void prepare(PrintEvent e);
}

View File

@ -1,49 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.PageState;
/**
* An event indicating that a Bebop page is being loaded, and control
* is about to be passed to the currently selected component
*
* @author David Lutterkort
*
* @version $Id$
*
* @see ActionListener
* @see java.awt.event.ActionEvent
*/
public class RequestEvent extends PageEvent {
/**
* Construct an <code>ActionEvent</code>.
*
* @param source the component that originated the event
* @param state the state of the containing page under the current
* request
*/
public RequestEvent(Component source, PageState state) {
super(source, state);
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import java.util.EventListener;
/**
* The listener interface for receiving request events. The class that is
* interested in processing a request event implements this interface, and
* the object created with that class is registered with a Bebop page, using
* the Page.addRequestListener method. When the page has finished processing
* the page state, and is about to pass control to the currently selected
* component, the pageRequested method will be called.
*
* @author David Lutterkort
*
* @version $Id$
*
* @see ActionEvent
* @see java.awt.event.ActionListener
*/
public interface RequestListener extends EventListener {
/**
* Invoked when an action has been performed.
*
* @pre e != null
*/
void pageRequested(RequestEvent e);
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import java.util.EventListener;
/**
* Analogous to Widget
* PrintListeners, this is called when the widget is displayed (or
* validated) to get the dataset. The dataset should be created
* dynamically so it can vary according to form variables.
* Eventually, this may also support setting the initial value for a
* SearchAndSelect widget, so that it may act as an edit widget as
* well.
*
* @author Patrick McNeill
* @version $Id$
* @since 4.5 */
public interface SearchAndSelectListener extends EventListener {
SearchAndSelectModel getModel( PageEvent e );
}

View File

@ -1,71 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
/**
* Listener interface for
* the SeachAndSelect Bebop widget. SearchAndSelect requires
* knowledge about the data it is searching over (to determine the
* display method and to actually execute the query).
*
* @author Patrick McNeill
* @version $Id$
* @since 4.5 */
public interface SearchAndSelectModel {
/**
* Specify the user's search and restrict the result set to those queries
* that match. An empty string should return all results.
*
* @param query the user's search string, space or comma delimited words
*/
void setQuery ( String query );
/**
* Retrieve the query that was last used.
*
* @return the query string
*/
String getQuery ();
/**
* Return the number of items that are currently selected by the query
* string. If the query string is empty, this should return the number
* of items in the dataset.
*
* @return the number of currently selected items
*/
int resultsCount ();
/**
* Get the "i"th label (0 based indexing)
*
* @param i the label number to retrieve
* @return the ith label
*/
String getLabel (int i);
/**
* Get the "i"th ID (0 based indexing)
*
* @param i the ID number to retrieve
* @return the ith ID
*/
String getID (int i);
}

View File

@ -1,52 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.FormProcessException;
/**
* An implentation of the TableActionListener interface meant to save the
* developer from having to override both the {@link
* #cellSelected(TableActionEvent)} and {@link #headSelected(TableActionEvent)}
* methods when they only need to change the behavior of one.
*
* @see TableActionEvent
* @author David Lutterkort
* @version $Id$
*/
public class TableActionAdapter implements TableActionListener {
/**
* A no-op implementation of {@link
* TableActionListener#cellSelected(TableActionEvent)}.
*
* @param e the event fired for the table.
*/
public void cellSelected(TableActionEvent e) throws FormProcessException {}
/**
* A no-op implementation of {@link
* TableActionListener#headSelected(TableActionEvent)}.
*
* @param e the event fired for the table.
*/
public void headSelected(TableActionEvent e) {
return;
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.PageState;
/**
* An event for the {@link com.arsdigita.bebop.Table} component.
* Table will fire this event when one of its active cells receives a
* click.
*
* @see TableActionListener
* @see TableActionAdapter
* @author David Lutterkort
* @version $Id$
*/
public class TableActionEvent extends ActionEvent {
private Object m_rowKey;
private Integer m_column;
/**
* Construct a TableActionEvent for a click on a particular row
* and a particular column.
*
* @param source the Component generating the event.
* @param s the state for the current request.
* @param rowKey the key for the row where the click was registered.
* @param column the index of the column where the click was registered.
*/
public TableActionEvent(Component source, PageState s,
Object rowKey, Integer column) {
super(source, s);
m_rowKey = rowKey;
m_column = column;
}
/**
* Construct a TableActionEvent for a click on a particular row.
*
* @param source the Component generating the event.
* @param s the state for the current request.
* @param rowKey the key for the row where the click was registered.
*/
public TableActionEvent(Component source, PageState s, Object rowKey) {
this(source, s, rowKey, new Integer(-1));
}
/**
* Get the key for the row that received the click.
*
* @return the key for the row that received the click.
*/
public final Object getRowKey() {
return m_rowKey;
}
/**
* Get the index of the column that received the click.
*
* @return the index of the column that received the click.
*/
public final Integer getColumn() {
return m_column;
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.FormProcessException;
import java.util.EventListener;
/**
* Specifies the interface for handling events on {@link
* com.arsdigita.bebop.Table}. Programmers wishing to override just
* one of these methods, not both, may prefer to use {@link
* TableActionAdapter}.
*
* @see TableActionEvent
* @see TableActionAdapter
* @author David Lutterkort
* @version $Id$
*/
public interface TableActionListener extends EventListener {
/**
* An event handler for actions on a particular cell or a set of
* cells.
*
* @param e the event fired for the table.
*/
void cellSelected(TableActionEvent e) throws FormProcessException;
/**
* An event handler for actions on a particular column heading or
* set of column headings.
*
* @param e the event fired for the table.
*/
void headSelected(TableActionEvent e);
}

View File

@ -1,50 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.PageState;
/**
* An event for the {@link com.arsdigita.bebop.Tree} component.
* Tree will fire this event when one of its nodes is expanded or
* collapsed.
*
* @author David Lutterkort
* @version $Id$
*/
public class TreeExpansionEvent extends ActionEvent {
private Object m_nodeKey;
public TreeExpansionEvent(Component source, PageState s, Object nodeKey) {
super(source, s);
m_nodeKey = nodeKey;
}
/**
* Get the key for the node that was expanded or collapsed.
*
* @return the key for the node that was expanded or collapsed.
*/
public final Object getNodeKey() {
return m_nodeKey;
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.event;
import java.util.EventListener;
/**
* The listener that is notified when a tree node is expanded or
* collapsed.
*
* @author David Lutterkort
* @version $Id$
*/
public interface TreeExpansionListener extends EventListener {
/**
* Called whenever an item in the tree has been collapsed.
*/
void treeCollapsed(TreeExpansionEvent event);
/**
* Called whenever an item in the tree has been expanded.
*/
void treeExpanded(TreeExpansionEvent event);
}

View File

@ -1,68 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.parameters.ArrayParameter;
// This interface contains the XML element name of this class
// in a constant which is used when generating XML
import com.arsdigita.bebop.util.BebopConstants;
/**
* A class representing a <em>group</em> of associated checkboxes.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Rory Solomon
* @author Michael Pih
* @version $Id$
*/
public class CheckboxGroup extends OptionGroup implements BebopConstants {
public CheckboxGroup(String name) {
this(new ArrayParameter(name));
}
public CheckboxGroup(ArrayParameter param) {
super(param);
//m_xmlElement = BEBOP_CHECKBOX;
}
/**
* Returns a string naming the type of this widget.
*/
public String getType() {
return "checkbox";
}
/** The XML tag.
* @return The tag to be used for the top level DOM element
* generated for this type of Widget. */
@Override
protected String getElementTag() {
return BEBOP_CHECKBOXGROUP;
}
@Override
public String getOptionXMLElement() {
return BEBOP_CHECKBOX;
}
}

View File

@ -1,348 +0,0 @@
/*
* Copyright (C) 2001-2006 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.arsdigita.bebop.BebopConfig;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.web.Web;
import com.arsdigita.xml.Element;
/**
* Displays and manages a WYSIWYG HTML editor that takes advantage of DHTML
* scripting features. This class can use:
* <ul>
* <li>CCM Editor, a new editor using HTML5 features.</li>
* <li><a href="http://www.xinha.org">Xinha</a></li>
* <li><a href="http://www.fckeditor.net">FCKeditor</a></li>
* <li>HTMLarea for backwards compatibility, development discontinued</li>
* </ul>
* Editor is chosen based on the configuration parameter
* {@code waf.bebop.dhtml_editor} default is {@code ccm-editor}.
*
* @author Jim Parsons
* @author Richard Li
* @author Chris Burnett
* @author Alan Pevec
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*
*/
public class DHTMLEditor extends TextArea {
/**
* Constant for specifying <tt>OFF</tt> value for the <tt>WRAP</tt>
* attribute of this image input.
*
* See <a href="http:
* //developer.netscape.com/docs/manuals/htmlguid/tags10.htm#1340340">here</a>
* for a description of what this attribute does.
*/
public static final int OFF = 0;
/**
* Constant for specifying <tt>HARD</tt> value for the <tt>WRAP</tt>
* attribute of this image input.
*
* See <a href="http://
* developer.netscape.com/docs/manuals/htmlguid/tags10.htm#1340340">here</a>
* for a description of what this attribute does.
*/
public static final int HARD = 1;
/**
* Constant for specifying <tt>SOFT</tt> value for the <tt>WRAP</tt>
* attribute of this image input. See <a href="http://
* developer.netscape.com/docs/manuals/htmlguid/tags10.htm#1340340">here</a>
* for a description of what this attribute does.
*/
public static final int SOFT = 2;
/**
* Configuration objects for supported DHTML editors
*/
public static class Config {
// WARNING: Processing of these default values by CMSConfig does NOT
// work correctly because of deviciencies in unmarshal method there.
public static final Config XINHA_STANDARD = new Config("Xinha.Config",
"/assets/xinha/CCMcoreXinhaConfig.js");
/**
* Example FCKEditor configuration.
*/
public static final Config FCK_STANDARD = new Config(
"FCKEditor.Config.StyleDefault",
"/assets/fckeditor/config/fckconfigstyledefault.js");
public static final Config FCK_CMSADMIN = new Config(
"FCKEditor.Config.StyleCMSAdmin",
"/assets/fckeditor/config/fckconfigstylecmsadmin.js");
/**
* Example old HTMLarea configuration.
*/
public static final Config HTMLAREA
= new Config("HTMLArea.Config", null);
/**
* Example of configuration for ccm-editor
*/
public static final Config CCM_EDITOR = new Config("ccm-editor.loader",
"/ccm-editor/ccm-editor-loader.js");
public static final Config STANDARD = new Config("tinymce.config",
"/tinymce/tinymce-config.js");
private String m_name;
private String m_path;
public Config(String name) {
this(name, null);
}
public Config(String name,
String path) {
m_name = name;
m_path = path;
}
public String getName() {
return m_name;
}
public String getPath() {
return m_path;
}
public static Config valueOf(String cfg) {
int offset = cfg.indexOf(",");
if (offset != -1) {
return new Config(cfg.substring(0, offset),
cfg.substring(offset + 1));
} else {
return new Config(cfg);
}
}
public String toString() {
if (m_path == null) {
return m_name;
} else {
return m_name + "," + m_path;
}
}
} //end config object(s)
private Config m_config;
private Set m_plugins;
private Set m_hiddenButtons;
/**
* Constructor
*
* @param name
*/
public DHTMLEditor(String name) {
this(new StringParameter(name));
}
/**
* Constructor
*
* @param model
*/
public DHTMLEditor(ParameterModel model) {
this(model, Config.STANDARD);
}
/**
* Constructor
*
* @param model
* @param config
*/
public DHTMLEditor(ParameterModel model,
Config config) {
super(model);
m_config = config;
m_plugins = new HashSet();
m_hiddenButtons = new HashSet();
}
/**
* Returns a string naming the type of this widget.
*/
public String getType() {
return "DHTMLEditor";
}
public String getEditorURL() {
return BebopConfig.getConfig().getDhtmlEditorSrcFile().substring(
0,
BebopConfig.getConfig().getDhtmlEditorSrcFile().lastIndexOf("/") + 1);
}
public String getEditorSrc() {
return BebopConfig.getConfig().getDhtmlEditorSrcFile();
}
/**
* deprecated - use {@link setConfig(Config)}
*
* @param config
*/
public void setConfig(String config) {
setAttribute("config", config);
}
public void setConfig(Config config) {
m_config = config;
}
public void addPlugin(String name) {
m_plugins.add(name);
}
/**
* Prevent the specified button from being displayed in the editor toolbar.
*
* @param name name of the button, as specified in the btnList of the
* htmlarea.js file
*
*/
public void hideButton(String name) {
m_hiddenButtons.add(name);
}
/**
* Sets the <tt>ROWS</tt> attribute for the <tt>TEXTAREA</tt> tag.
*/
@Override
public void setRows(int rows) {
setAttribute("rows", String.valueOf(rows));
}
/**
* Sets the <tt>COLS</tt> attribute for the <tt>TEXTAREA</tt> tag.
*/
@Override
public void setCols(int cols) {
setAttribute("cols", String.valueOf(cols));
}
/**
* Sets the <tt>COLS</tt> attribute for the <tt>TEXTAREA</tt> tag.
*/
@Override
public void setWrap(int wrap) {
String wrapString = null;
switch (wrap) {
case OFF:
wrapString = "off";
break;
case HARD:
wrapString = "hard";
break;
case SOFT:
wrapString = "soft";
break;
}
if (wrapString != null) {
setAttribute("wrap", wrapString);
}
}
/**
* The XML tag.
*
* @return The tag to be used for the top level DOM element generated for
* this type of Widget.
*/
@Override
protected String getElementTag() {
return BebopConfig.getConfig().getDefaultDhtmlEditor();
}
/**
* Generates the DOM for the DHTML editor widget
* <p>
* Generates DOM fragment:
* <p>
* <code>&lt;bebop:dhtmleditor name=... value=... [onXXX=...]/>
* </code>
*/
@Override
public void generateWidget(PageState state, Element parent) {
String value = getParameterData(state).marshal();
Element editor = parent.newChildElement(getElementTag(), BEBOP_XML_NS);
editor.addAttribute("name", getName());
generateDescriptionXML(state, editor);
// Set the needed config params so they don't have to be hardcoded in
//the theme
editor.addAttribute("editor_url",
Web.getWebappContextPath().concat(getEditorURL()));
editor.addAttribute("editor_src",
Web.getWebappContextPath().concat(getEditorSrc()));
if (value != null) {
editor.setText(value);
}
exportAttributes(editor);
Element config = editor.newChildElement("bebop:config", BEBOP_XML_NS);
config.addAttribute("name", m_config.getName());
if (m_config.getPath() != null) {
config.addAttribute(
"path", String.format("%s/%s",
Web.getWebappContextPath(),
m_config.getPath()));
}
if (m_hiddenButtons.size() > 0) {
StringBuffer hiddenButtons = new StringBuffer();
// list must start and end with a space
hiddenButtons.append(" ");
Iterator hidden = m_hiddenButtons.iterator();
while (hidden.hasNext()) {
hiddenButtons.append(hidden.next());
hiddenButtons.append(" ");
}
config.addAttribute("hidden-buttons", hiddenButtons.toString());
}
Iterator plugins = m_plugins.iterator();
while (plugins.hasNext()) {
String name = (String) plugins.next();
Element plugin = editor
.newChildElement("bebop:plugin", BEBOP_XML_NS);
plugin.addAttribute("name", name);
}
}
}

View File

@ -1,502 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.GregorianCalendar;
import com.arsdigita.util.Assert;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.bebop.parameters.DateParameter;
import com.arsdigita.bebop.parameters.ParameterData;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.FormData;
import com.arsdigita.bebop.parameters.DateTimeParameter;
import com.arsdigita.bebop.parameters.IncompleteDateParameter;
import com.arsdigita.bebop.parameters.NotNullValidationListener;
// This interface contains the XML element name of this class
// in a constant which is used when generating XML
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.bebop.util.GlobalizationUtil;
import com.arsdigita.xml.Element;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.l10n.GlobalizationHelper;
import java.text.SimpleDateFormat;
import java.util.Locale;
/**
* A class representing a date field in an HTML form.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Michael Pih
* @author Sören Bernstein <quasi@quasiweb.de>
* @version $Id$
*/
public class Date extends Widget implements BebopConstants {
protected OptionGroup m_year;
protected OptionGroup m_month;
protected TextField m_day;
private int m_year_begin;
private int m_year_end;
private Locale m_locale;
private boolean yearAsc = true;
/**
* Inner class for the year fragment
*/
protected class YearFragment extends SingleSelect {
protected Date parent;
private boolean autoCurrentYear; //Decide wether to set the current year if year is null
/**
* Constructor.
*
* @param name
* @param parent
*/
public YearFragment(String name, Date parent) {
super(name);
this.parent = parent;
setHint(GlobalizationUtil.globalize("bebop.date.year.hint"));
}
/**
*
* @param ps
*
* @return
*/
@Override
protected ParameterData getParameterData(PageState ps) {
Object value = getValue(ps);
if (value == null) {
return null;
}
return new ParameterData(getParameterModel(), value);
}
/**
*
* @param autoCurrentYear
*/
public void setAutoCurrentYear(final boolean autoCurrentYear) {
this.autoCurrentYear = autoCurrentYear;
}
/**
*
* @param ps
*
* @return
*/
@Override
public Object getValue(PageState ps) {
ParameterModel model = parent.getParameterModel();
if (model instanceof IncompleteDateParameter) {
if (((IncompleteDateParameter) model).isYearSkipped()) {
return null;
}
}
Object value = parent.getFragmentValue(ps, Calendar.YEAR);
if ((value == null) && autoCurrentYear) {
Calendar currentTime = GregorianCalendar.getInstance();
int currentYear = currentTime.get(Calendar.YEAR);
value = new Integer(currentYear);
}
return value;
}
}
/**
*
*/
protected class MonthFragment extends SingleSelect {
protected Date parent;
public MonthFragment(String name, Date parent) {
super(name);
this.parent = parent;
}
@Override
protected ParameterData getParameterData(PageState ps) {
Object value = getValue(ps);
if (value == null) {
return null;
}
return new ParameterData(getParameterModel(), value);
}
@Override
public Object getValue(PageState ps) {
ParameterModel model = parent.getParameterModel();
if (model instanceof IncompleteDateParameter) {
if (((IncompleteDateParameter) model).isMonthSkipped()) {
return null;
}
}
return parent.getFragmentValue(ps, Calendar.MONTH);
}
}
/**
*
*/
protected class DayFragment extends TextField {
protected Date parent;
public DayFragment(String name, Date parent) {
super(name);
this.parent = parent;
}
@Override
protected ParameterData getParameterData(PageState ps) {
Object value = getValue(ps);
if (value == null) {
return null;
}
return new ParameterData(getParameterModel(), value);
}
@Override
public Object getValue(PageState ps) {
ParameterModel model = parent.getParameterModel();
if (model instanceof IncompleteDateParameter) {
if (((IncompleteDateParameter) model).isDaySkipped()) {
return null;
}
}
return parent.getFragmentValue(ps, Calendar.DATE);
}
}
/**
* Construct a new Date. The model must be a DateParameter
*/
public Date(ParameterModel model) {
super(model);
if (!(model instanceof DateParameter
|| model instanceof DateTimeParameter)) {
throw new IllegalArgumentException(
"The Date widget " + model.getName()
+ " must be backed by a DateParameter parmeter model");
}
String name = model.getName();
String nameYear = name + ".year";
String nameMonth = name + ".month";
String nameDay = name + ".day";
Calendar currentTime = GregorianCalendar.getInstance();
m_year = new YearFragment(nameYear, this);
m_month = new MonthFragment(nameMonth, this);
m_day = new DayFragment(nameDay, this);
m_day.setMaxLength(2);
m_day.setSize(2);
populateMonthOptions();
int currentYear = currentTime.get(Calendar.YEAR);
setYearRange(currentYear - 1, currentYear + 3);
}
/**
* Constructor.
*
* @param name
*/
public Date(String name) {
this(new DateParameter(name));
}
public void setAutoCurrentYear(final boolean autoCurrentYear) {
((YearFragment) m_year).setAutoCurrentYear(autoCurrentYear);
}
public void setYearRange(int yearBegin, int yearEnd) {
Assert.isUnlocked(this);
if (yearBegin != m_year_begin || yearEnd != m_year_end) {
m_year_begin = yearBegin;
m_year_end = yearEnd;
m_year.clearOptions();
if (this.getParameterModel() instanceof IncompleteDateParameter) {
// Create an empty year entry to unset a date, if either
// a) skipYearAllowed is true
// b) skipDayAllowed is true and skipMonthAllowed is true, to unset a date
if (((IncompleteDateParameter) this.getParameterModel())
.isSkipYearAllowed()
|| (((IncompleteDateParameter) this.getParameterModel())
.isSkipDayAllowed()
&& ((IncompleteDateParameter) this
.getParameterModel())
.isSkipMonthAllowed())) {
m_year.addOption(new Option("", ""));
}
}
if (yearAsc) {
for (int year = m_year_begin; year <= m_year_end; year++) {
m_year.addOption(new Option(String.valueOf(year)));
}
} else {
for (int year = m_year_end; year >= m_year_begin; year--) {
m_year.addOption(new Option(String.valueOf(year)));
}
}
}
}
public boolean getYearAsc() {
return yearAsc;
}
public void setYearAsc(final boolean yearAsc) {
this.yearAsc = yearAsc;
}
public void addYear(java.util.Date date) {
Calendar cal = new GregorianCalendar();
cal.setTime(date);
int year = (cal.get(Calendar.YEAR));
if (year < m_year_begin) {
m_year.prependOption(new Option(String.valueOf(year)));
}
if (year > m_year_end) {
m_year.addOption(new Option(String.valueOf(year)));
}
}
/**
* Returns a string naming the type of this widget.
*
* @return
*/
@Override
public String getType() {
return "date";
}
/**
* Sets the <tt>MAXLENGTH</tt> attribute for the <tt>INPUT</tt> tag used to
* render this form element.
*
* @param length
*/
public void setMaxLength(int length) {
setAttribute("MAXLENGTH", String.valueOf(length));
}
@Override
public boolean isCompound() {
return true;
}
/**
* The XML tag for this derived class of Widget.
*
* @return
*/
@Override
protected String getElementTag() {
return BEBOP_DATE;
}
/**
*
* @param ps
* @param parent
*/
@Override
public void generateWidget(PageState ps, Element parent) {
if (!isVisible(ps)) {
return;
}
Element date = parent.newChildElement(getElementTag(), BEBOP_XML_NS);
date.addAttribute("name", getParameterModel().getName());
if (getLabel() != null) {
date.addAttribute("label", (String) getLabel().localize(ps
.getRequest()));
}
exportAttributes(date);
generateDescriptionXML(ps, date);
generateLocalizedWidget(ps, date);
// If Element could be null insert an extra widget to clear entry
if (!hasValidationListener(new NotNullValidationListener())) {
date.newChildElement("NoDate");
}
}
// Resepct the localized
public void generateLocalizedWidget(PageState ps, Element date) {
Locale defaultLocale = Locale.getDefault();
Locale locale = CdiUtil.createCdiUtil().findBean(
GlobalizationHelper.class).getNegotiatedLocale();
// Get the current Pattern
// XXX This is really, really, really, really, really, really bad
// but there is no way to get a SimpleDateFormat object for a
// different locale the the system default (the one you get with
// Locale.getDefault();). Also there is now way getting the pattern
// in another way (up until JDK 1.1 there was), so I have to temporarly
// switch the default locale to my desired locale, get a SimpleDateFormat
// and switch back.
Locale.setDefault(locale);
String format = new SimpleDateFormat().toPattern();
Locale.setDefault(defaultLocale);
// Repopulate the options for the month select box to get them localized
populateMonthOptions();
char[] chars = format.toCharArray();
for (int i = 0; i < chars.length; i++) {
// Test for doublettes
if (i >= 1 && chars[i - 1] == chars[i]) {
continue;
}
switch (chars[i]) {
case 'd':
m_day.generateXML(ps, date);
break;
case 'M':
m_month.generateXML(ps, date);
break;
case 'y':
m_year.generateXML(ps, date);
break;
default:
break;
}
}
}
@Override
public void setDisabled() {
m_month.setDisabled();
m_day.setDisabled();
m_year.setDisabled();
}
@Override
public void setReadOnly() {
m_month.setReadOnly();
m_day.setReadOnly();
m_year.setReadOnly();
}
/**
* Sets the Form Object for this Widget. This method will throw an exception
* if the _form pointer is already set. To explicity change the _form
* pointer the developer must first call setForm(null)
*
* @param f the <code>Form</code> Object for this Widget.
*
* @exception IllegalStateException if form already set.
*/
@Override
public void setForm(Form f) {
super.setForm(f);
m_year.setForm(f);
m_month.setForm(f);
m_day.setForm(f);
}
public Object getFragmentValue(PageState ps, int field) {
Assert.exists(ps, "PageState");
FormData f = getForm().getFormData(ps);
if (f != null) {
java.util.Date value = (java.util.Date) f.get(getName());
if (value != null) {
Calendar c = Calendar.getInstance();
c.setTime(value);
return new Integer(c.get(field));
}
}
return null;
}
@Override
public void setClassAttr(String at) {
m_month.setClassAttr(at);
m_year.setClassAttr(at);
m_day.setClassAttr(at);
super.setClassAttr(at);
}
private void populateMonthOptions() {
Locale locale = CdiUtil.createCdiUtil().findBean(
GlobalizationHelper.class).getNegotiatedLocale();
if (m_locale == null || (locale != null && !m_locale.equals(locale))) {
DateFormatSymbols dfs = new DateFormatSymbols(locale);
String[] months = dfs.getMonths();
m_month.clearOptions();
if (this.getParameterModel() instanceof IncompleteDateParameter) {
if (((IncompleteDateParameter) this.getParameterModel())
.isSkipMonthAllowed()) {
m_month.addOption(new Option("", ""));
}
}
for (int i = 0; i < months.length; i += 1) {
// This check is necessary because
// java.text.DateFormatSymbols.getMonths() returns an array
// of 13 Strings: 12 month names and an empty string.
if (months[i].length() > 0) {
m_month.addOption(new Option(String.valueOf(i), months[i]));
}
}
m_locale = CdiUtil.createCdiUtil().findBean(
GlobalizationHelper.class).getNegotiatedLocale();
}
}
}

View File

@ -1,150 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.DateTimeParameter;
import com.arsdigita.bebop.parameters.NotNullValidationListener;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.xml.Element;
/**
* A class representing a date and time field in an HTML form.
* (based on the code in Date.java)
*
* @author Sören Bernstein <quasi@quasiweb.de>
* @version $Id$
*/
public class DateTime extends Widget implements BebopConstants {
private Date m_date;
private Time m_time;
/**
* Construct a new DateTime. The model must be a DateTimeParameter
* @param model
*/
public DateTime(ParameterModel model) {
this(model, false);
}
/**
* Construct a new DateTime. The model must be a DateTimeParameter
* @param model
* @param showSeconds
*/
public DateTime(ParameterModel model, boolean showSeconds) {
super(model);
if (!(model instanceof DateTimeParameter)) {
throw new IllegalArgumentException(
"The DateTime widget " + model.getName() +
" must be backed by a DateTimeParameter parmeter model");
}
m_date = new Date(model);
m_time = new Time(model, showSeconds);
}
public DateTime(String name) {
this(new DateTimeParameter(name));
}
public void setYearRange(int startYear, int endYear) {
m_date.setYearRange(startYear, endYear);
}
/**
* Returns a string naming the type of this widget.
* @return
*/
@Override
public String getType() {
return "dateTime";
}
/**
* Sets the <tt>MAXLENGTH</tt> attribute for the <tt>INPUT</tt> tag
* used to render this form element.
*/
public void setMaxLength(int length) {
setAttribute("MAXLENGTH", String.valueOf(length));
}
public boolean isCompound() {
return true;
}
/** The XML tag for this derived class of Widget.
*/
@Override
protected String getElementTag() {
return BEBOP_DATETIME;
}
@Override
public void generateWidget(PageState ps, Element parent) {
if (!isVisible(ps)) {
return;
}
Element datetime = parent.newChildElement(getElementTag(), BEBOP_XML_NS);
datetime.addAttribute("name", getParameterModel().getName());
m_date.generateLocalizedWidget(ps, datetime);
m_time.generateLocalizedWidget(ps, datetime);
generateDescriptionXML(ps, datetime);
// If Element could be null insert a extra widget to clear entry
if (!hasValidationListener(new NotNullValidationListener())) {
datetime.newChildElement("NoDateTime");
}
}
@Override
public void setDisabled() {
m_date.setDisabled();
m_time.setDisabled();
}
@Override
public void setReadOnly() {
m_date.setReadOnly();
m_time.setReadOnly();
}
/**
* Sets the Form Object for this Widget. This method will throw an
* exception if the _form pointer is already set. To explicity
* change the _form pointer the developer must first call
* setForm(null)
*
* @param the <code>Form</code> Object for this Widget.
* @exception IllegalStateException if form already set.
*/
@Override
public void setForm(Form f) {
super.setForm(f);
m_date.setForm(f);
m_time.setForm(f);
}
}

View File

@ -1,174 +0,0 @@
/*
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.xml.Element;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.form.Widget;
import com.arsdigita.bebop.parameters.ParameterModel;
// This interface contains the XML element name of this class
// in a constant which is used when generating XML
import com.arsdigita.bebop.util.BebopConstants;
/**
* A class representing a textarea field in an HTML form.
*
* @deprecated See {@link DHTMLEditor}
* @author Jim Parsons
*/
public class Deditor extends Widget implements BebopConstants {
/**
* Constant for specifying <tt>OFF</tt> value for the
* <tt>WRAP</tt> attribute of this image input. See <a
* href="http://developer.netscape.com/docs/manuals/htmlguid/tags10.htm#1340340">here</a>
* for a description of what this attribute does. */
public static final int OFF = 0;
/**
* Constant for specifying <tt>HARD</tt> value for the
* <tt>WRAP</tt> attribute of this image input. * See <a
* //href="http://developer.netscape.com/docs/manuals/htmlguid/tags10.htm#1340340">here</a>
* for a description of what this attribute does.
*/
public static final int HARD = 1;
/**
* Constant for specifying <tt>SOFT</tt> value for the
* <tt>WRAP</tt> attribute of this image input. See <a
* href="http://developer.netscape.com/docs/manuals/htmlguid/tags10.htm#1340340">here</a>
* for a description of what this attribute does.
*/
public static final int SOFT = 2;
public Deditor(String name) {
super(name);
}
public Deditor(ParameterModel model) {
super(model);
}
/**
* Returns a string naming the type of this widget.
*/
public String getType() {
return "deditor";
}
/**
* Set the default value (text)
* @deprecated [since 17Aug2001] use {@link Widget#setDefaultValue(Object)}
*/
public void setValue( String text ) {
this.setDefaultValue(text);
}
/**
* Sets the <tt>ROWS</tt> attribute for the <tt>TEXTAREA</tt> tag.
*/
public void setRows(int rows) {
setAttribute("rows", String.valueOf(rows));
}
/**
* Sets the <tt>COLS</tt> attribute for the <tt>TEXTAREA</tt> tag.
*/
public void setCols(int cols) {
setAttribute("cols", String.valueOf(cols));
}
/**
* Sets the <tt>COLS</tt> attribute for the <tt>TEXTAREA</tt> tag.
*/
public void setWrap(int wrap) {
String wrapString = null;
switch (wrap) {
case OFF:
wrapString = "off";
break;
case HARD:
wrapString = "hard";
break;
case SOFT:
wrapString = "soft";
break;
}
if (wrapString != null) {
setAttribute("wrap", wrapString);
}
}
/**
* Is this a compound widget?
* @return false
*/
public boolean isCompound() {
return false;
}
/** The XML tag.
* @return The tag to be used for the top level DOM element
* generated for this type of Widget. */
protected String getElementTag() {
return "bebop:deditor";
}
/**
* Generates the DOM for the textarea widget
* <p>Generates DOM fragment:
* <p><code>&lt;bebop:textarea name=... value=... [onXXX=...]/>
* </code>
*/
public void generateWidget( PageState state, Element parent ) {
Element deditor = parent.newChildElement(getElementTag(), BEBOP_XML_NS);
deditor.addAttribute("name", getName());
String userAgent =
state.getRequest().getHeader("user-agent").toLowerCase();
boolean isIE55 =
(userAgent != null &&
((userAgent.indexOf("msie 5.5") != -1) ||
(userAgent.indexOf("msie 6") != -1)));
deditor.addAttribute("isIE55", (new Boolean(isIE55)).toString());
String value = getParameterData(state).marshal();
if ( value == null ) {
value = "";
}
Element texter = deditor.newChildElement("bebop:textcontent",BEBOP_XML_NS);
texter.setCDATASection(value);
exportAttributes(deditor);
}
}

View File

@ -1,36 +0,0 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.xml.Element;
/**
* A fieldset for form.
*
* @author Sören Bernstein <quasi@quasiweb.de>
*/
public class Fieldset extends SimpleContainer {
GlobalizedMessage m_title;
public Fieldset(GlobalizedMessage title) {
super("bebop:fieldset", BEBOP_XML_NS);
m_title = title;
}
@Override
public void generateXML(PageState state, Element p) {
if (isVisible(state)) {
Element parent = generateParent(p);
parent.addAttribute("legend", (String) m_title.localize());
generateChildrenXML(state, parent);
}
}
}

View File

@ -1,108 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.event.ParameterEvent;
import com.arsdigita.bebop.parameters.GlobalizedParameterListener;
import com.arsdigita.bebop.parameters.ParameterData;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.dispatcher.MultipartHttpServletRequest;
import com.arsdigita.globalization.GlobalizedMessage;
import javax.servlet.http.HttpServletRequest;
/**
* A class representing a file upload widget.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Stas Freidin
* @author Rory Solomon
* @author Michael Pih
* @version $Id$ */
public class FileUpload extends Widget {
public FileUpload(String name) {
this(name, true);
}
public FileUpload(String name, boolean validateInputFile) {
super(name);
addValidationListener(new FileExistsValidationListener());
}
public FileUpload(ParameterModel model) {
this(model, true);
}
public FileUpload(ParameterModel model, boolean validateInputFile) {
super(model);
addValidationListener(new FileExistsValidationListener());
}
/**
* Returns a string naming the type of this widget.
* @return
*/
@Override
public String getType() {
return "file";
}
/**
*
* @return
*/
@Override
public boolean isCompound() {
return false;
}
/**
*
*/
private class FileExistsValidationListener extends GlobalizedParameterListener {
public FileExistsValidationListener() {
setError(new GlobalizedMessage("file_empty_or_not_found", getBundleBaseName()));
}
@Override
public void validate (ParameterEvent e) {
ParameterData data = e.getParameterData();
HttpServletRequest request = e.getPageState().getRequest();
String filename = (String) data.getValue();
if (!(request instanceof MultipartHttpServletRequest) ||
filename == null ||
filename.length() == 0) {
return;
}
if (((MultipartHttpServletRequest) request).getFile(data.getModel()
.getName())
.length()==0) {
data.addError(filename + " " + getError().localize());
}
}
}
}

View File

@ -1,97 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.PageErrorDisplay;
import com.arsdigita.bebop.list.ListModelBuilder;
import com.arsdigita.bebop.list.ListModel;
import com.arsdigita.bebop.List;
import com.arsdigita.bebop.FormData;
import com.arsdigita.bebop.PageState;
import com.arsdigita.util.LockableImpl;
import java.util.Collections;
/**
* Displays validation errors on the form which were added by the form's
* validation listener. Does not handle errors in the individual parameters;
* these errors are handled by the form's template. This class is not
* a form widget, since it does not produce a value.
*
* @author Stanislav Freidin
* @version $Id$
*
*/
public class FormErrorDisplay extends PageErrorDisplay {
private Form m_form;
/**
* Construct a new <code>FormErrorDisplay</code>
*
* @param form The parent form whose errors will be displayed by
* this widget
*/
public FormErrorDisplay(Form form) {
super(new FormErrorModelBuilder(form));
m_form = form;
}
/**
* Return the form whose errors are to be displayed
* @return the form whose errors are to be displayed
*/
public final Form getForm() {
return m_form;
}
/**
* Determine if there are errors to display
*
* @param state the current page state
* @return true if there are any errors to display; false otherwise
*/
protected boolean hasErrors(PageState state) {
FormData data = m_form.getFormData(state);
return (data != null && data.getErrors().hasNext());
}
// A private class which builds a ListModel based on form errors
private static class FormErrorModelBuilder extends LockableImpl
implements ListModelBuilder {
private Form m_form;
public FormErrorModelBuilder(Form form) {
super();
m_form = form;
}
public ListModel makeModel(List l, PageState state) {
FormData data = m_form.getFormData(state);
if(data == null) {
return new StringIteratorModel(Collections.EMPTY_LIST.iterator());
} else {
return new StringIteratorModel(data.getErrors());
}
}
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.parameters.ParameterModel;
/**
* A class representing a hidden HTML form element.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Stas Freidin
* @author Rory Solomon
* @author Michael Pih
* @version $Id$
*/
public class Hidden extends Widget {
public Hidden(String name) {
super(name);
}
public Hidden(ParameterModel model) {
super(model);
}
/**
* Returns a string naming the type of this widget.
*/
public String getType() {
return "hidden";
}
public boolean isCompound() {
return false;
}
}

View File

@ -1,136 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.bebop.util.PanelConstraints;
/**
* A class representing an image HTML form element.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Rory Solomon
* @author Michael Pih
* @version $Id$
*/
public class ImageSubmit extends Widget implements PanelConstraints {
/**
* Constructor.
*
* @param name
*/
public ImageSubmit(String name) {
super(name);
}
public ImageSubmit(ParameterModel model) {
super(model);
}
/**
* Returns a string naming the type of this widget.
*
* @return
*/
@Override
public String getType() {
return "image";
}
/**
* Sets the <tt>SRC</tt> attribute for the <tt>INPUT</tt> tag
* used to render this form element.
*
* @param location
*/
public void setSrc(String location) {
setAttribute("src",location);
}
/*
* Sets the <tt>ALRT</tt> attribute for the <tt>INPUT</tt> tag
* used to render this form element.
*/
public void setAlt(String alt) {
setAttribute("alt",alt);
}
/**
* Sets the <tt>ALIGN</tt> attribute for the <tt>INPUT</tt> tag
* used to render this form element. Uses the positional constants defined
* in Interface PanelConstraints.
* Note: These may be refactored in future versions.
*
* @param align Symbolic constant denoting the alignment.
*/
public void setAlign(int align) {
String alignString = null;
switch (align) {
case LEFT:
alignString = "left";
break;
case RIGHT:
alignString = "right";
break;
case TOP:
alignString = "top";
break;
case ABSMIDDLE:
alignString = "absmiddle";
break;
case ABSBOTTOM:
alignString = "absbottom";
break;
case TEXTTOP:
alignString = "texttop";
break;
case MIDDLE:
alignString = "middle";
break;
case BASELINE:
alignString = "baseline";
break;
case BOTTOM:
alignString = "botton";
break;
}
if (alignString != null)
setAttribute("align",alignString);
}
@Override
public boolean isCompound() {
return false;
}
/**
* Callback method for rendering this Image widget in a visitor.
*/
/* public void accept(FormVisitor visitor) throws IOException {
visitor.visitImage(this);
}
*/
}

View File

@ -1,53 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.parameters.ArrayParameter;
// This interface contains the XML element name of this class
// in a constant which is used when generating XML
import com.arsdigita.bebop.util.BebopConstants;
/**
* A class
* representing an HTML <code>SELECT</code> element.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Rory Solomon
* @author Michael Pih
* @version $Id$ */
public class MultipleSelect extends Select implements BebopConstants {
public MultipleSelect(String name) {
super(new ArrayParameter(name));
}
/** State that this is a multiple select
* @return true
*/
public boolean isMultiple()
{ return true; }
/** The XML tag for this derived class of Widget. */
protected String getElementTag() {
return BEBOP_MULTISELECT;
}
}

View File

@ -1,557 +0,0 @@
/*
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.FormStep;
import com.arsdigita.bebop.GridPanel;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.RequestLocal;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.parameters.ArrayParameter;
import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Iterator;
import java.util.HashMap;
import java.util.Map;
/**
* <p>Multiple select widget pair for knowledge types. This FormStep
* displays two multiple select widgets, one which contains possible
* the user may want to add, and the right displays the options that
* are currently applicable. </p>
*
* <p>To use the widget, you should call {@link
* #setLeftMultipleSelect(RequestLocal)} and {@link
* #setRightMultipleSelect(RequestLocal)} and pass in the appropriate
* collections to initialize the MutlipleSelect options. Then, in the
* process listener of the form in which the MultipleSelectPairWidget
* is embedded, call {@link #getSelectedOptions(PageState)} and {@link
* #getUnselectedOptions(PageState)} to get the chosen values. The process
* listener for the parent form must use the Submit.isSelected(ps) so
* that the process listener can distinguish between different types
* of form submits.</p>
*
* <p>Note that the right multiple select can be empty and does not need
* to be set. This class also uses a relatively inefficient
* implementation of removeOption in {@link OptionGroup OptionGroup}
* so that operations run in O(N^2). This can be reduced to O(N) with
* a more optimal implementation of OptionGroup.</p>
*
* @see Option
* @see OptionGroup
* @version $Id$
*/
public class MultipleSelectPairWidget extends FormStep {
private Hidden m_addSelectOptions;
private Hidden m_removeSelectOptions;
private MultipleSelect m_addSelect;
private MultipleSelect m_removeSelect;
private Submit m_addSubmit;
private Submit m_removeSubmit;
private RequestLocal m_addSelectDataSource;
private RequestLocal m_removeSelectDataSource;
private RequestLocal m_selectsPopulated;
private RequestLocal m_leftSelectMap = null;
private RequestLocal m_rightSelectMap = null;
private boolean m_leftSideChanges;
private String m_qualifier;
private final static int RIGHT = 1;
private final static int LEFT = 2;
// Empty array for internal use. Should be part of a generic utility class.
private static final String[] EMPTY_STRING_ARRAY = new String[0];
// Configuration options.
private int m_multipleSelectSize = 20;
/**
* This create a standard MultipleSelectPairWidget with the
* default names used for internal widgets.
*/
public MultipleSelectPairWidget() {
this(null);
}
public MultipleSelectPairWidget(String nameQualifier) {
super(nameQualifier + "MultipleSelectPairWidget", new GridPanel(3));
m_qualifier = nameQualifier;
m_addSelectOptions =
new Hidden(new ArrayParameter(qualify("addSelectOptions")));
m_removeSelectOptions = new Hidden
(new ArrayParameter(qualify("removeSelectOptions")));
m_addSelect = new MultipleSelect(qualify("leftSelect"));
m_addSelect.setSize(m_multipleSelectSize);
m_removeSelect = new MultipleSelect(qualify("rightSelect"));
m_removeSelect.setSize(m_multipleSelectSize);
setLeftSideChanges(true);
m_addSubmit = new Submit(qualify("->"), " -> ");
m_removeSubmit = new Submit(qualify("<-"), " <- ");
GridPanel centerPanel = new GridPanel(1);
centerPanel.add(m_addSubmit);
centerPanel.add(m_removeSubmit);
add(m_addSelect, GridPanel.LEFT);
add(centerPanel, GridPanel.CENTER);
add(m_removeSelect, GridPanel.RIGHT);
add(m_addSelectOptions);
add(m_removeSelectOptions);
m_selectsPopulated = new RequestLocal();
addInitListener(new MultipleSelectPairFormInitListener
(m_selectsPopulated));
addProcessListener(new MultipleSelectPairFormProcessListener
(m_selectsPopulated));
}
public boolean isSelected(PageState ps) {
return m_addSubmit.isSelected(ps) || m_removeSubmit.isSelected(ps);
}
/**
* @param collection A collection of Option objects
*/
public void setLeftMultipleSelect(RequestLocal collection) {
m_addSelectDataSource = collection;
}
/**
* This lets the user pass in a RequestLocal that returns
* a java.util.Map that contains the option value as the
* key and the actual option as the map value.
* When populating the left select, the system will use
* this map before falling back to the default map.
*/
public void setLeftMultipleSelectMap(RequestLocal map) {
m_leftSelectMap = map;
}
/**
* This lets the user pass in a RequestLocal that returns
* a java.util.Map that contains the option value as the
* key and the actual option as the map value.
* When populating the left select, the system will use
* this map before falling back to the default map.
*/
public void setRightMultipleSelectMap(RequestLocal map) {
m_rightSelectMap = map;
}
/**
* This returns the left select widget so that callers
* can have access to the underlying parameters and
* other features (e.g. in case they need to add a
* ParameterListener)
*/
public Widget getLeftSelect() {
return m_addSelect;
}
/**
* This returns the left select widget so that callers
* can have access to the underlying parameters and
* other features (e.g. in case they need to add a
* ParameterListener)
*/
public Widget getRightSelect() {
return m_removeSelect;
}
/**
* @param doesChange This indicates whether the items in the
* "to add" select box are removed as they are added to
* the "to remove" select box. That is, as choices are
* selected, should they be removed from the list of
* choices? This defaults to true.
*/
public void setLeftSideChanges(boolean doesChange) {
m_leftSideChanges = doesChange;
}
/**
* This returns an indication of whether or not the left
* multiple select changes as items are moved from the left
* to the right.
*/
public boolean leftSideChanges() {
return m_leftSideChanges;
}
/**
* @param collection A collection of Option objects
*/
public void setRightMultipleSelect(RequestLocal collection) {
m_removeSelectDataSource = collection;
}
/**
* Returns the selected options, those selected from the left hand widget
*
* @return array of options
* @post return != null
*/
public String[] getSelectedOptions(PageState ps) {
String[] options = (String[]) m_removeSelectOptions.getValue(ps);
// Probably unneccessary, as widget should be populated with EMPTY_STRING_ARRAY in init listener
// if there is no data.
if (null == options) {
options = EMPTY_STRING_ARRAY;
}
return options;
}
/**
* Returns the unselected options, those removed from the right hand widget
*
* @return array of options
* @post return != null
*/
public String[] getUnselectedOptions(PageState ps) {
String[] options = (String[]) m_addSelectOptions.getValue(ps);
// Probably unneccessary, as widget should be populated with EMPTY_STRING_ARRAY in init listener
// if there is no data.
if (null == options) {
options = EMPTY_STRING_ARRAY;
}
return options;
}
public void generateXML(PageState state, Element element) {
// if the page has not been populated then it need to
// be populated from the hidden variables. Otherwise,
// nothing will be displayed in the multi-select boxes.
if (!Boolean.TRUE.equals(m_selectsPopulated.get(state)) &&
isInitialized(state)) {
List addOptions = new ArrayList();
List removeOptions = new ArrayList();
String[] unselected = getUnselectedOptions(state);
for (int i = 0; i < unselected.length; i++) {
String option = unselected[i];
addOptions.add(option);
}
String[] selected = getSelectedOptions(state);
for (int i = 0; i < selected.length; i++) {
String option = selected[i];
removeOptions.add(option);
}
m_selectsPopulated.set(state, Boolean.TRUE);
generateOptionValues(state, addOptions, removeOptions,
setupOptionMap(state));
m_addSelect.addOption(getEmptyOption(), state);
m_removeSelect.addOption(getEmptyOption(), state);
}
super.generateXML(state, element);
}
/**
* This changes the name of the parameter so that it is possible
* to include several of these on the same page.
*/
private String qualify(String property) {
if (m_qualifier != null) {
return m_qualifier + "_" + property;
} else {
return property;
}
}
/**
* @size The number of rows to display in the multiple selects.
*/
public void setMultipleSelectSize(int size) {
m_multipleSelectSize = size;
m_removeSelect.setSize(m_multipleSelectSize);
m_addSelect.setSize(m_multipleSelectSize);
}
private HashMap setupOptionMap(PageState ps) {
// We put all of our options into a HashMap so that we can add the
// Option object to the destination MultipleSelect.
HashMap optionsMap = new HashMap();
Collection addOptions = (Collection) m_addSelectDataSource.get(ps);
Iterator i;
Option option;
i = addOptions.iterator();
while ( i.hasNext() ) {
option = (Option) i.next();
optionsMap.put(option.getValue(), option);
}
if ( m_removeSelectDataSource != null ) {
Collection removeOptions = (Collection) m_removeSelectDataSource.get(ps);
if ( removeOptions != null ) {
i = removeOptions.iterator();
while ( i.hasNext() ) {
option = (Option) i.next();
if (optionsMap.get(option.getValue()) == null) {
optionsMap.put(option.getValue(), option);
}
}
}
}
return optionsMap;
}
private void generateOptionValues(PageState ps, List addOptions,
List removeOptions,
HashMap m_optionsMap) {
Iterator iter;
iter = addOptions.iterator();
while ( iter.hasNext() ) {
String s = (String) iter.next();
Option o = getOption(ps, m_optionsMap, s, LEFT);
// it is possible to be null if for some reason the key, s, is
// not found any of the maps
if (o != null) {
m_addSelect.addOption(o, ps);
}
}
iter = removeOptions.iterator();
while ( iter.hasNext() ) {
String s = (String) iter.next();
Option o = getOption(ps, m_optionsMap, s, RIGHT);
// it is possible to be null if for some reason the key, s, is
// not found any of the maps
if (o != null) {
m_removeSelect.addOption(o, ps);
}
}
}
/**
* This looks at the request locals set in setRightMultipleSelectMap
* and setLeftMultipleSelectMap before falling back on the default
* mapping that was auto-generated. If the value is found
* in the passed in map then that value is used. Otherwise, the
* value is located in the default mapping
*/
private Option getOption(PageState state, Map optionMapping, String key,
int side) {
if (side == RIGHT) {
if (m_rightSelectMap != null) {
Map map = (Map)m_rightSelectMap.get(state);
if (map.get(key) != null) {
return (Option)map.get(key);
}
}
} else {
if (m_leftSelectMap != null) {
Map map = (Map)m_leftSelectMap.get(state);
if (map.get(key) != null) {
return (Option)map.get(key);
}
}
}
return (Option)optionMapping.get(key);
}
private class MultipleSelectPairFormProcessListener
implements FormProcessListener {
// This is to allow a call back to set an item as being
// initialized
private RequestLocal m_processed;
MultipleSelectPairFormProcessListener(RequestLocal processed) {
m_processed = processed;
}
public void process(FormSectionEvent evt) {
PageState ps = evt.getPageState();
if (!m_addSubmit.isSelected(ps)
&& !m_removeSubmit.isSelected(ps)) {
return;
}
m_processed.set(ps, Boolean.TRUE);
HashMap m_optionsMap;
List addOptions = new ArrayList();
List removeOptions = new ArrayList();
m_optionsMap = setupOptionMap(ps);
// We first update the array lists that contain the list
// of unselected options based on the contents of the
// hidden form variables.
updateUnselectedOptions(ps, addOptions, removeOptions);
// Then we update those array lists based on what the user
// moves.
if ( m_addSubmit.isSelected(ps) ) {
String[] selectedArray = (String[]) m_addSelect.getValue(ps);
if ( selectedArray != null ) {
List selectedAddOptions = Arrays.asList(selectedArray);
Iterator iter = selectedAddOptions.iterator();
while ( iter.hasNext() ) {
String s = (String) iter.next();
// we only want to add the item if it has not
// already been added
if (!removeOptions.contains(s)) {
removeOptions.add(s);
}
if (leftSideChanges()) {
addOptions.remove(s);
}
}
}
}
if ( m_removeSubmit.isSelected(ps) ) {
String[] selectedArray = (String[]) m_removeSelect.getValue(ps);
if ( selectedArray != null ) {
List selectedRemoveOptions = Arrays.asList(selectedArray);
Iterator iter = selectedRemoveOptions.iterator();
while ( iter.hasNext() ) {
String s = (String) iter.next();
removeOptions.remove(s);
// if the left side does not change then the
// item was never removed from the addOptions so
// it does not need to be added back.
if (leftSideChanges()) {
addOptions.add(s);
}
}
}
}
// Next, we put the full list of options back into the hidden.
// we have to convert this to a String[]...otherwise we
// can get a ClassCastException when used within a Wizard
String[] newValues = (String[]) addOptions.toArray(EMPTY_STRING_ARRAY);
m_addSelectOptions.setValue(ps, newValues);
// We do the same conversion for the new values
newValues = (String[]) removeOptions.toArray(EMPTY_STRING_ARRAY);
m_removeSelectOptions.setValue(ps, newValues);
// We finally generate the option values.
generateOptionValues(ps, addOptions, removeOptions, m_optionsMap);
m_addSelect.addOption(getEmptyOption(), ps);
m_removeSelect.addOption(getEmptyOption(), ps);
}
private void updateUnselectedOptions(PageState ps, List addOptions,
List removeOptions) {
// We add the unselected options back to the MultipleSelects.
String[] unselected = getUnselectedOptions(ps);
for (int i = 0; i < unselected.length; i++) {
String s = unselected[i];
addOptions.add(s);
}
String[] selected = getSelectedOptions(ps);
for (int i = 0; i < selected.length; i++) {
String s = selected[i];
removeOptions.add(s);
}
}
}
private class MultipleSelectPairFormInitListener implements FormInitListener {
private RequestLocal m_initialized;
MultipleSelectPairFormInitListener(RequestLocal initialized ) {
m_initialized = initialized;
}
public void init(FormSectionEvent evt) {
PageState ps = evt.getPageState();
m_initialized.set(ps, Boolean.TRUE);
String[] addOptionsForHidden = EMPTY_STRING_ARRAY;
String[] removeOptionsForHidden = EMPTY_STRING_ARRAY;
Assert.exists(m_addSelectDataSource,
"You must provide some options for the " +
"user to choose!");
Collection addOptions = (Collection) m_addSelectDataSource.get(ps);
if (addOptions.size() > 0) {
Iterator iter = addOptions.iterator();
addOptionsForHidden = new String[addOptions.size()];
int idx = 0;
while ( iter.hasNext() ) {
Option option = (Option) iter.next();
m_addSelect.addOption(option, ps);
addOptionsForHidden[idx++] = option.getValue();
}
}
if ( m_removeSelectDataSource != null ) {
Collection c = (Collection) m_removeSelectDataSource.get(ps);
if ( c != null && c.size() > 0 ) {
removeOptionsForHidden = new String[c.size()];
Iterator iter = c.iterator();
int idx = 0;
while ( iter.hasNext() ) {
Option option = (Option) iter.next();
m_removeSelect.addOption(option, ps);
removeOptionsForHidden[idx++] = option.getValue();
}
}
}
m_addSelectOptions.setValue(ps, addOptionsForHidden);
m_removeSelectOptions.setValue(ps, removeOptionsForHidden);
m_addSelect.addOption(getEmptyOption(), ps);
m_removeSelect.addOption(getEmptyOption(), ps);
}
}
private Option getEmptyOption() {
return new Option("",
new Label("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;",
false));
}
}

View File

@ -1,317 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.DescriptiveComponent;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.ParameterData;
import com.arsdigita.util.Assert;
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.xml.Element;
/**
* A class representing an option of a widget.
*
* The Option consist of two parts:
* - a value, used by the background task to process the option
* - a display component, used to display the option to the user in the GUI,
* usually a Label (title), but may be e.g. an image as well.
* @author Rory Solomon
* @author Michael Pih
*
* $Id$
*/
public class Option extends DescriptiveComponent {
/** The value of the option, used by the background task to process the
* option.
* NOTE: The display component, the label, is provided by parent class! */
private String m_value;
/** The display component for the user in the GUI. It's usually a Label,
* but may be e.g. an image as well. */
private Component m_component;
private OptionGroup m_group;
private boolean m_isSelectOption;
// ///////////////////////////////////////////////////////////////////////
// Constructor Section
//
/**
* A (too) simple Constructor which uses a String as value as well as
* display component.
*
* @param value A String used as value as well as display component.
* @deprecated use Option(value,component) instead
*/
public Option(String value) {
this(value, value);
}
/**
* Constructor creates an Option whose label part consisting of a string.
* This results in a badly globalized label part. The localization depends
* on the language selected at the time the Option is created.
*
* @param value
* @param label
* @deprecated use Option(value,component) instead
*/
public Option(String value, String label) {
setValue(value);
setLabel(label);
}
/**
* Constructor creates an Option whose label part consisting of a Component,
* usually a Label(GlobalizedMessage).
* This constructor should be used to create a fully globalized and
* localized user interface.
*
* @param value
* @param label
*/
public Option(String value, Component label) {
setValue(value);
setComponent(label);
}
// ///////////////////////////////////////////////////////////////////////
// Getter/Setter Section
//
/**
* Retrieves the value part of an option.
* @return the value part of this option.
*/
public final String getValue() {
return m_value;
}
/**
* Sets of modifies the value of on option.
* @param value new value part of the option
*/
public final void setValue(String value) {
m_value = value;
}
/**
* Retrieves the display part of the option.
* @return the display component for this option
*/
public final Component getComponent() {
return m_component;
}
/**
* Sets of modifies the display component of an option.
*
* @param component the display component for this option
*/
public final void setComponent(Component component) {
Assert.isUnlocked(this);
m_component = component;
}
/**
* Sets of modifies the display component of an option providing a Label.
* The label is internally stored as a component.
*
* @param label
*/
public final void setLabel(Label label) {
setComponent(label);
}
/**
* This sets the display component using a String. It results in a badly
* globalized UI
*
* @param label String to use as the display component
* @deprecated Use {@link #setComponent(Component component)} instead
*/
public final void setLabel(String label) {
setComponent(new Label(label));
}
/**
*
* @param group
*/
public final void setGroup(OptionGroup group) {
Assert.isUnlocked(this);
Assert.exists(group);
m_group = group;
m_isSelectOption = BebopConstants.BEBOP_OPTION.equals(m_group.getOptionXMLElement());
}
/**
*
* @return
*/
public final OptionGroup getGroup() {
return m_group;
}
/**
* Retrieves the name (identifier) of the option group containing this
* option. Don't know the purpose of this.
*
* @return The name (identifier) of the option group this option belongs
* to
*/
public String getName() {
return m_group.getName();
}
/**
* Sets the <tt>ONFOCUS</tt> attribute for the HTML tags that compose
* this element.
* @param javascriptCode
*/
public void setOnFocus(String javascriptCode) {
setAttribute(Widget.ON_FOCUS,javascriptCode);
}
/**
* Sets the <tt>ONBLUR</tt> attribute for the HTML tags that compose
* this element.
* @param javascriptCode
*/
public void setOnBlur(String javascriptCode) {
setAttribute(Widget.ON_BLUR,javascriptCode);
}
/**
* Sets the <tt>ONSELECT</tt> attribute for the HTML tags that compose
* this element.
* @param javascriptCode
*/
public void setOnSelect(String javascriptCode) {
setAttribute(Widget.ON_SELECT,javascriptCode);
}
/**
* Sets the <tt>ONCHANGE</tt> attribute for the HTML tags that compose
* this element.
* @param javascriptCode
*/
public void setOnChange(String javascriptCode) {
setAttribute(Widget.ON_CHANGE,javascriptCode);
}
/**
* Sets the <tt>ON_KEY_UP</tt> attribute for the HTML tags that compose
* this element.
* @param javascriptCode
**/
public void setOnKeyUp(String javascriptCode) {
setAttribute(Widget.ON_KEY_UP, javascriptCode);
}
/**
* Sets the <tt>ONCLICK</tt> attribute for the HTML tags that compose
* this element.
* @param javascriptCode
*/
public void setOnClick(String javascriptCode) {
setAttribute(Widget.ON_CLICK,javascriptCode);
}
private ParameterData getParameterData(PageState s) {
return m_group.getParameterData(s);
}
public boolean isSelected(ParameterData data) {
if (data == null || data.getValue() == null) {
return false;
}
Object value = data.getValue();
Object[] selectedValues;
if (value instanceof Object[]) {
selectedValues = (Object[])value;
} else {
selectedValues = new Object[] {value};
}
String optionValue = getValue();
if (optionValue == null || selectedValues == null) {
return false;
}
for (Object selectedValue : selectedValues) {
if (selectedValue != null
&& optionValue.equalsIgnoreCase(selectedValue.toString())) {
return true;
}
}
return false;
}
/**
* Generate XML depending on what OptionGr.
*
* @param s
* @param e
*/
@Override
public void generateXML(PageState s, Element e) {
Element option = e.newChildElement(m_group.getOptionXMLElement(), BEBOP_XML_NS);
if ( ! m_isSelectOption ) {
option.addAttribute("name", getName());
}
option.addAttribute("value", getValue());
if (m_component != null) {
m_component.generateXML(s, option);
} else {
(new Label()).generateXML(s, option);
}
exportAttributes(option);
if ( isSelected(getParameterData(s)) ) {
if ( m_isSelectOption ) {
option.addAttribute("selected", "selected");
} else {
option.addAttribute("checked", "checked");
}
}
}
/**
* Kludge to live with the fact that options don't do their own
* printing. Don't use this method, it will go away !
*
* @deprecated Will be removed without replacement once option handling
* has been refactored.
*/
final void generateAttributes(Element target) {
exportAttributes(target);
}
}

View File

@ -1,596 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.RequestLocal;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.ParameterData;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.bebop.parameters.ParameterModelWrapper;
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.text.Collator;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.l10n.GlobalizationHelper;
/**
* A class representing any widget that contains a list of options.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Rory Solomon
* @author Michael Pih
*/
public abstract class OptionGroup extends Widget implements BebopConstants {
private static final Logger LOGGER = LogManager.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 List<String> m_selected;
private List<Option> m_options;
private Widget m_otherOption = null;
private Form m_form = null;
private boolean m_isDisabled = false;
private boolean m_isReadOnly = false;
/**
* Sort Mode for options
*/
private OptionGroup.SortMode sortMode;
/**
* Exclude first option from sorting?
*/
private boolean excludeFirst;
public static final String OTHER_OPTION = "__other__";
// 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.";
/**
* request-local copy of selected elements, options
*/
private final RequestLocal m_requestOptions = new RequestLocal() {
@Override
public Object initialValue(final PageState state) {
return new ArrayList<Option>();
}
};
/**
*
* @return
*/
@Override
public final boolean isCompound() {
return true;
}
/**
* The ParameterModel for multiple OptionGroups is always an array parameter
*
* @param model
*
* @param model
*/
protected OptionGroup(final ParameterModel model) {
//super(model);
//m_options = new ArrayList<Option>();
//m_selected = new ArrayList<String>();
this(model, OptionGroup.SortMode.NO_SORT, false);
}
protected OptionGroup(final ParameterModel model,
final OptionGroup.SortMode sortMode) {
this(model, sortMode, false);
}
protected OptionGroup(final ParameterModel model,
final OptionGroup.SortMode sortMode,
final boolean excludeFirst) {
super(model);
m_options = new ArrayList<Option>();
m_selected = new ArrayList<String>();
this.sortMode = sortMode;
this.excludeFirst = excludeFirst;
}
/**
* Returns an Iterator of all the default Options in this group.
*
* @return
*/
public Iterator<Option> getOptions() {
return m_options.iterator();
}
public enum SortMode {
NO_SORT,
ALPHABETICAL_ASCENDING,
ALPHABETICAL_DESENDING
}
public abstract String getOptionXMLElement();
/**
* This {@link Comparator} implementation is used to sort the list of
* options alphabetical. If the sorting is ascending or descending depends
* on the selected sort mode. The Comparator needs the {@link PageState} for
* retrieving the localised labels from the options.
*/
private class AlphabeticalSortComparator implements Comparator<Option> {
private final PageState state;
/**
* Constructor taking the current {@code PageState}.
*
* @param state
*/
public AlphabeticalSortComparator(final PageState state) {
this.state = state;
}
@Override
public int compare(final Option option1, final Option option2) {
String label1;
String label2;
//Check if the first option to compare has a inner label component. If it has
//store the localised text. Otherwise use the name of the option.
if (option1.getComponent() instanceof Label) {
final Label label = (Label) option1.getComponent();
label1 = label.getLabel(state);
} else {
label1 = option1.getName();
}
// Same for the second option
if (option2.getComponent() instanceof Label) {
final Label label = (Label) option2.getComponent();
label2 = label.getLabel(state);
} else {
label2 = option2.getName();
}
//We are using a Collator instance here instead of String#compare(String) because
//String#compare(String) is not local sensitive. For example in german a word starting
//with the letter 'Ö' should be handled like a word starting with the letter 'O'.
//Using String#compare(String) would put them at the end of the list.
//Depending on the sort mode we compare label1 with label2 (ascending) or label2 with
//label1 (descending).
final Collator collator = Collator
.getInstance(CdiUtil.createCdiUtil().findBean(
GlobalizationHelper.class).getNegotiatedLocale());
if (sortMode == SortMode.ALPHABETICAL_ASCENDING) {
return collator.compare(label1, label2);
} else if (sortMode == SortMode.ALPHABETICAL_DESENDING) {
return collator.compare(label2, label1);
} else {
return 0;
}
}
}
/**
* Returns an Iterator of all the default Options in this group, plus any
* request-specific options.
*
* @param state
*
* @return
*/
public Iterator<Option> getOptions(final PageState state) {
List<Option> allOptions = new ArrayList<Option>();
allOptions.addAll(m_options);
List<Option> requestOptions = (List<Option>) m_requestOptions.get(state);
for (Iterator<Option> iterator = requestOptions.iterator(); iterator
.hasNext();) {
final Option option = iterator.next();
if (!allOptions.contains(option)) {
allOptions.add(option);
}
}
return allOptions.iterator();
}
public void clearOptions() {
Assert.isUnlocked(this);
m_options = new ArrayList<Option>();
}
/**
* Adds a new option.
*
* @param option 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(final Option option) {
addOption(option, null, false);
}
/**
* Adds a new option.
*
* @param opt
* @param ps
*/
public void addOption(final Option option, final PageState state) {
addOption(option, state, false);
}
/**
* Adds a new option at the beginning of the list.
*
* @param option 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(final Option option) {
addOption(option, null, true);
}
public void prependOption(final Option option, final PageState state) {
addOption(option, state, true);
}
public void removeOption(final Option option) {
removeOption(option, null);
}
/**
* 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 option The {@link Option} to be added. Note: the argument is
* modified and associated with this OptionGroup, regardless
* of what its group was.
* @param state 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(final Option option, final PageState state,
final boolean prepend) {
List<Option> list = m_options;
if (state == null) {
Assert.isUnlocked(this);
} else {
list = (List<Option>) m_requestOptions.get(state);
}
option.setGroup(this);
if (prepend == true) {
list.add(0, option);
} else {
list.add(option);
}
}
public void removeOption(final Option option, final PageState state) {
List<Option> list = m_options;
if (state == null) {
Assert.isUnlocked(this);
} else {
list = (List<Option>) m_requestOptions.get(state);
}
list.remove(option);
}
public void removeOption(String key) {
removeOption(key, null);
}
/**
* Removes the first option whose key is isEqual to the key that is passed
* in.
*
* @param key
* @param state the current page state. if ps is null, adds option to the
* default option list.
*/
public void removeOption(final String key, final PageState state) {
// This is not an entirely efficient technique. A more
// efficient solution is to switch to using a HashMap.
List<Option> list = m_options;
if (state == null) {
Assert.isUnlocked(this);
} else {
list = (List<Option>) m_requestOptions.get(state);
}
final Iterator<Option> iterator = list.iterator();
Option option;
while (iterator.hasNext()) {
option = iterator.next();
if (option.getValue().equals(key)) {
list.remove(option);
break;
}
}
}
/**
* Add an "Other (please specify)" type option to the widget
*
* @param label
* @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(final String label, final int width,
final int height) {
Assert.isUnlocked(this);
final Option otherOption = new Option(OTHER_OPTION, label);
addOption(otherOption);
final ParameterModel model = getParameterModel();
if (1 == height) {
TextField field = new TextField(model.getName() + ".other");
field.setSize(width);
m_otherOption = field;
} else {
TextArea area = new TextArea(model.getName() + ".other");
area.setCols(width);
area.setRows(height);
m_otherOption = area;
}
if (null != m_form) {
m_otherOption.setForm(m_form);
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) {
final String[] values = request.getParameterValues(getName());
String[] otherValues = request.getParameterValues(getName()
+ ".other");
String other = (null == otherValues) ? null : otherValues[0];
if (null != values) {
for (int i = 0; i < values.length; i++) {
if (OTHER_OPTION.equals(values[i])) {
values[i] = other;
}
}
}
LOGGER.debug("createParameterData in OptionGroup");
return super.createParameterData(new HttpServletRequestWrapper(
request) {
@Override
public String[] getParameterValues(String key) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Getting values for " + key);
}
if (model.getName().equals(key)) {
return values;
}
return super.getParameterValues(key);
}
}, defaultValue, isSubmission);
}
private void replaceOther(String[] values, String other) {
}
});
}
/**
* 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(final String value) {
Assert.isUnlocked(this);
if (!isMultiple()) {
// only one option may be selected
// to this selected list better be empty
Assert.isTrue(m_selected.isEmpty(), 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
*
* @param option the option to be added to the by-default-selected set.
*/
public void setOptionSelected(Option option) {
setOptionSelected(option.getValue());
}
@Override
public Object clone() throws CloneNotSupportedException {
final OptionGroup cloned = (OptionGroup) super.clone();
//cloned.m_options = m_options.clone();
//cloned.m_selected = m_selected.clone();
cloned.m_options.addAll(m_options);
cloned.m_selected.addAll(m_selected);
return cloned;
}
/**
* Whether 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(final 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:*select&gt;</code></pre>
*/
@Override
public void generateWidget(final PageState state, final Element parent) {
final Element optionGroup = parent.newChildElement(getElementTag(),
BEBOP_XML_NS);
optionGroup.addAttribute("name", getName());
optionGroup.addAttribute("class", getName().replace(".", " "));
// Localized title for this option group
if (getLabel() != null) {
optionGroup.addAttribute("label", (String) getLabel()
.localize(state.getRequest()));
}
if (isMultiple()) {
optionGroup.addAttribute("multiple", "multiple");
}
exportAttributes(optionGroup);
//Build a list of all options we can operator on.
final List<Option> options = new ArrayList<Option>();
for (Iterator<Option> iterator = getOptions(state); iterator.hasNext();) {
options.add(iterator.next());
}
//If the sort mode is not {@code NO_SORT}, sort the the list.
if (sortMode != SortMode.NO_SORT) {
//If exclude first is sest to true the first option should stay on the top.
//We simply remove the first option from our list and generate the XML for it here.
if (excludeFirst && !options.isEmpty()) {
final Option first = options.remove(0);
first.generateXML(state, optionGroup);
}
//Sort the list using our {@link AlphabeticalSortComparator}.
Collections.sort(options, new AlphabeticalSortComparator(state));
}
//Generate the XML for the options.
for (Option option : options) {
option.generateXML(state, optionGroup);
}
// for (Iterator<Option> iterator = getOptions(state); iterator.hasNext();) {
// Option option = iterator.next();
// option.generateXML(state, optionGroup);
// }
if (null != m_otherOption) {
m_otherOption.generateXML(state, optionGroup);
}
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.parameters.ParameterModel;
/**
* A class representing a password entry field in an HTML form.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Rory Solomon
* @author Michael Pih
* @version $Id$
*/
public class Password extends Widget {
public Password(String name) {
super(name);
}
public Password(ParameterModel model) {
super(model);
}
/**
* Returns a string naming the type of this widget.
*/
public String getType() {
return "password";
}
/**
* Sets the <tt>MAXLENGTH</tt> attribute for the <tt>INPUT</tt> tag
* used to render this form element.
*/
public void setMaxLength(int length) {
setAttribute("maxlength",String.valueOf(length));
}
/**
* Sets the <tt>SIZE</tt> attribute for the <tt>INPUT</tt> tag
* used to render this form element.
*/
public void setSize(int size) {
setAttribute("size",String.valueOf(size));
}
public boolean isCompound() {
return false;
}
/**
* Callback method for rendering this Password widget in a visitor.
public void accept(FormVisitor visitor) throws IOException {
visitor.visitPassword(this);
}
*/
}

View File

@ -1,119 +0,0 @@
/*
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.bebop.form;
import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.bebop.parameters.StringParameter;
// This interface contains the XML element name of this class
// in a constant which is used when generating XML
import com.arsdigita.bebop.util.BebopConstants;
/**
* A class
* representing a <em>group</em> of associated radio buttons.
*
* @author Karl Goldstein
* @author Uday Mathur
* @author Rory Solomon
* @author Michael Pih
* @version $Id$ */
public class RadioGroup extends OptionGroup implements BebopConstants {
// xml attribute for layout
private final static String AXIS = "axis";
/**
* Specifies that options should be laid out left to right.
*/
// this is default
public final static int HORIZONTAL = 1;
/**
* Specifies that options should be laid out top to bottom.
*/
public final static int VERTICAL = 2;
public RadioGroup(String name) {
this(new StringParameter(name));
}
public RadioGroup(ParameterModel model) {
super(model);
//m_xmlElement = BEBOP_RADIO;
}
/**
* Returns a string naming the type of this widget.
*/
public String getType() {
return "radio";
}
/** The XML tag.
* @return The tag to be used for the top level DOM element
* generated for this type of Widget. */
protected String getElementTag() {
return BEBOP_RADIOGROUP;
}
@Override
public String getOptionXMLElement() {
return BEBOP_RADIO;
}
/**
* Is this a multiple (and not single) selection option group?
*
* @return true if this OptionGroup can have more than one
* selected option; false otherwise.
*/
public boolean isMultiple() {
return false;
}
/**
* Sets the layout for the options in this radio group.
*
* @param layout one of RadioGroup.VERTICAL or RadioGroup.HORIZONTAL
**/
public void setLayout(int layout) {
setAttribute(AXIS, String.valueOf(layout));
}
/**
* Returns the layout for the options in this radio group.
*
* @return one of RadioGroup.VERTICAL or RadioGroup.HORIZONTAL
**/
public int getLayout() {
String value = getAttribute(AXIS);
if (value == null) {
return HORIZONTAL;
} else if (value.equals(String.valueOf(HORIZONTAL))) {
return HORIZONTAL;
} else if (value.equals(String.valueOf(VERTICAL))) {
return VERTICAL;
} else {
throw new IllegalStateException(
"invalid value for axis attribute: " + value);
}
}
}

Some files were not shown because too many files have changed in this diff Show More