001 /*
002 * Copyright 2002-2004 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package org.springframework.richclient.wizard;
017
018 import java.awt.Dimension;
019 import java.beans.PropertyChangeEvent;
020 import java.beans.PropertyChangeListener;
021
022 import javax.swing.JComponent;
023
024 import org.springframework.richclient.command.AbstractCommand;
025 import org.springframework.richclient.command.ActionCommand;
026 import org.springframework.richclient.core.UIConstants;
027 import org.springframework.richclient.dialog.DialogPage;
028 import org.springframework.richclient.dialog.Messagable;
029 import org.springframework.richclient.dialog.TitledApplicationDialog;
030 import org.springframework.richclient.util.GuiStandardUtils;
031 import org.springframework.util.Assert;
032
033 /**
034 * Dialog for wizards.
035 *
036 * @author Keith Donald
037 */
038 public class WizardDialog extends TitledApplicationDialog implements WizardContainer, PropertyChangeListener {
039 protected Wizard wizard;
040
041 protected ActionCommand nextCommand;
042
043 protected ActionCommand backCommand;
044
045 protected WizardPage currentPage;
046
047 protected int largestPageWidth;
048
049 protected int largestPageHeight;
050
051 public WizardDialog() {
052 this(null);
053 }
054
055 public WizardDialog(Wizard wizard) {
056 super();
057 setWizard(wizard);
058 setResizable(true);
059 }
060
061 public void setWizard(Wizard wizard) {
062 if (this.wizard != wizard) {
063 if (this.wizard != null) {
064 this.wizard.setContainer(null);
065 }
066 this.wizard = wizard;
067 if (this.wizard != null) {
068 this.wizard.setContainer(this);
069 this.setTitle(wizard.getTitle());
070 this.wizard.addPages();
071 }
072 }
073 }
074
075 protected String getFinishCommandId() {
076 return "finishCommand";
077 }
078
079 protected JComponent createTitledDialogContentPane() {
080 createPageControls();
081 WizardPage startPage = wizard.getStartingPage();
082 Assert.notNull(startPage, "No starting page returned; unable to show wizard.");
083 JComponent control = startPage.getControl();
084 if (getPreferredSize() == null) {
085 control.setPreferredSize(getLargestPageSize());
086 }
087 return control;
088 }
089
090 private Dimension getLargestPageSize() {
091 return new Dimension(largestPageWidth + UIConstants.ONE_SPACE, largestPageHeight + UIConstants.ONE_SPACE);
092 }
093
094 protected Object[] getCommandGroupMembers() {
095 if (!wizard.needsPreviousAndNextButtons()) {
096 return super.getCommandGroupMembers();
097 }
098 nextCommand = new ActionCommand("nextCommand") {
099 public void doExecuteCommand() {
100 onNext();
101 }
102 };
103 backCommand = new ActionCommand("backCommand") {
104 public void doExecuteCommand() {
105 onBack();
106 }
107 };
108 backCommand.setEnabled(false);
109 return new AbstractCommand[] { backCommand, nextCommand, getFinishCommand(), getCancelCommand() };
110 }
111
112 protected void onAboutToShow() {
113 showPage(wizard.getStartingPage());
114 super.onAboutToShow();
115 }
116
117 /**
118 * Allow the wizard's pages to pre-create their page controls. This allows
119 * the wizard dialog to open to the correct size.
120 */
121 private void createPageControls() {
122 WizardPage[] pages = wizard.getPages();
123 for (int i = 0; i < pages.length; i++) {
124 JComponent c = pages[i].getControl();
125 GuiStandardUtils.attachDialogBorder(c);
126 Dimension size = c.getPreferredSize();
127 if (size.width > largestPageWidth) {
128 largestPageWidth = size.width;
129 }
130 if (size.height > largestPageHeight) {
131 largestPageHeight = size.height;
132 }
133 }
134 }
135
136 public void showPage(WizardPage page) {
137 if (this.currentPage != page) {
138 if (this.currentPage != null) {
139 this.currentPage.removePropertyChangeListener(this);
140 }
141 this.currentPage = page;
142 this.currentPage.addPropertyChangeListener(this);
143 updateDialog();
144 setContentPane(page.getControl());
145 }
146 this.currentPage.onAboutToShow();
147 this.currentPage.setVisible(true);
148 }
149
150 public WizardPage getCurrentPage() {
151 return currentPage;
152 }
153
154 protected void onBack() {
155 WizardPage newPage = currentPage.getPreviousPage();
156 if (newPage == null || newPage == currentPage) {
157 throw new IllegalStateException("No such page.");
158 }
159 showPage(newPage);
160 }
161
162 protected void onNext() {
163 WizardPage newPage = currentPage.getNextPage();
164 if (newPage == null || newPage == currentPage) {
165 throw new IllegalStateException("No such page.");
166 }
167 showPage(newPage);
168 }
169
170 protected boolean onFinish() {
171 return wizard.performFinish();
172 }
173
174 protected void onCancel() {
175 if (wizard.performCancel()) {
176 super.onCancel();
177 }
178 }
179
180 /**
181 * Updates this dialog's controls to reflect the current page.
182 */
183 protected void updateDialog() {
184 if (!isControlCreated()) {
185 throw new IllegalStateException("Container controls not initialized - update not allowed.");
186 }
187
188 // Update the title pane
189 updateTitlePane();
190
191 // Update the message line
192 updateMessagePane();
193
194 // Update the buttons
195 updateButtons();
196 }
197
198 /**
199 * Updates the title bar (title, description, and image) to reflect the
200 * state of the currently active page in this container.
201 */
202 protected void updateTitlePane() {
203 setTitlePaneTitle(currentPage.getTitle());
204 setTitlePaneImage(currentPage.getImage());
205 setDescription(currentPage.getDescription());
206 }
207
208 /**
209 * Updates the message (or error message) shown in the message line to
210 * reflect the state of the currently active page in this container.
211 */
212 protected void updateMessagePane() {
213 setMessage(currentPage.getMessage());
214 }
215
216 private void updateButtons() {
217 if (wizard.needsPreviousAndNextButtons()) {
218 backCommand.setEnabled(currentPage.getPreviousPage() != null);
219 nextCommand.setEnabled(canFlipToNextPage());
220 }
221 setFinishEnabled(wizard.canFinish());
222 if (canFlipToNextPage() && !wizard.canFinish()) {
223 registerDefaultCommand(nextCommand);
224 }
225 else {
226 registerDefaultCommand();
227 }
228 }
229
230 private boolean canFlipToNextPage() {
231 return currentPage.canFlipToNextPage();
232 }
233
234 public void propertyChange(PropertyChangeEvent e) {
235 if (Messagable.MESSAGE_PROPERTY.equals(e.getPropertyName())) {
236 updateMessagePane();
237 }
238 else if (DialogPage.PAGE_COMPLETE_PROPERTY.equals(e.getPropertyName())) {
239 updateButtons();
240 }
241 else if (DialogPage.DESCRIPTION_PROPERTY.equals(e.getPropertyName())) {
242 updateTitlePane();
243 }
244 }
245 }