Last part of ThemeDirector code fix. Errors in validation of input fields is now displayed along the respective input field. Fixed uncought exception, unclosed result set, various missing globalization.
git-svn-id: https://svn.libreccm.org/ccm/trunk@2682 8810af33-2d31-482b-a856-94f89814c4dfmaster
parent
6c272debdd
commit
a7119bb541
|
|
@ -94,7 +94,7 @@ public class DecisionTreeTargetEditForm extends Form
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param selArticle the current article
|
||||
* @param selTree
|
||||
* @param selTarget the current section
|
||||
* @param container container which this form is added to
|
||||
*/
|
||||
|
|
@ -138,6 +138,7 @@ public class DecisionTreeTargetEditForm extends Form
|
|||
|
||||
/**
|
||||
* Returns the save/cancel section from this form.
|
||||
* @return
|
||||
*/
|
||||
public SaveCancelSection getSaveCancelSection() {
|
||||
return m_saveCancelSection;
|
||||
|
|
@ -213,7 +214,9 @@ public class DecisionTreeTargetEditForm extends Form
|
|||
}
|
||||
|
||||
/** Form initialisation hook. Sets the options for select widgets.
|
||||
* @param fse
|
||||
*/
|
||||
@Override
|
||||
public void init(FormSectionEvent fse) {
|
||||
PageState state = fse.getPageState();
|
||||
FormData data = fse.getFormData();
|
||||
|
|
@ -276,6 +279,7 @@ public class DecisionTreeTargetEditForm extends Form
|
|||
|
||||
try {
|
||||
m_targetSectionWidget.addPrintListener(new PrintListener() {
|
||||
@Override
|
||||
public void prepare(PrintEvent e) {
|
||||
initTargetOptions(e);
|
||||
}
|
||||
|
|
@ -287,6 +291,7 @@ public class DecisionTreeTargetEditForm extends Form
|
|||
add(m_targetSectionWidget);
|
||||
|
||||
addValidationListener(new FormValidationListener() {
|
||||
@Override
|
||||
public final void validate(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
final PageState state = event.getPageState();
|
||||
|
|
@ -312,7 +317,10 @@ public class DecisionTreeTargetEditForm extends Form
|
|||
/**
|
||||
* Called on form submission. Check to see if the user clicked the
|
||||
* cancel button. If they did, don't continue with the form.
|
||||
* @param event
|
||||
* @throws com.arsdigita.bebop.FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public void submitted(FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
PageState state = event.getPageState();
|
||||
|
|
@ -332,7 +340,10 @@ public class DecisionTreeTargetEditForm extends Form
|
|||
/**
|
||||
* Called after form has been validated. Create the new
|
||||
* DecisionTreeOptionTarget and assign it to the current DecisionTree.
|
||||
* @param event
|
||||
* @throws com.arsdigita.bebop.FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public void process(FormSectionEvent event) throws FormProcessException {
|
||||
PageState state = event.getPageState();
|
||||
FormData data = event.getFormData();
|
||||
|
|
|
|||
|
|
@ -238,32 +238,43 @@ public class Form extends FormSection implements BebopConstants {
|
|||
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);
|
||||
errors.addAttribute
|
||||
("message",
|
||||
errors.addAttribute("message",
|
||||
(String)((GlobalizedMessage) it.next()).localize
|
||||
(ps.getRequest()));
|
||||
(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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.</p>
|
||||
* 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);
|
||||
|
|
@ -273,10 +284,12 @@ public class Form extends FormSection implements BebopConstants {
|
|||
/**
|
||||
* 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
|
||||
* @see #process process(...)
|
||||
* @throws javax.servlet.ServletException
|
||||
*/
|
||||
@Override
|
||||
public void respond(PageState state) throws ServletException {
|
||||
final FormData data = process(state);
|
||||
|
||||
|
|
@ -420,15 +433,16 @@ public class Form extends FormSection implements BebopConstants {
|
|||
* 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>.
|
||||
* @see #getFormData
|
||||
* @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());
|
||||
|
|
@ -476,6 +490,7 @@ public class Form extends FormSection implements BebopConstants {
|
|||
*/
|
||||
protected void traverse() {
|
||||
Traversal formRegistrar = new Traversal() {
|
||||
@Override
|
||||
protected void act(Component c) {
|
||||
if ( c == Form.this ) {
|
||||
return;
|
||||
|
|
@ -497,6 +512,7 @@ public class Form extends FormSection implements BebopConstants {
|
|||
*
|
||||
* @param p page in which to register this form
|
||||
*/
|
||||
@Override
|
||||
public void register(Page p) {
|
||||
traverse();
|
||||
p.addComponent(this);
|
||||
|
|
@ -504,6 +520,7 @@ public class Form extends FormSection implements BebopConstants {
|
|||
|
||||
/**
|
||||
* TODO
|
||||
* @param model
|
||||
*/
|
||||
public void excludeParameterFromExport(ParameterModel model) {
|
||||
getModel().excludeFormParameterFromExport(model);
|
||||
|
|
@ -516,6 +533,7 @@ public class Form extends FormSection implements BebopConstants {
|
|||
*/
|
||||
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
|
||||
|
|
@ -524,7 +542,8 @@ public class Form extends FormSection implements BebopConstants {
|
|||
return process(s);
|
||||
} catch (FormProcessException e) {
|
||||
s_log.error("Form Process exception", e);
|
||||
throw new UncheckedWrapperException("Form Process error: " + e.getMessage(), e);
|
||||
throw new UncheckedWrapperException("Form Process error: "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -535,6 +554,7 @@ public class Form extends FormSection implements BebopConstants {
|
|||
*
|
||||
* @return a human-readable representation of <code>this</code>.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " " +
|
||||
"[" + getName() + "," + getAction() + "," + getMethod() + "," +
|
||||
|
|
@ -542,10 +562,13 @@ public class Form extends FormSection implements BebopConstants {
|
|||
}
|
||||
|
||||
/**
|
||||
* Protected access to set the formdata request local
|
||||
* 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
|
||||
*/
|
||||
// this method is required if a subclass wishes to override
|
||||
// the process method
|
||||
protected void setFormData(PageState state, FormData data) {
|
||||
m_formData.set(state, data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,9 +36,8 @@ import com.arsdigita.globalization.GlobalizedMessage;
|
|||
import com.arsdigita.util.URLRewriter;
|
||||
|
||||
/**
|
||||
* Manages the data associated with forms and
|
||||
* other remote sources.
|
||||
*
|
||||
* 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
|
||||
|
|
@ -81,8 +80,8 @@ public class FormData implements Map, Cloneable {
|
|||
private boolean m_isSubmission;
|
||||
|
||||
/**
|
||||
* Ensure that no one can create this object from outside the
|
||||
* package without supplying meaningful parameters
|
||||
* Ensure that no one can create this object from outside the package
|
||||
* without supplying meaningful parameters
|
||||
*/
|
||||
private FormData() {}
|
||||
|
||||
|
|
@ -277,9 +276,8 @@ public class FormData implements Map, Cloneable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Validates this <code>FormData</code> object according to its
|
||||
* form model. If the <code>FormData</code> is already valid,
|
||||
* does nothing.
|
||||
* 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
|
||||
|
|
@ -300,9 +298,8 @@ public class FormData implements Map, Cloneable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Validates this <code>FormData</code> object against its
|
||||
* form model, regardless of whether the object is currently
|
||||
* valid.
|
||||
* 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
|
||||
|
|
@ -325,6 +322,7 @@ public class FormData implements Map, Cloneable {
|
|||
|
||||
/**
|
||||
* Reports a validation error on the form as a whole.
|
||||
* Uses a GlobalizedMessage for inklusion
|
||||
*
|
||||
* @param message the error message
|
||||
* @pre message != null
|
||||
|
|
|
|||
|
|
@ -52,16 +52,17 @@ import javax.xml.parsers.ParserConfigurationException;
|
|||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The top-level container for all Bebop components and containers. </p>
|
||||
* The top-level container for all Bebop components and containers.
|
||||
*
|
||||
* <UL> <LI>Holds references to the components of a page.</LI> <LI>Provides methods for servicing
|
||||
* requests and for notifying other components that a request for this page has been received
|
||||
* through {@link ActionListener ActionListeners}.</LI>
|
||||
* <UL>
|
||||
* <LI>Holds references to the components of a page.</LI>
|
||||
* <LI>Provides methods for servicing requests and for notifying other
|
||||
* components that a request for this page has been received through
|
||||
* {@link ActionListener ActionListeners}.</LI>
|
||||
* <LI>Tracks request parameters for stateful components, such as tabbed panes
|
||||
* and sortable tables.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* <LI>Tracks request parameters for stateful components, such as tabbed panes and sortable
|
||||
* tables.</LI> </UL>
|
||||
* <p>
|
||||
* A typical <code>Page</code> may be created as follows: null <blockquote><pre><code>
|
||||
* Page p = new Page("Hello World");
|
||||
* p.add(new Label("Hello World");
|
||||
|
|
@ -114,9 +115,10 @@ public class Page extends BlockStylable implements Container {
|
|||
*/
|
||||
static final String INVISIBLE = INTERNAL + "i";
|
||||
/**
|
||||
* Map of stateful components (id --> Component) SortedMap used because component based hash for
|
||||
* page is based on concatenation of component ids, and so need to guarantee that they are
|
||||
* returned in the same order for the same page - cg.
|
||||
* Map of stateful components (id --> Component) SortedMap used because
|
||||
* component based hash for page is based on concatenation of component ids,
|
||||
* and so need to guarantee that they are returned in the same order for
|
||||
* the same page - cg.
|
||||
*/
|
||||
private SortedMap m_componentMap;
|
||||
private List m_components;
|
||||
|
|
@ -132,13 +134,14 @@ public class Page extends BlockStylable implements Container {
|
|||
private List m_actionListeners;
|
||||
private List m_requestListeners;
|
||||
/**
|
||||
* The title of the page to be added in the head of HTML output. The title is wrapped in a Label
|
||||
* to allow developers to add PrintListeners to dynamically change the value of the title.
|
||||
* The title of the page to be added in the head of HTML output. The title
|
||||
* is wrapped in a Label to allow developers to add PrintListeners to
|
||||
* dynamically change the value of the title.
|
||||
*/
|
||||
private Label m_title;
|
||||
/**
|
||||
* Stores the actual title for the current request. The title may be generated with a
|
||||
* PrintListener of the m_title Label.
|
||||
* Stores the actual title for the current request. The title may be
|
||||
* generated with a PrintListener of the m_title Label.
|
||||
*/
|
||||
private RequestLocal m_currentTitle;
|
||||
/**
|
||||
|
|
@ -172,54 +175,58 @@ public class Page extends BlockStylable implements Container {
|
|||
private boolean m_useHttpSession = false;
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this page should export state through the HttpSession instead of
|
||||
* the URL query string.
|
||||
* Returns <code>true</code> if this page should export state through the
|
||||
* HttpSession instead of the URL query string.
|
||||
* <P>
|
||||
* If this returns <code>true</code>, then PageState.stateAsURL() will only export the control
|
||||
* event as a URL query string. If this returns <code>false</code>, then stateAsURL() will
|
||||
* export the entire page state.
|
||||
*
|
||||
*
|
||||
* If this returns <code>true</code>, then PageState.stateAsURL() will only
|
||||
* export the control event as a URL query string. If this returns
|
||||
* <code>false</code>, then stateAsURL() will export the entire page state.
|
||||
* @see PageState#stateAsURL
|
||||
*
|
||||
* @return <code>true</code> if this page should export state through the HttpSession;
|
||||
* <code>false</code> if it should export using the URL query string.
|
||||
* @return <code>true</code> if this page should export state through the
|
||||
* HttpSession;
|
||||
* <code>false</code> if it should export using the URL query
|
||||
* string.
|
||||
*/
|
||||
public boolean isUsingHttpSession() {
|
||||
return m_useHttpSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates to this page whether it should export its entire state to subsequent requests
|
||||
* through the URL query string, or if it should use the HttpSession instead and only use the
|
||||
* URL query string for the control event.
|
||||
* Indicates to this page whether it should export its entire state to
|
||||
* subsequent requests through the URL query string, or if it should use the
|
||||
* HttpSession instead and only use the URL query string for the control
|
||||
* event.
|
||||
*
|
||||
* @see PageState#stateAsURL
|
||||
*
|
||||
* @param b <code>true</code> if PageState.stateAsURL() will export only the control event as a
|
||||
* URL query string. <code>false</code> if stateAsURL() will export the entire page
|
||||
* state.
|
||||
* @param b <code>true</code> if PageState.stateAsURL() will export only the
|
||||
* control event as a URL query string. <code>false</code> if stateAsURL()
|
||||
* will export the entire page state.
|
||||
*/
|
||||
public void setUsingHttpSession(boolean b) {
|
||||
m_useHttpSession = b;
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// Constructor Section
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Creates an empty page with the specified title and panel.
|
||||
* Constructor, creates an empty page with the specified title and panel.
|
||||
*
|
||||
* @param title title for this page
|
||||
*
|
||||
* @param panel container for this page
|
||||
* @deprecated use Page(Lab el, Container) instead.
|
||||
*/
|
||||
public Page(String title, Container panel) {
|
||||
this(new Label(title), panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty page with the specified title and panel.
|
||||
*
|
||||
* @param title title for this page
|
||||
* Constructor, creates an empty page with the specified title and panel.
|
||||
*
|
||||
* @param title title for this page as (globalized) Label
|
||||
* @param panel container for this page
|
||||
*/
|
||||
public Page(Label title, Container panel) {
|
||||
|
|
@ -231,7 +238,7 @@ public class Page extends BlockStylable implements Container {
|
|||
m_components = new ArrayList();
|
||||
m_componentMap = new TreeMap();
|
||||
setErrorDisplay(new PageErrorDisplay());
|
||||
setTitle(title);
|
||||
m_title = title;
|
||||
|
||||
// Initialize the RequestLocal where the title for the current
|
||||
// request will be kept
|
||||
|
|
@ -270,7 +277,8 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates an empty page with the specified title and implicit BoxPanel container.
|
||||
* Creates an empty page with the specified title and implicit BoxPanel
|
||||
* container.
|
||||
*
|
||||
* @param title title for this page
|
||||
*/
|
||||
|
|
@ -281,7 +289,8 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates an empty page with the specified title and implicit BoxPanel container.
|
||||
* Creates an empty page with the specified title and implicit BoxPanel
|
||||
* container.
|
||||
*
|
||||
* @param title title for this page
|
||||
*/
|
||||
|
|
@ -301,13 +310,13 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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, use
|
||||
* bitwise OR.
|
||||
* 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, use bitwise OR.
|
||||
*
|
||||
* @param c component to add to this container
|
||||
*
|
||||
* @param constraints layout constraints (a bitwise OR of static ints in the particular layout)
|
||||
* @param constraints layout constraints (a bitwise OR of static ints in the
|
||||
* particular layout)
|
||||
*/
|
||||
@Override
|
||||
public void add(Component c, int constraints) {
|
||||
|
|
@ -315,17 +324,20 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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)).
|
||||
* 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 component has been directly added to this
|
||||
* container. If this container contains another container that contains this component, this
|
||||
* method returns <code>false</code>.
|
||||
* 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;
|
||||
* @return <code>true</code> if this Container contains the specified
|
||||
* component directly;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -334,12 +346,12 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns 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 add), this method should be used in conjunction with indexOf.
|
||||
* Returns 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 add), 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.
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -351,14 +363,12 @@ public class Page extends BlockStylable implements Container {
|
|||
* Gets the index of a component.
|
||||
*
|
||||
* @param c 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.
|
||||
* @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 c != null
|
||||
* @post contains(c) implies (return >= 0) && (return < size())
|
||||
* @pos
|
||||
* t !contains(c) implies return == -1
|
||||
* @post !contains(c) implies return == -1
|
||||
*/
|
||||
@Override
|
||||
public int indexOf(Component c) {
|
||||
|
|
@ -368,8 +378,8 @@ public class Page extends BlockStylable implements Container {
|
|||
/**
|
||||
* Returns <code>true</code> if the container contains no components.
|
||||
*
|
||||
* @return <code>true</code> if this container contains no * * components; <code>false</code>
|
||||
* otherwise.
|
||||
* @return <code>true</code> if this container contains no components;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
|
|
@ -377,8 +387,9 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this container. This does not recursively count the
|
||||
* components that are indirectly contained in this container.
|
||||
* Returns the number of elements in this container. This does not
|
||||
* recursively count the components that are indirectly contained in this
|
||||
* container.
|
||||
*
|
||||
* @return the number of components directly in this container.
|
||||
*/
|
||||
|
|
@ -393,7 +404,8 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the panel that the <code>Page</code> uses for rendering its components.
|
||||
* Returns the panel that the <code>Page</code> uses for rendering its
|
||||
* components.
|
||||
*
|
||||
* @return the panel.
|
||||
*/
|
||||
|
|
@ -402,9 +414,11 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the Container used for rendering components on this page. Caution should be used with
|
||||
* this function, as the existing container is simply overwritten.
|
||||
* Set the Container used for rendering components on this page. Caution
|
||||
* should be used with this function, as the existing container is simply
|
||||
* overwritten.
|
||||
*
|
||||
* @param c
|
||||
* @author Matthew Booth (mbooth@redhat.com)
|
||||
*/
|
||||
public void setPanel(Container c) {
|
||||
|
|
@ -412,8 +426,7 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Retrieves the title of this page. </p>
|
||||
* Retrieves the title of this page.
|
||||
*
|
||||
* @return the static title of this page.
|
||||
*/
|
||||
|
|
@ -425,7 +438,6 @@ public class Page extends BlockStylable implements Container {
|
|||
* Retrieves the title of this page as a Bebop label component.
|
||||
*
|
||||
* @param state the state of the current request
|
||||
*
|
||||
* @return the title of the page for the current request.
|
||||
*/
|
||||
public final Label getTitle(PageState state) {
|
||||
|
|
@ -453,12 +465,13 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Component} that will display the validation errors in the current
|
||||
* {@link PageState}. Any validation error in the <code>PageState</code> will cause the
|
||||
* <code>Page</code> to completely ignore all other components and render only the error display
|
||||
* component.
|
||||
* Sets the {@link Component} that will display the validation errors in the
|
||||
* current {@link PageState}. Any validation error in the
|
||||
* <code>PageState</code> will cause the <code>Page</code> to completely
|
||||
* ignore all other components and render only the error display component.
|
||||
* <p>
|
||||
* By default, a {@link PageErrorDisplay} component is used to display the validation errors.
|
||||
* By default, a {@link PageErrorDisplay} component is used to display the
|
||||
* validation errors.
|
||||
*
|
||||
* @param c the component that will display the validation errors in the current
|
||||
* <code>PageState</code>
|
||||
|
|
@ -469,12 +482,13 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Component} that will display the validation errors in the current
|
||||
* {@link PageState}. Any validation error in the <code>PageState</code> will cause the
|
||||
* <code>Page</code> to completely ignore all other components and render only the error display
|
||||
* component.
|
||||
* Gets the {@link Component} that will display the validation errors in the
|
||||
* current {@link PageState}. Any validation error in the
|
||||
* <code>PageState</code> will cause the <code>Page</code> to completely
|
||||
* ignore all other components and render only the error display component.
|
||||
* <p>
|
||||
* By default, a {@link PageErrorDisplay} component is used to display the validation errors.
|
||||
* By default, a {@link PageErrorDisplay} component is used to display the
|
||||
* validation errors.
|
||||
*
|
||||
* @return the component that will display the validation errors in the current
|
||||
* <code>PageState</code>.
|
||||
|
|
@ -484,17 +498,19 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds a client-side stylesheet that should be used in HTML output. Arbitrarily many
|
||||
* client-side stylesheets can be added with this method. To use a CSS stylesheet, call
|
||||
* something like <code>setStyleSheet("style.css", "text/css")</code>.
|
||||
* Adds a client-side stylesheet that should be used in HTML output.
|
||||
* Arbitrarily many client-side stylesheets can be added with this method.
|
||||
* To use a CSS stylesheet, call something like
|
||||
* <code>setStyleSheet("style.css", "text/css")</code>.
|
||||
*
|
||||
* <p>
|
||||
* These values will ultimately wind up in a <tt><link></tt>
|
||||
* tag in the head of the HTML page.
|
||||
*
|
||||
* <p>
|
||||
* Note that the stylesheet set with this call has nothing to do with the XSLT stylesheet
|
||||
* (transformer) that is applied to the XML generated from this page!
|
||||
* Note that the stylesheet set with this call has nothing to do with the
|
||||
* XSLT stylesheet (transformer) that is applied to the XML generated from
|
||||
* this page!
|
||||
*
|
||||
* @param styleSheetURI the location of the stylesheet
|
||||
* @param mimeType the MIME type of the stylesheet, usually
|
||||
|
|
@ -507,19 +523,17 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds a global state parameter to this page. Global parameters are values that need to be
|
||||
* preserved between requests, but that have no special connection to any of the components on
|
||||
* the page. For a page that displays details about an item, a global parameter would be used to
|
||||
* identify the item.
|
||||
*
|
||||
* <p>
|
||||
* If the parameter was previously added as a component state parameter, its name is unmangled
|
||||
* and stays unmangled.
|
||||
*
|
||||
* @param p the global parameter to add
|
||||
* Adds a global state parameter to this page. Global parameters are values
|
||||
* that need to be preserved between requests, but that have no special
|
||||
* connection to any of the components on the page. For a page that displays
|
||||
* details about an item, a global parameter would be used to identify the
|
||||
* item.
|
||||
*
|
||||
* If the parameter was previously added as a component state parameter, its
|
||||
* name is unmangled and stays unmangled.
|
||||
* @see #addComponentStateParam
|
||||
*
|
||||
* @param p the global parameter to add
|
||||
* @pre ! isLocked()
|
||||
* @pre parameter != null
|
||||
*/
|
||||
|
|
@ -530,8 +544,8 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs the top nodes of the DOM or JDOM tree. Used by generateXML(PageState, Document)
|
||||
* below.
|
||||
* Constructs the top nodes of the DOM or JDOM tree. Used by
|
||||
* generateXML(PageState, Document) below.
|
||||
* <p>
|
||||
* Generates DOM fragment:
|
||||
* <pre>
|
||||
|
|
@ -541,12 +555,13 @@ public class Page extends BlockStylable implements Container {
|
|||
* ... page content gnerated by children ...
|
||||
* </bebop:page></pre> The content of the <tt><title></tt>
|
||||
* element can be set by calling {@link #setTitle setTitle}. The
|
||||
* <tt><stylesheet></tt> element will only be present if a stylesheet has been set with {@link
|
||||
* <tt><stylesheet></tt> element will only be present if a stylesheet
|
||||
* has been set with {@link
|
||||
* #setStyleSheet setStyleSheet}.
|
||||
*
|
||||
* @param ps the page state for the current page
|
||||
* @param parent the DOM node for the whole Document
|
||||
*
|
||||
* @return
|
||||
* @pre isLocked()
|
||||
*/
|
||||
protected Element generateXMLHelper(PageState ps, Document parent) {
|
||||
|
|
@ -569,8 +584,9 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs a DOM or JDOM tree with all components on the page. The tree represents the page
|
||||
* that results from the {@link javax.servlet.http.HttpServletRequest} kept in the
|
||||
* Constructs a DOM or JDOM tree with all components on the page. The tree
|
||||
* represents the page that results from the
|
||||
* {@link javax.servlet.http.HttpServletRequest} kept in the
|
||||
* <code>state</code>.
|
||||
*
|
||||
* @param state the page state produced by {@link #process}
|
||||
|
|
@ -611,19 +627,25 @@ public class Page extends BlockStylable implements Container {
|
|||
|
||||
/**
|
||||
* Do nothing. Top-level add nodes is meaningless.
|
||||
*
|
||||
* @param elt
|
||||
*/
|
||||
@Override
|
||||
public void generateXML(PageState state, Element elt) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PageState object and processes it by calling the respond method on the selected
|
||||
* component. Processes a request by notifying the component from which the process originated
|
||||
* and {@link #fireActionEvent
|
||||
* broadcasts} an {@link ActionEvent} to all the listeners that registered with
|
||||
* {@link #addActionListener addActionListener}.
|
||||
*
|
||||
* Creates a PageState object and processes it by calling the respond method
|
||||
* on the selected component. Processes a request by notifying the component
|
||||
* from which the process originated and {@link #fireActionEvent
|
||||
* broadcasts} an {@link ActionEvent} to all the listeners that registered
|
||||
* with {@link #addActionListener addActionListener}.
|
||||
* @see #generateXML(PageState,Document) generateXML
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
* @throws javax.servlet.ServletException
|
||||
* @pre isLocked()
|
||||
* @pre request != null
|
||||
* @pre response != null
|
||||
|
|
@ -675,26 +697,14 @@ public class Page extends BlockStylable implements Container {
|
|||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Does all the servicing of a request except output generation.
|
||||
// * This includes most of the common duties of buildDocument and print.
|
||||
// *
|
||||
// * @deprecated Use {@link
|
||||
// * #process(HttpServletRequest,HttpServletResponse)} instead.
|
||||
// */
|
||||
// protected PageState prepare(HttpServletRequest req, HttpServletResponse res)
|
||||
// throws ServletException {
|
||||
// Assert.isLocked(this);
|
||||
// PageState state = process(req, res);
|
||||
// return state;
|
||||
// }
|
||||
/**
|
||||
* Builds a DOM Document from the current request state by doing a depth-first tree walk on the
|
||||
* current set of components in this Page, calling generateXML on each. Does NOT do the
|
||||
* rendering. If the HTTP response has already been committed, does not build the XML document.
|
||||
*
|
||||
* @return a DOM ready for rendering, or null if the response has already been committed.
|
||||
* Builds a DOM Document from the current request state by doing a
|
||||
* depth-first tree walk on the current set of components in this Page,
|
||||
* calling generateXML on each. Does NOT do the rendering. If the HTTP
|
||||
* response has already been committed, does not build the XML document.
|
||||
*
|
||||
* @return a DOM ready for rendering, or null if the response has already
|
||||
* been committed.
|
||||
* @post res.isCommitted() == (return == null)
|
||||
*/
|
||||
public Document buildDocument(HttpServletRequest req,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ public class FormSectionEvent extends PageEvent {
|
|||
* @param state the state of the enclosing page
|
||||
* @param formData the form data constructed so far
|
||||
*/
|
||||
public FormSectionEvent(Object source, PageState state,
|
||||
public FormSectionEvent(Object source,
|
||||
PageState state,
|
||||
FormData formData) {
|
||||
super(source, state);
|
||||
_formData = formData;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import java.util.EventListener;
|
|||
* @author Uday Mathur
|
||||
* @version $Id: FormValidationListener.java 287 2005-02-22 00:29:02Z sskracic $
|
||||
*/
|
||||
|
||||
public interface FormValidationListener extends EventListener {
|
||||
|
||||
/**
|
||||
|
|
@ -49,23 +48,14 @@ public interface FormValidationListener extends EventListener {
|
|||
* be handled internally, or if they are unrecoverable may be
|
||||
* rethrown as instances of <code>FormProcessException</code>.
|
||||
*
|
||||
* @param model The form model describing the structure and properties
|
||||
* of the form data included with this request. The validation procedure
|
||||
* may require knowledge of form or parameter properties to complete.
|
||||
* @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.
|
||||
*
|
||||
* @param data The container for all data objects associated with
|
||||
* the request. All parameters specified in the form model are
|
||||
* converted to data objects and stored in this container before
|
||||
* any form validation procedures are called.
|
||||
*
|
||||
* @param request The HTTP request information from which the form
|
||||
* data was extracted. Note that the request object is supplied
|
||||
* only in case the validation procedure involves contextual
|
||||
* information (information extracted from cookies or the peer
|
||||
* address, for example).
|
||||
*
|
||||
* @exception FormProcessException If the data does not pass the
|
||||
* check. */
|
||||
* @exception FormProcessException ff the data does not pass the check.
|
||||
*/
|
||||
|
||||
void validate(FormSectionEvent e) throws FormProcessException;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ import com.arsdigita.bebop.FormProcessException;
|
|||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* Defines the interface
|
||||
* for a class that validates the values of a single parameter.
|
||||
* Defines the interface for a class that validates the values of a
|
||||
* single parameter.
|
||||
*
|
||||
* @author Karl Goldstein
|
||||
* @author Uday Mathur
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
package com.arsdigita.bebop.form;
|
||||
|
||||
|
||||
import com.arsdigita.bebop.event.PageEvent;
|
||||
import com.arsdigita.bebop.event.PrintEvent;
|
||||
import com.arsdigita.bebop.event.PrintListener;
|
||||
|
|
@ -41,12 +40,12 @@ import java.util.TooManyListenersException;
|
|||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Search and select Bebop widget. This widget is used to allow a user to
|
||||
* search for a particular item over a potentially very large set. Depending
|
||||
* on the size of the dataset, the user will either see a search box or a
|
||||
* selection box (with all valid items). The search box will then change to
|
||||
* a selection box once the user submits the form, allowing them then to
|
||||
* choose the items they desire.
|
||||
* Search and select Bebop widget. This widget is used to allow a user to search
|
||||
* for a particular item over a potentially very large set. Depending on the
|
||||
* size of the dataset, the user will either see a search box or a selection box
|
||||
* (with all valid items). The search box will then change to a selection box
|
||||
* once the user submits the form, allowing them then to choose the items they
|
||||
* desire.
|
||||
* <p>
|
||||
* The datasource for SearchAndSelect is provided by an implentation of the
|
||||
* SearchAndSelectModel interface. SAMPLE IMPLEMENTATION GOES HERE
|
||||
|
|
@ -58,8 +57,8 @@ import org.apache.log4j.Logger;
|
|||
public class SearchAndSelect extends FormSection
|
||||
implements BebopConstants, PrintListener {
|
||||
|
||||
private static final Logger s_cat =
|
||||
Logger.getLogger(SearchAndSelect.class);
|
||||
private static final Logger s_cat
|
||||
= Logger.getLogger(SearchAndSelect.class);
|
||||
|
||||
protected String m_name;
|
||||
// name of this super-widget
|
||||
|
|
@ -120,8 +119,8 @@ public class SearchAndSelect extends FormSection
|
|||
if (m_useCheckboxes) {
|
||||
m_outputSelectWidget = new CheckboxGroup(getName() + ".select");
|
||||
} else {
|
||||
m_outputSelectWidget =
|
||||
new MultipleSelect(getName() + ".select");
|
||||
m_outputSelectWidget
|
||||
= new MultipleSelect(getName() + ".select");
|
||||
}
|
||||
} else {
|
||||
m_outputSelectWidget = new SingleSelect(getName() + ".select");
|
||||
|
|
@ -148,11 +147,11 @@ public class SearchAndSelect extends FormSection
|
|||
|
||||
m_results.setQuery(m_query);
|
||||
|
||||
if ( m_isSearchLocked ||
|
||||
( ( ( ! m_oldValue.equals("") &&
|
||||
m_oldValue.equals(m_value) ) ||
|
||||
( m_maxViewableResults >= m_results.resultsCount() ) ) &&
|
||||
( m_results.resultsCount() > 0 ) ) ) {
|
||||
if (m_isSearchLocked
|
||||
|| (((!m_oldValue.equals("")
|
||||
&& m_oldValue.equals(m_value))
|
||||
|| (m_maxViewableResults >= m_results.resultsCount()))
|
||||
&& (m_results.resultsCount() > 0))) {
|
||||
|
||||
OptionGroup outputWidget = (OptionGroup) e.getTarget();
|
||||
|
||||
|
|
@ -219,6 +218,7 @@ public class SearchAndSelect extends FormSection
|
|||
* user as the error field is also used as a help field.
|
||||
*/
|
||||
super.addValidationListener(new FormValidationListener() {
|
||||
@Override
|
||||
public void validate(FormSectionEvent e) {
|
||||
FormData data = e.getFormData();
|
||||
|
||||
|
|
@ -271,9 +271,9 @@ public class SearchAndSelect extends FormSection
|
|||
* If search returns only one hit and is a non-optional single
|
||||
* select, it's done.
|
||||
*/
|
||||
if ( ! m_isOptional &&
|
||||
! m_isMultiple &&
|
||||
( m_results.resultsCount() == 1 ) ) {
|
||||
if (!m_isOptional
|
||||
&& !m_isMultiple
|
||||
&& (m_results.resultsCount() == 1)) {
|
||||
m_isSearchLocked = true;
|
||||
m_value = m_results.getID(0);
|
||||
}
|
||||
|
|
@ -284,14 +284,14 @@ public class SearchAndSelect extends FormSection
|
|||
*/
|
||||
if (m_isSearchLocked) {
|
||||
if (!m_isMultiple) {
|
||||
StringParameter param =
|
||||
new StringParameter( getName() );
|
||||
StringParameter param
|
||||
= new StringParameter(getName());
|
||||
|
||||
data.setParameter(getName(),
|
||||
new ParameterData(param, m_value));
|
||||
} else {
|
||||
ArrayParameter param =
|
||||
new ArrayParameter( getName() );
|
||||
ArrayParameter param
|
||||
= new ArrayParameter(getName());
|
||||
String[] tmpArray = (String[]) data
|
||||
.get(getName() + ".select");
|
||||
|
||||
|
|
@ -313,8 +313,7 @@ public class SearchAndSelect extends FormSection
|
|||
});
|
||||
}
|
||||
|
||||
public final void setSearchAndSelectListener
|
||||
(SearchAndSelectListener listener) {
|
||||
public final void setSearchAndSelectListener(SearchAndSelectListener listener) {
|
||||
m_listener = listener;
|
||||
}
|
||||
|
||||
|
|
@ -347,9 +346,9 @@ public class SearchAndSelect extends FormSection
|
|||
}
|
||||
|
||||
/**
|
||||
* Determine the type of HTML form element to create.
|
||||
* This will not necessarily be accurate until generateWidget is called
|
||||
* as the query will be unavailable until that point.
|
||||
* Determine the type of HTML form element to create. This will not
|
||||
* necessarily be accurate until generateWidget is called as the query will
|
||||
* be unavailable until that point.
|
||||
*
|
||||
* @return "text" or "select" depending on the result size
|
||||
*/
|
||||
|
|
@ -391,9 +390,9 @@ public class SearchAndSelect extends FormSection
|
|||
}
|
||||
|
||||
/**
|
||||
* Indicates if the widget is composed of multiple HTML elements.
|
||||
* Always returns true, as the widget makes use of a hidden element and
|
||||
* another element.
|
||||
* Indicates if the widget is composed of multiple HTML elements. Always
|
||||
* returns true, as the widget makes use of a hidden element and another
|
||||
* element.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
|
|
@ -402,8 +401,8 @@ public class SearchAndSelect extends FormSection
|
|||
}
|
||||
|
||||
/**
|
||||
* Generates the XML datastructure for this widget. Adds a hidden,
|
||||
* a textbox, checkbox group, or select, and possibly some number of
|
||||
* Generates the XML datastructure for this widget. Adds a hidden, a
|
||||
* textbox, checkbox group, or select, and possibly some number of
|
||||
* formErrors.
|
||||
*
|
||||
* @param state the state of the page
|
||||
|
|
@ -418,11 +417,11 @@ public class SearchAndSelect extends FormSection
|
|||
return;
|
||||
}
|
||||
|
||||
if ( m_isSearchLocked ||
|
||||
( ( ( ! m_oldValue.equals("") &&
|
||||
m_oldValue.equals(m_value) ) ||
|
||||
( m_maxViewableResults >= m_results.resultsCount() ) ) &&
|
||||
( m_results.resultsCount() > 0 ) ) ) {
|
||||
if (m_isSearchLocked
|
||||
|| (((!m_oldValue.equals("")
|
||||
&& m_oldValue.equals(m_value))
|
||||
|| (m_maxViewableResults >= m_results.resultsCount()))
|
||||
&& (m_results.resultsCount() > 0))) {
|
||||
m_outputSelectWidget.generateXML(state, parent);
|
||||
} else {
|
||||
m_outputTextWidget.generateXML(state, parent);
|
||||
|
|
@ -437,9 +436,9 @@ public class SearchAndSelect extends FormSection
|
|||
|
||||
/**
|
||||
* Generate the error messages for this widget. This widget has some
|
||||
* specialized error messages, so it is necessary to override the
|
||||
* default error generator. Basically, the m_results field won't be
|
||||
* available outside this class, so this needs to be internal.
|
||||
* specialized error messages, so it is necessary to override the default
|
||||
* error generator. Basically, the m_results field won't be available
|
||||
* outside this class, so this needs to be internal.
|
||||
*
|
||||
* @param state the state of the page
|
||||
* @param parent the parent widget
|
||||
|
|
@ -458,13 +457,13 @@ public class SearchAndSelect extends FormSection
|
|||
if ((curValue == null) || (curValue.equals(""))) {
|
||||
error.addAttribute("message",
|
||||
"Please enter a comma-delimited search");
|
||||
} else if ( ( ! m_oldValue.equals( curValue ) ) &&
|
||||
! m_isSearchLocked ) {
|
||||
} else if ((!m_oldValue.equals(curValue))
|
||||
&& !m_isSearchLocked) {
|
||||
error.addAttribute("message",
|
||||
"Your search returned " +
|
||||
m_results.resultsCount() +" matches. " +
|
||||
"Please refine your search or leave the " +
|
||||
"search as it is to see all results.");
|
||||
"Your search returned "
|
||||
+ m_results.resultsCount() + " matches. "
|
||||
+ "Please refine your search or leave the "
|
||||
+ "search as it is to see all results.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -472,8 +471,8 @@ public class SearchAndSelect extends FormSection
|
|||
if (!curValue.equals("")) {
|
||||
Element error = parent.newChildElement("bebop:formErrors", BEBOP_XML_NS);
|
||||
error.addAttribute("message",
|
||||
"Your search returned no matches. Please " +
|
||||
"try again");
|
||||
"Your search returned no matches. Please "
|
||||
+ "try again");
|
||||
} else {
|
||||
Element error = parent.newChildElement("bebop:formErrors", BEBOP_XML_NS);
|
||||
error.addAttribute("message", "WARNING -- NO DATA FOUND");
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ import com.arsdigita.bebop.parameters.ParameterModel;
|
|||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.util.BebopConstants;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.kernel.Kernel;
|
||||
// import com.arsdigita.kernel.Kernel;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ public abstract class GlobalizedParameterListener
|
|||
return BUNDLE_NAME;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the error message for this parameter.
|
||||
*
|
||||
|
|
@ -56,6 +55,7 @@ public abstract class GlobalizedParameterListener
|
|||
protected void setError(GlobalizedMessage error) {
|
||||
m_error = error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error message for this parameter.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -37,26 +37,48 @@ import com.arsdigita.globalization.GlobalizedMessage;
|
|||
*/
|
||||
public class NotEmptyValidationListener extends GlobalizedParameterListener {
|
||||
|
||||
/**
|
||||
* Default Constructor setting a predefined label as error message.
|
||||
*/
|
||||
public NotEmptyValidationListener() {
|
||||
setError(new GlobalizedMessage("bebop.parameters.parameter_not_empty",
|
||||
getBundleBaseName() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor taking a label specified as key into a resource bundle to
|
||||
* customize the error message.
|
||||
*
|
||||
* @param label key into the resource bundle
|
||||
*/
|
||||
public NotEmptyValidationListener(String label) {
|
||||
setError(new GlobalizedMessage(label, getBundleBaseName()));
|
||||
}
|
||||
|
||||
public NotEmptyValidationListener() {
|
||||
setError(new GlobalizedMessage(
|
||||
"parameter_is_required", getBundleBaseName()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor taking a GlobalizedMessage as error message to display.
|
||||
*
|
||||
* @param error GloblizedMessage taken as customized error message.
|
||||
*/
|
||||
public NotEmptyValidationListener(GlobalizedMessage error) {
|
||||
setError(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Method required and used to validate input.
|
||||
*
|
||||
* @param e ParameterEvent containing the data
|
||||
*/
|
||||
@Override
|
||||
public void validate (ParameterEvent e) {
|
||||
|
||||
ParameterData data = e.getParameterData();
|
||||
Object value = data.getValue();
|
||||
|
||||
if (value != null) {
|
||||
// all these are possible:
|
||||
// all these are possible values:
|
||||
// " "
|
||||
// " "
|
||||
// " "
|
||||
|
|
@ -68,13 +90,12 @@ public class NotEmptyValidationListener extends GlobalizedParameterListener {
|
|||
valueString = StringUtils.strip(valueString, Character.toString('\u00A0'));
|
||||
valueString = StringUtils.strip(valueString, Character.toString('\u2007'));
|
||||
if (valueString.length() > 0) {
|
||||
// non-empty value, just return
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Empty or null value, add error message to parameter data object.
|
||||
data.addError(getError());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.bebop.parameters;
|
||||
// package com.arsdigita.bebop.parameters;
|
||||
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
// import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
/**
|
||||
* @ deprecated Use {@link NotEmptyValidationListener}.
|
||||
*/
|
||||
|
||||
/*
|
||||
public class NotWhiteSpaceValidationListener extends NotEmptyValidationListener {
|
||||
|
||||
public NotWhiteSpaceValidationListener(String title) {
|
||||
|
|
@ -32,10 +32,11 @@ public class NotWhiteSpaceValidationListener extends NotEmptyValidationListener
|
|||
|
||||
public NotWhiteSpaceValidationListener() {
|
||||
setError(new GlobalizedMessage
|
||||
("parameter_is_required", getBundleBaseName()));
|
||||
("bebop.parameters.parameter_is_required", getBundleBaseName()));
|
||||
}
|
||||
|
||||
public NotWhiteSpaceValidationListener(GlobalizedMessage error) {
|
||||
setError(error);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
@ -6,3 +6,4 @@ parameter.only.letters.digits=This parameter can only contain letters and/or dig
|
|||
file_empty_or_not_found=is empty or was not found.
|
||||
file_too_large=is too large
|
||||
uri_parameter_is_invalid=This parameter must be a URI formatted according to RFC2396
|
||||
bebop.parameters.parameter_not_empty=This field must not be empty.
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@ parameter.only.letters.digits=Dieser Parameter darf nur Buchstaben und/oder Zahl
|
|||
file_empty_or_not_found=ist leer oder wurde nicht gefunden.
|
||||
file_too_large=ist zu gro\u00df
|
||||
uri_parameter_is_invalid=Dieser Parameter muss ein URI sein, das entsprechend RFC2396 formatiert wird
|
||||
bebop.parameters.parameter_not_empty=Dieser Eintrag darf nicht leer sein!
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@ parameter.only.letters.digits=This parameter can only contain letters and/or dig
|
|||
file_empty_or_not_found=is empty or was not found.
|
||||
file_too_large=is too large
|
||||
uri_parameter_is_invalid=This parameter must be a URI formatted according to RFC2396
|
||||
bebop.parameters.parameter_not_empty=This field must not be empty.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
bebop.parameters.parameter_is_required=Este par\u00e1metro es requerido
|
||||
string_in_range=Este par\u00e1metro no tiene entre {0} y {1} caracteres
|
||||
type_check={0} tiene que ser de clase {1} pero el objecto {2} es de clase {3}
|
||||
bebop.parameters.parameter_not_empty=This field must not be empty.
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ bebop.parameters.parameter_is_required=Ce param\u00e8tre est obligatoire
|
|||
string_in_range=La longueur de ce param\u00e8tre n'est pas comprise entre {0} et {1}
|
||||
type_check={0} doit \u00eatre de type {1} mais poss\u00e8de {2} de type {3}
|
||||
parameter.only.letters.digits=Ce param\u00e8tre ne doit contenir que des lettres ou des chiffres
|
||||
bebop.parameters.parameter_not_empty=This field must not be empty.
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ public class GlobalizedMessage {
|
|||
* @param args An Object[] of arguments to interpolate into the retrieved
|
||||
* message.
|
||||
*/
|
||||
public GlobalizedMessage(final String key, final String bundleName, final Object[] args) {
|
||||
public GlobalizedMessage(final String key,
|
||||
final String bundleName,
|
||||
final Object[] args) {
|
||||
this(key, bundleName);
|
||||
setArgs(args);
|
||||
}
|
||||
|
|
@ -176,7 +178,8 @@ public class GlobalizedMessage {
|
|||
* GlobalizedObject?
|
||||
*/
|
||||
public Object localize() {
|
||||
return localize(com.arsdigita.globalization.GlobalizationHelper.getNegotiatedLocale());
|
||||
return localize(com.arsdigita.globalization.GlobalizationHelper
|
||||
.getNegotiatedLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -201,7 +204,8 @@ public class GlobalizedMessage {
|
|||
* GlobalizedObject?
|
||||
*/
|
||||
public Object localize(final HttpServletRequest request) {
|
||||
return localize(com.arsdigita.globalization.GlobalizationHelper.getNegotiatedLocale());
|
||||
return localize(com.arsdigita.globalization.GlobalizationHelper
|
||||
.getNegotiatedLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -293,7 +297,7 @@ public class GlobalizedMessage {
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>For debugging, not for localizing!</p>
|
||||
* For debugging, not for localizing.
|
||||
*
|
||||
* If you need a String, use an additional localize() to get an object
|
||||
* and cast it to String. e.g.
|
||||
|
|
|
|||
|
|
@ -65,9 +65,9 @@ class UserForm extends Form implements FormValidationListener, AdminConstants {
|
|||
protected TextField m_url;
|
||||
protected TextField m_screenName;
|
||||
protected EmailList m_emailList;
|
||||
private PasswordValidationListener m_pwListener;
|
||||
private NotEmptyValidationListener m_notNullListener;
|
||||
private SecurityConfig securityConfig = SecurityConfig.getConfig();
|
||||
private final PasswordValidationListener m_pwListener;
|
||||
private final NotEmptyValidationListener m_notNullListener;
|
||||
private final SecurityConfig securityConfig = SecurityConfig.getConfig();
|
||||
|
||||
public UserForm(String formName) {
|
||||
super(formName);
|
||||
|
|
@ -184,6 +184,7 @@ class UserForm extends Form implements FormValidationListener, AdminConstants {
|
|||
* password-confirm field. Also verifies that primary email
|
||||
* address and screen name are unique amoung all users.
|
||||
*/
|
||||
@Override
|
||||
public void validate(FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
PageState ps = event.getPageState();
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ public class Web {
|
|||
/**
|
||||
* Processes an URL String trying to identify a corresponding recource
|
||||
* which is mapped to the given path String. The method ensures that the
|
||||
* resource defiunitely exists (using the URL returned) or definitely not
|
||||
* resource definitely exists (using the URL returned) or definitely not
|
||||
* (returning null).
|
||||
*
|
||||
* The resourcePath may be stored at various sources (file system, jar file,
|
||||
|
|
|
|||
|
|
@ -18,12 +18,10 @@
|
|||
*/
|
||||
package com.arsdigita.simplesurvey.ui.admin;
|
||||
|
||||
|
||||
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormInitListener;
|
||||
import com.arsdigita.bebop.parameters.NotWhiteSpaceValidationListener;
|
||||
import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
|
|
@ -47,7 +45,6 @@ import com.arsdigita.simplesurvey.util.GlobalizationUtil ;
|
|||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
|
|
@ -57,7 +54,6 @@ public class PropertiesForm extends Form {
|
|||
private SurveySelectionModel m_survey;
|
||||
private Class m_type;
|
||||
|
||||
|
||||
private TextField m_surveyName;
|
||||
private TextArea m_description;
|
||||
private Date m_startDate;
|
||||
|
|
@ -65,6 +61,12 @@ public class PropertiesForm extends Form {
|
|||
private RadioGroup m_responsesPublic;
|
||||
private RadioGroup m_quizType;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param survey
|
||||
* @param type
|
||||
*/
|
||||
public PropertiesForm(SurveySelectionModel survey,
|
||||
Class type) {
|
||||
|
||||
|
|
@ -74,10 +76,9 @@ public class PropertiesForm extends Form {
|
|||
m_type = type;
|
||||
|
||||
m_surveyName = new TextField("surveyName");
|
||||
m_surveyName.addValidationListener(new NotWhiteSpaceValidationListener());
|
||||
m_surveyName.addValidationListener(new NotEmptyValidationListener());
|
||||
m_description = new TextArea("description");
|
||||
|
||||
|
||||
m_startDate = new Date("startDate");
|
||||
m_endDate = new Date("endDate");
|
||||
|
||||
|
|
@ -95,8 +96,6 @@ public class PropertiesForm extends Form {
|
|||
add(new Label(GlobalizationUtil.globalize("simplesurvey.ui.admin.end_date")));
|
||||
add(m_endDate);
|
||||
|
||||
|
||||
|
||||
add(new Label(GlobalizationUtil.globalize("simplesurvey.ui.admin.should_quiz_responses_be_public")));
|
||||
m_responsesPublic = new RadioGroup("responsesPublic");
|
||||
Option o1 = new Option("true", new Label(GlobalizationUtil.globalize("simplesurvey.ui.admin.Yes")));
|
||||
|
|
@ -120,8 +119,6 @@ public class PropertiesForm extends Form {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
@ -170,8 +167,6 @@ public class PropertiesForm extends Form {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
@ -197,7 +192,6 @@ public class PropertiesForm extends Form {
|
|||
|
||||
// PackageInstance is old style application, no longer used.
|
||||
// survey.setPackageInstance(SimpleSurveyUtil.getPackageInstance(state));
|
||||
|
||||
form = new PersistentForm();
|
||||
survey.setForm(form);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ public class ThemeDirectorConfig extends AbstractConfig {
|
|||
"defaultThemeURLAttribute";
|
||||
|
||||
/**
|
||||
* Purpose uncodumented.
|
||||
* Purpose undocumented.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -38,3 +38,5 @@ theme.url_hint=Enter the LAST part of the url for the theme, eg 'holiday'. Shoul
|
|||
theme.save_button_hint=Save the details in the form
|
||||
theme.cancel_button_hint=Abort changes & reset the form.
|
||||
theme.cancel_button_pressed_msg=cancel pressed
|
||||
theme.form.url_can_contain_only_characters=The URL can only contain A-Z, a-z, 0-9, _, and -.
|
||||
theme.form.url_already_exists=A theme with this url already exists.
|
||||
|
|
|
|||
|
|
@ -38,3 +38,5 @@ theme.url_hint=Geben Sie den LETZTEN Teil der URL ein, z.B. 'ferien'. Der Eintra
|
|||
theme.save_button_hint=Speichern der Angaben in dem Formular.
|
||||
theme.cancel_button_hint=Verwerfen der Eintragungen und R\u00fccksetzen des Formulars.
|
||||
theme.cancel_button_pressed_msg=Vorgang abgebrochen
|
||||
theme.form.url_can_contain_only_characters=Die URL darf nur die Zeichen A-Z, a-z, 0-9, _ und - enthalten.
|
||||
theme.form.url_already_exists=Ein Theme mit dieser URL existiert bereits.
|
||||
|
|
|
|||
|
|
@ -38,3 +38,5 @@ theme.url_hint=Enter the LAST part of tht url for the theme, eg 'holiday'. Shou
|
|||
theme.save_button_hint=Save the details in the form
|
||||
theme.cancel_button_hint=Abort changes & reset the form.
|
||||
theme.cancel_button_pressed_msg=cancel pressed
|
||||
theme.form.url_can_contain_only_characters=The URL can only contain A-Z, a-z, 0-9, _, and -.
|
||||
theme.form.url_already_exists=A theme with this url already exists.
|
||||
|
|
|
|||
|
|
@ -38,3 +38,5 @@ theme.url_hint=Enter the LAST part of tht url for the theme, eg 'holiday'. Shou
|
|||
theme.save_button_hint=Save the details in the form
|
||||
theme.cancel_button_hint=Abort changes & reset the form.
|
||||
theme.cancel_button_pressed_msg=cancel pressed
|
||||
theme.form.url_can_contain_only_characters=The URL can only contain A-Z, a-z, 0-9, _, and -.
|
||||
theme.form.url_already_exists=A theme with this url already exists.
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ public class InternalThemePrefixerServlet extends InternalPrefixerServlet {
|
|||
}
|
||||
}
|
||||
|
||||
String prefix = pathInfo;
|
||||
String prefix;
|
||||
if (path != null) {
|
||||
String themeName = pathInfo.substring(0, pathInfo.indexOf(path));
|
||||
prefix = m_prefix + themeName;
|
||||
|
|
|
|||
|
|
@ -49,9 +49,13 @@ import org.apache.log4j.Logger;
|
|||
*
|
||||
* @author Randy Graebner <randyg@redhat.com>
|
||||
*/
|
||||
public class ThemeContainer extends SimpleContainer implements ThemeDirectorConstants {
|
||||
public class ThemeContainer extends SimpleContainer
|
||||
implements ThemeDirectorConstants {
|
||||
|
||||
/** A logger instance. */
|
||||
/** Internal logger instance to faciliate debugging. Enable logging output
|
||||
* by editing /WEB-INF/conf/log4j.properties int the runtime environment
|
||||
* and set com.arsdigita.themedirector.ui.ThemeContainer=DEBUG
|
||||
* by uncommenting or adding the line. */
|
||||
private static final Logger s_log =
|
||||
Logger.getLogger(ThemeContainer.class);
|
||||
|
||||
|
|
@ -62,6 +66,7 @@ public class ThemeContainer extends SimpleContainer implements ThemeDirectorCons
|
|||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param model
|
||||
* @param parent
|
||||
*/
|
||||
|
|
@ -228,6 +233,11 @@ public class ThemeContainer extends SimpleContainer implements ThemeDirectorCons
|
|||
*
|
||||
*/
|
||||
private class ProductionFilesDownloadLink extends Link {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param model
|
||||
*/
|
||||
ProductionFilesDownloadLink(final ThemeSelectionModel model) {
|
||||
super(new Label(GlobalizationUtil.globalize
|
||||
("theme.download_prod_theme_files")),
|
||||
|
|
@ -245,6 +255,11 @@ public class ThemeContainer extends SimpleContainer implements ThemeDirectorCons
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param state
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isVisible(PageState state) {
|
||||
return super.isVisible(state) &&
|
||||
|
|
|
|||
|
|
@ -52,18 +52,20 @@ import java.util.TooManyListenersException;
|
|||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* This is the base page for controlling themes in the system. It
|
||||
* contains a list of the themes on the left side and it manages the state
|
||||
* to show the correct forms/containers on the left
|
||||
* This is the base page for controlling themes in the system. It contains
|
||||
* a list of the themes on the left side and it manages the state to show the
|
||||
* correct forms/containers on the right
|
||||
*/
|
||||
public class ThemeControlPanel extends SelectionPanel implements ThemeDirectorConstants {
|
||||
public class ThemeControlPanel extends SelectionPanel
|
||||
implements ThemeDirectorConstants {
|
||||
|
||||
/** Internal logger instance to faciliate debugging. Enable logging output
|
||||
* by editing /WEB-INF/conf/log4j.properties int the runtime environment
|
||||
* and set com.arsdigita.templating.ui.ThemeControlPanel=DEBUG
|
||||
* and set com.arsdigita.themedirector.ui.ThemeControlPanel=DEBUG
|
||||
* by uncommenting or adding the line. */
|
||||
private static final Logger LOGGER = Logger.getLogger(ThemeControlPanel.class);
|
||||
private final ThemeSelectionModel selectionModel;
|
||||
/** Stored the theme form object, which shopws widget / data for a theme. */
|
||||
private final Form themeForm;
|
||||
private final BigDecimalParameter defaultThemeParam = new BigDecimalParameter("defaultTheme");
|
||||
|
||||
|
|
@ -121,19 +123,28 @@ public class ThemeControlPanel extends SelectionPanel implements ThemeDirectorCo
|
|||
addAction(defaultThemeForm);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Form createDefaultThemeForm() {
|
||||
|
||||
final Form defaultThemeForm = new Form("defaultThemeForm", new SimpleContainer());
|
||||
defaultThemeForm.add(new Label(GlobalizationUtil.globalize("theme.set_default_theme")));
|
||||
final Form defaultThemeForm = new Form("defaultThemeForm",
|
||||
new SimpleContainer());
|
||||
defaultThemeForm.add(new Label(GlobalizationUtil.globalize(
|
||||
"theme.set_default_theme")));
|
||||
|
||||
final SingleSelect themes = new SingleSelect(defaultThemeParam);
|
||||
themes.addOption(new Option(null, new Label(GlobalizationUtil.globalize("theme.none"))));
|
||||
themes.addOption(new Option(null, new Label(GlobalizationUtil.globalize(
|
||||
"theme.none"))));
|
||||
try {
|
||||
themes.addPrintListener(new PrintListener() {
|
||||
@Override
|
||||
public void prepare(final PrintEvent event) {
|
||||
final SingleSelect target = (SingleSelect) event.getTarget();
|
||||
final DataCollection options = SessionManager.getSession().retrieve(Theme.BASE_DATA_OBJECT_TYPE);
|
||||
final DataCollection options = SessionManager
|
||||
.getSession()
|
||||
.retrieve(Theme.BASE_DATA_OBJECT_TYPE);
|
||||
options.addNotEqualsFilter(Theme.LAST_PUBLISHED_DATE, null);
|
||||
options.addOrder(Theme.TITLE);
|
||||
while (options.next()) {
|
||||
|
|
|
|||
|
|
@ -29,31 +29,34 @@ import com.arsdigita.bebop.event.FormSubmissionListener;
|
|||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormValidationListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.ParameterEvent;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.GridPanel;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.parameters.GlobalizedParameterListener;
|
||||
import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
||||
import com.arsdigita.bebop.parameters.ParameterData;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.persistence.DataCollection;
|
||||
import com.arsdigita.persistence.SessionManager;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
import com.arsdigita.util.IO;
|
||||
//import com.arsdigita.util.IO;
|
||||
import com.arsdigita.themedirector.ThemeDirectorConstants;
|
||||
import com.arsdigita.themedirector.ThemeDirector;
|
||||
import com.arsdigita.themedirector.util.GlobalizationUtil;
|
||||
import com.arsdigita.themedirector.util.ManifestReader;
|
||||
//import com.arsdigita.themedirector.util.ManifestReader;
|
||||
import com.arsdigita.subsite.Subsite;
|
||||
import com.arsdigita.subsite.Site;
|
||||
import com.arsdigita.toolbox.ui.Cancellable;
|
||||
import com.arsdigita.web.Web;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
//import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
//import java.io.InputStream;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.filefilter.DirectoryFileFilter;
|
||||
//import org.apache.commons.io.filefilter.DirectoryFileFilter;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
|
@ -73,9 +76,17 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
|
|||
private static final Logger s_log = Logger.getLogger(ThemeForm.class);
|
||||
|
||||
private final ThemeSelectionModel m_theme;
|
||||
|
||||
/* Holds the theme's title. */
|
||||
private final TextField m_title;
|
||||
|
||||
/* Holds the theme's description. */
|
||||
private final TextArea m_description;
|
||||
|
||||
/* Holds the theme's URL. */
|
||||
private final TextField m_url;
|
||||
|
||||
/* Instance of the form's Save/Cancel buttons. */
|
||||
private final SaveCancelSection m_buttons;
|
||||
|
||||
/**
|
||||
|
|
@ -119,7 +130,9 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
|
|||
// Experimental, see above
|
||||
m_url.setLabel(GlobalizationUtil.globalize("theme.url"));
|
||||
m_url.addValidationListener(new NotEmptyValidationListener());
|
||||
m_title.setSize(40);
|
||||
m_url.addValidationListener(new URLFormValidationListener());
|
||||
m_url.addValidationListener(new UniqueURLValidationListener());
|
||||
m_url.setSize(40);
|
||||
m_url.setHint(GlobalizationUtil.globalize("theme.url_hint"));
|
||||
add(m_url);
|
||||
|
||||
|
|
@ -133,7 +146,11 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
|
|||
addSubmissionListener(new ThemeSubmissionListener());
|
||||
addProcessListener(new ThemeProcessListener());
|
||||
addInitListener(new ThemeInitListener());
|
||||
addValidationListener(new ThemeValidationListener());
|
||||
// Form wide validation listener commented out temporarily. All validation
|
||||
// is done using a parameterValidationListener on each input component.
|
||||
// A form wide validation listener may be introduced later to display
|
||||
// an error summerize text and advise what to do.
|
||||
//addValidationListener(new ThemeValidationListener());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -282,6 +299,8 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
|
|||
}
|
||||
|
||||
copyDefaultTheme(newDirectory,null);
|
||||
// Old way should be removed as soon as thorough testing the
|
||||
// new method has been completed.
|
||||
// copyDefaultFiles(newDirectory);
|
||||
|
||||
if (oldDirectory != null && !oldDirectory.exists()) {
|
||||
|
|
@ -334,100 +353,15 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ValöidatgionListener class to check the themedirector form input data.
|
||||
* It's validate method is the entry point and executed when submitting
|
||||
* the form.
|
||||
*/
|
||||
private class ThemeValidationListener implements FormValidationListener {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param e
|
||||
* @throws FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public void validate(FormSectionEvent e)
|
||||
throws FormProcessException {
|
||||
PageState state = e.getPageState();
|
||||
|
||||
String url = (String)m_url.getValue(state);
|
||||
validateURLForm(state, url);
|
||||
validateURLUniqueness(state, url);
|
||||
|
||||
// now, validate that the URL does not already exist if this
|
||||
// is actually a "new" and not an "edit"
|
||||
Theme theme = m_theme.getSelectedTheme(state);
|
||||
if (theme == null) {
|
||||
File currentRoot = new File(Web.getServletContext().getRealPath("/"));
|
||||
File newDirectory = new File(currentRoot, DEV_THEMES_BASE_DIR +
|
||||
url);
|
||||
if (newDirectory.exists()) {
|
||||
throw new FormProcessException
|
||||
("A file with the name " + url + " already exists " +
|
||||
"in the file system. Contact your system " +
|
||||
"administrator if you think this is an error.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks the form of the url...specifically, we are only allowing
|
||||
* [A-Z,a-z,0-9,_,-].
|
||||
* @param state
|
||||
* @param url
|
||||
* @throws com.arsdigita.bebop.FormProcessException
|
||||
*/
|
||||
public void validateURLForm(PageState state, String url)
|
||||
throws FormProcessException {
|
||||
|
||||
//Obviously, this is not at all globalized and should
|
||||
//only be used with English text....however, since we are dealing
|
||||
// with a string that will be in the file system and will not
|
||||
// be seen by the end user, this should be fine.
|
||||
for (int i = 0; i < url.length(); i++) {
|
||||
char c = url.charAt(i);
|
||||
if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
|
||||
('0' <= c && c <= '9') || c == '_' || c == '-')) {
|
||||
throw new FormProcessException
|
||||
("The URL can only contain A-Z, a-z, 0-9, _, and -.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This makes sure no other theme has the same URL
|
||||
* @param state
|
||||
* @param url
|
||||
* @throws com.arsdigita.bebop.FormProcessException
|
||||
*/
|
||||
public void validateURLUniqueness(PageState state, String url)
|
||||
throws FormProcessException {
|
||||
|
||||
if ( url != null ) {
|
||||
DataCollection collection = SessionManager.getSession()
|
||||
.retrieve(Theme.BASE_DATA_OBJECT_TYPE);
|
||||
collection.addEqualsFilter("lower(" + Theme.URL + ")",
|
||||
url.toLowerCase());
|
||||
Theme currentTheme = (Theme)m_theme.getSelectedObject(state);
|
||||
if (currentTheme != null) {
|
||||
collection.addNotEqualsFilter(Theme.ID, currentTheme.getID());
|
||||
}
|
||||
|
||||
if ( collection.size() > 0) {
|
||||
throw new FormProcessException
|
||||
("A theme with this url already exists");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a complete directory containing the default theme to a newly
|
||||
* created theme's directory without any filtering or other processing.
|
||||
* It assumes, that the source directory contains a complete and working
|
||||
* set of theme files.
|
||||
*
|
||||
* Developer's note: Why not move into private class ThemeProcessListener
|
||||
* where it is used (exclusivly).
|
||||
*
|
||||
* @param newThemeDirectory specifies the target directory. Must not
|
||||
* be null.
|
||||
* @param defaultThemeDirectory Directory containing a complete set of
|
||||
|
|
@ -449,13 +383,188 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
|
|||
newThemeDirectory);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Themedirector-specific parameter validation listener, verifies that the
|
||||
* URL parameter value contains only valid characters.
|
||||
* Helper method to checks the form of the url...specifically, we are
|
||||
* only allowing [A-Z,a-z,0-9,_,-].
|
||||
*/
|
||||
private class URLFormValidationListener
|
||||
extends GlobalizedParameterListener {
|
||||
|
||||
/**
|
||||
* Default Constructor setting a predefined label as error message.
|
||||
*/
|
||||
public URLFormValidationListener() {
|
||||
setError(GlobalizationUtil.globalize(
|
||||
"theme.form.url_can_contain_only_characters")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Method required and used to validate input.
|
||||
*
|
||||
* @param e ParameterEvent containing the data
|
||||
*/
|
||||
@Override
|
||||
public void validate(ParameterEvent e) {
|
||||
|
||||
ParameterData data = e.getParameterData();
|
||||
Object value = data.getValue();
|
||||
PageState state = e.getPageState();
|
||||
String url = (String)m_url.getValue(state);
|
||||
|
||||
if (value != null) {
|
||||
String urlString = value.toString().trim();
|
||||
|
||||
for (int i = 0; i < urlString.length(); i++) {
|
||||
char c = urlString.charAt(i);
|
||||
if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
|
||||
|| ('0' <= c && c <= '9') || c == '_' || c == '-')) {
|
||||
// urlString contains illegal character(s)
|
||||
// adds an error message to the widget object.
|
||||
data.addError(getError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// non-empty value, just return
|
||||
return;
|
||||
}
|
||||
// Empty or no illegal character found, just return
|
||||
return;
|
||||
|
||||
} // end method validatge
|
||||
} // end private class URLFormValidationListener
|
||||
|
||||
|
||||
/**
|
||||
* Themedirector-specific parameter validation listener, verifies that the
|
||||
* URL parameter is unique.
|
||||
*/
|
||||
private class UniqueURLValidationListener
|
||||
extends GlobalizedParameterListener {
|
||||
|
||||
/**
|
||||
* Default Constructor setting a predefined label as error message.
|
||||
*/
|
||||
public UniqueURLValidationListener() {
|
||||
setError(GlobalizationUtil.globalize(
|
||||
"theme.form.url_already_exists")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Method required and used to validate input.
|
||||
*
|
||||
* @param e ParameterEvent containing the data
|
||||
* @pre URL parameter is not empty and contains valid characters only
|
||||
* as ensured by previously invoked ValidationListeners.
|
||||
*/
|
||||
@Override
|
||||
public void validate(ParameterEvent e) {
|
||||
|
||||
ParameterData data = e.getParameterData();
|
||||
Object value = data.getValue();
|
||||
PageState state = e.getPageState();
|
||||
String url = (String)m_url.getValue(state);
|
||||
|
||||
if (value != null) {
|
||||
String urlString = value.toString().trim();
|
||||
|
||||
DataCollection collection = SessionManager.getSession()
|
||||
.retrieve(Theme.BASE_DATA_OBJECT_TYPE);
|
||||
collection.addEqualsFilter("lower(" + Theme.URL + ")",
|
||||
urlString.toLowerCase());
|
||||
Theme currentTheme = (Theme)m_theme.getSelectedObject(state);
|
||||
if (currentTheme != null) {
|
||||
collection.addNotEqualsFilter(Theme.ID, currentTheme.getID());
|
||||
}
|
||||
|
||||
if ( collection.size() > 0) {
|
||||
// urlString is not unique but already exists.
|
||||
// adds an error message to the widget object.
|
||||
data.addError(getError());
|
||||
return;
|
||||
}
|
||||
|
||||
// unique value, just return
|
||||
return;
|
||||
}
|
||||
// null or any other condition not able to handle here. Just return
|
||||
|
||||
} // end method validate
|
||||
|
||||
} // end private class UniqueURLValidationListener
|
||||
|
||||
|
||||
/**
|
||||
* ValidationListener class to check the themedirector's form input data.
|
||||
* It's validate method is the entry point and executed when submitting
|
||||
* the form.
|
||||
*/
|
||||
private class ThemeValidationListener implements FormValidationListener {
|
||||
|
||||
/**
|
||||
* Does the actual validation.
|
||||
*
|
||||
* @param fse
|
||||
* @throws FormProcessException
|
||||
*/
|
||||
@Override
|
||||
public void validate(FormSectionEvent fse)
|
||||
throws FormProcessException {
|
||||
|
||||
PageState state = fse.getPageState();
|
||||
|
||||
|
||||
// Nothing to do at the Moment
|
||||
// We should add something like that:
|
||||
// - acquire a formdata object
|
||||
// - iterate ober the formdata widgets and check for an
|
||||
// added error message
|
||||
// - Add the error to an error list
|
||||
// - If at least on error has been found, throw a FormProcessException
|
||||
// With a summerizing text and a list of errors found.
|
||||
// Text from a FPE is by default shown just below the action buttons
|
||||
// (Save / Cancel)
|
||||
|
||||
|
||||
// in case of an error in any of the input form widgets,
|
||||
// throw a FPE in give a summerizing message and advice.
|
||||
// throw new FormProcessException
|
||||
// ("[String]",
|
||||
// GlobalizationUtil.globalize("key",errorDetails)
|
||||
// );
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // end ThemeValidationListener
|
||||
|
||||
|
||||
|
||||
|
||||
// ///////////////////////////////////////////////////////////////////////
|
||||
// Outdated CODE
|
||||
// Temporarily retained for easy reference until migration is complete.
|
||||
// ///////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Copies the default theme files to the new directory using a
|
||||
* Manifest file to determine the files to copy.
|
||||
*
|
||||
* NOTE:
|
||||
* Old way should be removed as soon as thorough testing the
|
||||
* new method has been completed.
|
||||
*
|
||||
*
|
||||
* @param newDirectory specifies the target directory
|
||||
* @throws IOException
|
||||
*/
|
||||
/*
|
||||
private void copyDefaultFiles(File newDirectory) throws IOException {
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
InputStream is = loader.getResourceAsStream
|
||||
|
|
@ -476,21 +585,19 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
|
|||
new FileWriterManifestReader(is, newDirectory);
|
||||
reader.processFile();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* NOTE: Part of outdated way to copy a default theme. Copying is now done
|
||||
* without Manifest file. Class chould be completely removed as soon as
|
||||
* QA testing is completed.
|
||||
*/
|
||||
/*
|
||||
private class FileWriterManifestReader extends ManifestReader {
|
||||
private final File m_newDirectory;
|
||||
private final String m_directoryFilter;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stream
|
||||
* @param newDirectory
|
||||
*/
|
||||
FileWriterManifestReader(InputStream stream, File newDirectory) {
|
||||
super(stream);
|
||||
m_newDirectory = newDirectory;
|
||||
|
|
@ -498,12 +605,6 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
|
|||
m_directoryFilter = ThemeDirector.getConfig().getDefaultThemePath();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param is
|
||||
* @param filePath
|
||||
* @param isStyleFile
|
||||
*/
|
||||
@Override
|
||||
public void processManifestFileLine(InputStream is,
|
||||
String filePath,
|
||||
|
|
@ -541,4 +642,5 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,11 +182,11 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
|
|||
containing patterns to search for.
|
||||
|
||||
Developer's Note:
|
||||
We used to use a 'resource' tag involing a resource servlet to
|
||||
deliver the correct file either from database or filesystem. Ir would
|
||||
require an URL similar to
|
||||
We used to use a 'resource' tag involving a resource servlet to
|
||||
deliver the correct file either from database or filesystem. It
|
||||
would require an URL similar to
|
||||
http://localhost:9008/libreccm/resource/themes/heirloom/apps/theme/xsl/index.xs
|
||||
where librecms is the context ccm happpens to be installed in.
|
||||
where librecms is the context CCM happpens to be installed in.
|
||||
Currently we bypass the resource servlet and access the filesystem
|
||||
directly. Must be modified as soon as we deliver the theme from db. */
|
||||
String stylesheetPath = "http://" + Web.getConfig().getHost().toString()
|
||||
|
|
|
|||
|
|
@ -86,9 +86,12 @@ public class ThemeDevelopmentFileManager extends ThemeFileManager {
|
|||
* process the file. A startupDelay of 0 means that this is a no-op
|
||||
* @param pollDelay number of seconds to wait between checks if the file
|
||||
* has any entries.
|
||||
* @param baseDirectory
|
||||
* @return
|
||||
*/
|
||||
public static ThemeFileManager startWatchingFiles
|
||||
(int startupDelay, int pollDelay, String baseDirectory) {
|
||||
public static ThemeFileManager startWatchingFiles(int startupDelay,
|
||||
int pollDelay,
|
||||
String baseDirectory) {
|
||||
if (s_manager == null) {
|
||||
s_log.info("Starting Theme File Manager Thread with the base " +
|
||||
"directory of " + baseDirectory);
|
||||
|
|
@ -110,6 +113,8 @@ public class ThemeDevelopmentFileManager extends ThemeFileManager {
|
|||
/**
|
||||
* This returns the current thread or null if the thread has not
|
||||
* yet been started.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static ThemeFileManager getInstance() {
|
||||
return s_manager;
|
||||
|
|
@ -117,8 +122,11 @@ public class ThemeDevelopmentFileManager extends ThemeFileManager {
|
|||
|
||||
|
||||
/**
|
||||
* this typically returns something like "getBaseDirectory() + PROD_DIR"
|
||||
* This typically returns something like "getBaseDirectory() + PROD_DIR".
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected String getManagerSpecificDirectory() {
|
||||
return getBaseDirectory() + DEV_THEMES_BASE_DIR;
|
||||
}
|
||||
|
|
@ -134,6 +142,7 @@ public class ThemeDevelopmentFileManager extends ThemeFileManager {
|
|||
// it works if we want the thread to auto-update things for us.
|
||||
// if we decide that we definitely do not want the auto-update
|
||||
// then we should remove this.
|
||||
@Override
|
||||
protected void updateTheme(Theme theme) {
|
||||
// the first step is to make sure that all files from the theme
|
||||
// are in the db.
|
||||
|
|
@ -154,9 +163,11 @@ public class ThemeDevelopmentFileManager extends ThemeFileManager {
|
|||
|
||||
|
||||
/**
|
||||
* This allows subclasses to filter the collection as appropriate
|
||||
* This allows subclasses to filter the collection as appropriate.
|
||||
* (e.g. only return "live" files or only "draft" files).
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected ThemeFileCollection getThemeFilesCollection(Theme theme) {
|
||||
return theme.getDraftThemeFiles();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ import com.arsdigita.themedirector.ThemeDirectorConstants;
|
|||
import com.arsdigita.themedirector.ThemeFileCollection;
|
||||
import com.arsdigita.persistence.SessionManager;
|
||||
import com.arsdigita.persistence.TransactionContext;
|
||||
import com.arsdigita.themedirector.dispatcher.InternalThemePrefixerServlet;
|
||||
//import com.arsdigita.themedirector.dispatcher.InternalThemePrefixerServlet;
|
||||
import com.arsdigita.web.Web;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
|
@ -205,28 +206,18 @@ public abstract class ThemeFileManager extends Thread
|
|||
if (m_baseDirectory == null) {
|
||||
// Because the constructor sets the base directory this should
|
||||
// never happen, but just in case ....
|
||||
|
||||
// ThemeDirector may execute in a different web application context
|
||||
// as core oder CMS. To determine the actual context we may ask
|
||||
// Themedirector servlet.
|
||||
// as core oder CMS.
|
||||
// Old non-standard-compliant code had been removed, so currently
|
||||
// ThemeManager has to be installed into the same context as core.
|
||||
// To determine the actual context we may ask Themedirector servlet.
|
||||
// Something like
|
||||
// ServletContext themeCtx = InternalThemePrefixerServlet
|
||||
// .getThemedirectorContext();
|
||||
// We have to ensure the Servlet is initialized.
|
||||
|
||||
/* OLD code depending on deprecated ContextRegiserServlet
|
||||
ApplicationCollection collection = Application.retrieveAllApplications();
|
||||
collection.filterToApplicationType(ThemeDirector.BASE_DATA_OBJECT_TYPE);
|
||||
Application app = null;
|
||||
if (collection.next()) {
|
||||
// it should only be mounted once but the jsp does not
|
||||
// care about the application so even if it is mounted multiple
|
||||
// times that is fine.
|
||||
app = collection.getApplication();
|
||||
}
|
||||
collection.close();
|
||||
|
||||
String webapp = app.getContextPath();
|
||||
ServletContext themeCtx = Web.getServletContext(webapp + '/');
|
||||
m_baseDirectory = themeCtx.getRealPath("/");
|
||||
*/
|
||||
ServletContext themeCtx = InternalThemePrefixerServlet
|
||||
.getThemedirectorContext();
|
||||
ServletContext themeCtx = Web.getServletContext();
|
||||
m_baseDirectory = themeCtx.getRealPath("/");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,11 +32,14 @@ import org.apache.log4j.Logger;
|
|||
* runs for the first time, it examines all themes.
|
||||
*
|
||||
* @author <a href="mailto:randyg@redhat.com">Randy Graebner</a>
|
||||
*
|
||||
* @version $Revision: #2 $ $DateTime: 2004/03/17 09:56:37 $
|
||||
*/
|
||||
public class ThemePublishedFileManager extends ThemeFileManager {
|
||||
|
||||
/** Internal logger instance to faciliate debugging. Enable logging output
|
||||
* by editing /WEB-INF/conf/log4j.properties int hte runtime environment
|
||||
* and set com.arsdigita.themedirector.util.ThemePublishedFileManager=DEBUG
|
||||
* by uncommenting or adding the line. */
|
||||
private static Logger s_log =
|
||||
Logger.getLogger(ThemePublishedFileManager.class);
|
||||
|
||||
|
|
@ -46,7 +49,8 @@ public class ThemePublishedFileManager extends ThemeFileManager {
|
|||
static private ThemeFileManager s_manager = null;
|
||||
|
||||
|
||||
protected ThemePublishedFileManager(int startupDelay, int pollDelay,
|
||||
protected ThemePublishedFileManager(int startupDelay,
|
||||
int pollDelay,
|
||||
String baseDirectory) {
|
||||
super(s_log, startupDelay, pollDelay, baseDirectory);
|
||||
}
|
||||
|
|
@ -128,7 +132,7 @@ public class ThemePublishedFileManager extends ThemeFileManager {
|
|||
|
||||
|
||||
/**
|
||||
* This allows subclasses to filter the collection as appropriate
|
||||
* This allows subclasses to filter the collection as appropriate.
|
||||
* (e.g. only return "live" files or only "draft" files).
|
||||
*/
|
||||
protected ThemeFileCollection getThemeFilesCollection(Theme theme) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue