Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Web Development

Building an Eclipse Web-Search Plug-In


February, 2005: Building an Eclipse Web-Search Plug-In

A plug-in to search DDJ archives

Michael is a software engineer and researcher for the Department of Defense at the Naval Research Laboratory in Washington, D.C. He also founded and operates as CTO of Zizworks Inc. (http://www.zizworks.com/), a web-application and custom-software development company.


Text-editor development and command-line compiling have gone the way of the Dodo bird, as today's developers demand more sophisticated tools that provide functionality ranging from extensibility and seamless integration of components, to increased productivity and ease of use. This new generation tool, dubbed an "integrated development environment" (IDE), packages all of these features and more into a single application. In particular, the Eclipse IDE has come to the forefront of IDE technology. Eclipse (http://www.eclipse.org/) provides a stable, highly extensible, and robust plug-in architecture on which an IDE for Java is constructed.

The Eclipse IDE is really a combination of the Eclipse Platform and a number of well-crafted plug-ins. This plug-in architecture lets you add new functionality rapidly as new plug-ins are developed, as well as customization by individual users. In this article, I present an Eclipse plug-in that supports a simple online reference search of the Dr. Dobbs Journal (DDJ) web site. The complete source code and related files are available electronically; see "Resource Center," page 5. [Editor's Note: This plug-in assumes that you have a Premium Subscription to http://www.ddj.com/.]

Exploring the PDE

The Plug-in Development Environment (PDE), included with Eclipse 3.0, provides a number of views and editors that make it straightforward to build Eclipse plug-ins. In fact, the PDE is implemented as a collection of plug-ins itself that let you create all the required plug-in components without having to know a great deal about the underlying details. The PDE assists in:

  • Editing the plug-in manifest.
  • Specifying the required runtime environment.
  • Defining extension points.
  • Testing and debugging.
  • Deploying the final plug-in.

Because developing a plug-in without the PDE can be complex and time consuming, I use the PDE to create the example reference search plug-in in this article.

Generating a Template

After installing Eclipse, the first step in developing a plug-in is to generate a template plug-in project to use as a starting point. The PDE makes this process simple with its integrated wizards and editors. Select File|New|Project in the main menu to display the New Project wizard. The first page of the wizard asks you to select the type of project. Select Plug-in Development|Plug-in Project as the project type and click Next to display the New Plug-in Project wizard. Enter a project name of "DDJSearch" into the first field, leave the defaults for the rest of the fields, and then click Next. The next page is the Plug-in Content page (Figure 1), which lets you define many of the important attributes about your plug-in, such as:

  • Plug-in ID, a unique identifier for your plug-in. By convention, this is the base package of your plug-in.
  • Plug-in Version, the initial version of your plug-in.
  • Plug-in Name, the name of your plug-in as it appears in the software configuration list.
  • Plug-in Provider, the provider of the plug-in. By convention, this is the author's name or web site.
  • Runtime Library, the library that the plug-in is packaged into for deployment. By convention, this is the name of the plug-in in lowercase.
  • Plug-in Class Name, the main class name for your plug-in that is instantiated by Eclipse at startup.

Edit the values in this page to match Figure 1 and click Next to display the Template page. On this page, you can choose a template plug-in to use as your base. Select the check box to use a template and then select the Hello, World template. This basic template creates an action set extension, which provides a single menu and toolbar item. Click Finish to close the wizard and generate the new project.

Once the project is generated, you are presented with the plug-in Overview Editor (Figure 2). The form-based editor serves as the heart of the PDE for editing, testing, and deploying your plug-in. This editor gives an overview of the plug-in metadata as well as links to common actions to perform on the plug-in. Under the Testing heading in the lower right, click Launch a Runtime Workbench to launch a new Eclipse workbench with your Hello, World plug-in installed. Once the new workbench appears, click the Sample Menu|Sample Action menu item added by your plug-in. Congratulations, with a few clicks of a wizard, you just created an Eclipse plug-in that adds an action and displays a dialog box! Of course, there is no need to stop here; a plug-in can and should be much more useful. (Don't forget to close the testing workbench!)

Customizing the Plug-In

The menu item added by the sample plug-in needs to have a useful name if users are going to find it, so the first thing you want to do is change the name of the menu and action the plug-in creates. The menu and action name information is defined as an extension to the Eclipse User Interface (UI) plug-in extension point org.eclipse.ui.actionSet. Select the Extensions tab at the bottom of the editor to view the extensions currently in use (Figure 3). It is important to understand that the extension mechanism is used by Eclipse to provide a shared location in the tool, allowing plug-ins to add functionality and be discovered. Hooking into the Eclipse Platform is done by adding extensions to extension points that are defined by other plug-ins. The extension point mechanism is powerful in that it lets you extend the application indefinitely by installing new plug-ins. Defining a new extension point is beyond the scope of this article; however, your plug-in makes use of the existing extension point, org.eclipse.ui.actionSet.

You can see that a menu named "Sample Menu" is added to the extension point with a single action named "Sample Action." Select the Sample Menu (menu) item in the tree and change the label on the right to read "DDJ Search." This changes the text that will appear in the main menu bar of the application. The action, Sample Action (action), has many more properties than the menu, but the process is similar. Change the label field to read "Perform Search." You can leave the other fields with default values for now; however, before deployment, you may want to change some of these properties. Using the extensions editor, you can also add new actions or entirely new extensions by using the Add button. To see the changes applied, save the new values (Ctrl-S), flip back to the Overview tab, and launch a runtime workbench just like before.

In the extension editor, the properties of the action just defined declare the name of the actual Standard Widget Toolkit (SWT) action class that is notified when the action is invoked in the class field. The Hello, World template you started with defines this action to be an instance of the org.mpilone.ddj.actions.SampleAction class. For this example, to add the browser functionality desired, you can just edit the SampleAction class; however, in the future, it may make more sense to create a new class and change the value of the property. Open the class by double clicking on it in the left Package Explorer tree. This reveals the Java editor. At this point, the changes to be made are SWT specific and not directly related to the Eclipse plug-in framework.

When the action is activated by users, Eclipse triggers the public void run(IAction action) method, so this is where you start to insert your code. In this method, you add code to display a dialog containing the SWT browser widget, which loads a URL from the Internet using HTTP transport. The browser widget, org.eclipse.swt.browser.Browser, is a complex widget with a simple API that uses the native system HTML engine to render web sites. The widget respects the user's configuration, cookies, and cache on Windows and Linux using Internet Explorer and Mozilla, respectively. Replace the code in the method to create and display the new search dialog with the following:

public void run(IAction action) {
SearchDialog dialog =
new SearchDialog(window.getShell());
dialog.open();
}

Unfortunately, there is no standard dialog for performing a web search, so the SearchDialog class is a custom class that you need to create.

To create the SearchDialog class, right click on the org.mpilone.ddj package in the Package Explorer and select New|Class. In the New Class dialog, set the name of the class to "SearchDialog" and the parent class to org.eclipse.swt.widgets.Dialog (Figure 4). Once the SearchDialog class is created, enter Listing One to define the browser component. Most of this code is the SWT component creation and layout. However, the line:

browser.setUrl("http://www.ddj.com").

is important because it informs the browser to load the given URL and render the HTML page. This command handles all of the network communication, rendering details, and HTTP transport. At this point, the SearchDialog class is defined, letting the SampleAction compile, and completing the basic search functionality requested. To see the changes in action, save the new values (Ctrl-S), flip back to the Overview tab, and launch a runtime workbench. Remember that, because the browser widget is using the native HTML engine, the users's cookies and configuration should be available, letting them log into the destination site and use the premier features without extra code required by you.

Finishing Touches

The final features to add to the plug-in are some simple usability items. Once users start searching with the reference search plug-in, they may want basic web-navigation support such as back and forward buttons. Adding the buttons is trivial and requires only a few extra lines of SWT code. The buttons can be created and added to a toolbar on the dialog as shown here:

ToolBar navBar
= new ToolBar(shell, SWT.NONE);
navBar.setLayoutData(new GridData
(GridData.FILL_HORIZONTAL |
GridData.HORIZONTAL_ALIGN_END));
final ToolItem back =
new ToolItem(navBar, SWT.PUSH);
back.setText("Back");
back.setEnabled(false);

The first two lines create a toolbar where the rest of the buttons are attached. The last three lines create the button, set the text, and set it to be disabled. The same three lines would be repeated for any other buttons desired, such as forward and close buttons.

The next bit of code ties the button's click to a listener that performs an action on the browser:

back.addListener(SWT.Selection,
new Listener() {
public void handleEvent(Event event) {
browser.back();
}});

With the listener added, when the Back button is clicked, the browser is told to go back to the previous page. Notice that the browser maintains the history so you do not have to. Again, the code would be repeated for the Forward button.

Lastly, the button state must be updated as the browser moves from URL to URL. To do this, simply add a location listener to the browser and update the buttons in the call back:

browser.addLocationListener
(new LocationListener() {
public void changed(LocationEvent event) {
Browser browser =
(Browser)event.widget;
back.setEnabled
(browser.isBackEnabled());
forward.setEnabled
(browser.isForwardEnabled());
}
public void changing
(LocationEvent event) {
}});

The buttons now reflect the state of the history in the browser by asking the browser if it is possible to go forward or backward. Again, you do not have to handle the details of tracking the user's surfing. The final dialog source code with the aforementioned modifications can be seen in Listing Two. Launch the runtime workbench and activate the search action in the menu to display the reference search dialog with the new navigation button (Figure 6). Perform some searches, log in, or just browse the site and watch how the navigation buttons stay in perfect sync with your actions.

Packaging and Deploying

Packaging and deploying is the process of bundling up all of the required files that define your new plug-in. Once the plug-in is packaged, it can easily be distributed and installed on other Eclipse IDEs. The PDE plug-in editor provides a Build tab that allows you to customize the final packaged build for both a binary release (executable files only) and a source release (all java and build files). For most plug-ins you can use the default values. In the lower right corner of the Overview tab, there are two steps listed under the Deploying heading: editing the build configuration (which I just talked about), and exporting the plug-in for deployment. Since you are going to use the default build configuration, skip step one and click the Export Wizard option in step two to display the wizard.

The export wizard is a single page dialog (Figure 5) that lets you specify some last minute packaging options, such as:

  • Selecting the plug-ins to package.
  • Specifying the exported file type.
  • Selecting the exported file location.
  • Creating an ANT target for future deployment.

For simple distribution, it is best to create a single ZIP output file without the source, since you just want to let other users use the plug-in but not develop it. Select a logical destination for the output file and name it "ddjsearch.zip" and click the Finish button. The ZIP file is generated and it contains everything required for users to extract and install the plug-in. You can open the plug-in in a ZIP-compatible application (Window's Explorer) and browse the file hierarchy, which contains the root plug-ins directory, a directory for your plug-in, and all the metadata and class files. To install the plug-in into another Eclipse IDE, extract the ZIP archive into the root Eclipse install directory. Great job, you can now place your ZIP file on your web site and tell all your friends to try your new reference search plug-in!

DDJ



Listing One

package org.mpilone.ddj;

import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;

/** A basic dialog with a large HTML search
 * area with some simple navigation.  */
public class SearchDialog extends Dialog {
    /** Constructs the dialog as a child of the given parent shell.
     * @param parent the parent of this dialog */
    public SearchDialog(Shell parent) {
        super(parent);
        setText("DDJ Reference Search");
    }
    /** Opens the dialog and displays it on the screen. The dialog will
     * be modal and remain open until closed by the user. */
    public void open() {
        // Create the shell with a dialog trim and title text.
        Shell parent = getParent();
        final Shell shell = new Shell(parent, SWT.RESIZE | 
                SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
        shell.setText(getText());
        // Set the basic layout
        GridLayout layout = new GridLayout();
        layout.numColumns = 1;
        shell.setLayout(layout);
        // Create the browser and setup the layout information to
        // allow it to fill all available space in the dialog.
        final Browser browser = new Browser(shell, 0);
        GridData gridData = new GridData(700, 500);
        gridData.grabExcessHorizontalSpace = true;
        gridData.grabExcessVerticalSpace = true;
        gridData.horizontalAlignment = GridData.FILL;
        gridData.verticalAlignment = GridData.FILL;
        browser.setLayoutData(gridData);
        // Tell the browser to load the URL desired. It may
        // make more sense for this to be a property in a production release.
        browser.setUrl("http://www.ddj.com");
        // Pack the shell to resize everything.
        shell.pack();
        shell.open();
        Display display = parent.getDisplay();
        // Display the shell and process events
        // as long as the user hasn't closed the dialog.
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) display.sleep();
        }
    }
}
Back to article


Listing Two
    public void open() {
        // Create the shell with a dialog trim and title text.
        Shell parent = getParent();
        final Shell shell = new Shell(parent, SWT.RESIZE | 
                SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
        shell.setText(getText());
        // Set the basic layout
        GridLayout layout = new GridLayout();
        layout.numColumns = 1;
        shell.setLayout(layout);
        // Create the tool bar with the basic buttons: back, forward,
        // close. The back and forward buttons default to close since
        // they will be updated as the browser loads pages.
        ToolBar navBar = new ToolBar(shell, SWT.NONE);
        navBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL 
               | GridData.HORIZONTAL_ALIGN_END));
        final ToolItem back = new ToolItem(navBar, SWT.PUSH);
        back.setText("Back");
        back.setEnabled(false);
        final ToolItem forward = new ToolItem(navBar, SWT.PUSH);
        forward.setText("Forward");
        forward.setEnabled(false);
        final ToolItem close = new ToolItem(navBar, SWT.PUSH);
        close.setText("Close");
        // Create the browser and setup the layout information to
        // allow it to fill all available space in the dialog.
        final Browser browser = new Browser(shell, 0);
        GridData gridData = new GridData(700, 500);
        gridData.grabExcessHorizontalSpace = true;
        gridData.grabExcessVerticalSpace = true;
        gridData.horizontalAlignment = GridData.FILL;
        gridData.verticalAlignment = GridData.FILL;
        browser.setLayoutData(gridData);
        // Tell the browser to load the URL desired. It may
        // make more sense for this to be a property in a production release.
        browser.setUrl("http://www.ddj.com");
        // Add listeners to respond to the button clicks.
        back.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                browser.back();
            }
        });
        forward.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                browser.forward();
            }
        });
        close.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                shell.close();
            }
        });
        // Add a listener to update the state of the buttons
        // based on the state of the browser while the user is surfing.
        browser.addLocationListener(new LocationListener() {
            public void changed(LocationEvent event) {
                Browser browser = (Browser)event.widget;
                back.setEnabled(browser.isBackEnabled());
                forward.setEnabled(browser.isForwardEnabled());
            }
            public void changing(LocationEvent event) {
            }
        });
        // Pack the shell to resize everything.
        shell.pack();
        shell.open();
        Display display = parent.getDisplay();
        // Display the shell and process events
        // as long as the user hasn't closed the dialog.
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) display.sleep();
        }
    }
Back to article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.