
com.pekinsoft.wizard.api.WizardDisplayer Maven / Gradle / Ivy
/* The contents of this file are subject to the terms of the Common Development
* and Distribution License (the License). You may not use this file except in
* compliance with the License.
* You can obtain a copy of the License at http://www.netbeans.org/cddl.html
* or http://www.netbeans.org/cddl.txt.
* When distributing Covered Code, include this CDDL Header Notice in each file
* and include the License file at http://www.netbeans.org/cddl.txt.
* If applicable, add the following below the CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]" */
package com.pekinsoft.wizard.api;
import com.pekinsoft.api.Exceptions;
import com.pekinsoft.framework.Application;
import com.pekinsoft.framework.ResourceMap;
import com.pekinsoft.lookup.Lookup;
import com.pekinsoft.wizard.api.displayer.WizardDisplayerImpl;
import com.pekinsoft.wizard.spi.Wizard;
import java.awt.Container;
import java.awt.Rectangle;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Action;
/**
* Displaying Wizards
* Factory which can display a `Wizard` in a dialog onscreen or in an ad-hoc
* container. Usage:
*
* Wizard wizard = WizardPage.createWizard (new Class[] {WizardPageSubclass1.class,
* WizardPageSubclass2.class, WizardPageSubclass3.class},
* new MyWizardResultProducer();
* WizardDisplayer.showWizard (wizard);
*
* Alternately you can implement `WizardPanelProvider` instead of
* `WizardPage` to provide the panels of the wizard.
*
* To use a `Wizard` in a `JInternalFrame` or similar, use
* `WizardDisplayer.installInContainer()`. You will need to implement
* `WizardResultReceiver` which will me notified when the wizard
* is finished or cancelled, to close the internal frame or whatever UI is
* showing the wizard.
*
*
Customizing the default implementation
* The image on the left panel of the default implementation can be customized
* in the following ways:
*
* - Put an instance of `java.awt.image.BufferedImage` into
* UIManager with the key `wizard.sidebar.image`, i.e.
*
* BufferedImage img = ImageIO.read (getClass().getResource ("MySideImage.png");
* UIManager.put ("wizard.sidebar.image", img);
*
*
* - Use the system property `wizard.sidebar.image` to set a path
* within a JAR on the classpath to the image. The image must be visible
* to the classloader which loads `WizardDisplayer`, so this
* may not work in environments which manage the classpath. i.e.
*
* System.setProperty ("wizard.sidebar.image", "com/foo/myapp/MySideImage.png");
*
*
*
*
*
Providing a custom WizardDisplayer:
* The implementation of `WizardDisplayer` is pluggable. While the
* default implementation should be adequate for most cases, it is possible
* that in some cases one might want to completely replace the UI, buttons,
* etc. with custom UI code. To do that:
*
* - If the NetBeans Lookup library (`org.openide.util.Lookup`
* is on the classpath, the default implementation will be found in
* the default lookup (i.e. META-INF/services, same as
* JDK 6's ServiceLoader)
* - If Lookup is not available or not found, `WizardDisplayer`
* will check the system
* property `WizardDisplayer.default` for a fully qualified
* class name of a subclass of `WizardDisplayer`.
*
* - If no other implementation of `WizardDisplayer` is found
* by the above methods, the default implementation contained in this
* library will be used.
*
*
* @author Tim Boudreau
*/
public abstract class WizardDisplayer {
protected WizardDisplayer() {
}
private static final String SYSPROP_KEY = "WizardDisplayer.default";
private static final Logger logger = Application.getInstance().getContext()
.getLogger(WizardDisplayer.class);
private static final ResourceMap resourceMap = Application
.getInstance()
.getContext()
.getResourceMap(WizardDisplayer.class);
/**
* Display a wizard in a dialog, using the default implementation of
* WizardDisplayer.
*
* @param wizard The wizard to show. Must not be {@code null}
* @param rect The rectangle on screen for the wizard, may be
* {@code null} for default size
* @param help An action to invoke if the user presses the help
* button
* @param initialProperties are the initial values for properties to be
* shown
* and entered in the wizard. May be {@code null}.
*/
public static Object showWizard(Wizard wizard, Rectangle rect, Action help,
Map initialProperties) {
// validate it
nonBuggyWizard(wizard);
WizardDisplayer defaultInstance = getDefault();
return defaultInstance.show(wizard, rect, help, initialProperties);
}
private static WizardDisplayer getDefault() {
WizardDisplayer factory = Lookup.getDefault().lookup(
WizardDisplayer.class);
if (factory == null) {
String wdProp = System.getProperty(SYSPROP_KEY);
if (wdProp != null) {
try {
factory = (WizardDisplayer) Class.forName(wdProp)
.newInstance();
} catch (ClassNotFoundException
| IllegalAccessException
| InstantiationException e) {
logger.log(Level.WARNING, "Could not instantiate {0}",
new Object[]{e, wdProp});
System.setProperty(SYSPROP_KEY, null);
(Lookup.getDefault().lookup(Exceptions.class)).print(e);
}
}
}
if (factory == null) {
factory = new WizardDisplayerImpl();
}
return factory;
}
/**
* Show a wizard with default window placement and no Help button
*/
public static Object showWizard(Wizard wizard) {
return showWizard(wizard, null, null, null);
}
/**
* Show a wizard with default window placement, showing the help button,
* which will invoke the passed action.
*
* @param wizard The wizard to show
* @param help An action to invoke if the user presses the help button
*
* @return The result of Wizard.finish()
*/
public static Object showWizard(Wizard wizard, Action help) {
return showWizard(wizard, null, help, null);
}
/**
* Show a wizard in the passed location on screen with no help button
*
* @param wizard The wizard to show
* @param r The rectangle on screen for the wizard
*
* @return The result of Wizard.finish()
*/
public static Object showWizard(Wizard wizard, Rectangle r) {
return showWizard(wizard, r, null, null);
}
/**
* Show a wizard.
*
* @param wizard the Wizard to show
* @param r the bounding rectangle for the wizard dialog on
* screen, {@code null} means "computed from first
* panel size"
* @param help An action to be called if the Help button is
* pressed
* @param initialProperties are used to set initial values for screens
* within the wizard.
* This may be {@code null}.
*
* @return Whatever object the wizard returns from its `finish()`
* method, if the Wizard was completed by the user.
*/
protected abstract Object show(Wizard wizard, Rectangle r, Action help,
Map initialProperties);
/**
* Install a panel representing a Wizard in a user-supplied container
* with a user-supplied layout constraint.
*
* @param c The container the wizard panel should be added
* to. May not
* be {@code null}.
* @param layoutConstraint The argument to use when adding the wizard's
* ui component to the container. May be {@code null}.
* @param helpAction An action that should be invoked when the help
* button
* is clicked (if null, no help button will be displayed)
* @param initialProperties A set of properties that should be pre-set upon
* entering the wizard. May be {@code null}.
* @param receiver An object which will be called when the Finish
* or
* Cancel buttons are pressed. May not be {@code null}.
*/
public static void installInContainer(Container c, Object layoutConstraint,
Wizard awizard, Action helpAction, Map initialProperties,
WizardResultReceiver receiver) {
getDefault().install(c, layoutConstraint, awizard, helpAction,
initialProperties, receiver);
}
/**
* Instance implementation of installInContainer().
*/
protected abstract void install(Container c, Object layoutConstraint,
Wizard awizard, Action helpAction, Map initialProperties,
WizardResultReceiver receiver);
private static boolean nonBuggyWizard(Wizard wizard) {
String[] s = wizard.getAllSteps();
if (new HashSet(Arrays.asList(s)).size() != s.length) {
throw new RuntimeException("steps are duplicated: "
+ Arrays.asList(s));
}
if (s.length == 1 && Wizard.UNDETERMINED_STEP.equals(s[0])) {
throw new RuntimeException("Only ID may not be UNDETERMINED_ID");
}
for (int i = 0; i < s.length; i++) {
if (Wizard.UNDETERMINED_STEP.equals(s[i]) && i != s.length - 1) {
throw new RuntimeException(
"UNDETERMINED_ID may only be last element in"
+ " ids array " + Arrays.asList(s)); //NOI18N)
}
}
return true;
}
}