X

Geertjan's Blog

  • June 10, 2008

Code for Rerun DropDownButtonFactory

Geertjan Wielenga
Product Manager
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.

Join the discussion

Comments ( 3 )
  • Casper Bang Tuesday, June 10, 2008

    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.


  • Jesse Glick Tuesday, June 10, 2008

    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.


  • Geertjan Wednesday, June 11, 2008

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


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