01 Oct 2010 - Corrected two broken links Resources.
If you have been following this project since the beginning, you know that I am enthusiastic about Eclipse. As Emacs fans will tell you, a good development environment has to be extensible and configurable. Eclipse delivers on both counts, but unlike its prestigious ancestor Emacs, Eclipse also offers a modern user interface.
One of the best things about Eclipse is that it fixes what I consider to be one of the most frustrating deficiencies in Java technology: The user interface library. As I have already reported, Eclipse uses the Standard Widget Toolkit (SWT), which combines the best features of the Abstract Windowing Toolkit (AWT), the use of native controls, and Swing's rich set of widgets. At last, it's possible to design sophisticated user interfaces that behave like their native counterparts.
Most of the criticism of SWT has centered on portability. Since SWT is not part of the JDK (Java Development Kit), it may not be available on some platforms. Fortunately, the Eclipse team seems committed to porting SWT to as many platforms as necessary, so in practice it should not be a problem.
I was curious to test the portability of SWT, so when it became available I downloaded the Macintosh build. Although it is still under development, the Mac port is reasonably stable. I was most impressed, though, with SWT and its ability to paint native Aqua controls.
It's fun to use new projects and report on them, but there's a downside as well: Documentation for a new project is often deficient. Eclipse is no exception. Writing this article -- or rather coding for it -- required a lot of research. The documentation is limited to a few articles on the principles, documentation of the API, and, fortunately, the source code.
The development session was mostly trial and error -- working on code until it did something sensible. Unfortunately, I frequently thought I understood something and moved on to a new task only to find that I was wrong! Eventually, I reached a point where I was confident in my understanding. None of the isolated issues I faced was crucial, but the combination of problems was challenging. As more articles are written, the (lack of) documentation issue should eventually fade away.
At the end of the previous column, "Integrating XM and Eclipse," I had achieved a crude integration of XM with Eclipse. I added an entry to the contextual menu, which the user could select to run XM. I knew it was only a first step, but as I (and others at Pineapplesoft) started using it, I realized I needed to do much better. Specifically, I complained that:
- Starting a new project is difficult. I had to run the New Project wizard, then manually create several files. The wizard should take care of everything.
- The
.xmpfile was confusing. In most cases it's empty, since it is only required as a click target. Originally XM needed no configuration files, which was part of its attraction. - Right-clicking is a Windows/KDE/Gnome gesture. On the Mac, right-clicking is best left for complex, infrequent operations. I had to come up with a more portable interface. It is possible to register builders (essentially compilers) with Eclipse. Eclipse automatically invokes the appropriate builders when the project changes.
With these shortcomings in mind, I decided that for the immediate future, the XM plug-in should include a New Project wizard and the ability to invoke XM during a project build. These two features are implemented through extension points. (Turn to the "Use Eclipse to build a user interface for XM" article in Resources for more details on extension points.) The extension point for a new wizard is org.eclipse.ui.newWizards and it uses the interface org.eclipse.ui.INewPlugin. The extension point for a builder is org.eclipse.core.resources.builders and it uses the interface org.eclipse.core.resources.IncrementalProjectBuilder.
The new project wizard and the builder are related. For example, Eclipse will automatically invoke the builder when creating a new project. If you download the code from the online repository, you will see that both have been implemented. This article covers the wizard, while next month's article will cover the builder.
Let's start with some definitions. For Eclipse, a project is a set of files (source files, configuration files, compiled files, and more) in a project directory. In Eclipse jargon, files and directories are called resources. Do not confuse Eclipse resources (files) with Java resources (strings used for localization).
The list of projects available to the user constitutes the workspace. By default the projects are stored under the eclipse/workspace directory, but the user can create projects anywhere.
The user interacts with the projects through the navigator panel, as shown in Figure 1. Again, plug-ins can contribute specialized navigators. Figure 1 is the generic navigator that lists the resources (files) in the projects.
Figure 1. The Eclipse navigator

