Wizard Dialog

Creating Orana Wizards

Warning: This document is incomplete and is a work-in-progress.

This documentation is based on the 'Creating JFace Wizards' Eclipse article which can be found at http://www.eclipse.org/articles/Article-JFace%20Wizards/wizardArticle.html

Wizard Sample

This page will document the process of porting the wizard sample in the JFace article to Orana.

Creating a Moomba project

To make life simpler we will base this project on the simple Moomba plugin archetype described here. Once this project has been created import the project into Eclipse.

Adding the article files to the mix

Download the wizard sample code from the Eclipse article and unzip the project into a temporary directory.
Create a new package in the wizard project called 'com.xyz.article.wizards' and add all the source files to this package. You might aswell add the 2 image files to 'src/main/resource/image' also - we'll need them later.

Refactoring the JFace code to Orana

This section concentrates on refactoring the code to use Orana and Cooee instead of JFace and SWT so that it compiles properly.

HolidayModel.java

Luckily, because this is just a model and has no GUI references, no changes are required for this file.

HolidayAction.java

We're going to change this quite a bit because, unlike the example, we're going to add a simple Action to the Moomba workbench. The wizard example contributes a 'newWizard' to the Eclipse workbench which is something yet to be implemented in Moomba.
All we're interested in is an action that can display the wizard.

Replace the entire code with the following:

package com.xyz.article.wizards;

import org.karora.cooee.app.ImageReference;
import org.karora.cooee.app.ResourceImageReference;
import org.karora.moomba.ui.PlatformUI;
import org.karora.orana.action.Action;
import org.karora.orana.wizard.WizardDialog;

/**
 * Class associated with the popupMenu for the folder
 * Start the wizard in the run method
 */

public class HolidayAction extends Action 
{
	// Action unique ID
	public static final String ID = "org.karora.orana.wizard.HolidayAction";
	
	public String getActionDefinitionId() {
		return null;
	}

	public int getStyle() {
		return 0;
	}

	public boolean isToolBarAction() {
		return true;
	}

	public void setActionDefinitionId(String id) {
		
	}
	
	@Override
	public String getToolTipText()
	{
		return "Click me to go on holiday!!!";
	}
	
	@Override
	public ImageReference getImageDescriptor() {
		return new ResourceImageReference("image/wizard.gif");
	}                                  
	
	@Override
	public void run() {
		
		// Instantiates and initializes the wizard
		HolidayWizard wizard = new HolidayWizard();

		// Instantiates the wizard container with the wizard and opens it
		WizardDialog dialog = new WizardDialog( PlatformUI.getWorkbench().getActiveWorkbenchWindow().getWindow(), wizard);
		dialog.create();
		dialog.open(null);
	}

	@Override
	public String getText() {
		return "Wizard";
	}
	
	@Override
	public String getId() {
		return HolidayAction.ID;
	}
}

CarPage.java

The changes required in this file are all due to the differences between SWT and Cooee

  • Remove implements Listener from the class declaration.
  • Change the Combo, Text, and Button widgets to a SelectFieldEx, TextFieldEx, and CheckBoxEx respectively.
  • Remove the handleEvent method completely. We'll attach listeners directly to the controls.
  • Replace all occurrences of companyCombo.getText() with companyCombo.getSelectedItem().toString()
  • Replace insuranceButton.getSelection() with insuranceButton.isSelected()
  • Replace the createControl method with:
    public void createControl(Component parent) 
    {
    	Grid gl = new Grid(2);
    	parent.add(gl);
        
        // create the widgets. If the appearance of the widget is different from the default, 
        // create a GridData for it to set the alignment and define how much space it will occupy
        
        // rental company
        gl.add(new Label ("Rental company"));
        companyCombo = new SelectFieldEx(rentalCompanyNames);
        gl.add(companyCombo);
        companyCombo.addActionListener(new ActionListener() {
    
    		public void actionPerformed(ActionEvent arg0) {
    			if (companyCombo.getSelectedIndex() >=0)
    				priceText.setText("£"+prices[companyCombo.getSelectedIndex()]);
    			setPageComplete(isPageComplete());
    			getWizard().getContainer().updateButtons();		
    		}
        	
        });
    	    
    	    
        gl.add(new Label ("Price:"));
        priceText = new TextFieldEx();
    	    
        // insurance button
        insuranceButton = new CheckBoxEx("Buy insurance");
        gl.add(insuranceButton);
    	insuranceButton.setSelected(true);
        // set the composite as the control for this page
        setControl(gl);
    }
  • Remove all imports and then select 'Source/Organize Imports' from the editor popup menu.

PlanePage.java

