Chapter 15. Workbench Advisors

In Part II you got a glimpse of the ways in which the Workbench advisors are used in real applications, but you may have noticed that many of the advisors’ methods were not used. This chapter explores these additional APIs and explains how they can be used in your application. Another area that you’ve started to get familiar with is the Workbench; we end this chapter with an overview of the Workbench and its extension points.

15.1 Workbench Advisors

You may recall from Part II that when the Hyperbola application starts, its main job is to call PlatformUI.createAndRunWorkbench(Display, WorkbenchAdvisor), as shown in the snippet below. This somewhat inconspicuous method bootstraps your UI by starting the Workbench. This leads to the creation, configuration, and opening of the application windows.

image

The Workbench, however, does not know how the application should behave or look—that’s where the Workbench advisors come in. As their name implies, advisors give advice to the Workbench. In doing so, they influence what the UI contains and how it looks and feels.

Instead of changing the behavior of the Workbench, say, by subclassing, the Workbench aggregates the advisors and allows them to participate in the running of the Workbench. As you’ve seen in Hyperbola, when the Workbench opens a window, it asks an advisor to determine whether or not it should include a menu bar by calling the WorkbenchWindowAdvisor.preWindowOpen() method.

Adviser or Advisor?

The dictionary says that either spelling is correct, but common usage says that an adviser is someone defined by what he or she is doing: defined by a verb, one who is advising or dispensing advice. An advisor is someone defined by what he or she is—defined by what he or she continually does, someone in the position of providing advice.

There are three types of advisors, and each is characterized by the part of the Workbench to which it gives advice:

WorkbenchAdvisor—This advisor provides application-level advice. It participates in the startup and shutdown of the Workbench itself; there is one running Workbench per running Eclipse application.

WorkbenchWindowAdvisor—This advisor provides window-level advice. It participates in showing or hiding the menu, toolbar, and status line and in configuring the controls shown in the window. There is one WorkbenchWindowAdvisor instance for each window.

ActionBarAdvisor—This advisor provides window-level advice and helps define the actions that appear in the menu, toolbar, and status line of each window. There is one ActionBarAdvisor instance for each window.

Each advisor has an associated configurer that provides privileged access to the Workbench, Workbench window, and window’s action bars (e.g., menu, toolbar, and status line). There’s one configurer for each advisor type. Since the configurers provide privileged access to the Workbench, they should never be passed around to other plug-ins. The three different types of configurers are the IWorkbenchConfigurer, IWorkbenchWindowConfigurer, and IActionBarConfigurer. The following snippets demonstrate how each can be used within its associated advisor:

image

The advisors have another very important role—they define top-level integration points for the product. For example, the advisors decide the names for the groups and separators within the top-level menu, toolbar, and status line. Plug-ins contributing to the product must use these names as integration points when defining and placing their own actions. This is discussed further in Section 17.2.2, “Allowing Contributions.”

Advisors are very closely linked to the concept of a product. Although this relationship is not technically enforced—for example, the product extension point does not include details about the advisors—from the outside they are often seen as one. You typically have one set of advisors for each of your products. As you’ve seen, a product as defined by the product extension point refers to one application (e.g., IApplication), and each application is associated with one set of advisors.

15.1.1 Workbench Lifecycle

To understand the full scope of how advisors are used to configure the Workbench, let’s take a look at the Workbench lifecycle and the points at which the different advisors participate.

Under the covers, when PlatformUI.createAndRunWorkbench() is called, the Workbench performs the following high-level steps:

• Initializes an exception handler to trap uncaught exceptions.

• Opens the main window, creating the default controls (toolbar, status line, perspective switcher, perspective), and restores any saved state.

• Takes down the splash screen.

• Opens one or more windows and initializes them with UI settings that have been saved from the last session.

• Runs the SWT event loop.

• When IWorkbenchWindow.close() is called, the windows’ states are saved, then the windows are closed.

Figure 15-1 shows the typical runtime interaction between the Workbench and the various advisors.

Figure 15-1 Workbench advisors’ lifecycle events

image

When the Workbench runs, it allows the WorkbenchAdvisor to participate from the very beginning by calling WorkbenchAdvisor.initialize(). This happens before any windows are opened. As each window is opened, a WorkbenchWindowAdvisor is created and associated with that window instance. This WorkbenchWindowAdvisor instance is consulted throughout the window’s lifecycle. The ActionBarAdvisor is created by the WorkbenchWindowAdvisor before the window is opened and participates in populating the menu, toolbar, and status line of each window. The next sections reveal more detail about the lifecycle and APIs for each type of advisor.

15.2 WorkbenchAdvisor

The WorkbenchAdvisor in Hyperbola played only a small part in the overall application. It initialized settings in the WorkbenchAdvisor method initialize() and then hooked the chat listener to process incoming chats. This is very typical of a WorkbenchAdvisor—initializing application lifecycle settings and cleaning up when the Workbench shuts down.

It is tempting to use the lifecycle methods in your WorkbenchAdvisor to trigger initialization of additional parts of your application. Resist that urge! The work done here sits squarely in the path of displaying the application’s first window—the more work you do, the longer your users wait to see your application. This can’t be stressed enough: Do as little as possible in the WorkbenchAdvisor’s initialization code.

Note

A good technique for minimizing initialization costs is to initialize resources only when first accessed. For example, do not bother creating fonts or images until they are needed. This has the added benefit of saving space since only those resources being used are allocated. Note also that this approach applies to the initialization of model data structures and references to other plug-ins.

The WorkbenchAdvisor’s API methods fall into three categories:

Lifecycle—allows the advisors to participate in startup and shutdown of the application

Exception and idleness—allows the advisor to participate when an exception occurs and when the application is idle

Configuration—allows the advisor to determine default values for global application settings

15.2.1 Lifecycle API

You should use the lifecycle methods to initialize, restore, and then save and shut down aspects of your application. The description of each method in Table 15-1 provides a hint as to the type of work typically done in each method.

Table 15-1 Workbench Lifecycle Events

image

15.2.1.1 IWorkbenchConfigurer

When the WorkbenchAdvisor method initialize(IWorkbenchConfigurer) is called, it’s provided with an IWorkbenchConfigurer. The configurer is used to configure the Workbench and provides privileged access to it, for example, telling it to save Workbench settings or registering images with the Workbench. The configurer can be accessed after the initialize() method is called by calling the WorkbenchAdvisor method getWorkbenchConfigurer().

The IWorkbenchConfigurer is mostly used to

• Set and get properties on the configurer using the setData(String, Object) and getData(String) methods. This is useful for passing data from the WorkbenchAdvisor to the WorkbenchWindowAdvisor or ActionBarAdvisor.

• Close the Workbench in case of emergency and find out if it’s closing via the emergencyClose() and emergencyClosing() methods.

• Determine if the Workbench should exit when the last window is closed via the setExitOnLastWindowClose(boolean). If the Workbench does not exit and the event loop keeps running, you can either open another window using IWorkbench.openWorkbenchWindow(String, IAdaptable) or close the Workbench by calling IWorkbench.close().

Because advisors have privileged access to the Workbench, it’s best to keep both the configurers and the advisors private and not pass them to other plug-ins.

15.2.1.2 Closing the Workbench

The Workbench can be closed any time after the WorkbenchAdvisor method initialize() is called. There are three ways of closing the Workbench:

IWorkbench.close()—This method performs a normal shutdown. In Hyperbola the ActionFactory.QUIT_ACTION calls this method to exit the Workbench.

IWorkbench.restart()—This method performs a normal shutdown and causes the application to restart immediately.

IWorkbenchConfigurer.emergencyClose()—This method causes Eclipse to exit gracefully but immediately. It is called when a fatal error occurs and the application cannot risk a normal shutdown. The Workbench attempts to at least save the user’s settings.

15.2.1.3 Workbench Preferences

In addition to configuration settings available on the IWorkbenchConfigurer, there are additional Workbench preferences to control the look and feel of the application. These include setting the perspective bar’s location, the fast view bar’s location, and the use of traditional versus curvy tabs. Table 15-2 lists the most popular public preferences for RCP applications. See the org.eclipse.ui.IWorkbenchPreferenceConstants interface for a complete list.

Table 15-2 Useful Workbench Customization Preferences Defined by org.eclipse.ui

image

The WorkbenchAdvisor can set preferences in the initialize() method as shown here:

PlatformUI.getPreferenceStore().setValue(
  IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS, true);

As described in Section 13.4, “Adding Help Content,” preferences can also be initialized using the product preference customization file. For example, add the following to your product’s preferences customization file to show the perspective bar and fast view bar on the left and to use curvy tabs. The advantage of using a customization file is that it allows different products that may be built from your application to have different values for these preferences.

image

15.2.2 Exceptions and Idleness API

The Workbench runs a standard SWT event loop. It is possible that bugs in the application, a constituent plug-in, or critical situations (e.g., running out of memory) in the system can cause exceptions to be thrown into the event loop code. When this happens, the Workbench’s event loop calls WorkbenchAdvisor.eventLoopException(), as shown in the snippet below. Table 15-3 also lists the exception and idleness methods available on the WorkbenchAdvisor.

