blob: 4bdc29cbff7bc7c56aaf82d92a3345f7b8d2323a [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Creating JFace Wizards</title>
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1252">
<link href="../article.css" type="text/css" rel="stylesheet">
</head>
<body>
<h1>Creating JFace Wizards</h1>
<div class="summary">
<h2>Summary</h2>
<p>This article shows you how to implement a wizard using the JFace
toolkit and how to contribute your wizard to the Eclipse workbench. A
wizard whose page structure changes according to user input is
implemented to demonstrate the flexibility of wizard support.</p>
<div class="author">By Doina Klinger, IBM UK</div>
<div class="copyright">Copyright &copy; 2002 International
Business Machines Corp.</div>
<div class="date">December 16, 2002 (Sample code updated July 2007
for Eclipse 3.3)</div>
</div>
<div class="content">
<h2>Introduction</h2>
<p>Wizards are used extensively throughout Eclipse. You can use
wizards to create a new Java class or new resources like Projects,
Folders or Files. A well designed wizard can considerably simplify user
tasks and increase productivity.</p>
<p>Wizards are meant to take the hassle out of standard, repetitive,
or tedious user tasks. For example, the Java New Class wizard can
collect enough information to generate a skeleton implementation of a
user's class, including package statements, constructors, inherited
methods, and other details. Of course, as the wizard developer, you must
implement the code that makes the wizard useful for your domain.</p>
<p>Not only does the platform contain many wizards, but there is a
lot of support for writing your own. The JFace wizard framework lets you
concentrate on the specifics of your wizard implementation. You will
need to use the <code>org.eclipse.jface.wizard</code> package of JFace.
It is very easy to get started while the support is flexible enough to
allow you to add more complex logic to your wizards.</p>
<h2>Wizard sample</h2>
<p>Our sample wizard will gather some holiday travel choices from
the user and collect more information based on the user's initial
choices. Information about the holiday is kept in a model data object
which is manipulated by the wizard page. The user's holiday data will be
displayed in an information dialog upon completion of the wizard.</p>
<h3>Running the Wizard</h3>
<p>To run the sample or view its source, unzip the <a
href="com.xyz.article.wizards.zip">com.xyz.article.wizards.zip</a>
(updated July 2007 for Eclipse 3.3) into your eclipse root directory and
restart the workbench. You can start the sample wizard from the New
button or from File&gt;New menu of the workbench (<a href="#NewMenu">Figure
5</a>). Alternatively, you can select the context menu of a folder (in any
perspective) and start the wizard from there (<a href="#PopupMenu">Figure
6</a>).</p>
<p>Let's look at our sample wizard in detail before diving into
details of implementing it. On the first page the users can select the
dates of travel, the type of transport for their holiday and enter the
departure and destination locations:</p>
<center><img border="0" src="wizards_files/mainPage.gif" alt=""><br>
Figure 1. Starting page of the wizard</center>
<p>The next page to be shown depends on the selected mode of
transport. If the user has selected travel by plane the following page
is displayed which shows the available flights. To keep the example code
simple this information will be hard coded, rather than obtained from
some database. The user can select the type of seat they want and to ask
for the ticket price by pushing the &quot;Get price&quot; button. The
base price is hard-coded as well. A discount is offered in conditions
explained <a href="#Discount">below</a>.</p>
<center><img border="0" src="wizards_files/plane.gif" alt=""><br>
Figure 2. Page displayed when the user has selected the plane</center>
<p>When the user has selected a flight and a type of seat the wizard
can be finished.</p>
<p>If the user has selected the car as mode of transport, a
different page is shown. The user can select the name of a rental
company. Based on the company name, the price of the rented car is
displayed. Once again, the prices are hard-coded and depend only on the
rental company selected but not on dates and destination. The user can
select whether to buy insurance from the rental company.</p>
<center><img border="0" src="wizards_files/car.gif" alt=""><br>
Figure 3. Page displayed when the user has selected the car.</center>
<p>When the user clicks Finish a message dialog is displayed
summarizing the holiday data collected from the user. The wizard
responds to various events and reports user errors.</p>
<p>This article explains the following:</p>
<ul>
<li>how to create, add and initialize wizard pages</li>
<li>how to listen for events and control errors</li>
<li>how to change the page order</li>
<li>what to do on completion of a wizard</li>
<li>how to start a wizard</li>
</ul>
<h2>Wizard Pages</h2>
<p>JFace provides the interfaces <code>org.eclipse.jface.wizard.IWizard</code>
and <code>org.eclipse.jface.wizard.IWizardPage</code> to describe
wizards and corresponding implementation classes that handle many of the
details of implementing wizards. Our wizard class HolidayWizard extends
<code>org.eclipse.jface.wizard.Wizard</code>, which is a useful abstract
class to extend. Its main responsibilities are to create the pages
inside the wizard and perform the work when the wizard is completed.</p>
<h3>Adding Pages to a Wizard</h3>
<p>Each page is instantiated and added to the wizard. The order in
which we add the pages to the wizard is the default navigation order.
The page which is added first will be the starting page when the wizard
is opened. Later we will look at ways of changing these defaults. The
corresponding method on the HolidayWizard class is shown below:</p>
<pre>public void addPages()
{
holidayPage = new HolidayMainPage(workbench, selection);
addPage(holidayPage);
planePage = new PlanePage(&quot;&quot;);
addPage(planePage);
carPage = new CarPage(&quot;&quot;);
addPage(carPage);
}</pre>
<h3>Creating the Controls</h3>
<p>First you need to decide which controls you want to use and then
how they should appear on the wizard page. Here is a quick guideline on
common widgets choices:</p>
<ul>
<li>text fields : use them when you cannot predict what the user
will enter. In our example, we let the users type in any holiday
destination they want.</li>
<li>combo boxes : use them to indicate a single selection from
several options. The user can select only one type of seat in the
plane: window, aisle or center.</li>
<li>lists: use them to display many options from which one or more
can be selected. We show the available flights in a list widget.</li>
<li>buttons: there are three styles of buttons in SWT.
<ul>
<li>checkboxes: use them to show options with clear
&quot;yes&quot; or &quot;no&quot; meaning. When you rent a car, you
either take the insurance from the rental company or you don't.</li>
<li>radio buttons: use them when you want the user to select one
options from two or more options. In our simplified model, you can
either travel by car or by plane.</li>
<li>push buttons: use them to trigger an event. The button on the
plane page retrieves the price for the flight.</li>
</ul>
</li>
</ul>
<p>Widgets of type <code>org.eclipse.swt.widgets.Composite</code>
are used to hold other widgets. To create a widget of one of the types
mentioned above, you call its constructor and pass the parent Composite
and a mask of bits indicating the style.</p>
<p>More information about various widgets can be found in the
Javadoc for <strong>org.eclipse.swt.widgets</strong>, and <a
href="http://help.eclipse.org/help33/topic/org.eclipse.platform.doc.isv/guide/swt.htm"
target="_blank"> SWT documentation</a>.</p>
<p>You will need to use layouts to give your wizard page a specific
look. A layout controls the position and size of children in a
Composite. In our sample, we use <span lang="EN-US"
style="mso-ansi-language: EN-US"><code>org.eclipse.swt.layout.GridLayout</code>,
which is one of the most flexible standard layouts. With a <code>GridLayout</code>,
the widget children of a <code>Composite</code> are laid out in a grid,
left to right, top to bottom. The <code>numColumns</code> specifies the
number of columns in the grid. GridData is the layout data object
associated with GridLayout. With a GridData object you can control
things like the widget's alignment, indent or span, horizontally and
vertically. Use <code>setLayoutData</code> method to set the grid data
of a widget</span>. For more details on layouts see the <a
href="http://www.eclipse.org/articles/Understanding%20Layouts/Understanding%20Layouts.htm"
target="_blank">Understanding Layouts</a> article.</p>
<p>We start by hand-drawing a rough sketch of each wizard page, to
find out the number of columns of the grid and the general look of the
page. For a better organization of the information on the page, we use
horizontal rules to separate related groups of input fields.</p>
<p>The place to create the page controls and arrange them on a page
is the <code>createControl</code> method or each wizard page. The method
is invoked once for each page when the wizard is first created with a
parameter of type Composite. A typical implementation of this method is
shown below. It does the following tasks::</p>
<ul>
<li>create a composite using the specified parent (<img border="0"
src="wizards_files/tag_1.gif" alt="">)</li>
<li>construct the widgets and, if necessary, their layout data
objects (<img border="0" src="wizards_files/tag_2.gif" alt="">)</li>
<li>construct the widgets and, if neccesary, their layout data
objects(<img border="0" src="wizards_files/tag_3.gif" alt="">)</li>
<li>set the composite as the control associated with the wizard
page (<img border="0" src="wizards_files/tag_4.gif" alt="">).</li>
</ul>
<p>Here is a simplified implementation of the createControl method
for the HolidayMainPage. Some details have been omitted for brevity.</p>
<pre>public void createControl(Composite parent) {
// create the composite to hold the widgets
<img border="0" src="wizards_files/tag_1.gif" alt=""> Composite composite = new Composite(parent, SWT.NONE);
// create the desired layout for this wizard page
<img border="0" src="wizards_files/tag_2.gif" alt=""> GridLayout gl = new GridLayout();
int ncol = 4;
gl.numColumns = ncol;
composite.setLayout(gl);
// create the widgets and their grid data objects
// Date of travel
<img border="0" src="wizards_files/tag_3.gif" alt=""> new Label (composite, SWT.NONE).setText("Travel on:");
travelDate = new Combo(composite, SWT.BORDER | SWT.READ_ONLY);
GridData gd = new GridData();
gd.horizontalAlignment = GridData.BEGINNING;
gd.widthHint = 25;
travelDate.setLayoutData(gd);
travelMonth = new Combo(composite, SWT.BORDER | SWT.READ_ONLY);
travelMonth.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
travelYear = new Combo(composite, SWT.BORDER | SWT.READ_ONLY);
travelYear.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// Similar widgets are constructed for date of return ...
createLine(composite, ncol);
// Departure
new Label (composite, SWT.NONE).setText("From:");
fromText = new Text(composite, SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = ncol - 1;
fromText.setLayoutData(gd);
// Similar for Destination ...
createLine(composite, ncol);
// Travel by plane
planeButton = new Button(composite, SWT.RADIO);
planeButton.setText("Take a plane");
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = ncol;
planeButton.setLayoutData(gd);
planeButton.setSelection(true);
// Similar for carButton ...
// set the composite as the control for this page
<img border="0" src="wizards_files/tag_4.gif" alt=""> setControl(composite);
}</pre>
<h3>Events</h3>
<p>Our wizard is not very useful if it is not able to respond to
changes and user interaction. The simplest way to register events on
wizard controls is to use the addListener method to register the wizard
page itself as the handler of the events.The wizard page must implement
the <code>org.eclipse.swt.widgets.Listener</code> interface with its
handleEvent method. Classes which implement this interface are described
within SWT as providing the <em>untyped listener</em> API. <code></code>The
listeners implement a simple <code>handleEvent(...)</code> method that
is used internally by SWT to dispatch events.</p>
<p>In our Plane page we want to know when the user interacts with
the &quot;Get price&quot; button, with the list of flights and with the
combo box that holds the seats choices. We add listeners in the
createControl method for these widgets.The untyped event mechanism uses
a constant to identify the type of event. In our case we are interested
in Selection type events for the widgets.</p>
<pre>public void createControl(Composite parent) {
// ...
// price button
priceButton = new Button(composite, SWT.PUSH);
priceButton.addListener(SWT.Selection, this);
// ...
// flights
flightsList = new List(composite, SWT.BORDER | SWT.READ_ONLY );
flightsList.addListener(SWT.Selection, this);
// ...
// seat choice
seatCombo = new Combo(composite, SWT.BORDER | SWT.READ_ONLY);
seatCombo.addListener(SWT.Selection, this);
// ...
}</pre>
<p>When the specified event occurs, the handleEvent method is
invoked for each registered listener. The listener, in our case the
WizardPage, implements a "case style" listener in which we check for
various fields of the event parameter (like its type or source) and
respond accordingly. For the PlanePage, we do some special action if the
priceButton has been selected, informing the user of the flight price.</p>
<pre><a href="#getPrice"></a>public void handleEvent(Event e) {
if (e.widget == priceButton) {
if (flightsList.getSelectionCount() &gt;0) {
if (((HolidayWizard)getWizard()).model.discounted)
price *= discountRate;
MessageDialog.openInformation(this.getShell(),&quot;&quot;, &quot;Flight price &quot;+ price);
}
}
//...
}</pre>
<h3>Processing Errors</h3>
<p>The data entered by the user on a wizard page can have a number
of errors caused by wrong choices or invalid values. Where appropriate,
we should disable the options which are not valid in order to prevent
such errors. Where this is not possible, we need to inform the user of
the error. When the user corrects it the error message needs to be
cleared.</p>
<p>In the sample we disallow destinations to be the same as the
departures (not much of a holiday, is it?). No travel back in time is
allowed either, so the date of return needs to be after the date of
travel. We won't check that the dates are correct. Hopefully you will
not find any flight on the 30th of February anyway.</p>
<center><img border="0" src="wizards_files/error.gif" alt=""><br>
Figure 4. Reporting an error to the user.</center>
<p>You can use the <code>setMessage</code> and <code>setErrorMessage</code>
methods to display information or error messages. The user can interact
with the controls in any order and, consequently, produce or clear
various errors. A common way to handle errors is to use a status
variable for each possible type of event which can create an error, a
warning or an information message.</p>
<p>The error handling for the first page is shown below. If the
destination or departure fields have triggered the event <img border="0"
src="wizards_files/tag_5.gif" alt="">, the the corresponding <code>org.eclipse.core.runtime.IStatus</code>
variable, is either set with an error if the two are the same or
cleared. If any of the date fields was modified <img border="0"
src="wizards_files/tag_6.gif" alt="">, we set the timeStatus
variable to the right value. At the end of each processing of an event <img
border="0" src="wizards_files/tag_7.gif" alt="">, we update the
page to display the most serious error message. This can be the first
error or the first warning if there is no error or null if the page is
correct. When the page is correct, we should see again the page
description. This is how the sample code looks:</p>
<pre>public void handleEvent(Event event) {
// Initialize a variable with the no error status
Status status = new Status(IStatus.OK, &quot;not_used&quot;, 0, &quot;&quot;, null);
// If the event is triggered by the destination or departure fields
// set the corresponding status variable to the right value
<img border="0" src="wizards_files/tag_5.gif" alt=""> if ((event.widget == fromText) || (event.widget == toText)) {
if (fromText.getText().equals(toText.getText()))
status = new Status(IStatus.ERROR, &quot;not_used&quot;, 0,
&quot;Departure and destination cannot be the same&quot;, null);
destinationStatus = status;
}
// If the event is triggered by any of the date fields set
// corresponding status variable to the right value
<img border="0" src="wizards_files/tag_6.gif" alt=""> if ((event.widget == returnDate) || (event.widget == returnMonth)
|| (event.widget == returnYear) || (event.widget == travelDate)
|| (event.widget == travelMonth) || (event.widget == travelYear)) {
if (isReturnDateSet() &amp;&amp; !validDates())
status = new Status(IStatus.ERROR, &quot;not_used&quot;, 0,
&quot;Return date cannot be before the travel date&quot;, null);
timeStatus = status;
}
// Show the most serious error
<img border="0" src="wizards_files/tag_7.gif" alt=""> applyToStatusLine(findMostSevere())
// ...
}</pre>
<h3>Navigation Buttons</h3>
<p>Using the JFace wizard support we can easily manage the
navigation buttons on the wizard pages. These buttons can be Finish and
Cancel if the wizard has one page, otherwise each wizard page has Back,
Next, Finish and Cancel. By default, Next is enabled for all but the
last page and Back for all pages but the first. .</p>
<p>For correct navigation we need to:</p>
<ol>
<li>implement the <code>canFlipToNextPage</code> method on the
page to return true when the user has selected/entered all the required
information on the current page.</li>
<li>overwrite the <code>canFinish</code> method of of the wizard
to return true when the wizard can be completed</li>
<li>ensure that the methods from above are called at the right
moment to enable/disable the Next and Finish buttons</li>
</ol>
<p>We look at each of these steps in a little more detail.</p>
<ol>
<li>
<p>To implement the canFlipToNextPage method for the first page of
our wizard, we first prevent the user from moving to the next page when
the page has any errors. When there are no errors, the destination and
departure fields are filled, the return date is set and a mode of
transport is selected, the user can move to the next page.</p>
<pre>public Boolean canFlipToNextPage(){
if (getErrorMessage() != null) return false;
if (isTextNonEmpty(fromText)&amp;&amp; isTextNonEmpty(toText) &amp;&amp; (planeButton.getSelection()
|| carButton.getSelection()) &amp;&amp; isReturnDateSet())
return true;
return false;
}</pre></li>
<li>Overwriting the canFinish method on the wizard class is useful
when some fields or entire pages are optional. When we have all the
required information for the current path through the wizard, canFinish
should true and the wizard can be completed at any moment after this.</li>
<li>You can force the update of the navigation buttons. The right
moment for this depends on your problem and the implementation of
canFlipToNextPage and canFinish methods. If we have registered
listeners for all type of events that can affect the enabled/disabled
status of Next and Finish button, then at the end of the event
processing method we force the redraw of the buttons:<pre>public void handleEvent(Event event) {
//...
getWizard().getContainer().updateButtons();
}</pre></li>
</ol>
<h2>Changing the Page Order</h2>
<p>We can change the order of the wizard pages by overwriting the <code>getNextPage</code>
method of any wizard page.Before leaving the page, we save in the model
the values chosen by the user. In our example, depending on the choice
of travel the user will next see either the page with flights or the
page for travelling by car.</p>
<pre><a name="initialize"></a>public IWizardPage getNextPage(){
saveDataToModel();
if (planeButton.getSelection()) {
PlanePage page = ((HolidayWizard)getWizard()).planePage;
<img border="0" src="wizards_files/tag_1.gif" alt=""> page.onEnterPage();
return page;
}
// Returns the next page depending on the selected button
if (carButton.getSelection()) {
return ((HolidayWizard)getWizard()).carPage;
}
return null;
}</pre>
<h2>Initializing widgets on wizard pages</h2>
<p>The widgets can be initialized based on constants, values
available on the start of the wizard or other user choices. We look at
each case more closely.</p>
<ul>
<li>constants: the widgets can be initialized immediately after
their creation. In the sample, we initialize the travel date with
today's date.</li>
<li>values available at the start of the wizard.
<p><a name="Discount"></a>In our example, if the user starts the
wizard when a folder called Discounts is selected, he will get 10% off
the price of flights (You would want to get discounts this way,
wouldn't you?). To achieve this, we need to overwrite the <code>init</code>
method on the wizard class. If the parameter representing the selection
is the special folder, we know that we'll offer a discount so we cache
this information.</p>
<pre>public void init(IWorkbench workbench, IStructuredSelection selection) {
this.workbench = workbench;
this.selection = selection;
if (selection != null && !selection.isEmpty()) {
Object obj = selection.getFirstElement();
if (obj instanceof IFolder) {
IFolder folder = (IFolder) obj;
if (folder.getName().equals("Discounts"))
model.discounted = true;
}
}
}</pre>
<p>In our example, we initialize the model data based on the
selection field and use it when displaying the flight price, see <a
href="#getPrice">above</a> . In other examples, we might need to
initialize controls on the page with the selection values.The controls
are not created when the init method is called, but we can initialize
them as soon as they are created with the cached value.</p>
<p>For wizards which are started by defining a wizard contribution
(see <a href="#startWizard">Starting a Wizard</a> section), the init
method is called by the platform, otherwise we need to call it
explicitly.</p>
</li>
<li>user choices</li>
</ul>
<p>We can initialize the values of some controls based on values for
other controls as defined by the user at runtime. For example, in the
CarPage we assign the value of the price field based on the rental
company that was selected</p>
<pre>public void handleEvent(Event e)
{
if (e.widget == companyCombo) {
if (companyCombo.getSelectionIndex() &gt;=0)
priceText.setText(&quot;£&quot;+prices[companyCombo.getSelectionIndex()]);
}
// ...
}</pre>
<p>In another example, the source widgets are on one page and the
widgets whose values are initialized belong to subsequent page. Such is
the case in our example, where the departure and destination from the
first page is used to show.</p>
<p>We define a method to do this initialization for the PlanePage,
onEnterPage and we invoke this method when moving to the PlanePage, that
is in the <a href="#initialize">getNextPage (<img border="0"
src="wizards_files/tag_1.gif" alt="">)</a> method for the first page.</p>
<h2>Actions on Completion of the Wizard</h2>
<p>To complete a wizard, the user can press either the Finish or the
Cancel buttons. If the Cancel button is pressed, the <code>performCancel</code>
method is called and you should overwrite this to cleanup any resources
allocated while running the wizard. The real work is done in <code>performFinish</code>.
In our case, this method is quite simple:</p>
<pre>public boolean performFinish()
{
String summary = model.toString();
MessageDialog.openInformation(workbench.getActiveWorkbenchWindow().getShell(),
"Holiday info", summary);
return true;
}</pre>
<p>If possible, it is always best to subclass from an existing
wizard or wizard page which performs a similar task. A good place to
look for such wizards for subclassing are <code>org.eclipse.ui.newresource</code>
package which provides standard wizards for creating files, folders, and
projects in the workspace and <code>org.eclipse.ui.wizards.datatransfer</code>
package for the standard Import and Export wizards for moving resources
into and out of the workspace. &nbsp;</p>
<p>For example, if we want to save the user choices in a file we
would have the first page inherit from the class <code>org.eclipse.ui.dialogs.WizardNewFileCreationPage</code>,
which is the standard main page for a wizard that creates a file
resource. We would inherit the actual file creation from the parent
class and could overwrite one of its method getInitialContents() to
return the user choices to be saved in the file.</p>
<p>The task to be completed at the end of the wizard could be a
complex operation that modifies many workspace resources, files, classes
or projects. This sort of operation could take a relatively long time.
To keep the workbench responsive to user input or to give the user the
possibility to cancel the operation we might want to run it in a
different thread. To achieve all these, we create a runnable which
performs the task and runs it in the context of the container of the
wizard.</p>
<pre>getContainer().run(forkable, canceleable, runnable);</pre>
<p>For more details on this subject see <a
href="http://help.eclipse.org/help33/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/jface/operation/package-summary.html"
target="_blank"> JFace operations documentation</a>.</p>
<h2><a name="startWizard"></a>Starting a Wizard</h2>
<p>You can start a wizard either by defining a wizard contribution
to the workbench or explicitly in your code. We will look at each of
these methods in turn.</p>
<h3>Defining a wizard contribution</h3>
<p>You can contribute to the extension points for wizards that
create new resources, import or export resources. When you select the
new, import, or export menu or when you press the new wizard button, the
workbench uses a wizard selection dialog to display all the wizards that
have been contributed for that particular extension point.&nbsp;</p>
<center>
<p><a name="NewMenu"></a><img border="0" src="wizards_files/newWizard.gif" alt=""></p>
Figure 5. Starting the wizard from the New</center>
<p>In our sample, we contribute to the new wizard extension point.
The relevant fragment from plugin.xml is :</p>
<pre>&lt;extension id=&quot;com.xyz.article.wizards&quot;
name=&quot;Holiday&quot;
point=&quot;org.eclipse.ui.newWizards&quot;&gt;
&lt;category
name=&quot;Article Wizards&quot;
id=&quot;com.xyz.article.wizards.category1&quot;&gt;
&lt;/category&gt;
&lt;wizard
name=&quot;Holiday Document&quot;
icon=&quot;icons/create.gif&quot;
category=&quot;com.xyz.article.wizards.category1&quot;
<img border="0" src="wizards_files/tag_1.gif" alt=""> class=&quot;com.xyz.article.wizards.HolidayDocumentWizard&quot;
id=&quot;com.xyz.article.wizards.wizard1&quot;&gt;
&lt;description&gt;
Creates a holiday document
&lt;/description&gt;
&lt;/wizard&gt;
&lt;/extension&gt;</pre>
<p>We define the category to which we add our wizard, the name,
description and icon that will be used. The most important entry in the
extension point is the class field( <img border="0"
src="wizards_files/tag_1.gif" alt="">) where we give the name of
our wizard class. A class used in this way must implement the (empty) <code>org.eclipse.ui.INewWizard</code>
interface. This is all we need to do in this case. Some details are
handled by the workbench as we will see below.</p>
<h2>Starting the Wizard Explicitly</h2>
<p>You may want to launch your wizard as a result of some action
that you have defined. Typically you use extension points that
contribute to various menus and toolbars in the workbench and want the
wizard to be started when the user interacts with these, for example
when pressing a button or selecting a menu option.</p>
<p>In our example, we use the popupMenu extension point for a folder
to start the wizard.</p>
<center>
<p><a name="PopupMenu"></a><img border="0" src="wizards_files/popup.gif" alt=""></p>
<p>Figure 6. Starting the wizard from the popup menu</p>
</center>
<p>In the plugin.xml we have:</p>
<pre> &lt;extension point=&quot;org.eclipse.ui.popupMenus&quot;&gt;
&lt;objectContribution
<img border="0" src="wizards_files/tag_2.gif" alt=""> objectClass=&quot;org.eclipse.core.resources.IFolder&quot;
id=&quot;com.xyz.article.wizards.popup1&quot;&gt;
&lt;action
label=&quot;Create holiday document&quot;
icon=&quot;icons/create.gif&quot;
<img border="0" src="wizards_files/tag_3.gif" alt=""> class=&quot;com.xyz.article.wizards.CreateWizardAction&quot;
id=&quot;com.xyz.article.wizards.action1&quot;&gt;
&lt;/action&gt;
&lt;/objectContribution&gt;
&lt;/extension&gt;</pre>
<p>The objectClass entry (<img border="0"
src="wizards_files/tag_2.gif" alt="">) defines the type of
objects to which this popupMenu will be added to, in our case a Folder.
The real work is done by the action class defined on <code><img
border="0" src="wizards_files/tag_3.gif" alt=""></code>. Its run method
is executed when the user selects this new item from the popup menu of a
folder. The other two methods on the action class, <code>setActivePart</code>
and <code>selectionChanged</code> cache the workbench part and the
selection fields respectively for use when the wizard is started, see <img
border="0" src="wizards_files/tag_4.gif" alt=""> below. For more
details on the popup menu extension point see the documentation.</p>
<p>When you are launching your own wizard, you need to wrap the
wizard in a <a
href="http://dev.eclipse.org/help20/content/help:/org.eclipse.platform.doc.isv/reference/api/org/eclipse/jface/wizard/WizardDialog.html"
target="_blank"><code>org.eclipse.jface.wizard.WizardDialog</code></a>.
A WizardDialog is a container that can host a wizard and display wizard
pages. It has a standard layout: an area at the top containing the
wizard's title, description, and image; the actual wizard page appears
in the middle; below it is a progress indicator; and at the bottom is an
area with a message line and a button bar containing Next, Back, Finish,
Cancel, and Help buttons.</p>
<p>The relevant code to start the wizard is:</p>
<pre> // Instantiates and initializes the wizard
HolidayWizard wizard = new HolidayWizard();
<img border="0" src="wizards_files/tag_4.gif" alt=""> wizard.init(part.getSite().getWorkbenchWindow().getWorkbench(),
(IStructuredSelection)selection);
// Instantiates the wizard container with the wizard and opens it
WizardDialog dialog = new WizardDialog(shell, wizard);
dialog.create();
dialog.open();</pre>
<h2>Resources</h2>
<p>We have seen how to implement a wizard, initialize its contents,
and perform actions on its completion. For further information about
wizards and controls, see the following resources:</p>
<p><a
href="http://dev.eclipse.org/help20/content/help:/org.eclipse.platform.doc.isv/guide/swt.htm"
target="_blank">Eclipse Platform Plug-in Developer Guide: Standard
Widget Toolkit (SWT)</a><br>
<a
href="http://dev.eclipse.org/help20/content/help:/org.eclipse.platform.doc.isv/guide/jface.htm"
target="_blank">Eclipse Platform Plug-in Developer Guide: JFace UI
Framework</a><br>
<a
href="http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html"
target="_blank">Article: Understanding Layouts in SWT (Revised for
2.0)</a></p>
</div>
</body>
</html>