Eclipse Plugin Development TUTORIAL

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 163

ECLIPSE PLUGIN DEVELOPMENT TUTORIAL

Eclipse Plugin Development Tutorial website to teach you how to develop eclipse plugins using
simple examples to a complex eclipse rcp over time. This chapter will give you a detailed insight into
Eclipse Architecture and we will develop a simple but fully functional eclipse plug-in so as to give you a
quick start with eclipse plug-in development.

Overview

Eclipse isn’t a huge single java program, but rather a small program which provides the functionality
of typical loader called plug-in loader. Eclipse (plug-in loader) is surrounded by hundreds and
thousands of plug-ins. Plug-in is nothing but another java program which extends the functionality of
Eclipse in some way. Each eclipse plug-in can either consume services provided by other plug-in or
can extend its functionality to be consumed by other plug-ins. These plug-in are dynamically loaded

by eclipse at run time on demand basis.

An Open Platform

Eclipse is an open platform. It is designed to be easily and infinitely extensible by third parties. At the
core is the eclipse SDK, we can build various products/tools around this SDK. These products or tools
can further be extended by other products/tools and so on. For example, we can extend simple text
editor to create xml editor. Eclipse architecture is truly amazing when it comes to extensibility. This
extensibility is achieved by creating these products/tools in form of plug-ins.

Figure 1-1

Inside the Eclipse SDK


Figure 1-2

RCP: On the bottom is RCP which provides the architecture and framework to build any rich client
application.

IDE: It is a tools platform and a rich client application itself. We can build various form of tooling by
using IDE for example Database tooling.

JDT: It is a complete java IDE and a platform in itself.

PDE: It provides all tools necessary to develop plug-ins and RCP applications. This is what we will
concentrate on the course of this tutorial.

Plug-ins everywhere

All the layers in eclipse SDK are made up of plug-ins. If you see all the way, you will notice that
everything is a plug-in in eclipse sdk.
Figure 1-3

Plug-in Architecture

A plugin is a small unit of Eclipse Platform that can be developed separately. It must be noted that all
of the functionality of eclipse is located in different plugins (except for the kernel)

A plug-in can be delivered as a jar file. A plug-in is self-contained bundle in a sense that it contains
the code and resources that it needs to run for ex: code, image files, resource bundles etc. A plug-in is
self describing - when I say it is self describing it means that it describes who it is and what it
contributes to the world. It also declares what it requires from the world.
ECLIPSE PLUG IN DEVELOPMENT (PAGE 2)

A Mechanism For Extensibility

Figure 1-7

We all know that eclipse is extensible. In order to achieve this extensibility eclipse uses the concept of
extension points and extension. Think of extension point as Electric socket and think of extension as a
plug. Plug-in A exposes a extension point (electric socket) which Plug-in B extends by providing an
extension (an electric plug). Plug-in A knows nothing about plug-in B. If we think about it this is very
similar to concept of Inheritance – we extend functionality of base class to provide more specific
implementation. Think of Plug-in A as a text editor and Plug-in B as xml editor. Text editor declares
extension point thereby declaring to the world that it is open for extension and xml editor extends text
editor by using its extension point to customize it in its own way. It is important to understand that
each extension point essentially declares
a contract. An extension point provider only accepts those extensions which abide by the contract.

These extension points and extensions are declared in plugin.xml (discussed earlier). The runtime is
able to wire extensions and extension points and form a registry using markup alone.

Plug-in Example

Now that we have covered good amount of architecture basics, its time to get our hands dirty with
some actual plug-in coding. The process for creating a plug-in is best demonstrated by implementing a
plug-in on which discussion and examples can be based. Here we will take a step-by-step approach to
create a simple but fully operational plug-in. This example will try to give you an feel of eclipse plug-in
development. However, don’t try to grab all the details at this point. It is fine if you are not able to
understand much of the details in this example. Rest of the tutorial will cover all the topics in great
depth.

We will build a simple Resource Manager plug-in. Features of this plug-in are as follows:

• Ability to add/remove resources (essentially files in workspace) to resource manager.


• Display list of resources which were added to resource manager.
• Ability to open up associated editor whenever resource is clicked.

Note: All Examples in this tutorial have been implemented using Eclipse version 3.1.2

Creating a Plug-in
1. Launch Eclipse.
2. From File menu, select New Project. This will open up New Project wizard.
3. Now select Plug-in Project and click on the next button. (see Figure 1-8)

Figure 1-8

4. On next page of the wizard (see Figure 1-9), enter the name of the project "com.myplugin.rmp"
Figure 1-9

5. Fill in the other fields as shown and then click the Next button. The next wizard page displays
options for generating plug-in Java class. Fill all the fields as shown below. Do not fill anything in
classpath field - This has been removed in eclipse 3.4. Plug-in Activator is required if we want to do
anything on plug-in start up or shut down. For example we want to acquire some resources at plug-in
start up and perform clean up when plug-in is shutdown. It is important to note that Eclipse startup
does not essentially means that your plug-in is starting up. Plug-ins are loaded/started only when they
are demanded or required. So activator is used when plug-in startup/shutdown happens.
Figure 1-10

6. Click Next, select Plug-in with a view and then click the Next button.
Figure 1-11

7. Next, Enter the values for this page (see Figure 1-12), and click the Next button.
Figure 1-12

8. Finally, uncheck all the options (see Figure 1-13). and click Finish button.
ECLIPSE PLUGIN TUTORIAL (PAGE 3)

After completing New plug-in Project wizard following directory structure will be created (Figure 1-14).
Figure 1-14

Four important files to look for are:

• RmpPlugin.java – This is the main plug-in class. When plug-in is activated, startup method of
this class is called. This class can be used to initialize plugin specific resources.
• ResourceManagerView.java – This is the View class which gets generated. This class
contributes to the UI of our example Resource manager plug-in.
• MANIFEST.MF – defines runtime information of the plugin
• Plugin.xml – defines the extension information of the plug-in.

In order to open up plug-in manifest editor double click on MANIFEST.MF or plugin.xml file. Browse
through the tabs shown at the bottom of editor. Don’t worry if you are unable to understand all of the
content in this editor, it will be discussed during course of this tutorial.

Manifest Editor - Dependencies Tab

Figure 1-15

In This section a plug-in must list all the dependent plug-ins which are required so that our plug-in
compiles. As you know that we build our plug-ins on top of other plug-ins, so this section essentially
declares all those dependencies.

It must be noted that all above plug-in dependencies must be met before plug-in is resolved. It is
always good to scan your dependencies from time to time and remove unused dependencies. In order
to know unused dependencies use Dependency Analysis section.

Manifest Editor – Runtime Tab

Figure 1-16

On this page plug-in declares what all it exposes to the outside world. Lets understand this concept
with an example. Say you are building Plug-in A. Now if plug-in B wants to extend plug-in A or wants
to use plug-in A in any way it will be required that Plug-in A exposes its API’s. It is here that Plug-in A
would declare all the packages which it wants to expose to outside world. You can use Add.. button to
see all your plug-in packages and then select all Packages which you would like to export.

Another important section on this page is the Classpath. If your plug-in is using some external jars
then it is important to add such jars to runtime classpath. Note that simply adding such jars to project
classpath will only help you in compiling your source code. In order to make these jars available to
runtime environment use Classpath section.

Manifest Editor – Extensions Page


Figure 1-17

Extensions page is a viewer on top of plugin.xml. This is one of the most frequently used page in plug-
in development. This page makes it easy to create extensions as this page is aware of all the
extension points. Eclipse provides around 213 extension points where clients can contribute
functionality. Extension points are available for virtually every thing for ex: builders, editors,
preferences, help contents, markers, views, perspective and so on. Basically we select some extension
point and then use these to build our own extensions.

Manifest Editor – Extension Points


Figure 1-18

This page is also a viewer on top of plugin.xml. This page is used to define our own extension points.
Such extension points define a contract which other plug-ins may agree to abide by and extend plug-
ins functionality in some way.

Test New Plug-in

There are two ways to test this plug-in. First, we can build a product which will essentially create a
plugin bundle, this bundle is then dumped into plug-in folder of eclipse installation. Second, launching
new plug-in from within Overview tab of manifest editor. At this time we will take second approach to
test this plug-in. This is also the preferable choice when we are developing eclipse plug-ins and need
to test them from time to time. In order to test this plug-in click on Overview tab followed by clicking
on link Launch an Eclipse Application. See figure 1-19
Figure 1-19

This will launch another instance of eclipse application. However, this new instance will have our plug-
in registered with it, So we will be able to see resource manager view. After New Eclipse has started,
from the Window menu, select Show View > Other... to open the Show View dialog (see Figure 1-20).
In the dialog, expand the Resource Manager Category, select Resource Manager View, and then click
the OK button. This causes the Resource Manager view to open (see figure 1-21).
Figure 1-20

Figure 1-21

ECLIPSE SWT DEVELOPMENT

Working With Standard Widget Toolkit


Standard Widget Toolkit (SWT) is the foundation on which entire Eclipse UI is based. SWT provides
easy to use widgets and API's which are helpful in building rich user interfaces. SWT is designed in a
way so as to give us access to the underlying operation system resources. It uses native (OS) widgets
which gives an native look and feel, similar to what is provided by operating system (See figures
below). SWT includes many different type of controls for ex: tree, table, button, label etc. This tutorial
introduces SWT by describing some of the basic concepts and classes.

SWT Widgets

SWT provides a rich set of widgets that can be used to create either stand-alone Java applications or
Eclipse plug-ins. We will start by implementing a small SWT example before getting into details about
each of the widgets you are likely to use. In order to create this standalone version of swt program we
will start by creating new java Project in eclipse.

Before you can start using SWT, the SWT libraries need to be added to your project's classpath. To
add SWT support, do the following:

1. Download SWT library. For 3.1.2 version of eclipse, SWT library is available at
http://archive.eclipse.org/eclipse/downloads/drops/R-3.1.2-200601181600/index.php Look for the
section titled SWT Binary and Source.
2. From main menu tool bar, select "File" followed by "Import". Doing so will bring up the "Import
wizard" dialog.
3. Now select "Existing Projects into Workspace" and click on "Next" button.
4. Click on "Select archive file" followed by "Browse" button. Now locate the SWT archive that you
downloaded in step 1.
5. Click the Finish button to finish importing the SWT project into your workspace.
6. Create new java project from File > New Java Project.
7. Right-click on the project and select the Properties command to open the Properties dialog.
8. Select the Java Build Path followed by Projects tab and click the Add button.
9. Select the org.eclipse.swt project and click OK to finish adding the SWT libraries to your project's
classpath

Create a new Standalone SWT Program

Create a new java class as follows:

1 import org.eclipse.swt.*;
2 import org.eclipse.swt.graphics.*;
3 import org.eclipse.swt.widgets.*;

4 public class FirstExample {


5 public static void main(String[] args){
6 Display firstDisplay = new Display();
7 Shell firstShell = new Shell(firstDisplay);
8 firstShell.setText("First Example");
9 firstShell.setSize(200,100);
10 firstShell.open ();
11 while (!firstShell.isDisposed()) {
12 if (!firstDisplay.readAndDispatch())
13 firstDisplay.sleep ();
14 }
15 firstDisplay.dispose ();
16 }
17 }

Lines 1-3: SWT classes are contained in different packages which begin with org.eclipse.swt. The
package org.eclipse.swt is the main package and contains SWT class and exception/error classes. All
the SWT widgets are contained in org.eclipse.swt.widgets package. Refer to online help for more
information about these packages

Line 6: Every SWT program has a Display. Display acts like a bridge between program and underlying
operating system

Lines 7-9: Next, in the program we have created a shell. All the Top level windows are created by the
class Shell and shell's are contained in Display.

Line 10: When a shell is created it is invisible by default. Shell becomes visible only when method
open() is called on shell instance. open() method not only makes shell visible but also brings it to the
front so that all user input can be intercepted by the shell.

Lines 11-14: SWT supports an event based user interface. Event driven user interface essentially
means that user interaction events are generated which are then intercepted by eclipse application to
perform various actions. Not surprisingly, any event driven UI requires an event loop that continously
listens to user interface events and then broadcasts the events to interested parties. Example of such
event could be "Button click", "Minimize Window" etc. The condition when this event loop ends depend
upon the application For ex: in some cases user might close the window OR clicks on the exit button
provided by the application.

Line 15: Next, we are disposing the Display. Disposing display will release all resources that were
acquired by the running program in its lifetime.
In order to run this example program use the Run As > "SWT Application". This will open up new
window with title “First Example”.

Events

As discussed earlier, SWT supports an event based user interface. These events are generated by user
actions. User actions could be keyboard entry, button click, mouse drag etc. We can trap or listen to
these events by adding/attaching listeners to various SWT controls. Following listing shows an
example to attach selection listener to button widget
final Button myButton = new Button(shell, SWT.PUSH);

SelectionAdapter adapter = new SelectionAdapter() {


public void widgetSelected(SelectionEvent event) {
myButton.setText("You clicked me!");
}
};
myButton.addSelectionListener(adapter);
myButton.setText("Click");
For complete listing of events, listeners refer to online help

In order to know more about events and widgets which support each of these events refer to online
Platform Plug-in Developer Guide. Look for headings Low level events and High level events.

SWT ECLIPSE PLUGIN DEVELOPMENT TUTORIAL (PAGE 2)

Most Commonly Used Widgets

All the widgets have been defined in org.eclipse.swt.widgets package. In This section we will discuss
most commonly used widgets. Most likely you will use these widgets during eclipse plug-in
development. Best way to learn these widgets is through examples, so ill focus this discussion based
on examples. You can refer to SWT API document for further reading. All API’s are self explanatory
and quite simple.

1. Label Widget

Labels are used to display text messages/labels. Labels do not take part in event model and hence do
not generate user interaction events.

public static void main(String[] args) {


Display myDisplay = new Display();
Shell myShell = new Shell(myDisplay);
myShell.setText("This is a label");
myShell.setBounds(100, 100, 200, 50);
myShell.setLayout(new FillLayout());
Label label = new Label(myShell, SWT.CENTER);
label.setText("Hello World");
Color red = new Color(myDisplay, 255, 0, 0);
label.setForeground(red);
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
red.dispose();
myDisplay.dispose();
}
2. Button Widget

Buttons are used to generate special event called selection event when pressed or released. While
creating a button we can use different styles so that this control represent different type of UI
element. For example, we can use SWT.ARROW to create arrow button widget or SWT.CHECK to
create checkbox.

public class MYButton {


public static void main(String[] args) {
Display myDisplay = new Display();
Shell myShell = new Shell(myDisplay);
myShell.setText("This is my button");
myShell.setBounds(120, 120, 220, 120);
myShell.setLayout(new FillLayout());
final Button button = new Button(myShell, SWT.PUSH);
button.setText("Click");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
button.setText("You clicked me!");
}
});
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}

