출처 :http://www.eclipse.org/articles/Article-WorkbenchSelections/article.html
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:
- A list of objects
- A piece of text
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:
TheIStructuredSelection
refers to a set of objects;ITextSelection
andIMarkSelection
describe a piece of selected text.
For convenience there are default implementations for these interfaces:
org.eclipse.jface.viewers.StructuredSelection
org.eclipse.jface.text.TextSelection
org.eclipse.jface.text.MarkSelection
These implementations are used internally within the viewer when transforming low-level SWT events toISelection
objects. 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 theISelection
implementation 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:
Viewer | Selection Type |
ComboViewer | IStructuredSelection |
ListViewer | IStructuredSelection |
TreeViewer | IStructuredSelection |
+- CheckboxTreeViewer | IStructuredSelection |
TableViewer | IStructuredSelection |
+- CheckboxTableViewer | IStructuredSelection |
TextViewer | ITextSelection ,IMarkSelection |
+- SourceViewer | ITextSelection ,IMarkSelection |
+- ProjectionViewer | ITextSelection ,IMarkSelection |
Also custom viewers may serve as selection providers and implement theISelectionProvider
interface.
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 anISelectionService
implementation 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 anISelectionListener
to 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 anull
selection if the listener implementsINullSelectionListener
(seesection below).
Implementing a Selection Listener
TheISelectionListener
is 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 theISelectionListener
interface up withISelectionChangedListener
used 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
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. TheISelectionService
has 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 theIPostSelectionProvider
interface 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 inISelectionListener
get the new selection as well as the originating part passed in as parameters:
public void selectionChanged(IWorkbenchPart part, ISelection selection);
TheINullSelectionListener
interface extendsISelectionListener
but does not declare any additional methods. It is a pure marker interface to indicate that implementers of theselectionChanged()
method wants to bet notified even withnull
parameters. 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: TheIWorkbenchPage
is aISelectionService
. On the other hand theIWorkbenchWindow
has 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 intermediateISelectionProvider
implementation has to be provided that allows dynamically delegating to the currently active viewer within the part. As a starting point you may look intoSelectionProviderIntermediate.java
provided 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 theIWorkbenchAdapter
to 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.zip
and 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.java
applying the techniques discussed in this article. When reading through this short piece of code you may note that:
- The
ISelectionListener
implementation 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 of
ISelection
is 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 a
PageBook
. - 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 the
ISelectionService
. - 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
- OTI Inc., Eclipse Platform Technical Overview, 2003
http://www.eclipse.org/whitepapers/eclipse-overview.pdf - eclipse.org, JFace Viewer Package, 2005
http://help.eclipse.org/help31/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/jface/viewers/package-summary.html - eclipse.org, Workbench UI Package, 2005
http://help.eclipse.org/help31/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/ui/package-summary.html - wiki.eclipse.org, FAQ How do I find out what object is selected?, 2006
http://wiki.eclipse.org/index.php/FAQ_How_do_I_find_out_what_object_is_selected%3F - wiki.eclipse.org, FAQ How do I make a view respond to selection changes in another view?, 2006
http://wiki.eclipse.org/index.php/FAQ_How_do_I_make_a_view_respond_to_selection_changes_in_another_view%3F - wiki.eclipse.org, FAQ How do I use IAdaptable and IAdapterFactory?, 2006
http://wiki.eclipse.org/index.php/FAQ_How_do_I_use_IAdaptable_and_IAdapterFactory%3F - Dicky Johan, Take control of your properties, 2003
http://www.eclipse.org/articles/Article-Properties-View/properties-view.html
To discuss or report problems in this article seebug 112193.
Resources
This article come with the following resources:
- Example plug-in providing the"Workbench Selection"view
com.mountainminds.eclipse.selectionsample.zip - Selection provider implementation for delegating to multiple other selection providers
SelectionProviderIntermediate.java
'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 |