Geertjan's Blog

  • March 5, 2008


Geertjan Wielenga
Product Manager
I was learning about org.openide.awt.DropDownButtonFactory yesterday, because of the cool Profiler drop-down buttons in the IDE's toolbar. I assumed they came from some private package and that I'd have to hack the code somehow but then discovered org.openide.awt.DropDownButtonFactory and the fact that it is publicly available and has been that way for a while already. I then came across Vadiraj's excellent blog entry on this topic and his reference to the FAQ How do I add a drop-down menu to a toolbar button?

Armed with all those fine resources, I made my first DropDownButton. Then I wanted to do something practical and thought of all the times where I've known the NetBeans API classes I needed but not the layer entries for registering them. And that I'd then go through a wizard for no other reason than that I wanted the layer entries. And at some point you've got all your dependencies set, so the wizard isn't helpful for you then either. The one and only reason you're going through a wizard is to get the layer entries, also because of some strangeness like the fact that sometimes packages are separated by a hyphen and other times by a dot and you can never remember which is which.

So I created a new plugin that presents you with a DropDownButton with items representing a few of the key elements in the layer file. When you select one, some basic stubs are created in the layer file, as you can see below, the illustration showing the exact tags generated for the selected item:

Several enhancements are imaginable, such as having the items loaded from the user directory and letting the user register new items there via the Options window. Also the tags could be smarter and detect the class names and so on. But for now, and also because my focus wasn't this functionality but learning about the DropDownButton, it does the job fine.

Here's all the code, which will be extremely useful if you like DropDownButtons too:

