Issue #141886: let user select alternate file extensions in simple target chooser.
diff --git a/openide.filesystems/src/org/openide/filesystems/FileUtil.java b/openide.filesystems/src/org/openide/filesystems/FileUtil.java
--- a/openide.filesystems/src/org/openide/filesystems/FileUtil.java
+++ b/openide.filesystems/src/org/openide/filesystems/FileUtil.java
@@ -1262,7 +1262,7 @@
*
* @param folder parent folder
* @param name preferred base name of file
- * @param ext extension to use
+ * @param ext extension to use (or null)
* @return a free file name (without the extension)
*/
public static String findFreeFileName(FileObject folder, String name, String ext) {
diff --git a/openide.loaders/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java b/openide.loaders/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java
--- a/openide.loaders/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java
+++ b/openide.loaders/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java
@@ -71,9 +71,10 @@
protected FileObject createFromTemplate(FileObject template, FileObject f,
String name,
Map values) throws IOException {
+ boolean noExt = Boolean.TRUE.equals(values.get(FREE_FILE_EXTENSION)) && name.indexOf('.') != -1;
- String nameUniq = FileUtil.findFreeFileName(f, name, template.getExt());
- FileObject output = FileUtil.createData(f, nameUniq + '.' + template.getExt());
+ String nameUniq = FileUtil.findFreeFileName(f, name, noExt ? null : template.getExt());
+ FileObject output = FileUtil.createData(f, noExt ? nameUniq : nameUniq + '.' + template.getExt());
Charset targetEnc = FileEncodingQuery.getEncoding(output);
Charset sourceEnc = FileEncodingQuery.getEncoding(template);
diff --git a/openide.loaders/src/org/openide/loaders/CreateFromTemplateHandler.java b/openide.loaders/src/org/openide/loaders/CreateFromTemplateHandler.java
--- a/openide.loaders/src/org/openide/loaders/CreateFromTemplateHandler.java
+++ b/openide.loaders/src/org/openide/loaders/CreateFromTemplateHandler.java
@@ -57,7 +57,7 @@
/** Handles the creation of new file.
* @param orig the source file
* @param f the folder to create a file in
- * @param name the name of new file to create in the folder (extension will be inherited from orig
)
+ * @param name the name of new file to create in the folder (see {@link #FREE_FILE_EXTENSION} regarding extension)
* @param parameters map of additional arguments as specified by registered {@link CreateFromTemplateAttributesProvider}s
* @return the newly create file
* @throws IOException if something goes wrong with I/O
@@ -68,5 +68,19 @@
String name,
Map parameters
) throws IOException;
+
+ /**
+ * Parameter to enable free file extension mode.
+ * By default, the extension of the newly created file will be inherited
+ * from the template. But if {@link #createFromTemplate} is called with this
+ * parameter set to {@link Boolean#TRUE}
+ * (such as from {@link DataObject#createFromTemplate(DataFolder,String,Map)}),
+ * and the file name already seems to
+ * include an extension (*.*), the handler should not append
+ * any extension from the template.
+ * @since XXX
+ * @see Templates.SimpleTargetChooserBuilder.freeFileExtension
+ */
+ public static final String FREE_FILE_EXTENSION = "freeFileExtension"; // NOI18N
}
diff --git a/openide.loaders/src/org/openide/loaders/DataObject.java b/openide.loaders/src/org/openide/loaders/DataObject.java
--- a/openide.loaders/src/org/openide/loaders/DataObject.java
+++ b/openide.loaders/src/org/openide/loaders/DataObject.java
@@ -1323,8 +1323,11 @@
all.put(e.getKey(), e.getValue());
}
}
-
+
if (!all.containsKey("name") && name != null) { // NOI18N
+ if (Boolean.TRUE.equals(all.get(CreateFromTemplateHandler.FREE_FILE_EXTENSION))) {
+ name = name.replaceFirst("[.].*", "");
+ }
all.put("name", name); // NOI18N
}
if (!all.containsKey("user")) { // NOI18N
@@ -1344,7 +1347,8 @@
public static Map enhanceParameters(Map old, String name, String ext) {
HashMap all = new HashMap(old);
if (!all.containsKey("nameAndExt") && name != null) { // NOI18N
- if (ext != null && ext.length() > 0) {
+ if (ext != null && ext.length() > 0 &&
+ (!Boolean.TRUE.equals(old.get(CreateFromTemplateHandler.FREE_FILE_EXTENSION)) || name.indexOf('.') == -1)) {
all.put("nameAndExt", name + '.' + ext); // NOI18N
} else {
all.put("nameAndExt", name); // NOI18N
diff --git a/openide.loaders/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java b/openide.loaders/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java
--- a/openide.loaders/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java
+++ b/openide.loaders/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java
@@ -35,6 +35,7 @@
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
@@ -51,6 +52,8 @@
import org.openide.loaders.MultiDataObject;
import org.openide.loaders.MultiFileLoader;
import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
+import org.openide.loaders.CreateFromTemplateHandler;
+import org.openide.util.SharedClassObject;
import org.openide.util.test.MockLookup;
/**
@@ -71,7 +74,7 @@
@Override
protected void setUp() throws Exception {
- MockLookup.setInstances(new SimpleLoader());
+ MockLookup.setInstances(SharedClassObject.findObject(SimpleLoader.class, true));
}
public void testCreateFromTemplateEncodingProperty() throws Exception {
@@ -102,6 +105,50 @@
assertNotNull("Template encoding is null", targetEnc);
assertEquals("Encoding in template doesn't match", targetEnc.name(), instFO.asText());
}
+
+ public void testFreeFileExtension() throws Exception {
+ FileObject root = FileUtil.createMemoryFileSystem().getRoot();
+ FileObject template = FileUtil.createData(root, "simple.pl");
+ OutputStream os = template.getOutputStream();
+ os.write("#!/usr/bin/perl\n# ${license}\n# ${name} in ${nameAndExt}\n".getBytes());
+ os.close();
+ template.setAttribute("template", true);
+ template.setAttribute("javax.script.ScriptEngine", "freemarker");
+ Map parameters = new HashMap();
+ parameters.put("license", "GPL");
+ parameters.put(CreateFromTemplateHandler.FREE_FILE_EXTENSION, true);
+ ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader().getParent());
+ try {
+ FileObject inst;
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl\n# GPL\n# nue in nue.pl\n", inst.asText());
+ assertEquals("nue.pl", inst.getPath());
+ /* XXX perhaps irrelevant since typical wizards disable Finish in this condition
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl\n# GPL\n# nue_1 in nue_1.pl\n", inst.asText());
+ assertEquals("nue_1.pl", inst.getPath());
+ */
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue.cgi", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl\n# GPL\n# nue in nue.cgi\n", inst.asText());
+ assertEquals("nue.cgi", inst.getPath());
+ /* XXX
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue.cgi", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl\n# GPL\n# nue_1 in nue_1.cgi\n", inst.asText());
+ assertEquals("nue_1.cgi", inst.getPath());
+ */
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "explicit.pl", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl\n# GPL\n# explicit in explicit.pl\n", inst.asText());
+ assertEquals("explicit.pl", inst.getPath());
+ /* XXX
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "explicit.pl", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl\n# GPL\n# explicit_1 in explicit_1.pl\n", inst.asText());
+ assertEquals("explicit_1.pl", inst.getPath());
+ */
+ } finally {
+ Thread.currentThread().setContextClassLoader(oldLoader);
+ }
+ }
//fix for this test was rolled back because of issue #120865
public void XtestCreateFromTemplateDocumentCreated() throws Exception {
diff --git a/php.project/src/org/netbeans/modules/php/project/resources/layer.xml b/php.project/src/org/netbeans/modules/php/project/resources/layer.xml
--- a/php.project/src/org/netbeans/modules/php/project/resources/layer.xml
+++ b/php.project/src/org/netbeans/modules/php/project/resources/layer.xml
@@ -111,8 +111,8 @@
-
-
+
+
@@ -120,8 +120,8 @@
-
-
+
+
@@ -129,18 +129,18 @@
-
+
-
+
-
+
-
+
diff --git a/php.project/src/org/netbeans/modules/php/project/ui/wizards/Bundle.properties b/php.project/src/org/netbeans/modules/php/project/ui/wizards/Bundle.properties
--- a/php.project/src/org/netbeans/modules/php/project/ui/wizards/Bundle.properties
+++ b/php.project/src/org/netbeans/modules/php/project/ui/wizards/Bundle.properties
@@ -46,9 +46,6 @@
Templates/Scripting/PHPClass=PHP Class
Templates/Scripting/PHPInterface=PHP Interface
-# new file wizard
-TXT_FileExists=File {0} already exists!
-
# PHP project wizards
TXT_PhpProject=PHP Project
TXT_ExistingPhpProject=PHP Project with Existing Sources
diff --git a/php.project/src/org/netbeans/modules/php/project/ui/wizards/NewFileWizardIterator.java b/php.project/src/org/netbeans/modules/php/project/ui/wizards/NewFileWizardIterator.java
--- a/php.project/src/org/netbeans/modules/php/project/ui/wizards/NewFileWizardIterator.java
+++ b/php.project/src/org/netbeans/modules/php/project/ui/wizards/NewFileWizardIterator.java
@@ -42,8 +42,6 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.logging.Level;
@@ -52,8 +50,6 @@
import javax.swing.event.ChangeListener;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.SourceGroup;
-import org.netbeans.modules.php.api.util.FileUtils;
-import org.netbeans.modules.php.api.util.StringUtils;
import org.netbeans.modules.php.project.PhpProject;
import org.netbeans.modules.php.project.ProjectPropertiesSupport;
import org.netbeans.modules.php.project.SourceRoots;
@@ -62,10 +58,9 @@
import org.openide.WizardDescriptor;
import org.openide.WizardDescriptor.Panel;
import org.openide.filesystems.FileObject;
-import org.openide.filesystems.FileUtil;
+import org.openide.loaders.CreateFromTemplateHandler;
import org.openide.loaders.DataFolder;
import org.openide.loaders.DataObject;
-import org.openide.util.NbBundle;
/**
* Just as simple wrapper for the standard new file iterator as possible.
@@ -84,37 +79,10 @@
FileObject dir = Templates.getTargetFolder(wizard);
FileObject template = Templates.getTemplate(wizard);
- Map wizardProps = new HashMap();
-
DataFolder dataFolder = DataFolder.findFolder(dir);
DataObject dataTemplate = DataObject.find(template);
- String fname = Templates.getTargetName(wizard);
- String ext = FileUtil.getExtension(fname);
-
- FileObject foo = FileUtil.createData(FileUtil.createMemoryFileSystem().getRoot(), fname);
- if (foo == null || !FileUtils.isPhpFile(foo)) {
- if (!StringUtils.hasText(ext)) {
- Templates.setTargetName(wizard, fname + ".php"); // NOI18N
- fname = Templates.getTargetName(wizard);
- ext = FileUtil.getExtension(fname);
- }
- }
- if (StringUtils.hasText(ext)) {
- String name = fname.substring(0, fname.length() - ext.length() - 1);
- name = name.replaceAll("\\W", ""); // NOI18N
- wizardProps.put("name", name); // NOI18N
-
- // #168723
- String templateExt = FileUtil.getExtension(template.getNameExt());
- if (StringUtils.hasText(templateExt)) {
- Templates.setTargetName(wizard, name);
- }
- }
- String targetName = Templates.getTargetName(wizard);
- if (dir.getFileObject(targetName) != null) {
- throw new IOException(NbBundle.getMessage(NewFileWizardIterator.class, "TXT_FileExists", targetName));
- }
- DataObject createdFile = dataTemplate.createFromTemplate(dataFolder, targetName, wizardProps);
+ DataObject createdFile = dataTemplate.createFromTemplate(dataFolder, Templates.getTargetName(wizard),
+ Collections.singletonMap(CreateFromTemplateHandler.FREE_FILE_EXTENSION, true));
return Collections.singleton(createdFile.getPrimaryFile());
}
@@ -133,9 +101,6 @@
Templates.setTargetFolder(wizard, srcDir);
}
}
- FileObject template = Templates.getTemplate(wizard);
- String targetName = targetFolder != null ? FileUtil.findFreeFileName(targetFolder, template.getName(), "php") : template.getName(); // NOI18N
- Templates.setTargetName(wizard, targetName + ".php"); // NOI18N
wizardPanels = getPanels();
// Make sure list of steps is accurate.
@@ -271,7 +236,7 @@
new IllegalStateException("No source roots found (attach your IDE log to https://netbeans.org/bugzilla/show_bug.cgi?id=180054)"));
groups = null;
}
- WizardDescriptor.Panel simpleTargetChooserPanel = Templates.createSimpleTargetChooser(p, groups);
+ WizardDescriptor.Panel simpleTargetChooserPanel = Templates.buildSimpleTargetChooser(p, groups).freeFileExtension().create();
@SuppressWarnings("unchecked") // Generic Array Creation
WizardDescriptor.Panel[] panels = new WizardDescriptor.Panel[] {
diff --git a/projectui/src/org/netbeans/modules/project/ui/NewFileIterator.java b/projectui/src/org/netbeans/modules/project/ui/NewFileIterator.java
--- a/projectui/src/org/netbeans/modules/project/ui/NewFileIterator.java
+++ b/projectui/src/org/netbeans/modules/project/ui/NewFileIterator.java
@@ -107,9 +107,9 @@
currentProject = project;
Sources sources = ProjectUtils.getSources(project);
if (isFolder) {
- panel = new SimpleTargetChooserPanel(project, sources.getSourceGroups(Sources.TYPE_GENERIC), null, true);
+ panel = new SimpleTargetChooserPanel(project, sources.getSourceGroups(Sources.TYPE_GENERIC), null, true, false);
} else {
- panel = Templates.createSimpleTargetChooser(project, sources.getSourceGroups(Sources.TYPE_GENERIC));
+ panel = Templates.buildSimpleTargetChooser(project, sources.getSourceGroups(Sources.TYPE_GENERIC)).create();
}
}
return panel;
diff --git a/projectui/src/org/netbeans/modules/project/ui/NewFileWizard.java b/projectui/src/org/netbeans/modules/project/ui/NewFileWizard.java
--- a/projectui/src/org/netbeans/modules/project/ui/NewFileWizard.java
+++ b/projectui/src/org/netbeans/modules/project/ui/NewFileWizard.java
@@ -143,7 +143,7 @@
protected WizardDescriptor.Panel createTargetChooser() {
Sources c = ProjectUtils.getSources(getCurrentProject());
- return Templates.createSimpleTargetChooser(getCurrentProject(), c.getSourceGroups(Sources.TYPE_GENERIC));
+ return Templates.buildSimpleTargetChooser(getCurrentProject(), c.getSourceGroups(Sources.TYPE_GENERIC)).create();
}
}
diff --git a/projectui/src/org/netbeans/modules/project/ui/ProjectChooserFactoryImpl.java b/projectui/src/org/netbeans/modules/project/ui/ProjectChooserFactoryImpl.java
--- a/projectui/src/org/netbeans/modules/project/ui/ProjectChooserFactoryImpl.java
+++ b/projectui/src/org/netbeans/modules/project/ui/ProjectChooserFactoryImpl.java
@@ -62,8 +62,9 @@
return ProjectChooserAccessory.createProjectChooser( false );
}
- public @Override WizardDescriptor.Panel createSimpleTargetChooser(Project project, SourceGroup[] folders, WizardDescriptor.Panel bottomPanel) {
- return new SimpleTargetChooserPanel( project, folders, bottomPanel, false );
+ public @Override WizardDescriptor.Panel createSimpleTargetChooser(Project project, SourceGroup[] folders,
+ WizardDescriptor.Panel bottomPanel, boolean freeFileExtension) {
+ return new SimpleTargetChooserPanel(project, folders, bottomPanel, false, freeFileExtension);
}
public @Override File getProjectsFolder() {
diff --git a/projectui/src/org/netbeans/modules/project/ui/ProjectUtilities.java b/projectui/src/org/netbeans/modules/project/ui/ProjectUtilities.java
--- a/projectui/src/org/netbeans/modules/project/ui/ProjectUtilities.java
+++ b/projectui/src/org/netbeans/modules/project/ui/ProjectUtilities.java
@@ -322,7 +322,8 @@
* is allowed in the newObjectName
* @return localized error message or null if all right
*/
- public static String canUseFileName (FileObject targetFolder, String folderName, String newObjectName, String extension, boolean allowFileSeparator) {
+ public static String canUseFileName (FileObject targetFolder, String folderName, String newObjectName,
+ String extension, boolean allowFileSeparator, boolean freeFileExtension) {
assert newObjectName != null; // SimpleTargetChooserPanel.isValid returns false if it is... XXX should it use an error label instead?
boolean allowSlash = false;
@@ -372,7 +373,7 @@
}
relFileName.append(newObjectName);
String ext = "";
- if (extension != null && extension.length() != 0) {
+ if (extension != null && extension.length() != 0 && (!freeFileExtension || newObjectName.indexOf('.') == -1)) {
ext = "." + extension;
relFileName.append(ext);
}
diff --git a/projectui/src/org/netbeans/modules/project/ui/SimpleTargetChooserPanel.java b/projectui/src/org/netbeans/modules/project/ui/SimpleTargetChooserPanel.java
--- a/projectui/src/org/netbeans/modules/project/ui/SimpleTargetChooserPanel.java
+++ b/projectui/src/org/netbeans/modules/project/ui/SimpleTargetChooserPanel.java
@@ -69,9 +69,11 @@
private WizardDescriptor.Panel bottomPanel;
private WizardDescriptor wizard;
private boolean isFolder;
+ private boolean freeFileExtension;
@SuppressWarnings("LeakingThisInConstructor")
- SimpleTargetChooserPanel(Project project, SourceGroup[] folders, WizardDescriptor.Panel bottomPanel, boolean isFolder) {
+ SimpleTargetChooserPanel(Project project, SourceGroup[] folders,
+ WizardDescriptor.Panel bottomPanel, boolean isFolder, boolean freeFileExtension) {
this.folders = folders;
if (folders != null && folders.length == 0) {
throw new IllegalArgumentException("Attempting to create panel with an empty folders list"); // #161478
@@ -82,12 +84,13 @@
bottomPanel.addChangeListener( this );
}
this.isFolder = isFolder;
+ this.freeFileExtension = freeFileExtension;
this.gui = null;
}
public @Override Component getComponent() {
if (gui == null) {
- gui = new SimpleTargetChooserPanelGUI( project, folders, bottomPanel == null ? null : bottomPanel.getComponent(), isFolder );
+ gui = new SimpleTargetChooserPanelGUI(project, folders, bottomPanel == null ? null : bottomPanel.getComponent(), isFolder, freeFileExtension);
gui.addChangeListener(this);
}
return gui;
@@ -117,7 +120,8 @@
// check if the file name can be created
FileObject template = Templates.getTemplate( wizard );
- String errorMessage = ProjectUtilities.canUseFileName (gui.getTargetGroup().getRootFolder(), gui.getTargetFolder(), gui.getTargetName(), template.getExt (), isFolder);
+ String errorMessage = ProjectUtilities.canUseFileName(gui.getTargetGroup().getRootFolder(),
+ gui.getTargetFolder(), gui.getTargetName(), template.getExt(), isFolder, freeFileExtension);
wizard.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, errorMessage);
return errorMessage == null;
diff --git a/projectui/src/org/netbeans/modules/project/ui/SimpleTargetChooserPanelGUI.java b/projectui/src/org/netbeans/modules/project/ui/SimpleTargetChooserPanelGUI.java
--- a/projectui/src/org/netbeans/modules/project/ui/SimpleTargetChooserPanelGUI.java
+++ b/projectui/src/org/netbeans/modules/project/ui/SimpleTargetChooserPanelGUI.java
@@ -85,13 +85,15 @@
private final ChangeSupport changeSupport = new ChangeSupport(this);
private SourceGroup[] folders;
private boolean isFolder;
+ private boolean freeFileExtension;
/** Creates new form SimpleTargetChooserGUI */
@SuppressWarnings("LeakingThisInConstructor")
- public SimpleTargetChooserPanelGUI( Project project, SourceGroup[] folders, Component bottomPanel, boolean isFolder ) {
+ public SimpleTargetChooserPanelGUI( Project project, SourceGroup[] folders, Component bottomPanel, boolean isFolder, boolean freeFileExtension) {
this.project = project;
this.folders = folders.clone();
this.isFolder = isFolder;
+ this.freeFileExtension = freeFileExtension;
initComponents();
locationComboBox.setRenderer( CELL_RENDERER );
@@ -425,7 +427,7 @@
( folderName.startsWith("/") || folderName.startsWith( File.separator ) ? "" : "/" ) + // NOI18N
folderName +
( folderName.endsWith("/") || folderName.endsWith( File.separator ) || folderName.length() == 0 ? "" : "/" ) + // NOI18N
- documentName + expectedExtension;
+ documentName + (!freeFileExtension || documentName.indexOf('.') == -1 ? expectedExtension : "");
fileTextField.setText( createdFileName.replace( '/', File.separatorChar ) ); // NOI18N
diff --git a/projectui/test/unit/src/org/netbeans/modules/project/ui/ProjectUtilitiesTest.java b/projectui/test/unit/src/org/netbeans/modules/project/ui/ProjectUtilitiesTest.java
--- a/projectui/test/unit/src/org/netbeans/modules/project/ui/ProjectUtilitiesTest.java
+++ b/projectui/test/unit/src/org/netbeans/modules/project/ui/ProjectUtilitiesTest.java
@@ -268,31 +268,37 @@
FileObject d = FileUtil.toFileObject(getWorkDir());
FileObject p1 = d.getFileObject("project1");
assertNotNull(p1);
- assertNull("normal file addition", ProjectUtilities.canUseFileName(p1, null, "foo", "java", false));
- assertNull("normal file addition with no extension is OK", ProjectUtilities.canUseFileName(p1, null, "foo", null, false));
- assertNull("normal file addition in an existing subdir", ProjectUtilities.canUseFileName(d, "project1", "foo", "java", false));
- assertNull("normal file addition in a new subdir", ProjectUtilities.canUseFileName(d, "dir", "foo", "java", false));
+ assertNull("normal file addition", ProjectUtilities.canUseFileName(p1, null, "foo", "java", false, false));
+ assertNull("normal file addition with no extension is OK", ProjectUtilities.canUseFileName(p1, null, "foo", null, false, false));
+ assertNull("normal file addition in an existing subdir", ProjectUtilities.canUseFileName(d, "project1", "foo", "java", false, false));
+ assertNull("normal file addition in a new subdir", ProjectUtilities.canUseFileName(d, "dir", "foo", "java", false, false));
//assertNotNull("no target name", ProjectUtilities.canUseFileName(d, "dir", null, "java"));
- assertNotNull("no target folder", ProjectUtilities.canUseFileName(null, "dir", "foo", "java", false));
- assertNotNull("file already exists", ProjectUtilities.canUseFileName(p1, null, "f1_1", "java", false));
- assertNotNull("file already exists in subdir", ProjectUtilities.canUseFileName(d, "project1", "f1_1", "java", false));
- assertNull("similar file already exists in subdir", ProjectUtilities.canUseFileName(d, "project1", "f1_1", "properties", false));
- assertNull("similar file already exists in subdir", ProjectUtilities.canUseFileName(d, "project1", "f1_1", null, false));
+ assertNotNull("no target folder", ProjectUtilities.canUseFileName(null, "dir", "foo", "java", false, false));
+ assertNotNull("file already exists", ProjectUtilities.canUseFileName(p1, null, "f1_1", "java", false, false));
+ assertNotNull("file already exists in subdir", ProjectUtilities.canUseFileName(d, "project1", "f1_1", "java", false, false));
+ assertNull("similar file already exists in subdir", ProjectUtilities.canUseFileName(d, "project1", "f1_1", "properties", false, false));
+ assertNull("similar file already exists in subdir", ProjectUtilities.canUseFileName(d, "project1", "f1_1", null, false, false));
d = new XMLFileSystem().getRoot();
- assertNotNull("FS is r/o", ProjectUtilities.canUseFileName(d, null, "foo", "java", false));
+ assertNotNull("FS is r/o", ProjectUtilities.canUseFileName(d, null, "foo", "java", false, false));
// #59876: deal with non-disk-based filesystems sensibly
d = FileUtil.createMemoryFileSystem().getRoot();
d.createData("bar.java");
FileUtil.createData(d, "sub/dir/foo.java");
- assertNull("can create file in non-disk FS", ProjectUtilities.canUseFileName(d, null, "foo", "java", false));
- assertNotNull("file already exists", ProjectUtilities.canUseFileName(d, null, "bar", "java", false));
- assertNotNull("file already exists in subsubdir", ProjectUtilities.canUseFileName(d, "sub/dir", "foo", "java", false));
- assertNull("can otherwise create file in subsubdir", ProjectUtilities.canUseFileName(d, "sub/dir", "bar", "java", false));
+ assertNull("can create file in non-disk FS", ProjectUtilities.canUseFileName(d, null, "foo", "java", false, false));
+ assertNotNull("file already exists", ProjectUtilities.canUseFileName(d, null, "bar", "java", false, false));
+ assertNotNull("file already exists in subsubdir", ProjectUtilities.canUseFileName(d, "sub/dir", "foo", "java", false, false));
+ assertNull("can otherwise create file in subsubdir", ProjectUtilities.canUseFileName(d, "sub/dir", "bar", "java", false, false));
//#66792: allow to create whole directory tree at once using Folder Template:
- assertNull("can create directory subtree", ProjectUtilities.canUseFileName(d, null, "a/b/c", null, true));
+ assertNull("can create directory subtree", ProjectUtilities.canUseFileName(d, null, "a/b/c", null, true, false));
//#59654: do not allow slash and backslash for common templates:
- assertNotNull("cannot create file with slashes", ProjectUtilities.canUseFileName(d, null, "a/b/c", "txt", false));
- assertNotNull("cannot create file with backslashes", ProjectUtilities.canUseFileName(d, null, "a\\b\\c", "txt", false));
+ assertNotNull("cannot create file with slashes", ProjectUtilities.canUseFileName(d, null, "a/b/c", "txt", false, false));
+ assertNotNull("cannot create file with backslashes", ProjectUtilities.canUseFileName(d, null, "a\\b\\c", "txt", false, false));
+ // Check freeFileExtension mode:
+ assertNull(ProjectUtilities.canUseFileName(d, null, "foo", "java", false, true));
+ assertNotNull(ProjectUtilities.canUseFileName(d, null, "bar", "java", false, true));
+ assertNotNull(ProjectUtilities.canUseFileName(d, null, "bar.java", "java", false, true));
+ assertNull(ProjectUtilities.canUseFileName(d, null, "bar.java", "java", false, false));
+
}
public void testNavigatorIsNotClosed() throws Exception {
diff --git a/projectuiapi/src/org/netbeans/modules/project/uiapi/ProjectChooserFactory.java b/projectuiapi/src/org/netbeans/modules/project/uiapi/ProjectChooserFactory.java
--- a/projectuiapi/src/org/netbeans/modules/project/uiapi/ProjectChooserFactory.java
+++ b/projectuiapi/src/org/netbeans/modules/project/uiapi/ProjectChooserFactory.java
@@ -67,6 +67,7 @@
public JFileChooser createProjectChooser();
- public WizardDescriptor.Panel createSimpleTargetChooser(Project project, SourceGroup[] folders, WizardDescriptor.Panel bottomPanel);
+ public WizardDescriptor.Panel createSimpleTargetChooser(Project project, SourceGroup[] folders,
+ WizardDescriptor.Panel bottomPanel, boolean freeFileExtension);
}
diff --git a/projectuiapi/src/org/netbeans/spi/project/ui/templates/support/Templates.java b/projectuiapi/src/org/netbeans/spi/project/ui/templates/support/Templates.java
--- a/projectuiapi/src/org/netbeans/spi/project/ui/templates/support/Templates.java
+++ b/projectuiapi/src/org/netbeans/spi/project/ui/templates/support/Templates.java
@@ -49,6 +49,7 @@
import org.netbeans.spi.project.ui.support.CommonProjectActions;
import org.openide.WizardDescriptor;
import org.openide.filesystems.FileObject;
+import org.openide.loaders.CreateFromTemplateHandler;
import org.openide.loaders.DataFolder;
import org.openide.loaders.DataObject;
import org.openide.loaders.TemplateWizard;
@@ -200,30 +201,80 @@
}
/**
- * Create a basic target chooser suitable for many kinds of templates.
- * The user is prompted to choose a location for the new file and a (base) name.
+ * @deprecated Use {@link #buildSimpleTargetChooser} instead.
+ */
+ @Deprecated
+ public static WizardDescriptor.Panel createSimpleTargetChooser( Project project, SourceGroup[] folders ) {
+ return buildSimpleTargetChooser(project, folders).create();
+ }
+
+ /**
+ * @deprecated Use {@link #buildSimpleTargetChooser} instead.
+ */
+ @Deprecated
+ public static WizardDescriptor.Panel createSimpleTargetChooser(Project project, SourceGroup[] folders, WizardDescriptor.Panel bottomPanel) {
+ return buildSimpleTargetChooser(project, folders).bottomPanel(bottomPanel).create();
+ }
+
+ /**
+ * Builder for simple target choosers.
+ * The chooser is suitable for many kinds of templates.
+ * The user is prompted to choose a location for the new file and a name.
* Instantiation is handled by {@link DataObject#createFromTemplate}.
* @param project The project to work on.
* @param folders a list of possible roots to create the new file in
- * @return a wizard panel(s) prompting the user to choose a name and location
+ * @return a builder which can be used to customize and then create the target chooser
+ * @since XXX
*/
- public static WizardDescriptor.Panel createSimpleTargetChooser( Project project, SourceGroup[] folders ) {
- return createSimpleTargetChooser( project, folders, null );
+ public static SimpleTargetChooserBuilder buildSimpleTargetChooser(Project project, SourceGroup[] folders) {
+ return new SimpleTargetChooserBuilder(project, folders);
}
-
+
/**
- * Create a basic target chooser suitable for many kinds of templates.
- * The user is prompted to choose a location for the new file and a (base) name.
- * Instantiation is handled by {@link DataObject#createFromTemplate}.
- * Resulting panel can be decorated with additional panel placed below the standard target
- * chooser.
- * @param project The project to work on.
- * @param folders a list of possible roots to create the new file in
- * @param bottomPanel panel which should be placed underneth the default chooser
- * @return a wizard panel(s) prompting the user to choose a name and location
+ * A builder for simple target choosers.
+ * @see #buildSimpleTargetChooser
+ * @since XXX
*/
- public static WizardDescriptor.Panel createSimpleTargetChooser(Project project, SourceGroup[] folders, WizardDescriptor.Panel bottomPanel) {
- return Utilities.getProjectChooserFactory().createSimpleTargetChooser( project, folders, bottomPanel );
+ public static final class SimpleTargetChooserBuilder {
+ final Project project;
+ final SourceGroup[] folders;
+ WizardDescriptor.Panel bottomPanel;
+ boolean freeFileExtension;
+ SimpleTargetChooserBuilder(Project project, SourceGroup[] folders) {
+ this.project = project;
+ this.folders = folders;
+ }
+ /**
+ * Sets a panel which should be placed underneath the default chooser.
+ * @param bottomPanel a custom bottom panel
+ * @return this builder
+ */
+ public SimpleTargetChooserBuilder bottomPanel(WizardDescriptor.Panel bottomPanel) {
+ this.bottomPanel = bottomPanel;
+ return this;
+ }
+ /**
+ * Permits the file extension of the created file to be customized by the user.
+ * By default, the file extension is fixed to be the same as that of the template:
+ * whatever is entered for the filename is taken to be a base name only.
+ * In this mode, the GUI makes it possible to use an alternate extension: it
+ * simply checks for a file name containing a period (.) and
+ * suppresses the automatic appending of the template's extension,
+ * taking the entered filename as complete.
+ * @return this builder
+ * @see CreateFromTemplateHandler#FREE_FILE_EXTENSION
+ */
+ public SimpleTargetChooserBuilder freeFileExtension() {
+ this.freeFileExtension = true;
+ return this;
+ }
+ /**
+ * Creates the target chooser panel.
+ * @return a wizard panel prompting the user to choose a name and location
+ */
+ public WizardDescriptor.Panel create() {
+ return Utilities.getProjectChooserFactory().createSimpleTargetChooser(project, folders, bottomPanel, freeFileExtension);
+ }
}
}