Version 0.8
Copyright © 2007 Lars Vogel
10.04.2008
Abstract
The Eclipse Rich Client Platform (RCP) allows developers to use the Eclipse architecture to design flexible and extensible applications re-using a lot of already existing functionality and coding patterns inherent in Eclipse. Getting started with Eclipse RCP can be time consuming and difficult. Having a short how-to-description makes it easier to get started. Hence the following article focuses on how to get certain aspects of Eclipse RCP into work.
Within this article Eclipse Ganymede (Eclipse 3.4) will be used. Please note that this article is currently in the process of getting updated from Eclipse Europa to Eclipse Ganymede. This update is not yet finished.
The following topics will be covered: Creating a first RCP application, creating menus and toolbars, views, editors, dialogs, usage of preferences and preferences pages, usage of external jars, creating a product and branding and adding help to an RCP application.
Each sections of this article tries to be as independent from the other parts as possible.
Table of Contents
-
1. Rich Client Platform
- 2. Create your first RCP application
- 3. Launch configuration 4. Commands
- 5. System Tray 6. Views
- 7. Working with Editors, View Interaction and Model Updates
- 8. Dialog
- 9. Wizards
- 10. Preferences
- 11. Adding a status line
- 12. Perspectives
- 13. Progress report 14. Deploy your product with external jars
- 15. Tips and Trick
- 16. Making it a product
- 17. Branding
- 18. Deploy your product 19. Links and Literature
While Eclipse is a powerful development environment it can also be used to develop stand-alone general purpose applications which re-use the Eclipse framework.
For an brief introduction into Eclipse, the concepts and terminology (perspective, views, editors) please see Using the Eclipse Java IDE - Tutorial .
For Eclipse the whole RCP Application is a plug-in. A RCP application requires:
-
Main program
-
A Perspective
-
Workbench Advisor
A Workbench Advisor is an invisible technical component which controls the appearance of the application (menus, toolbars, perspectives, etc). Views are technical not required for a RCP application (but an RCP without views would not be very rich).
All plug-ins must provide a so-called manifest named "plugin.xml".
A RCP application extends the class org.eclipse.core.runtime.application. This represents the main program. The perspective is extended from org.eclipse.ui.perspective.
Also required are the two central plug-ins: org.eclipse.core.runtime and org.eclipse.ui
The most important architectural characteristics of Eclipse is the Plug-in architecture. The Eclipse IDE is build as a number of plug-ins which are dependent on each other.
Plug-ins are the smallest deployable and installable software components of Eclipse.
Each plug-in can define so-called extension-points which define possibilities for functionality contributions ( code and non-code ) by other plug-ins. Non-code functionality contributions are for example the provision of help content.
A plug-in 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 plug-in or by other plug-ins).
The basis for this architecture is the runtime environment of Eclipse which is based on the OSGI Alliance. Eclipse used the OSGI reference implementation Equinox to run upon. The Plug-in concept of Eclipse is the same as the bundle concept of OSGI. Generally speaking a OSGI bundle equals a Plug-in 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 (Plug-in Development Environment) which provides a nice user interface for editing this xml file.
Eclipse RCP provides and uses the same framework as the Eclipse Workbench hence allowing the programmer to divide the application functionality into several plug-ins, 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. 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 plug-ins, etc.
Some of the configuration files may be hidden by a filter. In the package explorer select the drop-down menu and then Filter to remove the filter for .* resources.
The plug-in manifest ties all the code and the resources together and is split on two files MANIFEST.MF" and plugin.xml .
The OSGi bundle manifest is stored in MANIFEST.MF.
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 to re-created it, e.g. after import into another workspace. It contains a XML tag "natures" where the nature of the project is described. A plug-in 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 plug-in project.
The following gives a quick guide on how to create a simple RCP application.
In Eclipse select File-> New Project. From the list select Plug-In Project.
Then perform the following steps:
Give your RCP plugin a name, e.g. "MyFirstRCP" .
![](http://www.vogella.de/articles/RichClientPlatform/images/firstrcp10.gif)
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".
![](http://www.vogella.de/articles/RichClientPlatform/images/firstrcp20.gif)
As a template select the "Hello RCP" .
![](http://www.vogella.de/articles/RichClientPlatform/images/firstrcp30.gif)
On the next screen select "Add branding" and press Finish.
![](http://www.vogella.de/articles/RichClientPlatform/images/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.
![](http://www.vogella.de/articles/RichClientPlatform/images/firstrcp50.gif)
The plug-in 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.
For example if your RCP application is called MyFirstRCP add the following declaration to Application.java.
public static final String PLUGIN_ID = "MyFirstRCP";
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".
![](http://www.vogella.de/articles/RichClientPlatform/images/firstrcp60.gif)
The result should look like the following:
![](http://www.vogella.de/articles/RichClientPlatform/images/firstrcp70.gif)
Congratulations, you have created your first RCP application.
A Launch configuration in Eclipse defines the environment under which your application will be started, e.g. compiler flag, plug-in (classpath) dependencies etc.
Select your plugin.xml -> Run As -> Run Configurations
![](http://pierre.iteye.com/admin/blogs/images/launchconfiguration10.gif)
![](http://pierre.iteye.com/admin/blogs/images/launchconfiguration20.gif)
You can specify the location of the Workspace Data. In this location the directory and the files required to run your RCP application will be created.
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.
Tip
Always add the parameter -consoleLog as an argument.
![](http://pierre.iteye.com/admin/blogs/images/launchconfiguration30.gif)
On the Plug-ins Tab select "Validate plug-ins prior to launching". This will check if you have all required plug-ins in your launch configuration. If this check reports that some Plug-ins are missing, try clicking the "Add Required-Plug-Ins" button.
Tip
Always set the flag "Validate plug-ins prior to launching".
![](http://pierre.iteye.com/admin/blogs/images/launchconfiguration40.gif)
As of Eclipse 3.3. it is recommended to use the commmand API to define menus, pop-up menu items and toolbars.
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.
Our first example will be a command which will exit the application. Create a new project "Command Test" and use the "Hello RCP" Template (see Create your first Eclipse RCP application for details).
You need the extension org.eclipse.ui.commands. Click on the plugin.xml and select the Extensions tab.
![](http://pierre.iteye.com/admin/blogs/images/command10.gif)
Press the add button and search for the extension extension org.eclipse.ui.commands. Select it and press finish.
![](http://pierre.iteye.com/admin/blogs/images/command20.gif)
Create a new command by right-clicking New -> command.
![](http://pierre.iteye.com/admin/blogs/images/command30.gif)
Set the ID to "exit.command" and the name to "Exit". Enter the class commandtest.handler.ExitHandler as defaultHandler.
![](http://pierre.iteye.com/admin/blogs/images/command40.gif)
Press the hyperlink "defaultHandler" to create this class.
Choose org.eclipse.core.commands.AbstractHandler as Superclass.
![](http://pierre.iteye.com/admin/blogs/images/command50.gif)
Tip
IHandler defines the following methods which can be implemented:-
isEnabled: Called during instantiation, defines if this action is enabled
-
isHandled: Defines if the handler can be called or not
-
execute: Coding which perform the action
-
fireHandlerChanged: needs to be called if isEnabled is changed.
Implement the following coding
package commandtest.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.ui.handlers.HandlerUtil; public class ExitHandler extends AbstractHandler implements IHandler { @Override public Object execute(ExecutionEvent event) throws ExecutionException { HandlerUtil.getActiveWorkbenchWindow(event).close(); return null; } }
Tip
The class HandlerUtil provides access methods to the important Eclipse services.
You have correctly implemented the command. This command can now be used in various placed in your application.
Tip
Instead of using the default handler in the command you could also have used the "org.eclipse.ui.handlers"
4.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.menu" to your application. Select therefore again plugin.xml and the tab "Extensions". Press Add, select the extension point "org.eclipse.ui.menu" and press Finish.
![](http://pierre.iteye.com/admin/blogs/images/command60.gif)
Right click on the extension point and select new -> menuContribution. Create a new menu contribution with the location URI "menu:org.eclipse.ui.main.menu".
-
menu: Extension of the menu of the application
-
toolbar: Extension of the toolbar of a view
-
popup: A context menu
Tip
The first part of the location URI defines what kind of menu contribution this is:
Tip
Make sure the URL must is correct, otherwise the menu will not get displayed.
![](http://pierre.iteye.com/admin/blogs/images/command70.gif)
![](http://pierre.iteye.com/admin/blogs/images/command80.gif)
Right click your menucontribution and select New -> Menu. Add a menu with the label "File" and the id "mymenu".
![](http://pierre.iteye.com/admin/blogs/images/commandmenu10.gif)
![](http://pierre.iteye.com/admin/blogs/images/commandmenu20.gif)
Now select your menu, right-click on it and select New-> Command. Maintain here the commandID you used earlier. Choose also a label.
![](http://pierre.iteye.com/admin/blogs/images/commandmenu30.gif)
If you the example you should see menu with the file. Selecting Exit should end your application.
![](http://pierre.iteye.com/admin/blogs/images/commandmenu40.gif)
You can also add to the view toolbar. Create a new plug-in project "CommandViewContribution" with the template "RCP application with a view". Run the project to see the user interface.
Change Perspective.java to the following (a standalone view does not have a own toolbar.
package commandviewcontribution; 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(false); layout.setFixed(true); layout.addView(View.ID, IPageLayout.LEFT, 1.0f, editorArea); } }
Switch to plugin.xml and add a new command with the id "hello.command" with default handler "handler.HelloHandler" and create the following coding for the handler.
package 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.dialogs.MessageDialog; import org.eclipse.ui.handlers.HandlerUtil; public class HelloHandler extends AbstractHandler implements IHandler { @Override public Object execute(ExecutionEvent event) throws ExecutionException { MessageDialog .openInformation(HandlerUtil.getActiveWorkbenchWindow(event).getShell(), "Info", "Info for you"); return null; } }
Add the extension point org.eclipse.ui.menus (fill out the ID and the name) and create a new menu contribution with the locationURI: "toolbar:CommandViewContribution.view".
Tip
toolbar tells the system to add it to the toolbar while the second argument is the id of your view (CommandViewContribution.view).
Create then a new command for this menucontribution and set the commandid to "hello.command" and the id to hello.menu. Assign the label "Hello" to it. Run it and it should show the contribution in the view.
![](http://pierre.iteye.com/admin/blogs/images/commandview10.gif)
Run the application to see your new view contribution.
![](http://pierre.iteye.com/admin/blogs/images/commandview10.gif)
Lets add the command from the last section also to the application coolbar. Therefore you add a new menucontribution to your org.eclipse.ui.menus extension point and you call it "toolbar:org.eclipse.ui.main.toolbar".
![](http://pierre.iteye.com/admin/blogs/images/commandcoolbar10.gif)
Add a toolbar to your menu contribution.
![](http://pierre.iteye.com/admin/blogs/images/commandcoolbar20.gif)
Add then a command to it, again using the ID hello.command. Assign a label and an icon to it.
You need also to activate the coolbar in your application. Switch to ApplicationWorkbenchWindowAdvisor.java and turn the coolbar on via configurer.setShowCoolBar(true);
package commandviewcontribution; 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(true); configurer.setShowStatusLine(false); } }
The result should look like the following:
![](http://pierre.iteye.com/admin/blogs/images/commandcoolbar30.gif)
Now lets try to add a ContextMenu to a table. Create a new project CommandContextMenu based on the "RCP with a view" example.
Create a new command "showselected.command" with the default handler "handler.ShowSelectedHandler".
Add a new menuContribution with the locationURI "popup:CommandContextMenu.view", where "popup:CommandContextMenu.view" is the ID of your view which has been automatically created for you.
Right click your new menuContribution and select New -> Command. Assign the commandID "showselected.command". Label it "List selected".
Now you have add a MenuManager to your view. Select View.java and in the method createPartControl add the following:
public void createPartControl(Composite parent) { viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); viewer.setContentProvider(new ViewContentProvider()); viewer.setLabelProvider(new ViewLabelProvider()); viewer.setInput(getViewSite()); // This is new code // First we create a menu Manager MenuManager menuManager = new MenuManager(); Menu menu = menuManager.createContextMenu(viewer.getTable()); // Set the MenuManager viewer.getTable().setMenu(menu); getSite().registerContextMenu(menuManager, viewer); }
Implement now the coding for your handler. I just print the selected elements to the console.
package handler; import java.util.Iterator; 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.handlers.HandlerUtil; public class ShowSelectedHandler extends AbstractHandler implements IHandler { @Override public Object execute(ExecutionEvent event) throws ExecutionException { ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event) .getActivePage().getSelection(); if (selection != null & selection instanceof IStructuredSelection) { IStructuredSelection strucSelection = (IStructuredSelection) selection; for (Iterator iterator = strucSelection.iterator(); iterator.hasNext();) { Object element = (Object) iterator.next(); System.out.println(element.toString()); } } return null; } }
Run your application. On right mouse click the menu should be visible. If you select it menu then the names of the selected items should be writen to the console.
Via keybindings you can define shortcuts for your commands.
Create a new project "CommandKey", declare command "hello.command" with a handler which does something, e.g. prints out "Hello" to the console
Right mouse click on the command extension and select New-> "keybinding"
![](http://pierre.iteye.com/admin/blogs/images/keybinding10.gif)
Maintain the following settings. The "keyConfigurationId" define the validity of the keybinding. "org.eclipse.ui.defaultAcceleratorConfiguration" is the workbench default and will make sure you keybinding is valid in the whole application. The commandId is the ID of the command you just created (in our example "hello.command"). The key sequence is the shortcut key for calling the command. M1 represents the Cntr key.
![](http://pierre.iteye.com/admin/blogs/images/keybinding20.gif)
If you now run it the keybinding should work and if you press Cntrl+1 the message on the console should be visible.
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 actions to the system tray icon.
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.
Create a new project "TrayTest" (see Create your first Eclipse RCP application for details). Use the "Hello RCP application" as a template.
Define your application ID as "TrayTest" in Application.java.
import org.eclipse.equinox.app.IApplication; public class Application implements IApplication { public static final String PLUGIN_ID = "TrayTest"; ......
Your project should have already a folder with icons. Check what you have icon "alt_about.gif" available.
Maintain the following code in class ApplicationWorkbenchWindowAdvisor. Note that you have to finished also the next part of the coding implementation, only this change will leave syntax errors. These will be gone after you make the change in "ApplicationActionBarAdvisor".
package traytest; import org.eclipse.jface.action.MenuManager; 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.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.plugin.AbstractUIPlugin; public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { private TrayItem trayItem; private Image trayImage; private IWorkbenchWindow window; public ApplicationActionBarAdvisor actionBarAdvisor; public ApplicationWorkbenchWindowAdvisor( IWorkbenchWindowConfigurer configurer) { super(configurer); } public ActionBarAdvisor createActionBarAdvisor( IActionBarConfigurer configurer) { actionBarAdvisor = new ApplicationActionBarAdvisor(configurer); return actionBarAdvisor; } 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) { // The following coding will will the program if the program is // minimized // Not always desired createMinimize(); // Create exit and about action on the icon hookPopupMenu(); } } private void hookPopupMenu() { trayItem.addListener(SWT.MenuDetect, new Listener() { public void handleEvent(Event event) { MenuManager trayMenu = new MenuManager(); Menu menu = trayMenu.createContextMenu(window.getShell()); actionBarAdvisor.fillTrayItem(trayMenu); menu.setVisible(true); } }); } 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 TrayItem initTaskItem(IWorkbenchWindow window) { final Tray tray = window.getShell().getDisplay().getSystemTray(); TrayItem trayItem = new TrayItem(tray, SWT.NONE); trayImage = AbstractUIPlugin.imageDescriptorFromPlugin( Application.PLUGIN_ID, "/icons/alt_about.gif").createImage(); trayItem.setImage(trayImage); trayItem.setToolTipText("TrayItem"); return trayItem; } public void dispose() { if (trayImage != null) { trayImage.dispose(); trayItem.dispose(); } } }
Now create the actions and the method fillTrayItem.
package traytest; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; import org.eclipse.ui.application.ActionBarAdvisor; import org.eclipse.ui.application.IActionBarConfigurer; public class ApplicationActionBarAdvisor extends ActionBarAdvisor { private IWorkbenchAction exitAction; private IWorkbenchAction aboutAction; public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) { super(configurer); } protected void makeActions(IWorkbenchWindow window) { exitAction = ActionFactory.QUIT.create(window); register(exitAction); aboutAction = ActionFactory.ABOUT.create(window); register(aboutAction); } protected void fillMenuBar(IMenuManager menuBar) { } public void fillTrayItem(MenuManager trayMenu) { trayMenu.add(aboutAction); trayMenu.add(exitAction); } }
Run your application and see that you have a system tray icon. Test the menu and the minimized behavior.
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.
Create a new project "ViewTemplateTest" (see Create your first Eclipse RCP application for details). Use the "Hello RCP" as a template.
Select your plugin.xml and select the extension tab. Press the "Add" button. Select the extension wizard tab.
Follow the following steps:
![](http://pierre.iteye.com/admin/blogs/images/addview1.jpg)
![](http://pierre.iteye.com/admin/blogs/images/addview2.jpg)
![](http://pierre.iteye.com/admin/blogs/images/addview3.jpg)
![](http://pierre.iteye.com/admin/blogs/images/addview4.jpg)
Change the ID of your new view to viewtemplatetest.views.MyTemplateView.
![](http://pierre.iteye.com/admin/blogs/images/addview50.gif)
If you run the application the new view is not displayed. To use the view you have to have to add it in method createInitialLayout of class Perspective. The first parameter of addView is the ID which you defined in your plugin.xml.
package viewtemplatetest; import org.eclipse.ui.IPageLayout; import org.eclipse.ui.IPerspectiveFactory; public class Perspective implements IPerspectiveFactory { public void createInitialLayout(IPageLayout layout) { layout.addView("viewtemplatetest.views.MyTemplateView", IPageLayout.TOP, IPageLayout.RATIO_MAX, IPageLayout.ID_EDITOR_AREA); } }
Run the application and see that the view is displayed.
![](http://pierre.iteye.com/admin/blogs/images/addview60.gif)
Note: If the view should not be closeable add the following setting to the view: layout.getViewLayout("myplugin.views.MySampleView1").setCloseable(false); or if all views not not be closeable call setFixed(true) on the layout inside method createInitialLayout(); A fixed perspective makes the view not resizable and closeable. Also views can not be moved.
Create a new project "ViewTest" Create your first Eclipse RCP application for details). Use the "Hello RCP" as a template.
Select the file plugin.xml and the tab extensions. Press the "add" button and add org.eclipse.ui.views as an extension.
![](http://pierre.iteye.com/admin/blogs/images/addview70.gif)
Right mouse-click on your new view extension and select New -> View
![](http://pierre.iteye.com/admin/blogs/images/addview80.gif)
Maintain the ID ViewTest.MyNewView and the class viewtest.MyNewView.
![](http://pierre.iteye.com/admin/blogs/images/addview90.gif)
Create the class of the view by clicking on the class hyperlink.
![](http://pierre.iteye.com/admin/blogs/images/addview100.gif)
Maintain the following code in your new class.
package viewtest; 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 MyNewView extends ViewPart { public MyNewView() { // TODO Auto-generated constructor stub } @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() { // TODO Auto-generated method stub } }
In Perspective.java add your new view.
package viewtest; import org.eclipse.ui.IPageLayout; import org.eclipse.ui.IPerspectiveFactory; public class Perspective implements IPerspectiveFactory { public void createInitialLayout(IPageLayout layout) { layout.addView("ViewTest.MyNewView", IPageLayout.TOP, IPageLayout.RATIO_MAX, IPageLayout.ID_EDITOR_AREA); } }
Run the application.
![](http://pierre.iteye.com/admin/blogs/images/addview110.gif)
In the following we create a project which demonstrate the usage of editors and its interaction with an view. We are also going to see how an application can access an external domain model and how a domain model can notify views and editors about changes.
We will create a simple application with a view which shows first and last name of a list of persons. Once the user double-clicks on the name an editor is opened in which the user can edit the name.
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.
Create a new project "EditorTest" (see Create your first Eclipse RCP application for details). Use the "RCP application with a view" as a template.
![](http://pierre.iteye.com/admin/blogs/images/editor10.gif)
Create a package mydomain. Create class MyModel.java in this package.
package mydomain; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class MyModel { private List<Person> persons = new ArrayList<Person>(); private List<PropertyChangeListener> listener = new ArrayList<PropertyChangeListener>(); public class Person { private String firstName; private String lastName; 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; notifyListeners(); } } public List<Person> getPersons() { return persons; } public MyModel() { // Just for testing we hard-code the persons here: persons.add(new Person("Lars", "Vogel")); persons.add(new Person("Jim", "Knopf")); } private void notifyListeners() { for (Iterator iterator = listener.iterator(); iterator.hasNext();) { PropertyChangeListener name = (PropertyChangeListener) iterator .next(); name.propertyChange(null); } } public void addChangeListener(PropertyChangeListener newListener) { listener.add(newListener); } }
Create a new package editortest.contentProvider
Create a new class "MyContentProvider" which implements the interface IStructuredContentProvider.
![](http://pierre.iteye.com/admin/blogs/images/editor20.gif)
Adjust the coding according to the following example:
package editortest.contentProvider; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import mydomain.MyModel; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.Viewer; public class MyContentProvider implements IStructuredContentProvider, PropertyChangeListener { private MyModel content; private final Viewer viewer; public MyContentProvider(Viewer viewer) { this.viewer = viewer; content = new MyModel(); content.addChangeListener(this); } @Override public Object[] getElements(Object inputElement) { return content.getPersons().toArray(); } @Override public void dispose() { // TODO Auto-generated method stub } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // TODO Auto-generated method stub } @Override public void propertyChange(PropertyChangeEvent arg0) { viewer.refresh(); } }
Create a new class "MyLabelProvider" which implements the interface ILabelProvider. Use the following code.
package editortest.contentProvider; import mydomain.MyModel.Person; 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; 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) { // TODO Auto-generated method stub } @Override public void dispose() { // TODO Auto-generated method stub } @Override public boolean isLabelProperty(Object element, String property) { // TODO Auto-generated method stub return false; } @Override public void removeListener(ILabelProviderListener listener) { // TODO Auto-generated method stub } }
Change the class View to use your new content providers.
package editortest; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.part.ViewPart; import editortest.contentProvider.MyContentProvider; import editortest.contentProvider.MyLabelProvider; public class View extends ViewPart { public static final String ID = "EditorTest.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(getViewSite()); } /** * Passing the focus request to the viewer's control. */ public void setFocus() { viewer.getControl().setFocus(); } }
Run your application. The view should now display the last names for your content provider. Currently nothing happens if you click on the names.
Go to plugin.xml and select the tab extensions. Add the extension org.eclipse.ui.editors. Do not use a template. Use the ID "editortest.editors.MyNameEditor", any name you want and the class "editortest.editors.MyNameEditor".
Make also sure to select an icon! Otherwise your editor will not work.
![](http://pierre.iteye.com/admin/blogs/images/editor30.gif)
![](http://pierre.iteye.com/admin/blogs/images/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 editortest.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; public class MyNameEditor extends EditorPart { public static final String ID = "editortest.editors.MyNameEditor"; private Text text1; private Text text2; public MyNameEditor() { // TODO Auto-generated constructor stub } @Override public void doSave(IProgressMonitor monitor) { // TODO Auto-generated method stub } @Override public void doSaveAs() { // TODO Auto-generated method stub } @Override public void init(IEditorSite site, IEditorInput input) throws PartInitException { setSite(site); setInput(input); setPartName(input.getName()); } @Override public boolean isDirty() { // TODO Auto-generated method stub return false; } @Override public boolean isSaveAsAllowed() { // TODO Auto-generated method stub 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("First Name"); text1 = new Text(parent, SWT.BORDER); Label label2 = new Label(parent, SWT.BORDER); label2.setText("Last Name"); text2 = new Text(parent, SWT.BORDER); } @Override public void setFocus() { // TODO Auto-generated method stub } }
In package editortest.editors create a new class "MyNameEditorInput" which implements IEditorInput.
![](http://pierre.iteye.com/admin/blogs/images/editor50.gif)
Change the created code the the following. It is important to note that the class which implements IEditorInput is a light-weight representation of the model. It should not contain the model. We cover this later (via view and editor linking).
It is recommended to overwrite the method equals and hashcode in an implementation of IEditorI. Based on the equals method the system will determine if the corresponding editor is already open or not.
package editortest.editors; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IPersistableElement; public class MyNameEditorInput implements IEditorInput { private final String lastname; public MyNameEditorInput(String lastname) { this.lastname = lastname; } @Override public boolean exists() { // TODO Auto-generated method stub return false; } @Override public ImageDescriptor getImageDescriptor() { // TODO Auto-generated method stub return null; } @Override public String getName() { return lastname; } @Override public IPersistableElement getPersistable() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.eclipse.ui.IEditorInput#getToolTipText() */ @Override public String getToolTipText() { return "My Tool Tip"; } @Override public Object getAdapter(Class adapter) { // TODO Auto-generated method stub return null; } @Override public boolean equals(Object obj) { if (super.equals(obj)) { return true; } if (obj instanceof MyNameEditorInput) { return lastname.equals(((MyNameEditorInput) obj).getName()); } return false; } @Override public int hashCode() { return lastname.hashCode(); } }
Add an action to your view which opens a new editor every time a new item is double-clicked. The view makes his viewer available as selection provider via the following line:" getSite().setSelectionProvider(viewer);". This make is possible for other components, e.g. editors or views to register them as listeners to changes of the view. After opening a editor we also sending out this change to the listeners via "viewer.setSelection(viewer.getSelection());". We will later register the editor as listener. Change therefore the code of View.java to the following.
package editortest; import mydomain.MyModel.Person; import org.eclipse.jface.action.Action; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPage; import org.