001 /* ========================================================================
002 * JCommon : a free general purpose class library for the Java(tm) platform
003 * ========================================================================
004 *
005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006 *
007 * Project Info: http://www.jfree.org/jcommon/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * -----------------
028 * WizardDialog.java
029 * -----------------
030 * (C) Copyright 2000-2004, by Object Refinery Limited.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): -;
034 *
035 * $Id: WizardDialog.java,v 1.5 2005/11/16 15:58:41 taqua Exp $
036 *
037 * Changes (from 26-Oct-2001)
038 * --------------------------
039 * 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
040 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
041 *
042 */
043
044 package org.jfree.ui;
045
046 import java.awt.BorderLayout;
047 import java.awt.Container;
048 import java.awt.event.ActionEvent;
049 import java.awt.event.ActionListener;
050 import java.util.ArrayList;
051
052 import javax.swing.BorderFactory;
053 import javax.swing.JButton;
054 import javax.swing.JDialog;
055 import javax.swing.JFrame;
056 import javax.swing.JPanel;
057
058 /**
059 * A dialog that presents the user with a sequence of steps for completing a task. The dialog
060 * contains "Next" and "Previous" buttons, allowing the user to navigate through the task.
061 * <P>
062 * When the user backs up by one or more steps, the dialog keeps the completed steps so that
063 * they can be reused if the user doesn't change anything - this handles the cases where the user
064 * backs up a few steps just to review what has been completed.
065 * <p>
066 * But if the user changes some options in an earlier step, then the dialog may have to discard
067 * the later steps and have them repeated.
068 * <P>
069 * THIS CLASS IS NOT WORKING CORRECTLY YET.
070 *
071 *
072 * @author David Gilbert
073 */
074 public class WizardDialog extends JDialog implements ActionListener {
075
076 /** The end result of the wizard sequence. */
077 private Object result;
078
079 /** The current step in the wizard process (starting at step zero). */
080 private int step;
081
082 /** A reference to the current panel. */
083 private WizardPanel currentPanel;
084
085 /** A list of references to the panels the user has already seen - used for navigating through
086 the steps that have already been completed. */
087 private java.util.List panels;
088
089 /** A handy reference to the "previous" button. */
090 private JButton previousButton;
091
092 /** A handy reference to the "next" button. */
093 private JButton nextButton;
094
095 /** A handy reference to the "finish" button. */
096 private JButton finishButton;
097
098 /** A handy reference to the "help" button. */
099 private JButton helpButton;
100
101 /**
102 * Standard constructor - builds and returns a new WizardDialog.
103 *
104 * @param owner the owner.
105 * @param modal modal?
106 * @param title the title.
107 * @param firstPanel the first panel.
108 */
109 public WizardDialog(final JDialog owner, final boolean modal,
110 final String title, final WizardPanel firstPanel) {
111
112 super(owner, title + " : step 1", modal);
113 this.result = null;
114 this.currentPanel = firstPanel;
115 this.step = 0;
116 this.panels = new ArrayList();
117 this.panels.add(firstPanel);
118 setContentPane(createContent());
119
120 }
121
122 /**
123 * Standard constructor - builds a new WizardDialog owned by the specified JFrame.
124 *
125 * @param owner the owner.
126 * @param modal modal?
127 * @param title the title.
128 * @param firstPanel the first panel.
129 */
130 public WizardDialog(final JFrame owner, final boolean modal,
131 final String title, final WizardPanel firstPanel) {
132
133 super(owner, title + " : step 1", modal);
134 this.result = null;
135 this.currentPanel = firstPanel;
136 this.step = 0;
137 this.panels = new ArrayList();
138 this.panels.add(firstPanel);
139 setContentPane(createContent());
140 }
141
142 /**
143 * Returns the result of the wizard sequence.
144 *
145 * @return the result.
146 */
147 public Object getResult() {
148 return this.result;
149 }
150
151 /**
152 * Returns the total number of steps in the wizard sequence, if this number is known. Otherwise
153 * this method returns zero. Subclasses should override this method unless the number of steps
154 * is not known.
155 *
156 * @return the number of steps.
157 */
158 public int getStepCount() {
159 return 0;
160 }
161
162 /**
163 * Returns true if it is possible to back up to the previous panel, and false otherwise.
164 *
165 * @return boolean.
166 */
167 public boolean canDoPreviousPanel() {
168 return (this.step > 0);
169 }
170
171 /**
172 * Returns true if there is a 'next' panel, and false otherwise.
173 *
174 * @return boolean.
175 */
176 public boolean canDoNextPanel() {
177 return this.currentPanel.hasNextPanel();
178 }
179
180 /**
181 * Returns true if it is possible to finish the sequence at this point (possibly with defaults
182 * for the remaining entries).
183 *
184 * @return boolean.
185 */
186 public boolean canFinish() {
187 return this.currentPanel.canFinish();
188 }
189
190 /**
191 * Returns the panel for the specified step (steps are numbered from zero).
192 *
193 * @param step the current step.
194 *
195 * @return the panel.
196 */
197 public WizardPanel getWizardPanel(final int step) {
198 if (step < this.panels.size()) {
199 return (WizardPanel) this.panels.get(step);
200 }
201 else {
202 return null;
203 }
204 }
205
206 /**
207 * Handles events.
208 *
209 * @param event the event.
210 */
211 public void actionPerformed(final ActionEvent event) {
212 final String command = event.getActionCommand();
213 if (command.equals("nextButton")) {
214 next();
215 }
216 else if (command.equals("previousButton")) {
217 previous();
218 }
219 else if (command.equals("finishButton")) {
220 finish();
221 }
222 }
223
224 /**
225 * Handles a click on the "previous" button, by displaying the previous panel in the sequence.
226 */
227 public void previous() {
228 if (this.step > 0) {
229 final WizardPanel previousPanel = getWizardPanel(this.step - 1);
230 // tell the panel that we are returning
231 previousPanel.returnFromLaterStep();
232 final Container content = getContentPane();
233 content.remove(this.currentPanel);
234 content.add(previousPanel);
235 this.step = this.step - 1;
236 this.currentPanel = previousPanel;
237 setTitle("Step " + (this.step + 1));
238 enableButtons();
239 pack();
240 }
241 }
242
243 /**
244 * Displays the next step in the wizard sequence.
245 */
246 public void next() {
247
248 WizardPanel nextPanel = getWizardPanel(this.step + 1);
249 if (nextPanel != null) {
250 if (!this.currentPanel.canRedisplayNextPanel()) {
251 nextPanel = this.currentPanel.getNextPanel();
252 }
253 }
254 else {
255 nextPanel = this.currentPanel.getNextPanel();
256 }
257
258 this.step = this.step + 1;
259 if (this.step < this.panels.size()) {
260 this.panels.set(this.step, nextPanel);
261 }
262 else {
263 this.panels.add(nextPanel);
264 }
265
266 final Container content = getContentPane();
267 content.remove(this.currentPanel);
268 content.add(nextPanel);
269
270 this.currentPanel = nextPanel;
271 setTitle("Step " + (this.step + 1));
272 enableButtons();
273 pack();
274
275 }
276
277 /**
278 * Finishes the wizard.
279 */
280 public void finish() {
281 this.result = this.currentPanel.getResult();
282 setVisible(false);
283 }
284
285 /**
286 * Enables/disables the buttons according to the current step. A good idea would be to ask the
287 * panels to return the status...
288 */
289 private void enableButtons() {
290 this.previousButton.setEnabled(this.step > 0);
291 this.nextButton.setEnabled(canDoNextPanel());
292 this.finishButton.setEnabled(canFinish());
293 this.helpButton.setEnabled(false);
294 }
295
296 /**
297 * Checks, whether the user cancelled the dialog.
298 *
299 * @return false.
300 */
301 public boolean isCancelled() {
302 return false;
303 }
304
305 /**
306 * Creates a panel containing the user interface for the dialog.
307 *
308 * @return the panel.
309 */
310 public JPanel createContent() {
311
312 final JPanel content = new JPanel(new BorderLayout());
313 content.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
314 content.add((JPanel) this.panels.get(0));
315 final L1R3ButtonPanel buttons = new L1R3ButtonPanel("Help", "Previous", "Next", "Finish");
316
317 this.helpButton = buttons.getLeftButton();
318 this.helpButton.setEnabled(false);
319
320 this.previousButton = buttons.getRightButton1();
321 this.previousButton.setActionCommand("previousButton");
322 this.previousButton.addActionListener(this);
323 this.previousButton.setEnabled(false);
324
325 this.nextButton = buttons.getRightButton2();
326 this.nextButton.setActionCommand("nextButton");
327 this.nextButton.addActionListener(this);
328 this.nextButton.setEnabled(true);
329
330 this.finishButton = buttons.getRightButton3();
331 this.finishButton.setActionCommand("finishButton");
332 this.finishButton.addActionListener(this);
333 this.finishButton.setEnabled(false);
334
335 buttons.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
336 content.add(buttons, BorderLayout.SOUTH);
337
338 return content;
339 }
340
341 }