package org.netbeans.gradle.project.newproject; import java.awt.Component; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.prefs.Preferences; import java.util.regex.Pattern; import javax.swing.JFileChooser; import javax.swing.text.JTextComponent; import org.jtrim.event.ListenerRef; import org.jtrim.event.ListenerRegistries; import org.jtrim.property.PropertySource; import org.jtrim.utils.ExceptionHelper; import org.netbeans.gradle.project.NbStrings; import org.netbeans.gradle.project.util.NbFileUtils; import org.netbeans.gradle.project.util.StringUtils; import org.netbeans.gradle.project.validate.BackgroundValidator; import org.netbeans.gradle.project.validate.Problem; import org.netbeans.gradle.project.validate.Validator; import org.netbeans.gradle.project.validate.Validators; import org.netbeans.spi.project.ui.support.ProjectChooser; import org.openide.WizardDescriptor; import org.openide.filesystems.FileUtil; import org.openide.util.NbPreferences; import org.openide.util.Utilities; import static org.netbeans.gradle.project.validate.Validators.*; public final class NewProjectUtils { public static final Charset DEFAULT_FILE_ENCODING = StringUtils.UTF8; private static final Pattern RECOMMENDED_PROJECTNAME_PATTERN = Pattern.compile("[a-zA-Z0-9_\\-.]*[a-zA-Z0-9]"); private static final Pattern MAVEN_GROUP_ID_PATTERN = Pattern.compile("[a-zA-Z0-9_\\-.]*[a-zA-Z0-9]"); private static final Pattern MAVEN_VERSION_PATTERN = Pattern.compile("[a-zA-Z0-9_\\-.]*[a-zA-Z0-9]"); public static Preferences getPreferences() { return NbPreferences.forModule(NewProjectUtils.class); } public static void copyTemplateFile( String resourcePath, Path destination, Charset encoding, Map<String, String> varReplaceMap) throws IOException { String resourceContent = StringUtils.getResourceAsString(resourcePath, encoding); for (Map.Entry<String, String> entry: varReplaceMap.entrySet()) { resourceContent = resourceContent.replace(entry.getKey(), entry.getValue()); } resourceContent = StringUtils.replaceLFWithPreferredLineSeparator(resourceContent); StringUtils.writeStringToFile(resourceContent, encoding, destination); } public static String getDefaultProjectDir(WizardDescriptor settings) { return ProjectChooser.getProjectsFolder().getAbsolutePath(); } public static void setDefaultProjectDir(String newValue) { File dir = new File(newValue.trim()); if (dir.isDirectory()) { ProjectChooser.setProjectsFolder(dir); } } public static Path resolveAndCreateDir(Path base, String dirName) throws IOException { Path result = base.resolve(dirName); Files.createDirectory(result); return result; } public static void createDefaultSourceDirs(Path projectDir) throws IOException { Path srcDir = resolveAndCreateDir(projectDir, "src"); Path mainDir = resolveAndCreateDir(srcDir, "main"); Path testDir = resolveAndCreateDir(srcDir, "test"); resolveAndCreateDir(mainDir, "java"); resolveAndCreateDir(mainDir, "resources"); resolveAndCreateDir(testDir, "java"); resolveAndCreateDir(testDir, "resources"); } public static void createMainClass(Path projectDir, String mainClass) throws IOException { ExceptionHelper.checkNotNullArgument(projectDir, "projectDir"); ExceptionHelper.checkNotNullArgument(mainClass, "mainClass"); String packageName; String simpleClassName; int classSepIndex = mainClass.lastIndexOf('.'); if (classSepIndex >= 0) { packageName = mainClass.substring(0, classSepIndex); simpleClassName = mainClass.substring(classSepIndex + 1); } else { packageName = ""; simpleClassName = mainClass; } String separator = projectDir.getFileSystem().getSeparator(); String relPackagePathStr = packageName.replace(".", separator); Path packagePath = projectDir.resolve("src").resolve("main").resolve("java"); if (!relPackagePathStr.isEmpty()) { packagePath = packagePath.resolve(relPackagePathStr); } List<String> content = new ArrayList<>(); if (!packageName.isEmpty()) { content.add("package " + packageName + ";"); content.add(""); } content.add("public class " + simpleClassName + " {"); content.add(" /**"); content.add(" * @param args the command line arguments"); content.add(" */"); content.add(" public static void main(String[] args) {"); content.add(" }"); content.add("}"); Path mainClassPath = packagePath.resolve(simpleClassName + ".java"); Files.createDirectories(packagePath); NbFileUtils.writeLinesToFile(mainClassPath, content, DEFAULT_FILE_ENCODING); } public static Validator<String> createProjectNameValidator() { Validator<String> patternValidators = merge( createFileNameValidator( Problem.Level.SEVERE, NewProjectStrings.getIllegalProjectName()), createPatternValidator(RECOMMENDED_PROJECTNAME_PATTERN, Problem.Level.WARNING, NewProjectStrings.getNotRecommendedProjectName())); Validator<String> notEmptyValidator = new Validator<String>() { @Override public Problem validateInput(String inputType) { return inputType.isEmpty() ? Problem.severe(NewProjectStrings.getProjectNameMustNotBeEmpty()) : null; } }; return merge(notEmptyValidator, patternValidators); } public static Validator<String> createGroupIdValidator() { return createPatternValidator( MAVEN_GROUP_ID_PATTERN, Problem.Level.SEVERE, NewProjectStrings.getInvalidGroupId()); } public static Validator<String> createVersionValidator() { return createPatternValidator( MAVEN_VERSION_PATTERN, Problem.Level.SEVERE, NewProjectStrings.getInvalidVersion()); } public static Validator<String> createNewFolderValidator() { return new Validator<String>() { @Override public Problem validateInput(String inputType) { String projectDirStr = inputType.trim(); if (projectDirStr.isEmpty()) { return Problem.severe(NewProjectStrings.getInvalidPath()); } File projectDir = FileUtil.normalizeFile(new File(projectDirStr)); if (projectDir == null) { return Problem.severe(NewProjectStrings.getInvalidPath()); } // This check is required because checking these kind of paths // can be extremly slow. if (Utilities.isWindows() && projectDir.getAbsolutePath().startsWith("\\\\")) { return Problem.severe(NewProjectStrings.getCannotCreateFolderHere()); } if (projectDir.exists()) { return Problem.severe(NewProjectStrings.getDirectoryAlreadyExists()); } File rootPath = projectDir; while (rootPath != null && !rootPath.exists()) { rootPath = rootPath.getParentFile(); } if (rootPath == null || !rootPath.canWrite() || !rootPath.isDirectory()) { return Problem.severe(NewProjectStrings.getCannotCreateFolderHere()); } return null; } }; } public static Validator<String> createVariableNameValidator() { return new Validator<String>() { @Override public Problem validateInput(String inputType) { if (inputType.isEmpty()) { return Problem.severe(NewProjectStrings.getIllegalIdentifier()); } if (!Character.isJavaIdentifierStart(inputType.charAt(0))) { return Problem.severe(NewProjectStrings.getIllegalIdentifier()); } for (int i = 1; i < inputType.length(); i++) { if (!Character.isJavaIdentifierPart(inputType.charAt(i))) { return Problem.severe(NewProjectStrings.getIllegalIdentifier()); } } return null; } }; } public static Validator<String> createClassNameValidator(final boolean optional) { final Validator<String> varNameValidator = createVariableNameValidator(); return new Validator<String>() { @Override public Problem validateInput(String inputType) { if (optional && inputType.isEmpty()) { return null; } if (inputType.endsWith(".")) { return Problem.severe(NewProjectStrings.getIllegalIdentifier()); } String[] parts = inputType.split(Pattern.quote(".")); for (String part: parts) { Problem problem = varNameValidator.validateInput(part); if (problem != null) { assert problem.getLevel() == Problem.Level.SEVERE; return problem; } } if (parts.length == 1) { return Problem.warning(NewProjectStrings.getShouldNotUseDefaultPackage()); } return null; } }; } public static void chooseProjectLocation(Component parent, JTextComponent jProjectEdit) { ExceptionHelper.checkNotNullArgument(jProjectEdit, "jProjectEdit"); JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(null); chooser.setDialogTitle(NbStrings.getSelectProjectLocationCaption()); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); String path = jProjectEdit.getText(); if (!path.isEmpty()) { File initialSelection = new File(path); if (initialSelection.exists()) { chooser.setSelectedFile(initialSelection); } } if (JFileChooser.APPROVE_OPTION == chooser.showOpenDialog(parent)) { File projectDir = chooser.getSelectedFile(); jProjectEdit.setText(FileUtil.normalizeFile(projectDir).getAbsolutePath()); } } public static ListenerRef setupNewProjectValidators( final BackgroundValidator bckgValidator, final JTextComponent jProjectNameEdit, final JTextComponent jProjectFolderEdit, final JTextComponent jProjectLocationEdit) { ExceptionHelper.checkNotNullArgument(bckgValidator, "bckgValidator"); ExceptionHelper.checkNotNullArgument(jProjectNameEdit, "jProjectNameEdit"); ExceptionHelper.checkNotNullArgument(jProjectFolderEdit, "jProjectFolderEdit"); ExceptionHelper.checkNotNullArgument(jProjectLocationEdit, "jProjectLocationEdit"); PropertySource<String> projectName = Validators.trimmedText(jProjectNameEdit); PropertySource<String> projectFolder = Validators.trimmedText(jProjectFolderEdit); PropertySource<String> projectLocation = Validators.trimmedText(jProjectLocationEdit); List<ListenerRef> refs = new ArrayList<>(); refs.add(bckgValidator.addValidator( NewProjectUtils.createProjectNameValidator(), projectName)); refs.add(bckgValidator.addValidator( NewProjectUtils.createNewFolderValidator(), projectFolder)); Runnable projectFolderUpdater = new Runnable() { @Override public void run() { File location = new File( jProjectLocationEdit.getText().trim(), jProjectNameEdit.getText().trim()); jProjectFolderEdit.setText(location.getPath()); } }; refs.add(projectName.addChangeListener(projectFolderUpdater)); refs.add(projectLocation.addChangeListener(projectFolderUpdater)); return ListenerRegistries.combineListenerRefs(refs.toArray(new ListenerRef[refs.size()])); } private NewProjectUtils() { throw new AssertionError(); } }