To create a new project, you need a new directory and several configuration files that Eclipse manages. Note that it's not enough to create a new directory in the workspace -- Eclipse would not recognize it as a project.
The main configuration file for a project is called .project (the dot marks a hidden file on UNIX file systems). It contains information on how to build the project as well as the project nature.
The nature is an identifier for the project type. For example, the Java project has the Java nature. Eclipse uses the project nature to control the interaction with the user. The nature may enable or disable menu items, so a project with the Java nature has Java-specific items in the menu.
A project can have more than one nature. For example, a plug-in project is both a Java project (after all, plug-ins are written in the Java language) and a plug-in project. In practice, it gets menu entries for both.
Like other Eclipse identifiers, nature identifiers start with a domain name in reverse order, not unlike package names. For example, the Java nature identifier is org.eclipse.jdt.core.javanature. Be careful not to confuse this identifier with a class/package name. Turn to "Use Eclipse to build a user interface for XM" in the Resources section for more details on identifiers.
Having learned this, I realized that the project nature makes the dummy .xmp file (introduced in the previous column) redundant. If I define a special nature for XM projects, it is possible to associate the Run XM menu item introduced in Integrating XM and Eclipse with those projects.
I defined org.ananas.xm.eclipse.xmnature as the project nature for XM. Listing 1 illustrates how I modified the manifest (plugin.xml) to reflect this.
Listing 1. New extension point
<extension point="org.eclipse.ui.popupMenus">
<objectContribution adaptable="true"
objectClass="org.eclipse.core.resources.IResource"
id="org.ananas.xm.eclipse.popupMenu">
<filter name="projectNature"
value="org.ananas.xm.eclipse.xmnature">
</filter>
<action label="Run XM"
tooltip="Call XM to publish the site."
class="org.ananas.xm.eclipse.XMRunner"
menubarPath="additions"
enablesFor="+"
id="org.ananas.xm.eclipse.popMenu.action">
</action>
</objectContribution>
</extension>
|
If you compare Listing 1 with the code published previously, you will see the following changes:
- The
filtertag replaces thenameFilterattribute.filtermatches on project nature,nameFiltermatched on filenames. - The
enablesForattribute was changed to+, which means that several files in the project can be selected. This is just a convenience for the user. - The
XMRunnerclass is mostly unchanged. I have shortened the package name, though, to save some typing.
Obviously the manifest in Listing 1 only works if the project has been declared as the XM nature. The generic wizard creates projects that have no nature. So to test the code in Listing 1, I first need to provide an XM project wizard.
Eclipse is incredibly extensible and this is reflected in how it treats wizards. With Eclipse, several plug-ins can contribute to a wizard. The project wizard takes advantage of this feature.
When the user selects New Project in the menu, the wizard shown in Figure 2 displays. The user selects the type of project to create. Although XM appears in the list, the XM plug-in has not yet been loaded. The list is populated from the manifest (plugin.xml).
Figure 2. New project wizard

However on the next screen, shown in Figure 3, the plug-in has been loaded and given control of the screen. The transition is very smooth for the user: The wizard does not flicker or change in any way. In fact, unless the user has written a plug-in, he may never realize that a new plug-in has been loaded.
Figure 3. The plug-in has been loaded

