I need to add-to/remove-from/customize the content of my Node/DataObject/TopComponent’s Lookup. How do I do it?
If it’s just adding something, use
return new ProxyLookup(
new Lookup[] {
super.getLookup(),
Lookups.fixed(
something, somethingElse)
});
If there’s only one object, substitute Lookups.singleton ( someObject )
.
If you need to change the content of the lookup on the fly, it’s a little more complicated, but not too much. Use the above
ProxyLookup technique if there’s a Lookup returned by the superclass and you still want to use its content.
What you’ll use to change content on the fly is the combination of AbstractLookup
(which, as fate would
have it, is not actually abstract), and InstanceContent
, which is a grab bag of stuff you can add to and
remove from.
The result will look something like this:
class MyNode extends AbstractNode {
private final InstanceContent lookupContents;
public MyNode() {
this(new InstanceContent());
}
private MyNode(InstanceContent ic) {
super(Children.LEAF, new AbstractLookup(ic));
this.lookupContents = ic;
}
}
When you need to change the contents of your lookup, you can call InstanceContent.add()
or and InstanceContent.remove()
, e.g.:
lookupContents.add(someObject);
lookupContents.remove(someObject);
Your lookup will be updated to include all items in the InstanceContent.
Custom Lookup Contents with DataObjects
DataObjects have a Lookup, but also use an older variant on the Lookup pattern, called a CookieSet
. Since this is a somewhat bewildering term, and CookieSet
will eventually be deprecated, you may want to avoid using it. A CookieSet
ordinarily provides the Lookup
for a DataObject; and certain APIs such as DataEditorSupport
require it.
However, it is possible to work with the more modern idioms of Lookup as described above, with a few caveats. Such a DataObject typically looks like:
public class FooDataObject extends MultiDataObject {
private final Lookup lookup;
private final InstanceContent lookupContents = new InstanceContent();
public FooDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
super(pf, loader);
lookup = new ProxyLookup(getCookieSet().getLookup(), new AbstractLookup(lookupContents));
lookupContents.add (...whatever...);
}
@Override
public Lookup getLookup() {
return lookup;
}
@Override
protected Node createNodeDelegate() {
return new DataNode (this, Children.LEAF, getLookup());
}
//...
You can then add and remove objects from your InstanceContent
and the DataObject
will behave as expected.
Caveat 1: You really must override createNodeDelegate()
or otherwise (in your DataNode
subclass) pass your DataObject’s `Lookup
to your DataNode’s constructor. Otherwise its lookup will be `getCookieSet().getLookup()
and nothing added to your InstanceContent
will appear in the Lookup
of your Node
. So, if you use AbstractLookup in a DataObject, make sure its Node is really using your DataObject’s Lookup.
Caveat 2: A DataObject should always appear in its own Lookup — If you are really sure that nothing is going to use your DataObject’s `CookieSet
at all, you can omit merging getCookieSet().getLookup()
into the ProxyLookup
in the constructor. However, many things will not work correctly if the DataObject itself cannot be found in its own Lookup
. If you are going to do that, replace getCookieSet().getLookup()
with Lookups.singleton(this)
to ensure it is present and cannot be removed or replaced.