├── .gitignore ├── .travis.yml ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.md ├── settings.gradle └── src └── main ├── java └── com │ └── jme3 │ └── bootmonkey │ ├── GenerationListener.java │ ├── GitUtils.java │ ├── ProjectGenerator.java │ ├── Proto.java │ ├── TestJGit.java │ └── ui │ ├── Icons.java │ ├── MainWindow.java │ ├── ProgressDialog.java │ └── SpringLayoutHelper.java └── resources └── icons ├── icon.icns ├── iconx128.png ├── iconx16.png ├── iconx32.png └── iconx64.png /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .gradle/ 3 | build/ 4 | /.nb-gradle/ 5 | .directory -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | before_cache: 7 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 8 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 9 | cache: 10 | directories: 11 | - $HOME/.gradle/caches/ 12 | - $HOME/.gradle/wrapper/ 13 | 14 | 15 | os: 16 | - linux 17 | 18 | install: 19 | - ./gradlew assemble 20 | 21 | script: 22 | - ./gradlew check 23 | 24 | deploy: 25 | provider: releases 26 | api_key: 27 | secure: ${GH_TOKEN} 28 | file_glob: true 29 | file: "${RELEASE_DIST}" 30 | skip_cleanup: true 31 | on: 32 | repo: Nehon/bootmonkey 33 | tags: true 34 | 35 | 36 | before_deploy: 37 | - ./gradlew fatJar 38 | - RELEASE_DIST=$(ls build/libs/*-exec-*.jar) 39 | # - ./gradlew createBundle 40 | # - RELEASE_DIST=$(ls build/distributions/*app.zip) 41 |   -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.jme3' 2 | version '1.0-SNAPSHOT' 3 | import org.apache.tools.ant.taskdefs.condition.Os 4 | 5 | 6 | apply plugin: 'java' 7 | apply plugin: 'application' 8 | apply plugin: "org.mini2Dx.parcl" 9 | mainClassName='com.jme3.bootmonkey.ui.MainWindow' 10 | 11 | sourceCompatibility = 1.8 12 | 13 | repositories { 14 | mavenLocal() 15 | mavenCentral() 16 | 17 | } 18 | 19 | dependencies { 20 | compile 'org.eclipse.jgit:org.eclipse.jgit:4.5.0.201609210915-r' 21 | compile 'commons-io:commons-io:2.5' 22 | compile 'org.apache.commons:commons-lang3:3.4' 23 | compile 'org.yaml:snakeyaml:1.17' 24 | compile "com.github.insubstantial:substance:[7.3,)" 25 | 26 | testCompile group: 'junit', name: 'junit', version: '4.11' 27 | } 28 | 29 | buildscript { 30 | repositories { 31 | mavenCentral() 32 | maven { url "https://mini2dx.org/maven/content/repositories/thirdparty" } 33 | maven { url "https://mini2dx.org/maven/content/repositories/releases" } 34 | } 35 | dependencies { 36 | //classpath 'com.github.mini2Dx:parcl:v1.0.10' 37 | classpath 'org.mini2Dx:parcl:1.0.7' 38 | // classpath 'com.github.spullara.mustache.java:compiler:0.9.4' 39 | } 40 | } 41 | 42 | 43 | task runProto(type: JavaExec) { 44 | classpath sourceSets.main.runtimeClasspath 45 | main = "com.jme3.bootmonkey.Proto" 46 | } 47 | 48 | // Create a custom server start script in the distribution 49 | task makeScript(type: CreateStartScripts) { 50 | mainClassName = "com.jme3.bootmonkey.ui.MainWindow" 51 | applicationName = "bootmonkey" 52 | outputDir = new File(project.buildDir, 'scripts') 53 | classpath = jar.outputs.files + project.configurations.runtime 54 | // defaultJvmOpts = ['-Dlog4j.configurationFile=server-log4j2.xml'] 55 | } 56 | 57 | // I think this is ultimately clearer than the above 58 | distributions { 59 | main { 60 | contents { 61 | from(makeScript) { 62 | into "bin" 63 | } 64 | } 65 | } 66 | } 67 | 68 | parcl { 69 | exe { 70 | exeName = "BootMonkey" 71 | } 72 | 73 | app { 74 | appName = "BootMonkey" 75 | icon = "src/main/resources/icons/icon.icns" 76 | applicationCategory = "public.app-category.jme3-tool-suite" 77 | displayName = 'BootMonkey' 78 | identifier = 'com.jme3.bootmonkey' 79 | copyright = 'Copyright 2016 jMonkeyEngine' 80 | 81 | } 82 | 83 | linux { 84 | binName = "bootmonkey" 85 | 86 | } 87 | } 88 | 89 | 90 | task createBundle(type: Zip, dependsOn:bundleNative) { 91 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 92 | from 'build/windows' 93 | archiveName "bootmonkey-$version-windows-app.zip" 94 | } else if (Os.isFamily(Os.FAMILY_MAC)){ 95 | from 'build/mac' 96 | archiveName "bootmonkey-$version-osx-app.zip" 97 | } else { 98 | from 'build/linux' 99 | archiveName "bootmonkey-$version-linux-app.zip" 100 | } 101 | include '**/*' 102 | 103 | } 104 | 105 | 106 | //create a single Jar with all dependencies 107 | task fatJar(type: Jar) { 108 | 109 | from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } 110 | exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' 111 | baseName = project.name + '-exec' 112 | manifest { 113 | attributes 'Implementation-Title': 'Bootmonkey executable jar', 114 | 'Implementation-Version': version, 115 | 'Main-Class': "$mainClassName" 116 | } 117 | with jar 118 | } 119 | 120 | // Either way we end up with dupes if we don't do this 121 | distZip { 122 | duplicatesStrategy = 'exclude' 123 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nehon/bootmonkey/60df37e75d0987e01109b6b0bc9de8cad5818b6c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 12 13:38:44 CEST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | BootMonkey 2 | ========== 3 | 4 | Very Basic project scaffolding tool for JME3. 5 | 6 | 1. Clones a template repository into a local folder. For adaptation, the template repo must contain a bootmonkey.yml file. 7 | 8 | 2. Attempts to change lines in project files as described in the bootmonkey.yml 9 | the file must be follow that structure: 10 | ``` 11 | replace: 12 | [filePath]: 13 | [search1]: [replacement1] 14 | [search2]: [replacement2] 15 | ... 16 | ``` 17 | - filePath is the path to the file to modify from the project root. 18 | - searchN is a regular expression to search in the file 19 | - replacementN is the text that will replace the regexp match. You can use template variables in this replacement: 20 | - templateUrl: the project template git repo url. 21 | - baseDir: the directory where to create the repo. 22 | - projectName: the project name. 23 | - packageName: the new project base package. 24 | - jmeVersion: the jme version code. 25 | - packagePath: the folder path of the package ('.' replaced with '/') 26 | 27 | 3. Clean up 28 | 29 | Will copy and delete files according to what's found in the yaml configuration file 30 | the file must be follow that structure: 31 | ``` 32 | copy: 33 | [srcPath]: [destPath] 34 | ... 35 | delete: 36 | - [fileORDirectoryPath] 37 | - ... 38 | ``` 39 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'bootmonkey' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/com/jme3/bootmonkey/GenerationListener.java: -------------------------------------------------------------------------------- 1 | package com.jme3.bootmonkey; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Nehon on 12/10/2016. 7 | */ 8 | @FunctionalInterface 9 | public interface GenerationListener { 10 | void progress(String newState, List errors); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/jme3/bootmonkey/GitUtils.java: -------------------------------------------------------------------------------- 1 | package com.jme3.bootmonkey; 2 | 3 | import org.eclipse.jgit.api.Git; 4 | import org.eclipse.jgit.api.errors.GitAPIException; 5 | import org.eclipse.jgit.lib.Ref; 6 | 7 | import java.io.*; 8 | import java.util.*; 9 | 10 | /** 11 | * Created by Nehon on 16/10/2016. 12 | */ 13 | public class GitUtils { 14 | 15 | public static List getRemoteBranches(String repoUrl) throws IOException, GitAPIException { 16 | Collection refs = Git.lsRemoteRepository().setRemote(repoUrl).call(); 17 | List names = new ArrayList<>(); 18 | refs.forEach((ref) -> { 19 | // System.err.println(ref); 20 | if(!ref.getName().equals("HEAD" ) && !ref.getName().equals("refs/heads/master") && !ref.getName().startsWith("refs/pull")){ 21 | names.add(ref.getName()); 22 | } 23 | }); 24 | return names; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/jme3/bootmonkey/ProjectGenerator.java: -------------------------------------------------------------------------------- 1 | package com.jme3.bootmonkey; 2 | 3 | import org.apache.commons.io.FileUtils; 4 | import org.apache.commons.lang3.text.StrSubstitutor; 5 | import org.eclipse.jgit.api.Git; 6 | import org.eclipse.jgit.api.errors.GitAPIException; 7 | import org.eclipse.jgit.api.errors.JGitInternalException; 8 | import org.yaml.snakeyaml.Yaml; 9 | 10 | import java.io.*; 11 | import java.util.*; 12 | 13 | /** 14 | * Created by Nehon on 12/10/2016. 15 | * Very Basic project scaffolding tool for JME3. 16 | * 1. Clones a template repository into a local folder. For adaptation, the template repo must contain a bootmonkey.yml file. 17 | * 2. attempt to change lines in project files as described in the bootmonkey.yml 18 | * the file must be follow that structure: 19 | * replace: 20 | * [filePath]: 21 | * [search1]: [replacement1] 22 | * [search2]: [replacement2] 23 | * ... 24 | * - filePath is the path to the file to modify from the project root. 25 | * - searchN is a regular expression to search in the file 26 | * - replacementN is the text that will replace the regexp match. You can use template variables in this replacement: 27 | * - templateUrl: the project template git repo url. 28 | * - baseDir: the directory where to create the repo. 29 | * - projectName: the project name. 30 | * - packageName: the new project base package. 31 | * - packagePath: the folder path of the package ('.' replaced with '/') 32 | * 33 | * 3. Clean up 34 | * Will copy and delete files according to what's found in the yaml configuration file 35 | * the file must be follow that structure: 36 | * copy: 37 | * [srcPath]: [destPath] 38 | * ... 39 | * delete: 40 | * - [fileORDirectoryPath] 41 | * - ... 42 | * 43 | * You can add GenerationListener that will be called whenever the generation process reaches a new step, with errors from the previous step. 44 | * 45 | */ 46 | public class ProjectGenerator { 47 | 48 | private static String CONF_FILE = "bootmonkey.yml"; 49 | 50 | private Map> replacements; 51 | private Map copies; 52 | private List deletes; 53 | private String tmpContent; 54 | private StrSubstitutor sub; 55 | private List lastGenerationErrors = new ArrayList<>(); 56 | private List listeners = new ArrayList<>(); 57 | 58 | public ProjectGenerator() { 59 | 60 | } 61 | 62 | private void readConfiguration(String projectPath) { 63 | try { 64 | Yaml yaml = new Yaml(); 65 | Map map = (Map) yaml.load(FileUtils.readFileToString(new File(projectPath + CONF_FILE), "UTF-8")); 66 | 67 | if (map.get("replace") != null) { 68 | replacements = (Map>) map.get("replace"); 69 | } 70 | if (map.get("copy") != null) { 71 | copies = (Map) map.get("copy"); 72 | } 73 | if (map.get("delete") != null) { 74 | deletes = (List) map.get("delete"); 75 | } 76 | } catch (IOException e){ 77 | reportError("No configuration (" + CONF_FILE + ") file found in the template project. No adaptation has been done.", e); 78 | } 79 | } 80 | 81 | 82 | /** 83 | * Generates a project given a param map. 84 | * The param map must contain : 85 | * 86 | * templateUrl: the project template git repo url. 87 | * baseDir: the directory where to create the repo. 88 | * projectName: the project name. 89 | * packageName: the new project base package. 90 | * 91 | * optional params: 92 | * tagName: can provide a branch name or a tag name in its complete form (ie refs/tags/myTag or refs/heads/myBranch) 93 | * 94 | * Those params can be used as template names in the replacement.yml file (ie: ${projectName}) 95 | * 96 | * this method returns a list of error that occurred during the generation 97 | * @param params the params map. 98 | */ 99 | public void generate(Map params){ 100 | 101 | progress("Initializing..."); 102 | sub = new StrSubstitutor(params, "${", "}"); 103 | String templateUrl = params.get("templateUrl"); 104 | String baseDir = params.get("baseDir"); 105 | String projectName = params.get("projectName"); 106 | String packageName = params.get("packageName"); 107 | String tagName = params.get("tagName"); 108 | String packagePath = packageName.replaceAll("\\.", "/"); 109 | params.put("packagePath", packagePath); 110 | String projectPath = baseDir + projectName + "/"; 111 | 112 | progress("Cloning template project..."); 113 | if(!cloneTemplate(templateUrl, projectPath, tagName)){ 114 | progress("Aborted."); 115 | return; 116 | } 117 | 118 | progress("Reading configuration..."); 119 | readConfiguration(projectPath); 120 | 121 | progress("Adapting project..."); 122 | replacements.entrySet().forEach((e) -> adaptFile(projectPath + e.getKey(), e.getValue())); 123 | 124 | progress("Cleaning up..."); 125 | moveAndCleanupFiles(projectPath); 126 | 127 | progress("Done."); 128 | 129 | } 130 | 131 | private void moveAndCleanupFiles(String projectPath) { 132 | try { 133 | for (Map.Entry copy : copies.entrySet()) { 134 | FileUtils.copyFile(new File(projectPath + copy.getKey()), new File(projectPath + sub.replace(copy.getValue()))); 135 | } 136 | } catch (IOException e) { 137 | reportError("Error while moving and cleaning up", e); 138 | } 139 | 140 | for (String delete : deletes) { 141 | String subDelete = sub.replace(delete); 142 | boolean deleted = FileUtils.deleteQuietly(new File(projectPath + subDelete)); 143 | if(!deleted){ 144 | reportError("Error while deleting " + subDelete, new Exception(delete)); 145 | } 146 | } 147 | 148 | //delete the configuration file if any 149 | FileUtils.deleteQuietly(new File(projectPath + CONF_FILE)); 150 | 151 | 152 | } 153 | 154 | private boolean cloneTemplate(String templateUrl, String projectPath, String tagName) { 155 | try (Git git = Git.cloneRepository().setURI(templateUrl) 156 | .setDirectory(new File(projectPath)).call()){ 157 | 158 | //This is how you checkout a branch or a tag, note that it will create a detached HEAD, 159 | // but we don't really care as we will wipe out git config once the file are properly downloaded. 160 | if(tagName != null){ 161 | if(tagName.startsWith("refs/heads")){ 162 | //it's a branch 163 | //Note that the branch name as we get it is "refs/heads/branchName", but to check it out we need to call it "origin/branchName" 164 | git.checkout().setName( "origin/" + tagName.replaceAll("refs/heads/","") ).call(); 165 | } else { 166 | //it's a tag 167 | git.checkout().setName( tagName ).call(); 168 | } 169 | } 170 | 171 | return true; 172 | } catch (GitAPIException | JGitInternalException e) { 173 | reportError("Error cloning repository " + templateUrl , e); 174 | return false; 175 | } 176 | } 177 | 178 | 179 | private void adaptFile(String fileName, Map replacement) { 180 | try { 181 | 182 | tmpContent = FileUtils.readFileToString(new File(fileName), "UTF-8"); 183 | replacement.forEach((key, value) -> { 184 | String finalValue = sub.replace(value); 185 | tmpContent = tmpContent.replaceAll(key, finalValue); 186 | }); 187 | 188 | //System.err.println(tmpContent); 189 | FileUtils.writeStringToFile(new File(fileName), tmpContent, "UTF-8"); 190 | } catch (IOException e) { 191 | reportError("Issue adapting file " + fileName, e); 192 | } 193 | } 194 | 195 | private void reportError(String message, Exception e){ 196 | lastGenerationErrors.add(message+ ": " +e.getMessage()); 197 | e.printStackTrace(); 198 | } 199 | 200 | public void addGenerationListener(GenerationListener l){ 201 | listeners.add(l); 202 | } 203 | 204 | public void removeGenerationListener(GenerationListener l){ 205 | listeners.add(l); 206 | } 207 | 208 | private void progress(String newState){ 209 | listeners.forEach((l) -> l.progress(newState, new ArrayList<>(lastGenerationErrors))); 210 | lastGenerationErrors.clear(); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/main/java/com/jme3/bootmonkey/Proto.java: -------------------------------------------------------------------------------- 1 | package com.jme3.bootmonkey; 2 | 3 | import org.eclipse.jgit.api.errors.GitAPIException; 4 | 5 | import java.io.IOException; 6 | import java.util.*; 7 | 8 | import static com.jme3.bootmonkey.GitUtils.getRemoteBranches; 9 | 10 | /** 11 | * Created by bouquet on 12/10/16. 12 | */ 13 | public class Proto { 14 | 15 | public static void main(String... argv) { 16 | 17 | Map params = new HashMap<>(); 18 | params.put("packageName", "org.myorg.mygame"); 19 | params.put("jmeVersion", "[3.1,)"); 20 | params.put("baseDir", "e:/JME/"); 21 | params.put("projectName", "baseJME"); 22 | params.put("templateUrl", "https://github.com/Nehon/base-jme.git"); 23 | 24 | // ProjectGenerator generator = new ProjectGenerator(); 25 | // generator.addGenerationListener((text , errors) -> { 26 | // for (String error : errors) { 27 | // System.err.println(error); 28 | // } 29 | // System.out.println(text); 30 | // }); 31 | 32 | try { 33 | List list = GitUtils.getRemoteBranches("https://github.com/Nehon/base-jme.git"); 34 | list.forEach(System.out::println); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } catch (GitAPIException e) { 38 | e.printStackTrace(); 39 | } 40 | 41 | 42 | //generator.generate(params); 43 | 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/jme3/bootmonkey/TestJGit.java: -------------------------------------------------------------------------------- 1 | package com.jme3.bootmonkey; 2 | import java.io.File; 3 | import java.io.IOException; 4 | 5 | import org.eclipse.jgit.api.*; 6 | import org.eclipse.jgit.api.errors.*; 7 | import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; 8 | import org.eclipse.jgit.internal.storage.file.FileRepository; 9 | import org.eclipse.jgit.lib.Repository; 10 | 11 | 12 | public class TestJGit { 13 | 14 | private String localPath, remotePath; 15 | private Repository localRepo; 16 | private Git git; 17 | 18 | public void init() throws IOException { 19 | localPath = "/home/me/repos/mytest"; 20 | remotePath = "git@github.com:me/mytestrepo.git"; 21 | localRepo = new FileRepository(localPath + "/.git"); 22 | git = new Git(localRepo); 23 | } 24 | 25 | public void testCreate() throws IOException { 26 | Repository newRepo = new FileRepository(localPath + ".git"); 27 | newRepo.create(); 28 | } 29 | 30 | 31 | public void testClone() throws IOException, GitAPIException { 32 | Git.cloneRepository().setURI(remotePath) 33 | .setDirectory(new File(localPath)).call(); 34 | } 35 | 36 | 37 | public void testAdd() throws IOException, GitAPIException { 38 | File myfile = new File(localPath + "/myfile"); 39 | myfile.createNewFile(); 40 | git.add().addFilepattern("myfile").call(); 41 | } 42 | 43 | 44 | public void testCommit() throws IOException, GitAPIException, 45 | JGitInternalException { 46 | git.commit().setMessage("Added myfile").call(); 47 | } 48 | 49 | 50 | public void testPush() throws IOException, JGitInternalException, 51 | GitAPIException { 52 | git.push().call(); 53 | } 54 | 55 | 56 | public void testTrackMaster() throws IOException, JGitInternalException, 57 | GitAPIException { 58 | git.branchCreate().setName("master") 59 | .setUpstreamMode(SetupUpstreamMode.SET_UPSTREAM) 60 | .setStartPoint("origin/master").setForce(true).call(); 61 | } 62 | 63 | 64 | public void testPull() throws IOException, GitAPIException { 65 | git.pull().call(); 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/java/com/jme3/bootmonkey/ui/Icons.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this template, choose Tools | Templates 3 | * and open the template in the editor. 4 | */ 5 | package com.jme3.bootmonkey.ui; 6 | 7 | import javax.swing.*; 8 | 9 | /** 10 | * @author Nehon 11 | */ 12 | public class Icons { 13 | 14 | // public final static ImageIcon icon = new ImageIcon(Icons.class.getResource("/icons/favicon.ico")); 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/main/java/com/jme3/bootmonkey/ui/MainWindow.java: -------------------------------------------------------------------------------- 1 | package com.jme3.bootmonkey.ui; 2 | 3 | import com.jme3.bootmonkey.*; 4 | import org.eclipse.jgit.api.errors.GitAPIException; 5 | import org.pushingpixels.substance.api.skin.SubstanceGraphiteGlassLookAndFeel; 6 | 7 | import javax.swing.*; 8 | import java.awt.*; 9 | import java.awt.event.*; 10 | import java.io.*; 11 | import java.net.URI; 12 | import java.util.*; 13 | import java.util.List; 14 | import java.util.prefs.Preferences; 15 | 16 | import static com.jme3.bootmonkey.ui.SpringLayoutHelper.makeCompactGrid; 17 | 18 | /** 19 | * Created by Nehon on 12/10/2016. 20 | */ 21 | public class MainWindow { 22 | 23 | public static final String REPOSITORIES = "bootmonkey.repositories"; 24 | public static final String LAST_SELECTED_REPOSITORY = "bootmonkey.lastSelectedRepository"; 25 | public static final String DEFAULT_REPOSITORY = "https://github.com/Nehon/base-jme.git"; 26 | public static final String LAST_DIRECTORY = "bootmonkey.lastDirectory"; 27 | private ProgressDialog progressDialog; 28 | private Preferences prefs = Preferences.userNodeForPackage(MainWindow.class); 29 | private String repoList; 30 | 31 | private JComboBox repoField; 32 | private JComboBox versionField; 33 | 34 | public static void main(String... argv) throws Exception{ 35 | new MainWindow(); 36 | } 37 | 38 | public MainWindow() throws Exception { 39 | JFrame.setDefaultLookAndFeelDecorated(true); 40 | JPopupMenu.setDefaultLightWeightPopupEnabled(false); 41 | UIManager.setLookAndFeel(new SubstanceGraphiteGlassLookAndFeel()); 42 | 43 | SwingUtilities.invokeAndWait(new Runnable() { 44 | public void run() { 45 | //creating the main window 46 | final JFrame mainFrame = new JFrame("Boot monkey"); 47 | mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 48 | mainFrame.getContentPane().setLayout(new BorderLayout()); 49 | mainFrame.setResizable(false); 50 | 51 | //setting up windows icons 52 | setupIcons(mainFrame); 53 | 54 | //creating the progress Dialog 55 | progressDialog = new ProgressDialog(mainFrame, "Generation progress"); 56 | 57 | //presentation label 58 | JLabel label = new JLabel("Create a new jMonkeyEngine3 project"); 59 | mainFrame.getContentPane().add(label, BorderLayout.NORTH); 60 | 61 | //creating the form 62 | JPanel container = new JPanel(new SpringLayout()); 63 | 64 | //Project name field 65 | JLabel l = new JLabel("Project Name: ", JLabel.TRAILING); 66 | container.add(l); 67 | final JTextField projectNameField = new JTextField(10); 68 | l.setLabelFor(projectNameField); 69 | projectNameField.setText("MyGame"); 70 | container.add(projectNameField); 71 | 72 | //Default package field 73 | l = new JLabel("Default package: ", JLabel.TRAILING); 74 | container.add(l); 75 | final JTextField packageField = new JTextField(10); 76 | l.setLabelFor(packageField); 77 | packageField.setText("com.mycompany.mygame"); 78 | container.add(packageField); 79 | 80 | //Template repository url field 81 | l = new JLabel("Template repo url: ", JLabel.TRAILING); 82 | container.add(l); 83 | repoList = prefs.get(REPOSITORIES, DEFAULT_REPOSITORY); 84 | String lastRepo = prefs.get(LAST_SELECTED_REPOSITORY, DEFAULT_REPOSITORY); 85 | String [] values = repoList.split("\\|"); 86 | 87 | JPanel repoFieldPanel = new JPanel(new FlowLayout(FlowLayout.LEADING)); 88 | 89 | repoField = new JComboBox(values); 90 | repoField.setEditable(true); 91 | repoField.setSelectedItem(lastRepo); 92 | l.setLabelFor(repoField); 93 | repoFieldPanel.add(repoField); 94 | //creating an info button. 95 | JButton infoButton = new JButton("?"); 96 | infoButton.setPreferredSize(new Dimension(25, 20)); 97 | repoFieldPanel.add(infoButton); 98 | container.add(repoFieldPanel); 99 | infoButton.addActionListener((e) -> { 100 | Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; 101 | if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { 102 | try { 103 | desktop.browse(new URI((String)repoField.getSelectedItem())); 104 | } catch (Exception ex) { 105 | ex.printStackTrace(); 106 | } 107 | } 108 | }); 109 | 110 | //Template version field 111 | l = new JLabel("Template version: ", JLabel.TRAILING); 112 | container.add(l); 113 | versionField = new JComboBox(); 114 | versionField.setRenderer((JList list, String value, int index, boolean isSelected, boolean cellHasFocus) -> { 115 | JLabel label1 = new JLabel(value); 116 | if(value.contains("/")){ 117 | label1.setText(value.substring(value.lastIndexOf("/") + 1)); 118 | } 119 | return label1; 120 | }); 121 | container.add(versionField); 122 | versionField.addItem("SNAPSHOT"); 123 | //fetching data 124 | new FetchBranchWorker().execute(); 125 | 126 | //setting up the callback to fetch data whenever the template repo changes 127 | repoField.addActionListener((e) -> new FetchBranchWorker().execute()); 128 | 129 | //Project folder field. 130 | l = new JLabel("Create project in folder: ", JLabel.TRAILING); 131 | container.add(l); 132 | JPanel browseFieldPanel = new JPanel(new FlowLayout(FlowLayout.LEADING)); 133 | final JTextField baseDirField = new JTextField(20); 134 | l.setLabelFor(baseDirField); 135 | String lastDir = prefs.get(LAST_DIRECTORY, ""); 136 | baseDirField.setText(lastDir); 137 | browseFieldPanel.add(baseDirField); 138 | //creating a browse button. 139 | JButton browseButton = new JButton("..."); 140 | browseButton.setPreferredSize(new Dimension(20, 15)); 141 | browseFieldPanel.add(browseButton); 142 | final JFileChooser fc = new JFileChooser(); 143 | fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 144 | browseButton.addActionListener((e) -> { 145 | int returnVal = fc.showOpenDialog(mainFrame); 146 | if (returnVal == JFileChooser.APPROVE_OPTION) { 147 | File file = fc.getSelectedFile(); 148 | baseDirField.setText(file.getPath()); 149 | } 150 | }); 151 | container.add(browseFieldPanel); 152 | 153 | /*The advanced settings frame 154 | final JFrame advancedSettingsFrame=new JFrame("Advanced Settings"); 155 | advancedSettingsFrame.getContentPane().setLayout(new BorderLayout()); 156 | advancedSettingsFrame.setResizable(false);*/ 157 | 158 | /*JButton button = new JButton("Close"); 159 | button.addActionListener((e) -> { 160 | advancedSettingsFrame.setVisible(false); 161 | }); 162 | advancedSettingsFrame.getContentPane().add(button, BorderLayout.SOUTH);*/ 163 | 164 | /*The advanced settings button 165 | l = new JLabel("Advanced Settings: ", JLabel.TRAILING); 166 | JButton defineButton = new JButton("Show advanced settings"); 167 | defineButton.addActionListener((e) -> { 168 | advancedSettingsFrame.pack(); 169 | advancedSettingsFrame.setLocationRelativeTo(mainFrame); 170 | advancedSettingsFrame.setVisible(true); 171 | }); 172 | 173 | JPanel settingsPanel=new JPanel(new FlowLayout(FlowLayout.LEADING)); 174 | settingsPanel.add(defineButton); 175 | 176 | container.add(l); 177 | container.add(settingsPanel);*/ 178 | 179 | //making the layout. 180 | 181 | //final JPanel settingsContainer = new JPanel(new SpringLayout()); 182 | 183 | l=new JLabel("JME Version code:", JLabel.TRAILING); 184 | final JTextField jmeVersionField = new JTextField(10); 185 | jmeVersionField.setText("[3.1,)"); 186 | l.setLabelFor(jmeVersionField); 187 | 188 | container.add(l); 189 | container.add(jmeVersionField); 190 | 191 | //mainFrame.getContentPane().add(settingsContainer, BorderLayout.SOUTH); 192 | 193 | /*makeCompactGrid(settingsContainer, 194 | 1, 2, //rows, cols 195 | 6, 6, //initX, initY 196 | 7, 7); //xPad, yPad*/ 197 | 198 | makeCompactGrid(container, 199 | 6, 2, //rows, cols 200 | 5, 5, //initX, initY 201 | 7, 7); //xPad, yPad 202 | 203 | mainFrame.getContentPane().add(container, BorderLayout.CENTER); 204 | 205 | //The create button 206 | JButton button = new JButton("Create"); 207 | button.addActionListener((e) -> { 208 | 209 | if(!validate(mainFrame, projectNameField, packageField, repoField, baseDirField)){ 210 | return; 211 | } 212 | progressDialog.display(); 213 | 214 | String repoUrl = (String) repoField.getSelectedItem(); 215 | String baseDir = baseDirField.getText(); 216 | 217 | savePreferences(repoUrl, baseDir); 218 | 219 | new ProjectGenerationWorker(projectNameField, packageField, jmeVersionField, repoUrl, baseDir).execute(); 220 | 221 | }); 222 | mainFrame.getContentPane().add(button, BorderLayout.SOUTH); 223 | 224 | //pack and display 225 | mainFrame.pack(); 226 | mainFrame.setLocationRelativeTo(null); 227 | mainFrame.setVisible(true); 228 | } 229 | 230 | 231 | }); 232 | } 233 | 234 | private void savePreferences(String repoUrl, String baseDir) { 235 | if(!repoList.contains(repoUrl)){ 236 | repoList += "|" + repoUrl; 237 | prefs.put(REPOSITORIES, repoList); 238 | } 239 | prefs.put(LAST_SELECTED_REPOSITORY, repoUrl); 240 | prefs.put(LAST_DIRECTORY, baseDir); 241 | } 242 | 243 | private void setupIcons(JFrame mainFrame) { 244 | try { 245 | List icons = new ArrayList<>(); 246 | icons.add(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("/icons/iconx16.png"))); 247 | icons.add(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("/icons/iconx32.png"))); 248 | icons.add(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("/icons/iconx64.png"))); 249 | icons.add(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("/icons/iconx128.png"))); 250 | mainFrame.setIconImages(icons); 251 | SystemTray.getSystemTray().add(new TrayIcon(Toolkit.getDefaultToolkit().getImage("/icons/icon16.png"))); 252 | } catch (AWTException e) { 253 | e.printStackTrace(); 254 | } 255 | } 256 | 257 | private boolean validate(JFrame mainFrame, JTextField projectNameField, JTextField packageField, JComboBox repoField, JTextField baseDirField) { 258 | if(packageField.getText().equals("")){ 259 | JOptionPane.showMessageDialog(mainFrame, "Package field must not be empty", "Error", JOptionPane.ERROR_MESSAGE); 260 | return false; 261 | } 262 | if(projectNameField.getText().equals("")){ 263 | JOptionPane.showMessageDialog(mainFrame, "Project name field must not be empty", "Error", JOptionPane.ERROR_MESSAGE); 264 | return false; 265 | } 266 | if(repoField.getSelectedItem().equals("")){ 267 | JOptionPane.showMessageDialog(mainFrame, "Template repository url must not be empty", "Error", JOptionPane.ERROR_MESSAGE); 268 | return false; 269 | } 270 | if(baseDirField.getText().equals("")){ 271 | JOptionPane.showMessageDialog(mainFrame, "Project folder must not be empty", "Error", JOptionPane.ERROR_MESSAGE); 272 | return false; 273 | } 274 | 275 | return true; 276 | } 277 | 278 | private class Step{ 279 | String text; 280 | java.util.List errors; 281 | 282 | public Step(String text, java.util.List errors) { 283 | this.text = text; 284 | this.errors = errors; 285 | } 286 | 287 | @Override 288 | public String toString() { 289 | return "Step{" + 290 | "text='" + text + '\'' + 291 | ", errors=" + errors + 292 | '}'; 293 | } 294 | } 295 | 296 | private class FetchBranchWorker extends SwingWorker{ 297 | List list; 298 | 299 | @Override 300 | protected Void doInBackground() throws Exception { 301 | try { 302 | list = GitUtils.getRemoteBranches((String)repoField.getSelectedItem()); 303 | } catch (IOException | GitAPIException e1) { 304 | e1.printStackTrace(); 305 | } 306 | return null; 307 | } 308 | 309 | @Override 310 | protected void done() { 311 | versionField.removeAllItems(); 312 | versionField.addItem("SNAPSHOT"); 313 | list.forEach(versionField::addItem); 314 | } 315 | } 316 | 317 | 318 | private class ProjectGenerationWorker extends SwingWorker{ 319 | 320 | Map params; 321 | 322 | public ProjectGenerationWorker(JTextField projectNameField, JTextField packageField, JTextField jmeVersionField, String repoUrl, String baseDir) { 323 | params = new HashMap<>(); 324 | params.put("packageName", packageField.getText()); 325 | params.put("jmeVersion", jmeVersionField.getText()); 326 | params.put("baseDir", baseDir + "/"); 327 | params.put("projectName", projectNameField.getText()); 328 | params.put("templateUrl", repoUrl); 329 | 330 | System.out.println(params.get("jmeVersion")); 331 | } 332 | 333 | @Override 334 | protected Void doInBackground() throws Exception { 335 | ProjectGenerator generator = new ProjectGenerator(); 336 | generator.addGenerationListener((text , errors) -> publish(new Step(text, errors))); 337 | generator.generate(params); 338 | return null; 339 | } 340 | 341 | @Override 342 | protected void process(java.util.List steps) { 343 | steps.forEach((s) -> progressDialog.progress(s.text, s.errors)); 344 | } 345 | 346 | }; 347 | } 348 | -------------------------------------------------------------------------------- /src/main/java/com/jme3/bootmonkey/ui/ProgressDialog.java: -------------------------------------------------------------------------------- 1 | package com.jme3.bootmonkey.ui; 2 | 3 | import javax.swing.*; 4 | import javax.swing.text.AttributeSet; 5 | import javax.swing.text.SimpleAttributeSet; 6 | import javax.swing.text.StyleConstants; 7 | import javax.swing.text.StyleContext; 8 | import java.awt.*; 9 | import java.awt.event.ActionEvent; 10 | import java.awt.event.ActionListener; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by bouquet on 13/10/16. 15 | */ 16 | public class ProgressDialog extends JDialog implements ActionListener{ 17 | 18 | private JTextPane log = new JTextPane(); 19 | 20 | public ProgressDialog(JFrame parent, String title) { 21 | super(parent, title, true); 22 | // if (parent != null) { 23 | // Dimension parentSize = parent.getSize(); 24 | // Point p = parent.getLocation(); 25 | // setLocation(p.x + parentSize.width / 4, p.y + parentSize.height / 4); 26 | // } 27 | 28 | getContentPane().setLayout(new BorderLayout()); 29 | log.setPreferredSize(new Dimension(600, 200)); 30 | getContentPane().add(new JScrollPane(log), BorderLayout.CENTER); 31 | setModal(false); 32 | 33 | JPanel buttonPane = new JPanel(); 34 | JButton button = new JButton("OK"); 35 | buttonPane.add(button); 36 | button.addActionListener(this); 37 | getContentPane().add(buttonPane, BorderLayout.SOUTH); 38 | setDefaultCloseOperation(HIDE_ON_CLOSE); 39 | pack(); 40 | setLocationRelativeTo(parent); 41 | 42 | } 43 | 44 | public void progress(String text, List errors){ 45 | for (String error : errors) { 46 | appendToPane(log, error, Color.RED); 47 | } 48 | appendToPane(log, text, Color.WHITE); 49 | } 50 | 51 | public void actionPerformed(ActionEvent e) { 52 | setVisible(false); 53 | dispose(); 54 | } 55 | 56 | public void clear(){ 57 | log.setText(""); 58 | } 59 | 60 | public void display(){ 61 | clear(); 62 | setVisible(true); 63 | } 64 | 65 | private void appendToPane(JTextPane tp, String msg, Color c){ 66 | StyleContext sc = StyleContext.getDefaultStyleContext(); 67 | AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c); 68 | 69 | aset = sc.addAttribute(aset, StyleConstants.FontFamily, "Lucida Console"); 70 | aset = sc.addAttribute(aset, StyleConstants.Alignment, StyleConstants.ALIGN_JUSTIFIED); 71 | 72 | int len = tp.getDocument().getLength(); 73 | tp.setCaretPosition(len); 74 | tp.setCharacterAttributes(aset, false); 75 | tp.replaceSelection(msg + "\n"); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/jme3/bootmonkey/ui/SpringLayoutHelper.java: -------------------------------------------------------------------------------- 1 | package com.jme3.bootmonkey.ui; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | 6 | /** 7 | * Created by Nehon on 16/10/2016. 8 | */ 9 | public class SpringLayoutHelper { 10 | 11 | /** 12 | * Aligns the first rows * cols 13 | * components of parent in 14 | * a grid. Each component in a column is as wide as the maximum 15 | * preferred width of the components in that column; 16 | * height is similarly determined for each row. 17 | * The parent is made just big enough to fit them all. 18 | * 19 | * @param rows number of rows 20 | * @param cols number of columns 21 | * @param initialX x location to start the grid at 22 | * @param initialY y location to start the grid at 23 | * @param xPad x padding between cells 24 | * @param yPad y padding between cells 25 | */ 26 | public static void makeCompactGrid(Container parent, 27 | int rows, int cols, 28 | int initialX, int initialY, 29 | int xPad, int yPad) { 30 | SpringLayout layout; 31 | try { 32 | layout = (SpringLayout)parent.getLayout(); 33 | } catch (ClassCastException exc) { 34 | System.err.println("The first argument to makeCompactGrid must use SpringLayout."); 35 | return; 36 | } 37 | 38 | //Align all cells in each column and make them the same width. 39 | Spring x = Spring.constant(initialX); 40 | for (int c = 0; c < cols; c++) { 41 | Spring width = Spring.constant(0); 42 | for (int r = 0; r < rows; r++) { 43 | width = Spring.max(width, 44 | getConstraintsForCell(r, c, parent, cols). 45 | getWidth()); 46 | } 47 | for (int r = 0; r < rows; r++) { 48 | SpringLayout.Constraints constraints = 49 | getConstraintsForCell(r, c, parent, cols); 50 | constraints.setX(x); 51 | constraints.setWidth(width); 52 | } 53 | x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad))); 54 | } 55 | 56 | //Align all cells in each row and make them the same height. 57 | Spring y = Spring.constant(initialY); 58 | for (int r = 0; r < rows; r++) { 59 | Spring height = Spring.constant(0); 60 | for (int c = 0; c < cols; c++) { 61 | height = Spring.max(height, 62 | getConstraintsForCell(r, c, parent, cols). 63 | getHeight()); 64 | } 65 | for (int c = 0; c < cols; c++) { 66 | SpringLayout.Constraints constraints = 67 | getConstraintsForCell(r, c, parent, cols); 68 | constraints.setY(y); 69 | constraints.setHeight(height); 70 | } 71 | y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad))); 72 | } 73 | 74 | //Set the parent's size. 75 | SpringLayout.Constraints pCons = layout.getConstraints(parent); 76 | pCons.setConstraint(SpringLayout.SOUTH, y); 77 | pCons.setConstraint(SpringLayout.EAST, x); 78 | } 79 | 80 | /* Used by makeCompactGrid. */ 81 | private static SpringLayout.Constraints getConstraintsForCell( 82 | int row, int col, 83 | Container parent, 84 | int cols) { 85 | SpringLayout layout = (SpringLayout) parent.getLayout(); 86 | Component c = parent.getComponent(row * cols + col); 87 | return layout.getConstraints(c); 88 | } 89 | 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/resources/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nehon/bootmonkey/60df37e75d0987e01109b6b0bc9de8cad5818b6c/src/main/resources/icons/icon.icns -------------------------------------------------------------------------------- /src/main/resources/icons/iconx128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nehon/bootmonkey/60df37e75d0987e01109b6b0bc9de8cad5818b6c/src/main/resources/icons/iconx128.png -------------------------------------------------------------------------------- /src/main/resources/icons/iconx16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nehon/bootmonkey/60df37e75d0987e01109b6b0bc9de8cad5818b6c/src/main/resources/icons/iconx16.png -------------------------------------------------------------------------------- /src/main/resources/icons/iconx32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nehon/bootmonkey/60df37e75d0987e01109b6b0bc9de8cad5818b6c/src/main/resources/icons/iconx32.png -------------------------------------------------------------------------------- /src/main/resources/icons/iconx64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nehon/bootmonkey/60df37e75d0987e01109b6b0bc9de8cad5818b6c/src/main/resources/icons/iconx64.png --------------------------------------------------------------------------------