# HG changeset patch # Parent b16278cd50c064496e631317572e9d65f03c0110 # User Jesse Glick #206126: display recommended template categories in a natural order. diff --git a/ant.freeform/src/org/netbeans/modules/ant/freeform/FreeformProject.java b/ant.freeform/src/org/netbeans/modules/ant/freeform/FreeformProject.java --- a/ant.freeform/src/org/netbeans/modules/ant/freeform/FreeformProject.java +++ b/ant.freeform/src/org/netbeans/modules/ant/freeform/FreeformProject.java @@ -138,7 +138,6 @@ new ArtifactProvider(this), // AntArtifactProvider new LookupMergerImpl(), // LookupMerger or ActionProvider UILookupMergerSupport.createPrivilegedTemplatesMerger(), - UILookupMergerSupport.createRecommendedTemplatesMerger(), new FreeformProjectOperations(this), new FreeformSharabilityQuery(this), //SharabilityQueryImplementation Accessor.DEFAULT.createProjectAccessor(this), //Access to AntProjectHelper and PropertyEvaluator diff --git a/apisupport.ant/src/org/netbeans/modules/apisupport/project/NbModuleProject.java b/apisupport.ant/src/org/netbeans/modules/apisupport/project/NbModuleProject.java --- a/apisupport.ant/src/org/netbeans/modules/apisupport/project/NbModuleProject.java +++ b/apisupport.ant/src/org/netbeans/modules/apisupport/project/NbModuleProject.java @@ -318,7 +318,6 @@ ic.add(new ModuleOperations(this)); ic.add(LookupProviderSupport.createSourcesMerger()); ic.add(UILookupMergerSupport.createPrivilegedTemplatesMerger()); - ic.add(UILookupMergerSupport.createRecommendedTemplatesMerger()); ic.add(new TemplateAttributesProvider(this, getHelper(), getModuleType() == NbModuleType.NETBEANS_ORG)); ic.add(new FileEncodingQueryImpl()); ic.add(new AnnotationProcessingQueryImpl(this)); @@ -934,6 +933,7 @@ } private static final String[] RECOMMENDED_TYPES = { + UIUtil.TEMPLATE_CATEGORY, "java-classes", // NOI18N "java-main-class", // NOI18N "java-forms", // NOI18N @@ -945,7 +945,6 @@ "ant-task", // NOI18N "junit", // NOI18N "simple-files", // NOI18N - UIUtil.TEMPLATE_CATEGORY, }; @Override public String[] getPrivilegedTemplates() { diff --git a/j2ee.clientproject/src/org/netbeans/modules/j2ee/clientproject/AppClientProject.java b/j2ee.clientproject/src/org/netbeans/modules/j2ee/clientproject/AppClientProject.java --- a/j2ee.clientproject/src/org/netbeans/modules/j2ee/clientproject/AppClientProject.java +++ b/j2ee.clientproject/src/org/netbeans/modules/j2ee/clientproject/AppClientProject.java @@ -350,7 +350,6 @@ new AppClientPersistenceProvider(this, evaluator(), cpProvider), enterpriseResourceSupport, UILookupMergerSupport.createPrivilegedTemplatesMerger(), - UILookupMergerSupport.createRecommendedTemplatesMerger(), LookupProviderSupport.createSourcesMerger(), ExtraSourceJavadocSupport.createExtraSourceQueryImplementation(this, helper, eval), LookupMergerSupport.createSFBLookupMerger(), diff --git a/j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarProject.java b/j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarProject.java --- a/j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarProject.java +++ b/j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarProject.java @@ -246,7 +246,6 @@ new EarProjectOperations(this), new AntArtifactProviderImpl(), UILookupMergerSupport.createPrivilegedTemplatesMerger(), - UILookupMergerSupport.createRecommendedTemplatesMerger(), LookupProviderSupport.createSourcesMerger(), buildExtender, new SourceForBinaryQueryImpl(this), diff --git a/j2ee.ejbjarproject/src/org/netbeans/modules/j2ee/ejbjarproject/EjbJarProject.java b/j2ee.ejbjarproject/src/org/netbeans/modules/j2ee/ejbjarproject/EjbJarProject.java --- a/j2ee.ejbjarproject/src/org/netbeans/modules/j2ee/ejbjarproject/EjbJarProject.java +++ b/j2ee.ejbjarproject/src/org/netbeans/modules/j2ee/ejbjarproject/EjbJarProject.java @@ -462,7 +462,6 @@ new EjbJarJPAModuleInfo(this), new EjbJarJPATargetInfo(this), UILookupMergerSupport.createPrivilegedTemplatesMerger(), - UILookupMergerSupport.createRecommendedTemplatesMerger(), LookupProviderSupport.createSourcesMerger(), WhiteListQueryMergerSupport.createWhiteListQueryMerger(), QuerySupport.createTemplateAttributesProvider(helper, encodingQuery), diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java @@ -115,7 +115,6 @@ import org.netbeans.spi.project.support.ant.ReferenceHelper; import org.netbeans.spi.project.ui.PrivilegedTemplates; import org.netbeans.spi.project.ui.ProjectOpenedHook; -import org.netbeans.spi.project.ui.RecommendedTemplates; import org.netbeans.spi.project.ui.support.UILookupMergerSupport; import org.netbeans.spi.queries.FileBuiltQueryImplementation; import org.netbeans.spi.queries.FileEncodingQueryImplementation; @@ -143,6 +142,7 @@ import static org.netbeans.spi.project.support.ant.GeneratedFilesHelper.FLAG_OLD_PROJECT_XML; import static org.netbeans.spi.project.support.ant.GeneratedFilesHelper.FLAG_OLD_STYLESHEET; import static org.netbeans.spi.project.support.ant.GeneratedFilesHelper.FLAG_UNKNOWN; +import org.netbeans.spi.project.ui.RecommendedTemplates2; import org.netbeans.spi.whitelist.support.WhiteListQueryMergerSupport; /** * Represents one plain J2SE project. @@ -382,7 +382,6 @@ new J2SEConfigurationProvider(this), new J2SEPersistenceProvider(this, cpProvider), UILookupMergerSupport.createPrivilegedTemplatesMerger(), - UILookupMergerSupport.createRecommendedTemplatesMerger(), LookupProviderSupport.createSourcesMerger(), encodingQuery, new J2SEPropertyEvaluatorImpl(evaluator()), @@ -734,7 +733,7 @@ } - private static final class RecommendedTemplatesImpl implements RecommendedTemplates, PrivilegedTemplates { + private static final class RecommendedTemplatesImpl implements RecommendedTemplates2, PrivilegedTemplates { RecommendedTemplatesImpl (UpdateHelper helper) { this.helper = helper; } @@ -752,8 +751,6 @@ "persistence", // NOI18N "oasis-XML-catalogs", // NOI18N "XML", // NOI18N - "ant-script", // NOI18N - "ant-task", // NOI18N "web-service-clients", // NOI18N "REST-clients", // NOI18N "wsdl", // NOI18N @@ -761,6 +758,8 @@ // "web-types", // NOI18N "junit", // NOI18N // "MIDP", // NOI18N + "ant-script", // NOI18N + "ant-task", // NOI18N "simple-files" // NOI18N }; @@ -773,8 +772,6 @@ "persistence", // NOI18N "oasis-XML-catalogs", // NOI18N "XML", // NOI18N - "ant-script", // NOI18N - "ant-task", // NOI18N "servlet-types", // NOI18N "servlet-types-j2se-only",// NOI18N "web-service-clients", // NOI18N @@ -783,6 +780,8 @@ // "web-types", // NOI18N "junit", // NOI18N // "MIDP", // NOI18N + "ant-script", // NOI18N + "ant-task", // NOI18N "simple-files" // NOI18N }; @@ -798,12 +797,17 @@ }; @Override - public String[] getRecommendedTypes() { + public Map getRecommendedTypes() { EditableProperties ep = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); // if the project has no main class, it's not really an application boolean isLibrary = ep.getProperty (ProjectProperties.MAIN_CLASS) == null || "".equals (ep.getProperty (ProjectProperties.MAIN_CLASS)); // NOI18N - return isLibrary ? LIBRARY_TYPES : APPLICATION_TYPES; + String[] types = isLibrary ? LIBRARY_TYPES : APPLICATION_TYPES; + Map result = new HashMap(); + for (int i = 0; i < types.length; i++) { + result.put((i + 1) * 100, types[i]); + } + return result; } @Override diff --git a/javacard.project/src/org/netbeans/modules/javacard/project/JCProject.java b/javacard.project/src/org/netbeans/modules/javacard/project/JCProject.java --- a/javacard.project/src/org/netbeans/modules/javacard/project/JCProject.java +++ b/javacard.project/src/org/netbeans/modules/javacard/project/JCProject.java @@ -255,7 +255,6 @@ refHelper.createSubprojectProvider(), encodingQuery, UILookupMergerSupport.createPrivilegedTemplatesMerger(), - UILookupMergerSupport.createRecommendedTemplatesMerger(), LookupProviderSupport.createSourcesMerger(), //PENDING replace second getRoots() with null if //http://www.netbeans.org/issues/show_bug.cgi?id=162270 gets diff --git a/javafx2.project/src/org/netbeans/modules/javafx2/project/JFXRecommendedTemplates.java b/javafx2.project/src/org/netbeans/modules/javafx2/project/JFXRecommendedTemplates.java --- a/javafx2.project/src/org/netbeans/modules/javafx2/project/JFXRecommendedTemplates.java +++ b/javafx2.project/src/org/netbeans/modules/javafx2/project/JFXRecommendedTemplates.java @@ -41,21 +41,19 @@ */ package org.netbeans.modules.javafx2.project; +import java.util.Collections; +import java.util.Map; import org.netbeans.spi.project.ProjectServiceProvider; -import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.RecommendedTemplates2; /** * * @author Tomas Zezula */ @ProjectServiceProvider( - service=RecommendedTemplates.class, + service=RecommendedTemplates2.class, projectType={"org-netbeans-modules-java-j2seproject"}) -public class JFXRecommendedTemplates implements RecommendedTemplates { - - private static final String[] RECOMMENDED_TEMPLATES = { - "javafx" //NOI18N - }; +public class JFXRecommendedTemplates implements RecommendedTemplates2 { /** * Returns template types for JFX. @@ -63,8 +61,8 @@ * @return JFX template tape */ @Override - public String[] getRecommendedTypes() { - return RECOMMENDED_TEMPLATES; + public Map getRecommendedTypes() { + return Collections.singletonMap(450, "javafx"); // NOI18N } } diff --git a/javawebstart/src/org/netbeans/modules/javawebstart/package-info.java b/javawebstart/src/org/netbeans/modules/javawebstart/package-info.java --- a/javawebstart/src/org/netbeans/modules/javawebstart/package-info.java +++ b/javawebstart/src/org/netbeans/modules/javawebstart/package-info.java @@ -36,7 +36,7 @@ * Portions Copyrighted 2011 Sun Microsystems, Inc. */ -@TemplateRegistration(folder="Other", content="JnlpTemplate.jnlp", category="java-classes", displayName="#JnlpTemplate", description="resources/JNLPTemplate.html", position=500) +@TemplateRegistration(folder="Classes", position=2000, content="JnlpTemplate.jnlp", category="java-classes", displayName="#JnlpTemplate", description="resources/JNLPTemplate.html") @Messages("JnlpTemplate=JNLP File") package org.netbeans.modules.javawebstart; diff --git a/maven.apisupport/src/org/netbeans/modules/maven/apisupport/ApisupportRecoPrivTemplates.java b/maven.apisupport/src/org/netbeans/modules/maven/apisupport/ApisupportRecoPrivTemplates.java --- a/maven.apisupport/src/org/netbeans/modules/maven/apisupport/ApisupportRecoPrivTemplates.java +++ b/maven.apisupport/src/org/netbeans/modules/maven/apisupport/ApisupportRecoPrivTemplates.java @@ -42,18 +42,20 @@ package org.netbeans.modules.maven.apisupport; +import java.util.HashMap; +import java.util.Map; import org.netbeans.modules.apisupport.project.api.UIUtil; import org.netbeans.modules.maven.api.NbMavenProject; import org.netbeans.spi.project.ProjectServiceProvider; import org.netbeans.spi.project.ui.PrivilegedTemplates; -import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.RecommendedTemplates2; /** * apisupport specific part of RecommendedTemplates and PrivilegedTemplates, * @author Milos Kleint */ -@ProjectServiceProvider(service={RecommendedTemplates.class, PrivilegedTemplates.class}, projectType="org-netbeans-modules-maven/" + NbMavenProject.TYPE_NBM) -public class ApisupportRecoPrivTemplates implements RecommendedTemplates, PrivilegedTemplates { +@ProjectServiceProvider(service={RecommendedTemplates2.class, PrivilegedTemplates.class}, projectType="org-netbeans-modules-maven/" + NbMavenProject.TYPE_NBM) +public class ApisupportRecoPrivTemplates implements RecommendedTemplates2, PrivilegedTemplates { private static final String[] NBM_PRIVILEGED_NAMES = { "Templates/Classes/Class.java", // NOI18N @@ -66,21 +68,28 @@ //"Templates/Other/properties.properties", // NOI18N }; private static final String[] NBM_TYPES = { + UIUtil.TEMPLATE_CATEGORY, "java-classes", // NOI18N "java-main-class", // NOI18N "java-forms", // NOI18N "java-beans", // NOI18N "oasis-XML-catalogs", // NOI18N "XML", // NOI18N - "junit", // NOI18N + "junit", // NOI18N "simple-files", // NOI18N "REST-clients", // NOI18N - UIUtil.TEMPLATE_CATEGORY, }; - public @Override String[] getRecommendedTypes() { - return NBM_TYPES; + @Override public Map getRecommendedTypes() { + return mapify(NBM_TYPES); + } + private static Map mapify(String[] types) { + Map result = new HashMap(); + for (int i = 0; i < types.length; i++) { + result.put((i + 1) * 100, types[i]); + } + return result; } public @Override String[] getPrivilegedTemplates() { diff --git a/maven.persistence/src/org/netbeans/modules/maven/persistence/RecommendedTemplatesImpl.java b/maven.persistence/src/org/netbeans/modules/maven/persistence/RecommendedTemplatesImpl.java --- a/maven.persistence/src/org/netbeans/modules/maven/persistence/RecommendedTemplatesImpl.java +++ b/maven.persistence/src/org/netbeans/modules/maven/persistence/RecommendedTemplatesImpl.java @@ -42,12 +42,14 @@ package org.netbeans.modules.maven.persistence; +import java.util.Collections; +import java.util.Map; import org.netbeans.spi.project.ProjectServiceProvider; -import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.RecommendedTemplates2; -@ProjectServiceProvider(service=RecommendedTemplates.class, projectType="org-netbeans-modules-maven") -public class RecommendedTemplatesImpl implements RecommendedTemplates { - public String[] getRecommendedTypes() { - return new String[] {"persistence"}; +@ProjectServiceProvider(service=RecommendedTemplates2.class, projectType="org-netbeans-modules-maven") +public class RecommendedTemplatesImpl implements RecommendedTemplates2 { + @Override public Map getRecommendedTypes() { + return Collections.singletonMap(777, "persistence"); } } diff --git a/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java b/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java --- a/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java +++ b/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java @@ -651,7 +651,6 @@ state, UILookupMergerSupport.createProjectOpenHookMerger(null), UILookupMergerSupport.createPrivilegedTemplatesMerger(), - UILookupMergerSupport.createRecommendedTemplatesMerger(), LookupProviderSupport.createSourcesMerger(), ProjectClassPathModifier.extenderForModifier(this), LookupMergerSupport.createClassPathModifierMerger()); diff --git a/maven/src/org/netbeans/modules/maven/queries/RecommendedTemplatesImpl.java b/maven/src/org/netbeans/modules/maven/queries/RecommendedTemplatesImpl.java --- a/maven/src/org/netbeans/modules/maven/queries/RecommendedTemplatesImpl.java +++ b/maven/src/org/netbeans/modules/maven/queries/RecommendedTemplatesImpl.java @@ -43,17 +43,20 @@ package org.netbeans.modules.maven.queries; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.netbeans.api.java.project.JavaProjectConstants; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectUtils; import org.netbeans.modules.maven.api.NbMavenProject; import org.netbeans.spi.project.ProjectServiceProvider; import org.netbeans.spi.project.ui.PrivilegedTemplates; -import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.RecommendedTemplates2; -@ProjectServiceProvider(service={RecommendedTemplates.class, PrivilegedTemplates.class}, projectType="org-netbeans-modules-maven") -public final class RecommendedTemplatesImpl implements RecommendedTemplates, PrivilegedTemplates { +@ProjectServiceProvider(service={RecommendedTemplates2.class, PrivilegedTemplates.class}, projectType="org-netbeans-modules-maven") +public final class RecommendedTemplatesImpl implements RecommendedTemplates2, PrivilegedTemplates { private static final String[] JAR_APPLICATION_TYPES = { "java-classes", @@ -145,7 +148,7 @@ prohibited.add(NbMavenProject.TYPE_OSGI); } - @Override public String[] getRecommendedTypes() { + @Override public Map getRecommendedTypes() { String packaging = project.getLookup().lookup(NbMavenProject.class).getPackagingType(); if (packaging == null) { packaging = NbMavenProject.TYPE_JAR; @@ -153,25 +156,24 @@ packaging = packaging.trim(); if (NbMavenProject.TYPE_POM.equals(packaging)) { if (ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA).length > 0) { - return JAR_APPLICATION_TYPES.clone(); // #192735 - // #192735 + return mapify(JAR_APPLICATION_TYPES); // #192735 } - return POM_APPLICATION_TYPES.clone(); + return mapify(POM_APPLICATION_TYPES); } if (NbMavenProject.TYPE_JAR.equals(packaging)) { - return JAR_APPLICATION_TYPES.clone(); + return mapify(JAR_APPLICATION_TYPES); } if (NbMavenProject.TYPE_WAR.equals(packaging)) { - return GENERIC_WEB_TYPES.clone(); + return mapify(GENERIC_WEB_TYPES); } if (NbMavenProject.TYPE_EJB.equals(packaging)) { - return GENERIC_EJB_TYPES.clone(); + return mapify(GENERIC_EJB_TYPES); } if (NbMavenProject.TYPE_EAR.equals(packaging)) { - return GENERIC_EAR_TYPES.clone(); + return mapify(GENERIC_EAR_TYPES); } if (prohibited.contains(packaging)) { - return new String[0]; + return Collections.emptyMap(); } // If packaging is unknown, any type of sources is recommanded. //TODO in future we probably can try to guess based on what plugins are @@ -179,7 +181,14 @@ // If packaging is unknown, any type of sources is recommanded. //TODO in future we probably can try to guess based on what plugins are // defined in the lifecycle. - return ALL_TYPES.clone(); + return mapify(ALL_TYPES); + } + private static Map mapify(String[] types) { + Map result = new HashMap(); + for (int i = 0; i < types.length; i++) { + result.put((i + 1) * 100, types[i]); + } + return result; } @Override public String[] getPrivilegedTemplates() { diff --git a/nbbuild/antsrc/org/netbeans/nbbuild/LayerIndex.java b/nbbuild/antsrc/org/netbeans/nbbuild/LayerIndex.java --- a/nbbuild/antsrc/org/netbeans/nbbuild/LayerIndex.java +++ b/nbbuild/antsrc/org/netbeans/nbbuild/LayerIndex.java @@ -51,12 +51,15 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringReader; +import java.text.Collator; import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -110,6 +113,11 @@ serviceOutput = f; } + private File templatesOutput; + public void setTemplatesOutput(File f) { + templatesOutput = f; + } + private String resourceId; private List resources; /** If this parameter is provided, then this tasks creates a resource @@ -129,6 +137,7 @@ SortedMap files = new TreeMap(); // layer path -> cnb SortedMap> labels = new TreeMap>(); // layer path -> cnb -> label final Map positions = new TreeMap(); // layer path -> position + SortedMap> templateCategories = new TreeMap>(Collator.getInstance(Locale.ENGLISH)); // templateCategory item (or "") -> layer paths SortedMap>> serviceImpls = new TreeMap>>(); // path -> interface -> [impl] Map servicePositions = new HashMap(); // impl -> position for (FileSet fs : filesets) { @@ -154,7 +163,7 @@ ZipResource res = new LayerResource(jar, layer, layer.replaceFirst("/[^/]+$", "").replace('/', '.') + ".xml"); resources.add(res); } else { - parse(jf.getInputStream(jf.getEntry(layer)), files, labels, positions, cnb, jf); + parse(jf.getInputStream(jf.getEntry(layer)), files, labels, positions, templateCategories, cnb, jf); } } ZipEntry generatedLayer = jf.getEntry("META-INF/generated-layer.xml"); @@ -163,7 +172,7 @@ ZipResource res = new LayerResource(jar, generatedLayer.getName(), cnb + "-generated.xml"); resources.add(res); } else { - parse(jf.getInputStream(generatedLayer), files, labels, positions, cnb + "@", jf); + parse(jf.getInputStream(generatedLayer), files, labels, positions, templateCategories, cnb + "@", jf); } } if (serviceOutput != null) { @@ -189,6 +198,9 @@ if (serviceOutput != null) { writeServiceIndex(serviceImpls, servicePositions); } + if (templatesOutput != null) { + writeTemplateIndex(templateCategories, labels, positions); + } } catch (IOException x) { throw new BuildException(x, getLocation()); } @@ -213,12 +225,14 @@ } private void parse(InputStream is, final Map files, final SortedMap> labels, - final Map positions, final String cnb, final JarFile jf) throws Exception { + final Map positions, final Map> templateCategories, final String cnb, final JarFile jf) throws Exception { SAXParserFactory f = SAXParserFactory.newInstance(); f.setValidating(false); f.setNamespaceAware(false); f.newSAXParser().parse(is, new DefaultHandler() { String prefix = ""; + List templateCategory; + boolean template; void register(String path) { if (!files.containsKey(path)) { files.put(path, cnb); @@ -270,6 +284,10 @@ throw new SAXException(x); } } + } else if (qName.equals("attr") && attributes.getValue("name").equals("template")) { + template = Boolean.parseBoolean(attributes.getValue("boolvalue")); + } else if (qName.equals("attr") && attributes.getValue("name").equals("templateCategory")) { + templateCategory = Arrays.asList(attributes.getValue("stringvalue").split(" *, *")); } } private void loadDisplayName(String bundle, String key) throws SAXException { @@ -308,9 +326,32 @@ if (qName.equals("folder")) { prefix = prefix.replaceFirst("[^/]+/$", ""); } else if (qName.equals("file")) { + // XXX really want to track simple=false, and templateCategory on folders + if (template && prefix.matches("Templates/(?!Project/|Licenses/|Services/|JSF/JSF_From_Entity_Wizard/|JSF/JSF_From_Entity_Snippets/).+")) { + if (templateCategory != null) { + for (String category : templateCategory) { + if (category.equals("invisible")) { + continue; + } + registerTemplateCategory(category); + } + } else { + registerTemplateCategory(""); + } + template = false; + } + templateCategory = null; prefix = prefix.replaceFirst("[^/]+$", ""); } } + void registerTemplateCategory(String category) { + Set paths = templateCategories.get(category); + if (paths == null) { + paths = new TreeSet(); + templateCategories.put(category, paths); + } + paths.add(prefix); + } @Override public InputSource resolveEntity(String pub, String sys) throws IOException, SAXException { return new InputSource(new StringReader("")); @@ -615,4 +656,43 @@ } } + private void writeTemplateIndex(Map> templateCategories, SortedMap> labels, Map positions) throws IOException { + PrintWriter pw = new PrintWriter(templatesOutput, "UTF-8"); + Comparator order = new LayerPathComparator(positions); + for (Map.Entry> categoryEntry : templateCategories.entrySet()) { + pw.print("CATEGORY "); + String category = categoryEntry.getKey(); + pw.println(category.isEmpty() ? "" : "'" + category + "'"); + SortedMap> templatesByFolder = new TreeMap>(order); + for (String path : categoryEntry.getValue()) { + int slash = path.lastIndexOf('/'); + String folder = path.substring(0, slash + 1); + SortedSet templates = templatesByFolder.get(folder); + if (templates == null) { + templates = new TreeSet(order); + templatesByFolder.put(folder, templates); + } + templates.add(path); + } + for (Map.Entry> folderEntry : templatesByFolder.entrySet()) { + String folder = folderEntry.getKey(); + pw.print(" FOLDER " + folder); + printlnLabel(pw, folder, labels); + for (String template : folderEntry.getValue()) { + pw.print(" " + template.substring(folder.length())); + printlnLabel(pw, template, labels); + } + } + } + pw.close(); + log(templatesOutput + ": template index written"); + } + private static void printlnLabel(PrintWriter pw, String path, SortedMap> labels) { + SortedMap possibilities = labels.get(path); + if (possibilities != null && possibilities.size() == 1) { + pw.print(" (\"" + possibilities.values().iterator().next() + "\")"); + } + pw.println(); + } + } diff --git a/nbbuild/build.xml b/nbbuild/build.xml --- a/nbbuild/build.xml +++ b/nbbuild/build.xml @@ -1515,7 +1515,7 @@ - + diff --git a/nbbuild/javadoctools/disallowed-links.xml b/nbbuild/javadoctools/disallowed-links.xml --- a/nbbuild/javadoctools/disallowed-links.xml +++ b/nbbuild/javadoctools/disallowed-links.xml @@ -91,6 +91,6 @@ - + diff --git a/projectapi/src/org/netbeans/api/project/Project.java b/projectapi/src/org/netbeans/api/project/Project.java --- a/projectapi/src/org/netbeans/api/project/Project.java +++ b/projectapi/src/org/netbeans/api/project/Project.java @@ -107,7 +107,7 @@ *
  • {@link org.netbeans.spi.queries.SharabilityQueryImplementation}
  • *
  • {@link org.netbeans.spi.queries.FileEncodingQueryImplementation}
  • *
  • ProjectOpenedHook
  • - *
  • RecommendedTemplates
  • + *
  • RecommendedTemplates2
  • *
  • PrivilegedTemplates
  • *
  • ClassPathProvider
  • *
  • SourceForBinaryQueryImplementation
  • diff --git a/projectui/src/org/netbeans/modules/project/ui/LazyProject.java b/projectui/src/org/netbeans/modules/project/ui/LazyProject.java --- a/projectui/src/org/netbeans/modules/project/ui/LazyProject.java +++ b/projectui/src/org/netbeans/modules/project/ui/LazyProject.java @@ -49,12 +49,13 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; +import java.util.Map; import javax.swing.Action; import javax.swing.Icon; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectInformation; import org.netbeans.spi.project.ui.LogicalViewProvider; -import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.RecommendedTemplates2; import org.netbeans.spi.project.ui.support.CommonProjectActions; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; @@ -77,7 +78,7 @@ * @author Tim Boudreau, Jaroslav Tulach */ final class LazyProject implements -Project, ProjectInformation, SearchInfo, LogicalViewProvider, RecommendedTemplates { +Project, ProjectInformation, SearchInfo, LogicalViewProvider, RecommendedTemplates2 { URL url; String displayName; ExtIcon icon; @@ -140,8 +141,8 @@ return null; } - public String[] getRecommendedTypes() { - return new String[] { "simple-files" }; // NOI18N + @Override public Map getRecommendedTypes() { + return Collections.singletonMap(0, "simple-files"); // NOI18N } diff --git a/projectui/src/org/netbeans/modules/project/ui/OpenProjectList.java b/projectui/src/org/netbeans/modules/project/ui/OpenProjectList.java --- a/projectui/src/org/netbeans/modules/project/ui/OpenProjectList.java +++ b/projectui/src/org/netbeans/modules/project/ui/OpenProjectList.java @@ -83,7 +83,6 @@ import javax.swing.Icon; import javax.swing.SwingUtilities; import org.netbeans.api.annotations.common.NonNull; -import org.netbeans.api.annotations.common.NullAllowed; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.netbeans.api.project.FileOwnerQuery; @@ -98,7 +97,6 @@ import org.netbeans.spi.project.SubprojectProvider; import org.netbeans.spi.project.ui.PrivilegedTemplates; import org.netbeans.spi.project.ui.ProjectOpenedHook; -import org.netbeans.spi.project.ui.RecommendedTemplates; import org.openide.ErrorManager; import org.openide.awt.StatusDisplayer; import org.openide.filesystems.FileChangeAdapter; @@ -1284,7 +1282,7 @@ ProjectManager.mutex().writeAccess(new Mutex.Action() { public @Override Void run() { - String[] rtNames = getRecommendedTypes(project); + String[] rtNames = TemplateChooserPanelGUI.getRecommendedTypes(project); Iterator it = getRecentTemplates().iterator(); for( int i = 0; i < NUM_TEMPLATES && it.hasNext(); i++ ) { String templateName = it.next(); @@ -1292,7 +1290,7 @@ if ( fo == null ) { it.remove(); // Does not exists remove } - else if ( isRecommended( rtNames, fo ) ) { + else if (isRecommended(rtNames, fo, true)) { result.add( fo ); privilegedTemplates.remove( templateName ); // Not to have it twice } @@ -1316,7 +1314,7 @@ } - static boolean isRecommended(@NonNull String[] recommendedTypes, @NonNull FileObject primaryFile) { + static boolean isRecommended(@NonNull String[] recommendedTypes, @NonNull FileObject primaryFile, boolean lax) { if (recommendedTypes.length == 0) { // if no recommendedTypes are supported (i.e. freeform) -> disaply all templates return true; @@ -1335,23 +1333,10 @@ } else { // issue 44871, if attr 'templateCategorized' is not set => all is ok // no category set, ok display it - return true; + return lax; } } - /** - * Returns list of recommended template types for project. Do not call in - * loop because it may scan project files to resolve its type which is time - * consuming. - */ - static @NonNull String[] getRecommendedTypes(@NullAllowed Project project) { - if (project == null) { - return new String[0]; - } - RecommendedTemplates rt = project.getLookup().lookup(RecommendedTemplates.class); - return rt == null ? new String[0] : rt.getRecommendedTypes(); - } - private static List getCategories (String source) { ArrayList categories = new ArrayList (); StringTokenizer cattok = new StringTokenizer (source, ","); // NOI18N diff --git a/projectui/src/org/netbeans/modules/project/ui/TemplateChooserPanelGUI.java b/projectui/src/org/netbeans/modules/project/ui/TemplateChooserPanelGUI.java --- a/projectui/src/org/netbeans/modules/project/ui/TemplateChooserPanelGUI.java +++ b/projectui/src/org/netbeans/modules/project/ui/TemplateChooserPanelGUI.java @@ -50,12 +50,23 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.DefaultComboBoxModel; import javax.swing.ListCellRenderer; import javax.swing.event.ChangeListener; +import org.netbeans.api.annotations.common.CheckForNull; import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; import org.netbeans.api.project.Project; +import org.netbeans.spi.project.ui.RecommendedTemplates2; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.loaders.DataFolder; @@ -67,20 +78,17 @@ import org.openide.nodes.Node; import org.openide.util.AsyncGUIJob; import org.openide.util.ChangeSupport; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.Utilities; -/** If you are looking for the non-GUI part of the panel please look - * into new file wizard - */ - - - // #89393: GTK needs cell renderer to implement UIResource to look "natively" /** * Provides the GUI for the template chooser panel. * @author Jesse Glick */ final class TemplateChooserPanelGUI extends javax.swing.JPanel implements PropertyChangeListener, AsyncGUIJob { + + private static final Logger LOG = Logger.getLogger(TemplateChooserPanelGUI.class.getName()); /** prefered dimmension of the panels */ private static final java.awt.Dimension PREF_DIM = new java.awt.Dimension (500, 340); @@ -94,7 +102,7 @@ //GUI Builder private TemplatesPanelGUI.Builder builder; private Project project; - private @NonNull String[] projectRecommendedTypes; + private String[] projectRecommendedTypes; private String category; private String template; private boolean isWarmUp = true; @@ -116,7 +124,7 @@ boolean wf; synchronized (this) { this.project = p; - this.projectRecommendedTypes = OpenProjectList.getRecommendedTypes(p); + this.projectRecommendedTypes = getRecommendedTypes(p); this.category = category; this.template = template; wf = this.isWarmUp; @@ -299,19 +307,35 @@ } @Override protected boolean createKeys(List keys) { - for (DataObject d : folder.getChildren()) { - if (isFolderOfTemplates(d)) { - boolean leaf = true; - for (DataObject child : ((DataFolder) d).getChildren()) { - if (isFolderOfTemplates(child)) { - leaf = false; - break; + Set added = new HashSet(); + DataObject[] potentialCategories = folder.getChildren(); + if (projectRecommendedTypes == null) { + return true; // in case readValues has not been called + } + for (String type : projectRecommendedTypes) { + addMatches(potentialCategories, added, new String[] {type}, false, type, keys); + } + addMatches(potentialCategories, added, projectRecommendedTypes, true, "", keys); + return true; + } + private void addMatches(DataObject[] potentialCategories, Set added, String[] types, boolean lax, String typeDiagnostic, List keys) { + for (DataObject d : potentialCategories) { + if (!added.contains(d)) { + DataObject trigger = isFolderOfTemplates(d, types, lax); + if (trigger != null) { + added.add(d); + LOG.log(Level.FINE, "adding {0} because of {1} matched by {2}", new Object[] {d.getPrimaryFile().getPath(), typeDiagnostic, trigger.getPrimaryFile().getPath()}); + boolean leaf = true; + for (DataObject child : ((DataFolder) d).getChildren()) { + if (isFolderOfTemplates(child, projectRecommendedTypes, true) != null) { + leaf = false; + break; + } } + keys.add(new TemplateKey(d, leaf)); } - keys.add(new TemplateKey(d, leaf)); } } - return true; } @Override protected Node createNodeForKey(TemplateKey k) { @@ -319,7 +343,7 @@ } @Override public void actionPerformed (ActionEvent event) { - projectRecommendedTypes = OpenProjectList.getRecommendedTypes(getProject()); + projectRecommendedTypes = getRecommendedTypes(getProject()); final String cat = getCategoryName (); String template = ((TemplatesPanelGUI)TemplateChooserPanelGUI.this.templatesPanel).getSelectedTemplateName(); refresh(false); @@ -330,14 +354,14 @@ // Private methods ----------------------------------------------------- - private boolean isFolderOfTemplates(DataObject d) { + private @CheckForNull DataObject isFolderOfTemplates(DataObject d, String[] projectRecommendedTypes, boolean lax) { if (d instanceof DataFolder && !isTemplate((DataFolder)d)) { Object o = d.getPrimaryFile().getAttribute("simple"); // NOI18N if (o == null || Boolean.TRUE.equals(o)) { - return hasChildren((Project) projectsComboBox.getSelectedItem(), d); + return hasChildren(getProject(), d, projectRecommendedTypes, lax); } } - return false; + return null; } } @@ -353,7 +377,7 @@ @Override protected boolean createKeys(List keys) { for (DataObject dobj : root.getChildren()) { - if (isTemplate(dobj) && OpenProjectList.isRecommended(projectRecommendedTypes, dobj.getPrimaryFile())) { + if (isTemplate(dobj) && OpenProjectList.isRecommended(projectRecommendedTypes, dobj.getPrimaryFile(), true)) { if (dobj instanceof DataShadow) { dobj = ((DataShadow) dobj).getOriginal(); } @@ -410,33 +434,32 @@ return false; } - private boolean hasChildren (Project p, DataObject folder) { + private @CheckForNull DataObject hasChildren(Project p, DataObject folder, String[] projectRecommendedTypes, boolean lax) { if (!(folder instanceof DataFolder)) { - return false; + return null; } DataFolder f = (DataFolder) folder; - if (!OpenProjectList.isRecommended(projectRecommendedTypes, f.getPrimaryFile())) { + if (!OpenProjectList.isRecommended(projectRecommendedTypes, f.getPrimaryFile(), true)) { // Eg. Licenses folder. //see #102508 - return false; + return null; } DataObject[] ch = f.getChildren (); for (int i = 0; i < ch.length; i++) { - if (isTemplate (ch[i]) && OpenProjectList.isRecommended(projectRecommendedTypes, ch[i].getPrimaryFile ())) { + if (isTemplate(ch[i]) && OpenProjectList.isRecommended(projectRecommendedTypes, ch[i].getPrimaryFile(), lax)) { // XXX: how to filter link to Package template in each java types folder? if (!(ch[i] instanceof DataShadow)) { - return true; + return ch[i]; } - } else if (ch[i] instanceof DataFolder && hasChildren (p, ch[i])) { - return true; + } else if (ch[i] instanceof DataFolder) { + DataObject t = hasChildren(p, ch[i], projectRecommendedTypes, lax); + if (t != null) { + return t; + } } } - return false; - - // simplied but more counts - //return new FileChildren (p, (DataFolder) folder).getNodesCount () > 0; - + return null; } public void construct () { @@ -469,4 +492,38 @@ } } + /** + * Returns list of recommended template types for project. Do not call in + * loop because it may scan project files to resolve its type which is time + * consuming. + */ + static @NonNull String[] getRecommendedTypes(@NullAllowed Project project) { + if (project == null) { + return new String[0]; + } + return getRecommendedTypes(project.getLookup()); + } + @SuppressWarnings("deprecation") + static @NonNull String[] getRecommendedTypes(@NonNull Lookup lookup) { + Map> typeMap = new TreeMap>(); + for (RecommendedTemplates2 rt2 : lookup.lookupAll(RecommendedTemplates2.class)) { + for (Map.Entry entry : rt2.getRecommendedTypes().entrySet()) { + List types = typeMap.get(entry.getKey()); + if (types == null) { + types = new LinkedList(); + typeMap.put(entry.getKey(), types); + } + types.add(entry.getValue()); + } + } + Set types = new LinkedHashSet(); + for (List _types : typeMap.values()) { + types.addAll(_types); + } + for (org.netbeans.spi.project.ui.RecommendedTemplates rt : lookup.lookupAll(org.netbeans.spi.project.ui.RecommendedTemplates.class)) { + types.addAll(Arrays.asList(rt.getRecommendedTypes())); + } + return types.toArray(new String[types.size()]); + } + } diff --git a/projectui/test/unit/src/org/netbeans/modules/project/ui/TemplateChooserPanelGUITest.java b/projectui/test/unit/src/org/netbeans/modules/project/ui/TemplateChooserPanelGUITest.java --- a/projectui/test/unit/src/org/netbeans/modules/project/ui/TemplateChooserPanelGUITest.java +++ b/projectui/test/unit/src/org/netbeans/modules/project/ui/TemplateChooserPanelGUITest.java @@ -43,10 +43,15 @@ package org.netbeans.modules.project.ui; import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; import org.netbeans.api.project.Project; import org.netbeans.junit.NbTestCase; import org.netbeans.modules.project.ui.TemplateChooserPanelGUI.FileChooserBuilder; -import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.RecommendedTemplates2; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.loaders.DataFolder; @@ -71,6 +76,14 @@ return 300000; } + @Override protected Level logLevel() { + return Level.FINE; + } + + @Override protected String logRoot() { + return "org.netbeans.modules.project.ui"; + } + public void testReadValues() { Project p = new P(); String category = ""; @@ -123,8 +136,6 @@ t.setAttribute("template", true); t.setAttribute("templateCategory", "main"); TemplateChooserPanelGUI gui = new TemplateChooserPanelGUI(); - gui.construct(); - gui.finished(); gui.readValues(new P(), null, null); FileChooserBuilder builder = gui.new FileChooserBuilder(); assertChildren("Main, Samples[Main]", builder.createCategoriesChildren(DataFolder.findFolder(r))); @@ -132,6 +143,59 @@ assertChildren("t5", builder.createTemplatesChildren(DataFolder.findFolder(r.getFileObject("Samples/Main")))); } + public void testTemplateCategoryOrder() throws Exception { // #206126 + FileObject r = FileUtil.createMemoryFileSystem().getRoot(); + FileObject f = r.createFolder("Specialized"); + f.setAttribute("position", 1); + FileObject t = f.createData("t1"); + t.setAttribute("template", true); + t.setAttribute("templateCategory", "inappropriate"); + t = f.createData("t2"); + t.setAttribute("template", true); + t.setAttribute("templateCategory", "misc"); + f = r.createFolder("Common"); + f.setAttribute("position", 2); + t = f.createData("t3"); + t.setAttribute("template", true); + t.setAttribute("templateCategory", "main"); + t = f.createData("t4"); + t.setAttribute("template", true); + t.setAttribute("templateCategory", "misc"); + f = r.createFolder("Plain"); + f.setAttribute("position", 3); + t = f.createData("t5"); + t.setAttribute("template", true); + TemplateChooserPanelGUI gui = new TemplateChooserPanelGUI(); + gui.readValues(new P(), null, null); + FileChooserBuilder builder = gui.new FileChooserBuilder(); + assertChildren("Common, Specialized, Plain", builder.createCategoriesChildren(DataFolder.findFolder(r))); + } + + @SuppressWarnings("deprecation") + public void testGetRecommendedTypes() throws Exception { + assertEquals("[early, principal, oops, old1, old2, old3, old4]", Arrays.toString(TemplateChooserPanelGUI.getRecommendedTypes(Lookups.fixed(new RecommendedTemplates2() { + @Override public Map getRecommendedTypes() { + return Collections.singletonMap(100, "principal"); + } + }, new RecommendedTemplates2() { + @Override public Map getRecommendedTypes() { + return Collections.singletonMap(50, "early"); + } + }, new org.netbeans.spi.project.ui.RecommendedTemplates() { + @Override public String[] getRecommendedTypes() { + return new String[] {"old1", "old2"}; + } + }, new RecommendedTemplates2() { + @Override public Map getRecommendedTypes() { + return Collections.singletonMap(100, "oops"); + } + }, new org.netbeans.spi.project.ui.RecommendedTemplates() { + @Override public String[] getRecommendedTypes() { + return new String[] {"old3", "old4"}; + } + })))); + } + private static void assertChildren(String repn, Children c) { StringBuilder b = new StringBuilder(); representationOf(c, b); @@ -162,9 +226,12 @@ } public @Override Lookup getLookup() { - return Lookups.singleton(new RecommendedTemplates() { - public @Override String[] getRecommendedTypes() { - return new String[] {"main", "misc"}; + return Lookups.singleton(new RecommendedTemplates2() { + public @Override Map getRecommendedTypes() { + Map types = new HashMap(); + types.put(1, "main"); + types.put(2, "misc"); + return types; } }); } diff --git a/projectuiapi/apichanges.xml b/projectuiapi/apichanges.xml --- a/projectuiapi/apichanges.xml +++ b/projectuiapi/apichanges.xml @@ -107,6 +107,40 @@ + + + RecommendedTemplates2 supersedes RecommendedTemplates + + + + +

    + Existing implementations of RecommendedTemplates should be changed to + RecommendedTemplates2. + Uses of UILookupMergerSupport.createRecommendedTemplatesMerger may be removed. +

    +

    + Positions of template folders may also need to be adjusted. + Order of displayed folders may differ from previous behavior + even if no RecommendedTemplates2 implementations + are in use, since the overall sort mechanism now gives priority + to the project's ordering preferences (via categories) rather + than the global ordering preferences (via folders). +

    +
    + +

    + UI infrastructure will now pay attention to an ordered list of categories + in RecommendedTemplates2, preferring to show template + folders first which contain templates marked with categories earlier + in the list. +

    +
    + + + + +
    Adding ability to create a file sensitive action with custom performer diff --git a/projectuiapi/nbproject/project.properties b/projectuiapi/nbproject/project.properties --- a/projectuiapi/nbproject/project.properties +++ b/projectuiapi/nbproject/project.properties @@ -42,7 +42,7 @@ javac.compilerargs=-Xlint -Xlint:-serial javac.source=1.6 -spec.version.base=1.56.0 +spec.version.base=1.57.0 is.autoload=true javadoc.arch=${basedir}/arch.xml javadoc.apichanges=${basedir}/apichanges.xml diff --git a/projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates.java b/projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates.java --- a/projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates.java +++ b/projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates.java @@ -54,7 +54,9 @@ * For more information about registering templates see overview of * {@link org.netbeans.spi.project.ui.templates.support} package. * @author Petr Hrebejk + * @deprecated Implement {@link RecommendedTemplates2} instead. */ +@Deprecated public interface RecommendedTemplates { /** diff --git a/projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates.java b/projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates2.java copy from projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates.java copy to projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates2.java --- a/projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates.java +++ b/projectuiapi/src/org/netbeans/spi/project/ui/RecommendedTemplates2.java @@ -44,24 +44,30 @@ package org.netbeans.spi.project.ui; +import java.util.Map; import org.netbeans.api.templates.TemplateRegistration; +import org.netbeans.spi.project.ui.support.UILookupMergerSupport; /** * List of template types supported by a project when making a new file. * An instance should be placed in {@link org.netbeans.api.project.Project#getLookup} * to affect the recommended template list for that project. *

    + * Unlike {@link RecommendedTemplates} this service supports ordering of template categories. + * Zero or more instances of either service may be present in project lookup; + * instances of this service will take priority. + *

    * For more information about registering templates see overview of * {@link org.netbeans.spi.project.ui.templates.support} package. - * @author Petr Hrebejk + * @since 1.57 */ -public interface RecommendedTemplates { +public interface RecommendedTemplates2 { /** * Lists supported template types. - * @return types of supported templates (should match template file attribute names) + * @return types of supported templates (should match template file attribute names), lower positions first * @see TemplateRegistration#category */ - public String[] getRecommendedTypes(); + Map getRecommendedTypes(); } diff --git a/projectuiapi/src/org/netbeans/spi/project/ui/support/UILookupMergerSupport.java b/projectuiapi/src/org/netbeans/spi/project/ui/support/UILookupMergerSupport.java --- a/projectuiapi/src/org/netbeans/spi/project/ui/support/UILookupMergerSupport.java +++ b/projectuiapi/src/org/netbeans/spi/project/ui/support/UILookupMergerSupport.java @@ -52,7 +52,7 @@ import org.netbeans.spi.project.LookupMerger; import org.netbeans.spi.project.ui.PrivilegedTemplates; import org.netbeans.spi.project.ui.ProjectOpenedHook; -import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.RecommendedTemplates2; import org.openide.util.Lookup; /** @@ -67,15 +67,13 @@ } /** - * Create a {@link org.netbeans.spi.project.LookupMerger} instance - * for {@link org.netbeans.spi.project.ui.RecommendedTemplates}. Allows to merge - * templates from multiple sources. - * @return instance to include in project lookup + * @deprecated No longer needed; caller will look for all instances of {@link org.netbeans.spi.project.ui.RecommendedTemplates} and {@link RecommendedTemplates2}. */ - public static LookupMerger createRecommendedTemplatesMerger() { + @Deprecated + public static LookupMerger createRecommendedTemplatesMerger() { return new RecommendedMerger(); } - + /** * Create a {@link org.netbeans.spi.project.LookupMerger} instance * for {@link org.netbeans.spi.project.ui.PrivilegedTemplates}. Allows to merge @@ -108,14 +106,15 @@ return new PrivilegedTemplatesImpl(lookup); } } - - private static class RecommendedMerger implements LookupMerger { + + @Deprecated + private static class RecommendedMerger implements LookupMerger { - public Class getMergeableClass() { - return RecommendedTemplates.class; + public Class getMergeableClass() { + return org.netbeans.spi.project.ui.RecommendedTemplates.class; } - public RecommendedTemplates merge(Lookup lookup) { + public org.netbeans.spi.project.ui.RecommendedTemplates merge(Lookup lookup) { return new RecommendedTemplatesImpl(lookup); } } @@ -157,7 +156,8 @@ } } - private static class RecommendedTemplatesImpl implements RecommendedTemplates { + @Deprecated + private static class RecommendedTemplatesImpl implements org.netbeans.spi.project.ui.RecommendedTemplates { private Lookup lkp; @@ -167,7 +167,7 @@ public String[] getRecommendedTypes() { Set templates = new LinkedHashSet(); - for (RecommendedTemplates pt : lkp.lookupAll(RecommendedTemplates.class)) { + for (org.netbeans.spi.project.ui.RecommendedTemplates pt : lkp.lookupAll(org.netbeans.spi.project.ui.RecommendedTemplates.class)) { String[] temp = pt.getRecommendedTypes(); if (temp == null) { throw new IllegalStateException(pt.getClass().getName() + " returns null from getRecommendedTemplates() method."); //NOI18N diff --git a/projectuiapi/src/org/netbeans/spi/project/ui/templates/support/package.html b/projectuiapi/src/org/netbeans/spi/project/ui/templates/support/package.html --- a/projectuiapi/src/org/netbeans/spi/project/ui/templates/support/package.html +++ b/projectuiapi/src/org/netbeans/spi/project/ui/templates/support/package.html @@ -100,11 +100,21 @@ There is currently no annotation to define template folders; they should be defined in the XML layer as subfolders of Templates with displayName and position attributes. +

    +The position of template folders is considered in the UI as a secondary sort key; +the order of categories specified in RecommendedTemplates2 is primary. +Use -J-Dorg.netbeans.modules.project.ui.TemplateChooserPanelGUI.level=FINE +to see why particular folders are chosen in a particular order. +

    Note that it is possible to set the attribute simple to (boolean) false in order to hide templates from the list shown in the standard wizards, while still making it possible to use TemplateRegistration and apply templates programmatically. To hide templates from the "new" wizards but show them in Template Manager, just set a category which is never used (such as invisible). +

    +A summary of templates and categories in the NetBeans IDE can be found online: +templates.txt +

    There are two important interfaces affecting the behavior of the templates. Implementation of these interfaces should reside in the project's lookup. @@ -130,37 +140,24 @@ }

    -The second interface is {@link org.netbeans.spi.project.ui.RecommendedTemplates}, +The second interface is {@link org.netbeans.spi.project.ui.RecommendedTemplates2}, which influences the appearance of templates in the New File wizard according to project types. The implementation of the interface has to return array of Strings which corresponds to names of template categories listed in the templateCategory attribute of template files. All templates which list at least one recommended category in the templateCategory attribute will be listed for given project type.
    Note: if no templateCategory is declared then this template will be visible for each project regardless its type.

    -Example implementation of RecommendedTemplates interface: -

    
    -private static final class RecommendedTemplatesImpl implements RecommendedTemplates {
    -    
    -    // List of primarily supported templates categories
    -    private static final String[] TYPES = new String[] { 
    -        "java-classes",         
    -        "java-main-class",      
    -        "java-forms",           
    -        "gui-java-application", 
    -        "java-beans",           
    -        "oasis-XML-catalogs",   
    -        "XML",                  
    -        "ant-script",           
    -        "ant-task",             
    -        "junit",                
    -        "simple-files"          
    -    };
    -
    -    public String[] getRecommendedTypes() {
    -        return TYPES;
    +Example implementation of RecommendedTemplates2 interface:
    +
    +@ServiceProvider(service=RecommendedTemplates2.class, projectType="some-project-type")
    +public class RecommendedTemplatesImpl implements RecommendedTemplates2 {
    +    @Override public Map<? extends Number,String> getRecommendedTypes() {
    +        Map<Integer,String> types = new HashMap<>();
    +        types.put(100, "java-classes");
    +        types.put(110, "java-main-class");
    +        return types;
         }
    -
     }
    -
    +
    diff --git a/spring.beans/src/org/netbeans/modules/spring/beans/RecommendedTemplatesImpl.java b/spring.beans/src/org/netbeans/modules/spring/beans/RecommendedTemplatesImpl.java --- a/spring.beans/src/org/netbeans/modules/spring/beans/RecommendedTemplatesImpl.java +++ b/spring.beans/src/org/netbeans/modules/spring/beans/RecommendedTemplatesImpl.java @@ -42,22 +42,16 @@ package org.netbeans.modules.spring.beans; +import java.util.Collections; +import java.util.Map; import org.netbeans.spi.project.ProjectServiceProvider; -import org.netbeans.spi.project.ui.RecommendedTemplates; +import org.netbeans.spi.project.ui.RecommendedTemplates2; /** * * @author Andrei Badea */ -public class RecommendedTemplatesImpl implements RecommendedTemplates { - - private static final String[] SPRING_TYPES = new String[] { - "spring-types" // NOI18N - }; - - private static final String[] SPRING_WEB_TYPES = new String[] { - "spring-web-types" // NOI18N - }; +public class RecommendedTemplatesImpl implements RecommendedTemplates2 { private final boolean web; @@ -65,20 +59,20 @@ this.web = web; } - @ProjectServiceProvider(service=RecommendedTemplates.class, projectType="org-netbeans-modules-web-project") - public static RecommendedTemplates forWeb() { + @ProjectServiceProvider(service=RecommendedTemplates2.class, projectType="org-netbeans-modules-web-project") + public static RecommendedTemplates2 forWeb() { return new RecommendedTemplatesImpl(true); } - @ProjectServiceProvider(service=RecommendedTemplates.class, projectType={ + @ProjectServiceProvider(service=RecommendedTemplates2.class, projectType={ "org-netbeans-modules-java-j2seproject", "org-netbeans-modules-j2ee-ejbjarproject" }) - public static RecommendedTemplates forNonWeb() { + public static RecommendedTemplates2 forNonWeb() { return new RecommendedTemplatesImpl(false); } - public String[] getRecommendedTypes() { - return web ? SPRING_WEB_TYPES : SPRING_TYPES; + @Override public Map getRecommendedTypes() { + return Collections.singletonMap(1000, web ? "spring-web-types" : "spring-types"); // NOI18N } } diff --git a/web.project/src/org/netbeans/modules/web/project/WebProject.java b/web.project/src/org/netbeans/modules/web/project/WebProject.java --- a/web.project/src/org/netbeans/modules/web/project/WebProject.java +++ b/web.project/src/org/netbeans/modules/web/project/WebProject.java @@ -134,7 +134,6 @@ import org.netbeans.spi.project.support.ant.GeneratedFilesHelper; import org.netbeans.spi.project.support.ant.ProjectXmlSavedHook; import org.netbeans.spi.project.ui.PrivilegedTemplates; -import org.netbeans.spi.project.ui.RecommendedTemplates; import org.netbeans.spi.project.ui.support.UILookupMergerSupport; import org.netbeans.spi.project.support.ant.ReferenceHelper; import org.netbeans.spi.project.support.ant.PropertyEvaluator; @@ -175,6 +174,7 @@ import org.netbeans.spi.whitelist.support.WhiteListQueryMergerSupport; import org.netbeans.spi.project.support.ant.PropertyProvider; import org.netbeans.spi.project.support.ant.PropertyUtils; +import org.netbeans.spi.project.ui.RecommendedTemplates2; import org.netbeans.spi.queries.FileEncodingQueryImplementation; import org.openide.filesystems.FileLock; import org.openide.filesystems.FileSystem; @@ -585,7 +585,6 @@ new WebJPAModuleInfo(this), new WebJPATargetInfo(this), UILookupMergerSupport.createPrivilegedTemplatesMerger(), - UILookupMergerSupport.createRecommendedTemplatesMerger(), LookupProviderSupport.createSourcesMerger(), WhiteListQueryMergerSupport.createWhiteListQueryMerger(), new WebPropertyEvaluatorImpl(evaluator()), @@ -1276,6 +1275,7 @@ // List of primarily supported templates private static final String[] TYPES = new String[] { + "servlet-types", // NOI18N "java-classes", // NOI18N "java-main-class", // NOI18N "java-forms", // NOI18N @@ -1286,7 +1286,6 @@ "ant-script", // NOI18N "ant-task", // NOI18N "REST-clients", // NOI18N - "servlet-types", // NOI18N "web-types", // NOI18N "web-types-server", // NOI18N "web-services", // NOI18N @@ -1403,7 +1402,7 @@ privilegedTemplates.addAll(Arrays.asList(PRIVILEGED_NAMES)); } - private final class RecommendedTemplatesImpl implements RecommendedTemplates, PrivilegedTemplates { + private final class RecommendedTemplatesImpl implements RecommendedTemplates2, PrivilegedTemplates { private WebProject project; private J2eeProjectCapabilities projectCap; @@ -1416,22 +1415,30 @@ private boolean isEE5 = false; private boolean serverSupportsEJB31 = false; - public String[] getRecommendedTypes() { + @Override public Map getRecommendedTypes() { checkEnvironment(); if (isArchive) { - return TYPES_ARCHIVE; + return mapify(TYPES_ARCHIVE); } else if (projectCap.isEjb31LiteSupported()){ List list = new ArrayList(Arrays.asList(TYPES)); + // XXX intermix these into TYPES somehow nice if (projectCap.isEjb31Supported() || serverSupportsEJB31){ list.addAll(Arrays.asList(TYPES_EJB)); } else { list.addAll(Arrays.asList(TYPES_EJB_LITE)); } - return list.toArray(new String[list.size()]); + return mapify(list.toArray(new String[list.size()])); }else{ - return TYPES; + return mapify(TYPES); } } + private Map mapify(String[] types) { + Map result = new HashMap(); + for (int i = 0; i < types.length; i++) { + result.put((i + 1) * 100, types[i]); + } + return result; + } public String[] getPrivilegedTemplates() { checkEnvironment();