To achieve this transparent integration, Eclipse breaks a wizard into three sets of objects:
- The container is the dialog box with the buttons.
- The wizards respond to user actions. A container interacts with one or more wizards to respond to user actions.
- The pages draw the controls within the container. Each time the user presses the Next button, a new page is loaded. In Figure 3, the page manages the fields for the project name and directory.
XM implements the wizard in the NewXMProjectWizard class. The class implements the INewWizard interface. In practice, the easiest solution is to derive from Wizard since this class is a default implementation for most methods defined by INewWizard.
NewXMProjectWizard was registered as an extension point in the manifest, as always. Listing 2 is the relevant excerpt from the manifest. Notice that it declares a category for the wizard. This category would group several XM wizards.
Listing 2. Wizard extension point
<extension point="org.eclipse.ui.newWizards">
<category name="ananas.org"
id="org.ananas.xm.eclipse.newWizards">
</category>
<wizard name="XM Project"
icon="icons/newproject16.gif"
category="org.ananas.xm.eclipse.newWizards"
class="org.ananas.xm.eclipse.NewXMProjectWizard"
project="true"
id="org.ananas.xm.eclipse.newproject">
<description>Create an XM project.</description>
</wizard>
</extension>
|
The wizard tag is new to wizards, but it is very similar to the view introduced in the previous column, so it should be familiar. The only novelty is the project attribute: When set to true, it adds the wizard to the new project list. Without this attribute, the wizard is listed in the "Other" category.
After loading the plug-in, the container calls init(). NewXMProjectWizard needs little initialization. First it calls setNeedsProgressMonitor() to request a progress bar. While creating the project, it increments the bar, as shown in Listing 3.
Listing 3. The init() method
public void init(IWorkbench workbench,
IStructuredSelection selection)
{
setNeedsProgressMonitor(true);
}
|
Next, the container calls addPages() as shown in Listing 4. The method registers the wizard pages. NewXMProjectWizard needs only one page that prompts for the project name and location. Eclipse conveniently provides such a page in class WizardNewProjectCreationPage (you can see this page in Figure 2).
Listing 4. The addPages() method
public void addPages()
{
super.addPages();
namePage = new WizardNewProjectCreationPage("NewXMProjectWizard");
namePage.setTitle(Resources.getString("eclipse.newprojectname"));
namePage.setDescription(Resources.getString("eclipse.newprojectdescription"));
namePage.setImageDescriptor(ImageDescriptor.createFromFile(getClass(),
"/org/ananas/xm/eclipse/resources/newproject58.gif"));
addPage(namePage);
}
|
The wizard calls addPage() for every page it registers. In this case, that's one page only.
The performFinish() method executes when the user clicks Finish. Listing 5 is the method content. Not much happens in this method. The bulk of the project creation is in createProject(), which performFinish() calls indirectly.
Listing 5. The performFinish() method
public boolean performFinish()
{
try
{
WorkspaceModifyOperation op =
new WorkspaceModifyOperation()
{
protected void execute(IProgressMonitor monitor)
{
createProject(monitor != null ?
monitor : new NullProgressMonitor());
}
});
getContainer().run(false,true,op);
}
catch(InvocationTargetException x)
{
reportError(x);
return false;
}
catch(InterruptedException x)
{
reportError(x);
return false;
}
return true;
}
|
Creating a project modifies the workspace, since it adds directories and files. The wizard synchronizes itself with the workspace throughout the modification. The easiest solution is to execute the project creation in a descendant of WorkspaceModifyOperation.
The code that modifies the workspace must be called from the execute() method. In Listing 5, it simply calls createProject(). execute() takes an IProgressMonitor as an argument. If the project creation takes time, the wizard reports on its progress through this argument. The container uses it to update a progress bar.
The most useful methods on IProgressMonitor are:
-
beginTask(), which should be called before the operation starts. It takes a description and the duration of the operation. -
worked()reports on the progress. It typically updates a progress bar. -
done()must be called when the project is created. -
subTask()lets you change the description.
The length of the project creation and the progress is reported in units of work. It's up to you to define what a unit represents. For example, when processing files, each unit could be a file.
To execute the thread, call the run() method on the container. The container synchronizes its progress bar with the IProgressMonitor.
The actual project creation takes place in createProject() (see Listing 6). The order is very important in this method: The wizard will fail (often with confusing error messages) if your code does not follow the proper order.
To create a new project, follow these steps:
- Retrieve the workspace root as an instance of
IWorkspaceRoot. Eclipse provides a convenient plug-in (ResourcesPlugin) through which you can access resources, including the workspace. Again, these are Eclipse resources such as files and directories. - Call
getProject()onIWorkspaceRoot. (Personally, I think the method should have been callednewProject()because it creates the project.) - Create an empty project description with the
newProjectDescription()method. The project description holds certain types of information about the project, including where it is located on the file system. - If the user chooses the default location (under the workspace directory), move to the next step. Otherwise, set the location on the description object. For some reason, project creation fails if you explicitly set the project location to its default.
- Register the project natures, if any. This is an array of string identifiers.
- Register the project builders (or compilers). Although I cover it in the next article, XM is now available as a builder.
- Create the project with the
create()method. - Finally, open the newly created project.
Once you've created and opened the project, you can set its properties. These are stored with Eclipse properties. As you saw in Listing 6, the wizard sets a few properties for the XM builder. You should be familiar with those as they are identical to the .xmp file introduced in "Integrating XM and Eclipse."
Last but not least, the wizard populates the project with default directories (the usual src, rules, and publish), a sample XML document, and a simple style sheet. This is just a convenience for the user.
If you download the source code from the online repository (see Resources), you will find that the plug-in also offers a builder. The builder itself is the topic of my next column.
This article demonstrates that Eclipse gives you, the plug-in developer, enormous freedom to control the user experience. As a result, your plug-in can extend almost any aspect of the user interface.
Learn
- Check out WebSphere Studio Site Developer, a commercial offering built on the open Eclipse framework. (WebSphere Studio Site Developer replaces WebSphere Studio.)
- Check out "Integrating XM and Eclipse" (developerWorks, November 2002) and "Use Eclipse to build a user interface for XM" (developerWorks, October 2002), previous installments of this column. Check out a complete listing of Working XML column installments.
- Read "Developing Eclipse plug-ins" for information on creating, debugging, and installing your plug-ins (developerWorks, December 2002).
- Find more XML resources on the developerWorks XML technology zone.
- IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
Get products and technologies
- Download the plug-in from the
online repository.
- Eclipse is an open-source effort to develop an IDE framework. It was initiated by IBM.
- Try WebSphere Portal, a great solution when publishing more sophisticated portals.
Discuss

Benoît Marchal is a consultant and writer based in Namur, Belgium. He is the author of XML by Example and other XML books covering the latest features of the XML standard, including the final XML Schema recommendation and the latest developments of XSL. More details are available at www.marchal.com. You can contact Benoît at bmarchal@pineapplesoft.com.




