001: package com.xoetrope.swing.wizard;
002:
003: import com.xoetrope.template.XTemplateEngine;
004:
005: import java.awt.BorderLayout;
006: import java.awt.CardLayout;
007: import java.awt.Container;
008: import java.awt.Dimension;
009: import java.awt.FlowLayout;
010: import java.awt.event.ActionEvent;
011: import java.awt.event.ActionListener;
012: import java.util.Hashtable;
013: import javax.swing.BorderFactory;
014: import javax.swing.Icon;
015: import javax.swing.JLabel;
016: import javax.swing.JPanel;
017: import javax.swing.SwingConstants;
018: import net.xoetrope.swing.XButton;
019: import net.xoetrope.swing.XDialog;
020: import net.xoetrope.xui.PageSupport;
021: import net.xoetrope.xui.XPage;
022: import net.xoetrope.xui.XProject;
023: import net.xoetrope.xui.helper.XTranslator;
024: import net.xoetrope.xui.style.XStyleFactory;
025:
026: /**
027: * <p>
028: * The XWizard class manages the display and navigation actions of a wizard dialog.
029: * Wizards consist of multiple pages for the capture of user input, which upon
030: * completion paramaterize a task. The wizard can be dynamic, displaying a
031: * varying number of pages in response to user inputs and selections.
032: * </p>
033: * <p>
034: * The styles available are:
035: * <ul>
036: * </li>wizard - for the card, user and nav panels</li>
037: * </li>wizard/help - for the left hand help panel</li>
038: * </ul>
039: * </p>
040: *
041: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
042: * the GNU Public License (GPL), please see license.txt for more details. If
043: * you make commercial use of this software you must purchase a commercial
044: * license from Xoetrope.</p>
045: * <p> $Revision: 1.2 $</p>
046: */
047: public class XWizard extends XDialog implements ActionListener {
048: protected XButton nextButton;
049: protected XButton prevButton;
050: protected XButton cancelButton;
051: protected XButton finishButton;
052:
053: protected JPanel helpPanel;
054: protected JPanel cardPanel;
055: protected JPanel navPanel;
056:
057: protected JLabel statusText;
058: protected JLabel errorLabel;
059:
060: private XProject currentProject;
061: private CardLayout cardManager;
062: private CardLayout helpManager;
063: private PageSupport[] pages;
064: private int pageIdx;
065: private boolean showHelp;
066:
067: protected Hashtable<String, Object> settings;
068:
069: protected boolean hasError;
070:
071: /**
072: * Creates a new instance of XWizard
073: * @param project the owner project
074: * @param pages an array of page names
075: */
076: public XWizard(XProject project, String[] pages) {
077: this (project, pages, false);
078: }
079:
080: /**
081: * Creates a new instance of XWizard
082: * @param project the owner project
083: * @param pages an array of page names
084: * @param showHelp true to show help texts for each page
085: */
086: public XWizard(XProject project, String[] pages, boolean showHelp) {
087: currentProject = project;
088: this .showHelp = showHelp;
089: settings = new Hashtable<String, Object>();
090:
091: XTranslator translator = currentProject.getTranslator();
092:
093: BorderLayout bl = new BorderLayout();
094: bl.setVgap(0);
095: setLayout(bl);
096:
097: JPanel userPanel = new JPanel();
098: userPanel.setLayout(new BorderLayout(8, 8));
099: userPanel
100: .setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
101:
102: if (showHelp) {
103: helpManager = new CardLayout();
104: helpPanel = new JPanel();
105: helpPanel.setLayout(helpManager);
106: helpPanel.setBorder(BorderFactory.createEtchedBorder());
107: componentFactory.applyStyle(helpPanel, "wizard/help");
108: helpPanel.setMinimumSize(new Dimension(50, 2000));
109: }
110:
111: cardManager = new CardLayout();
112:
113: cardPanel = new JPanel();
114: cardPanel.setBorder(BorderFactory.createCompoundBorder(
115: BorderFactory.createEtchedBorder(), BorderFactory
116: .createEmptyBorder(6, 6, 6, 6)));
117: cardPanel.setLayout(cardManager);
118:
119: FlowLayout fl = new FlowLayout();
120: fl.setAlignment(fl.RIGHT);
121: fl.setHgap(8);
122:
123: JPanel footer = new JPanel();
124: footer.setLayout(new BorderLayout());
125: navPanel = new JPanel();
126: navPanel.setLayout(fl);
127:
128: errorLabel = new JLabel("");
129: errorLabel.setHorizontalTextPosition(SwingConstants.LEFT);
130: footer.add(errorLabel, BorderLayout.NORTH);
131:
132: statusText = new JLabel();
133: statusText.setHorizontalTextPosition(SwingConstants.RIGHT);
134: navPanel.add(statusText);
135:
136: cancelButton = new XButton();
137: cancelButton.setText(translator.translate("Cancel"));
138: cancelButton.setIcon((Icon) currentProject
139: .getIcon("com/xoetrope/resources/red.gif"));
140: cancelButton.addActionListener(this );
141: navPanel.add(cancelButton);
142:
143: prevButton = new XButton();
144: prevButton.setText(translator.translate("Prev"));
145: prevButton.setIcon((Icon) currentProject
146: .getIcon("com/xoetrope/resources/back.gif"));
147: prevButton.addActionListener(this );
148: navPanel.add(prevButton);
149:
150: nextButton = new XButton();
151: nextButton.setText(translator.translate("Next"));
152: nextButton.setHorizontalTextPosition(SwingConstants.LEFT);
153: nextButton.setIcon((Icon) currentProject
154: .getIcon("com/xoetrope/resources/forward.gif"));
155: nextButton.addActionListener(this );
156: navPanel.add(nextButton);
157:
158: finishButton = new XButton();
159: finishButton.setText(translator.translate("Finish"));
160: finishButton.setIcon((Icon) currentProject
161: .getIcon("com/xoetrope/resources/green.gif"));
162: finishButton.setHorizontalTextPosition(SwingConstants.LEFT);
163: finishButton.addActionListener(this );
164: navPanel.add(finishButton);
165:
166: XStyleFactory cf = (XStyleFactory) getComponentFactory();
167: cf.applyStyle(cardPanel, "wizard");
168: cf.applyStyle(userPanel, "wizard");
169: cf.applyStyle(navPanel, "wizard");
170:
171: footer.add(navPanel, BorderLayout.CENTER);
172:
173: if (showHelp)
174: userPanel.add(helpPanel, BorderLayout.WEST);
175: userPanel.add(cardPanel, BorderLayout.CENTER);
176: contentPanel.add(userPanel, BorderLayout.CENTER);
177: contentPanel.add(footer, BorderLayout.SOUTH);
178:
179: loadPages(pages);
180: }
181:
182: /**
183: * <p>Moves and resizes this component. The new location of the top-left
184: * corner is specified by <code>x</code> and <code>y</code>, and the
185: * new size is specified by <code>width</code> and <code>height</code>.</p>
186: * <p>Sets the size of the help panel, if any to one quarter of the width</p>
187: * @param x the new <i>x</i>-coordinate of this component
188: * @param y the new <i>y</i>-coordinate of this component
189: * @param width the new <code>width</code> of this component
190: * @param height the new <code>height</code> of this
191: * component
192: * @see #getBounds
193: * @see #setLocation(int, int)
194: * @see #setLocation(Point)
195: * @see #setSize(int, int)
196: * @see #setSize(Dimension)
197: */
198: public void setBounds(int x, int y, int w, int h) {
199: super .setBounds(x, y, w, h);
200: if (helpPanel != null)
201: helpPanel.setPreferredSize(new Dimension(w / 4, 2000));
202: }
203:
204: /**
205: * Load the pages that comprise the wizard
206: * @param pageNames an array of page names
207: */
208: protected void loadPages(String[] pageNames) {
209: pages = new PageSupport[pageNames.length];
210:
211: for (int i = 0; i < pageNames.length; i++) {
212: String pageName = (String) pageNames[i];
213: XPage newPage = (XPage) pageMgr.loadPage(pageName, false);
214: pages[i] = newPage;
215: if (newPage instanceof XWizardPage) {
216: XWizardPage wizardPage = (XWizardPage) newPage;
217: wizardPage.setWizard(this );
218:
219: if (showHelp) {
220: JLabel helpText = new JLabel(wizardPage
221: .getHelpText());
222: helpText.setBorder(BorderFactory.createEmptyBorder(
223: 6, 6, 6, 6));
224: helpText.setOpaque(false);
225: helpText.setVerticalAlignment(SwingConstants.TOP);
226: helpPanel.add(helpText, pageName);
227: }
228: }
229: cardPanel.add(newPage, pageName);
230: }
231: updateState();
232: }
233:
234: /**
235: * Show the help text for a given wizard panel
236: * @param panelName the wizard panel name
237: */
238: protected void showPanel(String panelName) {
239: cardManager.show(cardPanel, panelName);
240: updateState();
241: }
242:
243: /**
244: * Show the next page in the wizard
245: */
246: protected void showNextWizardPage() {
247: XWizardPage wp = (XWizardPage) pages[pageIdx];
248: if (wp.canAdvance())
249: showWizardPage(1);
250: }
251:
252: /**
253: * Show the previous page in the wizard
254: * @param panelName the wizard panel name
255: */
256: protected void showPreviousWizardPage() {
257: showWizardPage(-1);
258: }
259:
260: /**
261: * Move the wizard page forward or back
262: * @param inc 1, or -1 to move forward or back
263: */
264: private void showWizardPage(int inc) {
265: if (hasError)
266: return;
267:
268: PageSupport ps = pages[pageIdx];
269: ps.saveBoundComponentValues();
270: if (ps instanceof XWizardPage)
271: ((XWizardPage) ps).saveSettings();
272:
273: if (inc > 0) {
274: cardManager.next(cardPanel);
275: helpManager.next(helpPanel);
276: } else {
277: cardManager.previous(cardPanel);
278: helpManager.previous(helpPanel);
279: }
280:
281: pageIdx += inc;
282: pageIdx = Math.max(Math.min(pages.length - 1, pageIdx), 0);
283:
284: ps = pages[pageIdx];
285: if (ps instanceof XWizardPage)
286: ((XWizardPage) ps).restoreSettings();
287:
288: updateState();
289: }
290:
291: /**
292: * Update the components that depend on the page selection s
293: */
294: protected void updateState() {
295: statusText.setText(Integer.toString(pageIdx + 1) + "/"
296: + Integer.toString(pages.length));
297:
298: prevButton.setEnabled(pageIdx > 0);
299: nextButton.setEnabled(pageIdx != (pages.length - 1));
300: finishButton.setEnabled((pageIdx == (pages.length - 1))
301: && canFinish());
302:
303: pages[pageIdx].updateBoundComponentValues();
304: }
305:
306: /**
307: * Show the help text for a given wizard panel
308: * @param panelName the wizard panel name
309: */
310: public void addPanel(String panelName, Container panel) {
311: cardPanel.add(panel, panelName);
312: }
313:
314: /**
315: * Respond to button clicks
316: * @param ae the action event contaion details of the click
317: */
318: public void actionPerformed(ActionEvent ae) {
319: Object src = ae.getSource();
320:
321: if (src == nextButton)
322: showNextWizardPage();
323: else if (src == prevButton)
324: showPreviousWizardPage();
325: else if (src == cancelButton)
326: cancelDlg();
327: else if (src == finishButton) {
328: pages[pageIdx].saveBoundComponentValues();
329: XWizardPage wp = (XWizardPage) pages[pageIdx];
330: if (wp.canAdvance()) {
331: wp.saveSettings();
332: closeDlg();
333:
334: if (initProcessing()) {
335: if (processResources() >= 0)
336: if (finishProcessing())
337: finished();
338: }
339: }
340: }
341: }
342:
343: /**
344: * Display an error
345: * @param msg the message, or null to clear the error
346: */
347: public void setErrorMessage(String msg) {
348: errorLabel.setText(msg);
349: // errorIcon.setVisible( hasError = ( msg != null ));
350: }
351:
352: /**
353: * Has the wizard captured enough input to complete?
354: * @return true if the wizard can finish
355: */
356: public boolean canFinish() {
357: return true;
358: }
359:
360: /**
361: * Start processing and prepare for any new resources and/or setup the
362: * resources needed to complete the wizard
363: * @return true if the initialization is successful
364: */
365: public boolean initProcessing() {
366: return true;
367: }
368:
369: /**
370: * Process the resources
371: * @return zero if processing is sucessful or a positive integer if processing
372: * is completed, but with warnings, and a negative value if an error occurs
373: * that prevents complete processing
374: */
375: public int processResources() {
376: String[] resources = getTemplateResources();
377: if (resources == null)
378: return 0;
379:
380: Object op = settings.get("OutputPath");
381: if (op != null) {
382: String outputPath = op.toString();
383: XTemplateEngine engine = new XTemplateEngine(project,
384: project.getObject("ProjectPath").toString(),
385: outputPath);
386: return engine.process(resources);
387: }
388:
389: return -1;
390: }
391:
392: /**
393: * Finish processing and cleanup any resource usages
394: * @return true if the cleanup is successful
395: */
396: public boolean finishProcessing() {
397: return true;
398: }
399:
400: /**
401: * The wizard is complete, do any post creation action now
402: */
403: public void finished() {
404: }
405:
406: protected String[] getTemplateResources() {
407: return null;
408: }
409:
410: /**
411: * Get a wizard setting
412: * @param key the value key
413: * @return the value
414: */
415: public Object getProperty(String key) {
416: return settings.get(key);
417: }
418:
419: /**
420: * Save a setting
421: * @param key the lookup key
422: * @param value the value to store
423: */
424: public void setProperty(String key, Object value) {
425: settings.put(key, value);
426: }
427: }
|