Geertjan's Blog

  • February 9, 2011

Multiple Files from a Single Wizard

Geertjan Wielenga
Product Manager
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 name="newFile2.java" url="newFileNo2.ftl">
<attr name="template" boolvalue="true"/>
<attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>

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:

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.

Join the discussion

Comments ( 2 )
  • Jesse Glick Wednesday, February 9, 2011

    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.

  • Josh Friday, April 12, 2013

    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.

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