package org.netbeans.modules.layerreg;
import java.awt.Component;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.text.JTextComponent;
import org.netbeans.api.editor.EditorRegistry;
import org.openide.awt.DropDownButtonFactory;
import org.openide.util.HelpCtx;
import org.openide.util.Utilities;
import org.openide.util.actions.CallableSystemAction;
public class LayerRegistrationAction extends CallableSystemAction {
private static JButton dropDownButton;
private static ButtonGroup buttonGroup;
private static JPopupMenu popup;
private MyMenuItemListener menuItemListener;
public Component getToolbarPresenter() {
Image iconImage = Utilities.loadImage("org/netbeans/modules/layerreg/icon.png");
ImageIcon icon = new ImageIcon(iconImage);
popup = new JPopupMenu();
menuItemListener = new MyMenuItemListener();
buttonGroup = new ButtonGroup();
String[] names = {"Actions", "Loaders", "Menu", "TopComponent", "Toolbars"};
for (int i = 0; i < names.length; i++) {
String name = names[i];
JCheckBoxMenuItem item = new JCheckBoxMenuItem(name);
dropDownButton = DropDownButtonFactory.createDropDownButton(
new ImageIcon(
new BufferedImage(32, 32, BufferedImage.TYPE_BYTE_GRAY)),
dropDownButton.setToolTipText("Insert Layer Registration");
dropDownButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
int state = e.getStateChange();
if (state == ItemEvent.SELECTED) {
/\*\* show popup menu on dropdown button at position: (0, height) \*/
popup.show(dropDownButton, 0, dropDownButton.getHeight());
popup.addPopupMenuListener(new PopupMenuListener() {
public void popupMenuCanceled(PopupMenuEvent e) {
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
return dropDownButton;
private class MyMenuItemListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
JMenuItem item = (JMenuItem) ev.getSource();
String desiredInsertion = item.getName();
JTextComponent editor = EditorRegistry.lastFocusedComponent();
if (desiredInsertion.equals("Actions")) {
} else if (desiredInsertion.equals("Loaders")) {
} else if (desiredInsertion.equals("Menu")) {
} else if (desiredInsertion.equals("Toolbars")) {
} else if (desiredInsertion.equals("TopComponent")) {
String ACTIONS =
"<folder name=\\"Actions\\">\\n" +
" <folder name=\\"MyCategory\\">\\n" +
" <file name=\\"org-bla-bla-bla-MyOneAction.instance\\"/>\\n" +
" <file name=\\"org-bla-bla-bla-MyTwoAction.instance\\"/>\\n" +
" </folder>\\n" +
" <folder name=\\"MyOtherCategory\\">\\n" +
" <file name=\\"org-bla-bla-bla-MyOtherAction.instance\\"/>\\n" +
" </folder>\\n" +
String MENU =
"<folder name=\\"Menu\\">\\n" +
" <folder name=\\"MyMenu\\">\\n" +
" <file name=\\"MyAction.shadow\\">\\n" +
" <attr name=\\"originalFile\\" stringvalue=\\"Actions/MyCategory/org-bla-bla-bla-MyAction.instance\\"/>\\n" +
" </file>\\n" +
" </folder>\\n" +
"<folder name=\\"Toolbars\\">\\n" +
" <folder name=\\"MyToolbar\\">\\n" +
" <attr name=\\"SystemFileSystem.localizingBundle\\" stringvalue=\\"org.bla.bla.Bundle\\"/>\\n" +
" <file name=\\"org-bla-bla-bla-MyAction.instance\\">\\n" +
" <attr name=\\"SystemFileSystem.localizingBundle\\" stringvalue=\\"org.bla.bla.Bundle\\"/>\\n" +
" <attr name=\\"position\\" intvalue=\\"400\\"/>\\n" +
" </file>\\n" +
" </folder>\\n" +
String LOADERS =
"<folder name=\\"Loaders\\">\\n" +
" <folder name=\\"text\\">\\n" +
" <folder name=\\"x-mime\\">\\n" +
" <folder name=\\"Actions\\">\\n" +
" <file name=\\"org-openide-actions-CopyAction.instance\\">\\n" +
" <attr name=\\"position\\" intvalue=\\"500\\"/>\\n" +
" </file>\\n" +
" </folder>\\n" +
" </folder>\\n" +
" </folder>\\n" +
"<folder name=\\"Windows2\\">\\n" +
" <folder name=\\"Components\\">\\n" +
" <file name=\\"MyTopComponent.settings\\" url=\\"MyTopComponentSettings.xml\\"/>\\n" +
" </folder>\\n" +
" <folder name=\\"Modes\\">\\n" +
" <folder name=\\"MyMode:-editor-or-explorer-or-properties-etc\\">\\n" +
" <file name=\\"MyTopComponent.wstcref\\" url=\\"MyTopComponentWstcref.xml\\"/>\\n" +
" </folder>\\n" +
" </folder>\\n" +
public void performAction() {
public String getName() {
return "";
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
protected boolean asynchronous() {
return false;

Join the discussion

Comments ( 8 )
  • Emmanuel Wednesday, March 5, 2008

    I've played around with the DropDownButtonFactory for few weeks right now and I found something embarrassing.

    I use a DropDownButton with an arrow to navigate Back and Forth in a browser. Unfortunatly, there is no possibility on a JButton (returned by DropDownButtonFactory) to know if the use clicked on the button itself or on the small arrow.

    My solution: Copy the code of org.openide.awt.DropDownButton and set method isInArrowArea() public

    Then it is easy in the mouseClicked listener to know what part of the button was clicked exactly

  • Geertjan Thursday, March 6, 2008

    Thanks Emmanuel, very interesting. I passed this info on to the responsible engineer.

  • koike Thursday, March 27, 2008

    1155<a href='http://butbaker.ks-muryoukoukoku.com/' target='_blank'>butbakerアクセスアップステーション</a><br>

    1156<a href='http://www.k-sogolinknow.com/' target='_blank'>検索サイト上位、総合リンクnow</a><br>

    1157<a href='http://sheep.k-sogolinknow.com/' target='_blank'>sheep総合リンクnow</a><br>

  • N, Varun Wednesday, September 17, 2008

    Nice tutorial...

    I have one question, whats the use of having ButtonGroup? After adding items into it, the code is not using it anywhere..

    Also, like Antonio asked today on mailing lists..Can we make it Context Aware?


  • Evandro Giachetto Friday, February 13, 2009


    I'd really apreciate your tutorial.

    But, I couldn't find the lib org.openide.

    Where can I find it?

    Please, forgive my english...

  • Geertjan Wielenga Friday, February 13, 2009

    It's part of the NetBeans Platform. Download NetBeans IDE and you will have it for free.

  • Evandro Giachetto Friday, February 13, 2009

    I'm trying to make an import to that package, but the netbeans can't find it.

    is that correct?

  • Danie Palm Tuesday, June 9, 2009

    When one adds text to the button, the arrow curiously appears in the centre of the button. I would like this order of appearance: Icon, text, arrow. I could live with: Icon, arrow, text, but then at least clicking on the arrow should show the popup, instead one still has to click near the right edge of the button.

    Any ideas?

Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.