Eclipse

Eclipse Workbench: Using the Selection Service

_침묵_ 2007. 2. 5. 02:21

출처 :http://www.eclipse.org/articles/Article-WorkbenchSelections/article.html

 

 Copyright © 2006 Marc R. Hoffmann
 Eclipse Corner Article

사용자 삽입 이미지

 

Eclipse Workbench: Using the Selection Service

Summary
The selection service provided by the Eclipse workbench allows efficient linking of different parts within the workbench window. Knowing and using the existing selection mechanisms gives your plug-ins a clean design, smoothly integrates them into the workbench and opens them for future extensions.

By Marc R. Hoffmann, Mountainminds GmbH & Co. KG, hoffmann@mountainminds.com
April 14, 2006


Introduction

The Eclipse workbench is a powerful UI framework for IDEs and also other applications. It provides many services for a highly integrated and extensible user interfaces. One of the integration aspects are view parts that provide additional information for particular objects and update their content automatically whenever such objects are selected somewhere in the workbench window. For example the"Properties"view behaves in this way: Wherever an element is selected in the workbench this view lists the properties of that element.

사용자 삽입 이미지

Other aspects of the workbench like the enablement of global actions may also depend on the current selection.

Instead of implementing "hard-wired communication" plug-ins can rely on the so calledselection service. It decouples parts where items can be selected from others reacting on selection changes.

This article outlines the functionality and usage of the selection service. A providedsample plug-indemonstrates the workbench selection behaviour and can also serve for debugging purposes.

The Big Picture

Each workbench window has its ownselection serviceinstance. The service keeps track of the selection in the currently active part and propagates selection changes to all registered listeners. Such selection events occur when the selection in the current part is changed or when a different part is activated. Both can be triggered by user interaction or programmatically.

사용자 삽입 이미지

The view where elements or text is selected does not need to know who is interested in the selection. Therefore we may create new views that depend on the selection of an existing view – without changing a single line of code in that view.

The next sections explainwhoprovideswhatkind of selections towhom.

What can be selected?

From the users point of view a selection is a set of highlighted entries in a viewer like a table or tree widget. A selection can also be a piece of text in an editor. Behind the scene each visual element in the workbench is represented by a Java object. The MVC implementation of JFace maps between the domain model objects and the visual representations.

Internally a selection is a data structure holding the model objects which corresponds to the graphical elements selected in the workbench. As pointed out before there are two fundamental different kinds of selections:

Both can be empty, i.e. a empty list or a text string with zero length. Following the typical Eclipse philosophy these data structures are properly defined by interfaces:

사용자 삽입 이미지

TheIStructuredSelectionrefers to a set of objects;ITextSelectionandIMarkSelectiondescribe a piece of selected text.

For convenience there are default implementations for these interfaces:

These implementations are used internally within the viewer when transforming low-level SWT events toISelectionobjects. The implementations are also useful when elements should be selected programmatically by some application code, for example:

ISelection sel = new StructuredSelection(presetElement);    treeviewer.setSelection(sel);

사용자 삽입 이미지
Install the providedsample plug-inand check what kind of selections occur in different views. The"Workbench Selection"view shows theISelectionimplementation class and the selected elements or text itself.

Telling the Workbench Window about Selections

All JFace viewers are so calledselection providers. A selection provider implements the interfaceISelectionProvider:

사용자 삽입 이미지

The different JFace viewers use and propagate different kind of selections:

ViewerSelection Type
ComboViewerIStructuredSelection
ListViewerIStructuredSelection
TreeViewerIStructuredSelection
 +- CheckboxTreeViewerIStructuredSelection
TableViewerIStructuredSelection
 +- CheckboxTableViewerIStructuredSelection
TextViewerITextSelection,IMarkSelection
 +- SourceViewerITextSelection,IMarkSelection
     +- ProjectionViewerITextSelection,IMarkSelection

Also custom viewers may serve as selection providers and implement theISelectionProviderinterface.

Any workbench part that holds a viewer should register this viewer as the selection provider with the respective view site:

getSite().setSelectionProvider(tableviewer);

Even if you don't see a need for propagating your selection right now, this opens your plug-in for future extensions by you or by other plug-in implementers. If your view defines actions that depend on the current selection, setting a selection provider is also necessary to allow dynamic enablement of these actions.

사용자 삽입 이미지
Use thesample plug-into check whether your views properly register selection providers.

Tracking the Current Selection

The workbench window is typically assembled in many parts, each coming with at least one viewer. The workbench keeps track about the currently selected part in the window and the selection within this part. Here starts the interesting part of the story: Plug-in implementations can access this information or register for notifications on selection changes.

Each workbench window has anISelectionServiceimplementation which allows tracking the current selection. A view part can obtain a reference to it through its site:

getSite().getWorkbenchWindow().getSelectionService()

The selection service knows the current selection of the active part or of a part with a particular id:

ISelection getSelection()     ISelection getSelection(String partId)

Typically views react on selection changes in the workbench window. In this case they better register anISelectionListenerto get notified when the window's current selection changes:

void addSelectionListener(ISelectionListener listener)    void removeSelectionListener(ISelectionListener listener)

Listeners registered in this way are notified when the selection in the active part is changed or when a different part is activated. Only selections within the active part are propagated. If the application is only interested in the selection of a particular part (independently of its actual activation) one may register the listener only for the respective part id:

void addSelectionListener(String partId, ISelectionListener listener)     void removeSelectionListener(String partId, ISelectionListener listener)

This works even if there is currently no part with such a id. As soon as the part is created its initial selection will be propagated to the listeners registered for it. When the part is disposed, the listener is passed anullselection if the listener implementsINullSelectionListener(seesection below).

Implementing a Selection Listener

TheISelectionListeneris a simple interface with just one method. A typical implementation looks like this:

private ISelectionListener mylistener = new ISelectionListener() {        public void selectionChanged(IWorkbenchPart sourcepart, ISelection selection) {
사용자 삽입 이미지
if (sourcepart != MyView.this &&
사용자 삽입 이미지
selection instanceof IStructuredSelection) {
사용자 삽입 이미지
doSomething(((IStructuredSelection) selection).toList()); } } };

Depending on your requirements your listener implementation probably needs to deal with the following issues as shown in the code snippet above:

  • In case we also provide selections (e.g. a view or editor) we should
    사용자 삽입 이미지
    exclude our own selection events from processing. This avoids unexpected results when the user selects elements within our part.
  • Check whether we can handle this kind of selection (
    사용자 삽입 이미지
    ).
  • Get the selected content from the selection and process it. (
    사용자 삽입 이미지
    ).

사용자 삽입 이미지
Don't mix theISelectionListenerinterface up withISelectionChangedListenerused by JFace viewers to notify about selection changes.

Removing the Selection Listener

Don't forget to remove your selection listener when you can't handle events any more, e.g. when your view has been closed. Thedispose()method is a good place to

사용자 삽입 이미지
remove your listener:

public void dispose() {        ISelectionService s = getSite().getWorkbenchWindow().getSelectionService();
사용자 삽입 이미지
s.removeSelectionListener(mylistener); super.dispose(); }

More Selection Issues

Up to now we focused on the core functionality of the selection service, which covers most of the use cases. There are additional issues that might come into picture in implementation projects.

Post Selection

When navigating views the selection changes frequently - especially when the keyboard is used to scroll through long lists or the mouse is dragged over some text. This will lead to many unnecessary updates of the viewers registered as listeners to the selection service and may make your application less responsive.

So called post selection events will be send-out with a slight delay. All intermediate selections during the delay time are ignored; just the final selection is propagated. TheISelectionServicehas additional methods to register listeners for the delayed selection events:

void addPostSelectionListener(ISelectionListener listener)     void removePostSelectionListener(ISelectionListener listener)     void addPostSelectionListener(String partId,                                  ISelectionListener listener)     void removePostSelectionListener(String partId,                                     ISelectionListener listener)

To avoid performance issues viewers should typically register selection listeners this way.

The selection providers are responsible for sending out the delayed events and have to implement theIPostSelectionProviderinterface if they support it – all JFace viewers do so.

사용자 삽입 이미지
Change thesample plug-into listen to post selection events and check when they are sent.

INullSelectionListener

The call-back methodselectionChanged()defined inISelectionListenerget the new selection as well as the originating part passed in as parameters:

public void selectionChanged(IWorkbenchPart part, ISelection selection);

