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.6 2007/11/02 17:50:36 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 import javax.swing.BorderFactory;
052 import javax.swing.JButton;
053 import javax.swing.JDialog;
054 import javax.swing.JFrame;
055 import javax.swing.JPanel;
056
057 /**
058 * A dialog that presents the user with a sequence of steps for completing a task. The dialog
059 * contains "Next" and "Previous" buttons, allowing the user to navigate through the task.
060 * <P>
061 * When the user backs up by one or more steps, the dialog keeps the completed steps so that
062 * they can be reused if the user doesn't change anything - this handles the cases where the user
063 * backs up a few steps just to review what has been completed.
064 * <p>
065 * But if the user changes some options in an earlier step, then the dialog may have to discard
066 * the later steps and have them repeated.
067 * <P>
068 * THIS CLASS IS NOT WORKING CORRECTLY YET.
069 *
070 *
071 * @author David Gilbert
072 */
073 public class WizardDialog extends JDialog implements ActionListener {
074
075 /** The end result of the wizard sequence. */
076 private Object result;
077
078 /** The current step in the wizard process (starting at step zero). */
079 private int step;
080
081 /** A reference to the current panel. */
082 private WizardPanel currentPanel;
083
084 /** A list of references to the panels the user has already seen - used for navigating through
085 the steps that have already been completed. */
086 private java.util.List panels;
087
088 /** A handy reference to the "previous" button. */
089 private JButton previousButton;
090
091 /** A handy reference to the "next" button. */
092 private JButton nextButton;
093
094 /** A handy reference to the "finish" button. */
095 private JButton finishButton;
096
097 /** A handy reference to the "help" button. */
098 private JButton helpButton;
099
100 /**
101 * Standard constructor - builds and returns a new WizardDialog.
102 *
103 * @param owner the owner.
104 * @param modal modal?
105 * @param title the title.
106 * @param firstPanel the first panel.
107 */
108 public WizardDialog(final JDialog owner, final boolean modal,
109 final String title, final WizardPanel firstPanel) {
110
111 super(owner, title + " : step 1", modal);
112 this.result = null;
113 this.currentPanel = firstPanel;
114 this.step = 0;
115 this.panels = new ArrayList();
116 this.panels.add(firstPanel);
117 setContentPane(createContent());
118
119 }
120
121 /**
122 * Standard constructor - builds a new WizardDialog owned by the specified JFrame.
123 *
124 * @param owner the owner.
125 * @param modal modal?
126 * @param title the title.
127 * @param firstPanel the first panel.
128 */
129 public WizardDialog(final JFrame owner, final boolean modal,
130 final String title, final WizardPanel firstPanel) {
131
132 super(owner, title + " : step 1", modal);
133 this.result = null;
134 this.currentPanel = firstPanel;
135 this.step = 0;
136 this.panels = new ArrayList();
137 this.panels.add(firstPanel);
138 setContentPane(createContent());
139 }
140
141 /**
142 * Returns the result of the wizard sequence.
143 *
144 * @return the result.
145 */
146 public Object getResult() {
147 return this.result;
148 }
149
150 /**
151 * Returns the total number of steps in the wizard sequence, if this number is known. Otherwise
152 * this method returns zero. Subclasses should override this method unless the number of steps
153 * is not known.
154 *
155 * @return the number of steps.
156 */
157 public int getStepCount() {
158 return 0;
159 }
160
161 /**
162 * Returns true if it is possible to back up to the previous panel, and false otherwise.
163 *
164 * @return boolean.
165 */
166 public boolean canDoPreviousPanel() {
167 return (this.step > 0);
168 }
169
170 /**
171 * Returns true if there is a 'next' panel, and false otherwise.
172 *
173 * @return boolean.
174 */
175 public boolean canDoNextPanel() {
176 return this.currentPanel.hasNextPanel();
177 }
178
179 /**
180 * Returns true if it is possible to finish the sequence at this point (possibly with defaults
181 * for the remaining entries).
182 *
183 * @return boolean.
184 */
185 public boolean canFinish() {
186 return this.currentPanel.canFinish();
187 }
188
189 /**
190 * Returns the panel for the specified step (steps are numbered from zero).
191 *
192 * @param step the current step.
193 *
194 * @return the panel.
195 */
196 public WizardPanel getWizardPanel(final int step) {
197 if (step < this.panels.size()) {
198 return (WizardPanel) this.panels.get(step);
199 }
200 else {
201 return null;
202 }
203 }
204
205 /**
206 * Handles events.
207 *
208 * @param event the event.
209 */
210 public void actionPerformed(final ActionEvent event) {
211 final String command = event.getActionCommand();
212 if (command.equals("nextButton")) {
213 next();
214 }
215 else if (command.equals("previousButton")) {
216 previous();
217 }
218 else if (command.equals("finishButton")) {
219 finish();
220 }
221 }
222
223 /**
224 * Handles a click on the "previous" button, by displaying the previous panel in the sequence.
225 */
226 public void previous() {
227 if (this.step > 0) {
228 final WizardPanel previousPanel = getWizardPanel(this.step - 1);
229 // tell the panel that we are returning
230 previousPanel.returnFromLaterStep();
231 final Container content = getContentPane();
232 content.remove(this.currentPanel);
233 content.add(previousPanel);
234 this.step = this.step - 1;
235 this.currentPanel = previousPanel;
236 setTitle("Step " + (this.step + 1));
237 enableButtons();
238 pack();
239 }
240 }
241
242 /**
243 * Displays the next step in the wizard sequence.
244 */
245 public void next() {
246
247 WizardPanel nextPanel = getWizardPanel(this.step + 1);
248 if (nextPanel != null) {
249 if (!this.currentPanel.canRedisplayNextPanel()) {
250 nextPanel = this.currentPanel.getNextPanel();
251 }
252 }
253 else {
254 nextPanel = this.currentPanel.getNextPanel();
255 }
256
257 this.step = this.step + 1;
258 if (this.step < this.panels.size()) {
259 this.panels.set(this.step, nextPanel);
260 }
261 else {
262 this.panels.add(nextPanel);
263 }
264
265 final Container content = getContentPane();
266 content.remove(this.currentPanel);
267 content.add(nextPanel);
268
269 this.currentPanel = nextPanel;
270 setTitle("Step " + (this.step + 1));
271 enableButtons();
272 pack();
273
274 }
275
276 /**
277 * Finishes the wizard.
278 */
279 public void finish() {
280 this.result = this.currentPanel.getResult();
281 setVisible(false);
282 }
283
284 /**
285 * Enables/disables the buttons according to the current step. A good idea would be to ask the
286 * panels to return the status...
287 */
288 private void enableButtons() {
289 this.previousButton.setEnabled(this.step > 0);
290 this.nextButton.setEnabled(canDoNextPanel());
291 this.finishButton.setEnabled(canFinish());
292 this.helpButton.setEnabled(false);
293 }
294
295 /**
296 * Checks, whether the user cancelled the dialog.
297 *
298 * @return false.
299 */
300 public boolean isCancelled() {
301 return false;
302 }
303
304 /**
305 * Creates a panel containing the user interface for the dialog.
306 *
307 * @return the panel.
308 */
309 public JPanel createContent() {
310
311 final JPanel content = new JPanel(new BorderLayout());
312 content.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
313 content.add((JPanel) this.panels.get(0));
314 final L1R3ButtonPanel buttons = new L1R3ButtonPanel("Help", "Previous", "Next", "Finish");
315
316 this.helpButton = buttons.getLeftButton();
317 this.helpButton.setEnabled(false);
318
319 this.previousButton = buttons.getRightButton1();
320 this.previousButton.setActionCommand("previousButton");
321 this.previousButton.addActionListener(this);
322 this.previousButton.setEnabled(false);
323
324 this.nextButton = buttons.getRightButton2();
325 this.nextButton.setActionCommand("nextButton");
326 this.nextButton.addActionListener(this);
327 this.nextButton.setEnabled(true);
328
329 this.finishButton = buttons.getRightButton3();
330 this.finishButton.setActionCommand("finishButton");
331 this.finishButton.addActionListener(this);
332 this.finishButton.setEnabled(false);
333
334 buttons.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
335 content.add(buttons, BorderLayout.SOUTH);
336
337 return content;
338 }
339
340 }