I need to add-to/remove-from/customize the content of my Node/DataObject/TopComponent’s Lookup. How do I do it?

Apache NetBeans Wiki Index

Note: These pages are being reviewed.

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.