Table of Contents

1. Eclipse RCP
1.1. Overview
1.2. Eclipse RCP Architecture - Plugins, Extensions and Extension-Points
1.3. Main components of an Eclipse RCP application
1.4. Application versus Product
1.5. Important files
2. Installation
3. Create your first RCP application
3.1. Create a RCP application
3.2. Start your RCP application
4. Run configuration
4.1. Overview
4.2. Check your runtime configuration
4.3. Important Parameters
5. Commands
5.1. Overview
5.2. Defining commands
5.3. Using commands in menus
6. System Tray
7. Views
7.1. Overview
7.2. Create a view
7.3. Add the view to your perspective.
7.4. Result
7.5. Add view to perspective via code
8. Working with Editors, View Interaction and Model Updates
8.1. Overview
8.2. Create project
8.3. Create and prepare the domain model
8.4. Content and Label provider
8.5. Use the domain model in the view
8.6. Editor area
8.7. Editor Input
8.8. Adding the editor
8.9. Creating a command for calling the editor
8.10. Calling the editor
9. Dialog
9.1. Overview
9.2. Using standard dialogs
9.3. Selection
9.4. User defined dialogs
10. Field Assist
11. Wizards
11.1. Overview
11.2. Example
12. Adding a status line
12.1. Setup Status line
12.2. Shared Status Line
13. Perspectives
13.1. Adding a perspective to your application
13.2. Select the perspective
14. Progress report
15. Integrating external jars / third party libraries
15.1. Overview
15.2. Create a plugin project for your jar
16. Products and Branding
16.1. Product Configuration
16.2. Create a project
16.3. Create your product configuration
16.4. Maintain the overview tab
16.5. Maintain the configuration tab
16.6. Test your product
16.7. Splash Screen
16.8. Branding the about Dialog
16.9. Customizing the start icon and launcher arguments
16.10. Done
17. Deploy your product
18. Externalize strings - Multi Languages
18.1. Externalize strings
18.2. Select the message.properties file
19. Tips and Tricks
19.1. Save users layout
19.2. Plugin ID in application
19.3. Add the error log view to your RCP application
19.4. Finding unused dependencies
20. Next steps
21. Thank you
22. Questions and Discussion
23. Links and Literature
23.1. Source Code
23.2. Eclipse Resources
23.3. Other Resources

1. Eclipse RCP

1.1. Overview

Eclipse RCP allows developers to use the Eclipse architecture to design flexible and extensible stand-alone applications re-using a lot of already existing functionality and coding patterns inherent in Eclipse.

For an brief introduction into Eclipse, the concepts and terminology (perspective, views, editors) please see Eclipse Java IDE - Tutorial .

Eclipse is build upon a plugin architecture. This allows Eclipse to get easily extended. See Eclipse plugin Tutorial for a guide on how-to extend the Eclipse IDE. Eclipse RCP provides the same modular concept for stand-alone applications.

To create an Eclipse RCP application you would create a plugin which contains the application. This application can use the existing hooks of Eclipse (called Extension Points) to define functionality and / or the user interface and / or provide its own extension points to get extended by other plugins.

1.2.  Eclipse RCP Architecture - Plugins, Extensions and Extension-Points

The most important architectural characteristics of Eclipse is the Plugin architecture. The Eclipse IDE is build as a number of plugins which are dependent on each other.

Plugins are the smallest deployable and installable software components of Eclipse.

Each plugin can define extension-points which define possibilities for functionality contributions ( code and non-code ) by other plugins. Non-code functionality contributions are for example the provision of help content.

A plugin can use extensions, e.g. provide functionality to these extension points. In general an extension point can be used several times (either by the same plugin or by other plugins). See Eclipse Extension Points and Extensions - Tutorial for details.

The basis for this architecture is the runtime environment Equinox of Eclipse which is the reference implementation of OSGI. See OSGi development - Tutorial for details. The Plugin concept of Eclipse is the same as the bundle concept of OSGI. Generally speaking a OSGI bundle equals a Plugin and vice-versa.

The used extensions and the provided extension-points are described in the file plugin.xml. This file is a XML file which can be edited via the PDE (Plugin Development Environment) which provides a nice user interface for editing this file.

Eclipse RCP provides and uses the same framework as the Eclipse Workbench hence allowing the programmer to divide the application functionality into several plugins, to use existing extension points and to provide additional extension points. This concept of Eclipse allows every programmer to structure his RCP application into several independent components and to easily declare extensions to existing extensions points.

1.3.  Main components of an Eclipse RCP application

An Eclipse RCP application requires:

  • Main program - A RCP main application class implements the interface IApplication. Eclipse expects that the application class is defined via the extension point org.eclipse.core.runtime.application.

  • A Perspective - The perspective is extended from org.eclipse.ui.perspective

  • Workbench Advisor- invisible technical component which controls the appearance of the application (menus, toolbars, perspectives, etc)

All plugins must provide a so-called manifest named "plugin.xml".

The minimal required plugins to create and run an Eclipse RCP application are the two plugins "org.eclipse.core.runtime" and "org.eclipse.ui"

1.4. Application versus Product

To run an Eclipse RCP program you have to define an application . The application can be seen as the main() method of a standard Java program. If this application shuts down the complete program is terminated.

In Eclipse terms a product is everything that goes with your application, e.g. icons, splash screen, external jars, other plugins, etc.

1.5. Important files

The plugin configuration is contained in the two files:

  • MANIFEST.MF - the OSGi bundle manifest is stored in MANIFEST.MF

  • plugin.xml - additional Eclipse specific (non standard OSGi) configuration, e.g. the extension points

The PDE provides an editor for editing the "MANIFEST.MF" and "plugin.xml".

In addition to these files you have the .project file. The .project contains the description of your project. It contains a XML tag "natures" where the nature of the project is described. A plugin project has the nature "org.eclipse.pde.PluginNature" and a java project has the nature "org.eclipse.jdt.core.javanature". These tags will also steer some behavior of the development environment, e.g. a project with PluginNature will update the java class path if you change the dependency information in a plugin project.

Tip

The .* file may be hidden by a filter. In the package explorer select the drop-down menu and then Filter to remove the filter for .* resources.

2. Installation

On the webpage of eclipse (www.eclipse.org), click on DOWNLOADS. Download the package "Eclipse for RCP/Plug-in Developers".

Tip

You might have to click on "More Packages" to see the RCP download package.

Tip

Don’t extract Eclipse into a directory tree that contains special characters. I also recommend to avoid spaces in the directory name.

In case you have downloaded the Eclipse Java IDE (or any other non RCP flavor) distribution you can use the Eclipse Update Manager to install the plugins required for RCP development. Install "General Purpose Tools" -> "Eclipse Plug-in Development Environment" from the Galileo update site. SeeEclipse Update Manager for details on using the update manager.

update10.gif

3. Create your first RCP application

The following gives a quick guide on how to create a simple RCP application.

3.1. Create a RCP application

In Eclipse select File-> New Project. From the list select "Plug-In Project".

firstrcp02.gif

Give your plugin the name "de.vogella.rcp.intro.first" .

firstrcp10.gif

Press "Next" and make the following settings. As we are going to develop a RCP application, select "Yes" at the question "Would you like to create a rich client application".

firstrcp20.gif

Press next and select the template "Hello RCP" .

firstrcp30.gif

Press next and select "Add branding" and press Finish.

firstrcp40.gif

As a result a project with the following project structure will be created. Have a look at the different files especially the Java files to get a first feeling about the project structure.

firstrcp50.gif

Tip

As this tutorial is about RCP development I will use the following interchangable: "create a new plugin project " or "create a new RCP project". Both mean the same, create a plugin project with the flag "Would you like to create a rich client application" enabled.

3.2. Start your RCP application

