In the following sections, we will create a simple wizard as an example, which will support either creating a simulation (complete with NED and INI files), or just a single NED file with a network defined in it. The user will be able to specify the type and the number of the submodules the network contains.
The first step when creating a wizard is to create a new folder
under the templates
directory of the project. A file named template.properties
must be present in the newly created directory. This file is used to configure
the wizard. Create a folder a folder named templates/examplewizard
under the
project, then create template.properties
and add the following lines to it:
templateName = New Test Wizard templateDescription = Generate an example templateCategory = Test Wizards supportedWizardTypes = simulation, network
These lines specify the name, type and category for the wizard. Category is used to
specify how the wizards will be grouped in the tree control section of the template selection page.
Wizard type specifies in which New … Wizard your wizard will appear.
You can specify one or more of project
, simulation
, network
, etc.; the list
of all possible wizard types will be covered later in this document. In this case,
the wizard will appear in the New Simulation and New Network wizard dialogs.
You can now decide what data you would like to ask the user to provide. Template variables and their values can be defined as key-value pairs:
nodeType = Dummy networkSize = 6
The nodeType
variable will be used as the submodule type in your network, while
the networkSize
defines how many submodules you want in the network.
We define a custom wizard page where the user can specify the values of the above variables (i.e. override their default value, specified above).
page.1.file = parameters.xswt page.1.title = Network parameters
We will use the file parameters.xswt
to define the layout and the content of the new wizard page.
There are numerous other configuration keys that can be used in template.properties
. See the
"Configuration Keys" section for an exhaustive list of options.
Files with .xswt
extension (Wizard Page definitions) are used to define the UI and
add new wizard pages to gather user input for template generation. In the previous
section, we specified that the file called parameters.xswt
will contain the new
wizard page definition. We will add a spinner control to specify the size of our network
and a text control to specify the node type. Create a new file called parameters.xswt
with the following content:
<xswt xmlns:x="http://sweet_swt.sf.net/xswt"> <x:import> <!-- Import all widgets and utility classes --> <package name="java.lang"/> <package name="org.eclipse.swt.widgets" /> <package name="org.eclipse.swt.graphics" /> <package name="org.eclipse.swt.layout" /> <package name="org.eclipse.swt.custom" /> <package name="org.omnetpp.common.wizard.support" /> <package name="org.omnetpp.ned.editor.wizards.support" /> <package name="org.omnetpp.cdt.wizard.support" /> </x:import> <!-- Create a two-column layout --> <layout x:class="GridLayout" numColumns="2"/> <x:children> <!-- First row --> <label text="Number of nodes in the network:"/> <spinner x:id="networkSize" minimum="2" x:style="BORDER"/> <!-- Second row --> <label text="Type of nodes:"/> <text x:id="nodeType" x:style="BORDER"/> </x:children> </xswt>
The above defined wizard page will have two columns. The first column contains labels
and the second contains editable widgets.
The x:id="varName"
attributes in the spinner and text control definitions are used
to bind a template variable to the control. When a page is displayed, the content of
the bound variables are copied into the controls. When the user navigates away from
the page or presses the Finish button, the content of the controls are copied back
to the bound variables. These variables can be used in the template files we are
about to define in the following section.
To see the list of all available widgets, check the Appendix.
When the template is used, the contents of the template folder (and its subfolders)
will be copied over into the new project, thus preserving the directory structure
with the exception of template.properties
(it is also possible to specify
other files and folders to be ignored by specifying a file list for the
ignoreResources
configuration key).
When the wizard is being used, a pool of variables is kept by the wizard dialog.
These variables are initialized from the key = value
lines in the
template.properties
files; they can get displayed and/or edited
on custom wizard pages. Eventually, they get substituted into *.ftl
files
(using the ${varname}
syntax).
Some variables have special meaning and are interpreted by the wizard dialog
(e.g. the nedSrcFolders
variable determines which folders get denoted as
NED Source Folders by the New OMNeT++ Project wizard). Variables can be used
to generate output file names, can be used as input file names, and can serve
as input and working variables for arbitrarily complex algorithms programmed
in the template (*.ftl
) files.
Let us have a quick look at the FreeMarker template language.
Variables can be inserted into the output using the ${varname}
syntax. One can
also write expressions inside ${..}
. For example, ${numServers?number + 1}
uses the number
built-in operator to convert the numServers
variable to a number,
adds one to it, and inserts the result into the template output. FreeMarker
has many other functions (conversion to string, upper-case version of a string,
size of an array, etc.) that work as built-in operators.
Programming facilities can be accessed via directives that have the <#...>
syntax.
Use <#if>
(<#if> cond>..<#elseif cond>..<#else>..</#if>
) for conditionals;
<#list>
for iterations and loops (e.g. <#list words as w>..</#list>
;
<#list 0..9 as i>..</#list>
; <#list 9..0 as i>..</#list>
); and
<#assign>
for assigning variables (<#assign x=5>
; <#assign x>the number ${i}</#assign>
).
One can define functions (<#function>
) and macros (<#macros>
). You can also include
other templates (<#include>
). Here, we only covered a small fraction of FreeMarker’s
possibilities; we recommend that you read the FreeMarker manual for more information.
Let us create a file with a filename that has an .ftl
extension (e.g. untitled.ned.ftl
).
Because of the extension, this file will be processed by the templating engine.
The actual name of the file does not matter, because the
<@setoutput .../>
directive instructs the templating engine to output
everything from the current file into the file that is specified by the
targetFileName
variable. The targetFileName
, targetTypeName
, bannerComment
and nedPackageName
variables are automatically filled out by the wizard, based
on the filename and folder the user selected on the first wizard page.
<@setoutput path=targetFileName /> ${bannerComment}
<#if nedPackageName!="">package ${nedPackageName};</#if>
network ${targetTypeName} { node[${networkSize}] : ${nodeType} }
The template variables will be substituted into the template automatically.
Specific wizard dialog types will also define extra variables for use in the
templates. For example, the wizard type that creates a complete simulation (with all required files)
will put the simulationName
variable into the context. To see all defined variables,
check the Appendix.
The New Wizard wizard in the IDE provides you with some working examples, useful utilities for writing wizards, and sample code for accessing various features along with other helpful information. The aim of these wizards is to help you become productive in the shortest time possible.
As a last step in our example, we will also create an INI file template:
Create a file called omnetpp.ini.ftl
, and fill with:
<#if wizardType=="simulation"> network = ${targetTypeName} </#if>
We need the INI file only if we are creating a simulation. If the
current type is not simulation
, the content will be empty, and the
file will not be written to the disk.