org.openide.awt.DropDownButtonFactory

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;

    @Override
    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);
            item.setName(name);
            item.addActionListener(menuItemListener);
            buttonGroup.add(item);
            popup.add(item);
        }

        dropDownButton = DropDownButtonFactory.createDropDownButton(
                new ImageIcon(
                new BufferedImage(32, 32, BufferedImage.TYPE_BYTE_GRAY)),
                popup);

        dropDownButton.setIcon(icon);

        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) {
                dropDownButton.setSelected(false);
            }

            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                dropDownButton.setSelected(false);
            }

            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")) {
                editor.replaceSelection(ACTIONS);
            } else if (desiredInsertion.equals("Loaders")) {
                editor.replaceSelection(LOADERS);
            } else if (desiredInsertion.equals("Menu")) {
                editor.replaceSelection(MENU);
            } else if (desiredInsertion.equals("Toolbars")) {
                editor.replaceSelection(TOOLBARS);
            } else if (desiredInsertion.equals("TopComponent")) {
                editor.replaceSelection(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" +
            "</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>\\n";
    
    String TOOLBARS =
            "<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" +
            "</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>\\n";
    
    String TOPCOMPONENT =
            "<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" +
            "</folder>\\n";

    //Unused:
    @Override
    public void performAction() {
    }

    //Unused:
    public String getName() {
        return "";
    }

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

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

}
Comments:

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

Posted by Emmanuel on March 04, 2008 at 11:11 PM PST #

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

Posted by Geertjan on March 05, 2008 at 08:50 PM PST #

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>

Posted by koike on March 26, 2008 at 10:17 PM PDT #

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?

Thanks!

Posted by N, Varun on September 16, 2008 at 10:05 PM PDT #

Hello.
I'd really apreciate your tutorial.
But, I couldn't find the lib org.openide.
Where can I find it?

Please, forgive my english...

Posted by Evandro Giachetto on February 13, 2009 at 01:14 AM PST #

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

Posted by Geertjan Wielenga on February 13, 2009 at 01:15 AM PST #

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

Posted by Evandro Giachetto on February 13, 2009 at 01:29 AM PST #

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?

Posted by Danie Palm on June 09, 2009 at 07:11 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
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
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today