Similarly to above, the changes required in this file are due to differences between SWT and Cooee

  • Remove implements Listener from the class declaration.
  • Change the List and Text widgets to a ListBoxEx and TextFieldEx respectively.
  • Remove the handleEvent method completely. We'll attach listeners directly to the controls.
  • Replace all occurrences of seatCombo.getText() with seatCombo.getSelectedItem().toString()
  • Replace the createControl method with:
    public void createControl(Component parent) {
    
        // create the desired layout for this wizard page
    	Grid gl = new Grid(2);
    	parent.add(gl);
    		
        // create the widgets. If the appearance of the widget is different from the default, 
        // create a GridData for it to set the alignment and define how much space it will occupy
    	    
        // flights list
    	Label label = new Label();
    	gl.add(label);
    	label.setText("Flights:");
    
    	// price button
    	priceButton = new PushButton();
    	gl.add(priceButton);
    	priceButton.setText("Get price");
    	priceButton.addActionListener(new ActionListener() {
    
    		public void actionPerformed(ActionEvent arg0) {
    			if (flightsList.getSelectedIndices().length >0) {
    				if (((HolidayWizard)getWizard()).model.discounted)
    					price *= discountRate;
    				MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getWindow(),"", "Flight price "+ price, null);
    			}
    			setPageComplete(isPageComplete());
    			getWizard().getContainer().updateButtons();
    		}
    	
    	});
    
    	flightsList = new ListBoxEx();
           GridLayoutData layoutData = new GridLayoutData();
           layoutData.setColumnSpan(2);
           flightsList.setLayoutData(layoutData);
           gl.add(flightsList);
            
    	// seat choice		
    	gl.add(new Label ("Seat choice:"));
    	seatCombo = new SelectFieldEx(seatChoices);
    	seatCombo.setSelectedIndex(0);
    	gl.add(seatCombo);
    
        // set the composite as the control for this page
    	setControl(gl);		
    	setPageComplete(true);
    }
  • In isPageComplete replace:
    flightsList.getSelectionCount() == 0

    with

    flightsList.getSelectedIndices().length == 0
  • In saveDataToModel replace:
    flightsList.getSelection()[0];

    with

    flightsList.getSelectedValue().toString();
  • In onEnterPage replace:
    flightsList.removeAll();
    flightsList.add(text1);
    flightsList.add(text2);

    with

    DefaultListModel listModel = (DefaultListModel)flightsList.getModel();
    listModel.removeAll();
    listModel.add(text1);
    listModel.add(text2);
  • Remove all imports and then select 'Source/Organize Imports' from the editor popup menu.

