Removed several depcrecated classes from ccm-core, especially the complete Bebop UI kit.
parent
abe48a650d
commit
b681c769b9
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
* <bebop:link href="..." type="..." %bebopAttr;/>
|
||||
* </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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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><bebop:boxPanel [width=...] border=... center... axis...>
|
||||
* <bebop:cell> cell contents </bebop:cell>
|
||||
* </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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
* <table> 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 <table> 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>
|
||||
* <bebop:pad>
|
||||
* [<bebop:padFrame>]
|
||||
* [<bebop:border>]
|
||||
* <bebop:panelRow>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* ...
|
||||
* </bebop:panelRow>
|
||||
* <bebop:panelRow>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* ...
|
||||
* </bebop:panelRow>
|
||||
* [</bebop:border>]
|
||||
* [</bebop:padFrame>]
|
||||
* </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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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), <b>example</b>
|
||||
* will appear literally.</LI>
|
||||
* <LI>If output escaping is disabled, <b>example</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, <b>content</b> will appear literally.</LI> <LI>If
|
||||
* output escaping is disabled, <b>content</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>
|
||||
* <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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
* <bebop:form action=%url; %bebopAttr;>
|
||||
* .. XML for panel ..
|
||||
* .. XML for page state ..
|
||||
* </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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
* <table> 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 <table> 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>
|
||||
* <bebop:gridPanel>
|
||||
* <bebop:panelRow>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* ...
|
||||
* </bebop:panelRow>
|
||||
* <bebop:panelRow>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* ...
|
||||
* </bebop:panelRow>
|
||||
* </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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
* <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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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), <b>example</b>
|
||||
* will appear literally.</LI>
|
||||
* <LI>If output escaping is disabled, <b>example</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, <b>text</b> will appear
|
||||
* literally.</LI>
|
||||
* <LI>If output escaping is disabled, <b>text</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
|
||||
* <b>. 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>
|
||||
* <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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
* <bebop:list mode="single" %bebopAttr;>
|
||||
* <bebop:cell [selected="selected"] key="itemKey">
|
||||
* ... XML generated for component returned by renderer ...
|
||||
* </bebop:cell>
|
||||
* ... more <bebop:cell> elements, one for each list item ...
|
||||
* </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");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -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 <list>. 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ü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>
|
||||
* <bebop:listPanel>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* <bebop:cell> ... cell contents </bebop:cell>
|
||||
* ...
|
||||
* </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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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, " ". 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(" ", 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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(); }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
* <bebop:segmentedPanel>
|
||||
* <bebop:segment id="foo">
|
||||
* <bebop:segmentHeader>
|
||||
* <aRandomHeaderComponent/>
|
||||
* <anotherRandomHeaderComponent/>
|
||||
* ...
|
||||
* </bebop:segmentHeader>
|
||||
* <bebop:segmentBody>
|
||||
* <aRandomBodyComponent>
|
||||
* <anotherRandomBodyComponent>
|
||||
* ...
|
||||
* </bebop:segmentBody>
|
||||
* </bebop:segment>
|
||||
* ...
|
||||
* </bebop:segmentedPanel>
|
||||
* </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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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:
|
||||
* <xsl:template match="cms:foo">
|
||||
* <xsl:for-each select="*">
|
||||
* <p>
|
||||
* <xsl:apply-templates select="."/>
|
||||
* </p>
|
||||
* </xsl:for-each>
|
||||
* </xsl:template>
|
||||
* </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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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>
|
||||
* <bebop:tabbedPane>
|
||||
* <bebop:tabStrip>
|
||||
* <bebop:tab [href="..."] [current="t|f"]> .. label .. </bebop:tab>
|
||||
* <bebop:tab [href="..."] [current="t|f"]> .. label .. </bebop:tab>
|
||||
* <bebop:tab [href="..."] [current="t|f"]> .. label .. </bebop:tab>
|
||||
* </bebop:tabStrip>
|
||||
* <bebop:currentPane>
|
||||
* ... contentes ..
|
||||
* </bebop:currentPane>
|
||||
* </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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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><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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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><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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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(" " +
|
||||
" " +
|
||||
" " +
|
||||
" " +
|
||||
" " +
|
||||
" ",
|
||||
false));
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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><bebop:* name=... [onXXX=...]>
|
||||
* <bebop:option name=... [selected]> option value </bebop:option%gt;
|
||||
* ...
|
||||
* </bebop:*select></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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue