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    }