Download NetBeans!

20080610 Tuesday June 10, 2008

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.

Jun 10 2008, 02:48:10 PM PDT Permalink