Multiple Files from a Single Wizard

The question of the day comes from Børre Lervåg Dalhaug, a Systems Engineer from Offshore Simulator Center in Norway. (Speaking of offshore and Norway, take a look at what Marine Cybernetics in Norway is doing offshore with the NetBeans Platform.)

Børre needs to create multiple files from a single wizard in NetBeans IDE. Each file is defined via a FreeMarker template. The topic of FreeMarker has been widely discussed in this blog, as well as in the File Template Tutorial. But let's now focus on creating MULTIPLE files from a single wizard.

First, we need to register the templates, in this case, two of them:

<folder name="Templates">
    <folder name="Special">
        <file name="newFile1.java" url="newFileNo1.ftl">
            <attr name="SystemFileSystem.icon" urlvalue="nbresloc:/no/myfirm/filetemplates/icon.png"/>
            <attr name="displayName" bundlevalue="no.myfirm.filetemplates.Bundle#Templates/Special/newFile"/>
            <attr name="instantiatingIterator" newvalue="no.myfirm.filetemplates.NewFileWizardIterator"/>
            <attr name="template" boolvalue="true"/>
            <attr name="templateWizardURL" urlvalue="nbresloc:/no/myfirm/filetemplates/newFile.html"/>
            <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
        </file>
        <file name="newFile2.java" url="newFileNo2.ftl">
            <attr name="template" boolvalue="true"/>
            <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
        </file>
    </folder>
</folder>

In the above, only the "newFile2.java" file is interesting, the rest is straight from the tutorials and elsewhere.

So, now the question is, how to make use of both of the above file registrations? In the "instantiate()" method, use the above code as follows, assuming you've set up the classes such that a "var1" variable is returned from the wizard:

@Override
public Set instantiate() throws IOException {

    //Prepare the arguments for passing to the FreeMarker template:
    String var1 = (String) wizard.getProperty(NewFileVisualPanel1.VAR1);
    Map args = new HashMap();
    args.put("var1", var1);

    //Get the first template and convert it:
    FileObject firstTemplate = Templates.getTemplate(wizard);

    //Find the second template, based on the first, and convert it:
    FileObject secondTemplate = firstTemplate.getParent().getChildren()[1];

    DataObject dTemplate1 = DataObject.find(firstTemplate);
    DataObject dTemplate2 = DataObject.find(secondTemplate);

    //Get the package:
    FileObject dir = Templates.getTargetFolder(wizard);
    DataFolder df = DataFolder.findFolder(dir);

    //Get the names of the file:
    String targetName1 = Templates.getTargetName(wizard);
    String targetName2 = secondTemplate.getName();

    //Define the templates from the above,
    //passing the package, the file name, and the map of strings to the template:
    dTemplate1.createFromTemplate(df, targetName1, args);
    dTemplate2.createFromTemplate(df, targetName2, args);

    //Doesn't really make a difference what you return here,
    //the work is already done in the lines above.
    return Collections.EMPTY_SET;

}

That's all. Now you have two files created via a single wizard.

Comments:

SystemFileSystem.icon should be replaced by iconBase, and templateWizardURL by instantiatingWizardURL.

FileObject.getChildren returns results in no defined order; you cannot simply assume that children[1] is anything in particular.

I do not recommend mixing up the instantiatingIterator definition with (one of) the actual file templates; this is just confusing. Create an empty placeholder file for the wizard (template=true), and two layer entries for the template files (template=false or simply unspecified, because you do not want them to appear separately in the New metawizard). Of course the two template files do not necessarily have to appear in your layer at all; you might make them in a temporary FileUtil.createMemoryFileSystem with contents loaded e.g. using Class.getResource; or you can directly create the target files (using FileUtil.createData rather than DataObject.createFromTemplate) from content of your choice, optionally using ScriptEngine. Registering them in the layer is mainly useful because it permits users to customize the templates in the Tools > Templates dialog.

You should return the created Set<DataObject>. It does matter because the project system infrastructure can use this information to e.g. display and select newly created files.

Posted by Jesse Glick on February 09, 2011 at 12:13 AM PST #

Could you post an update to this, based on netbeans new method for registering templates?
It now uses the package-info.java file to automatically generate the layer.xml file, and I haven't been able to determine what should be put in the package-info.java file to mimic the behaviour described here.

Posted by Josh on April 12, 2013 at 01:18 PM 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
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today