Generic Workbench Overview

Last modified 17:00 EST December 15, 2003

N.B. Both the generic workbench itself and this document are very much works-in-progress.

What is a generic workbench?

The "generic workbench" is the core of the Eclipse Platform UI stripped of its former IDE-specific personality, predilections, and biases. The high-level picture of the Eclipse workbench is painted in the Eclipse Technical Overview. With minor modifications, it can paint a good high-level picture of what we're calling the generic workbench (new or modified passages are underlined):

Unlike SWT and JFace, which are both general purpose UI toolkits, the workbench provides overall UI organization and supplies the structures in which an application interact with the user. The workbench API is dependent on the SWT API, and to a lesser extent on the JFace API. The workbench implementation is built using both SWT and JFace; Java AWT and Swing are not used.

The Eclipse Platform UI paradigm is based on editors, views, and perspectives. From the user's standpoint, a workbench window consists visually of views and editors. Perspectives manifest themselves in the selection and arrangements of editors and views visible on the screen.

Editors allow the user to open, edit, and save objects. They follow an open-save-close lifecycle much like file system based tools, but are more tightly integrated into the workbench. When active, an editor can contribute actions to the workbench menus and tool bar. The generic workbench has no built-in editors. There is an separate plug-in containing the standard text editor and text editor framework. This plug-in is an optional component that can be used with the generic workbench in applications.

Views provide information about some object that the user is working with in the workbench. A view may assist an editor by providing information about the document being edited. For example, the standard content outline view shows a structured outline for the content of the active editor if one is available. A view may augment other views by providing information about the currently selected object. For example, the standard properties view presents the properties of the object selected in another view. Views have a simpler lifecycle than editors: modifications made in a view (such as changing a property value) are generally saved immediately, and the changes are reflected immediately in other related parts of the UI. The generic workbench has no built-in views. There is a separate plug-in containing the properties view and the content outline view. This plug-ins is an optional component that can be used with the generic workbench in applications.

A workbench window can have several separate perspectives, only one of which is visible at any given moment. Each perspective has its own views and editors that are arranged (tiled, stacked, or detached) for presentation on the screen (some may be hidden at any given moment). Several different types of views and editors can be open at the same time within a perspective. A perspective controls initial view visibility, layout, and action visibility. The user can quickly switch perspective to work on a different task, and can easily rearrange and customize a perspective to better suit a particular task. The generic workbench has no built-in perspectives. The application must supply at least a default perspective.

Tools integrate into this editors-views-perspectives UI paradigm in well-defined ways. The main extension points allow tools to augment the workbench:

The properties view, the content outline view, the standard text editor, and the default perspective are all contributed using these mechanisms.

Tools may also augment existing editors, views, and perspectives:

The Platform takes care of all aspects of workbench window and perspective management. Editors and views are automatically instantiated as needed, and disposed of when no longer needed. The display labels and icons for actions contributed by a tool are listed in the plug-in manifest so that the workbench can create menus and tool bars without activating the contributing plug-ins. The workbench does not activate the plug-in until the user attempts to use functionality that the plug-in provides.

Once an editor or view becomes an active part of a perspective it can use workbench services for tracking activation and selection. The part service tracks view and editor activation within the perspective, reporting activation and deactivation events to registered listeners. A view or editor can also register with the selection service as a source for selections. The selection service feeds selection change events to all parties that have registered interest. This is how, for example, the standard properties view is notified of the domain object selected in the currently active editor or view.

How does the application create a generic workbench?

In the Eclipse world, the "main program" for an application is an IPlatformRunnable contributed to the org.eclipse.core.runtime.application extension point. The IPlatformRunnable's run(Object args) method gets control once the Eclipse Platform Runtime has brought itself into existence. The plug-in that contributes this class is the first real plug-in to be activated. The application is responsible for opening the workbench using PlatformUI.createAndRunWorkbench. (PlatformUI is in the org.eclipse.ui API package in the org.eclipse.ui plug-in.) This method creates the workbench, opens the initial workbench window, and then processes UI events until the user calls it quits. The application is also responsible for creating an SWT display, using PlatformUI.createDisplay, and passing it to PlatformUI.createAndRunWorkbench.

public class MyApplication implements IPlatformRunnable {
  public Object run(Object args) {
    WorkbenchAdvisor workbenchAdvisor = new MyWorkbenchAdvisor();
    Display display = PlatformUI.createDisplay();
    int returnCode = PlatformUI.createAndRunWorkbench(display, workbenchAdvisor);
    if (returnCode == PlatformUI.RETURN_RESTART) {
      return IPlatformRunnable.EXIT_RESTART;
    } else {
      return IPlatformRunnable.EXIT_OK;
    }
  }
}

How does the application configure and control the generic workbench?

The application is responsible for more that just bringing up the workbench. The application is also responsible for configuring the workbench and its windows. Without some configuration, the workbench window is useless because its menu bar and tool bar are completely empty. The application must supply a workbench advisor object when it creates the workbench. The various methods on the workbench advisor are called at well-defined points in the life cycle of the workbench, and it is by implementing these methods that the application has the opportunity to configure the workbench. (It's called a workbench "advisor" because this object influences how the workbench works. The application does not "implement" the workbench; the implementation of the workbench is still internal, meaning most of the mechanism is still hidden.) The API for workspace advisor and other things that an application needs to configure the workbench are located in the org.eclipse.ui.application package (in the org.eclipse.ui plug-in). The API in this package is not of interest (or use) to other plug-ins.

What aspects of the workbench must the application configure?

The application is involved in key global decisions:

Does an application have to provide a default perspective for its windows?

Opening a workbench window (IWorkbench.openWorkbenchWindow) requires there to be a perspective. You either specify one explicitly, or allow the workbench to use the default one. This means that an application must contribute at least one perspective via the org.eclipse.ui.perspectives extension point, and must name one of them as the workbench's default perspective. The default perspective is controlled by a workbench preference. The application must establish a meaningful value for this preference before opening the first window (the preference does not have a useful default value).

Who's responsible for the menu bar for a workbench window?

A workbench window's menu bar consists of a row of individual menus. The application is responsible for defining the foundation items in the menu bar of a workbench window, and the foundation items and groups within each menu. Initially, the menu bar of a newly created workbench window is completely empty. Once the application has established the foundation, the workbench's action set mechanism allows addition menus and menu items to be added (but not removed or replaced). Action set contributions are handled automatically by the generic workbench, without further assistance from the application's workbench advisor. Action set contributions reference menu locations using a path composed from menu item ids. A typical application would provide as API the ids and paths of the places where plug-ins are allowed to make action contributions, and omit (or keep secret) ids for menu items that it does not want plug-ins contributing to. The application is also free to add or remove foundation items at any time.

How does the application configure the menus for a workbench window?

Here is an example of how an application uses its workbench advisor to configure the menu bar of an new workbench window. This should be done in the WorkbenchAdvisor.fillActionBars method. Building the individual menus and sub-menus is done using standard JFace API (in the org.eclipse.jface.action package). The top-level menus are then added to the workbench window's menu bar, which the workbench advisor can obtain via IActionBarConfigurer.getMenuManager. Here's a simple example of what this code looks like (momentarily ignoring the vexing issue of proxy configurers):

public void fillActionBars(IWorkbenchWindow window, IActionBarConfigurer configurer, int flags) {
    if ((flags & WorkbenchAdvisor.FILL_MENU_BAR) != 0
        && (flags & WorkbenchAdvisor.FILL_PROXY) == 0) {
       IMenuManager mm = configurer.getMenuManager();
       // build a File menu with 1 empty group and 3 commands
       IMenuManager fileMenu = new MenuManager("&File", "file");
       fileMenu.add(new GroupMarker("file.start"));
       fileMenu.add(new MyAction("hello"));
       IAction quit = ActionFactory.QUIT.create(configurer.getWindow());
       configurer.registerGlobalAction(quit);
       fileMenu.add(quit);
       // add File menu to workbench window menu bar
       mm.add(fileMenu);
    }
    ...
}

Workbench retarget actions (like CUT, COPY, PASTE) must be registered as global actions in order to work property. Also, actions must be registered as global actions in order to work property with key bindings.

While the above simple code works for this, it has a serious flaw for applications that make use of the Customize Perspective action (not used here). The Customize Perspective action creates a proxy action configurer and passes it to fillActionBars method with  the FILL_PROXY flag set. The body of fillActionBars uses ActionFactory to create new action instances. The issue is that each of these actions may registers listeners with the window, and these listeners will not go away until the window is closed. This means the performance of the workbench will degrade to the extent that the user uses Customize Perspective to change a window. Applications that make use of the Customize Perspective action can avoid this problem by using the same action objects in the proxies as in the real action bars (requires remembering and reusing the action instances on a per window basis).

Note: The workbench story for action contributions to menus and tool bars is likely to change for 3.0. When it does, this story will be revised to bring it into line.

What happens when the user closes the workbench window using the window's close button?

The workbench is responsible for the standard window operations, including resizing, maximizing and minimizing, and closing. The workbench immediately tells the window to close (IWorkbenchWindow.close) when the window's close button is pushed.

Who's responsible for the tool bar for a workbench window?

The story is basically the same as for the menu bar; the only real differences are in the mechanics.

The application is responsible for defining the foundation items in the tool bar of a workbench window, and the foundation items and groups within each tool bar. Initially, the tool bar of a newly created workbench window is completely empty. Once the application has established the foundation, the workbench's action set mechanism allows addition tool bars and tool bar items to be added (but not removed or replaced). Action set contributions are handled automatically by the generic workbench, without further assistance from the application's workbench advisor. Action set contributions reference tool bar locations using a path composed from tool item ids. A typical application would provide as API the ids and paths of the places where plug-ins are allowed to make action contributions, and omit (or keep secret) ids for tool items that it does not want plug-ins contributing to. The application is also free to add or remove foundation items at any time.

How does the application configure the tool bar for a workbench window?

Here is an example of how an application uses its workbench advisor to configure the tool bar of a new workbench window. This should be done in the WorkbenchAdvisor.fillActionBars method. Building the individual tool bars is done using standard JFace API (in the org.eclipse.jface.action package). A workbench window's tool bar is actually a JFace cool bar. A cool bar contains cool items which in turn contain tool bars. Individual cool items can be added to the workbench through the workbench advisor via IActionBarConfigurer.getCoolBarManager. Here's a simple example of what this code looks like:

public void fillActionBars(IWorkbenchWindow window, IActionBarConfigurer configurer, int flags) {
    ...
    if ((flags & WorkbenchAdvisor.FILL_TOOL_BAR) != 0
        && (flags & WorkbenchAdvisor.FILL_PROXY) == 0) {
       ICoolBarManager coolBarManager = configurer.getCoolBarManager();
       IToolbarManager mainTool = new ToolBarManager();
       mainTool.add(new MyAction("hello"));
       IAction quit = ActionFactory.QUIT.create(configurer.getWindow());
       configurer.registerGlobalAction(quit);
       mainTool.add(quit);
       ToolBarContributionItem tbItem = new ToolBarContributionItem(mainTool,"main");
       coolBarManager.add(tbItem);
    }
}

The cool bar manager, like all other contribution managers, can contain any type of contribution item. In most cases, it makes sense that the contribution items of a cool bar manager be tool bar managers. Since contribution managers only accept contribution items, each tool bar manager is wrapped in a ToolBarContributionItem. Every tool bar contribution item corresponds to a cool item (the movable widget in a cool bar) on the cool bar. To add a new action to the cool item, a standard JFace tool bar manager must be created. After populating the tool bar manager with actions, a tool bar contribution item is created from the tool bar manager and subsequently added to the cool bar manager.

Workbench retarget actions (like CUT, COPY, PASTE) must be registered as global actions in order to work property. Also, actions must be registered as global actions in order to work property with key bindings.

While the above simple code works for this, it has a serious flaw for applications that make use of the Customize Perspective action (not used here). The Customize Perspective action creates a proxy action configurer and passes it to fillActionBars method with  the FILL_PROXY flag set. The body of fillActionBars uses ActionFactory to create new action instances. The issue is that each of these actions may registers listeners with the window, and these listeners will not go away until the window is closed. This means the performance of the workbench will degrade to the extent that the user uses Customize Perspective to change a window. Applications that make use of the Customize Perspective action can avoid this problem by using the same action objects in the proxies as in the real action bars (requires remembering and reusing the action instances on a per window basis).

Note: The workbench story for action contributions to menus and tool bars is likely to change for 3.0. When it does, this story will be revised to bring it into line.

How does an application declare workbench images?

IWorkbench.getSharedImages() provides regular plug-ins access to a pool of images and image descriptors maintained by the workbench. The generic workbench has some built-in ones (their names are given by constants in the ISharedImages interface). The application can add to the set of workbench images by IWorkbenchConfigurer.declareImage. The application is responsible for documenting any additional images it makes available through this mechanism if it expect their names to be known to other plug-ins.

public void initialize(IWorkbenchConfigurer configurer) {
    ...
    // declare public "shared" image
    ImageDescriptor yoyoLogo = new URLImageDescriptor(new java.net.URL("..."));
    configurer.declareImage("yoyodyne", yoyoLogo, true);
    // declare public "non-shared" image
    ImageDescriptor yoyoWizardBanner = new URLImageDescriptor(new java.net.URL("..."));
    configurer.declareImage("com.yoyodyne.internal.wizardBanner", yoyoWizardBanner, false);
    ...
}

Does the generic workbench support editors?

The generic workbench contains the extension point and API for plug-ins to contribute arbitrary editors. The generic workbench does not include any particular editors.

For applications that do not need editors, the overhead of the mechanism built in to the generic workbench is minimal. Even though all workbench pages have a special editor area, the editor area does not need to be visible. The visible views will make use of the screen real estate, so there is no waste when editors are not used in an application.

Does the generic workbench support text editors?

The generic workbench has no built-in support for text editors. However, the text editor framework is available as a separate optional component (the org.eclipse.ui.workbench.texteditor plug-in, along with the two plug-ins it depends on: org.eclipse.text and org.eclipse.jface.text).

Does the generic workbench support OLE-based editors?

The generic workbench has no built-in support for OLE-based editors. The support for embedding any OLE document as an editor (Windows only) is available as a separate optional component (the org.eclipse.ui.win32 plug-in fragment).

Does the generic workbench support help?

The generic workbench contains the extension points for plug-in to contribute help content, including help books and context (F1) help. It includes the API interfaces used by the generic workbench (and other plug-ins) to request that help content be displayed. What the generic workbench is missing, however, is any way of actually displaying the help content (i.e., it has no help UI).

For applications that do not need a help system, the overhead of the mechanism built in to the generic workbench is minimal (under 100KB code size).

Applications that want to make use of the Eclipse help system will need a UI for presenting the info to the user. Here there are two options:

Does the generic workbench support online updates?

The generic workbench has no built-in support for downloading and installing new or updated features and plug-ins.

Applications that want to make use of the existing Eclipse update component have two options:

Does the generic workbench support workspace and resources?

The generic workbench does not support workspaces and resources. These are only available in the Eclipse IDE. An applications that would make use of the workspace and resources should probably be viewed instead as a tool (or set of tools) that plug in to an Eclipse IDE.

What's the minimal set of plug-ins needed to run the generic workbench?

As of I20031202, the minimal set of plug-ins needed to run the generic workbench is:

The application will have to provide at least one plug-in of its own to contribute to the org.eclipse.core.runtime.application extension point.

What optional components can be used with the generic workbench?

Text editors (optional) requires all of the following plug-ins in addition to those required for the generic workbench:

Support for OLE-based editor (optional) requires the following plug-in fragment in addition to those required for the generic workbench:

The content outline and properties views (optional) are in the following plug-in:

Help system (optional) requires all of the following plug-ins in addition to those required for the generic workbench:

Update manager (optional) requires all of the following plug-ins in addition to those required for the generic workbench:

Should applications use features?

[TBD] The application should probably define a primary feature and primary feature plug-in because certain keys pieces of information used to configure the Eclipse runtime come from the feature. The file eclipse/install.ini contains the ids of the default feature and default application. Use org.eclipse.platform as a guide for defining a primary feature and its plug-in.

What about preference pages?

[TBD] The generic workbench defines the org.eclipse.ui.preferencePages extension point for preference pages, and the IWorkbenchPreferencePage API interface. What are the options for an application to show preferences to the user?

What kinds of drag and drop to the editor area of a workbench window supported?

Each workbench window has an editor area (although it need not be visible). When the editor area is visible, it can be used as a target for drag and drop operations. For example, this is used by the IDE to open an editor on a file dropped on the editor area. The editor area may be blank; it need not have an editor in it. Internally, this means that the drop target listener is associated with the control for the editor area itself --- something which no editor can do. By default, workbench windows do not support drag and drop for the editor area. However, an application can configure a window's editor area via two IWorkbenchWindowConfigurer methods. There are two parts: defining the transfer types that will be allowed, and providing the drop target listener that will get to handle these types. Here's a simple example of what this code looks like:

public void preWindowOpen(IWorkbenchWindowConfigurer configurer) {
    ...
    // for dropping a standard IEditorInput
    configurer.addEditorAreaTransfer(EditorInputTransfer.getInstance());
    // for dropping application-specific transfer types A and B
    configurer.addEditorAreaTransfer(MyATransfer.getInstance());
    configurer.addEditorAreaTransfer(MyBTransfer.getInstance());
    // listener for handling drops of type IEditorInput, MyA, and MyB
    configurer.configureEditorAreaDropListener(new MyDropTargetAdapter(configurer.getWindow());
    ...
}

The editor area for each window can be individually configured. and reconfigured at any time.

How do I run the generic workbench?

As of N20031107, the generic workbench is found in the HEAD stream.

  1. Start with a workspace containing your application project.
  2. Use PDE to launch your application: