Download NetBeans!

20070713 Friday July 13, 2007

PrintCookie (Part 1)

An extremely tricky, and potentially frustrating, area of the NetBeans Platform is the PrintCookie. Before anything else, if you do not understand what a Cookie is, in the NetBeans world, then you will be even more confused. A Cookie, simply put, is a capability. So an OpenCookie is the capability attributed to something to open the thing in question. It's like the ThinkCookie is the capability given to (some) people enabling them to think. For things that open in the editor, if you add implements PrintCookie to the class signature, you will be able to print the editor's content. In that case, things are easy and the NetBeans Platform takes care of everything. So, the Print menu item in the File menu is enabled and you don't need to do any coding at all.

However, in the case of a TopComponent and a DataObject, things are different. You need to explicitly provide the capability to print. The actual code that does the printing is just normal standard Java code, as explained in this helpful article sent to me by Tom Wheeler. However, the NetBeans Platform cannot know exactly what you want to have happen when printing a TopComponent or DataObject, hence you need to provide the code for this yourself. Including... the tricky (i.e., frustrating) part where you explicitly need to enable the Print menu item.

I'd thought about investigating this before, but yesterday the question was posed again, here in Munich. Tanja Drüke, from the GenoMatix team, needs to enable the Print menu item for a TopComponent. How to do it? There's lots of confusing and contradictory information on the mailing list on this topic. But, something written there by Craig Conover switched on the light for me: "You can create an inner class of your TC class that extends AbstractNode (or some other appropriate extension or impl of a NB Node). Then you can set this as the active Node and provide it with the appropriate CookieActions and such."

That right there is the crucial piece of information. Cookies are capabilities of Nodes. You need a Node in order to be able to assign the Print capability. Therefore, you need to create a Node in the TopComponent especially for this purpose:

private class MyPrintNode extends AbstractNode {
    public MyPrintNode() {
        super(Children.LEAF);
        CookieSet cookies = getCookieSet();
        cookies.add(new MyPrintCookie());
    }
}

Note that a class called MyPrintCookie is added to the CookieSet above. In other words, the capability provided by my MyPrintCookie class is added to the set of capabilities assigned to the Node. That class must implement PrintCookie, which has one mandatory method, called print(). Here is the simplest (and least meaningful) definition:

class MyPrintCookie implements PrintCookie {
    public void print() {
        JOptionPane.showMessageDialog(null, "Printing...");
        //Put all the standard Java printing code here!
    }
}

And, finally, you need to associate the Node with the TopComponent's Lookup. In other words, you need to add the Node to the TopComponent's bag of tricks. So put this in the constructor, probably at the end, but possibly anywhere:

associateLookup(new MyPrintNode().getLookup());

And now the Print menu item is enabled. And when you select the Print menu item, the MyPrintCookie.print() method above is called. But, what if we're dealing with a DataObject instead of a TopComponent? Tom Wheeler wrote to say that one would have a MyPrintCookie class, like the above, and then add an instance of it to the DataObject's Lookup (or CookieSet, depending on which one you are using). Then, again, the print() method is invoked when the enabled menu item is selected.

As always, everything I've said above could be totally wrong, partially wrong, or brilliantly and surprisingly on the ball. So, use at your very own risk.

Jul 13 2007, 09:09:15 AM PDT Permalink