Netbeans模板,用于创建多个文件

时间:2014-02-06 17:02:50

标签: java netbeans javafx-2 freemarker wizard

一般来说,我想创建一个创建多个文件的Netbeans(7.4)文件向导。

在我的情况下,我希望它在加载fxml文件时创建JavaFX相关文件以使用约定优于配置方法。 (我从Adam Bien那里接过了这个想法:http://www.youtube.com/watch?v=mawFd4h1Or4

更具体:我想输入一个定义Basename的字符串,并希望向导创建3个不同的文件,位于Rightclick - >的包中。用户调用了“新建”向导。

  1. Basename.fxml
  2. BasenameController.java
  3. BasenameView.java
  4. 我现在尝试编写自己的向导近3天,但它无法正常工作。我研究过(瘦)Netbeans API并仔细阅读所有这些教程(及更多):

    我尝试了更多的东西然后我可以在这里列举,但这些是一些令人满意的事情:

    • 我从来没有使用过单个@TemplateRegistration和多个content条目。
    • 所以我使用@TemplateRegistrations注册了多个模板,每个我想要创建的文件都有一个模板。
    • 这会创建多个文件,但只有第一个文件具有正确的属性,例如为freemarker脚本设置的$ {package}。 (另外这种方式我最终得到了多个模板......但我可以忍受它。)
    • 然后我尝试使用其他的poperty名称并手动设置,但我无法弄清楚如何找到调用向导的包。

    相关问题,对我没有帮助:

    非常欢迎任何建议。提前谢谢!

    更新

    我设法创建了所需的文件。问题是你 使用稀疏记录的命名约定。如果要正确创建Basename.java文件,则必须命名模板文件:Basename.java(这会使编译器不满意,因为模板文件不是有效的java类),或 Basename.java.template 即可。如果您将其命名为:Basename.java.templ(并自行管理文件的正确命名),则不会为您设置${package}变量。

    所以现在我非常接近我想要的,但是仍然存在正确注册向导的问题。

    目前我正在使用@TemplateRegistrations注册3个模板(每个文件一个)。但由于“文件夹”属性是强制性的,我现在在Netbeans的“新建”向导中有3个条目。当我调用其中一个时,它将根据需要创建所有3个文件,但我想在“新建”向导中只有1个条目。

    @TemplateRegistrations({
        @TemplateRegistration(content = "FXML.fxml.template", scriptEngine = "freemarker", folder = "ASpecial", displayName = "#TemplateName", iconBase = "de/ekrnrw/fxmlview/view.png", description = "newFXMLView.html"),
        @TemplateRegistration(content = "View.java.template", scriptEngine = "freemarker", folder = "ASpecial"),
        @TemplateRegistration(content = "Controller.java.template", scriptEngine = "freemarker", folder = "ASpecial")
    })
    

    我尝试使用包含多个内容条目的单个@TemplateRegistration,但这不适用于本教程中的代码。似乎只有fxml文件被处理为freemarker,而且这两个java文件只是模板文件的纯文本副本。

    @TemplateRegistration(content = {"FXML.fxml.template","View.java.template","Controller.java.template"}, scriptEngine = "freemarker", folder = "ASpecial", displayName = "#TemplateName", iconBase = "de/ekrnrw/fxmlview/view.png", description = "newFXMLView.html")
    

    我将此问题发布到NetBeans邮件列表here。这是相关的代码片段:

    package de.ekrnrw.fxmlview;
    
    import java.awt.Component;
    ...
    import org.openide.util.NbBundle.Messages;
    
    @TemplateRegistrations({
        @TemplateRegistration(content = "FXML.fxml.template", scriptEngine = "freemarker", folder = "ASpecial", displayName = "#TemplateName", iconBase = "de/ekrnrw/fxmlview/view.png", description = "newFXMLView.html"),
        @TemplateRegistration(content = "View.java.template", scriptEngine = "freemarker", folder = "ASpecial"),
        @TemplateRegistration(content = "Controller.java.template", scriptEngine = "freemarker", folder = "ASpecial")
    })
    
    // Would like to use this, but i can't make it work.
    //@TemplateRegistration(content = {"FXML.fxml.template","View.java.template","Controller.java.template"}, scriptEngine = "freemarker", folder = "ASpecial", displayName = "#TemplateName", iconBase = "de/ekrnrw/fxmlview/view.png", description = "newFXMLView.html")
    
    @Messages("TemplateName=FXMLView4")
    
    public final class NewFXMLViewWizardIterator implements WizardDescriptor.InstantiatingIterator<WizardDescriptor> {
    
        private int index;
    
        private WizardDescriptor wizard;
        private List<WizardDescriptor.Panel<WizardDescriptor>> panels;
    
        private List<WizardDescriptor.Panel<WizardDescriptor>> getPanels() {
            if (panels == null) {
                panels = new ArrayList<>();
    
                // Change to default new file panel and add our panel at bottom
                Project p = Templates.getProject(wizard);
                SourceGroup[] groups = ProjectUtils.getSources(p).getSourceGroups(Sources.TYPE_GENERIC);
    
                // SimpleTargetChooser is the default new file panel
                WizardDescriptor.Panel<WizardDescriptor> advNewFilePanel = Templates.buildSimpleTargetChooser(p, groups).create();
                panels.add(advNewFilePanel);
    
                String[] steps = createSteps();
                for (int i = 0; i < panels.size(); i++) {
                    Component c = panels.get(i).getComponent();
                    if (steps[i] == null) {
                        // Default step name to component name of panel. Mainly
                        // useful for getting the name of the target chooser to
                        // appear in the list of steps.
                        steps[i] = c.getName();
                    }
                    if (c instanceof JComponent) { // assume Swing components
                        JComponent jc = (JComponent) c;
                        jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i);
                        jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps);
                        jc.putClientProperty(WizardDescriptor.PROP_AUTO_WIZARD_STYLE, true);
                        jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DISPLAYED, true);
                        jc.putClientProperty(WizardDescriptor.PROP_CONTENT_NUMBERED, true);
                    }
                }
            }
            return panels;
        }
    
        @Override
        public Set<?> instantiate() throws IOException {
    
            //Get the folder:
            FileObject dir = Templates.getTargetFolder(wizard);
            DataFolder df = DataFolder.findFolder(dir);
    
            //Get TargetName from File Wizard
            String targetName = Templates.getTargetName(wizard);
    
            // Read Title from wizard 
            String viewName = targetName + "View";
            String controllerName = targetName + "Controller";
    
            // FreeMarker Template will get its variables from HashMap.
            // HashMap key is the variable name.
            Map args = new HashMap();
            args.put("controllerName", controllerName);
            args.put("viewName", viewName);
    
            //Get Templates
            FileObject[] templates = Templates.getTemplate(wizard).getParent().getChildren();
    
            // Create all Files
            Set<DataObject> createdObjects = new HashSet<>();
    
            for (FileObject fileObject : templates) {
    
                DataObject dTemplate = DataObject.find(fileObject);
                String templateName = dTemplate.getName();
    
                // Sepcial treatment for the .fxml file.
                if (templateName.equals("FXML")) {
                    templateName = "";
                }
    
                // Create file
                createdObjects.add(dTemplate.createFromTemplate(df, targetName + templateName , args));
            }
            return createdObjects;
        }    
        ...
    }
    

