The Eclipse platform allows pluggable components -- plug-ins -- to help create a rich graphical user interface (GUI) application. For example, plug-ins can contribute views to the GUI. In a real-world application, however, the UI views can never be islands unto themselves. They need to interact and update themselves depending upon the state of other views.
A simple example is a GUI application depicting the world's major tourist destinations. This GUI might have a Select City view to display places of interest and public transportation information.
Figure 1. Example of view linking
This article presents ways to make views in Eclipse collaborate and respond to the states of other views. It also looks at cases in which one way of linking views may prove to be better than others.
Eclipse developers can rely on the following methods to link views:
- The selection provider-selection listener pattern, whereby views react to selections in other views
- The
IAdaptableinterface used in conjunction with some events - The property change listener, which allows a view to push property change events to registered listeners
The selection provider-selection listener paradigm
The selection provider-selection listener pattern is a handy way to create views that respond to changes in other views. For example, when a user clicks a UI item that represents a city name, some other view might want to display details of the places of interest in that city. Such a view can consume the information contained within the UI selection object (possibly a string object representing a city name) and use it to retrieve and display additional information from the model.
Views should be able to identify and consume UI selection events. The org.eclipse.ui.ISelectionListener is the listener interface that receives the UI selection events. The selection listeners must be registered with the workbench page. The workbench page implements a service defined by the interface org.eclipse.ui.ISelectionService to orchestrate the sourcing of UI selection events to the listeners. A selection listener must be registered with a selection service.
Views that display UI items capable of being selected should also be able to publish the UI selections. The views can be made to do so by registering "selection providers" with their respective workbench site. Each UI part in Eclipse liaises with the workbench site via an org.eclipse.ui.IWorkbenchPartSite reference. Selection providers are registered with the workbench site.
When views are linked by using the selection provider-selection listener pattern, a view adds itself as a listener to the workbench page, and other views that wish to publish a selection must add a selection provider to their respective workbench site. The org.eclipse.ui.ISelectionListener interface is shown below.
public void selectionChanged(IWorkbenchPart part, ISelection selection); |
To make a view capable of listening to selection changes, a view must implement the ISelectionListener interface and must register itself with the workbench page. Listing 1 shows an example.
Listing 1. Adding a selection listener to the workbench page
public class MyView extends ViewPart implements ISelectionListener{
public void createPartControl(Composite parent) {
// add this view as a selection listener to the workbench page
getSite().getPage().addSelectionListener((ISelectionListener) this);
}
// Implement the method defined in ISelectionListener, to consume UI selections
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
//Examine selection and act on it!
}
}
|
A smarter way to consume UI selections is to register the consumer views as listeners to specific view parts. As you can see in the example below, the view ID of the source view part is mentioned as a parameter during registering a selection listener.
getSite().getPage().addSelectionListener("SampleViewId",(ISelectionListener)this);
|
This approach will eliminate the redundant callbacks to the consumer view that would otherwise occur if that view were registered as a nonspecific listener.
The code snippet in Listing 2 shows the createPartControl() method of a view that creates a JFace TableViewer and adds it as a selection provider to the workbench site. This code enables any UI selection changes in the TableViewer to propagate to the page and finally to the interested consumer views.
Listing 2. Setting up a selection provider
public void createPartControl(Composite parent) {
// Set up a JFace Viewer
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setSorter(new NameSorter());
viewer.setInput(getViewSite());
// ADD the JFace Viewer as a Selection Provider to the View site.
getSite().setSelectionProvider(viewer);
}
|
The view chooses to register the JFace TableViewer that it created, as a selection provider for two reasons:
- The view plans to use the TableViewer to display its information, and the user will interact with the TableViewer.
- The TableViewer implements the selection provider interface and can source selection events to the workbench part site.
Because the JFace viewers are selection providers, you won't have to create a selection provider in most cases. A view simply has to use one of the many JFace viewers to display data and register the JFace viewer as the selection provider.
Some cases call for a different approach to view linking:
- The amount of information may simply be too large for a UI selection object to hold it efficiently, due to increased memory usage.
- A view may want to publish information that is not just a visual selection. The information to be published may be a result of some post-processing based on the selection.
- A view may want to consume information from another plug-in that may not have contributed a view (with a contained JFace viewer) at all. To leverage the UI selection based linking is not possible in this case.
You can mitigate the first issue with the org.eclipse.core.runtime.IAdaptable interface, which makes a selection object capable of sourcing more information, on demand. Issues 2 and 3 require a do-it-yourself approach, and the property change listener pattern could be just what the doctor ordered.
Using the IAdaptable interface
A class that implements IAdaptable has the capability to dynamically return certain types of adapters that can then be used to retrieve further information. If the selection objects in a viewer implement the IAdaptable interface, they can be effectively used to retrieve more information or related information, depending on the types of adapters they can return. The org.eclipse.core.runtime.IAdaptable interface is shown below.
public void object getAdapter(Class adapter); |
Obviously, the caller should be aware of the type of adapter interface it expects the selection to return. Consider a JFace TreeViewer that is set up to render cities in a single-level tree. The objects that represent the cities are of the type CityClass. A CityClass object should hold some preliminary information about the city and return detailed information only when needed. In Listing 3, note the adapter types that CityClass supports so that callers can retrieve more information on demand.
Listing 3. CityClass in JFace TreeViewer
class CityClass implements IAdaptable {
private String cityName;
public CityClass(String name) {
this.name = name;
}
public String getName() {
return name;
}
public CityClass getParent() {
return parent;
}
public String toString() {
return getName();
}
public Object getAdapter(Class key) {
if (key.getName().equals("ITransportationInfo"))
return CityPlugin.getInstance().getTransportAdapter();
else (key.getName().equals("IPlacesInfo"))
return CityPlugin.getInstance().getPlacesAdapter();
return null;
}
}
|
Developers familiar with the Eclipse IDE workbench are aware of the Outline view, which gives a structural view of a file opened in the editor. This Outline view example shows how the IAdaptable interface in conjunction with certain event types can effectively initialize views based on the contents of other views. An editor must create a Content Outline page for the file that a user has opened for editing. The Content Outline page conforms to a certain interface, the IContentOutlinePage. The editor must also implement the IAdaptable interface so that the editor can be queried for an adapter of type IContentOutlinePage. This adapter is used to retrieve and display the outline information for a file.
Another example of the IAdaptable interface is the Properties view. The Properties view tracks the selection on the active part and invokes the getAdapter method on the current selection object. The queried adapter type is IPropertySource. The Properties view then uses the IPropertySource adapter to retrieve information to be displayed.
In these examples of view linking, the application initiates a pull of information via IAdaptable upon receiving Selection Changed or Part Activation notifications. Thus, if the selections are IAdaptable, users can retrieve much more information via the adapter than what is otherwise available from the selection object itself.
The property change listener paradigm
You can use the property change listener type of interactions to address the other two issues mentioned earlier: How does a view consume information from a plug-in that has no view contribution and how does a view publish information generated after some processing occurs upon visual selection?
You can build a plug-in to accept registrations of a property change listener and even notify registered listeners as needed. The application can notify listeners about customized events that also contain the information to be shared.
Unlike the case of selection providers, there is no specific interface for property change providers to implement. You must decide on the semantics of registering listeners with the providers created. The code snippet in Listing 4 shows the methods to allow property change listeners to be added to or removed from a property provider view or plug-in class.
Listing 4. Adding and removing property change listeners
//To add a listener for property changes to this notifier: public void addPropertyChangeListener(IPropertyChangeListener listener); //To remove the given content change listener from this notifier: public void removePropertyChangeListener(IPropertyChangeListener listener); |
The property providers should use the org.eclipse.jface.util.PropertyChangeEvent to create an event that can be effectively populated and propagated. Also, the onus to maintain a list of listeners, then call back into them lies with the property provider.
As an example, consider a plug-in that invokes a World Weather Web Service for major cities every hour and wants to make the information available to other plug-in and views. The CityWeatherPlugin can expose a property called CitiesWeatherXML, and consumers can register themselves with CityWeatherPlugin as PropertyChange listeners. For this purpose, the listeners have to be aware of the method in CityWeatherPlugin to invoke to register themselves as listeners to the weather data events. The CityWeatherPlugin is expected to keep track and notify the listeners. It uses the PropertyChangeEvent to serve data to the listeners.
Listing 5. Create a property provider
class CityPopulationPlugin {
ArrayList myListeners;
// A public method that allows listener registration
public void addPropertyChangeListener(IPropertyChangeListener listener) {
if(!myListeners.contains(listener))
myListeners.add(listener);
}
// A public method that allows listener registration
public void removePropertyChangeListener(IPropertyChangeListener listener) {
myListeners.remove(listener);
}
public CityPopulationPlugin (){
// method to start the thread that invokes the population \
web service once every hour
// and then notifies the listeners via the propertyChange() callback method.
initWebServiceInvokerThread( myListeners );
}
void initWebServiceInvokerThread(ArrayList listeners) {
// Code to Invoke Web Service Periodically, and retrieve information
// Post Invocation, inform listeners
for (Iterator iter = listeners.iterator(); iter.hasNext();) {
IPropertyChangeListener element = (IProperty\
ChangeListener) iter.next();
element.propertyChange(new PropertyChangeEvent(this, \
"CitiesWeatherXML" , null , CityWeatherXMLObj));
}
}
}
|
The property change listeners have to implement the org.eclipse.jface.util.IPropertyChangeListener interface to enable callbacks from the property change providers. This interface has one method, the public void propertyChange(PropertyChangeEvent event).
Listing 6. Implementing the IPropertyChangeListener
class MyView implements IPropertyChangeListener {
public void createPartControl() {
//register with a Known Plugin that sources Population Data
CityPopulationPlugin.getInstance().addPropertyChangeListener(this);
}
public void propertyChange(PropertyChangeEvent event) {
//This view is interested in the Population Counts of the Cities.
//The population data is being sourced by another
plugin in the background.
if( event.getProperty().equals("CitiesWeatherXML")) {
Object val = event.getNewValue();
// do something with val
}
}
}
|
This approach is more flexible in that the application can notify the listeners and pass them information in a variety of scenarios as needed. The information passed on does not have to be directly related to a UI selection; it can be the result of some post-processing. And it can be related to the states of other background jobs or a periodic push of the latest information retrieved from the model. As an example, The City Selector View may not only propagate the selected city info but also asynchronously push the weather information of the current selected city to other consumers using the PropertyChange paradigm.
This article looked at various ways to make views collaborate and respond to each other. If UI selections themselves are not enough, they can be beefed up by the IAdaptable interface. The property change listener provides more flexibility to suit non-UI scenarios, as well.
Learn
-
Visit Eclipse.org for comprehensive information on the program and how to use it.
-
"Getting started with the Eclipse Platform" provides a history and overview of Eclipse, including details on how to install Eclipse and plug-ins.
-
Visit the developerWorks Java™ technology zone to expand your Java skills.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
-
Stay current with developerWorks technical events and webcasts.
Get products and technologies
-
Download a free trial version of WebSphere Application Server V6.0.
-
Build your next development project with IBM trial software, available for download directly from developerWorks.
-
Order the SEK for Linux®, a two-DVD set containing the latest IBM trial software for Linux from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
Discuss
-
Get involved in the developerWorks community by participating in developerWorks blogs.

Chinmay Pandit is a software engineer in the IBM India Software Labs and works as a developer on the IBM Workplace Managed Client messaging application. He is an avid Eclipse programmer and a Sun-certified J2EE architect. He was a co-technical mentor on the IBM Extreme Blue 2005 project, working on view collaboration and exploring different ways to achieve it.




