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 }