How Wizards Work (Geertjan Wielenga)
https://blogs.oracle.com/geertjan/how-wizards-work-part-1:-introduction
Introduction

Wizards can be used for three things:
- To create a project template. This type of wizard is made available by the New Project wizard after registration in the layer.xml file (e.g., Web Application wizard).
- To create a file template. This type of wizard is made available by the New File wizard after registration in the layer.xml file:
- the template can consist of a single file (e.g., New Servlet wizard)
- the template can consist of multiple files (e.g., New Web Service wizard)
- To define properties. This type of wizard is made available by an action registered in the layer.xml file (e.g., Add Server Instance wizard).
The NetBeans APIs provide the following wizard classes:
In NetBeans IDE 5.0, you can use wizards to generate code for creating wizards that generate code... Here's the Wizard wizard:


Resources:
- Howto Implement Wizards Steps
- Optimization of java.awt.Component's initialization
- All classes in Dialogs API
- Javadoc for Dialogs API
- Wizard GuideBook
- NetBeans Architecture Answers for Dialogs API module
Different Types

When I was about 12, I used to be a big fan of the 'Choose Your Own
Adventure' books. They had titles like: "Prisoner of the Ant People" and
"The Magic of the Unicorn". On page 1, the scene would be set—for
example, you'd wake up smothered by vampires drinking your blood. What
do you do? And then the book would helpfully give you some options: "Run
around screaming? Turn to page 27." "Cut them off with the Sword of
Destiny? Turn to page 8." "Curse them under your breath? Turn to page
92." And then you'd obediently turn to the appointed page and walk into a
snake pit or find yourself parachuting behind enemy lines in wartime
France or find (yet another) Sword of Destiny.NetBeans
IDE 5.0 allows you to do the very same thing. (No, not parachute behind
enemy lines in wartime France.) But, it's almost just as
exciting—'Write Your Own Wizard' means, essentially, 'Create Your Own
Adventure'. You could do it the simple way—the user must work through a
page, click Next, work through the next page, click Next, work through
the next page, click Next, work through the final page, and then click
Finish. But life often isn't that simple. Martin Krauskopf (the creater
of the Wizard wizard in NetBeans IDE 5.0) sent me a few wizards that
illustrate the point really well. Here's an example of a simple wizard
(click to enlarge):