Search in the menu path for the file "MANIFEST.MF" and double-click on it. You should see an editor and the tab "Overview" should be selected. Click the link "Launch an Eclipse Application".

Tip

Alternatively you can run your Eclipse RCP application by selecting the automatically created "plugin.xml", right mouse click and select "Run as" -> "Eclipse Application".

firstrcp60.gif

The result should look like the following:

firstrcp70.gif

Congratulations, you have created your first RCP application.

.1. Startup process of an RCP application

During the startup of an Eclipse RCP application the Eclipse runtime will evaluate which class is defined via the "org.eclipse.core.runtime.application" extension point.

This class will then be loaded. This class creates and runs a Workbench. The Workbench is configured via a WorkbenchAdvisor. The Workbench will start a WorkbenchWindow which is configured via a WorkbenchWindowAdvisor. This WorkbenchWindow will create the toolbar of the application which can get configured at startup via the ActionBarAdvisor.

Each adviser allow to configure certain behavior of the application, e.g. the WorkbenchAdvisor allows to perform certain actions at startup or shutdown by overriding the methods preStartUp() and preShutdown().

4. Run configuration

4.1. Overview

A run configuration in Eclipse defines the environment under which your application will be started, e.g. compiler flag, plugin (classpath) dependencies etc. Sometime a run configuration is called referred to as "launch configuration".

If you start your application a default run configuration will be automatically created for you.

To see and edit your run configuration select your plugin.xml -> Run As -> Run Configurations

launchconfiguration10.gif

In the field "location" you specify their the files will be created which are necessary to run your RCP application.

launchconfiguration20.gif

4.2. Check your runtime configuration

On the Plug-ins Tab select "Validate plug-ins prior to launching". This will check if you have all required plugins in your launch configuration.

If this check reports that some plugins are missing, try clicking the "Add Required-Plug-Ins" button.

launchconfiguration40.gif

Tip

This may solve errors like "One or more bundles are not resolved because the following root constraints are not resolved" or "java.lang.RuntimeException: No application id has been found."

4.3. Important Parameters

On the tab Arguments you should add the parameter -consoleLog. This will send error message of your Eclipse RCP application to your Eclipse development IDE. Otherwise you will not necessary know that your Eclipse RCP application has a problem.

launchconfiguration30.gif

Tip

Under Windows -> Preference -> Plug-in Development -> Target Platform it is possible to maintain -consoleLog in the tab launching Arguments -> Program Arguments. Then the parameter will always be set for your RCP runtime configurations.

consoleLog10.gif

Tip

Other nice parameters are -console (which will give you a OSGI console where you can check the status of your application) and -noExit (which will keep the OSGI console open even if the application ends / crashes).

5. Commands

5.1. Overview

A command is a declarative description of a component and is independent from the implementation details. A command can be categorized and a hot key (key binding) can be assigned to the command.

Commands can be used in menus, toolbars and / or context menus.

The following will focus on a simple definition and usage of commands. For details on the usage of commands please see Eclipse Commands - Tutorial

5.2. Defining commands

Our first example will be a command which will exit the application. Create a new RCP project "de.vogella.rcp.commands.first" and use the "Hello RCP" Template.

Click on the plugin.xml and select the Extensions tab.

command10.gif

Press the add button and search for the extension org.eclipse.ui.commands. Select it and press finish.

command20.gif

Create a new command by right-clicking New -> command.

Tip

Lots of people report that if they try this they can only select a "Generic" entry. The common source of this problem seems to be that you did not download the package "Eclipse for RCP/Plug-in Developers". Please see Eclipse Installation .

command30.gif

Set the ID to "de.vogella.rcp.commands.first.commands.Exit" and the name to "Exit". Enter the class "de.vogella.rcp.commands.first.commands.ExitHandler" as defaultHandler.

command40.gif

Press the hyperlink "defaultHandler" to create this class.

Choose org.eclipse.core.commands.AbstractHandler as Superclass.

command50.gif

Implement the following coding

			
package de.vogella.rcp.commands.first.commands;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.handlers.HandlerUtil;

public class ExitHandler extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		HandlerUtil.getActiveWorkbenchWindow(event).close();
		return null;
	}

}

		

You have correctly implemented the command. This command can now be used in various places in your application.

5.3. Using commands in menus

The command which we just defined should now be used in a new menu.

Add the extension point "org.eclipse.ui.menus" to your application. Select therefore again plugin.xml and the tab "Extensions". Press Add, select the extension point "org.eclipse.ui.menus" and press Finish.

command60.gif

Right click on the extension point and select new -> menuContribution.

command62.gif

Create a new menu contribution with the location URI "menu:org.eclipse.ui.main.menu".

Tip

Make sure the URL must is correct, otherwise the menu will not get displayed.

command70.gif

command80.gif

Right click your menucontribution and select New -> Menu. Add a menu with the label "File" and the id "fileMenu".

commandmenu10.gif

commandmenu20.gif

Now select your menu, right-click on it and select New-> Command. Maintain the commandID you used earlier. Set the label to "Exit" and the tooltip to "Exit the application".

commandmenu30.gif

If you run the example you should see menu with the file. Selecting Exit should end your application.

commandmenu40.gif

6. System Tray

In the following we will add a system tray icon, add the functionality that if the window is minimized then the program is not visible in the taskpane (only via the tray icon) and we will add a menu with some entries into the system tray icon.

Create a new project "de.vogella.rcp.intro.traytest". Use the "Hello RCP" as a template.

Create a command which the id "de.vogella.rcp.intro.traytest.exitCommand" which exists the application (see Eclipse commands for details).

Maintain the following code in class ApplicationWorkbenchWindowAdvisor.

Tip

To get a tray icon you need a Display. A display is an SWT object that represents the underlying graphics system. This object is available as of method postWindowOpen() in ApplicationWorkbenchWindowAdvisor.

			
package de.vogella.rcp.intro.traytest;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tray;
import org.eclipse.swt.widgets.TrayItem;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.plugin.AbstractUIPlugin;

public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
	private IWorkbenchWindow window;
	private TrayItem trayItem;
	private Image trayImage;
	private  final static String COMMAND_ID = "de.vogella.rcp.intro.traytest.exitCommand"; 

	
    public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
        super(configurer);
    }

    public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) {
        return new ApplicationActionBarAdvisor(configurer);
    }
    
    public void preWindowOpen() {
        IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
        configurer.setInitialSize(new Point(400, 300));
        configurer.setShowCoolBar(false);
        configurer.setShowStatusLine(false);
        configurer.setTitle("Hello RCP");
    }
    
    @Override
	public void postWindowOpen() {
		super.postWindowOpen();
		window = getWindowConfigurer().getWindow();
		trayItem = initTaskItem(window);
		if (trayItem != null) {
			createMinimize();
			// Create exit and about action on the icon
			hookPopupMenu();
		}
	}

	private void createMinimize() {
		window.getShell().addShellListener(new ShellAdapter() {
			public void shellIconified(ShellEvent e) {
				window.getShell().setVisible(false);
			}
		});

		trayItem.addListener(SWT.DefaultSelection, new Listener() {
			public void handleEvent(Event event) {
				Shell shell = window.getShell();
				if (!shell.isVisible()) {
					shell.setVisible(true);
					window.getShell().setMinimized(false);
				}
			}
		});
	}

	private void hookPopupMenu() {
		trayItem.addListener(SWT.MenuDetect, new Listener() {
			public void handleEvent(Event event) {
				Menu menu = new Menu(window.getShell(), SWT.POP_UP);

				// Creates a new menu item that terminates the program
				// when selected
				MenuItem exit = new MenuItem(menu, SWT.NONE);
				exit.setText("Goodbye!");
				exit.addListener(SWT.Selection, new Listener() {
					public void handleEvent(Event event) {
						// Lets call our command
						IHandlerService handlerService = (IHandlerService) window
								.getService(IHandlerService.class);
						try {
							handlerService.executeCommand(COMMAND_ID, null);
						} catch (Exception ex) {
							throw new RuntimeException(COMMAND_ID);
						}
					}
				});
				// We need to make the menu visible
				menu.setVisible(true);
			}
		});
	}

	private TrayItem initTaskItem(IWorkbenchWindow window) {
		final Tray tray = window.getShell().getDisplay().getSystemTray();
		TrayItem trayItem = new TrayItem(tray, SWT.NONE);
		trayImage = AbstractUIPlugin.imageDescriptorFromPlugin(
				"de.vogella.rcp.intro.traytest", "/icons/alt_about.gif").createImage();
		trayItem.setImage(trayImage);
		trayItem.setToolTipText("TrayItem");
		return trayItem;

	}

	public void dispose() {
		if (trayImage != null) {
			trayImage.dispose();
			trayItem.dispose();
		}
	}


}

		

