{{ !articles[0].partner.isSponsoringArticle ? "Platinum" : "Portal" }} Partner

Reusing NetBeans Plug-ins in Standalone Apps and in the IDE

I just spent some time on the phone with Jaspersoft. They have an interesting use case for NetBeans: They are both providing a NetBeans plug-in and a standalone iReport designer tool based on the NetBeans Platform. This is eminently doable, but I don't think there's been much talk about the tips and tricks for doing it. Here are some:

  • Separate UI Registration from Code - The NetBeans IDE does this with the Core UI module. Basically, you're going to want a different set of menus and toolbars in a standalone application. Probably a lot of the actions are going to be the same code in either place. So just put the action code in one module that depends on whatever it needs to call; put the actual registration of that code into the layer file of another module that depends on the one(s) that implement the actions. Then have one version of this module for the IDE and a different one for the standalone app.
  • Abstract dependencies on IDE modules - For example, the New Report Wizard in the IDE should let the user choose classes from the current project. The standalone report designer doesn't even have a concept of projects, and the Project API isn't there - but the user should be able to choose some files. The solution to this can be as simple as creating an API module with an interface such as
    public interface FileChooserPanelProvider {
    public JComponent getComponent();
    public Iterable<File> getSelectedFiles();
    public void addChangeListener(ChangeListener cl);
    public void removeChangeListener(ChangeListener cl);

    In the IDE version there is a module that will implement this interface and put it in the default Lookup. That implementation will use the Projects API. In the standalone version, a different module does the same thing and just provides a file chooser or similar. Poof! Dependency broken. The New Report Wizard will call
    and get the instance injected by whichever module is present.
  • If your editor needs lots of menus, add/remove on the fly - Now, many user interface experts will tell you that menu items and toolbars in an application should remain fixed, and not appear and disappear on the fly. Largely they are right. But in the case of something like an embedded image editor or a reporting tool, where you have a huge amount of customizability (fonts, colors, styles, etc.), it may be the only way to solve the problem without having your plug-in take up a huge amount of UI real estate when the majority of the time, it is not really being used. Fortunately NetBeans provides a way to handle this. Normally menu items and toolbars and other UI components are registered in the system filesystem via a layer file. But you can also add and remove layers from the system filesystem dynamically:
    • Create a subclass of MultiFileSystem
    • Register it in the default lookup by putting a flat file in your plug-in's JAR file in the
    • Find it at runtime via
      . Make a new XML Filesystem pointed at another layer file that registers the items you want to appear. Add/remove it from your MultiFileSystem to make the items it registers appear and disappear.
  • Replace the global selection model - Selection (action enablement, property sheet content, etc.) in the NetBeans IDE is based on which logical window has focus. The selection is represented as (yes), a Lookup - a thing like a map where the keys are Class objects and the values are one or more instances of that class, and to which you can subscribe for notification of changes in the set of instances of a given type. I blogged about a year ago about how applications which need a more Photoshop-style selection model (the active editor owns selection, everything else is a palette or something that responds to the editor's selection). Your actions work the same way in the IDE or the standalone platform app - but the feel of the application is what makes sense for each one.
{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks