I need to write some code that tracks the global selection. What should I do?
If you are writing an action, consider using one of the context sensitive action classes in the apis.
For other types of code, use Utilities.actionsGlobalContext()
. This is a Lookup which shows the contents of whatever TopComponent has focus. When component A has focus, the Lookup returned by Utilities.actionsGlobalContext()
contains whatever A.getLookup() contains. When the user sends focus to component B, the contents change - and events are fired if you are listening for changes.
Think of Utilities.actionsGlobalContext()
as watching a news program on television. If there is something exciting happening in Lichtenstein, you do not have to go to Lichtenstein to learn about it - the people in the studio show you their reporter in Lichtenstein. Similarly, if you want to know what the user has selected, with Utilities.actionsGlobalContext()
you do not have to pay attention to which component has focus, or even the fact that there is a component! You can just tune to the sports channel (well, in NetBeans, more likely, the DataObject channel) and get all the news about what is happening. Or, to use another metaphor, you are looking down one end of a hose. The platform takes care of moving the other end of the hose around so that you are always looking at the place where the user is working.
In practice, Utilities.actionsGlobalContext()
returns a Lookup which proxies the Lookup of the active (focused) TopComponent's Lookup (which, if it is an explorer view, is proxying the Lookup(s) of whatever Node(s) are selected). Say that we are interested in what is happening with - whether the user has selected - objects of the type SomeApiClass
:
//You must hold a reference to your Lookup.Result as long as you are interested
//in changes in it, or it will be garbage collected and you will stop getting
//notifications
Lookup.Result res = Utilities.actionsGlobalContext().lookupResult (SomeApiClass.class);
res.addLookupListener (new LookupListener() {
public void resultChanged (LookupEvent evt) {
Collection c = ((Lookup.Result) evt.getSource()).allInstances();
//do something with the collection of 0 or more instances - the collection has changed
}
});
The nice thing about this approach is that, unless your code specifically cares about Nodes, you don’t need to depend on the Nodes API.
The idea behind this is that every "logical window" in NetBeans has its own Lookup, whose contents represent the "selection" in that window (or whatever services it wants to expose). Utilities.actionsGlobalContext()
is a single point of entry - you don’t have to track which window currently has focus - it is a Lookup which proxies the Lookup of whatever window does have focus. When the focused window changes, the Lookup returned by Utilities.actionsGlobalContext()
will fire the appropriate changes. So, for example, an Action can be written to be sensitive to a particular object type; it does not need any code that relates to tracking window focus or similar.
Please note: Generally, keep a hard reference on the Lookup.Result (or make a closure on it with some final keyword and a reference from the anonymous listener). Because if you don’t — the garbage collector might kick in quite soon and your listener won’t be called. Source: Lookup.Result garbage collection trick
See also: How to Add Content to the Global Context