Run your application and see that you have a system tray icon. Test the menu and the minimized behavior.

7. Views

7.1. Overview

Views provide information for a given task. A view is typically used to navigate a hierarchy of information, open an editor, or display properties for the active editor.

The following will explain how to add views to your application.For this example create a new RCP project "de.vogella.rcp.intro.view". Use the "Hello RCP" as a template.

7.2. Create a view

Select the file "plugin.xml" and the tab "Extensions". Press the "add" button and add "org.eclipse.ui.views" as an extension.

addview70.gif

Right mouse-click on your new view extension and select New -> View

addview80.gif

Maintain the id "de.vogella.rcp.intro.view.MyView" and the class "de.vogella.rcp.intro.view.MyView".

addview90.gif

Create the class of the view by clicking on the class hyperlink.

addview100.gif

Maintain the following code in your new class.

				
package de.vogella.rcp.intro.view;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

public class MyView extends ViewPart {

	@Override
	public void createPartControl(Composite parent) {
		Text text = new Text(parent, SWT.BORDER);
		text.setText("Imagine a fantastic user interface here");
	}

	@Override
	public void setFocus() {
	}
}

			

7.3. Add the view to your perspective.

After creating the view you have to add this view to your perspective. We will do this by using another extension point.

Select again "plugin.xml" and the tab "Extensions". Press add and add the extension "org.eclipse.ui.perspectiveExtensions".

addview110.gif

Right click it and select view.

addview120.gif

Maintain your view id "de.vogella.rcp.intro.view.MyView". Make the view relative to "org.eclipse.ui.editorss" which is the currently invisible editor area and make the view use all the space by selecting the maximum ratio of "0.95f".

addview130.gif

7.4. Result

Run your application to see the result.

addview200.gif

7.5. Add view to perspective via code

Alternatively to the usage of the extension point "org.eclipse.ui.perspectiveExtensions" you could have add the view also via coding to your perspective. To to this you could modify "Perspective.java" to the following.

				
package de.vogella.rcp.intro.view;

import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;

public class Perspective implements IPerspectiveFactory {

	public void createInitialLayout(IPageLayout layout) {
		layout.addView("de.vogella.rcp.intro.view.MyView", IPageLayout.TOP,
				IPageLayout.RATIO_MAX, IPageLayout.ID_EDITOR_AREA);
	}
}

			

Tip

If possible use extension points over code.

8.  Working with Editors, View Interaction and Model Updates

8.1. Overview

In the following we create a project which demonstrate the usage of editors and its interaction with an view.

We will create a view which shows several person. Once the user double-clicks on the name an editor is opened in which the user can edit the address of this person.

The following data model makes the assumption that the last name of a person is unique. This assumption is of course not true in the real world.

8.2. Create project

Create a new RCP project "de.vogella.rcp.intro.editor" . Use the "RCP application with a view" as a template.

8.3. Create and prepare the domain model

Create a package "de.vogella.rcp.intro.editor.model". Create the following classes in this package.

				
package de.vogella.rcp.intro.editor.model;

public class Address {

	private String street;
	private String number;
	private String postalCode;
	private String city;
	private String country;

	public String getStreet() {
		return street;
	}

	public void setStreet(String street) {
		this.street = street;
	}

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

	public String getPostalCode() {
		return postalCode;
	}

	public void setPostalCode(String postalCode) {
		this.postalCode = postalCode;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String toString() {
		return street + " " + number + " " + postalCode + " " + city + " "
				+ country;
	}
}

			

				
package de.vogella.rcp.intro.editor.model;

public class Person {
	private String firstName;
	private String lastName;
	private Address address;

	public Person(String firstName, String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return firstName + " " + lastName;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((firstName == null) ? 0 : firstName.hashCode());
		result = prime * result
				+ ((lastName == null) ? 0 : lastName.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (firstName == null) {
			if (other.firstName != null)
				return false;
		} else if (!firstName.equals(other.firstName))
			return false;
		if (lastName == null) {
			if (other.lastName != null)
				return false;
		} else if (!lastName.equals(other.lastName))
			return false;
		return true;
	}

}

			

				
package de.vogella.rcp.intro.editor.model;

import java.util.ArrayList;
import java.util.List;

public class MyModel {

	private List<Person> persons = new ArrayList<Person>();

	public List<Person> getPersons() {
		return persons;
	}

	public MyModel() {
		// Just for testing we hard-code the persons here:
		Person person = new Person("Lars", "Vogel");
		person.setAddress(new Address());
		person.getAddress().setCountry("Germany");
		persons.add(person);
		person = new Person("Jim", "Knopf");
		person.setAddress(new Address());
		person.getAddress().setCountry("Germany");
		persons.add(person);
	}
}

			

Tip

Please note that we override the equals (and the hashcode method). This allows us later to identify the right editor for each person.

8.4. Content and Label provider

Create a new package "de.vogella.rcp.intro.editor.provider"

Create a new class "MyContentProvider" which implements the interface IStructuredContentProvider.

editor20.gif

Adjust the coding according to the following example:

				package de.vogella.rcp.intro.editor.provider;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;

import de.vogella.rcp.intro.editor.model.MyModel;

public class MyContentProvider implements IStructuredContentProvider,
		PropertyChangeListener {

	private final Viewer viewer;

	public MyContentProvider(Viewer viewer) {
		this.viewer = viewer;
	}

	@Override
	public Object[] getElements(Object inputElement) {
		MyModel content = (MyModel) inputElement;
		return content.getPersons().toArray();
	}

	@Override
	public void dispose() {
	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
	}

	@Override
	public void propertyChange(PropertyChangeEvent arg0) {
		viewer.refresh();
	}

}

			

Create a new class "MyLabelProvider" which implements the interface ILabelProvider. Use the following code.

				
package de.vogella.rcp.intro.editor.provider;

import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;

import de.vogella.rcp.intro.editor.model.Person;

public class MyLabelProvider implements ILabelProvider {

	@Override
	public Image getImage(Object element) {
		return PlatformUI.getWorkbench().getSharedImages().getImage(
				ISharedImages.IMG_OBJ_ELEMENT);
	}

	@Override
	public String getText(Object element) {
		Person person = (Person) element;
		return (person.getLastName());
	}

	@Override
	public void addListener(ILabelProviderListener listener) {
	}

	@Override
	public void dispose() {
	}

	@Override
	public boolean isLabelProperty(Object element, String property) {
		return false;
	}

	@Override
	public void removeListener(ILabelProviderListener listener) {
	}
}

			

8.5. Use the domain model in the view

Change the class View to use your new content providers.

				
package de.vogella.rcp.intro.editor;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

import de.vogella.rcp.intro.editor.model.MyModel;
import de.vogella.rcp.intro.editor.provider.MyContentProvider;
import de.vogella.rcp.intro.editor.provider.MyLabelProvider;

public class View extends ViewPart {
	public static final String ID = "de.vogella.rcp.intro.editor.view";

	private TableViewer viewer;

	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	public void createPartControl(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL);
		viewer.setContentProvider(new MyContentProvider(viewer));
		viewer.setLabelProvider(new MyLabelProvider());
		viewer.setInput(new MyModel());
		getSite().setSelectionProvider(viewer);
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
}
			

The view makes his viewer available as selection provider via the following line:" getSite().setSelectionProvider(viewer);". This make is possible for the command which opens the editor to get the selection of the view.

Tip

All workbench parts have a site, which can be accessed via the method getSite(). A site is a Facade which allows access to other parts of the workbench, e.g. the shell, the workbench window, etc. Whenever possible use the site to access Workbench objects.

Run your application. The view should now display the last names for your content provider. Currently nothing happens if you click on the names.

8.6. Editor area

Make the editor area visible by changing your Perspective.java.

				
package de.vogella.rcp.intro.editor;

import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;

public class Perspective implements IPerspectiveFactory {

	public void createInitialLayout(IPageLayout layout) {
		String editorArea = layout.getEditorArea();
		layout.setEditorAreaVisible(true);
		layout.setFixed(true);
		layout.addStandaloneView(View.ID, false, IPageLayout.LEFT, 1.0f,
				editorArea);
	}

}

			

8.7. Editor Input

In package "de.vogella.rcp.intro.editor.editors" create a new class "MyPersonEditorInput" which implements IEditorInput. IEditorInput serves as the model for the editor.

It is recommended to overwrite the method equals and hashcode in an implementation of IEditor. Based on the equals method the system will determine if the corresponding editor is already open or not.

Change the created code to the following.

				
package de.vogella.rcp.intro.editor.editors;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPersistableElement;

import de.vogella.rcp.intro.editor.model.Person;

public class MyPersonEditorInput implements IEditorInput {

	private final Person person;

	public MyPersonEditorInput(Person person) {
		this.person = person;
	}

	public Person getPerson() {
		return person;
	}

	@Override
	public boolean exists() {
		return false;
	}

	@Override
	public ImageDescriptor getImageDescriptor() {
		return null;
	}

	@Override
	public String getName() {
		return person.toString();
	}

	@Override
	public IPersistableElement getPersistable() {
		return null;
	}

	@Override
	public String getToolTipText() {
		return person.toString();
	}

	@Override
	public Object getAdapter(Class adapter) {
		return null;
	}

	@Override
	public boolean equals(Object obj) {
		if (super.equals(obj)) {
			return true;
		}
		if (obj instanceof MyPersonEditorInput) {
			return person.equals(((MyPersonEditorInput) obj).getPerson());
		}
		return false;
	}

	@Override
	public int hashCode() {
		return person.hashCode();
	}
}

			

8.8. Adding the editor

Go to plugin.xml and select the tab extensions. Add the extension org.eclipse.ui.editors. Do not use a template. Use the ID "de.vogella.rcp.intro.editor.editors.MyPersonEditor", any name you want and the class "de.vogella.rcp.intro.editor.editors.MyPersonEditor".

Tip

Make also sure to select an icon! Otherwise your editor will not work.

editor30.gif

editor40.gif

Click on the class hyperlink to create the class. Create the following class. Important is the class variable "ID" which we will later use to reference to this class. The variable ID must match the id defined in the editor extension.

				
package de.vogella.rcp.intro.editor.editors;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;

import de.vogella.rcp.intro.editor.model.Person;

public class MyPersonEditor extends EditorPart {
	public static final String ID = "de.vogella.rcp.intro.editor.editors.MyPersonEditor";
	private Person person;
	private Text text2;

	public MyPersonEditor() {
	}

	@Override
	public void doSave(IProgressMonitor monitor) {
		person.getAddress().setCountry(text2.getText());
	}

	@Override
	public void doSaveAs() {
	}

	@Override
	public void init(IEditorSite site, IEditorInput input)
			throws PartInitException {
		setSite(site);
		setInput(input);
		person = ((MyPersonEditorInput) input).getPerson();
		setPartName(person.getFirstName());

	}

	@Override
	public boolean isDirty() {
		if (person.getAddress().getCountry().equals(text2.getText())) {
			return false;
		}
		return true;
	}

	@Override
	public boolean isSaveAsAllowed() {
		return false;
	}

	@Override
	public void createPartControl(Composite parent) {

		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		parent.setLayout(layout);
		Label label1 = new Label(parent, SWT.BORDER);
		label1.setText("Person: ");
		Label personName = new Label(parent, SWT.BORDER);
		personName.setText(person.toString());
		Label label2 = new Label(parent, SWT.BORDER);
		label2.setText("Country");
		text2 = new Text(parent, SWT.BORDER);
		text2.setText(person.getAddress().getCountry());
	}

	@Override
	public void setFocus() {
	}

}

			

8.9. Creating a command for calling the editor

Create a command "de.vogella.rcp.intro.editor.callEditor" with the default handler "de.vogella.rcp.intro.editor.handler.CallEditor".

editor52.gif

Create the following class "de.vogella.rcp.intro.editor.handler.CallEditor".

				
package de.vogella.rcp.intro.editor.handler;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.handlers.HandlerUtil;

import de.vogella.rcp.intro.editor.View;
import de.vogella.rcp.intro.editor.editors.MyPersonEditor;
import de.vogella.rcp.intro.editor.editors.MyPersonEditorInput;
import de.vogella.rcp.intro.editor.model.Person;

public class CallEditor extends AbstractHandler implements IHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		// Get the view
		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
		IWorkbenchPage page = window.getActivePage();
		View view = (View) page.findView(View.ID);
		// Get the selection
		ISelection selection = view.getSite().getSelectionProvider()
				.getSelection();
		if (selection != null && selection instanceof IStructuredSelection) {
			Object obj = ((IStructuredSelection) selection).getFirstElement();
			// If we had a selection lets open the editor
			if (obj != null) {
				Person person = (Person) obj;
				MyPersonEditorInput input = new MyPersonEditorInput(person);
				try {
					page.openEditor(input, MyPersonEditor.ID);

				} catch (PartInitException e) {
					System.out.println(e.getStackTrace());
				}
			}
		}
		return null;
	}

}

			

8.10. Calling the editor

Add a double-click listener to your view which call the editor.

				
package de.vogella.rcp.intro.editor;

import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.ViewPart;

import de.vogella.rcp.intro.editor.provider.MyContentProvider;
import de.vogella.rcp.intro.editor.provider.MyLabelProvider;

public class View extends ViewPart {
	public static final String ID = "de.vogella.rcp.intro.editor.view";

	private TableViewer viewer;

	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	public void createPartControl(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL);
		viewer.setContentProvider(new MyContentProvider(viewer));
		viewer.setLabelProvider(new MyLabelProvider());
		viewer.setInput(new MyModel());
		getSite().setSelectionProvider(viewer);
		// New
		hookDoubleClickCommand();
	}

	// New
	private void hookDoubleClickCommand() {
		viewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(DoubleClickEvent event) {
				IHandlerService handlerService = (IHandlerService) getSite()
						.getService(IHandlerService.class);
				try {
					handlerService.executeCommand(
							"de.vogella.rcp.intro.editor.callEditor", null);
				} catch (Exception ex) {
					throw new RuntimeException(
							"de.vogella.rcp.intro.editor.callEditor not found");
				}
			}
		});
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
}

			

Run the application. If you double-click on an item in the view, the editor should open and the counry should get displayed. If you close the editor and re-open it, changes in the address should be displayed.

editor60.gif

9. Dialog

9.1. Overview

Eclipse supports several predefined dialogs. For example

  • org.eclipse.swt.widgets.FileDialog

  • org.eclipse.swt.widgets.DirectoryDialog

  • org.eclipse.swt.widgets.MessageDialog

  • org.eclipse.jface.dialogs.ErrorDialog

