Eclipse Plugin Tutorial

Abstract

In this article, I will develop the Renraku Blogger step by step. Join
me to see how developing Eclipse plugins
works.

The blogger opens on files called blog.xml,
will have a custom editor, the
articles will be shown in the outline,
and the attributes will be shown and edited using the property
sheet. A button will allow
to automatically insert the blog into a template file (local or remote)
and to upload the result to a domain via ftp. The format to be saved is
XML.

Jump Start

First, we need to create our workspace. For that, create a new, blank,
plugin project named renraku.blog. Make sure it has a Java
nature.
Create a package renraku.blog.

Then, we need to make sure we have all dependencies met. Edit the plugin.xml
file of the project. It should look like:

In the file explorer, rightclick the project and choose "Update
Classpath".
You should see a "Required plug-in entries" package in your project. If
not, look into the preferences (Plugin Development Environment ->Java Build Path ->Use classpath containers and Target
Platform -> Select All Plugins). A Project->Rebuild All
is always a good idea when something seems unstable.

Data Structure & Property Sheet

Our data structure is simple: We have one document and n
articles. A
document contains template URL, destination URL, ftp user name and ftp
password. An article is referenced by (user defined) ID and contains
title, link, author, date, section, and summary.

Since we want to display our structure in the outline, we will need a
tree structure. Create a class BlogNode
and make it be derived from DefaultMutableTreeNode (spares us
the
whole parent/children crap). A BlogNode
can be either document or article. First, make the constructor: public BlogNode(BlogNode oParent) {
if (null != oParent) {
oParent.add(this);
}
}

The node is a document when the parent is null, an article otherwise.
For the document case, we surely want to get the articles.

Now to more interesting parts. We need to make it suitable for the
property sheet, so we need to implement IPropertySource. That
has the
additional advantage that we can access the data the same way the
property sheet does. First, we need to be aware of our properties:

Ignore the rest of the methods; they are not interesting except one:
The delivery of the property descriptors. Since we dont have any
special requirements for the property sheets table cells, we just take
the standard text descriptor.

With this, we have a data structure that holds all our needs and is
prepared for the property sheet.

The XML Factory

I was pondering on whether to use XOM or other XML tools,
but our tool is so simple I would rather go for a quick hack to keep
the example easy. Make a class BlogFactory. The XML file to
be read typically looks like this:

I also wrote an analoguous save method, which traverses the document
tree and puts it all into a single string which is the XML file's
content. I assume you know how to do this, so I omit it here. Now on to
one interesting bit, the editor.

The Custom Editor

We want to create an editor with multiple pages: One for the articles,
one for the rest of the data. For that, create a class BlogEditor,
which descends
from MultiPageEditorPart. Like all new views, it must be
announced to Eclipse via the plugin.xml file:

Now back to the BlogEditor class. Leave the generated
methods alone
at first. First, we need to fulfill an impicit ViewPart
(which is superclass to MultiPageEditorPart) contract: To
implement the init() method in which we load the file.

We loaded the tree structure by using BlogFactory.loadTree();
the saving process is using BlogFactory.saveTree()
to write the tree as XML. Since in Eclipse files can only be saved when
they are "dirty", make a tDirty flag attribute; the pages' isDirty()
methods will return it, and we provide a setDirty() method to
facilitate notification of dirtyness.

And now, the save method: We get the string containing the whole XML
file, put it into a ByteArrayInputStream that the IFile.setContents()
method can suck out, and send a not-dirty-anymore notification.

Then, we need to create the GUI, which involves a list for the
articles, some input fields for the article's details, and an "Add
Article" button which also changes to "Mod Article" when an article has
been selected from the list.

The GUI is creating by filling the method createPartControl()
with content. We will look only at snippets here.

Where loadGUI() sets the widgets' values from the model. The
listener oSelectEar is a SelectionListener which
handles both the selection of an article (or the "New Article"
placeholder) in the article list and the "Add Article" button.

Then we have the "Add Article" button. It fulfills three operations:
When the "New Article" is selected, it adds an article; if an existing
article is selected, it modifies the article; and if the ID field is
empty, it deletes the article.

This time, we want to save a text fields content as soon as it loses
focus, and we do so with a FocusListener on each of the
textfields. The listener method is focusLost(), the other is
only a helper method.

During the upload, we disable the "Upload" button; afterwards, we show
a dialog with some result info. While BlogFactory.upload()
may be an interesting method, it
has nothing to do with Eclipse handling, so we omit it here.

The Outline

We now have a fully functional blogger, but without outline and
property sheet. We will now have a look at how to implement the outline
utilizing the standard Eclipse outline view. We tell BlogNode
to implement the interface IAdaptable, which means we must
supply an adapter if asked:

Obviously, we do not have a workbench adapter
yet. Create an attribute oWorkbenchAdapter to be of class IWorkbenchAdapter,
and then make sure it is initalized in the constructor with the
following inner class:

The children and parent are returned from the node, we discard the
images, and concentrate on the label that we want to appear
in the outline view. For articles, we take its ID, for the document
(somewhat random) the ftp user.

The next step is to specify the outline page that we want to
display. For this, we enter BlogEditor and override its getAdapter()
method. Again, we will only supply an adapter when asked for the
content outline page, and only if the input is the blog file.

Thats about it! On the next start of the plugin, we should have the
outline filled with the articles.

The Property Editor

Nothing to do. That's right, you heard me. We let BlogNode
implement IPropertySource, and the standard WorkbenchPart.getAdapter()
method that is in the superclass of our BlogEditor delivers
the appropriate workbench adapter. So, when we click an article in the
outline, we automagically have it in the property sheet (if not: Window
-> Show View -> Other -> Basic -> Properties).

Conclusion

We have seen how to build a tree model in a way that it can be used for
the property sheet, how to implement the interfaces and adapters to use
an outline page, and how to build a custom editor with multiple pages.

What we did not handle is synchronization between property sheet and
editor, tolerant XML handling in the BlogFactory, a "New
Blog" Wizard, XML source page and HTML preview page in the BlogEditor,
and I am sure when I think hard enough I can imagine a lot of other
goodies.