3. Text Widget

Eclipse plugin text field widget is used to take user input. It automatically shows scroll bar if
provided text is more then control’s length.

public class MYText {


public static void main(String[] args) {
Display myDisplay = new Display();
Shell myShell = new Shell(myDisplay);
myShell.setText("My Text Box");
myShell.setBounds(120, 120, 220, 120);
myShell.setLayout(new FillLayout());
final Text text = new Text(myShell, SWT.MULTI);
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}

4. Combo Widget

Eclipse plugin Combo widget helps in displaying multiple options to user. User is allowed to select
single option from the list of options.
public class MyCombo {
public static void main(String[] args) {
Display myDisplay = new Display();
Shell myShell = new Shell(myDisplay);
myShell.setText("My Combo");
myShell.setBounds(120, 120, 220, 120);
myShell.setLayout(new FillLayout(SWT.VERTICAL));
final Combo myCombo = new Combo(myShell,SWT.READ_ONLY);
myCombo.setItems(new String[]
{"option1", "option2", "option3", "option4",
"option5"});
myCombo.setText("option5");
myCombo.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
System.out.println("you selected me: " +
myCombo.getText());
}
});
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}

5. Table Widget

Table widget is used to display items in rows and columns. The columns of a table are defined by
TableColumn.

public class MyTable {


public static void main(String[] args) {
Display myDisplay = new Display();
Shell myShell = new Shell(myDisplay);
myShell.setText("My Table");
myShell.setBounds(120, 120, 220, 120);
myShell.setLayout(new FillLayout());
final Table myTable = new Table(myShell,
SWT.SINGLE | SWT.FULL_SELECTION);
TableColumn col1 =
new TableColumn(myTable, SWT.NULL);
col1.setText("First Column");
col1.pack();
TableColumn col2 =
new TableColumn(myTable, SWT.NULL);
col2.setText("Second Column");
col2.pack();
TableItem tableItem1 = new TableItem(myTable, SWT.NULL);
tableItem1.setText(new String[] {"A1", "A2"});
TableItem tableItem2 = new TableItem(myTable, SWT.NULL);
tableItem2.setText(new String[] {"B1", "B2"});
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}

6. Tree Widget

The tree widget is used to display data in a hierarchical manner. Typically tree has many tree items.
For understanding purposes you can call tree item an "Tree Parent" if this item contains other items.
Tree parent can contain other Tree Parents. or simply leaf nodes. A user navigates through a tree by
expanding and collapsing items.

public class MyTree {


public static void main(String[] args) {
Display myDisplay = new Display();
Shell myShell = new Shell(myDisplay);
myShell.setText("My Tree");
myShell.setBounds(120, 120, 220, 220);
myShell.setLayout(new FillLayout());
final Tree tree = new Tree(myShell, SWT.SINGLE);
for (int i = 1; i < 4; i++) {
TreeItem parent1 = new TreeItem(tree, 0);
parent1.setText("Paren1 - " + i);
for (int j = 1; j < 4; j++) {
TreeItem parent2 = new TreeItem(parent1,0);
parent2.setText("Parent2 - " + j);
for (int k = 1; k < 4; k++) {
TreeItem child = new TreeItem(parent2, 0);
child.setText("Child - " + k);
}
}
}
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}

7. Menu Widget

The Menu widget is used to display user set of actions. Typical example of menu is the file menu on
top of this browser window. Menu can further contain submenu’s and so on.

public class MyMenu {


public static void main(String[] args) {
Display myDisplay = new Display();
final Shell myShell = new Shell(myDisplay);
myShell.setText("My Menu");
myShell.setBounds(110, 110, 210, 110);
Menu myBar = new Menu(myShell, SWT.BAR);
myShell.setMenuBar(myBar);
MenuItem fileMenuItem = new MenuItem(myBar, SWT.CASCADE);
fileMenuItem.setText("&This is my Menu");
Menu subMenuItem = new Menu(myShell, SWT.DROP_DOWN);
fileMenuItem.setMenu(subMenuItem);
MenuItem selectMenuItem = new MenuItem(
subMenuItem, SWT.NULL);
selectMenuItem.setText("&Hello\tCtrl+S");
selectMenuItem.setAccelerator(SWT.CTRL + 'S');
selectMenuItem.addSelectionListener(
new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
System.out.println("Hello Selected!");
}
});
MenuItem thisIsSeperator = new MenuItem(subMenuItem,
SWT.SEPARATOR);
MenuItem exitMenuItem = new MenuItem(subMenuItem,
SWT.NULL);
exitMenuItem.setText("&Bye");
exitMenuItem.addSelectionListener(new SelectionAdapter(){
public void widgetSelected(SelectionEvent event) {
myShell.dispose();
}
});
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}

8. Composite Widget

This is a very important widget since it is used to group together all other widgets. Composite widget
can be used as a container for other widgets. We can use layout managers (Discussed next) for
positioning and placement of other widgets inside composite widget.

public class MyComposite {


public static void main(String[] args) {
Display myDisplay = new Display();
Shell myShell = new Shell(myDisplay);
myShell.setText("My Composite");
myShell.setBounds(120, 120, 220, 220);
Composite composite = new Composite(
myShell,SWT.BORDER);
composite.setBounds(35, 35, 155, 127);
final Button button = new Button(composite,SWT.PUSH);
button.setBounds(30, 30, 110, 85);
button.setText("ClickMe");
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}
SWT ECLIPSE PLUGIN DEVELOPMENT TUTORIAL (PAGE 3)

SWT Layout Managers

SWT defines many different types of layouts which are helpful in positioning and sizing of child widgets
in a composite. In the following SWT Layout Tutorial Next we will discuss four type of layouts
available in SWT.

1. Fill Layout

Fill layout is the simplest layout. It is used to layout widgets in a single row or column forcing them to
be of same size.

public class MyFillLayout {


Display myDisplay = new Display();
Shell myShell = new Shell(myDisplay);

public MyFillLayout() {
FillLayout fillLayout = new FillLayout(SWT.VERTICAL);
fillLayout.marginHeight = 5;
fillLayout.marginWidth = 5;
fillLayout.spacing = 1;

myShell.setLayout(fillLayout);

Button button1 = new Button(myShell, SWT.PUSH);


button1.setText("button1");

Button button2 = new Button(myShell, SWT.PUSH);


button2.setText("button2");

Button button3 = new Button(myShell, SWT.PUSH);


button3.setText("button3");

myShell.pack();
myShell.open();

while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) {
myDisplay.sleep();
}
}

myDisplay.dispose();
}

public static void main(String[] args) {


new MyFillLayout();
}
}

2. Row Layout
Row Layout provides more options as compared to fill layout, which provide more control Row Layout
has a number of configuration fields which can be used to control placement of the widget. In
addition, the height and width of each control in a RowLayout can be specified by setting a RowData
object into the control using setLayoutData()