Eclipse supports also user defined dialogs. Usually the class TitleAreaDialog is then extended.

9.2. Using standard dialogs

The following will describe how to use standard dialogs.

Create a new project "de.vogella.rcp.intro.dialogs.standard". Use the "Hello RCP" as a template.

Add one command "de.vogella.rcp.intro.dialogs.standard.openDialog" and create the default handler "de.vogella.rcp.intro.dialogs.standard.handler.OpenDialog" for the command. Add the command to the menu.

Define the following code for the default handler.

				
package de.vogella.rcp.intro.dialogs.standard.handler;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.FontDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.handlers.HandlerUtil;

public class OpenDialog extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		Shell shell = HandlerUtil.getActiveWorkbenchWindow(event).getShell();

		// File standard dialog
		FileDialog fileDialog = new FileDialog(shell);
		// Set the text
		fileDialog.setText("Select File");
		// Set filter on .txt files
		fileDialog.setFilterExtensions(new String[] { "*.txt" });
		// Put in a readable name for the filter
		fileDialog.setFilterNames(new String[] { "Textfiles(*.txt)" });
		// Open Dialog and save result of selection
		String selected = fileDialog.open();
		System.out.println(selected);

		// Directly standard selection
		DirectoryDialog dirDialog = new DirectoryDialog(shell);
		dirDialog.setText("Select your home directory");
		String selectedDir = dirDialog.open();
		System.out.println(selectedDir);

		// Select Font
		FontDialog fontDialog = new FontDialog(shell);
		fontDialog.setText("Select your favorite font");
		FontData selectedFont = fontDialog.open();
		System.out.println(selectedFont);

		// Select Color
		ColorDialog colorDialog = new ColorDialog(shell);
		fontDialog.setText("Select your favorite color");
		RGB selectedColor = colorDialog.open();
		System.out.println(selectedColor);

		// Now a few messages
		MessageDialog.openConfirm(shell, "Confirm", "Please confirm");
		MessageDialog.openError(shell, "Error", "Error occured");
		MessageDialog.openInformation(shell, "Info", "Info for you");
		MessageDialog.openQuestion(shell, "Question", "Really, really?");
		MessageDialog.openWarning(shell, "Warning", "I warn you");

		return null;
	}

}

			

Run the application. If you select your command the dialogs will be called after each other.

9.3. Selection

Eclipse provides the ElementListSelectionDialog which allows to select elements from a list.

Create a new project "de.vogella.rcp.intro.dialogs.selection". Use the "Hello RCP" as a template.

Add one command "de.vogella.rcp.intro.dialogs.selection.selectionDialog" and create the default handler "de.vogella.rcp.intro.dialogs.selection.handler.SelectionDialog" for the command. Add the command to the menu.

Define the following code in your handler.

				
package de.vogella.rcp.intro.dialogs.selection.handler;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.ui.handlers.HandlerUtil;

public class SelectionDialog extends AbstractHandler {

	private Object[] result;

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		Shell shell = HandlerUtil.getActiveWorkbenchWindow(event).getShell();
		ElementListSelectionDialog dialog = new ElementListSelectionDialog(
				shell, new LabelProvider());
		dialog.setElements(new String[] { "Linux", "Mac", "Windows" });
		dialog.setTitle("Which operating system are you using");
		dialog.open();
		result = dialog.getResult();
		for (Object s : result) {
			System.out.println(s.toString());
		}
		return null;
	}
}

			

Run the application. If you select your command then the dialog will be displayed.

dialog40.gif

9.4. User defined dialogs

The following will describe how to define your own dialogs and how to use it.

Create a new project "de.vogella.rcp.intro.dialogs.custom". Use the "Hello RCP" as a template.

Create the package "de.vogella.rcp.intro.dialogs.custom.dialogs" and create the following class MyDialog which extends TitleAreaDialog.

				
package de.vogella.rcp.intro.dialogs.custom.dialogs;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class MyDialog extends TitleAreaDialog {

	private Text text1;
	private Text text2;

	public MyDialog(Shell parentShell) {
		super(parentShell);
	}

	protected Control createContents(Composite parent) {
		Control contents = super.createContents(parent);
		// Set the title
		setTitle("This is my first own dialog");
		// Set the message
		setMessage("This is a TitleAreaDialog", IMessageProvider.INFORMATION);
		return contents;
	}

	@Override
	protected Control createDialogArea(Composite parent) {
		// return super.createDialogArea(parent);
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		parent.setLayout(layout);
		Label label1 = new Label(parent, SWT.NONE);
		label1.setText("First Name");
		text1 = new Text(parent, SWT.BORDER);
		Label label2 = new Label(parent, SWT.NONE);
		label2.setText("Last Name");
		text2 = new Text(parent, SWT.BORDER);
		return parent;
	}

	@Override
	protected void createButtonsForButtonBar(Composite parent) {
		createOkButton(parent, IDialogConstants.OK_ID,
				IDialogConstants.OK_LABEL, true);
		createButton(parent, IDialogConstants.CANCEL_ID,
				IDialogConstants.CANCEL_LABEL, false);

	}

	protected Button createOkButton(Composite parent, int id, String label,
			boolean defaultButton) {
		// increment the number of columns in the button bar
		((GridLayout) parent.getLayout()).numColumns++;
		Button button = new Button(parent, SWT.PUSH);
		button.setText(label);
		button.setFont(JFaceResources.getDialogFont());
		button.setData(new Integer(id));
		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				if (text2.getText().length() != 0) {
					buttonPressed(((Integer) event.widget.getData()).intValue());
				} else {
					setErrorMessage("Please maintain the last name");
				}
			}
		});
		if (defaultButton) {
			Shell shell = parent.getShell();
			if (shell != null) {
				shell.setDefaultButton(button);
			}
		}
		setButtonLayoutData(button);
		return button;
	}
}

			

Add one command "de.vogella.rcp.intro.dialogs.custom.openMyDialog" and create the default handler "de.vogella.rcp.intro.dialogs.custom.handler.OpenMyDialog" for the command. Add the command to the menu.

Implement the following coding for the handler.

				
package de.vogella.rcp.intro.dialogs.custom.handler;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.handlers.HandlerUtil;

import de.vogella.rcp.intro.dialogs.custom.dialogs.MyDialog;

public class OpenMyDialog extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		MyDialog dialog = new MyDialog(HandlerUtil.getActiveWorkbenchWindow(
				event).getShell());
		dialog.open();
		return null;
	}

}

			

Run the application. The dialog should open and you must maintain the last name otherwise the dialog will give you an error message.

10. Field Assist

Field Assit can be used to provide information about the possible inputs and status of a simple field, e.g. text field or combo box.

The org.eclipse.jface.fieldassist package provides assistance in two ways. Control decorations allow you to place image decorations to show the status of a field. Content proposal allows to provide a popup that which provides possible choices for this field. user. The following will demonstrate the content proposal.

Create a new project "de.vogella.rcp.intro.fieldassist". Use "RCP application with a view" as an example.

In our example the content proposal should get activated via certain keys ("." and "#") as well as the key combination "Cntrl+Space".

Change the View.java to the following.

		
package de.vogella.rcp.intro.fieldassist;

import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.SimpleContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

public class View extends ViewPart {
	public static final String ID = "de.vogella.rcp.intro.fieldassist.view";

	public void createPartControl(Composite parent) {
		Text text = new Text(parent, SWT.BORDER);
		text.setText("Example");

		// "." and "#" will also activate the content proposals
		char[] autoActivationCharacters = new char[] { '.', '#' };
		KeyStroke keyStroke;
		try {
			keyStroke = KeyStroke.getInstance("Ctrl+Space");
			// assume that myTextControl has already been created in some way
			ContentProposalAdapter adapter = new ContentProposalAdapter(text,
					new TextContentAdapter(),
					new SimpleContentProposalProvider(new String[] {
							"ProposalOne", "ProposalTwo", "ProposalThree" }),
					keyStroke, autoActivationCharacters);
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}

	public void setFocus() {
	}
}
	

Run the application and check the content proposal works.

fieldassists10.gif

11. Wizards

11.1. Overview

Wizards provide a flexible ways to systematically gather user input and perform input validation. A wizard guides a user step by step through a process.

Eclipse implements a Wizard via class WizardDialog. The WizardDialog controls the process (Navigation, process bar, area for error and information messages). The Wizard content and is provided by the class Wizard and the pages are provided via class WizardPages.

11.2. Example

Create a new project "de.vogella.rcp.intro.wizards". Use the "Hello RCP" as a template.

Create the command "de.vogella.rcp.intro.wizards.showWizard" with the default handler "de.vogella.rcp.intro.wizards.handler.ShowWizard". Add the command to the menu.

Create a package "de.vogella.rcp.intro.wizards.wizard". Create the classes "MyPageOne" and "MyPageTwo" MyWizard which extends org.eclipse.jface.wizard.WizardPage.

Maintain the following code for the classes.

				
package de.vogella.rcp.intro.wizards.wizard;

import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

public class MyPageOne extends WizardPage {
	private Text text1;
	private Composite container;

	public MyPageOne() {
		super("First Page");
		setTitle("First Page2");
		setDescription("This wizard does not really do anything. But this is the first page");
	}

	@Override
	public void createControl(Composite parent) {
		container = new Composite(parent, SWT.NULL);
		GridLayout layout = new GridLayout();
		container.setLayout(layout);
		layout.numColumns = 2;
		Label label1 = new Label(container, SWT.NULL);
		label1.setText("Put here a value");

		text1 = new Text(container, SWT.BORDER | SWT.SINGLE);
		text1.setText("");
		text1.addKeyListener(new KeyListener() {

			@Override
			public void keyPressed(KeyEvent e) {
			}

			@Override
			public void keyReleased(KeyEvent e) {
				if (!text1.getText().isEmpty()) {
					setPageComplete(true);

				}
			}

		});
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
		text1.setLayoutData(gd);
		// Required to avoid an error in the system
		setControl(container);
		setPageComplete(false);

	}

	public String getText1() {
		return text1.getText();
	}
}

			

				
package de.vogella.rcp.intro.wizards.wizard;

import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

public class MyPageTwo extends WizardPage {
	private Text text1;
	private Composite container;

	public MyPageTwo() {
		super("Second Page");
		setTitle("Second Page");
		setDescription("Now this is the second page");
		setControl(text1);
	}

	@Override
	public void createControl(Composite parent) {
		container = new Composite(parent, SWT.NULL);
		GridLayout layout = new GridLayout();
		container.setLayout(layout);
		layout.numColumns = 2;
		Label label1 = new Label(container, SWT.NULL);
		label1.setText("Say hello to Fred");

		text1 = new Text(container, SWT.BORDER | SWT.SINGLE);
		text1.setText("");
		text1.addKeyListener(new KeyListener() {

			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyReleased(KeyEvent e) {
				if (!text1.getText().isEmpty()) {
					setPageComplete(true);
				}
			}

		});
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
		text1.setLayoutData(gd);
		Label labelCheck = new Label(container, SWT.NONE);
		labelCheck.setText("This is a check");
		Button check = new Button(container, SWT.CHECK);
		check.setSelection(true);
		// Required to avoid an error in the system
		setControl(container);
		setPageComplete(false);
	}

	public String getText1() {
		return text1.getText();
	}

}

			

Create a new class MyWizard which extends org.eclipse.jface.wizard.Wizard.

>

				
package de.vogella.rcp.intro.wizards.wizard;

import org.eclipse.jface.wizard.Wizard;

public class MyWizard extends Wizard {

	private MyPageOne one;
	private MyPageTwo two;

	public MyWizard() {
		super();
		setNeedsProgressMonitor(true);
	}

	@Override
	public void addPages() {
		one = new MyPageOne();
		two = new MyPageTwo();
		addPage(one);
		addPage(two);
	}

	@Override
	public boolean performFinish() {

		// just put the result to the console, imagine here much more
		// intelligent stuff.
		System.out.println(one.getText1());
		System.out.println(two.getText1());

		return true;
	}
}

			

Implement the handler for the command.

				
package de.vogella.rcp.intro.wizards.handler;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.handlers.HandlerUtil;

import de.vogella.rcp.intro.wizards.wizard.MyWizard;

public class ShowWizard extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		MyWizard wizard = new MyWizard();
		WizardDialog dialog = new WizardDialog(HandlerUtil
				.getActiveShell(event), wizard);
		dialog.open();
		return null;
	}

}

			

If you run your application and select the menu entry the wizard should get displayed and after pressing "Finish" you should see the result on the console.

12. Adding a status line

12.1. Setup Status line

Create a new RCP project "Statusline". Use the "Hello RCP" as the template.

Go into the ApplicationWorkbenchWindowAdvisor and change method preWindowOpen(). The relevant line in the coding is: “configurer.setShowStatusLine(true); “

				
package statusline;

import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;

public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {

	public ApplicationWorkbenchWindowAdvisor(
			IWorkbenchWindowConfigurer configurer) {
		super(configurer);
	}

	public ActionBarAdvisor createActionBarAdvisor(
			IActionBarConfigurer configurer) {
		return new ApplicationActionBarAdvisor(configurer);
	}

	public void preWindowOpen() {
		IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
		configurer.setInitialSize(new Point(400, 300));
		configurer.setShowStatusLine(true);
		configurer.setShowCoolBar(false);
		configurer.setShowMenuBar(false);
		configurer.setTitle("Status Line Example");
	}
}

			

If you run the application you should already see a status line. At this point the status line does not contain text.

12.2. Shared Status Line

The shared message area can be used by all parts of the application to write messages to this area.

The following will explain how you can add a status line to your application. It will also indicate how the status line can be filled from a view or editor.

Tip

As the whole RCP application has access to the information in the shared status line the information in the shared status line might be overwritten.

Lets now fill the status line. We can do this for example via the postWindowOpen() method in ApplicationWorkbenchWindowAdvisor. You have two options to add this method:

  • You can either just paste this method into the class.

  • Or use the menu "Source" -> Implement / Overwrite Methods and then select "postWindowOpen()" to create the method and then adjust it to your needs.

				
package statusline;

import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;

public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {

	public ApplicationWorkbenchWindowAdvisor(
			IWorkbenchWindowConfigurer configurer) {
		super(configurer);
	}

	public ActionBarAdvisor createActionBarAdvisor(
			IActionBarConfigurer configurer) {
		return new ApplicationActionBarAdvisor(configurer);
	}

	public void preWindowOpen() {
		IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
		configurer.setInitialSize(new Point(400, 300));
		configurer.setShowCoolBar(false);
		configurer.setShowStatusLine(true);
		configurer.setTitle("Hello RCP");
	}
	// This is the new method
	@Override
	public void postWindowOpen() {

		IStatusLineManager statusline = getWindowConfigurer()
				.getActionBarConfigurer().getStatusLineManager();
		statusline.setMessage(null, "Status line is ready");
	}
}

			

Run your application. You should now see the following.

statusline10.gif

Add now view with the ID "StatusLine.View1" to your application (see Add a view to your Eclipse RCP application for details). Once you have your view you can access the status line, via the following.

				
IActionBars bars = getViewSite().getActionBars();
bars.getStatusLineManager().setMessage("Hello");

			

In our example we create a button which set the status line.

				
package statusline;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.part.ViewPart;

public class ViewPart1 extends ViewPart {

	boolean pressed = false;