HolidayMainPage.java

  • Remove implements Listener from the class declaration.
  • Change all occurrences of the Combo, Text, and planeButton/carButton Button widgets to a SelectFieldEx, TextFieldEx, and RadioButtonEx respectively.
  • Replace all occurrences of getSelectionIndex to getSelectedIndex
  • Replace all occurrences of getText for SelectFieldEx components to getSelectedIndex.toString()
  • Replace all occurrences of getSelection with isSelected for the RadioButtonEx
  • Remove the handleEvent method completely. And replace with the following ActionListener:
    private ActionListener actionListener = new ActionListener() {
    
    	public void actionPerformed(ActionEvent arg0) {
    	    // Initialize a variable with the no error status
    	    Status status = new Status(IStatus.OK, "not_used", 0, "", null);
    	    
    		String command = arg0.getActionCommand(); 
    		if(command.equals("travelDate") || command.equals("travelMonth")
    				|| command.equals("travelYear") || command.equals("returnDate")
    				|| command.equals("returnMonth") || command.equals("returnYear"))
    		{
    			if(isReturnDateSet() && !validDates()) 
    		            status = new Status(IStatus.ERROR, "not_used", 0, 
    		                "Return date cannot be before the travel date", null);	                
    		    timeStatus = status;
    		} else if(command.equals("fromText") || command.equals("toText"))
    		{
    		       	if (fromText.getText().equals(toText.getText()) && !"".equals(fromText.getText()))
    		           		status = new Status(IStatus.ERROR, "not_used", 0, 
    		               	"Departure and destination cannot be the same", null);        
    		       	destinationStatus = status;
    		}
    		
    	    // Show the most serious error
    	    applyToStatusLine(findMostSevere());
    		getWizard().getContainer().updateButtons();
    	}
    	
    };
  • Also replace the contents of addListeners with:
    planeButton.setActionCommand("planeButton");
    planeButton.addActionListener(actionListener);
    carButton.setActionCommand("carButton");
    carButton.addActionListener(actionListener);
    fromText.setActionCommand("fromText");
    fromText.addActionListener(actionListener);
    toText.setActionCommand("toText");
    toText.addActionListener(actionListener);
    
    travelDate.setActionCommand("travelDate");
    travelDate.addActionListener(actionListener);
    travelMonth.setActionCommand("travelMonth");
    travelMonth.addActionListener(actionListener);
    travelYear.setActionCommand("travelYear");
    travelYear.addActionListener(actionListener);
    returnDate.setActionCommand("returnDate");
    returnDate.addActionListener(actionListener);
    returnMonth.setActionCommand("returnMonth");
    returnMonth.addActionListener(actionListener);
    returnYear.setActionCommand("returnYear");
    returnYear.addActionListener(actionListener);
  • Replace all occurrences of seatCombo.getText() with seatCombo.getSelectedItem().toString()
  • Replace the createControl method with:
    public void createControl(Component parent) {
    
        // create the composite to hold the widgets
    	Grid gd = new Grid();
    	parent.add(gd);
    
        // create the desired layout for this wizard page
    	Grid gl = new Grid(4);
    	gd.add(gl);
    
    	// initial value for date of travel, today's date
    	Calendar cal = Calendar.getInstance();
    	cal.setTime(new Date());
    	int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
    	int month = cal.get(Calendar.MONTH);
    	int year = cal.get(Calendar.YEAR);
    
    		
        // create the widgets. If the appearance of the widget is different from the default, 
        // create a GridData for it to set the alignment and define how much space it will occupy		
    	    	    
        // Date of travel
    	gl.add(new Label ("Travel on:"));						
    	travelDate = new SelectFieldEx(dates);
    	gl.add(travelDate);
    	travelDate.setSelectedIndex(dayOfMonth -1); // 0 based indexes
    
    	travelMonth = new SelectFieldEx(months);
    	gl.add(travelMonth);
    	travelMonth.setSelectedIndex(month);
    
    	travelYear = new SelectFieldEx(years);
    	gl.add(travelYear);
    	travelYear.setSelectedIndex(year - startingYear);
    
    
    	// Date of return		
    	gl.add(new Label ("Return on:"));		
    	returnDate = new SelectFieldEx(dates);
    	gl.add(returnDate);
    
    	returnMonth = new SelectFieldEx(months);
    	gl.add(returnMonth);
    
    	returnYear = new SelectFieldEx(years);
    	gl.add(returnYear);
    
    	createLine(gd, 4);
    
    	// Departure				
    	gl.add(new Label ("From:"));				
    	fromText = new TextFieldEx();
    	gl.add(fromText);
    		
    	// Destination
    	gl.add(new Label ("To:"));				
    	toText = new TextFieldEx();
    	gl.add(toText);
    
    	createLine(gl, 4);
    
    	// Choice of transport		
    	ButtonGroup bg = new ButtonGroup();
    	planeButton = new RadioButtonEx();
    	gl.add(planeButton);
    	planeButton.setGroup(bg);
    	planeButton.setText("Take a plane");
    	planeButton.setSelected(true);
    		
    	carButton = new RadioButtonEx();
    	gl.add(carButton);
    	carButton.setGroup(bg);
    	carButton.setText("Rent a car");
    		
        // set the composite as the control for this page
    	setControl(gl);		
    	addListeners();
    }
  • Remove all imports and then select 'Source/Organize Imports' from the editor popup menu.

HolidayWizard.java

Remove all the imports from the top of the file and then select 'Source/Organize Imports' from the editor popup menu. This will replace all Eclipse/JFace/SWT imports with Moomba/Orana/Cooee imports. Clever eh?
There will still be a few errors because of some slight differences in the APIs of Eclipse and Moomba.

  • MessageDialog.openInformation(workbench.getActiveWorkbenchWindow().getShell(), "Holiday info", summary);
    with
    MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getWindow(), "Holiday info", summary, null);
  • Remove the entire init method (this override is yet to be implemented in Orana)

Adding Spring-OSGi configuration

Add the following Spring bean configuration to the src/main/resources/META-INF/spring/bundle-context.xml file to declare the HolidayAction bean:

<bean name="HolidayAction" class="com.xyz.article.wizards.HolidayAction" singleton="false"/>

And then add the following Spring-OSGi service configuration to the src/main/resources/META-INF/spring/bundle-context-osgi.xml file to declare the bean as an Moomba IAction OSGi service.

<osgi:service ref="HolidayAction" interface="org.karora.orana.action.IAction" />

Configuring the MANIFEST.MF

Because the example wizard code has dependencies on some core equinox libraries, we'll have to add the required packages to the Import-Package section of the MANIFEST.MF file

org.eclipse.core.runtime
org.eclipse.core.internal.runtime

Building and Deploying

Build the project using mvn package and copy the built jar into your runtime. You can find a pre-packaged runtime here

Labels

 
(None)