The best way of showing the basics of client application development with the Eclipse RCP is by using an example. As we have seen in Chapter 8, Eclipse Development, Eclipse contains useful plugin project templates that can get you going into plugin development in no time. The same goes for RCP applications. Let's create a new RCP application project using a template to have an idea of what a basic RCP application project looks like.
The process of creating an RCP application is very similar to that of creating a plugin project. Navigate to File | New | Other, and in the wizard window, select Plug-in Project. Click on Next. In the next wizard window, fill in the project's Name field with something such as HelloRCP
, and then click on Next. In the next window, select Yes for the Would you like to create a rich client application question, as shown in the following screenshot:
The next wizard window contains the available RCP templates. Let's use the RCP application with a view template. The last page contains some basic information required by this template. Let's leave the default values and click on Finish. You will be asked if you want to switch to the Plug-in Development perspective at this point if you're not already using it. This perspective adds views and menu entries that can be very useful for plugin development, so go ahead and choose Yes. The project will appear in the Package Explorer window and the Plug-in Manifest Editor window will be opened.
If you take a look at the project's contents, you will notice that they are very similar to the contents of a Plug-in project. This is because an RCP application is actually a plugin. The implementation of the org.eclipse.core.runtime.applications
extension point, which can be verified in the Extensions tab of the Plug-in Manifest Editor window, sets it apart from a regular plugin project. Notice that the Application element points to a class named Application
.
We will now look at the content of classes generated by the template to understand what they do and why they are there. Let's start with the Application.java
source file. As you can see, this class is an implementation of the IApplication
interface, which contains the following two methods:
public Object start(IApplicationContext context) { Display display = PlatformUI.createDisplay(); try { int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor()); if (returnCode == PlatformUI.RETURN_RESTART) { return IApplication.EXIT_RESTART; } return IApplication.EXIT_OK; } finally { display.dispose(); } }
And
/* (non-Javadoc) * @see org.eclipse.equinox.app.IApplication#stop() */ public void stop() { if (!PlatformUI.isWorkbenchRunning()) return; final IWorkbench workbench = PlatformUI.getWorkbench(); final Display display = workbench.getDisplay(); display.syncExec(new Runnable() { public void run() { if (!display.isDisposed()) workbench.close(); } }); }
As the names imply, the start
method is called during the application's startup, and the stop
method is called when the application is stopped. The start
method can return any type of object, including integers, as is the case with the Application
implementation. This is a very basic implementation that simply creates a new Display
object and calls the static PlatformUI.createAndRunWorkbench
method. This method receives a WorkbenchAdvisor
object as a parameter. This object allows you to configure some basic aspects of your application's look and feel. Every RCP application must implement a WorkbenchAdvisor
object. The Display
object manages the connection between SWT and the operating system. For most RCP applications, you won't need much more than these in the start
method to get it going. The stop
method simply closes the workbench created during the start
method.
Now let's take a closer look at the generated extension of the WorkbenchAdvisor
class, the ApplicationWorkbenchAdvisor
extension:
public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor { private static final String PERSPECTIVE_ID = "HelloRCP.perspective"; public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( IWorkbenchWindowConfigurer configurer) { return new ApplicationWorkbenchWindowAdvisor(configurer); } public String getInitialWindowPerspectiveId() { return PERSPECTIVE_ID; } }
The getInitialWindowPerspectiveId
method determines which perspective will be displayed when a new window of our application is opened. The CreateWorkbenchWindowAdvisor
method is responsible for instantiating and returning a WorkbenchWindowAdvisor
object, which configures the application window itself. Our implementation returns an instance of ApplicationWorkbenchWindowAdvisor
extension, which extends WorkbenchWindowAdvisor
object. Let's take a look at its implementation:
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"); } }
The preWindowOpen
method implementation calls getWindowConfigurer
and performs some actions on the IworkbenchWindowConfigurer
configurer, such as setting an initial size for the application window, disabling the coolbar and status line, and setting a title for the application. The createActionBarAdvisor
method instantiates and returns ApplicationActionBarAdvisor
, which extends ActionBarAdvisor
. ActionBarAdvisor
creates, adds, and disposes the JFace actions of a workbench window. A JFace action is a command that can be triggered by the end user utilizing UI elements, such as buttons, menu items, and items in the toolbar. The ApplicationActionBarAdvisor
implementation doesn't modify ActionBarAdvisor
's behavior.
Now, let's go back to the Plug-in Manifest Editor window and see what other plugins are required to build a fully functional RCP application. As we said in the beginning of the chapter, an RCP application is something like an Eclipse instance stripped of every Eclipse graphical element. This means you must create these elements if you want your application to function properly. The first thing we need is a perspective, which is created by implementing the org.eclipse.ui.perspectives
extension point. The perspective element contains an ID, which must be unique across the applications, must be a user-friendly name that will be displayed in the interface, and a class. Let's take a look at the Perspective
class code:
public class Perspective implements IPerspectiveFactory { public void createInitialLayout(IPageLayout layout) { layout.setEditorAreaVisible(false); layout.setFixed(true); } }
The code shows us that perspective classes must implement the IPerspectiveFactory
interface, which contains the createInitialLayout
method. The implementation generated by the template simply removes the editor area from the application and disallows users to modify the view's size and placement by calling the setFixed
method. The editor area is a space in the center of the application's window that is reserved for editors. Any other views will be rendered either below, to the left of, or to the right of this area. The editor area is disabled for our application because it doesn't have any editors.
This method could also be used to add the views to the perspective by calling the layout.addView
method. However, the code generated by the template uses a different approach. Go back to the Plug-in Manifest Editor window and take a look at the org.eclipse.ui.perspectiveExtensions
implementation. This extension point allows you to add a view to an existing perspective. This approach is generally used when you want to add a view to a perspective that wasn't developed by you. In this case, you wouldn't have access to the IPerspectiveFactory
implementation to add a layout.addView
call to the createInitialLayout
implementation.
The perspectiveExtension
element is where you define the ID of the perspective that will receive the view. This field allows using the *
(asterisk) character, which will cause the view to be added to every perspective that matches the pattern. For example, org.eclipse.jdt.*
would include the view in every Java Development Tools (JDT) perspective. This is another benefit of using the perspectiveExtensions
extension point instead of calling layout.addView
in the IPerspectiveFactory
implementation. It simplifies the task of managing the perspectives into which the view is added. In our example, targetID
is simply *
, which means that in HelloRCP.view
, the view will be added to every perspective available (there's only one perspective in our application).
Speaking of the view, let's take a look at the org.eclipse.ui.views
extension. This is a simple view, just like the one we created in Chapter 8, Eclipse Development. It points to a View class that extends the ViewPart
abstract class. The createPartControl
method instantiates a TableViewer
object and associates a content provider and a label provider to it. We will explore the concepts of a label and content providers when we expand this example in the later sections. TableViewer
is a JFace widget that displays content in a table-like list, similar to the one utilized in JDT's Problems view.
The last extension point that our RCP application implement is org.eclipse.ui.menus
. It simply provides a File menu contribution that contains an Exit entry. This entry runs the org.eclipse.ui.file.exit
command, which causes the program to exit.