Code for Rerun DropDownButtonFactory

I made some serious progress with my redeploy plugin today. Since it was inspired by Gareth Uren, who liked this functionality in Eclipse and misses it in NetBeans IDE, I decided I should try to make it as similar as possible to how it works in Eclipse. So, here it is, no longer in a separate window, but using the NetBeans org.openide.awt.DropDownButtonFactory class:

Let's step through the code required for this functionality. First, I have extended org.apache.tools.ant.module.spi.AntLogger, which is exposed in META-INF/services, in a file called "org.apache.tools.ant.module.spi.AntLogger":

public class StoreDeployedApps extends org.apache.tools.ant.module.spi.AntLogger {

    @Override
    public boolean interestedInSession(AntSession session) {
        return true;
    }

    @Override
    public boolean interestedInAllScripts(AntSession session) {
        return true;
    }

    @Override
    public String[] interestedInTargets(AntSession session) {
        return AntLogger.ALL_TARGETS;
    }

    @Override
    public void targetStarted(AntEvent event) {
        BufferedReader br = null;
        try {
            //Get the build-impl.xml:
            File buildImplXML = event.getScriptLocation();
            //From the build-impl.xml parent, get the project.xml:
            File projectXML = new File(buildImplXML.getParentFile(), "project.xml");

            String targetName = event.getTargetName();
            String projectName = null;
            String projectType = null;
            
            //Read the Dom and figure out the project name and type,
            //where the type is a string like "org.netbeans.modules.java.j2seproject":
            InputSource source = new InputSource(new FileInputStream(projectXML));
            org.w3c.dom.Document doc = XMLUtil.parse(source, false, false, null, null);
            org.w3c.dom.NodeList nodeList = doc.getElementsByTagName("\*");
            int length = nodeList.getLength();
            for (int i = 0; i < length; i++) {
                org.w3c.dom.Node currentNode = nodeList.item(i);
                String nodeName = currentNode.getNodeName();
                if ("name".equals(nodeName)){
                    projectName = currentNode.getTextContent();
                }
                if ("type".equals(nodeName)){
                    projectType = currentNode.getTextContent();
                }
            }
        
            //If the target name is run, send the build-impl.xml, the project name,
            //and the project type to our action class:
            if (targetName.equals("run")) {
                ListDeployedAppsAction.setProjectNames(buildImplXML, projectName, projectType);
            }
            
        } catch (SAXException ex) {
            Exceptions.printStackTrace(ex);
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        } finally {
            try {
                br.close();
            } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
    }

    @Override
    public void targetFinished(AntEvent event) {
    }
    
}

And here's the action class, which is registered in the layer.xml file, just like any other action class that we want to be able to invoke from a toolbar button:

public class ListDeployedAppsAction extends CallableSystemAction {

    private static JButton dropDownButton;
    private static JPopupMenu popup;
    static JMenu menu;
    
    static void setProjectNames(File buildImplXML, String projectName, String projectType) {

        Image icon = null;

        if (projectType.equals("org.netbeans.modules.java.j2seproject")) {
            icon = Utilities.loadImage("/org/netbeans/modules/java/j2seproject/ui/resources/j2seProject.png");
        } else if (projectType.equals("org.netbeans.modules.web.project")) {
            icon = Utilities.loadImage("/org/netbeans/modules/web/project/ui/resources/webProjectIcon.gif");
        } else {
            icon = Utilities.loadImage("/org/netbeans/modules/project/ui/resources/runProject.png");
        }

        ImageIcon image = new ImageIcon(icon);

        menu = new JMenu();
        JMenuItem subItemRun;

        menu.setIcon(image);
        menu.setText(projectName);

        subItemRun = new JMenuItem("Run \\"" + projectName + "\\" again");
        subItemRun.addActionListener(new RunActionListener(buildImplXML));
        menu.add(subItemRun);

        popup.add(menu);

    }

    static class RunActionListener implements ActionListener {

        File file;

        public RunActionListener(File file) {
            this.file = file;
        }

        public void actionPerformed(ActionEvent e) {
            try {
                ActionUtils.runTarget(FileUtil.toFileObject(file), new String[]{"run"}, new Properties());
            } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
            } catch (IllegalArgumentException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
    }

    @Override
    public Component getToolbarPresenter() {

        Image iconImage = Utilities.loadImage("/org/netbeans/modules/project/ui/resources/runProject.png");
        ImageIcon icon = new ImageIcon(iconImage);

        popup = new JPopupMenu();

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

        dropDownButton.setIcon(icon);

        return dropDownButton;

    }

    @Override
    public void performAction() {
    }

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

    @Override
    public HelpCtx getHelpCtx() {
        return null;
    }
    
}

That's it. Next I need to add a submenu item for removing menu items. Maybe also a configuration dialog for tweaking the launch configurations that are registered in the list. By the way, in the process of moving my code from a window to a dropdown button factory, I was able to improve my code in several ways. Refactoring rocks. It really lets you look at your old code afresh.

Comments:

That's seriously cool, gonna give it a spin right away. Glad to see NetBeans is starting to use DropDownButton's rather than JComboBox'es.

Posted by Casper Bang on June 10, 2008 at 10:49 AM PDT #

Your code will throw errors if the user ever runs any build script that is not the principal script of an Ant-based project. Anyway it is too much work. Scrap the parsing of project.xml. Just use FileOwnerQuery to find the owning project (if any) and use ProjectUtils.getInformation to find its display name and icon. Also interestedInTargets() should return just "run" if that is in fact all you are interested in; anyway targetStarted should return quickly if it is not a relevant target.

Posted by Jesse Glick on June 10, 2008 at 01:27 PM PDT #

Jesse, thanks a lot again. I'll investigate these things for sure.

Posted by Geertjan on June 11, 2008 at 02:30 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
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today