Normally, exported packages are visible to all “downstream” plug-ins. Nevertheless, you can declare packages to be internal, meaning they’re not necessarily intended for use by downstream plug-ins, but are still visible. Such internal packages can be hidden when Eclipse is started in “strict” mode by selecting the hidden option under package visibility. Internal packages can also have “friend” plug-ins that have access to the package even in strict mode.
The Classpath section lists all locations the runtime will search when loading classes from a plug-in. This is an artifact of earlier Eclipse releases and should normally be left blank. Starting with Eclipse 3.1, plug-ins are packaged as Java archives (.jar) and don’t require an extended classpath.
Click the Extensions tab or click Extensions in the Extension/Extension Point Content section of the Overview tab. This is where the real functionality of our plug-in is defined. Clicking Add… brings up a list of extension points defined in the plug-ins listed in the Dependencies tab. Here we select the extension points for which our plug-in will provide extensions. Find and select org.eclipse.ui.views
. A description of the extension point appears (Figure 7.5). Many extension points also offer one or more templates to provide additional help in structuring the plug-in’s Java code. In this case, we won’t use the template. Click Finish.
Figure 7.5: Selecting extension points.
Back in the Extensions list, right-click on the new entry and select New→category (Figure 7.6). Leave the id as is, and change the name to EclipseBook.
Figure 7.6: Adding a category.
Right-click the extension point entry again and select New→view (Figure 7.7). Change the name to SuperView and add com.eclipsebook.superview.category1
to the category to match the id in the category entry. Click the class link, enter SuperView as the name, and click Finish.
Figure 7.7: Adding a view.
The PDE creates a new class implementing the required interface and opens it in the Java editor. We’ll come back to that in a moment, but for now let’s finish up our tour of the Manifest Editor.
The final product of the Manifest Editor is the two files that constitute the plug-in’s manifest, MANIFEST.MF
and plugin.xml
. The content of these files is available in tabs of the same names. Have a look. MANIFEST.MF
basically describes the plug-in with the information from the Overview and Dependencies forms. plugin.xml
defines the extensions and extension points that this plug-in provides. In this case, we haven’t defined any extension points.
You can, of course, edit MANIFEST.MF
and plugin.xml
manually, but why? The beauty of PDE is that you don’t need to understand XML or the syntax of MANIFEST.MF
, in order to create a plug-in. Some developers even suggest that it is bad practice to manually edit an XML file as this can lead to hard-to-diagnose configuration problems.
Now go back to the Editor tab displaying SuperView.java
. Not much here. Just templates for the class constructor and two other functions that are the minimum necessary to extend the view. To get something that works, import the file SuperView.java
from EclipseSamples/plug-in/
to com.eclipsebook.superview
in the Package Explorer. Eclipse asks if you want to overwrite the existing file. Yes, you do.
7.3.3 Running and Debugging a Plug-In
Eclipse and PDE have a notion of self-hosting, which means that we can launch a new instance of Eclipse with plug-ins we’re currently working on, without having to export or deploy any plug-ins. One way to start the new instance is to go back to the Overview form in the Manifest Editor and click on Launch an Eclipse application under Testing. You can also just click on the Run icon in the menu toolbar or, from the top-level project context menu in the Package Explorer view, select Run As→Eclipse Application.
After a little churning, a new instance of Eclipse appears in the default C/C++ perspective. Interestingly, it doesn’t ask for a workspace location. Instead, it creates a workspace in your home directory, called runtime-EclipseApplication.
In the main menu select Window→Show View→Other. Expand the EclipseBook entry and select SuperView. The new view shows up in the bottom window.
Now that you know what the plug-in does, go back into the Java code and try to figure out how it does it.
Debugging is virtually identical to what we did with CDT. The one “gotcha” here is that there’s no “Stop on main.” This means you must have a breakpoint set before you launch the debug run. Open SuperView.java
if it’s not already open. Now switch to the Debug perspective. This is essentially the same Debug perspective we used for C programming, but now we’re using a Java debugger instead of gdb.
Scroll down to line 24 in SuperView.java
that starts with viewer.setContentProvider…
and set a breakpoint just as we did before. Now from the Manifest Editor Overview form, click Launch an Eclipse application in Debug mode. The new Eclipse instance starts as before. Select the SuperView view as we did above and the program hits the breakpoint (Figure 7.8).
Figure 7.8: Java Debug perspective.
The Debug view shows the call stack with the method containing the breakpoint highlighted. If you select any other frame in the call stack, a window appears in the editor saying that the source is not available. Nevertheless, the local variables for that frame are displayed in the Variables view and the Outline view shows an outline of the corresponding method.
Note, incidentally, that the debug instance of Eclipse is blank and waiting for something to happen. You can step through the createPartControl()
method to see what happens, but in fact nothing actually changes on the workbench until after setFocus()
is called.
Without going into a lot of detail, let’s take a quick look at what createPartControl()
does. First it creates a table-like visual component, a “table viewer,” to display your view’s contents. It then configures the viewer with a content provider and a label provider. The former allows the viewer to navigate your model, or more specifically, to extract your model’s structural elements suitable for inclusion in a table. The latter allows it to convert your model’s elements into table cells with textual labels and optional images.
Then there’s a sorter to display the entries in alphabetical order. Finally, you provide an input source that is an array of descriptors of all views available in the workbench at run-time. Note that we’re providing an implementation of setLabelProvider()
here, and we’re overriding the getText()
and getImage()
methods.