See: Description
Package | Description |
---|---|
org.netbeans.api.templates |
Registration of templates and creation of new files from
them.
|
API allows to create new files based on templates. Scripting engines can be specified for processing the template, or custom Handlers may be registered to process certain templates.
A template can use places substituable with parameter values; certain well-known parameters are predefined, if the caller does not provide its custom values.
Allows the template API caller to communicate additional details or services to template handlers and decorators.
Allows to specify a handler for a template, as a counterpart to WizardIterator.
Default processing can now handle folders, will copy them recursively. Interpolates variable references in filenames.
In addition to provide CreateFromTemplateHandler
which overtakes the
template processing, CreateFromTemplateDecorator
can participate in
file creation doing pre- and post-creation tasks and edits either in the created file
or other files.
One can now create project wizards that create new projects from Maven archetypes. See the how-to for more details.
TemplateHandler may need to create additional files, using the same parameters for creation as a base. Attribute providers may need to be processed in a custom way, which requires to create and manage CreateDescriptor by the client. This change allows to clone information from CreateDescriptor into an independent FileBuilder, and to create a Descriptor out of a Builder.
The
HTML UI API for Java
revision 1.1 supports technolgy identifiers. Now they can
be used via TemplateRegistration
annotation as well.
An existing file can be used as a boilerplate for creation of a new file. The boiler plate can contain necessary skeleton, comments, content. As the boilerplate resides on config filesystem, it is also customizable by the user and the user can eventually develop custom templates.
In previous NetBeans versions, templating system was built into
Often many people require ability to create a "clever" template - e.g. write piece of simple text and at the time of its processing do some advanced changes to it using either scripting or templating languages.
This traditionally used to be a bit complicated task (hacking into DataObject implementation), however since
version 6.1 there are interface in
Runtime or project-related values may be supplied by
The CreateFromTemplateAttribute implementation knows which template is being used, where the outcome should be placed, so it can derive appropriate values for both the template and the target location.
There is a built in support for scripting languages
in the NetBeans Platform. If a template is annotated with
ScriptEngine
interface or
a String
name of the engine that is then used to
search for it in the javax.script.ScriptEngineManager
.
Usually the freemarker engine is the one that is
supported by the NetBeans IDE - if your module wants to use it
then include a token dependency OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker
in your manifest file (also accessible through project customizer GUI)
to indicate to the system that you need it.
String
representing the current day like 23. 3. 2007
String
the current time like 17:18:30
java.util.Date
representing current data and time like
String
the file encoding of the template instance
Other properties can indeed be provided by
CreateFromTemplateAttributess.
After processing, the output is also sent to appropriate
org.openide.text.IndentEngine
associated
with the mime type of the template, for formating.
Smart Templating Quick How-To
First of all create a file in your module layer located somewhere
under the Templates/
folder. Make it a template by
adding <attr name="template" boolvalue="true"/>. Associate
this template with a scripting language, for example by
<attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>.
Now make sure that the scripting language integration is also available
by requesting a token in standard format, for freemarker just put
OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker
in your manifest. This tells the NetBeans module system that a
module providing integration with such scripting engine has to be
enabled. Now you can use regular script language tags inside of
your template file. When you write your instantiate
method in your wizard, you can create a Map<String,Object> and
fill it with parameters collected from your wizard and then pass it
to
createFromTemplate(targetFolder, targetName, mapWithParameters)
. This will invoke the scripting language and make the
mapWithParameters
values available to it. Beyond this
there is few standard parameters predefined including name
, user
, date
, time
, etc.
and also additional parameters are collected from all registered
CreateFromTemplateAttributesProviders.
A CreateFromTemplateHandler should be able to create multiple files, one of them important so it will open after user initiates the creation action. The template of set of related files may be represented by a folder with a handler attached, and the operation deploys multiple files in the target directory.
There is a way to create a portable wizard (e.g. one that can
be executed inside of NetBeans as well as in a browser). The
most portable UI these days is written in HTML. To
register such HTML based wizard with your file template,
use @TemplateRegistration
annotation and include page()
attribute referencing
your own HTML page:
public class X {
@TemplateRegistration
(
page = "x.html",
scriptEngine = "freemarker",
displayName = "JS Wizard",
folder = "Other",
content = "x.fmk"
)
public static String jsWizard() {
return "yourInitializationCode();";
}
}
the return value of the annotated method (named jsWizard
)
should be of type String and its content should be snippet of
JavaScript code to execute inside of your specified HTML page
(e.g. x.html
) to create an instance of
KnockoutJS model to
drive the wizard. Here is a sample code for the model:
function yourInitializationCode() { var ok = ko.observable(false); var msg = ko.observable(''); var current = ko.observable('Init'); var data = { 'errorCode': ko.computed(function() { if ('Init' == current()) return 0; if (!ok()) return 1; if (msg()) return 0; return 2; }), 'current': current, 'ok': ok, 'msg' : msg } ko.applyBindings(data); return data; }
The model defines wizard composed of few panels (defined in following
HTML file) and a verification function (registered as errorCode
)
to check if everything is OK. In addition to that it defines
proprietary text value msg
which is
going to be filled by the wizard and cannot be empty. Each
page of the wizard is registered using a custom
Knockout.js binding called
step
. Here is an HTML page defining three steps:
<section data-bind="step: { 'id' : 'init', text : 'Initial Page'}" > <p> Write your UI in portable HTML and display it in NetBeans or on web! Read more at <a href="http://wiki.netbeans.org/HtmlUIForTemplates">our wiki</a>... </p> </section> <section data-bind="step: 'info'" > <p> Use <a href="http://knockoutjs.com">knockout.js</a> bindings to isolate your view model from the actual look of your HTML page. Bind your view to model written in Java or JavaScript. </p> <h3>Is everything OK?</h3> <input type="checkbox" data-bind="checked: ok"/> <h3>How do you feel?</h3> <input type='text' data-bind="textInput: msg"/> </section> <section data-bind="step: { 'id' : 'summary' }" > <p> You are feeling <span data-bind="text: msg"></span>! Let's proceed to create a file which will express your feeling by using <a href="http://freemarker.org/">Freemarker</a> templating engine and values filled in this wizard. </p> </section>
The Next/Finish buttons are controlled by the errorCode
property.
If it is non-zero, there is an error and these buttons are disabled.
Also once can use that inside of the HTML page to display user related errors:
<div data-bind="visible: errorCode() == 1"> <span style="color: red">Please check you are OK!</span> </div> <div data-bind="visible: errorCode() == 2"> <span style="color: red">Tell us how do you feel!</span> </div>
The L10N of the wizard is done on the level of HTML pages.
The whole page gets translated into different language with appropriate
suffix like x_cs.html
and it is then
selected instead of the default one, when user runs in such locale.
When the wizard is successfully finished, all the values
specified in the model (except system ones like current
,
errorCode
, etc.) are transfered to the templating engine,
so they can influence the content of created files.
Here is a sample x.fmt
content which reuses the msg
value provided by the wizard:
Hi, I am Freemarker. I feel ${wizard.msg}.
When such file is instantiated, the ${wizard.msg}
is
replaced by the actual value taken from the wizard.
Some people would rather use Java instead of Java script while getting the portability of the HTML. There is a simple way to rewrite the HTML and JavaScript sample to Java (and possibly run it in a plugin-less browser via bck2brwsr VM). Keep the same HTML, Freemarker, etc. files - just instead of encoding the logic in JavaScript use Java:
@Model
(className = "JavaWizard", properties = {@Property
(name = "current", type = String.class),@Property
(name = "ok", type = boolean.class),@Property
(name = "msg", type = String.class) }) public class JavaWizardCntrl {@ComputedProperty
static int errorCode( String current, boolean ok, String msg ) { if ("Init".equals(current)) return 0; if (!ok) return 1; if (msg == null || msg.isEmpty()) return 2; return 0; }@TemplateRegistration
( page = "x.html", scriptEngine = "freemarker", displayName = "HTML/Java Wizard", folder = "Java", content = "x.fmk" ) public static JavaWizard javaWizardFactory() { return new JavaWizard("Init", false, ""); } }
The return value of the annotated method is now an HTML/Java model class which can naturally represent the essential Knockout.js objects in Java.
It is very common that the HTML file creation wizards (either controled by JavaScript or by Java) need to allow user to specify target location of their file. To simplify such common task and to ensure its UI is consistent with the rest of the environment, one can just include following code snippet in the HTML file and leave its actual rendering on the system:
<section data-bind="step: 'targetChooser'" > </section>
Such section will then be replaced by a panel which provides appropriate UI for choosing target directory as well as name for the newly created file.
In case one prefers more Java-like chooser, it is possible to use
'targetChooser:java'
as name of the step. Then all
Java source groups in target project will be listed and presented
in a typical Java package view selection mode. Once can use different
suffix than java
to list other types of source groups.
This feature requires presence of org.netbeans.modules.java.project.ui
module, otherwise the target chooser falls back to classical one.
There is a way to create a portable wizard (with logic either in JavaScript or in Java) to instantiate a Maven archetype. This way one merges the project templating functionality of Maven with flexible and tailored UI provided by HTML and JS/Java.
The definition of the UI is the same as in
previous
cases, just as a target chooser
one can also use dedicated Maven one - just use
'targetChooser:archetype'
to get a panel
with options to select directory, archetypeId
,
groupId
and version
of the project to
create.
This feature requires presence of org.netbeans.api.maven
module, otherwise the target chooser falls back to classical one.
The archetype registration is then a classical one. Here is an
example of the UI being in x.html
and the archetype
described in x.archetype
one:
@TemplateRegistration
(
page = "x.html",
displayName = "HTML/Java Wizard",
folder = "Java",
content = "x.archetype"
)
public static MavenWizard mavenArchetype() {
return new MavenWizard(/*...*/);
}
The x.archetype
file describes the archetype to use
and has following properties-like syntax:
archetypeGroupId=org.codehaus.mojo.archetypes archetypeArtifactId=javafx archetypeVersion=0.6 archetypeBuild=false # or true to build the project once created archetypeOpen=src/main/java/.*/Main.java,src/main/resources/default.config # regexp to # find files that should be opened once the project is created
The values archetypeArtifactId
,
archetypeGroupId
and archetypeVersion
are by default taken from the archetype definition file, but the
wizard model can define these properties as well and in such case
they would take precedence. These values define what Maven
archetype will be used to initialized the project structure.
Any properties defined by the model (in the above example
the MavenWizard
) are going to be passed into
Maven archetype execution and can thus influence the
the behavior of the archetype - this is the way to write an
HTML UI for Maven archetype.
|
|
|
The sources for the module are in the Apache Git repositories or in the GitHub repositories.
No specific deploy dependencies.
Read more about the implementation in the answers to architecture questions.