public class MyRowLayout {


public static void main(String[] args) {
Button myButton;
Display myDisplay = new Display();
Shell myShell = new Shell(myDisplay);
myShell.setText("MyRowLayout");
myShell.setBounds(120, 120, 420, 120);
RowLayout myLayout = new RowLayout();
myShell.setLayout(myLayout);
myLayout.spacing = 15;
myLayout.marginTop = 15;
myLayout.marginRight = 15;
myLayout.marginLeft = 15;
myLayout.marginBottom = 15;
for (int i = 1; i <= 10; i++) {
myButton = new Button(myShell, SWT.PUSH);
myButton.setText("" + i);
}
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}

3. Grid Layout

SWT Gridlayout is to arrange children in a grid of rows and columns, We have many options to
control the sizing of each child widget.

public class MyGridLayout {


public static void main(String[] args) {

// Gridlayout swt image tutorial

Display myDisplay = new Display();


Shell myShell = new Shell(myDisplay);
myShell.setText("My GridLayout");
myShell.setBounds(120, 120, 220, 120);
GridLayout myLayout = new GridLayout();
myLayout.numColumns = 2;
myShell.setLayout(myLayout);

Label myLabel = new Label(myShell, SWT.LEFT);


myLabel.setText("Please enter your age and birthdate");
GridData gridData = new GridData();
gridData.horizontalSpan = 2;
myLabel.setLayoutData(gridData);
myLabel = new Label(myShell, SWT.LEFT);
myLabel.setText("Age:");

Text myText = new Text(myShell, SWT.SINGLE | SWT.BORDER);


gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.grabExcessHorizontalSpace = true;
myText.setLayoutData(gridData);

myLabel = new Label(myShell, SWT.LEFT);


myLabel.setText("BirthDate");
myText = new Text(myShell, SWT.SINGLE | SWT.BORDER);
gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.grabExcessHorizontalSpace = true;
myText.setLayoutData(gridData);

myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}

4. Form Layout

Instances of this class control the position and size of the children of a composite control by using
FormAttachments to optionally configure the left, top, right and bottom edges of each child. It is one
of the most powerful layout managers.

public class MyFormLayout {


public static void main(String[] args) {

Display myDisplay = new Display();


final Shell myShell = new Shell(myDisplay);
myShell.setText("My FormLayout");
myShell.setBounds(120, 120, 240, 200);
myShell.setLayout(new FormLayout());
Button myCancelButton = new Button(myShell, SWT.PUSH);
myCancelButton.setText("This is Cancel Button");
FormData myFormData = new FormData();
myFormData.right = new FormAttachment(100,-10);
myFormData.bottom = new FormAttachment(100,-10);
myCancelButton.setLayoutData(myFormData);
Button myOKButton = new Button(myShell, SWT.PUSH);
myOKButton.setText("This is OK Button");
myFormData = new FormData();
myFormData.right = new FormAttachment(myCancelButton,-10);
myFormData.bottom = new FormAttachment(100,-10);
myOKButton.setLayoutData(myFormData);
Text myTextBox = new Text(myShell, SWT.MULTI | SWT.BORDER);
myFormData = new FormData();
myFormData.top = new FormAttachment(0,10);
myFormData.bottom = new FormAttachment(
myCancelButton,-10);
myFormData.left = new FormAttachment(0,10);
myFormData.right = new FormAttachment(100,-10);
myTextBox.setLayoutData(myFormData);
myShell.open();
while (!myShell.isDisposed()) {
if (!myDisplay.readAndDispatch()) myDisplay.sleep();
}
myDisplay.dispose();
}
}

ECLIPSE JFACE TUTORIAL

Working With JFace Viewers

We have already seen SWT in action. It helps in rapid application development by providing ready
made widgets like Tree, Table etc. However, there is a severe limitation in using these widgets
directly. Let me explain it with an example. Consider the table example in SWT chapter. Following
lines of code were used to populate Table with one row of data.

TableItem tableItem1 = new TableItem(myTable, SWT.NULL);


tableItem1.setText(new String[] {"A1", "A2"});

You can see that we have used String Literals "A1" and "A2" respectively while creating a row in table.
If you think from object oriented perspective it is a severe limitation. In object oriented world we talk
in terms of Objects. In order to build above table we will have to get Strings out of those objects and
then supply it to Table to form every single row. Isn’t there a way in which we can simply map objects
to tables so that table can itself use those objects and populate itself? This is where JFace viewers
step in to provide OO wrappers around their associated SWT widgets. JFace provides two types of
Viewers, Text Viewers and List Viewers. First we will discuss about list viewers.

List Viewers

JFace list viewers, such as TableViewer and TreeViewer, allow you to directly use your business
objects (Employee, Customer, User, Business etc.) without. The trick is to provide adapters for things
such as retrieving an item's name/label OR for retrieving an Tree parent's children (tree widget). So
we will talk about these adaptors first before moving onto implementing Table/Tree Viewers.

1. Label Providers

A label provider maps an element of the viewer's model to an optional image and optional text string
used to display the element in the viewer's control.

The two most frequently used label providers are ILabelProvider and ITableLabelProvider In order to
display elements name and label we can use getImage and getText methods provided by
ILabelProvider Similarly in case of ITableLabelProvider, in order to display label image and label text
for any column in a table we can use getColumnImage and getColumnText. We can use
setLabelProvider() method to attach/associate provider with the viewer.

2. Content Providers

A content provider is another common adapter type used in list viewers. This provider is used to feed
the actual content to the viewer. Viewer then uses its internal logic to display these input elements
with its internal controls.
The two most frequently used content providers are IStructuredContentProvider and
ITreeContentProvider. These adapters provide convienient methods to retrive child elements for a
given element. We can use setContentProvider() method to attach/associate provider with the viewer.
A intial domain/business model of the application can be associated with the viewer with the help of
setInput() method.

3. Viewer Sorters

A viewer sorter is a adapter which is called by viewer before the elements/contents are displayed to
the user. We can use this provider to sort the elements which are provided by the content provider.
We can use setSorter() method on the viewer to attach sorter.

4. Viewer Filters Providers

As the name suggests a viewer filter is used to filter out some of the elements from original list of
elements provided by the content provider. For example: Original list of Employees consist of
employees with two type of roles Admin, Non admin. We can use filters to display only admin role
users. We can attach viewer filter by using the setFilter() method on the viwer itself.

Table Viewers

The TableViewer class acts as a OO wrapper around the Table widget. Table Viewer is capable of
displaying data in rows and cloumns with the help of adapters like label provider and content provider.

Table Viewer provides many useful APIs, Please refer to online Eclipse Platform API Specification

Following example creates a table viewer

public static void main(String[] args) {


Display exampleDisplay = new Display();
Shell exampleShell = new Shell(exampleDisplay);

exampleShell.setBounds(120, 120, 345, 220);


exampleShell.setLayout(new FillLayout());

final TableViewer myTableViewer = new TableViewer(


exampleShell, SWT.SINGLE);

final Table myTable = myTableViewer.getTable();

String[] myColumns = new String[] {


"Hello", "Bye"};

for (int i = 0; i < columnNames.length; i++) {


TableColumn tableColumn =
new TableColumn(myTable);
tableColumn.setText(myColumns[i]);
}

myTableViewer.setLabelProvider(
new ExampleLabelProvider());

myTableViewer.setContentProvider(
new ArrayContentProvider());
myTableViewer.setInput(Example.getInput());

exampleShell.open();

while (!exampleShell.isDisposed()) {
if (!exampleDisplay.readAndDispatch())
exampleDisplay.sleep();
}

exampleDisplay.dispose();
}

In Above listing we are creating table viewer Then we are creating two columns namely "Hello" and
"Bye" The header of each column is set using setText() method. There after label provider and content
providers are being attached with the viewer. Following listing shows how the label provider looks like

public class PersonTableLabelProvider


extends LabelProvider
implements ITableLabelProvider {
public Image getColumnImage(
Object element, int) {
return null;
}

public String getColumnText(Object element, int index) {


Example ex = (Example) element;
switch (index) {
case 0 :
return ex.hello;
case 1 :
return ex.bye;
}
}
}

public class Example{


String hello;

String bye;

Example(String hello, String bye){


this.hello = hello;
this.bye=bye;
}

public static Example[] getInput(){


return new Example[]{
new Example("FirstHello","FirstBye"),new
Example("SecondHello","SecondBye")
};
}
}

Tree Viewers
The treeViewer class acts as a OO wrapper around the Tree widget. Tree Viewer is capable of
displaying data in hierarchical manner with the help of adapters like label provider and content
provider.

Tree Viewer provides many useful APIs, Please refer to online Eclipse Platform API Specification

The following listing creates a tree viewer

public static void main(String[] args) {


Display exampleDisplay = new Display();
Shell exampleShell = new Shell(exampleDisplay);

exampleShell.setBounds(120, 120, 220, 220);


exampleShell.setLayout(new FillLayout());

final TreeViewer myTreeViewer =


new TreeViewer(exampleShell, SWT.SINGLE);

myTreeViewer.setLabelProvider(
new MyTreeLabelProvider());

myTreeViewer.setContentProvider(
new MyTreeContentProvider());

myTreeViewer.setInput(Example1.getInput());

exampleShell.open();

while (!exampleShell.isDisposed()) {
if (!exampleDisplay.readAndDispatch())
exampleDisplay.sleep();
}
exampleDisplay.dispose();
}

In above code listing we are creating the tree viewer. There after we are configuring label and content
adapters. Following listing shows the rest of code:

public class MyTreeContentProvider


extends ArrayContentProvider
implements ITreeContentProvider {

public Object[] getChildren(Object parent) {


Example1 ex1 = (Example1) parent;
return ex1.children;
}

public Object getParent(Object element) {


Example1 ex1 = (Example1) element;
return ex1.parent;
}
public boolean hasChildren(Object element) {
Example1 ex1 = (Example1) element;
return ex1.children.length > 0;
}
}

public class MyTreeLabelProvider extends LabelProvider {


public Image getImage(Object element) {
return null;
}
public String getText(Object element) {
Example1 ex1 = (Example1) element;
return ex1.name;
}
}

public class Example1{


String name;

Example1[] children = new Example1[0];

Example1 parent = null;

Example1(String name){
this.name = name;
}

Example1(String name,Example1[] children){


this.name = name;
this.children = children;
for (int i = 0; i < children.length; i++) {
children[i].parent = this;
}
}

public static Example1[] getInput(){


return new Example1[]{
new Example1("First",new Example1[]
{new Example1("Child1"), new
Example1("Child2")}),
new Example1("Second",new Example1[]{
new Example1("Child3"),new
Example1("Child4")}
)
};
}
}

ECLIPSE PERSPECTIVE TUTORIAL

As most of you who are Eclipse users will know, you can easily organize your views around in each
perspective to make yourself comfortable with development related tasks. As an Eclipse user the first
thing you do when you launch eclipse application is to select a perspective which is most suitable for
the job in hand. In this chapter we will create a new perspective which will open up Resource manager
view when selected. Since our plug-in is very small with only one view, creating a perspective for the
purpose of opening up single view might look overburden. However, in real world Plug-in applications
Views can grow real big in terms of number, so creating a perspective and managing views become
almost a necessity.

What is a Perspective?

A perspective is useful in organizing various eclipse views around the editor area, these are also
helpful in managing menus and toolbars We can save perspectives and these can be switched to in
future. As an eclipse plugin developer we can either create a new perspective from scratch or enhance
existing perspective. Enhancing existing perspective essentially means to accommodate your view in
an existing perspective for example: we can add our resource manager view to existing Resource
perspective, so that it opens up when ever user selects resource perspective.

Eclipse comes with many inbuilt perspectives (Some of them are listed below):

Resource - This perspective shows various workspace resources irrespective of file extension.

Java/Java Browsing - This is useful for Java development

Debug - This is useful for debugging Java Applications.

Plug-in Development - This is useful while developing Eclipse Plugin Applications

Following figure shows how Java Browsing perspective looks like. Notice how different views Projects
view, Packages view etc. are organized in screen below. So the whole purpose of creating perspective
can be to organize your screens according to ease of use.
Figure 4-1

Creating a Perspective

We can create a new perspective by extending the org.eclipse.ui.perspectives extension point.

Perspective extension point

In order to create perspective, open the Resource Manager’s Eclipse plugin manifest editor, Now
select the Extensions tab. In Extensions tab click the Add button. Now select
org.eclipse.ui.perspectives from the list in the New Extension wizard. Click the Finish button.
Figure 4-2

Again go to the Extensions page in the plug-in manifest editor, open mouse right click context menu
on the org.eclipse.ui.perspectives extension followed by selecting New > perspective. This will add a
new perspective called “com.myplugin.rmp.perspective1”. Modify properties on right side as shown in
the figure below.
Figure 4-3

Perspective factories

Now we will create perspective factory which will be used to define the layout of our newly created
perspective Click on the "class" link on the right side of the class property and use Java Attribute
Editor to create a new class.
Figure 4-4

Open the ResourceManagerPerspectiveFactory class and modify it as follows so that the Resource
Manager view will appear below the editor area and the standard Outline view will be shown to its left.

package com.myplugin.rmp;
import org.eclipse.ui.IPerspectiveFactory;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IFolderLayout;

public class ResourceManagerPerspectiveFactory implements


IPerspectiveFactory {

private static final String VIEW_ID =


"com.myplugin.rmp.views.ResourceManagerView";
private static final String BOTTOM = "bottom";

public void createInitialLayout(IPageLayout myLayout) {

myLayout.addView(IPageLayout.ID_OUTLINE,IPageLayout.LEFT,0.
30f,

myLayout.getEditorArea());

IFolderLayout bot =
myLayout.createFolder(BOTTOM,IPageLayout.BOTTOM,0.76f,

myLayout.getEditorArea());
bot.addView(VIEW_ID);

}
}

Lets test the new Perspective

Open Manifest editor if not already open. Select Overview tab > Launch an eclipse application. It will
launch separate eclipse application.
Open our new perspective from Window > Open Perspective > Other (as shown below)

Figure 4-5

This will open up Select Perspective dialog (as shown below)


Figure 4-6

Select Resource Manager perspective and click ok button. This will switch the perspective to our newly
created perspective as shown below
Figure 4-7

Enhancing an already existing Perspective

As discussed earlier, in addition to creating new perspective we can also use already existing
perspectives and add our views to it. For example we may want to open Resource Manager view
whenever Java Perspective or Resource Perspective is opened up. In this section we will discuss how
to enhance an existing perspective such that it accommodates our view in its existing view
arrangement.

First, open the Resource Manager’s plug-in manifest editor, Next, click on the Extensions tab followed
by clicking the "Add" button. Now select org.eclipse.ui.perspectiveExtensions (as shown below) from
the list extension points. Next, Click the Finish button
Figure 4-8

Next, again go to the Extensions page of manifest editor, Open right click context menu on the
org.eclipse.ui.perspectiveExtensions. Select New > perspectiveExtension. This will add a perspective
extension named “com.myplugin.rmp.perspectiveExtension1”. Modify Properties as shown in the figure
below.
Figure 4-9

On the Extensions page, click on the org.eclipse.ui.resourcePerspective extension and select New >
view. Modify Extension element details as shown in figure below.
Figure 4-10

Lets test the Resource Perspective

Open Manifest editor if not already open. Select Overview tab > Launch an eclipse application. It will
launch separate eclipse application.

Open Resource Perspective and you will see that Resource Manager view is shown.
Figure 4-11

GETTING STARTED WITH ACTIONS

Actions

Action represent user actions such as “Run”, “Debug”, “Save to file”, “Search” or “Go to marker”.
Actions are attached to buttons, tool/menu bars in an eclipse application. Actions run method is called
whenever end user clicks on menu item or button. This chapter covers all this with examples that
show how to use actions and action sets in the example Resource Manager plug-in.
Following figure shows the many areas where a plug-in can contribute actions. It includes Context
menu of a view or editor, to local toolbar and pull down menu of a view, to the main toolbar and menu
bar of the workbench window. In course of this tutorial we will add actions to various places in
workbench window. However, at this time some of these actions may not do anything useful other
then displaying some pop up message or opening up resource manager view. During the course of this
tutorial we will re-visit these actions to add more meaningful implementation.
Figure 5-1

Adding actions to Main Menu bar and Main Toolbar

Now we will add a menu to the main menu bar and a button to the main toolbar. Both of these open
the Resource manager view when clicked by the user. Open the Resource Manager plug-in manifest
editor, Next navigate to Extensions page followed by clicking on the "Add" button.

Select org.eclipse.ui.actionSets from the list an then Click on the Finish button.
Figure 5-2

Navigate back to the Extensions page. Open right click context menu on the org.eclipse.ui.actionSets
item and select New > actionSet (See Image below).
Figure 5-3

Once new com.myplugin.rmp.actionSet1 is added, Select this action set and modify its properties as
shown below.
Figure 5-4

Next, add a menu to the main menu bar by opening up the right click context menu on on the action
set followed by selecting New > menu (As shown below)
Figure 5-5

Next, Select the menu and modify its properties as shown below. Notice the path attribute, we have
specified its value as “additions”. For now don’t worry about this attribute, we will discuss it in section
to follow.
Figure 5-6

Working With Groups

When working with menu’s we often define groups. So we will have menu’s - which will have groups
and actions will be added to groups. So first some groups need to be defined. Two types of groups are
available – Separator and groupMarker. A separator group displays a horizontal line. We will now
create both of these groups. First we create a groupMarker by opening up right click context menu on
Resource Manager menu and select New followed by groupMarker. Select the groupMarker and change
its name to "content" Next define second group to the Resource Manager menu; by selecting New
followed by separator and change its name to "additions".
Figure 5-7

We will use this groups when we create actions discussed next. Take a minute to look back at path
attribute which we provided at the time of creating menu inside action set. We defined “additions” in
the path attribute, this is nothing but a predefined group.

Next, we will define the action itself. Open right click context menu on the Resource Manager
ActionSet and select New followed by action. Modify action properties as shown below:
Figure 5-8

Almost every attribute is self descriptive, However following attributes require special attention:

menubarPath: We have entered “com.myplugin.rmp.workbenchMenu/content” in this attribute. Notice


that the first part is same as the id attribute of Resource Manager menu created earlier and the
second part i.e. content is the name of the group created earlier. So this full statement means that we
want to add this action to Resource Manager Menu under content group.

toolbarPath: We have entered "Normal/additions" to this attribute. The first part is the id of toolbar
where we would like to add this action. Note that eclipse has only single toolbar and its id is “Normal”.
Second part is again a predefined group in toolbar. So the complete statement specifies that we would
like to add this action to Normal toolbar under additions group.

Working with action delegate

Action delegate is a class which implements the behavior associated with the action. All above steps
have no meaning until we specify the behavior associated with the action. When we say behavior, it
essentially means what action will be triggered when user clicks on the menu item or toolbar button.
Next, we will create a action delegate class.

Click on the "class" link on the left of the class Text Box.

Figure 5-9

Clicking the class label will open up the Java Attribute Editor for the action's class.
In Package text box, provide "com.myplugin.rmp.actions" and
"OpenResourceManagerViewActionDelegate" as Name. Click on the Finish button.
Figure 5-10

Modify the class as shown below:

package com.myplugin.rmp.actions;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PartInitException;
public class OpenResourceManagerViewActionDelegate implements
IWorkbenchWindowActionDelegate {

private IWorkbenchWindow window;


public static final String ID =
"com.myplugin.rmp.views.ResourceManagerView";

public void init(IWorkbenchWindow window) {


this.window = window; // cache the window object in
which action delegate is operating
}
public void dispose() {}

public void run(IAction action) {

IWorkbenchPage page = window.getActivePage();

try {

page.showView(ID); // use the Resource


Manager View id to open up view.

} catch (PartInitException e) {

}
}
public void selectionChanged(IAction action, ISelection
selection) {}
}

Testing the new action

launch the Runtime Workbench. You will see that action have been added to main menu bar and a
push button has been added to main toolbar. Clicking on anyone of these will open up Resource
Manager View.
Figure 5-11

GETTING STARTED WITH ACTIONS (PAGE 2)

Adding actions to View Toolbar

In this section we will add actions to out Resource Manager View. In order to add these actions, open
the Resource Manager plug-in manifest editor, navigate to Extensions tab and click the "Add" button.

Select org.eclipse.ui.viewActions from the list. Click the Finish button to add this extension to the
plug-in manifest.
Figure 5-12

Next, right click and add viewActions > New > viewContribution.
Figure 5-13

Next, modify the viewContribution attributes as shown below, Notice that the targetID attribute points
to the ID of the view to which we are adding this action. In this example the target view is Resource
Manager View.
Figure 5-14

Next, Right click on the ResourceManagerViewContribution > New > Action to create a new action
which will be associated with the View toolbar. Provide action attributes as shown below.
Figure 5-15

Creating an action delegate

Action delegate is a class which implements the behavior associated with the action. Next, we will
create a action delegate class.

Click on the class: label that appears to the left of the class field to create a new action delegate class.
We will modify the class so that it opens up a pop up when action is clicked on the View tool bar.

package com.myplugin.rmp;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
public class ResourceManagerViewActionDelegate implements
IViewActionDelegate {
private IViewPart view;

public void init(IViewPart view) {


this.view = view;
}

public void run(IAction action) {


MessageBox box = new
MessageBox(view.getSite().getShell(),SWT.ICON_INFORMATION);
box.setMessage("Hello! You clicked view action!");
box.open();
}
public void selectionChanged(IAction action, ISelection
selection) {}
}

Testing the new action

Launch the Runtime Workbench. You will see a new push button has been added to Resource Manager
View tool bar. It will open up a Message box when clicked (See Below).
Figure 5-16

Dialogs

Dialogs are almost always used in every application. Dialogs are used to either inform user or to take
user input. In Eclipse dialogs can be broadly classified into two categories i.e. SWT dialogs and JFace
Dialogs. We will discuss how to create dialogs in eclipse plugins starting with Introduction to
SWT Dialogs.

SWT Dialogs
Figure 6-1

Dialog class is an abstract class from which you can derive concrete native dialogs. The SWT already
contains some concrete subclasses of dialog, such as shown in table below:

Subclass Description
ColorDialog Dialog for selecting a color
DirectoryDialog Dialog for selecting a directory in host file system
Dialog for selecting a file in host file system. Supported
FileDialog
styles are SWT.OPEN and SWT.SAVE
FontDialog Dialog for selecting text font
Dialog for displaying a message. Various style
parameters govern which buttons will be displayed to
the user For ex: SWT.OK, SWT.CLOSE etc.
MessageBox
Icon to be displayed with the message can be governed
by styles such as SWT.ICON_ERROR,
SWT.ICON_QUESTION etc.
PrintDialog Dialog for selecting printer and for printer settings

JFace Dialogs
Figure 6-2

The package org.eclipse.jface.dialogs provides classes that implement standard Dialog. All these
classes are subclasses of abstract class Dialog which itself is a subclass of abstract class Window.
Following table describes some of the most commonly used subclasses of Jface Dialog.

Subclass Description
superclass of dialogs with an icon and a
IconAndMessageDialog
message.
SelectionDialog superclass for displaying a selection
StatusDialog superclass for dialogs with status bar
TitleAreaDialog dialog having a title area.
ErrorDialog A dialog to display errors
MessageDialog dialog class for showing messages to the user.
A dialog which prompts for one element out of a
ListDialog
list.
A modal dialog to display progress of a
ProgressMonitorDialog
operation.
WizardDialog A dialog to show a wizard to the end user.
A simple input dialog for getting an input from
InputDialog
the user.
Lets try out a simple dialog example

We will modify ResourceManagerViewActionDelegate to try out some dialogs. Here is new code listing.

package com.myplugin.rmp;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;

public class ResourceManagerViewActionDelegate implements


IViewActionDelegate {
private IViewPart view;

public void init(IViewPart view) {


this.view = view; // cache the view part, this will
be used in run action
// to fetch the
parent shell for dialog
}

public void run(IAction action) {


InputDialog dialog = new
InputDialog(view.getSite().getShell(),"Lets try!",
"Please enter your
name","",null); // new input dialog
if( dialog.open()== IStatus.OK){ // open dialog and
wait for return status code.
// If user clicks
ok display message box
String value = dialog.getValue(); // fetch the
value entered by the user.
MessageBox box = new
MessageBox(view.getSite().getShell(),SWT.ICON_INFORMATION);
box.setMessage("Hey there! You entered : " +
value);
box.open();
}else{
MessageBox box = new
MessageBox(view.getSite().getShell(),SWT.ICON_INFORMATION);
box.setMessage("Bye!");
box.open();
}
}

public void selectionChanged(IAction action, ISelection


selection) {}
}
Wizards

If you use Eclipse IDE for java development then you must have used Wizards extensively for
example, while creating Java class or while new Projects etc.

Wizards are helpful in performing repetitive tasks for ex: New Java Class wizard takes information
from user and create java class template. Depending upon user input it is also generate main method,
abstract methods from super class etc.

JFace has two interface's org.eclipse.jface.wizard.IWizard and org.eclipse.jface.wizard.IWizardPage


which are useful in creating wizards. So each wizard consists of one or more pages. In order to take
huge data as input we can divide the input data into logical sets and display each such set on every
page of the wizard. For example: We want to take employee information, On first page we can take
personal information such as first name, last name, age etc. On second page we can gather address
information and so on. In order to make things simple for us JFace also provides corresponding
abstract classes which we will use in our examples. First we will see how to construct an wizard and
thereafter we will move on to understand how we can open up wizards.

Creating Wizard Pages

Open Resource Manager plugin project and create a new java class as described in steps below:

1. Create new package in project name it com.myplugin.rmp.wizards

2. Create a new Wizard Page (PersonalInformationPage) by creating java class as shown in figure
below
Figure 6-3

3. Modify the above generated class as shown below:

package com.myplugin.rmp.wizards;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
public class PersonalInformationPage extends WizardPage {
Text firstNameText;
Text secondNameText;
protected PersonalInformationPage(String pageName) {
super(pageName);
setTitle("Personal Information");
setDescription("Please enter your personal
information");
}
public void createControl(Composite parent) {
Composite composite = new Composite(parent,
SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
composite.setLayout(layout);
setControl(composite);
new Label(composite,SWT.NONE).setText("First
Name");
firstNameText = new Text(composite,SWT.NONE);
new Label(composite,SWT.NONE).setText("Last
Name");
secondNameText = new Text(composite,SWT.NONE);
}
}

4. Create another Wizard page (AddressInformationPage) class and modify it as follows:

package com.myplugin.rmp.wizards;
import org.eclipse.jface.wizard.WizardPage;
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;

public class AddressInformationPage extends WizardPage {


Text street;
Text city;
Text State;

protected AddressInformationPage(String pageName) {


super(pageName);
setTitle("Address Information");
setDescription("Please enter your address
information");
}
public void createControl(Composite parent) {
Composite composite = new Composite(parent,
SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
composite.setLayout(layout);
setControl(composite);
new Label(composite,SWT.NONE).setText("Street");
street = new Text(composite,SWT.NONE);
new Label(composite,SWT.NONE).setText("City");
city = new Text(composite,SWT.NONE);
new Label(composite,SWT.NONE).setText("State");
state = new Text(composite,SWT.NONE);
}
}

5. Create a new Wizard name it CaptureEmployeeInfomrationWizard as shown below:

Figure 6-4

6. Modify the above created class as shown below:

package com.myplugin.rmp.wizards;
import org.eclipse.jface.wizard.Wizard;
public class CaptureEmployeeInfomrationWizard extends Wizard {
PersonalInformationPage personalInfoPage;
AddressInformationPage addressInfoPage;

public void addPages() {


personalInfoPage = new
PersonalInformationPage("Personal Information Page");
addPage(personalInfoPage);
addressInfoPage = new
AddressInformationPage("Address Information");
addPage(addressInfoPage);
}
public boolean performFinish() {
return false;
}
}

Test newly created wizard

In order to test this wizard Modify run method of


com.myplugin.rmp.ResourceManagerViewActionDelegate created in earlier chapter to open up the
wizard when user clicks on View tool bar action

public void run(IAction action) {


CaptureEmployeeInfomrationWizard wizard = new
CaptureEmployeeInfomrationWizard();
WizardDialog dialog = new
WizardDialog(view.getSite().getShell(), wizard);
dialog.create();
dialog.open();
}

From Overview tab of Manifest editor - launch eclipse to test your changes. Open Resource Manager
Perspective and click on toolbar action to open up wizard (See image below).
Figure 6-5

ECLIPSE VIEWS

Working with Views

In eclipse the entire workbench contains one or more workbench windows. Each workbench window
may further contain one or more workbench pages and each page may contain one or more editor or
views. An editor is typically used to edit/modify a workspace resource whereas Views are arranged
around editors and provide assistance to editors in some way (though this is not always true). Views
are used to display hierarchy of information, open up an editor or display properties for an active
editor. Classic example of view is Package explorer and outline view. Package explorer is used to
display workspace resources in a hierarchy and is used to open up associated editor whenever user
performs double click action on the resource. Outline view is used to display information about the
java resource for ex: package declaration, imports etc. (See figure below)
One of the key difference between editors and view is that editors are resource based i.e. they work
on underlying resources in workspace. For ex: XML editor requires “.xml” file in workspace. Whereas,
views may not be resource based. They can be used to show any kind of information. It is also
important that we can make views which may display information irrespective of resources opened up
in editor window (that’s why I said its not always true that view plays role of assistant window around
editor area).

Resource Manager View


In first chapter of this tutorial we created a Resource Manager view as part of plug-in creation. We
have been playing around with our resource manager view for quite some time for ex: we added this
view to our own customized perspective, added actions to Resource Manager view. However, Resource
Manager view itself does not do anything useful – every time it is opened it just displays static model
as shown below:

Let’s Manage Workspace Property Files

In this chapter, we will create Property File Manager View so that it does something useful and more
meaningful rather then just displaying static data.

Property File Manager View will search the entire workspace for all the projects. In each project it will
search for "Property Files" folder, In each such folder it will look out for all the files with
".properties" extension and display it to the user. This way we will end up with a view as shown in
the figure below. Please note that a property file gets displayed in the Property File Manager view only
when it is created inside Property Files folder.
Property File Manager View

In order to create a new view, open up manifest editor – click on extensions tab. Right click on
“org.eclipse.ui.views” extension and click on new > view (See figure below)
It will immediately open up Extension element details page. Edit the element details as shown below
In order to create “com.myplugin.rmp.views.PropertyManagerView” class click on the class link to
open up Java attribute editor as shown below:
Click finish to generate the Property Manager View class.

Complete Listing of the Property Manager View Class

What follows is the complete listing of Property Manager View class. However, before we move ahead
to show this listing we will need to add two dependencies (if not already added) in the plug-in
manifest editor.

First dependency (org.eclipse.core.resources) is required since property manager needs to access


workspace resources.

Second dependency (org.eclipse.ui.ide) is required since we will open up associated editor whenever
user clicks on listed property files in property manager view.
In order to add the dependencies, open up manifest editor – click on dependencies tab and add above
two dependencies as shown in fig below:

Once the dependencies have been added following code listing will compile successfully.

1. package com.myplugin.rmp.views;
2. import java.util.ArrayList;
3. import org.eclipse.core.resources.IFile;
4. import org.eclipse.core.resources.IFolder;
5. import org.eclipse.core.resources.IProject;
6. import org.eclipse.core.resources.IResource;
7. import org.eclipse.core.resources.IWorkspace;
8. import org.eclipse.core.resources.ResourcesPlugin;
9. import org.eclipse.core.runtime.IAdaptable;
10. import org.eclipse.jface.action.Action;
11. import org.eclipse.jface.action.MenuManager;
12. import org.eclipse.jface.dialogs.MessageDialog;
13. import org.eclipse.jface.viewers.DoubleClickEvent;
14. import org.eclipse.jface.viewers.IDoubleClickListener;
15. import org.eclipse.jface.viewers.ISelection;
16. import org.eclipse.jface.viewers.IStructuredContentProvider;
17. import org.eclipse.jface.viewers.IStructuredSelection;
18. import org.eclipse.jface.viewers.ITreeContentProvider;
19. import org.eclipse.jface.viewers.LabelProvider;
20. import org.eclipse.jface.viewers.TreeViewer;
21. import org.eclipse.jface.viewers.Viewer;
22. import org.eclipse.swt.SWT;
23. import org.eclipse.swt.graphics.Image;
24. import org.eclipse.swt.widgets.Composite;
25. import org.eclipse.swt.widgets.Menu;
26. import org.eclipse.ui.ISharedImages;
27. import org.eclipse.ui.IWorkbenchPage;
28. import org.eclipse.ui.PlatformUI;
29. import org.eclipse.ui.ide.IDE;
30. import org.eclipse.ui.part.ViewPart;

31. public class PropertyManagerView extends ViewPart {


32. private TreeViewer viewer;
33. private TreeParent invisibleRoot;

34. class TreeObject implements IAdaptable {

35. private String name;


36. private TreeParent parent;
37. private IResource resouce;

38. public TreeObject(String name) {


39. this.name = name;
40. }

41. public String getName() {


42. return name;
43. }

44. public void setParent(TreeParent parent) {


45. this.parent = parent;
46. }

47. public TreeParent getParent() {


48. return parent;
49. }

50. public String toString() {


51. return getName();
52. }

53. public Object getAdapter(Class key) {


54. return null;
55. }
56. protected IResource getResouce() {
57. return resouce;
58. }
59. protected void setResouce(IResource resouce) {
60. this.resouce = resouce;
61. }
62. }
63. class TreeParent extends TreeObject {
64. private ArrayList children;
65. public TreeParent(String name) {
66. super(name);
67. children = new ArrayList();
68. }

69. public void addChild(TreeObject child) {


70. children.add(child);
71. child.setParent(this);
72. }

73. public void removeChild(TreeObject child) {


74. children.remove(child);
75. child.setParent(null);
76. }

77. public TreeObject[] getChildren() {


78. return (TreeObject[]) children.toArray(new
TreeObject[children.size()]);
79. }

80. public boolean hasChildren() {


81. return children.size() > 0;
82. }

83. }
84. class ViewContentProvider implements ITreeContentProvider {

85. public void inputChanged(Viewer v, Object oldInput, Object


newInput) {
86. }

87. public void dispose() {


88. }

89. public Object[] getElements(Object parent) {


90. if (parent.equals(getViewSite())) {
91. if (invisibleRoot == null)
92. initialize();

93. return getChildren(invisibleRoot);


94. }

95. return getChildren(parent);


96. }

97. public Object getParent(Object child) {


98. if (child instanceof TreeObject) {
99. return ((TreeObject) child).getParent();
100. }
101. return null;
102. }

103. public Object[] getChildren(Object parent) {

104. if (parent instanceof TreeParent) {


105. return ((TreeParent)
parent).getChildren();
106. }

107. return new Object[0];


108. }

109. public boolean hasChildren(Object parent) {


110. if (parent instanceof TreeParent)
111. return ((TreeParent)
parent).hasChildren();
112. return false;
113. }

114. }

115. class ViewLabelProvider extends LabelProvider {


116. public String getText(Object obj) {
117. return obj.toString();
118. }

119. public Image getImage(Object obj) {


120. String imageKey = ISharedImages.IMG_OBJ_ELEMENT;

121. if (obj instanceof TreeParent)


122. imageKey = ISharedImages.IMG_OBJ_FOLDER;
123. return
PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
124. }

125. }

126. public void initialize() {


127. TreeParent root = new TreeParent("WorkSpace Property
Files");
128. try {
129. IWorkspace workspace =
ResourcesPlugin.getWorkspace();

130. IProject[] projects =


workspace.getRoot().getProjects();

131. for (int i = 0; i < projects.length; i++) {


132. IResource[] folderResources =
projects[i].members();

133. for (int j = 0; j < folderResources.length; j+


+) {

134. if (folderResources[j] instanceof IFolder)


{
135. IFolder resource = (IFolder)
folderResources[j];
136. if
(resource.getName().equalsIgnoreCase("Property Files")) {
137. IResource[] fileResources =
resource.members();
138. for (int k = 0; k <
fileResources.length; k++) {
139. if (fileResources[k] instanceof
IFile &&
fileResources[k].getName().ends
With(".properties")){
140. TreeObject obj = new
TreeObject(fileResources[k]
.getName(
));
141.
obj.setResouce(fileResources[k]);
142. root.addChild(obj);
143. }
144. }
145. }
146. }
147. }
148. }
149. }catch (Exception e) {
// log exception
150. }
151. invisibleRoot = new TreeParent("");
152. invisibleRoot.addChild(root);
153. }

154. public PropertyManagerView() {


155. }

156. public void createPartControl(Composite parent) {


157. viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
| SWT.V_SCROLL);
158. viewer.setContentProvider(new ViewContentProvider());
159. viewer.setLabelProvider(new ViewLabelProvider());
160. viewer.setInput(getViewSite());
161. hookContextMenu();
162. hookDoubleCLickAction();
163. }

164. private void hookDoubleCLickAction() {


165. viewer.addDoubleClickListener(new IDoubleClickListener()
{
166. public void doubleClick(DoubleClickEvent event) {
167. ISelection selection = event.getSelection();
168. Object obj = ((IStructuredSelection)
selection).getFirstElement();
169. if (!(obj instanceof TreeObject)) {
170. return;
171. }else {
172. TreeObject tempObj = (TreeObject) obj;
173. IFile ifile =
ResourcesPlugin.getWorkspace().getRoot().

getFile(tempObj.getResouce().getFullPath());
174. IWorkbenchPage dpage =
PropertyManagerView.this.g
etViewSite()

.getWorkbenchWindow().getActivePage();
175. if (dpage != null) {
176. try {
177. IDE.openEditor(dpage,
ifile,true);
178. }catch (Exception e) {
179. // log exception
180. }
181. }
182. }
183. };
184. });
185. }

186. private void hookContextMenu() {


187. MenuManager menuMgr = new MenuManager("#PopupMenu");
188. Menu menu =
menuMgr.createContextMenu(viewer.getControl());
189. viewer.getControl().setMenu(menu);
190. Action refresh =new Action() {
191. public void run() {
192. initialize();
193. viewer.refresh();
194. }
195. };
196. refresh.setText("Refresh");
197. menuMgr.add(refresh);
198. }

199. public void setFocus() {


200. viewer.getControl().setFocus();
201. }
202. }

GETTING STARTED WITH VIEWS (PAGE 2)

You might face issues understanding above code if you have not gone through JFace Viewers chapter.
I would briefly discuss main points of complete listing below – for detailed information on SWT/JFace
viewers please read respective chapters.

Lines 32 - 125: Nothing special here - Most of the SWT/JFace concepts have been put to practice.
TreeObject and TreeParent represents the model objects for our TreeViewer class. We have used
TreeViewer class here because we need to show property files under “WorkSpace Property Files”
folder, so it is more like tree rather then a table.

TreeParent represent Folders whereas TreeObject represent Files in specific folder. These two classes
are essentially wrappers/adapters over the IResource objects. In our example we will use TreeParent
to represent “WorkSpace Property Files” folder and TreeObject to represent various property files.

ViewContentProvider: A content provider is another common adapter type used in viewers. This
provider is used to map a domain model object used as the input to the viewer and the internal
structure needed by the viewer itself. We have implemented ITreeContentProvider interface. This
interface adds support for retrieving an item's parent or children within a tree. Special attention is
required for the method.

89. public Object[] getElements(Object parent) {


90. if (parent.equals(getViewSite())) {
91. if (invisibleRoot == null)
92. initialize();

93. return
getChildren(invisibleRoot);
94. }

95. return getChildren(parent);


96. }

getElements method is defined in the interface IStructuredContentProvider as shown below

This method returns the elements to display in the viewer. This method is called internally by the
viewer and reference to the parent object is passed as an argument. In line 90, we are comparing
parent with the ViewSite returned by getViewSite() method. Views are contained in a view site
(org.eclipse.ui.IViewSite) and ViewSite is in turn contained in a workbench page
(org.eclipse.ui.IWorkbenchPage). Basically at this time we want to know whether the elements are
demanded by View itself or TreeParent object(folder). If it is demanded by View itself then we will
initialize our model object and return it to viewer.
ViewLabelProvider: This provider is used to map a domain model object into one or more images and
text strings displayable in the viewer's widget. We will use this provider to display names of property
files as well as folder. Also, we have used this provider to display images in the view.

Line 126: Initialize method is used to initialize our domain model.

Line 127: We have created TreeParent to represent “WorkSpace Property Files” folder which will
act as a parent folder for all property files in workspace.
Line 129: he handle of workspace through Resources plug-in. Resource plugin is used for any
workspace/resource modifications problems.

Line 130: workspace.getRoot() returns the root resource of this workspace. It is basically container of
all projects in the workspace. IWorkspaceRoot.getProjects() returns the collection of projects which
exist under this root. The projects can be open or closed.

126. public void initialize() {


127. TreeParent root = new TreeParent("WorkSpace
Property Files");
128. try {
129. IWorkspace workspace =
ResourcesPlugin.getWorkspace();

130. IProject[] projects =


workspace.getRoot().getProjects();

131. for (int i = 0; i < projects.length; i++) {


132. IResource[] folderResources =
projects[i].members();

133. for (int j = 0; j <


folderResources.length; j++) {

134. if (folderResources[j] instanceof


IFolder) {
135. IFolder resource = (IFolder)
folderResources[j];
136. if
(resource.getName().equalsIgnoreCase("Property Files")) {
137. IResource[] fileResources
= resource.members();
138. for (int k = 0; k <
fileResources.length; k++) {
139. if (fileResources[k]
instanceof IFile &&
fileResources[k].get
Name().endsWith(".properties")) {
140. TreeObject obj =
new TreeObject(fileResources[k]

.getName());
141.
obj.setResouce(fileResources[k]);
142.
root.addChild(obj);
143. }
144. }
145. }
146. }
147. }
148. }
149. }catch (Exception e) {
// log exception
150. }
151. invisibleRoot = new TreeParent("");
152. invisibleRoot.addChild(root);
153. }

Line 131 – 151: Here we are iterating over projects in a workspace. For each project we are looking
for folder named “Property Files”. In this folder we are looking for files with extension “.properties”
and if they exist we create our domain model TreeObject and add this object to TreeParent created
above by using root.addChild(obj) method. Following figure shows the hierarchy of IResource
interface. For complete API listing refer Eclipse Platform Documentation.

Lines 151 - 152. Basically we have created an invisible node (TreeParent) which will act as a root
node of tree but it will not be visible to user. This node will also act as a parent node for all the folders
in the tree. We are adding root node which represents “Workspace Property Files” folder as child to
invisible node.

Lines 156 – 163: we are overriding createPartControl (Composite) method defined in WorkbenchPart
Class. This method is responsible for creating SWT/Jface components for our properties view. In this
method we are creating TreeViewer and providing content , label providers to the viewer. For more
information on this refer to Jface viewer chapter. Viewer.setInput method is used to provide the initial
input to the viewer. We have used getViewSite method to get site reference which is passed to viewer
as initial input. That is the reason that we are checking for parent.equals(viewsite) at line 90. We
could have very well used invisibleroot in setinput method instead. Point is that our domain model
gets to meet viewer control with the help of setInput method.

156. public void createPartControl(Composite parent) {


157. viewer = new TreeViewer(parent, SWT.MULTI |
SWT.H_SCROLL | SWT.V_SCROLL);
158. viewer.setContentProvider(new
ViewContentProvider());
159. viewer.setLabelProvider(new
ViewLabelProvider());
160. viewer.setInput(getViewSite());
161. hookContextMenu();
162. hookDoubleCLickAction();
163. }

Next we have called to methods to provide context menu and doubleclick action to our property view.

Lines 164 – 185: Here we are using viewer.addDoubleClickListener method to provide


doubleclickListener. On line 167, we are using event object to retrieve current selection.
IStructuredSelection represent multiple selected elements. It is possible that user has selected more
then one element in the view.

164. private void hookDoubleCLickAction() {


165. viewer.addDoubleClickListener(new IDoubleClickListener()
{
166. public void doubleClick(DoubleClickEvent event) {
167. ISelection selection = event.getSelection();
168. Object obj = ((IStructuredSelection)
selection)
.getFirstElement(
);
169. if (!(obj instanceof TreeObject)) {
170. return;
171. }else {
172. TreeObject tempObj = (TreeObject)
obj;
173. IFile ifile =
ResourcesPlugin.getWorkspace().getRoot()
.getFile(tempObj.getResouce().ge
tFullPath());
174. IWorkbenchPage dpage =
PropertyManagerView.this
.getViewSite()

.getWorkbenchWindow().getActivePage();
175. if (dpage != null) {
176. try {
177.
IDE.openEditor(dpage, ifile,true);
178. }catch (Exception e) {
179. // log exception
180. }
181. }
182. }
183. };
184. });
185. }

On line 168, we are retrieving first element from the structured selection. Next we are checking if
current selection is a property file by comparing it to TreeObject. Remember that TreeObject is our
domain model which we have created in the initialize method and it represents the property file. Next
we are retrieving Ifile handle with the help of TreeObject. Remember TreeObject saves the instance of
corresponding Resource Object. On line 177, we are opening up the editor with the help of
IDE.openEditor method.

public static IEditorPart openEditor(IWorkbenchPage page, IFile input,boolean activate)


throws PartInitException

The above method opens the editor for the given file resource. This method will attempt to resolve the
editor based on content-type bindings as well as traditional name/extension bindings. * If the page
already has an editor open on the target object then that editor is brought to front; otherwise, a new
editor is opened. If activate == true the editor will be activated.

Lines 186 – 198 : Nothing special here, your knowledge about actions have been put to practice
here. Essentially we have created new action which will perform viewer.refresh() – This will refresh
the tree starting from invisible node. We can also use public void refresh (final Object element)
to perform refresh action on a particular folder by passing TreeParent object.

186. private void hookContextMenu() {


187. MenuManager menuMgr = new
MenuManager("#PopupMenu");
188. Menu menu =
menuMgr.createContextMenu(viewer.getControl());
189. viewer.getControl().setMenu(menu);
190. Action refresh =new Action() {
191. public void run() {
192. initialize();
193. viewer.refresh();
194. }
195. };
196. refresh.setText("Refresh");
197. menuMgr.add(refresh);
198. }

Lines 199 – 201: We have overridden setFocus method defined in WorkbechPart class. This method
asks view to take focus within the workbench.

199. public void setFocus() {


200. viewer.getControl().setFocus();
201. }

Lets Test Properties View

Testing the modifications you have just made involves launching the Runtime Workbench. Open up
Property Manager View (Window > ShowView > Other)
It will open up Property Manager View as shown below.
Next, create a new project as shown below
Click Next, Name it Testing and click finish
Now create a new Folder inside the project
Make sure that you name this folder “Property Files”
Next, create some property files inside the Property Files Folder
Make sure that you provide right extension for these files:
Once you have created a property file, Right click on WorkSpace Property Files Folder in the property
manager view and click refresh.
You will notice that newly created file(s) is listed in property view as shown in figure below.
ECLIPSE TRACKING CHANGES

How to Track resource changes

In Last chapter (Views) we created a property manager view. Whenever user click refresh action, this
view searches for all the property files in the workspace and displays it to the user. Wouldn’t it be cool
if this view can refresh automatically whenever a property file is added to workspace? If you answer
yes, then you are at right place.
Eclipse provides IResourceChangeListener to keep track of resource changes in the workspace. Eclipse
generates resource change events indicating that the files and folders that have been added, modified,
and removed from the workspace. Interested parties can subscribe to these events and take
necessary action. The interface org.eclipse.core.resources.IResourceChangeListener defines single
method:
public void resourceChanged (IResourceChangeEvent event). In this chapter we will modify
PropertyManagerView so as to implement IResourceChangeListener and use IResourceChangeEvent to
update itself. Before we move on it is important to understand IResourceChangeEvent.

Note about IResourceChangeEvent

According to Eclipse API Specification there are currently five different types of resource change
events:

• PRE_BUILD
• POST_BUILD
• POST_CHANGE
• PRE_CLOSE
• PRE_DELETE

Please refer to online Eclipse API Specification to know more about these events.

Note about IResourceDelta

A resource delta represents changes in the state of a resource tree between two discrete points in
time OR we can say it is through delta object that we come to know about the changes taking place in
workspace. Whenever resource modification is performed by the user delta of modification is prepared
by eclipse and interested parties can use this delta to update themselves. This interface declares many
constants describing the kind of change.

Please refer to online Eclipse API Specification to know about methods provided by IResourceDelta.

Let’s Modify Property Manager View

Best way to learn above mentioned theory is to practice with concrete example. In this section we will
take step by step approach to
modify Property Manager View so that it can keep itself updated with resource modifications in
workspace. Lets start by implementing IResourceChangeListener. Open
com.myplugin.rmp.views.PropertyManagerView in java editor and implement resource change listener
as shown below.

public class PropertyManagerView extends ViewPart implements IResourceChangeListener

Next, register PropertyManagerView with Work Space so that this view is notified whenever work
space modification event is generated.
Modify createPartControl method as shown below:

public void createPartControl(Composite parent) {


viewer = new TreeViewer(parent, SWT.MULTI |
SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new
ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setInput(getViewSite());
ResourcesPlugin.getWorkspace().addResourceChangeLis
tener(this);
hookContextMenu();
hookDoubleCLickAction();
}

Next, Override dispose method of view to remove Listener. Dispose method of View is called every
time the View Part is destroyed.

public void dispose() {


super.dispose();
ResourcesPlugin.getWorkspace().removeResourceChangeL
istener(this);
}

Next, Override resourceChanged method from IResourceChangeListener as shown below:

1. public void resourceChanged(IResourceChangeEvent event) {


2. try{
3. if(event.getType() ==
IResourceChangeEvent.POST_CHANGE){
4. event.getDelta().accept(new
IResourceDeltaVisitor(){
5. public boolean visit(IResourceDelta
delta) throws CoreException {
6.
if(delta.getResource().getName().endsWith(".properties")){
7. initialize();
8.
Display.getDefault().asyncExec(new Runnable() {
9. public void
run() {
10.
viewer.refresh();
11.
viewer.expandAll();
13. }
14 });
15. }
16. return true;
17. }
18. });
19. }
20. }catch(CoreException e){
21. // log it
22. e.printStackTrace();
23. }
24. }

Line 3: We are only interested in Post change events. So here we are checking the event type. If the
event is a POST_CHANGE event then we proceed ahead.

Line 4: getDelta() method in IResourceChangeEvent returns the delta i.e. information about the
modifications which triggered this event.

Line 5: IResourceDeltaVisitor is an object that visits (visitor pattern) resource deltas. It visits resource
deltas that are ADDED, CHANGED, or REMOVED. In case visitor returns true - the resource delta's
children are also visited.

Line 6: Here we are retrieving the resource which has been modified and checking if it is a .properties
file.

Line 7: If the modified resource is a .properties file then we are initializing our model object again.

Line 8 – 13: Next we want to refresh viewer so that it updates itself and resource changes are visible
in Property Manager View. The code Display.getDefault().asyncExec(new Runnable(){… makes sure
that we don’t get illegal thread access exception. If we try to refresh viewer outside of this code (say
immediately after initialize is called) then we will get illegal thread access exception. Reason? Basically
the resourceChanged Method is called in a non UI thread and when we try to modify UI by calling
viewer.refresh() in this non UI thread it throws exception. In order to overcome this problem we have
redirected the execution to UI Thread by using Display object.

Let’s Test Property Manager View

Launch eclipse application from plug-in manifest editor. Open up Property manager View (Window >
show view > other). Create property files in Project under folder (Property Files) and notice that
Property manager View Refreshes on every addition/deletion of property file resource.
GETTING STARTED WITH PREFERENCE PAGES

Preference Pages

As an eclipse user you must have used preferences on many occasions. A Preference is a data which is
persisted between workspace sessions.
Preferences are used in Eclipse to take preferences from user on the fly rather then hard cording them
in plug-in itself. In order to view preferences go to window > preferences. Following figure show how
preferences dialog look like.

In this chapter we will create a new preference page which will take Folder name preference from
user. This folder name will be used in Properties view instead of hard coding “Workspace Property
Files”.
Property File Manager Preference Page

Eclipse provide a wizard for creating preference pages. Open plugin.xml. Navigate to the Extensions
page followed by clicking "Add" button then click on org.eclipse.ui.preferencePages. Now select
Preference Page in list of available templates as shown below.

Click next button and provide values as shown in figure below and click finish.
After you click finish, open up com.myplugin.rmp.preferences.PropertyManagerPreferencePage class to
see the default implementation. We will discuss default implementation in sections to follow. At this
time we will launch new runtime workbench to see how Property Manager Preference page looks like.
Once you launch new Runtime workbench, open preference dialog (Window > preferences) and you
will see something as shown in figure below.
Note about FieldEditor and FieldEditorPreferencePage

Field editors are basically used to make UI of a preference page. A field editor can be thought of as an
item which is used to show the user with the value of a preference. FieldEditor is mostly used together
with a FieldEditorPreferencePage, Eclipse provides many ready-to-use field editors as shown in figure
below.
FieldEditorPreferencePage is a special abstract preference page to host field editors. Our preference
page extends FieldEditorPreferencePage, which, along with the various editor classes helps in
capturing preferences. Following figure shows complete hierarchy of FieldEditorPreferencePage. Please
refer to Eclipse API Specification to know about methods available in this class.

Reviewing the generated code

Armed with the knowledge of field editors and FieldEditorPreferencePage we are now ready to review
the generated code. Open com.myplugin.rmp.preferences.PropertyManagerPreferencePage class.
Notice that the default implementation (generated by wizard) extends FieldEditorPreferencePage and
implements IWorkbenchPreferencePage interface.

1. public class PropertyManagerPreferencePage


2. extends FieldEditorPreferencePage
3. implements IWorkbenchPreferencePage {
4. public PropertyManagerPreferencePage() {
5. super(GRID);
6.
setPreferenceStore(RmpPlugin.getDefault().getPreferenceStore());
7. setDescription("A demonstration of a preference
page implementation");
8. }
9. public void createFieldEditors() {
10. addField(new
DirectoryFieldEditor(PreferenceConstants.P_PATH,
11. "&Directory preference:",
getFieldEditorParent()));
12. addField(
13. new BooleanFieldEditor(
14. PreferenceConstants.P_BOOLEAN,
15. "&An example of a boolean
preference",
16. getFieldEditorParent()));

17. addField(new RadioGroupFieldEditor(


18. PreferenceConstants.P_CHOICE,
19. "An example of a multiple-choice
preference",
20. 1,
21. new String[][] { { "&Choice 1",
"choice1" }, {
22. "C&hoice 2", "choice2" }
23. }, getFieldEditorParent()));

24. addField(
25. new
StringFieldEditor(PreferenceConstants.P_STRING,
"A &text preference:",
getFieldEditorParent()));
26. }
27. public void init(IWorkbench workbench) {
28. }
29.}

Line 5: GRID is a layout constant defined in FieldEditorPreferencePage. Layout constant (value 1)


indicates that the field editors' basic controls are put into a grid layout. Read SWT chapter for more on
layouts.

Line 6: Sets the preference store for this preference page. We are using
RmpPlugin.getDefault().getPreferenceStore() to retrieve the preference store for this Resource
Manager Plugin. getDefault method returns the shared instance of plug-in. every plug-in has its own
preference store. Preferences are stored in a
<runtimeworkspace>\.metadata\.plugins\<pluginid>\pref_store.ini file.

Line 7: Set Description method is used to set the description title on the top of preference window.

Line 9 -26: createFieldEditors method is used to create GUI of the preference page. In this method we
are creating four field editors (Directory, Boolean, Radio and String). AddField method is used to add
the filed editor to preference page.

DirectoryFieldEditor

This editor is used to create a directory filed with in the preference page. First argument to
constructor is the name of this field. This name is defined as a constant in
com.myplugin.rmp.preferences.PreferenceConstants which was generated by preference page creation
wizard. These names are also used to retrieve values of a specific preference from preference store.
Last argument specifies the parent of the field editor's control. We are using getFieldEditorParent()
defined in FieldEditorPreferencePage to retrieve the parent control.

BooleanFieldEditor

This editor is used to create a Boolean field. It creates a checkbox in the preference page. Arguments
are same as described in directory filed editor.

RadioFieldEditor

This editor is used to create a radio button field. Third argument is the numColumns - the number of
columns for the radio button presentation.
In our case it is one. Next argument is the labelAndValues list of radio button [label, value] entries.
The value is returned when the radio button is selected

StringFieldEditor

This editor is used to create a Text box which takes a String as input. Arguments are same as
described in DirectoryFieldEditor.

Lines 27 – 28: We have not used this method. However, it can be used to Initialize this preference
page for the given workbench.

GETTING STARTED WITH PREFERENCE PAGES (PAGE 2)

Lets Customize Preference Pages

In this section we will modify the preference page so as to create a single String Text Box where user
can set his preference for the name of folder which will be displayed in the Property Manager View.

Modify the PreferenceConstants class to add another constant FOLDER_NAME as shown in bold below.

public class PreferenceConstants {


public static final String P_PATH = "pathPreference";
public static final String P_BOOLEAN = "booleanPreference";
public static final String P_CHOICE = "choicePreference";
public static final String P_STRING = "stringPreference";
public static final String FOLDER_NAME = "folderName";
}

Next, Modify the createFieldEditors() in PropertyManagerPreferencePage class to create String filed


editor. Provide FOLDER_NAME constant as the name of this field editor (as shown below). Also declare
class level reference variable to hold String Field Editor object.

private StringFieldEditor fieldEditor;


public void createFieldEditors() {
fieldEditor = new StringFieldEditor(PreferenceConstants.
FOLDER_NAME, "Folder Name: ", getFieldEditorParent());
addField(fieldEditor);
}

Following figure shows, how preference page will look like after above customization.

Next, Override checkState() method defined in FieldEditorPreferencePage for the purpose of


customized validations. I could have very well use fieldEditor.setEmptyStringAllowed to perform same
validation. However, I am manually checking it here so that you can get an idea as to how to use this
method for complex validations.
protected void checkState() {
super.checkState();
if(fieldEditor.getStringValue()!= null && !
fieldEditor.getStringValue().equals("")){
setErrorMessage(null);
setValid(true);
}else{
setErrorMessage("Folder name cannot be blank!");
setValid(false);
}
}

The FieldEditorPropertyPage listens for FieldEditor.IS_VALID property change events and then calls
checkState() and setValid() as necessary. The String field editors are never in an invalid state and
thus do not issue FieldEditor.IS_VALID property change events, only FieldEditor.VALUE property
change events. You must override the FieldEditorPreferencePage propertyChange() method to call the
checkState() method when the FieldEditor.VALUE property change event is received.

public void propertyChange(PropertyChangeEvent event) {


super.propertyChange(event);
if (event.getProperty().equals(FieldEditor.VALUE)) {
checkState();
}
}

With above change an error message is displayed across the top of the preference page and the Apply
and OK buttons are disabled (as shown below)
Next, Modify com.myplugin.rmp.preferences. PreferenceInitializer (Generated by create preference
page wizard) to set the default value for folder name. In general Initializers are used to initialize
default preference values. Modify initializeDefaultPreferences() as shown below

public void initializeDefaultPreferences() {


IPreferenceStore store = RmpPlugin.getDefault()
.getPreferenceStore();
store.setDefault(PreferenceConstants.FOLDER_NAME,"WorkSpace
Property Files");
}

With above change, folder name will be defaulted to “WorkSpace Property Files” whenever user clicks
on default button in preferences dialog (as shown below)
Next Modify PropertyManagerView class so as to use preference rather than hard coded folder name.
Modify initialize method as follows:

public void initialize() {


IPreferenceStore store = RmpPlugin.getDefault()
.getPreferenceStore();

String folderName =
store.getString(PreferenceConstants.FOLDER_NAME);

TreeParent root = new TreeParent(folderName);


try {
IWorkspace workspace = ResourcesPlugin.getWorkspace();

IProject[] projects =
workspace.getRoot().getProjects();
rest method is same
With above mentioned change, On every refresh on root node of Properties view – folder name will be
picked up from preferences.
GETTING STARTED WITH PROPERTIES

Working with Properties

Eclipse plugin Properties are used to assign additional information to resources and objects.
Additional information could be anything. For Example, we may want to attach author name property
with the java file resource in eclipse. There are two ways to access resource property. First, right click
on resource and select properties option from context menu (as shown in figure below)
Another way to access properties for a resource is to open up the properties view from Window >
Show View > Properties (as shown in figure below)

In this chapter we will learn how to create property on a particular resource and display it's properties
in properties dialog as well as properties view. For the purpose of our example we will associate
properties with property files displayed in Property Manager View. We will create a context menu
option to open properties dialog. Later on we will see how to display properties in property view when
ever user selects a property file in Property Manager View.

Let’s create a property dialog

We will first create a property page through plug-in manifest editor. This preference page will be
shown in properties dialog. In order to create property page open plugin.xml in manifest editor.
Navigate to extension page. Click on Add… button. Select org.eclipse.ui.propertyPages and click finish.
Next, In the extensions page right click on org.eclipse.ui.propertyPages and select new > page. Click
on new page declaration and edit its properties as shown in figure below. We need to provide
TreeObject class in object Class because we will be showing property dialog on selection of property
files in Property Manager View and model class for property files in our view is TreeObject class.

Note: In order to access TreeObject class in below mentioned properties change access modifier from
default to public. Also change the getResource() method in TreeObject to public from protected. It will
be accessed from outside in coming sections.
Next, generate the com.myplugin.rmp.propertyPage class by clicking on class link in manifest
editor(extensions page) with the help of java attribute dialog. Modify the
com.myplugin.rmp.propertyPage as shown in the listing below.

1. package com.myplugin.rmp;
2. import org.eclipse.core.resources.IResource;
3. import org.eclipse.core.runtime.CoreException;
4. import org.eclipse.core.runtime.QualifiedName;
5. import org.eclipse.swt.SWT;
6. import org.eclipse.swt.layout.GridData;
7. import org.eclipse.swt.layout.GridLayout;
8. import org.eclipse.swt.widgets.Composite;
9. import org.eclipse.swt.widgets.Control;
10. import org.eclipse.swt.widgets.Label;
11. import org.eclipse.swt.widgets.Text;
12. import org.eclipse.ui.IWorkbenchPropertyPage;
13. import org.eclipse.ui.dialogs.PropertyPage;
14. import com.myplugin.rmp.views.PropertyManagerView.TreeObject;

15. public class propertyPage extends PropertyPage implements


16. IWorkbenchPropertyPage {
17. private Text textField;
18. public static QualifiedName AUTHOR_PROP_KEY = new
QualifiedName("Author", "Author");

19. public propertyPage() {


20. super();
21. }

22. protected Control createContents(Composite parent) {


23. Composite myComposite = new
Composite(parent, SWT.NONE);
24. GridLayout mylayout = new GridLayout();
25. mylayout.marginHeight = 1;
26. mylayout.marginWidth = 1;
27. myComposite.setLayout(mylayout);
28. Label mylabel = new Label(myComposite,
SWT.NONE);
29. mylabel.setLayoutData(new GridData());
30. mylabel.setText("Author");
31. textField = new Text(myComposite,
SWT.BORDER);
32. textField.setLayoutData(new
GridData(GridData.FILL_HORIZONTAL));
33. textField.setText(getAuthor());
34. return myComposite;
35. }

36. protected String getAuthor() {


37. IResource resource =
38. ((TreeObject)
getElement()).getResouce();
39. try {
40. String value =
41. resource.getPersistentProperty(
42. AUTHOR_PROP_KEY);
43. if (value == null)
44. return "";
45. return value;
46. }
47. catch (CoreException e) {
48. return e.getMessage();
49. }
50. }

51. protected void setAuthor(String author) {


52. IResource resource =
53. ((TreeObject)
getElement()).getResouce();
54. String value = author;
55. if (value.equals(""))
56. value = null;
57. try {
58.
resource.setPersistentProperty(
59. AUTHOR_PROP_KEY,
60. value);
61. }
62. catch (CoreException e) {
63. }
64. }

65. public boolean performOk() {


66. setAuthor(textField.getText());
67. return super.performOk();
68. }
69. }

Lines 15 -16: We are extending abstract base class PropertyPage. This class is Abstract base
implementation of a workbench property page (IWorkbenchPropertyPage). Subclasses of this base
class should implement the createContents method in order to provide the property page's main
control. Following figure shows the hierarchy of this class.

Lines 22 – 35: Here we are implementing createContents method defined in PreferencePage class.
This method creates and returns the SWT control. Nothing special here we are just using SWT controls
to create the GUI of properties dialog. At line 33 we are calling getAuthor() method discussed next to
get the existing author property.

Lines 37 - 38: In our properties dialog we will be showing single property named author for every
“.properties” file. getAuthor() method is used to fetch the existing property saved in workspace.
getElement() returns the object that owns the properties shown in the dialog. In our example case
this dialog will open up whenever user right clicks on “.property” file in Property Manager View. Since
our model object behind tree viewer is TreeObject we are casting getElement with TreeObject. Finally
we are fetching corresponding resource object from treeObject.

Lines 39 – 50: There are two types of properties: persistent and session. Methods in IResource
provide both session properties, which are discarded when Eclipse exits, and persistent properties,
which are preserved across multiple workspace sessions. Following are the four methods provided by
IResource implementation

getPersistentProperty(QualifiedName)

getSessionProperty(QualifiedName)
setPersistentProperty(QualifiedName, String)

setSessionProperty(QualifiedName, Object)

Please follow the link to know more about these methods.


In order to retrieve property we use qualified name. Qualified names are two-part names: qualifier
and local name. AUTHOR_PROP_KEY(QualifiedName) is defined on line 18.

Lines 51 – 64: All concepts are similar to what we discussed above with exception that we are using
setPersistentProperty to set the author property for every object.

Lines 65 – 68: finally we are overriding perform ok method to fetch author name from dialog and
calling the setAuthor() method which will persist the preference.

In order to open properties dialog we will modify hookContextMenu() method in


com.myplugin.rmp.views.PropertyManagerView as shown below.
We have used Eclipse inbuilt action “PropertyDialogAction to open up Properties Dialog Below.

private void hookContextMenu() {


MenuManager menuMgr = new MenuManager("#PopupMenu");
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
Action refresh =new Action() {
public void run() {
initialize();
viewer.refresh();
}
};
refresh.setText("Refresh");
menuMgr.add(refresh);
menuMgr.add(new Separator());
menuMgr.add(new PropertyDialogAction(getSite(), viewer));
}
GETTING STARTED WITH PROPERTIES

Lets display properties in properties View

Object properties are shown in Properties view if selected object implements


org.eclipse.ui.views.properties.IPropertySource interface. In our example we will show Author
property in the properties view whenever “.properties” file is selected in the
com.myplugin.rmp.views.PropertyManagerView. Since TreeObject is the model object behind
“.properties” file – TreeObject needs to implement “org.eclipse.ui.views.properties.IPropertySource”
interface. Also, com.myplugin.rmp.views.PropertyManagerView should emit selection changed events
so that the Properties View can listen to them and decide whether properties are to be displayed for
selected object. Before we get into details it will be good to look at the IPropertySource interface and
its methods. Please refer to Eclipse API Specification to know about this interface

Property descriptors objects are used to create a property editor in the Properties view. Eclipse
provides some implementations of the IPropertyDescriptor interface as shown in figure below.

Confused! Let’s start with real coding

If you are not able to understand above mentioned details then don’t worry!! What follows is the step
by step approach of integrating properties View with our own Property Manager View (similar names!!
Don’t get confused, Property Manager View is our example view where in we are displaying all the
property files in workspace whereas Properties View is provided by eclipse to display properties of
object selected in workbench).

Step 1: Modify com.myplugin.rmp.views.PropertyManagerView such that it starts broadcasting


selection changed events. Remember Property View listens to selection change events in order to
display properties of selected object. Modify createPartControl method in
com.myplugin.rmp.views.PropertyManagerView as shown below (in bold).

public void createPartControl(Composite parent) {


viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL |
SWT.V_SCROLL);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setInput(getViewSite());
ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
getSite().setSelectionProvider(viewer);
hookContextMenu();
hookDoubleCLickAction();
}
Step 2: With above step, PropertyManagerView will start broadcasting selection changed events.
Whenever user selects/deselects “.properties” file in view an event will be generated. Eclipse
Properties View listen to these selection change events and display properties of currently selected
object. BUT HOW???? How does it know which properties to display?? What are the values for these
properties. Can it display properties for any type of objects?? The short answer is NO… Eclipse
Properties View will display properties for only those objects which implement
org.eclipse.ui.views.properties.IPropertySource Interface.
In our case “.properties” files are essentially TreeObject. So we need to modify TreeObject class so
that it implements IPropertySource Interface. However, in order to use
org.eclipse.ui.views.properties.IPropertySource you need to add org.eclipse.ui.views in plug-in
dependencies as shown in figure below.
Next, add following three lines in com.myplugin.rmp.views.PropertyManagerView class.

private static final String AUTHOR_ID = "RMP.author";


private static final TextPropertyDescriptor AUTHOR_PROP_DESC = new

TextPropertyDescriptor(AUTHOR_ID,"author");
private static final IPropertyDescriptor[] DESCRIPTORS =
{ AUTHOR_PROP_DESC };
Next, modify com.myplugin.rmp.views.PropertyManagerView$TreeObject as shown below (notice
changes in bold):
public class TreeObject implements IAdaptable,IPropertySource {
private String name;
private TreeParent parent;
private IResource resouce;

public TreeObject(String name) {


this.name = name;
}

public String getName() {


return name;
}

public void setParent(TreeParent parent) {


this.parent = parent;
}

public TreeParent getParent() {


return parent;
}

public String toString() {


return getName();
}

public Object getAdapter(Class key) {


return null;
}

public IResource getResouce() {


return resouce;
}

public void setResouce(IResource resouce) {


this.resouce = resouce;
}

public Object getEditableValue() {


return null;
}

public IPropertyDescriptor[] getPropertyDescriptors() {


return DESCRIPTORS;
}

public Object getPropertyValue(Object id) {


try{
if(AUTHOR_ID.equals(id)){
return
resouce.getPersistentProperty(propertyPage.AUTHOR_PROP_KEY);
}
}catch(Exception e){

}
return null;
}

public boolean isPropertySet(Object id) {


return false;
}

public void resetPropertyValue(Object id) {

public void setPropertyValue(Object id, Object value) {


try{
if(AUTHOR_ID.equals(id)){
resouce.setPersistentProperty(propertyPage.AUTHOR_PR
OP_KEY,(String)value);
}
}catch(Exception e){

}
}

}
Now, whenever a “.properties” file is selected in Property Manager View. Its properties are shown in
Eclipse Properties View as shown in figure below.
ECLIPSE PLUGIN EDITORS TUTORIAL

Working with Editors

Editors are used to create/modify workspace resources. As an Eclipse user you must have used editors
all the time. Famous example of editor is the Java Editor. It provides many capabilities like Content
assist, color coding and so on. There is no specific implementation of an editor because editors
essentially cater to application specific behavior.

Once the implementation model for an editor is determined, implementing the editor is much like
programming a standalone JFace or SWT application.

Workbench Editors
Although the implementation of a workbench editor will be specific to your plug-in and the content
that you want to edit, the workbench provides a general structure for building an editor. Editors
should implement org.eclipse.ui.IEditorPart interface. In Eclipse, Editors rests inside
org.eclipse.ui.IEditorSite, which in turn rests in org.eclipse.ui.IWorkbenchPage.

Thankfully, Eclipse provides two important base implementations of IEditorPart interface namely
EditorPart and MultiPageEditorPart (discussed next). Major difference between the two type of editors
is that MultiPageEditorPart provides the functionality of displaying multiple pages on same editor in
tabbed fashion – similar to what we see in plug-in manifest editor (Overview tab, extensions tab,
dependency tab etc.)

EditorPart

This is the Abstract base implementation of all workbench editors. Subclasses must implement the
following methods:

• IEditorPart.init - to initialize editor when assigned its site


• IWorkbenchPart.createPartControl - to create the editor's controls (SWT/JFace controls)
• IWorkbenchPart.setFocus - to accept focus
• IEditorPart.isDirty - to decide whether a significant change has occurred
• IEditorPart.doSave - to save contents of editor
• IEditorPart.doSaveAs - to save contents of editor
• IEditorPart.isSaveAsAllowed - to control Save As

MultiPageEditorPart

A multi-page editor is an editor with multiple pages, each of which may contain an editor or an
arbitrary SWT control. Subclasses must implement the following methods:

• CreatePages - to create the required pages by calling one of the addPage methods (pages will
be subclasses of EditorPart discussed above)
• IEditorPart.doSave - to save contents of editor
• IEditorPart.doSaveAs - to save contents of editor
• IEditorPart.isSaveAsAllowed - to enable Save As
• IEditorPart.gotoMarker - to scroll to a marker.
Creating Editor by using inbuilt editor template

In order to understand editor concepts we will use one of the templates available in eclipse itself. This
template creates a multi-page editor. The editor has three pages: Edit where you enter text,
Properties that allows you to change font of the result and Preview that shows sorted words from the
Edit page using the font set in Properties.

In order to create multi-page editor, open plug-in.xml file. Navigate to extensions tab and click on
Add. Select “Extension Wizards” tab followed by Multi-page Editor as shown in figure below.

Next, click on “Next” button and provide values as shown below:


Java Package Name: is the package in which editor class will be generated.

Editor Class Name: is the name of multi page editor class which will be generated after this wizard
finishes

Editor Contributor Class: is an instance of org.eclipse.ui.IEditorActionBarContributor which manages


the installation and removal of global menus, menu items, and toolbar buttons for one or more
editors. The platform sends the some events to the contributor, indicating when an editor has become
active or inactive, so that the contributor can install or remove menus and buttons as appropriate.

Editor Name: Human readable name of editor.

File Extension: This attribute specifies the file extensions with which we would like to associate this
particular editor.

Next, Click finish. Save the Plugin manifest file. We will first look how newly created editor looks like
before reviewing the generated code. In order to view the editor in action launch eclipse runtime
application. Create a new file from right click context menu as shown below:
Name the new file anything but keep the extension of the “.mpe” because this is the extension with
which newly created editor is associated with. Once you have created the file – Sample Multi-Page
editor will open up with three tabs namely <filename>.mpe, Properties and Preview. Play around with
the editor before we get onto reviewing generated code.
Let’s Review the generated code

Let’s start with plug-in manifest editor.


In order to create a new editor we need to extend org.eclipse.ui.editors extension point. Following are
some of attributes (with brief description) which need special attention.

Extensions: every editor typically understands only special file extensions. For ex: XML editor
understands only .xml extension. You can provide file extensions (comma separated) understood by
editor.

Command: We can specify command here to launch an external editor. For example: I may like to
open XML SPY (external editor) when user clicks on xml file inside eclipse.

Launcher: class that implements org.eclipse.ui.IEditorLauncher and is used to launch an external


editor.

contributerClass: a class that implements org.eclipse.ui. IEditorActionBarContributor . This class us


useful in adding actions to various parts of eclipse whenever editor is opened. We will discuss
Contributor class in coming sections when we review its generated code.

Default: If true, this editor will be used as the default editor for the file extension

Filenames: if we want to open our editor for specific filenames


Let’s review com.myplugin.rmp.editors.MultiPageEditor class.

As discussed earlier that implementation of editor is much like programming a standalone JFace or
SWT application. So we will not get into details of how to build an editor with help of SWT/JFACE. We
will just concentrate on the lifecycle of editor. In Coming sections ill discuss various editor specific
methods. We will discuss the order in which these method get called (in editor lifecycle) and what is
the purpose of these methods.

public MultiPageEditor() {
super();
ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
}

Whenever user clicks on a “.mpe” file constructor of MultiPageEditor will be called. This class
implements IResourceChangeListener (discussed in resource change tracking chapter). In editor
constructor we are registering this instance of editor with the workspace so that editor is notified for
any resource changes in the workspace.

public void init(IEditorSite site, IEditorInput editorInput)


throws PartInitException {
if (!(editorInput instanceof IFileEditorInput))
throw new PartInitException("Invalid Input: Must be
IFileEditorInput");
super.init(site, editorInput);
}

Next in the editor lifecycle init method is called, we are overriding init method defined in EditorPart
class. This method is the first method to be called when editor is created In this method we are
verifying whether the editor input is acceptable (it should be instance of IFileEditorInput) otherwise
throwing an exception. IEditorInput is a light weight descriptor of editor input, like a file name but
more abstract. It is a object which can be queried to know more about the input which is coming to
editor.

protected void createPages() {


createPage0();
createPage1();
createPage2();
}

void createPage0() {
try {
editor = new TextEditor();
int index = addPage(editor, getEditorInput());
setPageText(index, editor.getTitle());
} catch (PartInitException e) {
ErrorDialog.openError(
getSite().getShell(),
"Error creating nested text editor",
null,
e.getStatus());
}
}

...
...

Next in the editor lifecycle createPages() method is called, This method creates the pages of this
multipage editor. Typically, this method simply calls more finely grained methods such as
createPage0(To create eclipse plugin text editor), createPage1(To create composite) etc. So this
method is used to create the GUI for our editor. Next, in createPage0() we are creating a new
TextEditor. This is a inbuilt standard text editor for file resources (we could have created our own
editor by extensing EditoPart Directly). addPage method is used to add a new page containing the
given editor to this multipage editor. addPage returns the index where this page is added. Next
setPageText is used to set the title for the page index.

public boolean isSaveAsAllowed() {


return true;
}

isSaveAsAllowed() returns whether the "Save As" operation is supported by this editor part. This
method calculates whether save action should be disabled or enabled whenever editor is opened.

protected void pageChange(int newPageIndex) {


super.pageChange(newPageIndex);
if (newPageIndex == 2) {
sortWords();
}
}

pageChange(int) method is called whenever user toggles the page tab on bottom of multi page editor.
This method is used to calculate the contents of selected page.

public void doSave(IProgressMonitor monitor) {


getEditor(0).doSave(monitor);
}

public void doSaveAs() {


IEditorPart editor = getEditor(0);
editor.doSaveAs();
setPageText(0, editor.getTitle());
setInput(editor.getEditorInput());
}

doSave() and doSaveAs() methods are called whenever user clicks “Save” or “Save As” actions. We
are using editor at index zero i.e. the Text Editor to save the file. On save, the editor should generate
a property changed event (PROP_DIRTY). doSaveAs() is used to open a Save As dialog

public void gotoMarker(IMarker marker) {


setActivePage(0);
IDE.gotoMarker(getEditor(0), marker);
}

gotoMarker() sets the cursor and selection state for this editor as specified by the given marker. We
will discuss about markers in chapters to follow.

Note About Marking Editors Dirty

In above example we have not covered process to mark editors dirty so that Save and Save As
buttons can be enabled. Whenever user makes some modification to editor file we can mark editor as
dirty by calling firePropertyChange(IEditorPart.PROP_DIRTY). We can also use isDirty() method to see
if editor is marked as dirty at any point in editor.

Let’s review com.myplugin.rmp.editors.MultiPageEditorContributor class.

This class is responsible for Managing the installation/deinstallation of global actions for multi-page
editors. In our example editor, you will notice that “Editor Menu” action is displayed on top menu
whenever editor is opened (as shown in figure below). This action is removed from workbench menu
bar whenever multi page editor is closed.

The EditorActionBarContributor class implements the IEditorActionBarContributor interface, which


caches the action bar and workbench page, and provides two new accessor methods.

getActionBars() : it returns the contributor's action bars provided to the contributor when it was
initialized.

getPage(): it returns the contributor's workbench page provided to the contributor when it was
initialized.

contributeToMenu(): Contributes to the given menu. In our example we are adding new “Editor
&Menu” to the workbench menu.

contributeToToolBar(): Contributes to the given tool bar.

The MultiPageEditorActionBarContributor class extends EditorActionBarContributor, providing a new


method to override instead of the setActiveEditor(IEditorPart) method.

setActivePage(IEditorPart part): This method is called whenever the page changes. This method
Sets the active page of the multipage editor to the given editor. If there is no active page, or if the
active page does not have a corresponding editor, the argument is null. We are calling

ECLIPSE BUILDERS, NATURES AND MARKERS

In this chapter we will talk about builders, natures and markers.

Builders: If you are using Eclipse IDE for java development then you are not new to Builders. Inside
Eclipse builders are used to take java source as input and generate corresponding class files. So you
can define builders as an engine which generates some output based on your input. Incremental
Builders - These contribute to performance improvement by rebuilding only the delta since last full
build.

Markers: Markers are used mark locations in editor. Java editor uses these markers to mark error
locations, warnings, book marks etc.

Natures: Natures are used to link project with various functionalities such as builders in a project. For
ex: if we add java nature to a project inside eclipse. It associates project with incremental java
compiler.

Creating Builders Nature using existing templates

In order to understand builder nature and marker concepts we will use one of the templates available
in eclipse itself. This template will create an builder (incremental). In addition, it will also create a
project nature. Name of this builder is "sample builder" and it basically validates XML file and if
required adds a problem marker to problematic xml files. The builder will run only for projects which
have declared themselves as having sample nature projects. Select Add/Remove Sample Nature
action from a project context menu, to toggle the nature on a project.

In order to create project builder and nature, open plug-in manifest editor. Navigate to extensions
page followed by clicking on "Add" button. Now select Extension Wizards tab followed by Project
Builder and nature template as shown in figure below.
Click next and use default values as shown below.
Click finish and save the plug-in manifest file. Before we move onto discuss the generated code let’s
first see the builder in action. Launch eclipse runtime application. Create a new xml file in existing
project (create new project if workspace is new). Edit newly created xml file such that it is not well
formed. Right click on project and click Add/Remove sample Nature. Notice that the marker will
appear inside the editor (as shown in figure below).
Eclipse Builders

Let’s review the plug-in manifest file to see what it takes to create a new project builder.
New builder is created by extending the org.eclipse.core.resources.builders extension point. ID and
name are used to give builder a datavalue and name respectively. Point is nothing but the extension
point which we have extended.
Next, is the builder element. The hasNature attribute flags whether this builder is associated with any
nature.
Next, is the run element (class attribute). Here we specify the actual java class which provides the
functionality of the builder.
IncrementalProjectBuilder

The java class (com.myplugin.rmp.builder.SampleBuilder) discussed above needs more attention as


this is the class which is doing the actual work. Any builder class must be a subclass of
IncrementalProjectBuilder. All builders must subclass this class according to the following guidelines:

• Subclasses should implement the build method of this class


• Subclasses may implement remaining methods
• Subclasses should supply a public and no arg constructor

Please refer to Eclipse API Specification to find details of all the methods provided by this Class.

The build method requires special attention here. This method of the builder is called whenever build
is required (for ex: user saves java file and automatic build preference is checked)

build(int kind, Map args, IProgressMonitor monitor)

kind: What kind of build is required?? Kind parameter could be a FULL_BUILD, INCREMENTAL_BUILD,
and AUTO_BUILD.
Args: A map to pass arguments/information to builder.

Monitor: A progress monitor

Let’s review generated code related to builders

In this section we will review generated class (com.myplugin.rmp.builder.SampleBuilder) and will


discuss builder/marker related code segments.

We will not go into details of IResourceDelta, IResourceDeltaVisitor or IResourceVisitor in this chapter.


For more details on these topics refer to resource change tracking chapter.

protected IProject[] build(int kind, Map args, IProgressMonitor monitor)


throws CoreException {
if (kind == FULL_BUILD) {
fullBuild(monitor);
} else {
IResourceDelta delta = getDelta(getProject());
if (delta == null) {
fullBuild(monitor);
} else {
incrementalBuild(delta, monitor);
}
}
return null;
}
Eclipse will call build method of the builder whenever any type of build is required. In above code
segment we are using kind parameter to understand the kind of build request. We have implemented
two methods for each kind of build full build/ incremental build discussed next.
protected void fullBuild(final IProgressMonitor monitor) throws CoreException
{
try {
getProject().accept(new SampleResourceVisitor());
} catch (CoreException e) {
}
}

protected void incrementalBuild(IResourceDelta delta, IProgressMonitor


monitor)
throws
CoreException {
// the visitor does the work.
delta.accept(new SampleDeltaVisitor());
}

In both of above methods we are delegating calls to Visitors. Visitor will visit all the resources (in case
of delta only the modified resources since last build). For each resource we are calling checkXML()
method. CheckXML method essentially delegates call to XMLErrorHandler defined in builder class
which will check if XML document is well formed or not. In case it is not well formed it will create a
marker (as shown below). I am not going into details of SAX parsing or SAX event handlers (it is out
of scope for this tutorial). We are using Sample builder’s addMarker method to create a marker on line
number where the exception occurred.

private void addMarker(SAXParseException e, int severity) {


SampleBuilder.this.addMarker(file, e.getMessage(), e
.getLineNumber(), severity);
BUILDERS, NATURES AND MARKERS (PAGE 2)

Markers

As described earlier, Markers are used mark locations in editor. Java editor uses these markers to
mark error locations, warnings, book marks etc.

There are many types of predefined markers defined as constants in IMarker interface.

org.eclipse.core.resources.bookmarkIMarker.BOOKMARK
org.eclipse.core.resources.markerIMarker.MARKER
org.eclipse.core.resources.problemmarker IMarker.PROBLEM
org.eclipse.core.resources.taskmarkerIMarker.TASK
org.eclipse.core.resources.textmarkerIMarker.TEXT

Let’s review the plug-in manifest file to see what it takes to create a new marker. New marker is
created by extending org.eclipse.core.resources.markers extension point. ID and Name are datavalue
and name respectively. Point is nothing but the extension point we are using to create this marker.
Next, we need to define the super type marker for new marker. Since we want to show errors in
Problems View we are using org.eclipse.core.resources.problemmarker as supertype.
Next is the persistent element. Since we want this markers to persist across eclipse sessions we are
setting this property to true.
Reviewing the generated code

addMarker method in SampleBuilder class is used to show above defined marker in the editor
whenever problem/error occurs.

private static final String MARKER_TYPE = "com.myplugin.rmp.xmlProblem";


private void addMarker(IFile file, String message, int lineNumber, int
severity) {
try {
IMarker marker = file.createMarker(MARKER_TYPE);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.SEVERITY, severity);
if (lineNumber == -1) {
lineNumber = 1;
}
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
} catch (CoreException e) {
}
}
IMarker is the main interface when we are dealing with eclipse markers. Please refer to Eclipse API
Specification to know more about IMarker Interface.

BUILDERS, NATURES AND MARKERS (PAGE 3)

Natures

Natures are used to link project with various functionalities such as builders in a project. For ex: if we
add java nature to a project inside eclipse. It associates project with incremental java compiler.
natures are added in .project file of the project. Natures are not only used to associate builders but
are also used to define many other functionalities for ex: only java nature projects are shown in
Package Explorer. Some of the predefined natures are
org.eclipse.jdt.core.javanature,org.eclipse.pde.PluginNature

Reviewing the generated code

Let’s review the plug-in manifest file to see what it takes to create a nature. Nature is created by
extending org.eclipse.core.resources.natures extension point. ID is the unique identifier for this
nature. Name is the human readable name of the nature.
Next element is the builder. Here we will add a builder to this nature. We have associated
SampleBuilder created earlier with this nature. So that projects with SampleNature use SampleBuilder
whenever an XML file is saved.
Next elements which we are going to discuss are runtime and run. Here we will specify a class named
Sample Nature which will be used to configure/deconfigure project with Sample Nature. With the help
of this class we will be able to configure non Sample Nature project to Sample Nature project at run
time. OR we will be able to convert Sample Nature Project to non Sample Nature project.
Repercussions of making a Project as Sample Nature project will be that a Sample builder will be
attached to project which will run whenever an XML file is saved and will look for any errors in XML.
IProjectNature

Class com.myplugin.rmp.builder.SampleNature declared above implements IProjectNature interface. It


can configure a project with the project nature, or de-configure it. Please refer to Eclipse API
Specification to know more about this class.

In our example, user is provided with toggle action to convert non Sample Nature project to Sample
Nature project. Following method from SampleNature class will be called to associate the project with
SampleNature.

public void configure() throws CoreException {


IProjectDescription desc = project.getDescription();
get the description of the project basically .project
file information
ICommand[] commands = desc.getBuildSpec();
// get the build commands already associated with
project.
for (int i = 0; i < commands.length; ++i) {
if
(commands[i].getBuilderName().equals(SampleBuilder.BUILDER_ID)) {
return; // Do nothing if Sample builder is already
associated with project
}
}

ICommand[] newCommands = new ICommand[commands.length + 1];


// create a new
build command
System.arraycopy(commands, 0, newCommands, 0, commands.length);
ICommand command = desc.newCommand();
command.setBuilderName(SampleBuilder.BUILDER_ID); // attach it
to sample builder
newCommands[newCommands.length - 1] = command;
desc.setBuildSpec(newCommands);
project.setDescription(desc, null); // write to .project file
}
Every workbench project contains a .project file that contains build commands. Executing above
method causes the following to appear in the buildSpec section of the project's .project file. Also
Sample nature is added in natures section.
<buildSpec>
<buildCommand>
<name>com.myplugin.rmp.sampleBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.myplugin.rmp.sampleNature</nature>
</natures>

Eclipse Help System

Help in eclipse is accessed by using Help > Help Contents menu. Once you done with development of
your plug-in and before you are ready to ship it as a product, one thing which you would like to do is
create help contents. No matter how simple or complex your plugin is, users would like to see get
started documents. Also help provide us with opportunity to describe functionalities available with the
plugin.
Creating New Help

Eclipse has support for many formats like HTML, PDF, XHTML to name a few. We can create help
within the main plugin or create altogether a new plugin project for help.

Creating new help project

We will start by creating a new Plug in project. In order to create new project click on File > New
Project > Select Plug in project (as shown below)
Click next button, Provide “com.myplugin.rmp.help” in Project Name field.
Click next button, Provide values as shown in figure below.
Click finish, this will create a new plug in project and will generate minimal code for the project. Till
this point project is empty. Now we will use Existing extension templates to generate necessary files
for creating help.

Navigate to Extensions page, click on "Add" button and select Extensions Wizard tab followed by
selecting Help Content template. This template creates a Help table of contents. If this table is set to
primary, it can be standalone, or integrated into pre-set categories. If this is not set as primary then it
can be attached with the primary toc for testing purposes.
Click Next button and provide values as shown below: Check the Primary Option. This will create a
primary table of content file. We will select only Getting Started and Reference categories for this
example.
Click Finish and save the manifest file.

Let’s Review the generated code

Once you have finished creating the extension points you will notice that many files have been
generated by the Help Template Wizard. It also creates html files in a new folder.In order to create
eclipse help org.eclipse.help.toc extension point is used. Next, we have to create various toc’s and
mark them primary/secondary depending on the type of help we are creating. Every toc is represented
by XML file.
Now let’s have a look at toc.xml file. Remember this file represents primary table of contents file.

<toc label="My Table of Contents" topic="html/toc.html">


<topic label="Getting Started">
<anchor id="gettingstarted"/>
</topic>
<topic label="Reference">
<anchor id="reference"/>
</topic>
</toc>
In above xml file, two subtopics have been defined i.e. "Getting Started" and "Reference". In the
above xml file, labels are used to display human readable text on the help. and the topic is used to
navigate to the real help page.

Next, examine tocgettingstarted.xml :


<toc label="Getting Started" link_to="toc.xml#gettingstarted">
<topic label="Main Topic"
href="html/gettingstarted/maintopic.html">
<topic label="Sub Topic"
href="html/gettingstarted/subtopic.html" />
</topic>
<topic label="Main Topic 2">
<topic label="Sub Topic 2"
href="html/gettingstarted/subtopic2.html" />
</topic>
</toc>
Above xml file has links to Help HTML files.

This is all it takes to create a help with eclipse. In order to test recently created help, launch new
eclipse runtime and open help window, you will see newly created help in the Eclipse help System.

GETTING STARTED WITH INTERNATIONALIZATION

In today’s world internationalization has become really important. Good news is that Eclipse has
internationalization support. This is achieved by externalizing strings to a resource bundle. In Eclipse
plug-in’s there are many files which can contain Strings (seen by end user) such as plugin.xml, Views,
Editors and more specifically all the GUI labels.

In this chapter (eclipse plugin for internationalization) we will externalize strings (seen by end
user) to a properties file called plugin.properties.

Externalizing Strings in plug-in manifest

In plug-in manifest file we need to externalize strings, such as the names of views, name of wizards
and the labels of actions.

Externalizing strings from the plug-in manifest file very simple and straight forward. The file
plugin.properties contains all the extracted strings.

Steps involved in externalizing strings are as follows:

1. create a plugin.properties file


2. provide key value pairs in resource bundle. Key are the datavalues to be used in code and value is
actual human readable string.

Step 1: Create a resource bundle

First step is to create a new properties file in plug-in project. Right click on project > select new file as
shown below. Name this file “plugin.properties”. It must be noted that the translated files for each
targeted language should be named plugin_<language>_<country>.properties, where <language>
and <country> represent the language and country.
Edit the plugin.properties file and add following line to the file:

views.propertyviewname = Property Manager View

Next, open plug-in manifest editor and replace Property Manager View name with a descriptive key
that starts with a percent (%) sign. These are the same keys that are used in the associated
plugin.properties file. The only rule is that the keys need to be unique within the plug-in.
In order to test if strings have been externalized correctly you can play around by changing Property
Manager View name and launch eclipse runtime. Note: If your changes are not reflected in the eclipse
runtime then try clean build on your project followed by launch of eclipse runtime.

Externalizing Strings in plug-in classes

Eclipse has excellent inbuilt support for externalizing Strings. These can be used in any Java Project
not necessarily plugin project. Here ill give you brief introduction on how to use this support (Please
refer to eclipse help for complete details). We will externalize strings from
com.myplugin.rmp.preferences.PropertyManagerPreferencePage class created earlier in this tutorial.

In order to externalize strings from this class, right click on Source > Externalize Strings when this
class is open in java editor.
This will open up Externalize strings wizard. You will notice that list displays all the strings from java
file.

In this wizard against each string - "Internalize" button can be used to mark the string as non-
translatable using end-of-line comment.
On the bottom of the page you can specify properties file where these strings have to be externalized.
Change it to refer to existing resource bundle file (if you already have one). Click next and you will be
displayed following message.
Click Next, Last page will show you the summary of all the changes which will take place if you click
finish. Verify your changes and press finish so that eclipse can automatically externalize strings into
resource bundle.
Once you have finished review the generated code to see how eclipse have externalized all your
strings into resource bundle.

You might also like