TheINullSelectionListenerinterface extendsISelectionListenerbut does not declare any additional methods. It is a pure marker interface to indicate that implementers of theselectionChanged()method wants to bet notified even withnullparameters. This is usefull when you need to know that there is no current selection simply due to the fact that there is no one who provides a selection. You step into this when:

  • The active part has not set a selection provider.
  • The specific part we have registered our listener for has not set a selection provider.
  • There is no active part in the workbench window, all parts are closed.
  • The specific part we have registered our listener for has been closed.

Which Selection Service: Page or Window?

If you study the workbench API carefully you will find out that there are two selection services: TheIWorkbenchPageis aISelectionService. On the other hand theIWorkbenchWindowhas a methodgetSelectionService(). Therefore e.g. registering a listener within a part implementation is possible in two ways:

getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(l);

or

getSite().getPage().addSelectionListener(l);

Actually this is totally equivalent because since Eclipse 2.0 a workbench window is limited to a single page only. Just don't mix both selection services when adding and removing a listener as two different implementations sit behind it.

Multiple Selection Providers Within a Part

Be aware that the part's site accepts a single selection provider only, which should be registered within thecreatePartControl()method only:

getSite().setSelectionProvider(provider);

Replacing the selection provider during the lifetime of the part is not properly supported by the workbench. If a part contains multiple viewers providing selections, like the"Java Hierarchy"view does, a intermediateISelectionProviderimplementation has to be provided that allows dynamically delegating to the currently active viewer within the part. As a starting point you may look intoSelectionProviderIntermediate.javaprovided with this article.

What to do With the Selected Objects?

This article claims that theselection servicehelps to decouple views reacting on each others selection. But the view handling a selection still needs to deal with the selected objects to provide any useful functionality. Check out theadapter patternprovided by the Eclipse runtime core, which allows attaching new functionality to existing model objects or the other way round providing required functionality for newly contributed objects.

Actually ourexample plug-indoes exactly this by using the workbench label provider which in turn relies on theIWorkbenchAdapterto retrieve icons and text labels for the listed objects. The same mechanism is utilized by the"Properties"view, see article"Take control of your properties"for details.

Example Plug-in

This article comes with a small example plug-in that demonstrates the explained techniques. Additionally the plug-in may serve for debugging your selection providers. The example contributes a new view"Workbench Selection"which simply mirrors the current selection in the workbench. It works for element selections as well as for text selections.

Getting and Running the Example

Download the plug-in projectcom.mountainminds.eclipse.selectionsample.zipand import it into your workspace via the"Import..."wizard from the"File"menu. Select"Existing Project into Workspace"on the first wizard page. On the second page simply use the option"Select archive file"to import the downloaded archive.

The fastest way to launch the example is right-clicking the plug-in project and select"Run As""Eclipse Application"in the context menu. From the menu of the launched workbench activate"Window""Show View""Other..."and select our view"Workbench Selection"in the category"Other".

Now you can play around with selections in various workbench parts and see how our"Workbench Selection"view reflects these selections:

사용자 삽입 이미지

The same works for text selections:

사용자 삽입 이미지

The example is implemented in a single classSelectionView.javaapplying the techniques discussed in this article. When reading through this short piece of code you may note that:

  • TheISelectionListenerimplementation makes sure that we do not react on our own selections.
  • The title of the source part of the current selection as well as the implementation class ofISelectionis shown in the view description (the optional grey bar at the top).
  • The view uses two viewers: One for object lists and one for text blocks. Switching between the viewers is implemented done with aPageBook.
  • The viewer for object lists itself registeres as a selection provider. Check it out: If you select a element listed in our"Workbench Selection"view its properties are shown in turn in the"Properties"view.

Conclusion

The mechanisms provided by the Eclipse workbench are simple to use and powerful. Not using this mechanisms result in plug-ins that poorly integrate with the rest of the workbench and will be hard to extend. To avoid such pitfalls simply follow these rules when selections come into picture:

  • Avoid direct hard-wired inter-view communication. If one view needs to react on the selection in another view use theISelectionService.
  • Be cooperative and open for future extensions: Always register your viewers as selection providers with the part site.
  • Use existing selection specific views like the"Properties"view when appropriate instead of creating new ones.

References

To discuss or report problems in this article seebug 112193.

Resources

This article come with the following resources:

'Eclipse' 카테고리의 다른 글

GEF references  (0) 2007.02.05
Eclipse RCP & OSGi on the Client & Server  (0) 2007.01.31
Platform UI Error Handling  (0) 2007.01.26