| <!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 © 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>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 "Get price" 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(""); |
| addPage(planePage); |
| carPage = new CarPage(""); |
| 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 |
| "yes" or "no" 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 "Get price" 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 name="#getPrice"></a>public void handleEvent(Event e) { |
| if (e.widget == priceButton) { |
| if (flightsList.getSelectionCount() >0) { |
| if (((HolidayWizard)getWizard()).model.discounted) |
| price *= discountRate; |
| MessageDialog.openInformation(this.getShell(),"", "Flight price "+ 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, "not_used", 0, "", 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, "not_used", 0, |
| "Departure and destination cannot be the same", 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() && !validDates()) |
| status = new Status(IStatus.ERROR, "not_used", 0, |
| "Return date cannot be before the travel date", 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)&& isTextNonEmpty(toText) && (planeButton.getSelection() |
| || carButton.getSelection()) && 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() >=0) |
| priceText.setText("£"+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. </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. </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><extension id="com.xyz.article.wizards" |
| name="Holiday" |
| point="org.eclipse.ui.newWizards"> |
| <category |
| name="Article Wizards" |
| id="com.xyz.article.wizards.category1"> |
| </category> |
| <wizard |
| name="Holiday Document" |
| icon="icons/create.gif" |
| category="com.xyz.article.wizards.category1" |
| <img border="0" src="wizards_files/tag_1.gif" alt=""> class="com.xyz.article.wizards.HolidayDocumentWizard" |
| id="com.xyz.article.wizards.wizard1"> |
| <description> |
| Creates a holiday document |
| </description> |
| </wizard> |
| </extension></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> <extension point="org.eclipse.ui.popupMenus"> |
| <objectContribution |
| <img border="0" src="wizards_files/tag_2.gif" alt=""> objectClass="org.eclipse.core.resources.IFolder" |
| id="com.xyz.article.wizards.popup1"> |
| <action |
| label="Create holiday document" |
| icon="icons/create.gif" |
| <img border="0" src="wizards_files/tag_3.gif" alt=""> class="com.xyz.article.wizards.CreateWizardAction" |
| id="com.xyz.article.wizards.action1"> |
| </action> |
| </objectContribution> |
| </extension></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://help.eclipse.org/ganymede/index.jsp?topic=/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://help.eclipse.org/ganymede/index.jsp?topic=/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://help.eclipse.org/ganymede/index.jsp?topic=/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> |