001: /*
002: * The contents of this file are subject to the Mozilla Public License
003: * Version 1.1 (the "License"); you may not use this file except in
004: * compliance with the License. You may obtain a copy of the License at
005: * http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
009: * License for the specific language governing rights and limitations
010: * under the License.
011: *
012: * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
013: *
014: * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
015: * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
016: *
017: * Contributor(s):
018: * Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
019: *
020: * If you didn't download this code from the following link, you should check
021: * if you aren't using an obsolete version: http://www.isqlviewer.com
022: */
023: package org.isqlviewer.ui;
024:
025: import java.awt.Color;
026: import java.awt.Component;
027: import java.awt.Dimension;
028: import java.awt.Font;
029: import java.awt.Frame;
030: import java.awt.GridBagConstraints;
031: import java.awt.GridBagLayout;
032: import java.awt.Insets;
033: import java.awt.event.ActionEvent;
034: import java.awt.event.ActionListener;
035: import java.awt.event.WindowEvent;
036: import java.util.Collection;
037:
038: import javax.swing.BorderFactory;
039: import javax.swing.Box;
040: import javax.swing.DefaultListCellRenderer;
041: import javax.swing.DefaultListModel;
042: import javax.swing.Icon;
043: import javax.swing.JButton;
044: import javax.swing.JDialog;
045: import javax.swing.JLabel;
046: import javax.swing.JList;
047: import javax.swing.JPanel;
048: import javax.swing.JSeparator;
049: import javax.swing.ListSelectionModel;
050: import javax.swing.SwingConstants;
051: import javax.swing.UIManager;
052: import javax.swing.WindowConstants;
053: import javax.swing.border.BevelBorder;
054:
055: import org.isqlviewer.swing.SwingUtilities;
056: import org.isqlviewer.swing.WizardPanel;
057: import org.isqlviewer.swing.action.SwingEventManager;
058: import org.isqlviewer.ui.wizards.Step;
059: import org.isqlviewer.ui.wizards.Wizard;
060: import org.isqlviewer.ui.wizards.WizardContext;
061: import org.isqlviewer.util.LocalMessages;
062:
063: /**
064: * Runtime environment for running wizard sub-systems.
065: * <p>
066: * This dialog window follows the wizard interface for showing step by step processes.
067: *
068: * @author Mark A. Kobold <mkobold at isqlviewer dot com>
069: * @version 1.0
070: */
071: public class WizardRunner extends JDialog implements ActionListener {
072:
073: private static final long serialVersionUID = -1030110039402276194L;
074:
075: private LocalMessages messages = new LocalMessages(
076: "org.isqlviewer.ui.ResourceBundle");
077:
078: private static final GridBagConstraints UI_CONSTRAINT = new GridBagConstraints(
079: 0, 0, 0, 0, 0, 0, 0, 0, new Insets(1, 1, 1, 1), 0, 0);
080:
081: private DefaultListModel steplistModel = new DefaultListModel();
082: private JList stepList = new JList(steplistModel);
083: private JButton nextButton = new JButton();
084: private JButton previousButton = new JButton();
085: private JButton cancelButton = new JButton();
086: private JButton homeButton = new JButton();
087:
088: private JLabel marqueeLabel = new JLabel();
089: private JLabel commentLabel = new JLabel();
090: private JLabel iconLabel = new JLabel();
091:
092: private JPanel bannerPanel = new JPanel(new GridBagLayout());
093: private JPanel navigationPanel = new JPanel(new GridBagLayout());
094:
095: private Wizard wizard = null;
096: private WizardContextImpl wizardContext = null;
097: private Step currentStep = null;
098: private JPanel stepContainer = new JPanel(new WizardPanel.Layout());
099:
100: public WizardRunner(Frame owner, Wizard wizard,
101: SwingEventManager eventManager) {
102:
103: super (owner, true);
104: if (wizard == null) {
105: throw new NullPointerException(Wizard.class.getName());
106: }
107: wizardContext = new WizardContextImpl(eventManager, this );
108: this .wizard = wizard;
109: initUI();
110: }
111:
112: public void actionPerformed(ActionEvent event) {
113:
114: Object source = event.getSource();
115: int index = stepList.getSelectedIndex();
116: if (source == nextButton) {
117: boolean isValid = false;
118: try {
119: isValid = currentStep.isValid(wizardContext);
120: } catch (Throwable t) {
121: wizardContext.showErrorDialog(this , t, "");
122: }
123: if (isValid) {
124: Step next = currentStep.getNext();
125: if (next == null) {
126: wizard.finish(wizardContext);
127: dispatchEvent(new WindowEvent(this ,
128: WindowEvent.WINDOW_CLOSING));
129: } else {
130: showStep(next);
131: stepList.setSelectedIndex(index + 1);
132: currentStep = next;
133: }
134: } else {
135: SwingUtilities.beep();
136: }
137: } else if (source == previousButton) {
138: Step previous = currentStep.getPrevious();
139: if (previous == null) {
140: wizard.finish(wizardContext);
141: } else {
142: stepList.setSelectedIndex(index - 1);
143: showStep(previous);
144: currentStep = previous;
145: }
146: } else if (source == homeButton) {
147: Step first = wizard.firstStep();
148: if (first == null) {
149: wizard.finish(wizardContext);
150: } else {
151: showStep(first);
152: currentStep = first;
153: }
154: } else if (source == cancelButton) {
155: wizard.finish(wizardContext);
156: dispatchEvent(new WindowEvent(this ,
157: WindowEvent.WINDOW_CLOSING));
158: }
159: }
160:
161: protected void setBanner(String text) {
162:
163: marqueeLabel.setText(text);
164: }
165:
166: protected void setComment(String text) {
167:
168: commentLabel.setText(text);
169: }
170:
171: protected void setIcon(Icon ico) {
172:
173: iconLabel.setIcon(ico);
174: }
175:
176: protected void startWizard() {
177:
178: currentStep = wizard.firstStep();
179: setTitle(wizard.getTitle());
180: steplistModel.addElement(currentStep);
181: Step current = currentStep;
182: while ((current = current.getNext()) != null) {
183: steplistModel.addElement(current);
184: }
185: stepList.setSelectedIndex(0);
186: showStep(currentStep);
187: }
188:
189: protected synchronized void showStep(Step step) {
190:
191: if (step == null) {
192: return;
193: }
194: setBanner(step.getTitle());
195: setComment(step.getComment());
196: setIcon(step.getImage());
197: previousButton.setEnabled(!step.isFirst());
198: if (step.isLast()) {
199: nextButton.setText(messages
200: .getMessage("wizardrunner.nav_finish.text"));
201: nextButton.setToolTipText(messages
202: .getMessage("wizardrunner.nav_finish.tip"));
203: } else {
204: nextButton.setText(messages
205: .getMessage("wizardrunner.nav_next.text"));
206: nextButton.setToolTipText(messages
207: .getMessage("wizardrunner.nav_next.tip"));
208: }
209: stepContainer.removeAll();
210: try {
211: step.activate(wizardContext);
212: } catch (Exception error) {
213: error.printStackTrace();
214: }
215: stepContainer.add(step.getView());
216: validateTree();
217: if (!SwingUtilities.isFrameModified(this ).booleanValue()) {
218: SwingUtilities.setFrameModified(this , Boolean.TRUE);
219: }
220: repaint();
221: }
222:
223: protected void setNextStepEnabled(boolean f) {
224:
225: nextButton.setEnabled(f);
226: }
227:
228: protected void setPreviousStepEnabled(boolean f) {
229:
230: previousButton.setEnabled(f);
231: }
232:
233: protected void setHomeAllowable(boolean f) {
234:
235: homeButton.setVisible(f);
236: homeButton.setEnabled(f);
237: }
238:
239: @Override
240: protected void processWindowEvent(WindowEvent e) {
241:
242: switch (e.getID()) {
243: case WindowEvent.WINDOW_OPENED:
244: startWizard();
245: break;
246: }
247: super .processWindowEvent(e);
248: }
249:
250: private void initUI() {
251:
252: setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
253: JPanel rootContentPanel = (JPanel) getContentPane();
254: rootContentPanel.setLayout(new WizardPanel.Layout());
255:
256: JPanel cp = new JPanel(new GridBagLayout());
257: rootContentPanel.add(cp);
258:
259: configureToolbar();
260: configureBanner();
261:
262: stepList.setBorder(BorderFactory
263: .createBevelBorder(BevelBorder.LOWERED));
264: stepList.setEnabled(false);
265: stepList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
266: stepList.setCellRenderer(new StepListCellRenderer());
267:
268: constrain(0, 0, 1, 3, 0.25, 1.0, GridBagConstraints.CENTER,
269: GridBagConstraints.BOTH);
270: cp.add(stepList, UI_CONSTRAINT);
271:
272: constrain(1, 0, 1, 3, 0.0, 0.0, GridBagConstraints.CENTER,
273: GridBagConstraints.BOTH);
274: cp.add(Box.createHorizontalStrut(5), UI_CONSTRAINT);
275:
276: constrain(2, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER,
277: GridBagConstraints.HORIZONTAL);
278: cp.add(bannerPanel, UI_CONSTRAINT);
279:
280: constrain(2, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
281: GridBagConstraints.BOTH);
282: cp.add(stepContainer, UI_CONSTRAINT);
283:
284: constrain(2, 2, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER,
285: GridBagConstraints.HORIZONTAL);
286: cp.add(navigationPanel, UI_CONSTRAINT);
287: wizard.init(wizardContext);
288:
289: setSize(new Dimension(620, 360));
290: setPreferredSize(getSize());
291: }
292:
293: private void configureToolbar() {
294:
295: homeButton.addActionListener(this );
296: previousButton.addActionListener(this );
297: nextButton.addActionListener(this );
298: cancelButton.addActionListener(this );
299:
300: homeButton.setText(messages
301: .getMessage("wizardrunner.nav_home.text"));
302: homeButton.setToolTipText(messages
303: .getMessage("wizardrunner.nav_home.tip"));
304: homeButton.setVisible(wizard.supportsHome());
305:
306: previousButton.setToolTipText(messages
307: .getMessage("wizardrunner.nav_previous.tip"));
308: previousButton.setText(messages
309: .getMessage("wizardrunner.nav_previous.text"));
310:
311: nextButton.setText(messages
312: .getMessage("wizardrunner.nav_next.text"));
313: nextButton.setToolTipText(messages
314: .getMessage("wizardrunner.nav_next.tip"));
315:
316: cancelButton.setText(messages
317: .getMessage("wizardrunner.nav_cancel.text"));
318: cancelButton.setToolTipText(messages
319: .getMessage("wizardrunner.nav_cancel.tip"));
320:
321: constrain(0, 0, 5, 1, 1.0d, 0.0d, GridBagConstraints.CENTER,
322: GridBagConstraints.HORIZONTAL);
323: navigationPanel.add(new JSeparator(SwingConstants.HORIZONTAL),
324: UI_CONSTRAINT);
325:
326: constrain(0, 1, 1, 1, 1.0d, 0.0d, GridBagConstraints.CENTER,
327: GridBagConstraints.HORIZONTAL);
328: navigationPanel.add(Box.createHorizontalGlue(), UI_CONSTRAINT);
329: constrain(1, 1, 1, 1, 0.0d, 0.0d, GridBagConstraints.EAST,
330: GridBagConstraints.NONE);
331: navigationPanel.add(homeButton, UI_CONSTRAINT);
332: constrain(2, 1, 1, 1, 0.0d, 0.0d, GridBagConstraints.EAST,
333: GridBagConstraints.NONE);
334: navigationPanel.add(previousButton, UI_CONSTRAINT);
335: constrain(3, 1, 1, 1, 0.0d, 0.0d, GridBagConstraints.EAST,
336: GridBagConstraints.NONE);
337: navigationPanel.add(nextButton, UI_CONSTRAINT);
338: constrain(4, 1, 1, 1, 0.0d, 0.0d, GridBagConstraints.EAST,
339: GridBagConstraints.NONE);
340: navigationPanel.add(cancelButton, UI_CONSTRAINT);
341: }
342:
343: private void configureBanner() {
344:
345: bannerPanel.setBorder(BorderFactory.createLineBorder(UIManager
346: .getColor("TextArea.foreground"), 1));
347: bannerPanel.setBackground(UIManager
348: .getColor("TextArea.background"));
349: bannerPanel.setForeground(UIManager
350: .getColor("TextArea.foreground"));
351: marqueeLabel.setFont(marqueeLabel.getFont().deriveFont(
352: Font.BOLD, 16f));
353: marqueeLabel.setForeground(bannerPanel.getForeground());
354: marqueeLabel.setBackground(bannerPanel.getBackground());
355: commentLabel.setFont(commentLabel.getFont().deriveFont(
356: Font.ITALIC, 12f));
357: commentLabel.setForeground(bannerPanel.getForeground());
358: commentLabel.setBackground(bannerPanel.getBackground());
359:
360: constrain(0, 0, 1, 2, 0.0d, 0.0d, GridBagConstraints.CENTER,
361: GridBagConstraints.NONE);
362: bannerPanel.add(Box.createHorizontalStrut(12), UI_CONSTRAINT);
363: constrain(0, 0, 2, 1, 1.0d, 0.0d, GridBagConstraints.WEST,
364: GridBagConstraints.HORIZONTAL);
365: bannerPanel.add(marqueeLabel, UI_CONSTRAINT);
366: constrain(1, 1, 1, 1, 1.0d, 0.0d, GridBagConstraints.WEST,
367: GridBagConstraints.HORIZONTAL);
368: bannerPanel.add(commentLabel, UI_CONSTRAINT);
369: constrain(2, 0, 1, 2, 0.0d, 0.0d, GridBagConstraints.CENTER,
370: GridBagConstraints.NONE);
371: bannerPanel.add(iconLabel, UI_CONSTRAINT);
372: constrain(3, 0, 1, 2, 0.0d, 0.0d, GridBagConstraints.CENTER,
373: GridBagConstraints.NONE);
374: bannerPanel.add(Box.createHorizontalStrut(12), UI_CONSTRAINT);
375: }
376:
377: protected static void constrain(int x, int y, int w, int h,
378: double wx, double wy, int a, int f) {
379:
380: UI_CONSTRAINT.gridx = x;
381: UI_CONSTRAINT.gridy = y;
382: UI_CONSTRAINT.gridwidth = w;
383: UI_CONSTRAINT.gridheight = h;
384: UI_CONSTRAINT.weightx = wx;
385: UI_CONSTRAINT.weighty = wy;
386: UI_CONSTRAINT.anchor = a;
387: UI_CONSTRAINT.fill = f;
388: }
389:
390: private static class WizardContextImpl extends WizardContext {
391:
392: WizardRunner reference = null;
393:
394: WizardContextImpl(SwingEventManager eventManager,
395: WizardRunner reference) {
396:
397: super (eventManager);
398: this .reference = reference;
399: }
400:
401: @Override
402: public void showErrorDialog(Throwable error, String message) {
403:
404: super .showErrorDialog(reference, error, message);
405: }
406:
407: @Override
408: public void showInformationDialog(String message) {
409:
410: super .showInformationDialog(reference, message);
411: }
412:
413: @Override
414: public void updateSteps(Collection<Step> newSteps) {
415:
416: Step currentStep = reference.currentStep;
417: DefaultListModel listModel = reference.steplistModel;
418:
419: int currentIndex = listModel.indexOf(currentStep);
420: try {
421: int fromIndex = currentIndex + 1;
422: int toIndex = listModel.getSize() - 1;
423: if (fromIndex <= toIndex) {
424: listModel.removeRange(fromIndex, toIndex);
425: }
426: } catch (ArrayIndexOutOfBoundsException ignored) {
427: debug("", ignored);
428: } catch (IllegalArgumentException ignored) {
429: debug("", ignored);
430: }
431: for (Step step : newSteps) {
432: listModel.addElement(step);
433: }
434: reference.pack();
435: }
436:
437: @Override
438: public void invokeNext() {
439:
440: reference.nextButton.doClick(0);
441: }
442: }
443:
444: private static class StepListCellRenderer extends
445: DefaultListCellRenderer {
446:
447: private static final long serialVersionUID = 1664986318928860084L;
448: static final Color selectedFocusedColor = Color
449: .decode("#3D80DF");
450:
451: @Override
452: public Component getListCellRendererComponent(JList list,
453: Object value, int index, boolean selected,
454: boolean hasFocus) {
455:
456: super .getListCellRendererComponent(list, value, index,
457: selected, hasFocus);
458: if (selected) {
459: setBackground(selectedFocusedColor);
460: setForeground(Color.WHITE);
461: }
462: if (index < list.getSelectedIndex()) {
463: setIcon(SwingUtilities
464: .loadIconResource("button_ok", 16));
465: } else {
466: setIcon(null);
467: }
468: Step step = (Step) value;
469:
470: setText(step.getTitle());
471: setToolTipText(step.getComment());
472: setEnabled(true);
473: return this;
474: }
475: }
476: }
|