	public ViewPart1() {
	}

	@Override
	public void createPartControl(Composite parent) {
		Button setStatusLine = new Button(parent, SWT.PUSH);
		setStatusLine.setText("Set Statusline ");
		setStatusLine.addSelectionListener(new SelectionListener() {
			public void widgetSelected(SelectionEvent e) {
				IActionBars bars = getViewSite().getActionBars();
				if (pressed) {
					bars.getStatusLineManager().setMessage(
							"I would like to say hello to you.");
				} else {
					bars.getStatusLineManager().setMessage(
							"Thank you for using me");
				}
				pressed = !pressed;

			}

			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});
	}

	@Override
	public void setFocus() {
	}

}

			

If you run it the result should look like the following.

statusline20.gif

Tip

From an editor you can access the status line via the following:

					
IEditorPart.getEditorSite().getActionBarContributor();

				

13. Perspectives

Perspectives group together and organize UI element that relate to a specific task.

Eclipse RCP allows you to add easily perspectives to your application. The following presents an example

13.1. Adding a perspective to your application

Create a new RCP project called "de.vogella.rcp.intro.perspective". Use the "RCP application with a view" as a template.

In plugin.xml add a new perspective extension point.

perspective10.gif

Give the perspective the id "de.vogella.rcp.intro.perspective.MyPerspective" and the name "MyPerspective". The name is the name under which the perspective will be visible. Change the class name to "de.vogella.rcp.intro.perspective.PerspectiveFactory".

perspective20.gif

Click on the "class*" link to create the class.

The method createInitialLayout() in your new class is responsible for creating the new perspective. For the sake of this example let use the same view then in the pre-created perspective but instead of having defined it as a standalone view, it will we be a normal view.

perspective30.gif

				
package perspectivetest;

import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;

public class PerspectiveFactoryNew implements IPerspectiveFactory {

	@Override
	public void createInitialLayout(IPageLayout layout) {
		String editorArea = layout.getEditorArea();
		layout.setEditorAreaVisible(true);
		layout.setFixed(false);
		layout.addView(View.ID, IPageLayout.LEFT, 0.33f, editorArea);
	}
}

			

Now the perspective is define but not yet reachable view the application.

13.2. Select the perspective

13.2.1.  Select perspective via the toolbar / coolbar

You can activate the switch between perspectives the ApplicationWorkbenchWindowAdvisor in method preWindowOpen() with configurer.setShowPerspectiveBar(true);

					
package perspectivetest;

import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;

public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {

	public ApplicationWorkbenchWindowAdvisor(
			IWorkbenchWindowConfigurer configurer) {
		super(configurer);
	}

	public ActionBarAdvisor createActionBarAdvisor(
			IActionBarConfigurer configurer) {
		return new ApplicationActionBarAdvisor(configurer);
	}

	public void preWindowOpen() {
		IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
		configurer.setInitialSize(new Point(400, 300));
		configurer.setShowCoolBar(false);
		configurer.setShowStatusLine(false);
		configurer.setTitle("RCP Application");
		configurer.setShowPerspectiveBar(true);
		// Set the preference toolbar to the left place
		// If other menus exists then this will be on the left of them
		IPreferenceStore apiStore = PlatformUI.getPreferenceStore();
		apiStore.setValue(IWorkbenchPreferenceConstants.DOCK_PERSPECTIVE_BAR,
				"TOP_LEFT");
	}
}

				

You should now be able to select your perspective interactively.

perspective40.gif

13.2.2.  Select perspective via the menu

You can re-use the Eclipse perspective switch in a menu via the following standard command "org.eclipse.ui.perspectives.showPerspective".

See Using Eclipse Commands for details on using Eclipse standard commands.

14. Progress report

If you perform long running operations you should provide the user some information about the long running job. A good way of doing this is to show a progress indicator or a progress dialog.

Create a new project "de.vogella.rcp.intro.progress" with "Hello RCP" as a template. Create the command "de.vogella.rcp.intro.progress.showDialog" with the default handler "de.vogella.rcp.intro.progress.handler.ShowDialog". Create the handler class.

			
package de.vogella.rcp.intro.progress.handler;

import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ui.handlers.HandlerUtil;

public class ShowDialog extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		ProgressMonitorDialog dialog = new ProgressMonitorDialog(HandlerUtil
				.getActiveShell(event).getShell());
		try {
			dialog.run(true, true, new IRunnableWithProgress() {
				@Override
				public void run(IProgressMonitor monitor) {
					monitor
							.beginTask("Doing something timeconsuming here",
									100);
					for (int i = 0; i < 10; i++) {
						if (monitor.isCanceled())
							return;
						monitor.subTask("I'm doing something here " + i);
						sleep(1000);
						monitor.worked(i);
					}
					monitor.done();
				}
			});
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		return null;
	}

	private void sleep(Integer waitTime) {
		try {
			Thread.sleep(waitTime);
		} catch (Throwable t) {
			System.out.println("Wait time interrupted");
		}
	}

}

		

Add this command to the menu.

Run the application. Your command should open a dialog which show the process.

progress10.gif

15. Integrating external jars / third party libraries

15.1.  Overview

Java bundles packages into jars. Eclipse RCP requires that these jars are bundled into plugin project. The following will describes how to integrated these jars into an Eclipse RCP product.

You create a plugin project for these jars and and add this plugin as dependency to your Eclipse RCP application / product.

Tip

If you repack a jars into a plugin it is wise to check if the license of this jar allows this.

15.2. Create a plugin project for your jar

Create a new Plugin project by selection File-> New -> Project...-> Plug-in Development -> Plug-in from existing JAR archives

externaljars20.gif

Add the jars you want to have in this new plugin. Press next.

externaljars25.gif

Maintain a name and a version for this plugin. Uncheck the flag "Unzip the JAR archive into the project". Press then finish.

Tip

Uncheck the flag "Unzip the JAR archive into the project" prevents that the class files are extracted from the Jar.

externaljars30.gif

You have now bundled your jars into a new plugin. Check the MANIFEST.MF on the tab runtime. All the packages from your jars should be included in the exported packages as your Eclipse RCP application will access these packages.

In the plugin project in which you want to use the libraries you can now select your plugin.xml and the tab dependencies. Under required Plug-ins press add and add your generated plugin as a dependency to your RCP application. This will make the classes from the jar available to your plugin.

externaljars40.gif

16. Products and Branding

16.1. Product Configuration

So far your RCP applications can only get started from Eclipse itself. You want to create a stand-alone program . This stand-alone program will be called product.

Tip

In Eclipse terms a product is everything that goes with your application, including all the plugs-ins it depends on, a program to run the application and any branding (icons, etc.) of the application.

To create a product you need a product configuration. This configuration file contains all the information about required packages, configuration file, etc. The configuration file is used for exporting / creating your product.

16.2. Create a project

Create a new RCP project "de.vogella.rcp.intro.deploy" based on the "RCP application with a view" template. Make sure your example runs without problems.

16.3. Create your product configuration

Right-click on your project and select New -> Product Configuration.

product10.gif

Type in the name "de.vogella.rcp.intro.deploy.product" and press finish. Select "Create a configuration file with basis settings".

product20.gif

This will create your product configuration file "de.vogella.rcp.intro.deploy.product" and open the "Overview" Tab of your product configuration.

16.4.  Maintain the overview tab

The overview tab for the product configuration file "de.vogella.rcp.intro.deploy.product" should still be open.

Type in a name for your product. The name of your product is the name which will be displayed in the title of the window.

Tip

You can change this default name in class ApplicationWorkbenchWindowAdvisor in the method preWindowOpen() via the configurer.setTitle("New title");)