3 个答案:

答案 0 :(得分:1)

请在邮件列表dev@platform.netbeans.org询问并提供非工作样本,以便重现该问题。

答案 1 :(得分:1)

我尝试了你的样品,我查了一下。您不需要使用@TemplateRegistration注释来使用freemarker,也不需要使用Templates.getTemplate(wizard).getParent().getChildren()

  1. 通过获取每个模板 FileObject template1 = FileUtil.getConfigFile("CustomerSalesTemplates/project1.txt"); DataObject dTemplate1 = DataObject.find(template1);
  2. 然后使用 dTemplate1.createFromTemplate调用freemarker
  3. 查看文章 * https://blogs.oracle.com/geertjan/entry/how_to_visually_diff_multiple * https://blogs.oracle.com/geertjan/entry/freemarker_baked_into_netbeans_ide1

答案 2 :(得分:0)

在构建时,所有@TemplateRegistration注释都将转换为名为layer.xml的文件中的文件条目。在layer.xml中,文件模板显示如下:

<filesystem>
    <folder name="Templates">
        <folder name="javafx">
            <file name="FxmlNode.java" url="nbresloc:/tuupertunut/fxmltemplates/FxmlNode.java.template">
                <attr name="template" boolvalue="true"/>
                <attr name="displayName" bundlevalue="tuupertunut.fxmltemplates.Bundle#FxmlNode_displayName"/>
                <attr name="iconBase" stringvalue="org/netbeans/spi/java/project/support/ui/templates/class.png"/>
                <attr name="instantiatingWizardURL" urlvalue="nbresloc:/tuupertunut/fxmltemplates/FxmlNodeDescription.html"/>
                <attr name="instantiatingIterator" newvalue="tuupertunut.fxmltemplates.FxmlNodeIterator"/>
                <attr name="requireProject" boolvalue="true"/>
                <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
            </file>
        </folder>
    </folder>
