001: /**
002: * Wizard Framework
003: * Copyright 2004 - 2005 Andrew Pietsch
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: *
019: * $Id: Wizard.java,v 1.23 2007/09/26 15:17:29 perrydillard Exp $
020: */package org.pietschy.wizard;
021:
022: import java.awt.BorderLayout;
023: import java.awt.Color;
024: import java.awt.Component;
025: import java.awt.Dialog;
026: import java.awt.Dimension;
027: import java.awt.Frame;
028: import java.awt.Graphics;
029: import java.awt.Image;
030: import java.awt.Insets;
031: import java.awt.Window;
032: import java.awt.event.WindowAdapter;
033: import java.awt.event.WindowEvent;
034: import java.beans.PropertyChangeEvent;
035: import java.beans.PropertyChangeListener;
036: import java.beans.PropertyVetoException;
037: import java.util.Iterator;
038:
039: import javax.swing.Action;
040: import javax.swing.BorderFactory;
041: import javax.swing.Icon;
042: import javax.swing.JComponent;
043: import javax.swing.JDesktopPane;
044: import javax.swing.JDialog;
045: import javax.swing.JFrame;
046: import javax.swing.JInternalFrame;
047: import javax.swing.JOptionPane;
048: import javax.swing.JPanel;
049: import javax.swing.JSeparator;
050: import javax.swing.JWindow;
051: import javax.swing.RootPaneContainer;
052: import javax.swing.SwingUtilities;
053: import javax.swing.border.AbstractBorder;
054: import javax.swing.event.InternalFrameAdapter;
055: import javax.swing.event.InternalFrameEvent;
056:
057: /**
058: * The wizard class is the main entry point for creating wizards. Typically you will create
059: * the wizard with your own {@link WizardModel} implementation and then call {@link Wizard#showInFrame}
060: * or one of the releated methods.
061: * <p>
062: * In the simplest case, you would subclass {@link org.pietschy.wizard.models.StaticModel} and add a number
063: * of {@link WizardStep} instances.
064: * <pre>
065: * StaticModel model = new StaticModel();
066: * model.add(new MyFirestStep());
067: * model.add(...);
068: * ...
069: *
070: * Wizard wizard = new Wizard(model);
071: * wizard.showInFrame("My Wizard");
072: * </pre>
073: *
074: * @see org.pietschy.wizard.models.StaticModel
075: * @see org.pietschy.wizard.models.DynamicModel
076: * @see org.pietschy.wizard.models.MultiPathModel
077: */
078: public class Wizard extends JPanel {
079: protected static final int BORDER_WIDTH = 8;
080:
081: /**
082: * When specified as the {@link #setDefaultExitMode(int) defaultExitMode}, this
083: * causes the wizard to continue displaying the final step after finished has been pressed. The
084: * wizard is closed when the user presses the close button. This allows the wizard to display a
085: * final confirmation screen.
086: *
087: * @see #EXIT_ON_FINISH
088: */
089: public static final int EXIT_ON_CLOSE = 1;
090:
091: /**
092: * When specified as the {@link #setDefaultExitMode(int) defaultExitMode}, this
093: * causes the wizard to exit immediately once finish is pressed and
094: * {@link WizardStep#applyState()} has been invoked.
095: *
096: * @see #EXIT_ON_CLOSE
097: */
098: public static final int EXIT_ON_FINISH = 2;
099:
100: private NextAction nextAction;
101: private PreviousAction previousAction;
102: private LastAction lastAction;
103: private FinishAction finishAction;
104: private CancelAction cancelAction;
105: private CloseAction closeAction;
106: private HelpAction helpAction;
107:
108: private HelpBroker helpBroker;
109:
110: private WizardStep activeStep;
111: private WizardModel model;
112: private int defaultExitMode = EXIT_ON_CLOSE;
113:
114: private JComponent titleComponent;
115: private ButtonBar buttonBar;
116: private JPanel viewPanel;
117: private JPanel mainContainer;
118: private JPanel overviewContainer;
119:
120: private boolean overviewVisible = true;
121:
122: private boolean canceled = false;
123:
124: private PropertyChangeListener viewListener = new PropertyChangeListener() {
125: public void propertyChange(PropertyChangeEvent evt) {
126: handleViewChange();
127: }
128: };
129:
130: /**
131: * Creates a new Wizard that uses the specified {@link WizardModel}.
132: *
133: * @param model the model that the wizard is to use.
134: */
135: public Wizard(WizardModel model) {
136: if (model == null)
137: throw new NullPointerException("models is null");
138:
139: this .model = model;
140: this .model
141: .addPropertyChangeListener(new PropertyChangeListener() {
142: public void propertyChange(PropertyChangeEvent evt) {
143: if (evt.getPropertyName().equals("activeStep")) {
144: handleStepChange();
145: }
146: }
147: });
148:
149: nextAction = new NextAction(this );
150: previousAction = new PreviousAction(this );
151: lastAction = new LastAction(this );
152: finishAction = new FinishAction(this );
153: cancelAction = new CancelAction(this );
154: closeAction = new CloseAction(this );
155: helpAction = new HelpAction(this );
156:
157: // initialize all the wizard steps.
158: for (Iterator iter = model.stepIterator(); iter.hasNext();) {
159: ((WizardStep) iter.next()).init(this .model);
160: }
161:
162: setLayout(new BorderLayout());
163:
164: titleComponent = createTitleComponent();
165: buttonBar = createButtonBar();
166:
167: mainContainer = new JPanel(new BorderLayout());
168: overviewContainer = new JPanel(new BorderLayout());
169:
170: viewPanel = new JPanel(new BorderLayout());
171: viewPanel.setPreferredSize(calculatePreferredStepSize());
172: mainContainer.add(titleComponent, BorderLayout.NORTH);
173: JPanel p = new JPanel(new BorderLayout());
174: p.setBorder(BorderFactory.createEmptyBorder(BORDER_WIDTH,
175: BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH));
176: p.add(viewPanel, BorderLayout.CENTER);
177: mainContainer.add(p, BorderLayout.CENTER);
178: // mainContainer.add(buttonBar, BorderLayout.SOUTH);
179: JPanel commandPanel = new JPanel(new BorderLayout());
180: commandPanel.add(new JSeparator(JSeparator.HORIZONTAL),
181: BorderLayout.NORTH);
182: commandPanel.add(buttonBar, BorderLayout.CENTER);
183: mainContainer.add(commandPanel, BorderLayout.SOUTH);
184:
185: if (model instanceof OverviewProvider) {
186: p = new JPanel(new BorderLayout());
187: p.setBorder(BorderFactory.createCompoundBorder(
188: BorderFactory.createEmptyBorder(0, 0, 0, 2),
189: BorderFactory.createEtchedBorder()));
190: // p.setBorder(new OverviewBorder());
191: p.add(((OverviewProvider) model).getOverviewComponent(),
192: BorderLayout.CENTER);
193: overviewContainer.add(p, BorderLayout.WEST);
194: //overviewContainer.add(Box.createVerticalStrut(buttonBar.getPreferredSize().height + BORDER_WIDTH), BorderLayout.SOUTH);
195: }
196:
197: add(mainContainer, BorderLayout.CENTER);
198: add(overviewContainer, BorderLayout.WEST);
199:
200: configureOverviewContainer();
201:
202: if (model instanceof HelpBroker)
203: setHelpBroker((HelpBroker) model);
204:
205: this .model.reset();
206: }
207:
208: /**
209: * Set the time when the wizard exits. The two allowable values are
210: * {@link #EXIT_ON_FINISH} and {@link #EXIT_ON_CLOSE}.
211: * <p>
212: * The default value is {@link #EXIT_ON_CLOSE}
213: *
214: * @param defaultExitMode the default exit mode.
215: */
216: public void setDefaultExitMode(int defaultExitMode) {
217: if (defaultExitMode != EXIT_ON_FINISH
218: && defaultExitMode != EXIT_ON_CLOSE)
219: throw new IllegalArgumentException();
220:
221: this .defaultExitMode = defaultExitMode;
222: }
223:
224: /**
225: * Gets the exit mode of the wizard, being either {@link #EXIT_ON_FINISH} or
226: * {@link #EXIT_ON_CLOSE}
227: *
228: * @return the default close opertation.
229: */
230: public int getDefaultExitMode() {
231: return defaultExitMode;
232: }
233:
234: /**
235: * Called by the constructor to create the wizards title component. The default component will be an instance of
236: * {@link DefaultTitleComponent} but subclasses may override to provide a custom implementation. Typically the
237: * title component listens to the wizard model and updates its appearance accordingly.
238: *
239: * @return the wizards title component.
240: * @see #getTitleComponent()
241: */
242: protected JComponent createTitleComponent() {
243: return new DefaultTitleComponent(this );
244: }
245:
246: /**
247: * Gets the component being used to render the wizards title. By default this will be an instance of
248: * {@link DefaultTitleComponent}. Subclasses can change the default by overriding {@link #createTitleComponent()}.
249: * <p>
250: * For example, to activate the gradient background on the default title component you can call.
251: * <pre>
252: * ((DefaultTitleComponent) wizard.getTitleComponent()).setGradientBackground(true);
253: * </pre>
254: *
255: * @return the wizards title component.
256: */
257: public JComponent getTitleComponent() {
258: return titleComponent;
259: }
260:
261: /**
262: * Called by the constructor to create the button bar. Subclasses may override to provide a custom {@link ButtonBar}
263: * implementation.
264: *
265: * @return the wizards {@link ButtonBar}.
266: */
267: protected ButtonBar createButtonBar() {
268: return new ButtonBar(this );
269: }
270:
271: /**
272: * Resets the wizard. This method delegates directly to {@link WizardModel#reset}.
273: */
274: public void reset() {
275: canceled = false;
276: getModel().reset();
277: };
278:
279: /**
280: * Gets the models this wizard is using.
281: *
282: * @return the wizard models.
283: */
284: public WizardModel getModel() {
285: return model;
286: }
287:
288: /**
289: * Checks the visibily of the overview panel that is displayed on the wizards left
290: * panel. The overview panel will only be displayed if this property is <tt>true</tt> and
291: * the current {@link WizardModel} implements {@link OverviewProvider}.
292: */
293: public boolean isOverviewVisible() {
294: return overviewVisible;
295: }
296:
297: /**
298: * Checks the ability of the wizard to be resized. The wizard is resizable if
299: * this method returns <tt>true</tt>, otherwise it cannot be resized.
300: */
301: protected boolean isResizable() {
302: return true;
303: }
304:
305: /**
306: * Configures the visibily of the overview panel that is displayed on the wizards left
307: * panel. This method will only have an effect if the current {@link WizardModel} implements
308: * {@link OverviewProvider}.
309: *
310: * @param overviewVisible <tt>true</tt> to display the overview, <tt>false</tt> otherwise.
311: */
312: public void setOverviewVisible(boolean overviewVisible) {
313: if (this .overviewVisible != overviewVisible) {
314: boolean old = this .overviewVisible;
315: this .overviewVisible = overviewVisible;
316: firePropertyChange("overviewVisible", old, overviewVisible);
317: configureOverviewContainer();
318: }
319: }
320:
321: private void configureOverviewContainer() {
322: overviewContainer.setVisible(overviewVisible
323: && model instanceof OverviewProvider);
324: }
325:
326: public void setHelpBroker(HelpBroker broker) {
327: HelpBroker old = this .helpBroker;
328: this .helpBroker = broker;
329: firePropertyChange("helpBroker", old, broker);
330: }
331:
332: public HelpBroker getHelpBroker() {
333: return helpBroker;
334: }
335:
336: /**
337: * Returns the action that is bound to the next button.
338: */
339: public Action getNextAction() {
340: return nextAction;
341: }
342:
343: /**
344: * Returns the action that is bound to the previous button.
345: */
346: public Action getPreviousAction() {
347: return previousAction;
348: }
349:
350: /**
351: * Returns the action that is bound to the last button.
352: */
353: public Action getLastAction() {
354: return lastAction;
355: }
356:
357: /**
358: * Returns the action that is bound to the showCloseButton button.
359: */
360: public Action getFinishAction() {
361: return finishAction;
362: }
363:
364: /**
365: * Returns the action that is bound to the cancel button.
366: */
367: public Action getCancelAction() {
368: return cancelAction;
369: }
370:
371: /**
372: * Returns the action that is bound to the close button.
373: */
374: public Action getHelpAction() {
375: return helpAction;
376: }
377:
378: /**
379: * Returns the action that is bound to the close button.
380: */
381: public Action getCloseAction() {
382: return closeAction;
383: }
384:
385: /**
386: * Marks this wizard as finished. This will cause the button bar to only display
387: * the close button.
388: */
389: protected void showCloseButton() {
390: buttonBar.showCloseButton(true);
391: }
392:
393: /**
394: * Cancels this wizard. This method simply fires the {@link WizardListener#wizardCancelled}
395: * event.
396: */
397: public void cancel() {
398: WizardStep activeStep = getModel().getActiveStep();
399: if (activeStep != null && activeStep.isBusy()) {
400: if (!confirmAbort())
401: return;
402:
403: activeStep.abortBusy();
404: }
405:
406: canceled = true;
407: fireWizardCancelled();
408: }
409:
410: /**
411: * Checks if the wizard was canceled. This method will return <tt>false</tt> unless the user
412: * canceled the wizard.
413: *
414: * @return <tt>true</tt> if the user canceled the wizard, <tt>false</tt> otherwise.
415: */
416: public boolean wasCanceled() {
417: return canceled;
418: }
419:
420: /**
421: * This method is called when the user cancels the wizard while the {@link #activeStep} is
422: * {@link WizardStep#isBusy busy}. This method displays a {@link JOptionPane} asking if the
423: * user wants to abort the wizard.
424: *
425: * @return <tt>true</tt> if the user confirms the abort, <tt>false</tt> otherwise.
426: */
427: protected boolean confirmAbort() {
428: int response = JOptionPane.showConfirmDialog(this ,
429: "Cancel the currently active task?", "Abort",
430: JOptionPane.YES_NO_CANCEL_OPTION);
431: return response == JOptionPane.YES_OPTION;
432: }
433:
434: /**
435: * Closes this wizard. This method simply fires the {@link WizardListener#wizardClosed}
436: * event.
437: */
438: public void close() {
439: fireWizardClosed();
440: }
441:
442: /**
443: * Adds a {@link WizardListener} to this wizard.
444: *
445: * @param l the listener to add.
446: */
447: public void addWizardListener(WizardListener l) {
448: listenerList.add(WizardListener.class, l);
449: }
450:
451: /**
452: * Removes a {@link WizardListener} from this wizard.
453: *
454: * @param l the listener to remove.
455: */
456: public void removeWizardListener(WizardListener l) {
457: listenerList.remove(WizardListener.class, l);
458: }
459:
460: /**
461: * Handles a change in the {@link WizardModel} active step.
462: */
463: private void handleStepChange() {
464:
465: if (activeStep != null) {
466: activeStep.removePropertyChangeListener("view",
467: viewListener);
468: }
469:
470: activeStep = model.getActiveStep();
471:
472: activeStep.addPropertyChangeListener("view", viewListener);
473:
474: activeStep.prepare();
475: handleViewChange();
476: }
477:
478: /**
479: * Handles changes in the current {@link WizardStep}s view.
480: */
481: private void handleViewChange() {
482: viewPanel.removeAll();
483: viewPanel.add(activeStep.getView(), BorderLayout.CENTER);
484: viewPanel.revalidate();
485: viewPanel.repaint();
486: }
487:
488: /**
489: * Caculates the preferred size of the main wizard area based on the {@link WizardStep#getPreferredSize}
490: * values of all the wizard steps.
491: */
492: private Dimension calculatePreferredStepSize() {
493: int w = 0;
494: int h = 0;
495:
496: for (Iterator iter = getModel().stepIterator(); iter.hasNext();) {
497: WizardStep step = (WizardStep) iter.next();
498: Dimension d = step.getPreferredSize();
499:
500: w = Math.max(d.width, w);
501: h = Math.max(d.height, h);
502: }
503:
504: return new Dimension(w, h);
505: }
506:
507: private void fireWizardClosed() {
508: // Guaranteed to return a non-null array
509: Object[] listeners = listenerList.getListenerList();
510:
511: WizardEvent event = null;
512:
513: // Process the listeners last to first, notifying
514: // those that are interested in this event
515: for (int i = listeners.length - 2; i >= 0; i -= 2) {
516: if (listeners[i] == WizardListener.class) {
517: // Lazily create the event:
518: if (event == null)
519: event = new WizardEvent(this );
520: ((WizardListener) listeners[i + 1]).wizardClosed(event);
521: }
522: }
523:
524: }
525:
526: private void fireWizardCancelled() {
527: // Guaranteed to return a non-null array
528: Object[] listeners = listenerList.getListenerList();
529:
530: WizardEvent event = null;
531:
532: // Process the listeners last to first, notifying
533: // those that are interested in this event
534: for (int i = listeners.length - 2; i >= 0; i -= 2) {
535: if (listeners[i] == WizardListener.class) {
536: // Lazily create the event:
537: if (event == null)
538: event = new WizardEvent(this );
539: ((WizardListener) listeners[i + 1])
540: .wizardCancelled(event);
541: }
542: }
543:
544: }
545:
546: /**
547: * Displays the wizard in a new {@link JFrame} with the specified title. The frame will
548: * be automatically closed when the wizard is completed or canceled. This method will
549: * not block.
550: *
551: * @param title the title of the frame.
552: * @see #addWizardListener
553: * @see #removeWizardListener
554: */
555: public void showInFrame(String title) {
556: showInFrame(title, null, null);
557: }
558:
559: /**
560: * Displays the wizard in a new {@link JFrame} with the specified title. The frame will
561: * be automatically closed when the wizard is completed or canceled. This method will
562: * not block.
563: *
564: * @param title the title of the frame.
565: * @param windowIcon the icon to use for the frame. This is used to configure {@link javax.swing.JFrame#setIconImage(java.awt.Image)}.
566: * @see #addWizardListener
567: * @see #removeWizardListener
568: */
569: public void showInFrame(String title, Image windowIcon) {
570: showInFrame(title, windowIcon, null);
571: }
572:
573: /**
574: * Displays the wizard in a new {@link JFrame} with the specified title. The frame will
575: * be automatically closed when the wizard is completed or canceled. This method will
576: * not block.
577: *
578: * @param title the title of the frame.
579: * @param relativeTo the new {@link JFrame} will be displayed relative to this component. If
580: * the component is <tt>null</tt>, the window will be centered on the
581: * desktop as per {@link JWindow#setLocationRelativeTo(java.awt.Component)}.
582: * @see #addWizardListener
583: * @see #removeWizardListener
584: */
585: public void showInFrame(String title, Component relativeTo) {
586: showInFrame(title, null, relativeTo);
587: }
588:
589: /**
590: * Displays the wizard in a new {@link JFrame} with the specified title. The frame will
591: * be automatically closed when the wizard is completed or canceled. This method will
592: * not block.
593: *
594: * @param title the title of the frame.
595: * @param windowIcon the icon to use for the frame. This is used to configure {@link javax.swing.JFrame#setIconImage(java.awt.Image)}.
596: * @param relativeTo the new {@link JFrame} will be displayed relative to this component. If
597: * the component is <tt>null</tt>, the window will be centered on the
598: * desktop as per {@link JWindow#setLocationRelativeTo(java.awt.Component)}.
599: * @see #addWizardListener
600: * @see #removeWizardListener
601: */
602: public void showInFrame(String title, Image windowIcon,
603: Component relativeTo) {
604: JFrame window = new JFrame(title);
605: window.setResizable(isResizable());
606: window.setIconImage(windowIcon);
607: showInWindow(window, relativeTo);
608: }
609:
610: /**
611: * Displays the wizard in a new {@link JDialog} with the specified title. The dialog will
612: * be automatically closed when the wizard is completed or canceled. This method will
613: * block if the dialog is modal.
614: *
615: * @param title the dialog title.
616: * @param parent the component that will own the dialog.
617: * @param modal <tt>true</tt> to make the dialog modal, <tt>false otherwise</tt>.
618: * @see #addWizardListener
619: * @see #removeWizardListener
620: */
621: public void showInDialog(String title, Component parent,
622: boolean modal) {
623:
624: JDialog dialog = null;
625: if (parent != null) {
626: Window w = (parent instanceof Window) ? (Window) parent
627: : SwingUtilities.getWindowAncestor(parent);
628:
629: if (w instanceof Frame) {
630: dialog = new JDialog((Frame) w, title, modal);
631: } else if (w instanceof Dialog) {
632: dialog = new JDialog((Dialog) w, title, modal);
633: } else {
634: throw new IllegalArgumentException(
635: "Parent component must be within a Frame or Dialog");
636: }
637:
638: if (parent instanceof Window) {
639: dialog = createDialogFor((Window) parent, title, modal);
640: } else {
641: dialog = createDialogFor(SwingUtilities
642: .getWindowAncestor(parent), title, modal);
643: }
644: } else {
645: dialog = new JDialog();
646: dialog.setResizable(isResizable());
647: dialog.setModal(modal);
648: dialog.setTitle(title);
649: }
650:
651: dialog.setLocationRelativeTo(parent);
652: showInWindow(dialog, parent);
653: }
654:
655: private JDialog createDialogFor(Window window, String title,
656: boolean modal) {
657: if (window == null)
658: throw new NullPointerException("window is null");
659:
660: JDialog dialog = null;
661: if (window instanceof Frame) {
662: dialog = new JDialog((Frame) window, title, modal);
663: } else if (window instanceof Dialog) {
664: dialog = new JDialog((Dialog) window, title, modal);
665: }
666:
667: return dialog;
668: }
669:
670: /**
671: * Displays this wizard in the specified {@link Window} that is positioned relative to the
672: * specified component.
673: *
674: * @param window the window that will contain the wizard.
675: * @param relativeTo the component used to position the window. If the component is <tt>null</tt>,
676: * the window will be centered on the desktop as per
677: * {@link JWindow#setLocationRelativeTo(java.awt.Component)}.
678: */
679: private void showInWindow(Window window, Component relativeTo) {
680: ((RootPaneContainer) window).getContentPane().add(this );
681: window.addWindowListener(new WindowAdapter() {
682: public void windowClosing(WindowEvent e) {
683: cancel();
684: }
685: });
686:
687: WizardFrameCloser.bind(this , window);
688: window.pack();
689: window.setLocationRelativeTo(relativeTo);
690: window.setVisible(true);
691: window.toFront();
692: }
693:
694: /**
695: * Displays the wizard in a new {@link JFrame} with the specified title. The frame will
696: * be automatically closed when the wizard is completed or canceled. This method will
697: * not block.
698: *
699: * @param title the title of the frame.
700: * @param desktopPane the desktop in which to display the wizard.
701: * @see #addWizardListener
702: * @see #removeWizardListener
703: */
704: public void showInInternalFrame(String title, Icon frameIcon,
705: JDesktopPane desktopPane) {
706: showInInternalFrame(title, frameIcon, true, true, true, true,
707: desktopPane);
708: }
709:
710: /**
711: * Displays the wizard in a new {@link JFrame} with the specified title. The frame will
712: * be automatically closed when the wizard is completed or canceled. This method will
713: * not block.
714: *
715: * @param title the title of the frame.
716: * @param resizable if <code>true</code>, the internal frame can be resized
717: * @param closable if <code>true</code>, the internal frame can be closed
718: * @param maximizable if <code>true</code>, the internal frame can be maximised
719: * @param iconifiable if <code>true</code>, the internal frame can be iconified
720: *
721: * @param desktopPane the desktop in which to display the wizard.
722: * @see #addWizardListener
723: * @see #removeWizardListener
724: */
725: public void showInInternalFrame(String title, Icon frameIcon,
726: boolean resizable, boolean closable, boolean maximizable,
727: boolean iconifiable, JDesktopPane desktopPane) {
728: JInternalFrame frame = new JInternalFrame(title, resizable,
729: closable, maximizable, iconifiable);
730: frame.setResizable(isResizable());
731: frame.setFrameIcon(frameIcon);
732: frame.getContentPane().add(this );
733: frame.addInternalFrameListener(new InternalFrameAdapter() {
734: public void internalFrameClosing(InternalFrameEvent event) {
735: cancel();
736: }
737: });
738:
739: WizardInternalFrameCloser.bind(this , frame);
740: frame.pack();
741: desktopPane.add(frame);
742: frame.setVisible(true);
743: try {
744: frame.setSelected(true);
745: } catch (PropertyVetoException e) {
746: }
747:
748: }
749:
750: private class OverviewBorder extends AbstractBorder {
751: private int width = 5;
752: private Insets insets = new Insets(0, 0, 0, 2);
753:
754: public boolean isBorderOpaque() {
755: return true;
756: }
757:
758: public void paintBorder(Component c, Graphics g, int x, int y,
759: int width, int height) {
760: Color old = g.getColor();
761:
762: g.setColor(Color.BLACK);
763:
764: g.drawLine(x + width - 1, y, x + width - 1, y + height);
765:
766: g.setColor(old);
767: }
768:
769: public Insets getBorderInsets(Component c) {
770: return insets;
771: }
772: }
773: }
|