Here you can see that you can choose either 'Tea', 'Coffee', or 'Water'.
But only if you choose 'Tea' or 'Coffee' does it make sense to go to
the next page, which lets you say 'Yes' or 'No' to sugar. For this
reason, the first page implements the WizardDescriptor.FinishablePanel interface. By implementing this interface, you allow the Finish button to be enabled if 'Water' is selected:
public boolean isFinishPanel() {
return getDrinkType() == MenuVisualPanel1.WATER;
}
This is the only method required by the WizardDescriptor.FinishablePanel interface (in addition to those required by its superinterface, WizardDescriptor.Panel). However, the isValid() method must also be set to true, which is set to true by default. So, WizardDescriptor.FinishablePanel
enables you to end your adventure prematurely. There are many more
pages that you could work through, potentially, but why should you? You
chose water and it doesn't make sense to specify whether or not you want
sugar.
However, a cool thing about NetBeans is that each step in the wizard
consists of two components (kind of like how each web page in Wicket consists of two components): a Java class that implements WizardDescriptor.Panel (for example, WizardDescriptor.FinishablePanel, described above) and a Java class that implements JPanel. According to this document, "The WizardDescriptor.Panel subclass should reference the JPanel subclass, instantiate and return an instance of that class the first time its java.awt.Component getComponent()
method is called. This is the safest, performant and also the preferred
way to construct wizard steps." So, when you use the Wizard wizard,
this method is automatically generated for you in the WizardDescriptor.Panel subclass (which, in this case, was called MenuWizardPanel1, which is a name that correlates with the name of the visual panel instantiated below, although the names don't have to be similar at all):
public Component getComponent() {
if (component == null) {
component = new MenuVisualPanel1();
}
return component;
}
Similarly, the getDrinkType() method that is called in the isFinishPanel() method interacts with the visual component:
private int getDrinkType() {
return ((MenuVisualPanel1) component).getDrinkType();
}
However, note that irrespective of your choice, you have the same number
of pages. If there were a third page, you wouldn't be able to skip the
second. (And even if you choose 'Water', the Next button is always
enabled. Hmmm. Must be some way to disable the Next button.) Why can't
you skip pages? What happened to 'Choose Your Own Adventure?' How
adventurous does NetBeans let you be if you can't let the user skip
around from page to page? Good questions. And the answer is... the WizardDescriptor.Iterator interface. Here, for example, is what you could implement; thanks again to Martin for this wizard (click to enlarge):

Here you can see that only if you choose 'Drink' will Next take you to the Drink page (and only if
you choose Food will 'Next' bring you to the Food page). In terms of
the Wizard wizard, and the NetBeans APIs, the above scenario is
completely different to the previous one. In fact, when you use the
Wizard wizard, the first panel forces you to specify which wizard you
want (click to enlarge):

Above, if you choose 'Simple', you cannot let the user diverge from the
given number of steps (i.e, although it is possible to let the user
prematurely finish the wizard, using WizardDescriptor.FinishablePanel,
you cannot let the user skip a page). If you choose 'Variable', you can
let the user branch off as much as you allow. This means that in the
second scenario there's a lot more work for you than in the first. In
'Number of Steps' above, you specify the number of steps—i.e., for each
step you'll get two files, a Java class that implements WizardDescriptor.Panel and a Java class that implements JPanel. The interaction between these two was briefly outlined above (i.e., instantiation via the getComponent method and calling methods on the visual component from the WizardDescriptor.Panel class).
There's actually a lot more to say about wizards—here's just a few off the top of my head:
- The readSettings() and storeSettings() methods take care of the state.
- Iteration for 'Variable' wizards is via the generated WizardDescriptor.Iterator
subclass; for 'Simple' wizards, you just need to invoke the wizard and
the iteration is linear, so you don't need to provide an iterator. - There's a lot going on with change listeners.
The above are some of the things I need to look into before writing a tutorial on all of this...
Your First Wizard

The wizard described below consists of one panel. Therefore, it could
not possibly be simpler. However, creating this panel shows you some of
the central concepts involved in the creation of wizards using the
NetBeans APIs. The good thing is that most of the initial stages are
wizard-driven; the bad part is that the rest of it is a little tricky.
Most of the reason for this is that each panel is split over two
classes, for good reasons (described here),
but it doesn't make your life as a programmer much easier. Still, it's
great for performance, as the comments in the Wizard wizard's generated
code tells you—"if the wizard is created but never displayed, or not all
panels are displayed, it is better to create only those which really
need to be visible". So, each step in the wizard consists of a Visual
component (which consists of a 'Design' part and a 'Source' part),
subclassing JPanel and a Wizard component, subclassing the NetBeans API's WizardDescriptor.Panel. The WizardDescriptor.Panel subclass references the JPanel subclass, instantiates and returns an instance of that class the first time its java.awt.Component getComponent() method is called.The one-panel wizard created below lets you specify a preferred job location. Here are the steps to take:
-
Create a module project; with code name base org.myorg.simplewizard (Ctrl-Shift-N and then find it in the New Project wizard).
-
Right-click the project, choose New, choose Wizard. Make this selection:

If you're using NetBeans IDE 5.0 Beta, the panel above will look
different. (It's undergone quite a bit of change—not easy to make this
panel clear, a lot of consequences flow out of decisions made here.)
- Fill in 'MyDestination' in the next panel and complete the wizard.
You'll end up with something like this in the Projects window (the four
highlighted files are the only ones you'll be working with):

- Now the fun begins. Broadly, there are five tasks that need to be done:
- In the 'Design' part of the Visual component, design the wizard.
- In the 'Source' part of the Visual component, set values based on user choices.
- In the Wizard component, retrieve the current values from the Visual panel.
- In the action class, do something with the values set in the Visual Panel.
- In the layer.xml file, register the action class.
Here are some notes on each of the five tasks listed above:
- Design the panel. Use Matisse (yay! you can use Matisse when
designing the layout of modules) to add a button group, add three
buttons, change labels ('Hawaii', 'Tahiti, 'Bahamas', for example),
change names ('hawaii', 'tahiti', 'bahamas', for example), set first one
as selected, add a label ('Preferred job location:', for example). Add
the buttons to the button group. This is how it looks for me:

- Set values. In the Visual component, add these to the top of the code:
static final int BAHAMAS = 0;
static final int HAWAII = 1;
static final int TAHITI = 2;
static final String DESTINATION_LOCATION = "destlocation";
Add these lower down in the code:
int getDestLocation() {
return hawaii.isSelected() ? HAWAII : (bahamas.isSelected() ? BAHAMAS : TAHITI);
}
static String getAsString(int type) {
return type == HAWAII ? "Hawaii" : (type == BAHAMAS ? "Bahamas" : "Tahiti");
}
Change the getName() method so that it returns "Job Location" (this will be displayed in the left sidebar of the wizard).
- Pass the values. In the Wizard component, retrieve the values like this:
private int getDestinationLocationFromVisualPanel() {
return ((MyDestinationVisualPanel1) component).getDestLocation();
}
Then change the default storeSettings method to this:
public void storeSettings(Object settings) {
((WizardDescriptor) settings).putProperty(MyDestinationVisualPanel1.DESTINATION_LOCATION, Integer.valueOf(getDestinationLocationFromVisualPanel()));
}
- Do something with the values. In the action class, add this to the end of the performAction method:
if (!cancelled) {
StringBuffer message = new StringBuffer();
Integer destLocation = (Integer)
wizardDescriptor.getProperty(MyDestinationVisualPanel1.DESTINATION_LOCATION);
message.append("You're going to: " +
MyDestinationVisualPanel1.getAsString(destLocation.intValue()));
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(message.toString()));
}
Change the getName() method so that it returns "Job Seeker
Wizard" (this will be displayed as the action's label in the menu bar).
Do the same for the wizardDescriptor.setTitle in the peformAction() method; this sets the title of the wizard.
- Register the action class. Specify where/how the action class is to be invoked, by adding something like the following to the module's layer.xml:
<folder name="Actions">
<folder name="Build">
<file name="org-myorg-simplewizard-SampleAction.instance">
<attr name="instanceClass" stringvalue="org.myorg.simplewizard.SampleAction"/>
</file>
</folder>
</folder>
<folder name="Menu">
<folder name="Window">
<file name="org-myorg-simplewizard.SampleAction.shadow">
<attr name="originalFile" stringvalue="Actions/Build/org-myorg-simplewizard-SampleAction.instance"/>
</file>
</folder>
</folder>
Now install the module. Look for the action in the place where you registered it in the layer.xml (above, the action is registered as a menu item in the Window menu):

When you choose the menu item, you get the wizard:

When you click Finish, this dialog is displayed, showing your selection in the wizard:

Yay, you're done. Your first wizard.
Your Own Iterator

When you use the Wizard wizard to create files for a dynamic
wizard—because you want the user to be able to skip steps or to branch
off to a subset of the wizard steps—one of the files created for you
subclasses WizardDescriptor.InstantiatingIterator. This is the class that you use to define what the next step in the wizard will be, depending on the choices made by the user in the current and/or previous step. But a subclass of WizardDescriptor.InstantiatingIterator is also created for you when you make this selection in the Wizard wizard:

In this case, the wizard is invoked—not by an action, as in the case of
custom wizards—but by the New File wizard. When you select it in the New
File wizard, the wizard is invoked. So, in this case, since you have no
action, where do you put the code that specifies what happens at the
end of the wizard? In How Wizards Work (Part 3): Your First Wizard, the peformAction method contained this code:
if (!cancelled) {
StringBuffer message = new StringBuffer();
Integer destLocation = (Integer)
wizardDescriptor.getProperty(MyDestinationVisualPanel1.DESTINATION_LOCATION);
message.append("You're going to: " +
MyDestinationVisualPanel1.getAsString(destLocation.intValue()));
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(message.toString()));
}
But, now that we don't have an action, and therefore no performAction either, we fill out the iterator's instantiate() method (part of the default code generated by the Wizard wizard) instead:
public Set instantiate() throws IOException {
boolean cancelled = wizard.getValue() != wizard.FINISH_OPTION;
if (!cancelled) {
StringBuffer message = new StringBuffer();
Integer question = (Integer) wizard.getProperty(NewWizardVisualPanel1.QUIZ_QUESTION);
message.append("Your question: " + NewWizardVisualPanel1.getAsString(question.intValue()));
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(message.toString()));
}
return Collections.EMPTY_SET;
}
For the rest, the one-panel wizard works exactly as in How Wizards Work (Part 3): Your First Wizard. Here's what my new one-panel New File wizard looks like:

Reusing and Embedding Existing Panels

When you use the IDE to create a wizard, there are a few panels provided
by the IDE that you can reuse, instead of creating everything from
scratch yourself. For example, this panel is used over and over (all of
the IDE's file wizards have it), for setting the name and location for a
to-be-created file:

Instead of creating the above panel yourself, use the following steps to reuse it:
-
Create a module project and then add wizard files (use the 'Wizard' file type in the 'NetBeans Plug-in Modules' category).
-
Right-click the project node and use the Libraries node to add module
dependencies for 'Java project Support', 'Project API', and 'Project UI
API'. -
Everything else you'll need to do is done in the getPanels()
method of the iterator class. This is the default code provided by the
Wizard wizard (for a wizard with two panels and a prefix of 'NewFile'):
private WizardDescriptor.Panel[] getPanels() {
if (panels == null) {
panels = new WizardDescriptor.Panel[] {
new NewFileWizardPanel1(),
new NewFileWizardPanel2()
};
String[] steps = createSteps();
for (int i = 0; i > panels.length; i++) {
Component c = panels[i].getComponent();
if (steps[i] == null) {
// Default step name to component name of panel. Mainly
// useful for getting the name of the target chooser to
// appear in the list of steps.
steps[i] = c.getName();
}
if (c instanceof JComponent) { // assume Swing components
JComponent jc = (JComponent) c;
// Sets step number of a component
jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
// Sets steps names for a panel
jc.putClientProperty("WizardPanel_contentData", steps);
// Turn on subtitle creation on each step
jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
// Show steps on the left side with the image on the background
jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
// Turn on numbering of all steps
jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
}
}
}
return panels;
}
Add the following to the top of the method, click Alt-Shift-F, and choose org.netbeans.spi.project.ui.templates.support.Templates:
Project project = Templates.getProject(wizard);
Sources sources = (Sources)project.getLookup().lookup(Sources.class);
SourceGroup[] groups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
Add this above new NewFileWizardPanel1:
JavaTemplates.createPackageChooser(project,groups),
Again you will need to fix imports to get the right package imported at the top of the file.
So, if you used the Wizard wizard to create two panels, the iterator class will now contain this:
panels = new WizardDescriptor.Panel[] {
JavaTemplates.createPackageChooser(project,groups),
new NewFileWizardPanel1(),
new NewFileWizardPanel2()
};
Embedding a Panel
But, maybe you want the second panel to appear inside the first panel.
To do this, take the following steps (complete code is included at the
end of this blog entry):
- Declare a new panel at the top of the class:
private WizardDescriptor.Panel packageChooserPanel;
- Now define the panel in the class:
packageChooserPanel = JavaTemplates.createPackageChooser(project,groups);
- Specify that the panel should be created, and when; here, the panel is created before the other two:
panels = new WizardDescriptor.Panel[] {
packageChooserPanel,
new NewFileWizardPanel1(),
new NewFileWizardPanel2()
};
- However, if you define the panel as above, the one panel follows the
other panel. But, like this, you embed your own panel inside the one
provided by the IDE:
packageChooserPanel = JavaTemplates.createPackageChooser(project,groups,new NewFileWizardPanel1());
- And then all you need to do is this:
panels = new WizardDescriptor.Panel[] {
packageChooserPanel,
new NewFileWizardPanel2()
};
Embedding one panel inside another is a pattern that many wizards in the IDE follow. For example, here's the New JSP wizard:

Here you can see what seems to be one panel. However, it is in fact
two—the second is embedded inside the first. So this is what my getPanels() method looks like now (everything I added is highlighted below):
private WizardDescriptor.Panel[] getPanels() {Project project = Templates.getProject(wizard);
Sources sources = (Sources)project.getLookup().lookup(Sources.class);
SourceGroup[] groups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
packageChooserPanel = JavaTemplates.createPackageChooser(project,groups,new NewFileWizardPanel1());
if (panels == null) {
panels = new WizardDescriptor.Panel[] {packageChooserPanel,
new NewFileWizardPanel2()
};
String[] steps = createSteps();
for (int i = 0; i < panels.length; i++) {
Component c = panels[i].getComponent();
if (steps[i] == null) {
// Default step name to component name of panel. Mainly
// useful for getting the name of the target chooser to
// appear in the list of steps.
steps[i] = c.getName();
}
if (c instanceof JComponent) { // assume Swing components
JComponent jc = (JComponent) c;
// Sets step number of a component
jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
// Sets steps names for a panel
jc.putClientProperty("WizardPanel_contentData", steps);
// Turn on subtitle creation on each step
jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
// Show steps on the left side with the image on the background
jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
// Turn on numbering of all steps
jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
}
}
}
return panels;
}
Creating a File in a Package
In the Libraries panel of the Project Properties dialog box, declare module dependencies for 'Datasystems API', 'File System API', and 'Nodes API'. Then fill out the iterator class's instantiate() method as follows:
String className = Templates.getTargetName(wizard);
FileObject pkg = Templates.getTargetFolder(wizard);
DataFolder targetFolder = DataFolder.findFolder(pkg);
TemplateWizard template = (TemplateWizard)wizard;
DataObject doTemplate = template.getTemplate();
return Collections.EMPTY_SET;
That's it. At the end of the wizard, the class name and package name will be taken from the reused 'Name and Location' panel—and a package and file will be created for you.
If you add the following above the return statement, your newly created file will open in the Source Editor when you complete the wizard:
OpenCookie open = (OpenCookie) doTemplate.getCookie(OpenCookie.class);
if (open != null) {
open.open();
}
Creating Multiple Files
Here is the instantiate() method for a wizard that creates three files (using the specified class name as a prefix)—an HTML file, a Java source file, and a Java source file that has 'Application' appended on to the end of the classname:
public Set instantiate() throws IOException {
String className = Templates.getTargetName(wizard);
FileObject pkg = Templates.getTargetFolder(wizard);
DataFolder targetFolder = DataFolder.findFolder(pkg);
TemplateWizard template = (TemplateWizard)wizard;
DataObject doTemplate1 = template.getTemplate();
DataObject doTemplate2 = template.getTemplate();
DataObject doTemplate3 = template.getTemplate();
doTemplate1.createFromTemplate(targetFolder,className+".java");
doTemplate2.createFromTemplate(targetFolder,className+".html");
doTemplate3.createFromTemplate(targetFolder,className+"Application.java");
OpenCookie open = (OpenCookie) doTemplate1.getCookie(OpenCookie.class);
if (open != null) {
open.open();
}
return Collections.EMPTY_SET;
}
Using the above code, three files are created whenever I complete the wizard.