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.Iterator;
020:
021: import org.apache.wicket.Component;
022: import org.apache.wicket.behavior.HeaderContributor;
023: import org.apache.wicket.feedback.ContainerFeedbackMessageFilter;
024: import org.apache.wicket.markup.html.WebMarkupContainer;
025: import org.apache.wicket.markup.html.form.Form;
026: import org.apache.wicket.markup.html.panel.FeedbackPanel;
027: import org.apache.wicket.markup.html.panel.Panel;
028:
029: /**
030: * A wizard is a dialog component that takes users through a number of steps to
031: * complete a task. It has common functionality like a next, previous, finish
032: * and cancel button, and it uses a {@link IWizardModel} to navigate through the
033: * steps.
034: * <p>
035: * Before you can use the wizard component, it needs to be initialized with a
036: * model. You do this by calling {@link #init(IWizardModel)} with the wizard
037: * model you intent to use.
038: * </p>
039: *
040: * <p>
041: * This default implementation should be useful for basic cases, if the layout
042: * is exactly what you need. If you want to provide your own layout and/ or have
043: * more or less components (e.g. you want to additionally provide an overview
044: * component), you can override this class and add the components you want
045: * yourself using methods like {@link #newButtonBar(String)} et-cetera.
046: * </p>
047: *
048: * @author Eelco Hillenius
049: */
050: public class Wizard extends Panel implements IWizardModelListener,
051: IWizard {
052: /** Component id of the buttons panel as used by the default wizard panel. */
053: public static final String BUTTONS_ID = "buttons";
054:
055: /** Component id of the feedback panel as used by the default wizard panel. */
056: public static final String FEEDBACK_ID = "feedback";
057:
058: /** Component id of the header panel as used by the default wizard panel. */
059: public static final String HEADER_ID = "header";
060:
061: /** Component id of the overview panel as used by the default wizard panel. */
062: public static final String OVERVIEW_ID = "overview";
063:
064: /**
065: * Component id of the view panel (where the main wizard contents go) as
066: * used by the default wizard panel.
067: */
068: public static final String VIEW_ID = "view";
069:
070: private static final long serialVersionUID = 1L;
071:
072: /** The currently active step. */
073: private IWizardStep activeStep;
074:
075: /**
076: * The form in which the view is nested, and on which the wizard buttons
077: * work.
078: */
079: private Form form;
080:
081: /** The wizard model. */
082: private IWizardModel wizardModel;
083:
084: /**
085: * Construct. Adds the default style.
086: * <p>
087: * If you override this class, it makes sense to call this constructor
088: * (super(id)), then - in your constructor - construct a transition model
089: * and then call {@link #init(IWizardModel)} to initialize the wizard.
090: * </p>
091: * <p>
092: * This constructor is not meant for normal clients of this class
093: * </p>
094: *
095: * @param id
096: * The component model
097: */
098: public Wizard(String id) {
099: this (id, true);
100: }
101:
102: /**
103: * Construct.
104: * <p>
105: * If you override this class, it makes sense to call this constructor
106: * (super(id)), then - in your constructor - construct a transition model
107: * and then call {@link #init(IWizardModel)} to initialize the wizard.
108: * </p>
109: * <p>
110: * This constructor is not meant for normal clients of this class
111: * </p>
112: *
113: * @param id
114: * The component model
115: * @param addDefaultCssStyle
116: * Whether to add the {@link #addDefaultCssStyle() default style}
117: */
118: public Wizard(String id, boolean addDefaultCssStyle) {
119: super (id);
120:
121: if (addDefaultCssStyle) {
122: addDefaultCssStyle();
123: }
124: }
125:
126: /**
127: * Construct with a transition model. Adds the default style.
128: * <p>
129: * For most clients, this is typically the right constructor to use.
130: * </p>
131: *
132: * @param id
133: * The component id
134: * @param wizardModel
135: * The transitions model
136: */
137: public Wizard(String id, IWizardModel wizardModel) {
138: this (id, wizardModel, true);
139: }
140:
141: /**
142: * Construct with a transition model.
143: * <p>
144: * For most clients, this is typically the right constructor to use.
145: * </p>
146: *
147: * @param id
148: * The component id
149: * @param wizardModel
150: * The transitions model
151: * @param addDefaultCssStyle
152: * Whether to add the {@link #addDefaultCssStyle() default style}
153: */
154: public Wizard(String id, IWizardModel wizardModel,
155: boolean addDefaultCssStyle) {
156: super (id);
157:
158: init(wizardModel);
159:
160: if (addDefaultCssStyle) {
161: addDefaultCssStyle();
162: }
163: }
164:
165: /**
166: * Will let the wizard contribute a CSS include to the page's header. It
167: * will add Wizard.css from this package. This method is typically called by
168: * the class that creates the wizard.
169: */
170: public final void addDefaultCssStyle() {
171: add(HeaderContributor.forCss(Wizard.class, "Wizard.css"));
172: }
173:
174: /**
175: * Convenience method to get the active step from the model.
176: *
177: * @return The active step
178: */
179: public final IWizardStep getActiveStep() {
180: return getWizardModel().getActiveStep();
181: }
182:
183: /**
184: * Gets the form in which the view is nested, and on which the wizard
185: * buttons work.
186: *
187: * @return The wizard form
188: */
189: public Form getForm() {
190: return form;
191: }
192:
193: /**
194: * @see org.apache.wicket.extensions.wizard.IWizard#getWizardModel()
195: */
196: public final IWizardModel getWizardModel() {
197: return wizardModel;
198: }
199:
200: /**
201: * Turn versioning off for wizards. This works best when the wizard is
202: * <strong>not</strong> accessed from bookmarkable pages, so that the url
203: * doesn't change at all.
204: *
205: * @return False
206: * @see org.apache.wicket.Component#isVersioned()
207: */
208: public boolean isVersioned() {
209: return false;
210: }
211:
212: /**
213: * @see org.apache.wicket.extensions.wizard.IWizardModelListener#onActiveStepChanged(org.apache.wicket.extensions.wizard.IWizardStep)
214: */
215: public void onActiveStepChanged(IWizardStep newStep) {
216: this .activeStep = newStep;
217: form.replace(activeStep.getView(VIEW_ID, this , this ));
218: form.replace(activeStep.getHeader(HEADER_ID, this , this ));
219: }
220:
221: /**
222: * Called when the wizard is cancelled.
223: */
224: public void onCancel() {
225: };
226:
227: /**
228: * Called when the wizard is finished.
229: */
230: public void onFinish() {
231: }
232:
233: /**
234: * Initialize this wizard with a transition model.
235: * <p>
236: * If you constructed this wizard using a constructor without the
237: * transitions model argument, <strong>you must</strong> call this method
238: * prior to actually using it.
239: * </p>
240: *
241: * @param wizardModel
242: */
243: protected void init(IWizardModel wizardModel) {
244: if (wizardModel == null) {
245: throw new IllegalArgumentException(
246: "argument wizardModel must be not null");
247: }
248:
249: this .wizardModel = wizardModel;
250:
251: form = newForm("form");
252: addOrReplace(form);
253: // dummy view to be replaced
254: form.addOrReplace(new WebMarkupContainer(HEADER_ID));
255: form.addOrReplace(newFeedbackPanel(FEEDBACK_ID));
256: // add dummy view; will be replaced on initialization
257: form.addOrReplace(new WebMarkupContainer(VIEW_ID));
258: form.addOrReplace(newButtonBar(BUTTONS_ID));
259: form.addOrReplace(newOverviewBar(OVERVIEW_ID));
260:
261: wizardModel.addListener(this );
262:
263: Iterator stepsIterator = wizardModel.stepIterator();
264: if (stepsIterator != null) {
265: while (stepsIterator.hasNext()) {
266: ((IWizardStep) stepsIterator.next()).init(wizardModel);
267: }
268: }
269:
270: // reset model to prepare for action
271: wizardModel.reset();
272: }
273:
274: /**
275: * Create a new button bar. Clients can override this method to provide a
276: * custom button bar.
277: *
278: * @param id
279: * The id to be used to construct the component
280: *
281: * @return A new button bar
282: */
283: protected Component newButtonBar(String id) {
284: return new WizardButtonBar(id, this );
285: }
286:
287: /**
288: * Create a new feedback panel. Clients can override this method to provide
289: * a custom feedback panel.
290: *
291: * @param id
292: * The id to be used to construct the component
293: *
294: * @return A new feedback panel
295: */
296: protected FeedbackPanel newFeedbackPanel(String id) {
297: return new FeedbackPanel(id,
298: new ContainerFeedbackMessageFilter(this ));
299: }
300:
301: /**
302: * Create a new form. Clients can override this method to provide a custom
303: * {@link Form}.
304: *
305: * @param id
306: * The id to be used to construct the component
307: * @return a new form
308: */
309: protected Form newForm(String id) {
310: return new Form(id);
311: }
312:
313: /**
314: * Create a new overview bar. Clients can override this method to provide a
315: * custom bar.
316: *
317: * @param id
318: * The id to be used to construct the component
319: *
320: * @return A new ovewview bar
321: */
322: protected Component newOverviewBar(String id) {
323: // return a dummy component by default as we don't have an overview
324: // component
325: return new WebMarkupContainer(id).setVisible(false);
326: }
327: }
|