</filesystem>

您可以看到具有file属性的attr条目。与您的问题相关的属性为templatejavax.script.ScriptEngine

  • file的每个<attr name="template" boolvalue="true"/>条目都会在“新建”中显示为单独的条目 文件“对话框。
  • 每个file条目都有<attr name="javax.script.ScriptEngine" stringvalue="freemarker"/> 在创建文件之前由freemarker处理。

案例1:多个@TemplateRegistration s

@TemplateRegistrations({
    @TemplateRegistration(content = "FXML.fxml.template", scriptEngine = "freemarker", folder = "ASpecial", ...),
    @TemplateRegistration(content = "View.java.template", scriptEngine = "freemarker", folder = "ASpecial"),
    @TemplateRegistration(content = "Controller.java.template", scriptEngine = "freemarker", folder = "ASpecial")
})

将转换为

<filesystem>
    <folder name="Templates">
        <folder name="ASpecial">
            <file name="FXML.fxml" url="nbresloc:/yourpackage/FXML.fxml.template">
                <attr name="template" boolvalue="true"/>
                <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
                ...
            </file>
            <file name="View.java" url="nbresloc:/yourpackage/View.java.template">
                <attr name="template" boolvalue="true"/>
                <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
                ...
            </file>
            <file name="Controller.java" url="nbresloc:/yourpackage/Controller.java.template">
                <attr name="template" boolvalue="true"/>
                <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
                ...
            </file>
        </folder>
    </folder>
</filesystem>

如您所见,所有三个模板都将显示在“新文件”对话框中,所有三个模板都将由freemarker处理。

案例2:单content

中的多个@TemplateRegistration
@TemplateRegistration(content = {"FXML.fxml.template","View.java.template","Controller.java.template"}, scriptEngine = "freemarker", folder = "ASpecial", ...)

将转换为

<filesystem>
    <folder name="Templates">
        <folder name="ASpecial">
            <file name="FXML.fxml" url="nbresloc:/yourpackage/FXML.fxml.template">
                <attr name="template" boolvalue="true"/>
                <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
                ...
            </file>
            <file name="View.java" url="nbresloc:/yourpackage/View.java.template">
                ...
            </file>
            <file name="Controller.java" url="nbresloc:/yourpackage/Controller.java.template">
                ...
            </file>
        </folder>
    </folder>
</filesystem>

此处只有第一个模板会显示在“新文件”对话框中,而且只有第一个模板将由freemarker处理。

解决方案

由于注释不会产生所需的layer.xml,因此您必须自己创建一个注释。您应该能够从项目的generated-layer.xml目录中找到自动生成的build/classes/META-INF。从“新建文件”对话框中为项目创建一个新的layer.xml文件,然后将所有内容复制粘贴到其中。然后,您可以手动编辑这些templatejavax.script.ScriptEngine属性。

最后,看起来应该是这样的:

<filesystem>
    <folder name="Templates">
        <folder name="ASpecial">
            <file name="FXML.fxml" url="nbresloc:/yourpackage/FXML.fxml.template">
                <attr name="template" boolvalue="true"/>
                <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
                ...
            </file>
            <file name="View.java" url="nbresloc:/yourpackage/View.java.template">
                <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
                ...
            </file>
            <file name="Controller.java" url="nbresloc:/yourpackage/Controller.java.template">
                <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>
                ...
            </file>
        </folder>
    </folder>
</filesystem>

第一个条目是template唯一的条目,但所有条目都javax.script.ScriptEngine

不要忘记删除@TemplateRegistration注释,因为模板现在由layer.xml管理。