Under application select the application of your plugin ("de.vogella.rcp.intro.deploy.application".

product30.gif

You now need to create the product identifier. Press the "New" button under "Specify the product identifier".

product35.gif

Maintain the following.

product40.gif

As a result your product identifier should now be filled.

product45.gif

Tip

The product identifier is stored as extension in the plugin in which you maintain your product configuration file. Open your plugin.xml and have a look at the "org.eclipse.runtime.products" extension point.

16.5.  Maintain the configuration tab

Tip

A product can either be based on plugins or features. In this example we are using plugins. This setting is done on the overview tab.

Switch to the Configuration Tab and click "Add". Select the plugin "de.vogella.rcp.intro.deploy" you created (including plugs-ins for external jars) and press "Add Required Plug-ins". Save and switch back to the overview screen.

product50.gif

16.6. Test your product

On the overview tab press synchronize and then press the launch application.

Tip

Synchronize will allign your product configuration with the other existing configuration files. .

Tip

If you receive the error "Dependent plug-in could not be loaded" or "Application could not be found" then you may have to adjust your launch configuration configuration. Open the launch configuration and press "Add required Plug-ins".

Tip

The launch configuration for your product is automatically created and updated based on your product configuration, e.g. the selected plugins. Changes in the launch configuration will not automatically update the product configuration.

16.7. Splash Screen

The tab "Splash" allows you to specify the splash screen. Your application will use the splash.bmp picture which must be under the main directory. The file must be a bmp file and it must be called splash.bmp.

You can ad a message and a process bar to your splash screen by selecting the corresponding settings.

Create now a bitmap and save it directly in the "de.vogella.rcp.intro.deploy" project. Maintain the the following.

product60.gif

If you now start your application you should see a slashscreen.

16.8. Branding the about Dialog

In this example I do not use this.

The standard Eclipse About Dialog can be branded. You can add an icon and / or and a text to your application.

product70.gif

Add the standard command "org.eclipse.ui.help.about" to your menu to open the about dialog. See Eclipse Commands Tutorial

for details.

16.9. Customizing the start icon and launcher arguments

In this example I do not use this.

The launcher is the executable program that is created during the deployment of the product. Per default "eclipse.exe" with an "eclipse" icon is created. To change this select the launcher tab of your product configuration.

Here you can specify the name of the application and the icon which should be used. Make sure the deep of the icons is correctly maintained otherwise Eclipse will not use these icons.

product78.gif

In the launcher section you can also specify parameters to your Eclipse program or JVM arguments.

16.10. Done

Super. You created your product configuration. The next chapter will explain how to use this configuration to create an product, e.g. a stand- alone program which can be started outside of Eclipse.

17. Deploy your product

To create a standalone program which can run outside of the Eclipse IDE environment you deploy your product. The result can then be shared with your end users.

Eclipse will automatically include all your compiled classes into the build output. You have to manage manually the other files. If you using icons / splash screens images, etc. you have to add them to the build output.

Select your plugin.xml and select the build tab. Make sure the META-INF directory and the file plugin.xml is selected, select your icon directory and any other graphic file which should be included in your output.

deploy40.gif

Tip

Without META-INF directory and the file "plugin.xml" in build the exported product will not start. If after deployment your graphics are missing check this tab if you really include them in the deployment.

Switch now to your product configuration file and select the tab Overview. Click on the "Eclipse Product export wizard" to export your product.

deploy50.gif

Maintain the target directory and press finish.

deploy50.gif

This should create a directory in the specified place with a file "eclipse" or "eclipse.exe" which starts your application. Double click on this to start your application.

If you take the content of this directory and unzip on another machine (which has Java installed) your program should run there too.

Tip

The export dialog allows to created a Archive file which you can the send directly to your users.

18. Externalize strings - Multi Languages

18.1. Externalize strings

The following describes the Eclipse way of replacing strings and how to select them.

Create a new plugin project "MultiLanguage". Use "RCP application with a view" as template.

Change the View.java to the following.

				
package multilanguage;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.part.ViewPart;

public class View extends ViewPart {
	public static final String ID = "MultiLanguage.view";

	
	public void createPartControl(Composite parent) {
		Label label = new Label(parent, SWT.BORDER);
		label.setText("This is a hardcoded text");
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
	}
}
			

Right mouse-click on the source code. Select Source -> Externalize Strings. Select the strings which should be externalized

multilanguage10.gif

Press finished. As a result a class Message.java is created which contains static member variables which can be used in the coding as String replacements. The message.properties contain the real strings.

18.2. Select the message.properties file

Copy message.properties to message_de.properties or message_en.properties to support different strings for different languages.

Tip

You can use the runtime parameter -nl to pass additional parameters for this message.properties should be selected. E.g. if two departments are using the same RCP application but the labels should be labeled differently create message_app1.properties and message_app2.properties and pass -nl app1 or -nl app2 to the runtime argument of the launch configuration (or the product configuration as Program Arguments in the Launching tab.

19. Tips and Tricks

19.1. Save users layout

To remember the user's layout and window size for the next time you start your application, add configurer.setSaveAndRestore(true); to the initialize method of ApplicationWorkbenchAdvisor.

				
package addactiontoview;

import org.eclipse.ui.application.IWorkbenchConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchAdvisor;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;

public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {

	private static final String PERSPECTIVE_ID = "AddActiontoView.perspective";

	public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(
			IWorkbenchWindowConfigurer configurer) {
		return new ApplicationWorkbenchWindowAdvisor(configurer);
	}

	public String getInitialWindowPerspectiveId() {
		return PERSPECTIVE_ID;
	}

	@Override
	public void initialize(IWorkbenchConfigurer configurer) {
		super.initialize(configurer);
		configurer.setSaveAndRestore(true);
	}

}

			

Eclipse has a pre-defined command to reset the perspective. See Eclipse Commands .

19.2. Plugin ID in application

The plugin ID is usually needed in several places, so it is a good idea to declare it as static in Application.java. This ID must be the same as defined in the field "ID" of the overview tab of plugin.xml. The ID is case sensitive.

In our example if the RCP application is called "de.vogella.rcp.intro.first" therefore add the following statement to Application.java.

				
public static final String PLUGIN_ID = "MyFirstRCP";

			

19.3. Add the error log view to your RCP application

Eclipse gives you errors in case something goes wrong. To make these errors visible for the user you can use the exiting error log in your application.

Create a new project "ErrorTest" for this purpose. Use the "Hello RCP" as a template.

Select the plugin.xml and add the dependency to org.eclipse.ui.views.log.

errorLogView10.gif

Now you could add this view directly to your perspective. The view ID is "org.eclipse.pde.runtime.LogView". We will not do this, but use the standard showView command to display the view if requested.

Add therefore the extension point org.eclipse.ui.menus to your application. Create a new menu contribution with the locationURI "menu:org.eclipse.ui.main.menu". Add a new menu and give it the label "Admin".

See Creating commands for details).

Then add the command "org.eclipse.ui.views.showView" to it.

errorLogView20.gif

This command takes the view to open as an argument. Right Click on it, and select new parameter. The ID of the parameter is "org.eclipse.ui.views.showView.viewId" and the ID of the view is "org.eclipse.pde.runtime.LogView".

errorLogView30.gif

Run your new application. You should have a menu entry "Admin" with an entry "Show Error View". If you select it the error view should open.

19.4. Finding unused dependencies

In the file plugin.xml (tab dependencies) you define on which plugins your plugin depends. Of course you should only define the required plugins here. You can check if you have any dependency maintained which is actually not used, by selecting Dependency Analysis -> Find unused dependencies.

unuseddependency10.gif

20. Next steps

In general you find lots of good Eclipse articles on eclipse.org Resources

.

To learn how to use JFace Views you can use Eclipse JFace TableViewer - Tutorial

.

To learn how to use Eclipse Preferences and Preference Pages you can use Eclipse Preferences

.

Good luck in your journey of learning Eclipse the platform!

21. Other Resource