image

Table 15-3 Workbench Event Loop Methods

image

Even though this usually means that the application is in an invalid state, the WorkbenchAdvisor’s default implementation logs the exceptions and allows the application to keep running. Your advisor can extend this exception handling by, for example, prompting the user to take some action such as logging a bug report, or by shutting down the application. To shut down the Workbench in an emergency, the WorkbenchAdvisor should call the IWorkbenchConfigurer method emergencyClose().

To avoid causing such emergencies, you should write your code defensively—catching and handling exceptions locally. This can be challenging since you do not have control over the exceptions thrown during calls to third-party code. To help, the Runtime provides the platform method run(ISafeRunnable), a convenient mechanism for safely running untrusted code.

The ISafeRunnable interface contains two methods: run() and handleException(Throwable). You simply wrap calls to untrusted code in the run() method. When ISafeRunnable is executed, the platform catches all exceptions and allows the handleException() method to handle them. Since the platform automatically logs exceptions, your handleException() should focus on recovering from the problem if possible. The snippet below shows a typical use of ISafeRunnable when notifying listeners. If the listener fails, the code moves on to the next listener, trusting that the failure has been logged.

image

15.2.3 Configuration API

When a Workbench window is opened for the first time, it asks the WorkbenchAdvisor for the settings that are used to create the initial perspective and page input. Without this information, your application does not start. The information is provided by the methods listed in Table 15-4. These are used only once to initialize the setting. Subsequent runs use the values saved with the Workbench settings.

Table 15-4 Workbench Configuration Methods

image

15.3 WorkbenchWindowAdvisor

In Hyperbola, WorkbenchWindowAdvisor plays a more visible role than WorkbenchAdvisor. It configures the window’s title, the visibility of the menu bar, toolbar, and status line, and many more things. Essentially, this advisor controls the appearance of each Workbench window.

The methods on WorkbenchWindowAdvisor relate to the lifecycle of the window instead of the Workbench’s lifecycle. Within the lifecycle methods, the advisor can configure the window via its IWorkbenchWindowConfigurer. Think of the configurer as providing special APIs that allow the advisor to fine-tune elements of the WorkbenchWindow that are not available via the standard IWorkbenchWindow APIs. As such, the configurer has several useful methods such as setInitialSize(Point), setShowToolbar(boolean), setTitle(String), and setShowMenuBar(boolean). The following snippet shows a typical use of this advisor:

image

The Hyperbola WorkbenchWindowAdvisor overrides a few methods, such as these:

preWindowOpen()—configures the parts of the window that should be visible and sets the initial window size, as shown in the previous snippet

postWindowOpen()—configures things that need the window to be created, for example, to set up system tray integration

Working through the tutorial in Part II is the best way to understand how a WorkbenchWindowAdvisor is used. For more advanced Workbench window customization, see Chapter 19, “Customizing Workbench Windows.”

15.3.1 IWorkbenchWindowConfigurer

As shown in the previous code snippet, the window’s configurer is most often used in the WorkbenchWindowAdvisor to show and hide items in the window. It can also be used to

• Set and get properties on the configurer using the setData(String, Object) and getData(String) methods. This is useful for passing data from this advisor to the ActionBarAdvisor.

• Allow the advisor to create the menu, toolbar, and status line itself and arrange these controls in different ways. See Chapter 17, “Actions,” for examples of using these methods with Hyperbola.

• Configure the drag-and-drop behavior of the editor’s area. See Section 16.4, “Drag and Drop with Editors.”

15.4 ActionBarAdvisor

The ActionBarAdvisor is responsible for the actions shown in the top-level menu, toolbar, and status line of your application. As you saw in Chapter 6, “Adding Actions,” this advisor has a very straightforward lifecycle. It creates the actions when makeActions(IWorkbenchWindow) is called and positions the actions in their respective areas when fillMenuBar(), fillCoolBar(), and fillStatusLine() are called. When the window is closed, the dispose() method is called so it can clean up. The following snippet shows a typical use of this advisor:

image

The following points describe the responsibility of the ActionBarAdvisor:

• Creates the fixed menu, toolbar, and status line structure for the application

• Adds placeholders for contributed actions and menus

• Creates the static actions and registers them with the Workbench to enable key bindings

Reading Chapter 6 and seeing how it is used in building Hyperbola is the best way to learn about ActionBarAdvisor. Chapters 18 and 19 contain more advanced examples.

15.4.1 IActionBarConfigurer

As shown in the previous code snippet, the action bar’s configurer is used only in ActionBarAdvisor to access the areas in the window that can accept actions and contributions.

15.5 Workbench Overview

There is much more to the Workbench than the advisors. In Part II you saw that much of the Workbench configuration is done by adding extensions to the many Workbench extension points. This section provides a quick overview of the overall role of the Workbench and a reference to its many extension points.

As JFace adds structure to SWT, so the Workbench adds presentation and coordination to JFace. Consider the Workbench as providing the following functionality to your application:

Configures and manages windows—The first Workbench window is opened using PlatformUI.createAndRunWorkbench(Display, IWorkbenchAdvisor) during application startup. This also runs the event loop and manages all subsequent windows. An RCP application has special status with the Workbench—it provides a set of Workbench advisors that participate in the management of the Workbench and the windows that it opens. This part of the Workbench is specific to RCP applications since only one application plug-in can define the running of the Workbench.

Defines a UI paradigmChapters 5, “Starting the Hyperbola Prototype,” and 7, “Adding a Chat Editor,” introduced the RCP basic building blocks of the Workbench UI: perspectives, views, and editors. These common UI components define the way application content is shown to the user. A perspective is a visual container for a set of views and editors—everything shown to the user is in a view or editor and is laid out by a perspective. There are many APIs available to manage and control these components of the UI.

Provides contribution-based extensibility—While JFace defines the notions of actions, preferences, wizards, windows, and so on, the Workbench defines extension points that expose these elements. For example, the Workbench’s wizard and preference page extensions are just thin veneers over the related JFace constructs.

The use of extension points to build UIs has a fundamental impact on the scalability of the interface in terms of both complexity and performance. Since all these extensions are handled lazily, applications scale better with respect to performance. As the UI gains views, editors, actions, and so forth, the additional contributions are available but are not loaded or executed until they are required—no code is loaded before its time.

The use of extension points allows multiple unrelated plug-ins to coexist within the same dialogs and menus—UI elements do not need to know about each other to be integrated.

15.5.1 Workbench Extension Point Reference

Throughout the tutorial in Part II, you encountered most of the important extension points defined by the Workbench. For example, in Chapters 5 and 7 you added a view, an editor, and a perspective to Hyperbola. This section gives you a quick overview of all the Workbench extension points, to provide context for the following chapters and a reference for extension points that are not described later but that may be useful in your RCP application.

Note

Some extension points are not fully covered in this book because they are covered well in existing documentation or are not specific or key to RCP use cases.

Although the list of over 42 Workbench extension points looks daunting, categorizing them makes it much more tractable. The next sections (including Tables 15-5 through 15-9) summarize the categories and give short descriptions of each of the Workbench’s extension points. When possible, pointers to other chapters in the book are provided in an extension point’s description.

15.5.2 Actions

The extension points in Table 15-5 support adding menus, menu items, and toolbar buttons to windows, editors, and views. Also, as shown in Chapter 12, “Adding Key Bindings,” you can use them to add key bindings to existing actions.

Table 15-5 Action Extension Points at a Glance

image

15.5.3 Scalability

The extension points described in Table 15-6 support the creation of large-scale applications. For example, activities are used to automatically or manually hide certain elements of the UI.

Table 15-6 Scalability Extension Points at a Glance

image

15.5.4 Contributions

The extension points in Table 15-7 allow the contribution of pages, wizards, and other standard elements to the UI.

Table 15-7 Contribution Extension Points at a Glance

image

15.5.5 Perspectives

The extension points in Table 15-8 are used to define the basic components of the UI in terms of views, editors, and perspectives. Most RCP applications have at least one perspective and minimally one view. Perspective extension points are meant to allow plug-ins to contribute to perspectives contributed from other plug-ins.

Table 15-8 Perspective Extension Points at a Glance

image

15.5.6 Startup

The extension points in Table 15-9 relate to the behavior of the Workbench when the application starts up.

Table 15-9 Startup Extension Points at a Glance

image

15.6 Summary

In this chapter you got a glimpse of the Workbench features available to you when building RCP applications. The features in the Workbench exist because they were needed when building the Eclipse IDE product—not because the Eclipse RCP needed a UI framework; that is, they address real, concrete problems but are general enough to be used in other situations. After all, the IDE is essentially a very sophisticated RCP application!

The next couple of chapters are dedicated to uncovering the essential RCP-specific Workbench features.

15.7 Pointers

• Eclipse Help > Platform Plug-in Developer Guide > Advanced workbench concepts

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset