Monday Oct 06, 2008

Custom Toolbar Loaded via Lookup

Let's say you want the toolbar to be on the right side of your application. Let's also say that you want the icons to be larger than 16x16 or 24x24. At the same time, you want to use the NetBeans Actions system, so you can't simply create a TopComponent and then put buttons on the TopComponent. How to solve this problem? Use Lookup! Here's how the result looks for me:

First, I removed all the existing toolbars, by simply adding this to the layer:

<file name="Toolbars_hidden"/>

So, now the toolbars were all gone when I ran the application. Then I created a new TopComponent. I also created a new mode specifically for the TopComponent, to position it along the right side of the application.

Next, I exposed my CallableSystemActions via the META-INF/services technique:

This is the complete content of the file in META-INF/services:

org.nb.customtoolbar.Action1
org.nb.customtoolbar.Action2
org.nb.customtoolbar.Action3
org.nb.customtoolbar.Action4
org.nb.customtoolbar.Action5

Each of the actions looks as follows:

public final class Action1 extends CallableSystemAction {

    @Override
    public void performAction() {
        JOptionPane.showMessageDialog(null, "hello from 1");
    }

    @Override
    protected String iconResource() {
        return "/org/nb/customtoolbar/pic1.png";
    }

    @Override
    public String getName() {
        return "rightSideToolBar";
    }

    @Override
    public HelpCtx getHelpCtx() {
        return HelpCtx.DEFAULT_HELP;
    }

    @Override
    protected boolean asynchronous() {
        return false;
    }

}

The only interesting thing is the getName(). I use that to determine whether or not the action should be displayed in the TopComponent. And how are they displayed in the TopComponent? Like this:

private CustomToolbarDisplayerTopComponent() {

    initComponents();
    
    //Here we iterate over implementations of 'CallableSystemAction':
    for (CallableSystemAction action : Lookup.getDefault().lookupAll(CallableSystemAction.class)) {
        //We're only interested in an implementation if it has the right name and an icon:
        if (action.getName().equals("rightSideToolBar") && action.getIcon() != null) {
            //Then we add a new button to the JPanel:
            addButton(action, jPanel1);
        }
    }

}

private static void addButton(final CallableSystemAction action, JPanel container) {
    JButton button = new JButton();
    button.setAlignmentX(Component.CENTER_ALIGNMENT);
    //The icon is set by calling 'getIcon' on the implementation:
    button.setIcon(action.getIcon());
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            //The action is performed by calling 'actionPerformed' on the implementation:
            action.actionPerformed(e);
        }
    });
    container.add(button);
}

And that's all! The TopComponent is in a different module to where the actions are found; there is no direct dependency on them, only on the CallableSystemAction class. And my toolbar is pluggable because anyone can add their own module that implements CallableSystemAction. All that's needed is for their implementation to include the correct name and an icon and then the additional toolbar button will be loaded. Currently, it will be loaded upon restart. But I could add a LookupListener that would detect whenever a new module fitting the requirements is available, at which point the toolbar button would be loaded at runtime.

One potential problem will occur when the user drags the TopComponent to a different position. Potentially the images will then need to be reorganized, so that they're horizontal when they're in a horizontal mode. But apart from that, I think this is a good solution.

About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« October 2008 »
SunMonTueWedThuFriSat
   
2
7
8
11
12
20
24
25
27
31
 
       
Today