001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.extensions.wizard;
018:
019: import java.util.ArrayList;
020: import java.util.HashSet;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Set;
024:
025: import org.apache.wicket.Component;
026: import org.apache.wicket.extensions.wizard.dynamic.DynamicWizardModel;
027: import org.apache.wicket.markup.html.basic.Label;
028: import org.apache.wicket.markup.html.form.Form;
029: import org.apache.wicket.markup.html.form.FormComponent;
030: import org.apache.wicket.markup.html.form.validation.IFormValidator;
031: import org.apache.wicket.markup.html.panel.Panel;
032: import org.apache.wicket.model.AbstractReadOnlyModel;
033: import org.apache.wicket.model.CompoundPropertyModel;
034: import org.apache.wicket.model.IModel;
035: import org.apache.wicket.model.Model;
036:
037: /**
038: * default implementation of {@link IWizardStep}. It is also a panel, which is
039: * used as the view component.
040: *
041: * <p>
042: * And example of a custom step with a panel follows.
043: *
044: * Java (defined e.g. in class x.NewUserWizard):
045: *
046: * <pre>
047: * private final class UserNameStep extends WizardStep
048: * {
049: * public UserNameStep()
050: * {
051: * super(new ResourceModel("username.title"), new ResourceModel("username.summary"));
052: * add(new RequiredTextField("user.userName"));
053: * add(new RequiredTextField("user.email").add(EmailAddressValidator.getInstance()));
054: * }
055: * }
056: * </pre>
057: *
058: * HTML (defined in e.g. file x/NewUserWizard$UserNameStep.html):
059: *
060: * <pre>
061: * <wicket:panel>
062: * <table>
063: * <tr>
064: * <td><wicket:message key="username">Username</wicket:message></td>
065: * <td><input type="text" wicket:id="user.userName" /></td>
066: * </tr>
067: * <tr>
068: * <td><wicket:message key="email">Email Adress</wicket:message></td>
069: * <td><input type="text" wicket:id="user.email" /></td>
070: * </tr>
071: * </table>
072: * </wicket:panel>
073: * </pre>
074: *
075: * </p>
076: *
077: *
078: * @author Eelco Hillenius
079: */
080: public class WizardStep extends Panel implements IWizardStep {
081: /**
082: * Adds form validators. We don't need this in 2.0 as the hierarchy is know
083: * at construction time from then.
084: */
085: private final class AddFormValidatorAction {
086: /**
087: * Wrapper for any form validators.
088: */
089: final FormValidatorWrapper formValidatorWrapper = new FormValidatorWrapper();
090:
091: void execute() {
092: Form form = (Form) WizardStep.this .findParent(Form.class);
093: form.add(formValidatorWrapper);
094: }
095: }
096:
097: /**
098: * Wraps form validators for this step such that they are only executed when
099: * this step is active.
100: */
101: private final class FormValidatorWrapper implements IFormValidator {
102:
103: private static final long serialVersionUID = 1L;
104:
105: private final List validators = new ArrayList();
106:
107: /**
108: * Adds a form validator.
109: *
110: * @param validator
111: * The validator to add
112: */
113: public final void add(IFormValidator validator) {
114: validators.add(validator);
115: }
116:
117: /**
118: * @see org.apache.wicket.markup.html.form.validation.IFormValidator#getDependentFormComponents()
119: */
120: public FormComponent[] getDependentFormComponents() {
121: if (isActiveStep()) {
122: Set components = new HashSet();
123: for (Iterator i = validators.iterator(); i.hasNext();) {
124: IFormValidator v = (IFormValidator) i.next();
125: FormComponent[] dependentComponents = v
126: .getDependentFormComponents();
127: if (dependentComponents != null) {
128: int len = dependentComponents.length;
129: for (int j = 0; j < len; j++) {
130: components.add(dependentComponents[j]);
131: }
132: }
133: }
134: return (FormComponent[]) components
135: .toArray(new FormComponent[components.size()]);
136: }
137: return null;
138: }
139:
140: /**
141: * @see org.apache.wicket.markup.html.form.validation.IFormValidator#validate(org.apache.wicket.markup.html.form.Form)
142: */
143: public void validate(Form form) {
144: if (isActiveStep()) {
145: for (Iterator i = validators.iterator(); i.hasNext();) {
146: IFormValidator v = (IFormValidator) i.next();
147: v.validate(form);
148: }
149: }
150: }
151:
152: /**
153: * @return whether the step this wrapper is part of is the current step
154: */
155: private final boolean isActiveStep() {
156: return (wizardModel.getActiveStep().equals(WizardStep.this ));
157: }
158: }
159:
160: /**
161: * Default header for wizards.
162: */
163: private final class Header extends Panel {
164: private static final long serialVersionUID = 1L;
165:
166: /**
167: * Construct.
168: *
169: * @param id
170: * The component id
171: * @param wizard
172: * The containing wizard
173: */
174: public Header(final String id, final IWizard wizard) {
175: super (id);
176: setModel(new CompoundPropertyModel(wizard));
177: add(new Label("title", new AbstractReadOnlyModel() {
178: private static final long serialVersionUID = 1L;
179:
180: public Object getObject() {
181: return getTitle();
182: }
183: }).setEscapeModelStrings(false));
184: add(new Label("summary", new AbstractReadOnlyModel() {
185: private static final long serialVersionUID = 1L;
186:
187: public Object getObject() {
188: return getSummary();
189: }
190: }).setEscapeModelStrings(false));
191: }
192: }
193:
194: private static final long serialVersionUID = 1L;
195:
196: /**
197: * Marks this step as being fully configured. Only when this is
198: * <tt>true</tt> can the wizard progress. True by default as that works
199: * best with normal forms. Clients can set this to false if some
200: * intermediate step, like a file upload, needs to be completed before the
201: * wizard may progress.
202: */
203: private boolean complete = true;
204:
205: private transient AddFormValidatorAction onAttachAction;
206:
207: /**
208: * A summary of this step, or some usage advice.
209: */
210: private IModel summary;
211:
212: /**
213: * The title of this step.
214: */
215: private IModel title;
216:
217: /**
218: * The wizard model.
219: */
220: private IWizardModel wizardModel;
221:
222: /**
223: * Construct without a title and a summary. Useful for when you provide a
224: * custom header by overiding {@link #getHeader(String, Component, IWizard)}.
225: */
226: public WizardStep() {
227: super (Wizard.VIEW_ID);
228: }
229:
230: /**
231: * Creates a new step with the specified title and summary. The title and
232: * summary are displayed in the wizard title block while this step is
233: * active.
234: *
235: * @param title
236: * the title of this step.
237: * @param summary
238: * a brief summary of this step or some usage guidelines.
239: */
240: public WizardStep(IModel title, IModel summary) {
241: this (title, summary, null);
242: }
243:
244: /**
245: * Creates a new step with the specified title and summary. The title and
246: * summary are displayed in the wizard title block while this step is
247: * active.
248: *
249: * @param title
250: * the title of this step.
251: * @param summary
252: * a brief summary of this step or some usage guidelines.
253: * @param model
254: * Any model which is to be used for this step
255: */
256: public WizardStep(IModel title, IModel summary, IModel model) {
257: super (Wizard.VIEW_ID, model);
258:
259: this .title = wrap(title);
260: this .summary = wrap(summary);
261: }
262:
263: /**
264: * Creates a new step with the specified title and summary. The title and
265: * summary are displayed in the wizard title block while this step is
266: * active.
267: *
268: * @param title
269: * the title of this step.
270: * @param summary
271: * a brief summary of this step or some usage guidelines.
272: */
273: public WizardStep(String title, String summary) {
274: this (title, summary, null);
275: }
276:
277: /**
278: * Creates a new step with the specified title and summary. The title and
279: * summary are displayed in the wizard title block while this step is
280: * active.
281: *
282: * @param title
283: * the title of this step.
284: * @param summary
285: * a brief summary of this step or some usage guidelines.
286: * @param model
287: * Any model which is to be used for this step
288: */
289: public WizardStep(String title, String summary, IModel model) {
290: this (new Model(title), new Model(summary), model);
291: }
292:
293: /**
294: * Adds a form validator.
295: *
296: * @param validator
297: */
298: public final void add(IFormValidator validator) {
299: if (onAttachAction == null) {
300: onAttachAction = new AddFormValidatorAction();
301: }
302: onAttachAction.formValidatorWrapper.add(validator);
303: }
304:
305: /**
306: * @see org.apache.wicket.extensions.wizard.IWizardStep#applyState()
307: */
308: public void applyState() {
309: }
310:
311: /**
312: * @see org.apache.wicket.extensions.wizard.IWizardStep#getHeader(java.lang.String,
313: * org.apache.wicket.Component,
314: * org.apache.wicket.extensions.wizard.IWizard)
315: */
316: public Component getHeader(String id, Component parent,
317: IWizard wizard) {
318: return new Header(id, wizard);
319: }
320:
321: /**
322: * Gets the summary of this step. This will be displayed in the title of the
323: * wizard while this step is active. The summary is typically an overview of
324: * the step or some usage guidelines for the user.
325: *
326: * @return the summary of this step.
327: */
328: public String getSummary() {
329: return (summary != null) ? (String) summary.getObject()
330: : (String) null;
331: }
332:
333: /**
334: * Gets the title of this step.
335: *
336: * @return the title of this step.
337: */
338: public String getTitle() {
339: return (title != null) ? (String) title.getObject()
340: : (String) null;
341: }
342:
343: /**
344: * @see org.apache.wicket.extensions.wizard.IWizardStep#getView(java.lang.String,
345: * org.apache.wicket.Component,
346: * org.apache.wicket.extensions.wizard.IWizard)
347: */
348: public Component getView(String id, Component parent, IWizard wizard) {
349: return this ;
350: }
351:
352: /**
353: * Called to initialize the step. When this method is called depends on the
354: * kind of wizard model that is used.
355: *
356: * The {@link WizardModel static wizard model} knows all the steps upfront
357: * and initializes themm when starting up. This method will be called when
358: * the wizard is {@link #init(IWizardModel) initializing}.
359: *
360: * The {@link DynamicWizardModel dynamic wizard model} initializes steps
361: * every time they are encountered.
362: *
363: * This method sets the wizard model and then calls template method
364: * {@link #onInit(IWizardModel)}
365: *
366: * @param wizardModel
367: * the model to which the step belongs.
368: */
369: public final void init(IWizardModel wizardModel) {
370: this .wizardModel = wizardModel;
371: onInit(wizardModel);
372: }
373:
374: /**
375: * Checks if this step is compete. This method should return true if the
376: * wizard can proceed to the next step. This property is bound and changes
377: * can be made at anytime by calling {@link #setComplete(boolean)} .
378: *
379: * @return <tt>true</tt> if the wizard can proceed from this step,
380: * <tt>false</tt> otherwise.
381: * @see #setComplete
382: */
383: public boolean isComplete() {
384: return complete;
385: }
386:
387: /**
388: * Marks this step as compete. The wizard will not be able to proceed from
389: * this step until this property is configured to <tt>true</tt>.
390: *
391: * @param complete
392: * <tt>true</tt> to allow the wizard to proceed, <tt>false</tt>
393: * otherwise.
394: * @see #isComplete
395: */
396: public void setComplete(boolean complete) {
397: this .complete = complete;
398: }
399:
400: /**
401: * Sets summary.
402: *
403: * @param summary
404: * summary
405: */
406: public void setSummaryModel(IModel summary) {
407: this .summary = wrap(summary);
408: }
409:
410: /**
411: * Sets title.
412: *
413: * @param title
414: * title
415: */
416: public void setTitleModel(IModel title) {
417: this .title = wrap(title);
418: }
419:
420: /**
421: * @see org.apache.wicket.Component#detachModel()
422: */
423: protected void detachModel() {
424: super .detachModel();
425: if (title != null) {
426: title.detach();
427: }
428: if (summary != null) {
429: summary.detach();
430: }
431: }
432:
433: /**
434: * Workaround for adding the form validators.
435: *
436: * @see org.apache.wicket.Component#onBeforeRender()
437: */
438: protected void onBeforeRender() {
439: super .onBeforeRender();
440: if (onAttachAction != null) {
441: onAttachAction.execute();
442: onAttachAction = null;
443: }
444: }
445:
446: /**
447: * Template method that is called when the step is being initialized.
448: *
449: * @param wizardModel
450: * @see #init(IWizardModel)
451: */
452: protected void onInit(IWizardModel wizardModel) {
453: }
454: }
|