-<?xml version="1.0" encoding="UTF-8"?>\r
-<classpath>\r
- <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>\r
- <classpathentry kind="src" output="target/classes" path="src/main/java">\r
- <attributes>\r
- <attribute name="optional" value="true"/>\r
- <attribute name="maven.pomderived" value="true"/>\r
- </attributes>\r
- </classpathentry>\r
- <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">\r
- <attributes>\r
- <attribute name="maven.pomderived" value="true"/>\r
- </attributes>\r
- </classpathentry>\r
- <classpathentry kind="src" output="target/test-classes" path="src/test/java">\r
- <attributes>\r
- <attribute name="optional" value="true"/>\r
- <attribute name="maven.pomderived" value="true"/>\r
- </attributes>\r
- </classpathentry>\r
- <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">\r
- <attributes>\r
- <attribute name="maven.pomderived" value="true"/>\r
- </attributes>\r
- </classpathentry>\r
- <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">\r
- <attributes>\r
- <attribute name="maven.pomderived" value="true"/>\r
- </attributes>\r
- </classpathentry>\r
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">\r
- <attributes>\r
- <attribute name="maven.pomderived" value="true"/>\r
- </attributes>\r
- </classpathentry>\r
- <classpathentry kind="output" path="target/classes"/>\r
-</classpath>\r
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
+ <classpathentry kind="src" output="target/classes" path="src/main/java">
+ <attributes>
+ <attribute name="optional" value="true"/>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+ <attributes>
+ <attribute name="optional" value="true"/>
+ <attribute name="maven.pomderived" value="true"/>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
--- /dev/null
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL =
+ "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+ * use instead of the default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+ ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH =
+ ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main(String args[]) {
+ System.out.println("- Downloader started");
+ File baseDirectory = new File(args[0]);
+ System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+ String url = DEFAULT_DOWNLOAD_URL;
+ if(mavenWrapperPropertyFile.exists()) {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try {
+ mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+ url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+ } catch (IOException e) {
+ System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+ } finally {
+ try {
+ if(mavenWrapperPropertyFileInputStream != null) {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println("- Downloading from: : " + url);
+
+ File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+ if(!outputFile.getParentFile().exists()) {
+ if(!outputFile.getParentFile().mkdirs()) {
+ System.out.println(
+ "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+ }
+ }
+ System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+ try {
+ downloadFileFromURL(url, outputFile);
+ System.out.println("Done");
+ System.exit(0);
+ } catch (Throwable e) {
+ System.out.println("- Error downloading");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+ URL website = new URL(urlString);
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel(website.openStream());
+ FileOutputStream fos = new FileOutputStream(destination);
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ fos.close();
+ rbc.close();
+ }
+
+}
--- /dev/null
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
-eclipse.preferences.version=1\r
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate\r
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve\r
-org.eclipse.jdt.core.compiler.compliance=1.6\r
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate\r
-org.eclipse.jdt.core.compiler.debug.localVariable=generate\r
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate\r
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning\r
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
-org.eclipse.jdt.core.compiler.problem.autoboxing=ignore\r
-org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning\r
-org.eclipse.jdt.core.compiler.problem.deadCode=warning\r
-org.eclipse.jdt.core.compiler.problem.deprecation=warning\r
-org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled\r
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled\r
-org.eclipse.jdt.core.compiler.problem.discouragedReference=warning\r
-org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore\r
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
-org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore\r
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled\r
-org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore\r
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning\r
-org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning\r
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=ignore\r
-org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning\r
-org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning\r
-org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore\r
-org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore\r
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore\r
-org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning\r
-org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore\r
-org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore\r
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore\r
-org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning\r
-org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore\r
-org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning\r
-org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning\r
-org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore\r
-org.eclipse.jdt.core.compiler.problem.nullReference=warning\r
-org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning\r
-org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore\r
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore\r
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore\r
-org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning\r
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore\r
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore\r
-org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled\r
-org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning\r
-org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled\r
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore\r
-org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning\r
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning\r
-org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore\r
-org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning\r
-org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore\r
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore\r
-org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore\r
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore\r
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled\r
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled\r
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled\r
-org.eclipse.jdt.core.compiler.problem.unusedImport=warning\r
-org.eclipse.jdt.core.compiler.problem.unusedLabel=warning\r
-org.eclipse.jdt.core.compiler.problem.unusedLocal=warning\r
-org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore\r
-org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled\r
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled\r
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled\r
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning\r
-org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning\r
-org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning\r
-org.eclipse.jdt.core.compiler.source=1.6\r
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=ignore
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.6
--- /dev/null
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+ # TODO classpath?
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ wget "$jarUrl" -O "$wrapperJarPath"
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ curl -o "$wrapperJarPath" "$jarUrl"
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
--- /dev/null
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
+FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ echo Found %WRAPPER_JAR%
+) else (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
+ echo Finished downloading %WRAPPER_JAR%
+)
+@REM End of extension
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
if [[ -z "$JAVA_HOME" ]]; then
if [[ -x "/usr/libexec/java_home" ]]; then
JAVA_HOME="$(/usr/libexec/java_home)"
+ if [[ $? -ne 0 ]]; then
+ # java_homeがエラーを返すならばJavaが無いものと見なす
+ JAVA_HOME=""
+ fi
fi
fi
fi
# JAVAをオプションとJARを指定して起動する
if [[ -f $RESOURCE_DIR/$JARNAME ]]; then
- "$JAVA_CMD" ${jvm_options[@]} -jar "$RESOURCE_DIR/$JARNAME" || ShowMessage "Failed to launch ${APPNAME}"
+ # アプリケーション名とロケールの取得
+ APPTITLE=( $("$JAVA_CMD" -jar "$RESOURCE_DIR/$JARNAME" --show-appinfo) )
+ if [[ $? -ne 0 ]]; then
+ # JAVAの起動に失敗した場合
+ ShowMessage "Could not launch Java SE Runtime Environment. ${APPNAME}"
+ exit 1
+ fi
+
+ # アプリケーションの起動
+ "$JAVA_CMD" ${jvm_options[@]} "-Xdock:name=${APPTITLE[0]}" -jar "$RESOURCE_DIR/$JARNAME" || ShowMessage "Failed to launch ${APPNAME}"
else
ShowMessage "$JARNAME is not found."
fi
package charactermanaj;
+import java.util.Locale;
+import java.util.Properties;
+
+import charactermanaj.model.AppConfig;
+import charactermanaj.util.LocalizedResourcePropertyLoader;
+
/**
* Java7 on OSX で、クラス名がメニューの「〜の終了」「〜について」の起動クラス名がアプリ名に使われており、
* info.pinfoのBundleNameでも変更できないため、回避方法がみつかるまで、本クラス名を表示させることにする。
- *
+ *
* @author seraphy
*/
public class CharacterManaJ {
public static void main(String[] args) throws Exception {
+ // アプリケーション名表示オプションか?
+ for (String arg : args) {
+ if ("--show-appinfo".equals(arg)) {
+ showAppinfo();
+ return;
+ }
+ }
+
Main.main(args);
}
+
+ /**
+ * アプリケーション名の表示
+ */
+ public static void showAppinfo() {
+ Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
+ .getLocalizedProperties("languages/mainframe");
+ AppConfig appConfig = AppConfig.getInstance();
+
+ System.out.println(strings.getProperty("title"));
+ System.out.println(Locale.getDefault().getLanguage());
+ System.out.println(appConfig.getSpecificationVersion());
+ System.out.println(appConfig.getImplementationVersion());
+ }
}
}
// スタートアップ時の初期化
- // ver0.999ではキャラクターデータディレクトリに依存しない初期化部しかないので最初に移動する。
+ // ver0.999ではキャラクターデータディレクトリに依存しない初期化部しかないので最初に実行する。
// (APPDATAからLOCALAPPDATAへの移動処理などがあるため、先に行う必要がある。)
StartupSupport.getInstance().doStartup();
if (currentCharacterDir == null) {
// キャラクターセットディレクトリの選択
- File defaultCharacterDir = ConfigurationDirUtilities
- .getDefaultCharactersDir();
- currentCharacterDir = SelectCharatersDirDialog
- .getCharacterDir(defaultCharacterDir);
+ File defaultCharacterDir = ConfigurationDirUtilities.getDefaultCharactersDir();
+ currentCharacterDir = SelectCharatersDirDialog.getCharacterDir(defaultCharacterDir);
if (currentCharacterDir == null) {
// キャンセルされたので終了する.
- logger.info("luncher canceled.");
+ logger.info("launcher canceled.");
return;
}
}
// OSXにしか存在しないクラスを利用するためリフレクションとしている.
// ただしJDKによっては、Apple Java Extensionsがないことも予想されるので、
// その場合はエラーにしない。
- Class<?> clz = Class
- .forName("charactermanaj.ui.MainFramePartialForMacOSX");
- Method mtd = clz.getMethod("setupScreenMenu",
- MainFrame.class);
+ Class<?> clz = Class.forName("charactermanaj.ui.MainFramePartialForMacOSX");
+ Method mtd = clz.getMethod("setupScreenMenu", MainFrame.class);
mtd.invoke(null, mainFrame);
}
* クラスローダからリソースを読み込むイメージリソース.<br>
* @author seraphy
*/
-public class EmbeddedImageResource extends ResourceLoader implements ImageResource {
+public class EmbeddedImageResource implements ImageResource {
/**
* ロガー
private static final Logger logger = Logger.getLogger(EmbeddedImageResource.class.getName());
/**
+ * クラスパス上からのリソースローダー
+ */
+ private final ResourceLoader resourceLoader = new ResourceLoader(ResourceLoader.getDefaultClassLoader());
+
+ /**
* ファイル
*/
private String resourceName;
this.resourceName = resourceName;
}
+ @Override
public int compareTo(ImageResource o) {
return getFullName().compareTo(o.getFullName());
}
return false;
}
+ @Override
public String getFullName() {
return resourceName;
}
+ @Override
public URI getURI() {
URL url = getResource(resourceName);
if (url != null) {
* リソースが実在すれば日付は常に1を返す.<br>
* リソースが存在しなければ0を返す.<br>
*/
+ @Override
public long lastModified() {
URL url = getResource(resourceName);
if (url == null) {
return 0;
}
+ @Override
public InputStream openStream() throws IOException {
URL url = getResource(resourceName);
if (url == null) {
public String toString() {
return getFullName();
}
+
+ private URL getResource(String resourceName) {
+ return resourceLoader.getResource(resourceName);
+ }
}
propChangeSupport.firePropertyChange(ENABLE_COLOR_ADVANCED_SETTINGS, old, enableRestoreWindow);
}
}
+
+ private boolean useRecycleBinIfSupported = true;
+
+ public boolean isUseRecycleBinIfSupported() {
+ return useRecycleBinIfSupported;
+ }
+
+ public static final String USE_RECYCLE_BIN_IF_SUPPORTED = "useRecycleBinIfSupported";
+
+ public void setUseRecycleBinIfSupported(boolean useRecycleBinIfSupported) {
+ boolean old = this.useRecycleBinIfSupported;
+ if (old != useRecycleBinIfSupported) {
+ this.useRecycleBinIfSupported = useRecycleBinIfSupported;
+ propChangeSupport.firePropertyChange(USE_RECYCLE_BIN_IF_SUPPORTED, old, useRecycleBinIfSupported);
+ }
+ }
}
cd.setImageSize((Dimension)(this.imageSize == null ? null : this.imageSize.clone()));
cd.setWatchDirectory(this.isWatchDirectory());
+ cd.setEnableCustomLayerPattern(this.isEnableCustonLayerPattern());
ArrayList<RecommendationURL> recommendationURLList = null;
if (this.recommendationURLList != null) {
return docBase;
}
+ private static final String PROPNAME_WATCH_DIR = "watch-dir";
+
/**
* ディレクトリを監視するか? (デフォルトは監視する)
* @return ディレクトリを監視する場合はtrue
*/
public boolean isWatchDirectory() {
try {
- String value = properties.getProperty("watch-dir");
+ String value = properties.getProperty(PROPNAME_WATCH_DIR);
if (value != null) {
return Boolean.parseBoolean(value);
}
} catch (RuntimeException ex) {
- logger.log(Level.WARNING, "watch-dir property is invalid.", ex);
+ logger.log(Level.WARNING, PROPNAME_WATCH_DIR + " property is invalid.", ex);
}
// デフォルトは監視する.
return true;
* @param watchDir 監視する場合はtrue、しない場合はfalse
*/
public void setWatchDirectory(boolean watchDir) {
- properties.setProperty("watch-dir", Boolean.toString(watchDir));
+ properties.setProperty(PROPNAME_WATCH_DIR, Boolean.toString(watchDir));
+ }
+
+ private static final String PROPNAME_ENABLE_CUSTOM_LAYER_PATTERN = "custom-layer-pattern";
+
+ /**
+ * カスタムレイヤーパターンが有効であるか?(デフォルトは有効)
+ * @return カスタムレイヤーパターンが有効である場合はtrue
+ */
+ public boolean isEnableCustonLayerPattern() {
+ try {
+ String value = properties.getProperty(PROPNAME_ENABLE_CUSTOM_LAYER_PATTERN);
+ if (value != null) {
+ return Boolean.parseBoolean(value);
+ }
+ } catch (RuntimeException ex) {
+ logger.log(Level.WARNING, PROPNAME_ENABLE_CUSTOM_LAYER_PATTERN + " property is invalid.", ex);
+ }
+ // デフォルトは有効.
+ return true;
+ }
+
+ /**
+ * カスタムレイヤーパターンの有効・無効を設定する。
+ * @param enableCustomLayerPattern 有効にする場合はtrue、無効にする場合はfalse
+ */
+ public void setEnableCustomLayerPattern(boolean enableCustomLayerPattern) {
+ properties.setProperty(PROPNAME_ENABLE_CUSTOM_LAYER_PATTERN, Boolean.toString(enableCustomLayerPattern));
}
public String getProperty(String key) {
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import charactermanaj.graphics.io.PNGFileImageHeader;
import charactermanaj.graphics.io.PNGFileImageHeaderReader;
import charactermanaj.model.CharacterData;
+import charactermanaj.model.CustomLayerOrder;
+import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.Layer;
import charactermanaj.model.PartsCategory;
import charactermanaj.model.PartsManageData;
import charactermanaj.model.io.CharacterDataDefaultProvider.DefaultCharacterDataVersion;
-public abstract class AbstractCharacterDataArchiveFile
- implements
- CharacterDataArchiveFile {
+public abstract class AbstractCharacterDataArchiveFile implements CharacterDataArchiveFile {
private static final Logger logger = Logger
.getLogger(AbstractCharacterDataArchiveFile.class.getName());
long lastModified();
- InputStream openStream() throws IOException;
+ long length();
+ InputStream openStream() throws IOException;
}
@Override
/**
* パーツイメージを示す.<br>
- *
+ *
* @param fileContent
* ファイルコンテンツ
* @param categoryLayerPairs
return dirName;
}
+ @Override
public String getEntryName() {
return fileContent.getEntryName();
}
return pngFileImageHeader;
}
+ @Override
public long lastModified() {
return fileContent.lastModified();
}
+ @Override
+ public long length() {
+ return fileContent.length();
+ }
+
+ @Override
public InputStream openStream() throws IOException {
return fileContent.openStream();
}
/**
* アーカイブファイルをベースとしたURIを返す.<br>
- *
+ *
* @param name
* コンテンツ名
* @return URI
/**
* 指定したコンテンツが存在するか?
- *
+ *
* @param name
* コンテンツ名
* @return 存在すればtrue、存在しなければfalse
*/
+ @Override
public boolean hasContent(String name) {
return entries.containsKey(name);
}
/**
* 指定したコンテンツを取得する.<br>
* 存在しない場合はnullを返す.<br>
- *
+ *
* @param name
* コンテンツ名
* @return 存在すればコンテンツ、存在しなければnull
return entries.get(name);
}
+ @Override
public String getRootPrefix() {
return this.rootPrefix;
}
* 指定したディレクトリ(フルパス指定)のファイルのみを取り出す.<br>
* サブフォルダは含まない.<br>
* ディレクトリに空文字またはnullまたは「/」を指定した場合はルートを意味する.<br>
- *
+ *
* @param dir
* ディレクトリ
* @return ファイルへのフルパスのコレクション
/**
* キャラクター定義を読み込む.<br>
* アーカイブに存在しないか、妥当性がない場合はnullを返す.<br>
- *
+ *
* @return キャラクター定義、もしくはnull
*/
+ @Override
public CharacterData readCharacterData() {
FileContent characterFile = entries.get(rootPrefix
+ CharacterDataPersistent.CONFIG_FILE);
* 「キャラクターなんとか機 v2.2」の設定ファイルを想定している.<br>
* ただし、character.iniの下にeye_colorフォルダがある場合は「ver3」とみなす。<br>
* (設定ファイルの形式はv2, v3の間で変わらず)
- *
+ *
* @return キャラクター定義、もしくはnull
*/
+ @Override
public CharacterData readCharacterINI() {
FileContent characterFile = null;
characterFile = entries.get(rootPrefix
}
}
+ @Override
+ public Map<CustomLayerOrderKey, List<CustomLayerOrder>> readCustomLayerPatterns(CharacterData cd)
+ throws IOException {
+ FileContent mapFile = entries.get(rootPrefix
+ + CustomLayerOrderXMLPersist.CUSTOM_LAYER_ORDERS_XML_FILE);
+ if (mapFile == null) {
+ // ファイルがない
+ return null;
+ }
+
+ if (mapFile.length() == 0) {
+ // 空ファイルは空マップを返す
+ return Collections.emptyMap();
+ }
+
+ CustomLayerOrderXMLReader xmlReader = new CustomLayerOrderXMLReader(cd);
+ try {
+ // character.xmlを読み込む
+ return xmlReader.read(mapFile.openStream());
+
+ } catch (Exception ex) {
+ logger.log(Level.INFO, CustomLayerOrderXMLPersist.CUSTOM_LAYER_ORDERS_XML_FILE + " load failed.", ex);
+ return null;
+ }
+ }
+
/**
* お気に入りを読み込みキャラクター定義に追加する.<br>
* アーカイブにお気に入り(favorites.xml)が存在しなければ何もしない.<br>
* 読み取り中に失敗した場合は、その時点で読み込みを止めて戻る.<br>
- *
+ *
* @param characterData
* キャラクター定義(お気に入りが追加される)
*/
+ @Override
public void readFavorites(CharacterData characterData) {
if (characterData == null) {
throw new IllegalArgumentException("characterDataにnullは指定できません。");
/**
* サンプルピクチャを読み込む.<br>
* アーカイブに存在しないか、画像として読み取れなかった場合はnull
- *
+ *
* @return サンプルピクチャ、もしくはnull
*/
+ @Override
public BufferedImage readSamplePicture() {
FileContent samplePictureFile = entries.get(rootPrefix + "preview.png");
if (samplePictureFile == null) {
* readme.txtが優先される。ともに存在しない場合はnull.<br>
* 改行コードはプラットフォーム固有の改行コードに変換して返される.<br>
* 読み取れなかった場合はnull.<br>
- *
+ *
* @return テキスト、もしくはnull
*/
+ @Override
public String readReadMe() {
Locale locale = Locale.getDefault();
* BOMがない場合はUTF-16/8ともに判定できない.<br>
* BOMがなければMS932もしくはEUC_JPであると仮定して読み込む.<br>
* 改行コードはプラットフォーム固有の改行コードに変換して返される.<br>
- *
+ *
* @param name
* コンテンツ名
* @return テキスト、コンテンツが存在しない場合はnull
* @throws IOException
* 読み込みに失敗した場合
*/
+ @Override
public String readTextFile(String name) throws IOException {
if (name == null) {
throw new IllegalArgumentException();
* UTF-16LE/BE/UTF-8についてはBOMにより判定する.<br>
* BOMがない場合はUTF-16/8ともに判定できない.<br>
* BOMがなければMS932もしくはEUC_JPであると仮定して読み込む.<br>
- *
+ *
* @param content
* コンテンツ
* @return テキスト
* enabledRootPefixがtrueの場合、ディレクトリの先頭はアーカイブのコンテンツルートとなる.<br>
* 同一のディレクトリに対して複数のレイヤー(複数カテゴリを含む)が参照している場合、それらを含めて返す.<br>
* 参照されているディレクトリがない場合は返される結果には含まれない.<br>
- *
+ *
* @param characterData
* キャラクター定義
* @param enabledRootPrefix
* ルートプレフィックス(アーカイブのコンテンツルート)を付与する場合
- * @return
+ * @return
* パーツで使用する画像のディレクトリとして認識されるディレクトリの一覧、キーはアーカイブのディレクトリ位置、値は参照する1つ以上のレイヤー
*/
protected Map<String, Collection<CategoryLayerPair>> getLayerDirs(
/**
* アーカイブに含まれるフォルダをもつpngファイルからパーツイメージを取得する.<br>
- *
+ *
* @param インポート先のキャラクターデータ
* 、フォルダ名などを判別するため。nullの場合はディレクトリなしとみなす.<br>
* @param newly
* (アーカイブファイルからの読み込みでは無視される)
* @return パーツイメージコンテンツのコレクション、なければ空
*/
+ @Override
public Collection<PartsImageContent> getPartsImageContents(
CharacterData characterData, boolean newly) {
// コンテンツルートからの絶対位置指定でパーツイメージを取得する.
/**
* コンテンツルートからの絶対位置のフォルダからpngファイルからパーツイメージを取得する.<br>
- *
+ *
* @param インポート先のキャラクターデータ
* 、フォルダ名などを判別するため。nullの場合はディレクトリなしとみなす.<br>
* @return パーツイメージコンテンツのコレクション、なければ空
characterData, true);
CategoryLayerPairResolveStrategy strategy = new CategoryLayerPairResolveStrategy() {
+ @Override
public Collection<CategoryLayerPair> resolveCategoryLayerPairs(
String dir) {
Collection<CategoryLayerPair> categoryLayerPairs = layerDirMap
/**
* アーカイブに含まれる任意のフォルダからpngファイルからパーツイメージを取得する.<br>
* ディレクトリ名の大文字・小文字は区別されません.<br>
- *
+ *
* @param インポート先のキャラクターデータ
* 、フォルダ名などを判別するため。nullの場合はディレクトリなしとみなす.<br>
* @return パーツイメージコンテンツのコレクション、なければ空
characterData, false);
CategoryLayerPairResolveStrategy strategy = new CategoryLayerPairResolveStrategy() {
+ @Override
public Collection<CategoryLayerPair> resolveCategoryLayerPairs(
String dir) {
dir = (dir == null) ? "" : dir.toLowerCase();
/**
* ディレクトリ名からカテゴリとレイヤーを取得するためのインターフェイス.<br>
- *
+ *
* @author seraphy
*/
protected interface CategoryLayerPairResolveStrategy {
* 同一のディレクトリに対して複数のレイヤーが割り当てられている可能性があるためコレクションで返されます.<br>
* 空のコレクションにはなりません.<br>
* レイヤーとして認識されていないディレクトリの場合はnullを返します.<br>
- *
+ *
* @param dir
* ディレクトリ
* @return カテゴリ・レイヤーのペアのコレクション、またはnull (空のコレクションにはならない。)
/**
* アーカイブに含まれるフォルダをもつpngファイルからパーツイメージを取得する。
- *
+ *
* @param strategy
* ディレクトリが売れ入れ可能であるか判断するストラテジー
* @return パーツイメージコンテンツのコレクション、なければ空
/**
* PNGファイルとしてファイルを読み込みPNGヘッダ情報を返します.<br>
* PNGでないか、ファイルの読み込みに失敗した場合はnullを返します.<br>
- *
+ *
* @param fileContent
* 画像ファイル
* @return PNGヘッダ情報、またはnull
/**
* アーカイブに含まれるparts-info.xmlを読み込み返す.<br>
* 存在しなければ空のインスタンスを返す.<br>
- *
+ *
* @return パーツ管理データ
* @throws IOException
*/
+ @Override
public PartsManageData getPartsManageData() throws IOException {
FileContent content = entries.get(rootPrefix + "parts-info.xml");
if (content == null) {
import charactermanaj.graphics.io.ImageSaveHelper;
import charactermanaj.model.AppConfig;
import charactermanaj.model.CharacterData;
+import charactermanaj.model.CustomLayerOrder;
+import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.Layer;
import charactermanaj.model.PartsCategory;
import charactermanaj.model.PartsFiles;
import charactermanaj.model.PartsSet;
import charactermanaj.model.PartsSpec;
+/**
+ * キャラクターデータをアーカイブ(zip, jar形式)で保存するための共通クラス.
+ */
public abstract class AbstractCharacterDataArchivedFileWriter extends AbstractCharacterDataFileWriter {
protected AbstractCharacterDataArchivedFileWriter(File outFile) throws IOException {
super(outFile);
}
-
+
+ /**
+ * 現在のエントリの出力ストリームを取得する
+ * @return
+ * @throws IOException
+ */
protected abstract OutputStream getOutputStream() throws IOException;
-
+
+ /**
+ * 次のエントリに進む
+ * @param name エントリ名
+ * @param lastModified 最終更新日時(0以下の場合はデフォルトとする)
+ * @throws IOException
+ */
protected abstract void putNextEntry(String name, long lastModified) throws IOException;
-
+
+ /**
+ * 現在のエントリを閉じる
+ * @throws IOException
+ */
protected abstract void closeEntry() throws IOException;
@Override
protected void internalWriteCharacterData(CharacterData characterData)
throws IOException {
CharacterDataXMLWriter xmlWriter = new CharacterDataXMLWriter();
-
+
// character.xmlの出力
putNextEntry(CharacterDataPersistent.CONFIG_FILE, 0);
xmlWriter.writeXMLCharacterData(characterData, getOutputStream());
closeEntry();
-
+
// character.iniの出力
internalWriteCharacterIni(characterData);
}
/**
* character.iniを出力します.<br>
- *
+ *
* @param characterData
* キャラクターデータ
* @throws IOException
buf.append("; created by charactermanaj "
+ new Timestamp(System.currentTimeMillis()) + "\r\n");
-
+
buf.append("[Size]\r\n");
Dimension dim = characterData.getImageSize();
if (dim == null) {
buf.append("\r\n");
buf.append("[Parts]\r\n");
-
+
Map<String, String> partsMap = new HashMap<String, String>();
for (PartsCategory partsCategory : characterData.getPartsCategories()) {
String categoryId = partsCategory.getCategoryId();
partsMap.put(categoryId, "");
}
-
+
Map<String, PartsSet> partsSets = characterData.getPartsSets();
PartsSet partsSet = partsSets.get(characterData.getDefaultPartsSetId());
if (partsSet == null && !partsSets.isEmpty()) {
// UTF16LEで出力する.
internalWriteTextUTF16LE(CharacterDataPersistent.COMPATIBLE_CONFIG_NAME, buf.toString());
}
-
+
+ @Override
+ protected void internalWriteCustomLayerPatterns(Map<CustomLayerOrderKey, List<CustomLayerOrder>> map)
+ throws IOException {
+ if (map == null) {
+ return;
+ }
+
+ // カスタムレイヤーパターンを出力する
+ CustomLayerOrderXMLWriter xmlWriter = new CustomLayerOrderXMLWriter();
+ putNextEntry(CustomLayerOrderPersist.CUSTOM_LAYER_ORDERS_XML_FILE, 0);
+ xmlWriter.write(map, getOutputStream());
+ closeEntry();
+ }
+
@Override
protected void internalWriteTextUTF16LE(String name, String contents) throws IOException {
if (contents == null) {
contents = contents.replace("\r\n", "\n");
contents = contents.replace("\r", "\n");
contents = contents.replace("\n", "\r\n");
-
+
putNextEntry(name, 0);
OutputStream os = getOutputStream();
os.write((byte) 0xff);
wr.close();
}
}
-
+
@Override
protected void internalWriteSamplePicture(BufferedImage samplePicture)
throws IOException {
imageSaveHelper.savePicture(samplePicture, Color.white, getOutputStream(), "image/png", null);
closeEntry();
}
-
+
@Override
protected void internalWritePartsImages(
Map<PartsIdentifier, PartsSpec> partsImages) throws IOException {
AppConfig appConfig = AppConfig.getInstance();
byte[] buf = new byte[appConfig.getJarTransferBufferSize()];
-
+
for (Map.Entry<PartsIdentifier, PartsSpec> entry : partsImages.entrySet()) {
PartsIdentifier partsIdentifier = entry.getKey();
PartsSpec partsSpec = entry.getValue();
PartsFiles partsFiles = partsSpec.getPartsFiles();
-
+
for (Map.Entry<Layer, ImageResource> imageEntry : partsFiles.entrySet()) {
Layer layer = imageEntry.getKey();
ImageResource imageResource = imageEntry.getValue();
String name = layer.getDir() + "/" + partsIdentifier.getPartsName() + ".png";
name = name.replace("//", "/");
-
+
putNextEntry(name, imageResource.lastModified());
OutputStream os = getOutputStream();
InputStream is = imageResource.openStream();
}
}
}
-
+
@Override
protected void internalWritePartsManageData(
Map<PartsIdentifier, PartsSpec> partsImages) throws IOException {
-
+
PartsManageDataConverter partsManageDataConverter = new PartsManageDataConverter();
-
+
for (Map.Entry<PartsIdentifier, PartsSpec> entry : partsImages.entrySet()) {
PartsIdentifier partsIdentifier = entry.getKey();
PartsSpec partsSpec = entry.getValue();
partsManageDataConverter.convert(partsIdentifier, partsSpec);
}
-
+
PartsManageData partsManageData = partsManageDataConverter.getPartsManageData();
PartsInfoXMLWriter xmlWriter = new PartsInfoXMLWriter();
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import charactermanaj.model.CharacterData;
+import charactermanaj.model.CustomLayerOrder;
+import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.PartsIdentifier;
import charactermanaj.model.PartsSpec;
+import charactermanaj.util.FileUtilities;
public abstract class AbstractCharacterDataFileWriter implements CharacterDataWriter {
private static final Logger logger = Logger.getLogger(AbstractCharacterDataFileWriter.class.getName());
protected File outFile;
-
+
protected File tmpFile;
-
+
protected Exception occureException;
-
+
protected AbstractCharacterDataFileWriter(File outFile) throws IOException {
if (outFile == null) {
throw new IllegalArgumentException();
}
-
+
if (outFile.exists()) {
if (!outFile.canWrite()) {
throw new IOException("not writable: " + outFile);
}
}
File tmpFile = new File(outFile.getPath() + ".tmp");
-
+
this.tmpFile = tmpFile;
this.outFile = outFile;
}
-
+
+ @Override
public void writeExportProp(Properties prop) throws IOException {
if (prop == null) {
throw new IllegalArgumentException();
}
-
+
try {
internalWriteExportProp(prop);
-
+
} catch (IOException ex) {
occureException = ex;
throw ex;
throw ex2;
}
}
-
+
protected abstract void internalWriteExportProp(Properties prop) throws IOException;
-
+
+ @Override
public void writeCharacterData(CharacterData characterData) throws IOException {
if (characterData == null) {
throw new IllegalArgumentException();
}
-
+
try {
internalWriteCharacterData(characterData);
-
+
} catch (IOException ex) {
occureException = ex;
throw ex;
throw ex2;
}
}
-
+
protected abstract void internalWriteCharacterData(CharacterData characterData) throws IOException;
-
+
+
+ @Override
+ public void writeCustomLayerPatterns(Map<CustomLayerOrderKey, List<CustomLayerOrder>> map) throws IOException {
+ try {
+ internalWriteCustomLayerPatterns(map);
+
+ } catch (IOException ex) {
+ occureException = ex;
+ throw ex;
+
+ } catch (Exception ex) {
+ occureException = ex;
+ IOException ex2 = new IOException("write characterdata failed.");
+ ex2.initCause(ex);
+ throw ex2;
+ }
+ }
+
+ protected abstract void internalWriteCustomLayerPatterns(Map<CustomLayerOrderKey, List<CustomLayerOrder>> map)
+ throws IOException;
+
+ @Override
public void writeTextUTF16LE(String name, String contents) throws IOException {
if (name == null) {
throw new IllegalArgumentException();
}
-
+
try {
internalWriteTextUTF16LE(name, contents);
-
+
} catch (IOException ex) {
occureException = ex;
throw ex;
throw ex2;
}
}
-
+
protected abstract void internalWriteTextUTF16LE(String name, String contents) throws IOException;
-
+
+ @Override
public void writeSamplePicture(BufferedImage samplePicture) throws IOException {
if (samplePicture == null) {
throw new IllegalArgumentException();
protected abstract void internalWriteSamplePicture(BufferedImage samplePicture) throws IOException;
+ @Override
public void writePartsImages(Map<PartsIdentifier, PartsSpec> partsImages) throws IOException {
if (partsImages == null) {
throw new IllegalArgumentException();
throw ex2;
}
}
-
+
protected abstract void internalWritePartsImages(Map<PartsIdentifier, PartsSpec> partsImages) throws IOException;
+ @Override
public void writePartsManageData(Map<PartsIdentifier, PartsSpec> partsImages) throws IOException {
if (partsImages == null) {
throw new IllegalArgumentException();
throw ex2;
}
}
-
+
protected abstract void internalWritePartsManageData(Map<PartsIdentifier, PartsSpec> partsImages) throws IOException;
-
+
+ @Override
public void close() throws IOException {
try {
internalClose();
-
+
if (outFile.exists()) {
- if (!outFile.delete()) {
- throw new IOException("old file can't delete. " + outFile);
- }
+ FileUtilities.delete(outFile);
}
} catch (Exception ex) {
}
return;
}
-
+
if (!tmpFile.renameTo(outFile)) {
throw new IOException("rename failed. " + tmpFile);
}
}
-
+
protected abstract void internalClose() throws IOException;
}
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Collection;
+import java.util.List;
+import java.util.Map;
import charactermanaj.model.CharacterData;
+import charactermanaj.model.CustomLayerOrder;
+import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.PartsManageData;
import charactermanaj.model.io.AbstractCharacterDataArchiveFile.PartsImageContent;
* @throws IOException
*/
void close() throws IOException;
-
+
/**
* コンテンツルートへのプレフィックスを取得する.<br>
* アーカイブの実際のルートに単一のフォルダしかない場合、そのフォルダがルートプレフィックスとなる.<br>
* @return コンテンツルートへのプレフィックス
*/
String getRootPrefix();
-
+
/**
* 指定したコンテンツが存在するか?
* @param name コンテンツ名
* @return 存在すればtrue、存在しなければfalse
*/
boolean hasContent(String name);
-
+
/**
* キャラクター定義を読み込む.<br>
* アーカイブに存在しなければnull
* @throws IOException 読み取りに失敗した場合
*/
CharacterData readCharacterData() throws IOException;
-
+
+ /**
+ * カスタムレイヤーパターン定義を読みこむ
+ * アーカイブに存在しないければnull
+ * @param cd キャラクターデータ(カテゴリ情報が必要なため)
+ * @return カスタムレイヤーパターン、もしくはnull
+ * @throws IOException 読み取りに失敗した場合
+ */
+ Map<CustomLayerOrderKey, List<CustomLayerOrder>> readCustomLayerPatterns(CharacterData cd) throws IOException;
+
/**
* お気に入りを読み込みキャラクター定義に追加する.<br>
* アーカイブにお気に入りが存在しなければ何もしない.<br>
* @throws IOException 読み取りに失敗した場合
*/
void readFavorites(CharacterData characterData) throws IOException;
-
+
/**
* キャラクター定義をINIファイルより読み取る.<br>
* character.iniが存在しなければnull.<br>
* @throws IOException 読み取りに失敗した場合
*/
CharacterData readCharacterINI() throws IOException;
-
+
/**
* サンプルピクチャを読み込む.<br>
* アーカイブに存在しなければnull.
* @throws IOException 読み取りに失敗した場合
*/
BufferedImage readSamplePicture() throws IOException;
-
+
/**
* アーカイブにある「readme.txt」、もしくは「readme」というファイルをテキストファイルとして読み込む.<br>
- * readme.txtが優先される。ともに存在しない場合はnull.
+ * readme.txtが優先される。ともに存在しない場合はnull.
* @return テキスト、もしくはnull
* @throws 読み込みに失敗した場合
*/
String readReadMe() throws IOException;
-
+
/**
* ファイルをテキストとして読み取り、返す.<br>
* UTF-16LE/BE/UTF-8についてはBOMにより判定する.<br>
* BOMがない場合はUTF-16/8ともに判定できない.<br>
* BOMがなければMS932もしくはEUC_JPであると仮定して読み込む.<br>
- * @param name コンテンツ名
+ * @param name コンテンツ名
* @return テキスト、コンテンツが存在しない場合はnull
* @throws IOException 読み込みに失敗した場合
*/
String readTextFile(String name) throws IOException;
-
+
/**
* アーカイブに含まれる、キャラクター定義と同じフォルダをもつpngファイルからパーツイメージを取得する.<br>
* パーツの探索は引数で指定したキャラクター定義によって行われます.<br>
* @return パーツイメージコンテンツのコレクション、なければ空
*/
Collection<PartsImageContent> getPartsImageContents(CharacterData characterData, boolean newly);
-
+
/**
* アーカイブに含まれるparts-info.xmlを読み込み返す.<br>
* 存在しなければ空のインスタンスを返す.<br>
package charactermanaj.model.io;
+import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.sql.Timestamp;
-import java.util.EnumSet;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import charactermanaj.model.CharacterData;
import charactermanaj.model.CustomLayerOrder;
import charactermanaj.model.CustomLayerOrderKey;
+import charactermanaj.model.PartsCategoryResolver;
import charactermanaj.util.ConfigurationDirUtilities;
import charactermanaj.util.LocalizedResourcePropertyLoader;
import charactermanaj.util.ResourceLoader;
-import charactermanaj.util.ResourceNames;
import charactermanaj.util.SetupLocalization;
/**
private static final String CUSTOM_LAYER_ORDERS_SUFFIX = "-customlayerorders.xml";
/**
+ * リソースローダー
+ * ローカルファイルをクラスパスより優先する。
+ */
+ private final ResourceLoader resourceLoader = new ResourceLoader(true);
+
+ /**
* ロガー
*/
private static final Logger logger = Logger
}
}
- public Map<CustomLayerOrderKey, List<CustomLayerOrder>> createCustomLayerOrderMap(CharacterData cd,
- CharacterDataDefaultProvider prov) {
+ public Map<CustomLayerOrderKey, List<CustomLayerOrder>> createCustomLayerOrderMap(
+ PartsCategoryResolver partsCategoryResolver, CharacterDataDefaultProvider prov) {
if (prov == null) {
throw new IllegalArgumentException();
}
try {
- return prov.loadPredefinedCustomLayerOrder(cd, reskey);
+ return prov.loadPredefinedCustomLayerOrder(partsCategoryResolver, reskey);
} catch (IOException ex) {
throw new RuntimeException(
return version.create(this);
}
- public Map<CustomLayerOrderKey, List<CustomLayerOrder>> createDefaultCustomLayerOrderMap(
- CharacterData cd, DefaultCharacterDataVersion version) {
- if (version == null) {
- throw new IllegalArgumentException();
- }
- return version.createCustomLayerOrderMap(cd, this);
- }
-
/**
- * テンプレートリストの定義プロパティを読み込む.<br>
- * neutral引数がfalseの場合は現在のロケールを優先する.<br>
- * 引数がtrueの場合は読み込み順を逆転させ、言語中立を優先する.<br>
+ * デフォルトのキャラクター定義に付随するカスタムレイヤーパターンを生成して返す。
*
- * @param neutral
- * 言語中立を優先する場合
- * @return テンプレートリストのプロパティ
+ * 引数のpartsCategoryResolverは、カスタムレイヤーパターンはパーツカテゴリインスタンスを保持するため、
+ * そのキャラクターデータと同じインスタンスのパーツカテゴリインスタンスを取得できるようにするためのものである。
+ * @param partsCategoryResolver カテゴリIDでカテゴリを索引するリゾルバ
+ * @param version バージョン
+ * @return 付随するカスタムレイヤーパターン、なければnull
*/
- private Properties getTemplateListProperties(boolean neutral) {
- // テンプレートリソースは実行中に増減する可能性があるため、
- // 共有キャッシュには入れない.
- LocalizedResourcePropertyLoader loader = new LocalizedResourcePropertyLoader(
- null);
- String name = DEFAULT_CHARACTER_PREFIX + TEMPLATE_LIST_XML;
- ResourceNames resNames = LocalizedResourcePropertyLoader
- .getResourceNames(name, null);
- if (neutral) {
- // 言語中立を優先する場合は、プロパティの重ね順を逆転させて言語中立で最後に上書きする.
- resNames = resNames.reverse();
+ public Map<CustomLayerOrderKey, List<CustomLayerOrder>> createDefaultCustomLayerOrderMap(
+ PartsCategoryResolver partsCategoryResolver, DefaultCharacterDataVersion version) {
+ if (partsCategoryResolver == null) {
+ throw new NullPointerException("categories is required.");
}
- return loader.getLocalizedProperties(name);
+ if (version == null) {
+ throw new NullPointerException("version is required.");
+ }
+ return version.createCustomLayerOrderMap(partsCategoryResolver, this);
}
/**
* キャラクターデータのxmlファイル名をキーとし、表示名を値とするマップ.<br>
* 表示順序でアクセス可能.<br>
*
- * @return 順序付マップ
+ * @return 順序付マップ(キーはテンプレートxmlのファイル名、値は表示名)
*/
public Map<String, String> getCharacterDataTemplates() {
// キャラクターデータのxmlファイル名をキーとし、表示名を値とするマップ
final LinkedHashMap<String, String> templateNameMap = new LinkedHashMap<String, String>();
// テンプレートの定義プロパティのロード
- Properties props = getTemplateListProperties(false);
+ // テンプレートリソースは実行中に増減する可能性があるため、共有キャッシュには入れない.
+ LocalizedResourcePropertyLoader propLoader = LocalizedResourcePropertyLoader.getNonCachedInstance();
+ Properties props = propLoader.getLocalizedProperties(DEFAULT_CHARACTER_PREFIX + TEMPLATE_LIST_XML, null);
- // 順序優先
+ // 順序優先のキーに、テンプレート名がカンマ区切りになっているので、
+ // このキーにあるものを先に順番に登録する
String strOrders = props.getProperty("displayOrder");
if (strOrders != null) {
- for (String key : strOrders.split(",")) {
- key = key.trim();
- String val = props.getProperty(key);
- if (val != null && val.trim().length() > 0) {
- String resKey = DEFAULT_CHARACTER_PREFIX + key;
+ for (String templateFileName : strOrders.split(",")) {
+ templateFileName = templateFileName.trim();
+ String displayName = props.getProperty(templateFileName);
+ if (displayName != null && displayName.trim().length() > 0) {
+ String resKey = DEFAULT_CHARACTER_PREFIX + templateFileName;
if (getResource(resKey) != null) {
// 現存するテンプレートのみ登録
- templateNameMap.put(key, val);
+ templateNameMap.put(templateFileName, displayName);
}
}
}
}
- // é \86åº\8fã\81\8c指定されていないアイテムの追加
+ // é \86åº\8fã\81§指定されていないアイテムの追加
Enumeration<?> enm = props.propertyNames();
while (enm.hasMoreElements()) {
- String key = (String) enm.nextElement();
- String val = props.getProperty(key);
- if (key.endsWith(".xml")) {
- String resKey = DEFAULT_CHARACTER_PREFIX + key;
- if (getResource(resKey) != null) {
- // 現存するテンプレートのみ登録
- templateNameMap.put(key, val);
+ String templateFileName = (String) enm.nextElement();
+ if (!templateNameMap.containsKey(templateFileName)) {
+ if (templateFileName.endsWith(".xml")) {
+ String displayName = props.getProperty(templateFileName);
+ String resKey = DEFAULT_CHARACTER_PREFIX + templateFileName;
+ if (getResource(resKey) != null) {
+ // 現存するテンプレートのみ登録
+ templateNameMap.put(templateFileName, displayName);
+ }
}
}
}
- // フォルダにある未登録のxmlファイルもテンプレート一覧に加える
- // (ただし、テンプレートリストプロパティを除く)
+ // ã\83ã\83¼ã\82«ã\83«ã\83\95ã\82©ã\83«ã\83\80ã\81«ã\81\82ã\82\8bæ\9cªç\99»é\8c²ã\81®xmlã\83\95ã\82¡ã\82¤ã\83«ã\82\82ã\83\86ã\83³ã\83\97ã\83¬ã\83¼ã\83\88ä¸\80覧ã\81«å\8a ã\81\88ã\82\8b
+ // (ã\81\9fã\81 ã\81\97ã\80\81ã\83\86ã\83³ã\83\97ã\83¬ã\83¼ã\83\88ã\83ªã\82¹ã\83\88ã\83\97ã\83ã\83\91ã\83\86ã\82£ã\80\81ã\82«ã\82¹ã\82¿ã\83 ã\83¬ã\82¤ã\83¤ã\83¼ã\83\91ã\82¿ã\83¼ã\83³å®\9a義ã\82\92é\99¤ã\81\8f)
try {
- File templDir = getTemplateDir(false);
- if (templDir.isDirectory()) {
+ File templDir = getUserTemplateDir();
+ if (templDir.exists() && templDir.isDirectory()) {
File[] files = templDir.listFiles(new java.io.FileFilter() {
public boolean accept(File pathname) {
String name = pathname.getName();
// テンプレートリストプロパティファイルは除外する.
return false;
}
+ if (name.endsWith(CUSTOM_LAYER_ORDERS_SUFFIX)) {
+ // カスタムレイヤーパターン定義ファイルは除外する.
+ return false;
+ }
return pathname.isFile() && name.endsWith(".xml");
}
});
* XMLリソースファイルから、定義済みのカスタムレイヤーパターンを生成して返す。
* 指定されたリソース名に対して「-customlayerorders.xml」のような末尾に変えたリソースで検索される。
* 定義がない場合はnullを返す。
- * @param cd
+ * @param partsCategoryResolver
* @param name リソース名
* @return
* @throws IOException
*/
- public Map<CustomLayerOrderKey, List<CustomLayerOrder>> loadPredefinedCustomLayerOrder(CharacterData cd, String name)
- throws IOException {
+ public Map<CustomLayerOrderKey, List<CustomLayerOrder>> loadPredefinedCustomLayerOrder(
+ PartsCategoryResolver partsCategoryResolver, String name) throws IOException {
// キャラクター定義xmlへのリソース名から、カスタムレイヤー定義のリソース名を組み立てる
int pt = name.lastIndexOf(".");
String nameBody = name.substring(0, pt);
InputStream is = predefinedCharacter.openStream();
try {
logger.log(Level.INFO, "load a predefined custom layer orders. resKey=" + resKey);
- CustomLayerOrderXMLReader xmlReader = new CustomLayerOrderXMLReader(cd);
+ CustomLayerOrderXMLReader xmlReader = new CustomLayerOrderXMLReader(partsCategoryResolver);
return xmlReader.read(is);
} finally {
* @return リソース、なければnull
*/
protected URL getResource(String resKey) {
- ResourceLoader resourceLoader = new ResourceLoader();
return resourceLoader.getResource(resKey);
}
/**
- * カスタマイズ用のテンプレートディレクトリを取得する.<br>
- * まだ作成されていない場合で、prepareが指示されている場合はフォルダを準備し、 既定のファイルを作成する.<br>
+ * ã\83¦ã\83¼ã\82¶ã\83¼å®\9a義ã\81®ã\82«ã\82¹ã\82¿ã\83\9eã\82¤ã\82ºç\94¨ã\81®ã\83\86ã\83³ã\83\97ã\83¬ã\83¼ã\83\88ã\83\87ã\82£ã\83¬ã\82¯ã\83\88ã\83ªã\82\92å\8f\96å¾\97ã\81\99ã\82\8b.<br>
+ * (ディレクトリが実在しない場合もありえる)
*
- * @param prepare
- * 実際にディレクトリを準備する場合はtrue
* @return テンプレートディレクトリ
*/
- public File getTemplateDir(boolean prepare) throws IOException {
+ public File getUserTemplateDir() throws IOException {
File baseDir = ConfigurationDirUtilities.getUserDataDir();
SetupLocalization setup = new SetupLocalization(baseDir);
File resourceDir = setup.getResourceDir();
-
- if (prepare) {
- // テンプレートリソースが未設定であれば設定する.
- setup.setupToLocal(
- EnumSet.of(SetupLocalization.Resources.Template), false);
-
- // ディレクトリがなければ作成しておく
- if (resourceDir.exists()) {
- resourceDir.mkdirs();
- }
- }
return new File(resourceDir, DEFAULT_CHARACTER_PREFIX);
}
* キャラクターデータ
* @param localizedName
* 表示名
+ * @param customLayerPattern
+ * カスタムレイヤーパターン、なければnull
* @throws IOException
*/
- public void saveTemplate(String name, CharacterData cd, String localizedName)
- throws IOException {
+ public void saveTemplate(String name, CharacterData cd, String localizedName,
+ Map<CustomLayerOrderKey, List<CustomLayerOrder>> customLayerPatterns) throws IOException {
if (name == null || !canFileSave(name)) {
throw new IllegalArgumentException();
}
// テンプレートファイル位置の準備
- // (リソースが、まだファイルに展開されていなれば展開する)
- File templDir = getTemplateDir(true);
+ // (ディレクトリが存在しない場合は作成する)
+ File templDir = getUserTemplateDir();
+ templDir.mkdirs();
+
File templFile = new File(templDir, name);
// キャラクターデータをXML形式でテンプレートファイルへ保存
bos.close();
}
- // テンプレートの定義プロパティのロード(言語中立を優先)
- Properties neutralProps = getTemplateListProperties(true);
+ // カスタムレイヤーパターンを保存する
+ if (customLayerPatterns != null && cd.isEnableCustonLayerPattern()) {
+ // 拡張子を取り除いた名前を取得する
+ int pt = name.lastIndexOf(".");
+ String nameBody = (pt > 0) ? name.substring(0, pt) : name;
+ // カスタムレイヤーパターンとして識別される末尾文字列を付与する
+ File templCustomLayerFile = new File(templDir, nameBody + CUSTOM_LAYER_ORDERS_SUFFIX);
+
+ // カスタムレイヤーパターンXMLファイルを作成する
+ CustomLayerOrderXMLWriter xmlWriter = new CustomLayerOrderXMLWriter();
+ BufferedOutputStream bos2 = new BufferedOutputStream(new FileOutputStream(templCustomLayerFile));
+ try {
+ xmlWriter.write(customLayerPatterns, bos2);
+ } finally {
+ bos2.close();
+ }
+ }
+
+ // ユーザー定義テンプレートのプロパティファイルをロードする
+ Properties userTemplDefProp = loadUserDefineTemplateDef();
// テンプレート一覧の更新
- neutralProps.put(name, localizedName);
+ userTemplDefProp.put(name, localizedName);
+ saveUserDefineTemplateDef(userTemplDefProp);
+ }
+
+ private File getUserTemplateDefPropertyFile() throws IOException {
+ File templDir = getUserTemplateDir();
+ return new File(templDir, TEMPLATE_LIST_XML + ".xml");
+ }
+
+ private Properties loadUserDefineTemplateDef() throws IOException {
+ File userTemplDefPropFile = getUserTemplateDefPropertyFile();
+ Properties userTemplDefProp = new Properties();
+ if (userTemplDefPropFile.exists() && userTemplDefPropFile.length() > 0) {
+ InputStream is = new BufferedInputStream(new FileInputStream(userTemplDefPropFile));
+ try {
+ userTemplDefProp.loadFromXML(is);
+ } finally {
+ is.close();
+ }
+ }
+ return userTemplDefProp;
+ }
+
+ private void saveUserDefineTemplateDef(Properties userTemplDefProp) throws IOException {
+ if (userTemplDefProp == null) {
+ userTemplDefProp = new Properties();
+ }
+
+ File userTemplDefPropFile = getUserTemplateDefPropertyFile();
// テンプレート一覧の保存
- File neutralPropsFile = new File(templDir, TEMPLATE_LIST_XML + ".xml");
- BufferedOutputStream fos = new BufferedOutputStream(
- new FileOutputStream(neutralPropsFile));
+ BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(userTemplDefPropFile));
try {
- neutralProps.storeToXML(fos,
- new Timestamp(System.currentTimeMillis()).toString());
+ userTemplDefProp.storeToXML(fos, new Timestamp(System.currentTimeMillis()).toString());
} finally {
- bos.close();
+ fos.close();
}
}
}
/**
* ディレクトリをアーカイブと見立てる
- *
+ *
* @author seraphy
*/
public class CharacterDataDirectoryFile extends AbstractCharacterDataArchiveFile {
-
+
/**
* ロガー
*/
private static final Logger logger = Logger.getLogger(CharacterDataDirectoryFile.class.getName());
-
+
/**
* 対象ディレクトリ
*/
protected File baseDir;
-
+
/**
* ディレクトリ上のファイルコンテンツ
- *
+ *
* @author seraphy
*/
protected static class DirFileContent implements FileContent {
* 実際のファイルへのパス
*/
private File entry;
-
+
protected DirFileContent(File entry, String entryName) {
this.entry = entry;
this.entryName = entryName;
}
-
+
public String getEntryName() {
return entryName;
}
-
+
public long lastModified() {
return entry.lastModified();
}
+ @Override
+ public long length() {
+ return entry.length();
+ }
+
public InputStream openStream() throws IOException {
return new FileInputStream(entry);
}
}
-
+
/**
* アーカイブファイルをベースとしたURIを返す.<br>
- *
+ *
* @param name
* コンテンツ名
* @return URI
protected URI getContentURI(String name) throws IOException {
return new File(baseDir, name).toURI();
}
-
+
@Override
public Collection<PartsImageContent> getPartsImageContents(
CharacterData characterData, boolean newly) {
}
return super.getPartsImageContents(characterData, newly);
}
-
+
/**
* このディレクトリに対してターゲットプロファイルのディレクトリがかぶっているか? つまり、ターゲット自身のディレクトリをソースとしていないか?
- *
+ *
* @param characterData
* ソースプロファイル
* @return 被っている場合はtrue、被っていない場合はfalse
String folderPlace = File.separator;
String basePath = new File(docBase).getParent() + folderPlace;
String sourcePath = baseDir.getPath() + folderPlace;
-
+
// インポートもとディレクトリがインポート先のキャラクター定義のディレクトリを含むか?
boolean result = basePath.contains(sourcePath);
logger.log(Level.FINE, "checkOverlapped: " + basePath + " * " + sourcePath + " :" + result);
-
+
return result;
}
public void close() throws IOException {
// ディレクトリなのでクローズ処理は必要ない.
}
-
+
public CharacterDataDirectoryFile(File file) throws IOException {
super(file);
baseDir = file;
load(baseDir, "");
searchRootPrefix();
}
-
+
private void load(File dir, String prefix) {
if (!dir.exists() || !dir.isDirectory()) {
// ディレクトリでなければ何もせず戻る
return;
}
-
+
// ファイル名をノーマライズする
FileNameNormalizer normalizer = FileNameNormalizer.getDefault();
-
+
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
public class CharacterDataJarArchiveFile extends AbstractCharacterDataArchiveFile {
protected JarFile jarFile;
-
+
protected class JarFileContent implements FileContent {
private JarEntry entry;
-
+
protected JarFileContent(JarEntry entry) {
this.entry = entry;
}
-
+
+ @Override
public String getEntryName() {
return entry.getName();
}
-
+
+ @Override
public long lastModified() {
return entry.getTime();
}
-
+
+ @Override
+ public long length() {
+ return entry.getSize();
+ }
+
+ @Override
public InputStream openStream() throws IOException {
return jarFile.getInputStream(entry);
}
-
}
-
+
public void close() throws IOException {
jarFile.close();
}
-
+
public CharacterDataJarArchiveFile(File file) throws IOException {
super(file);
jarFile = new JarFile(file);
load();
}
-
+
private void load() {
Enumeration<JarEntry> enm = jarFile.entries();
while (enm.hasMoreElements()) {
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
-import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
-import java.util.Iterator;
import java.util.List;
-import java.util.NoSuchElementException;
+import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
import charactermanaj.graphics.io.FileImageResource;
import charactermanaj.graphics.io.ImageLoader;
import charactermanaj.graphics.io.ImageSaveHelper;
import charactermanaj.graphics.io.LoadedImage;
import charactermanaj.model.AppConfig;
import charactermanaj.model.CharacterData;
+import charactermanaj.model.CustomLayerOrder;
+import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.Layer;
import charactermanaj.model.PartsCategory;
import charactermanaj.model.io.CharacterDataDefaultProvider.DefaultCharacterDataVersion;
import charactermanaj.util.DirectoryConfig;
import charactermanaj.util.FileNameNormalizer;
import charactermanaj.util.FileUserData;
+import charactermanaj.util.FileUtilities;
import charactermanaj.util.UserData;
public class CharacterDataPersistent {
}
/**
+ * {@link #createProfile(CharacterData)}に加えて、同時にカスタムレイヤーパターンを登録します。
+ * @param characterData キャラクターデータ
+ * @param customLayerPatterns カスタムレイヤーパターン、なければnull可
+ * @throws IOException 失敗
+ */
+ public void createProfile(CharacterData characterData,
+ Map<CustomLayerOrderKey, List<CustomLayerOrder>> customLayerPatterns) throws IOException {
+ // キャラクターデータの登録
+ createProfile(characterData);
+
+ // カスタムレイヤーパターンの登録
+ if (characterData.isEnableCustonLayerPattern() && customLayerPatterns != null) {
+ CustomLayerOrderPersist persist = CustomLayerOrderPersist.newInstance(characterData);
+ persist.save(customLayerPatterns);
+ }
+ }
+
+ /**
* リビジョンを生成して返す.
*
* @return リビジョン用文字列
return;
}
- // favories.xmlの削除
- if (forceRemove) {
- UserData[] favoritesDatas = new UserData[]{getFavoritesUserData(cd)};
- for (UserData favoriteData : favoritesDatas) {
- if (favoriteData != null && favoriteData.exists()) {
- logger.log(Level.INFO, "remove file: " + favoriteData);
- favoriteData.delete();
- }
- }
+ // ディレクトリ
+ File baseDir = xmlFile.getParentFile();
+ if (!baseDir.exists()) {
+ // すでに存在しない場合
+ return;
}
+// ver0.998以降では、お気に入りはキャラクターデータと同一ディレクトリにあるので、別個の処理は不要
+// // favories.xmlの削除
+// if (forceRemove) {
+// UserData[] favoritesDatas = new UserData[] { getFavoritesUserData(cd) };
+// for (UserData favoriteData : favoritesDatas) {
+// if (favoriteData != null && favoriteData.exists()) {
+// logger.log(Level.INFO, "remove file: " + favoriteData);
+// favoriteData.delete();
+// }
+// }
+// }
+
// ワーキングセットの削除
// XML形式でのワーキングセットの保存
WorkingSetPersist workingSetPersist = WorkingSetPersist.getInstance();
workingSetPersist.removeWorkingSet(cd);
- // xmlファイルの拡張子を変更することでキャラクター定義として認識させない.
- // (削除に失敗するケースに備えて先にリネームする.)
- String suffix = "." + System.currentTimeMillis() + ".deleted";
- File bakFile = new File(xmlFile.getPath() + suffix);
- if (!xmlFile.renameTo(bakFile)) {
- throw new IOException("can not rename configuration file.:"
- + xmlFile);
- }
-
- // ディレクトリ
- File baseDir = xmlFile.getParentFile();
-
if (!forceRemove) {
- // 削除されたディレクトリであることを識別できるようにディレクトリ名も変更する.
- File parentBak = new File(baseDir.getPath() + suffix);
- if (!baseDir.renameTo(parentBak)) {
- throw new IOException("can't rename directory. " + baseDir);
- }
+ // 論理削除
+ logicalDelete(xmlFile);
} else {
- // 完全に削除する
- removeRecursive(baseDir);
+ // 完全に削除する(物理削除)
+ try {
+ FileUtilities.delete(baseDir);
+
+ } catch (IOException ex) {
+ // 削除に失敗した場合は論理削除を試行する
+ logicalDelete(xmlFile);
+ throw ex; // 論理削除でエラーがでない場合は物理削除エラーをそのまま返す
+ }
}
}
/**
- * 指定したファイルを削除します.<br>
- * 指定したファイルがディレクトリを示す場合、このディレクトリを含む配下のすべてのファイルとディレクトリを削除します.<br>
- *
- * @param file
- * ファイル、またはディレクトリ
+ * キャラクターデータxmlファイルをリネームすることで論理的に削除する。
+ * 削除されたキャラクターデータであることを示すためにフォルダ名も.deletedとづける
+ * @param xmlFile
* @throws IOException
- * 削除できない場合
*/
- protected void removeRecursive(File file) throws IOException {
- if (file == null) {
- throw new IllegalArgumentException();
- }
- if (!file.exists()) {
- return;
- }
- if (file.isDirectory()) {
- File[] children = file.listFiles();
- if (children != null) {
- for (File child : children) {
- removeRecursive(child);
- }
- }
- }
- if (!file.delete()) {
- throw new IOException("can't delete file. " + file);
- }
- }
+ private void logicalDelete(File xmlFile) throws IOException {
+ File baseDir = xmlFile.getParentFile();
- protected Iterable<Node> iterable(final NodeList nodeList) {
- final int mx;
- if (nodeList == null) {
- mx = 0;
- } else {
- mx = nodeList.getLength();
+ // xmlファイルの拡張子を変更することでキャラクター定義として認識させない.
+ // (削除に失敗するケースに備えて先にリネームする.)
+ String suffix = "." + System.currentTimeMillis() + ".deleted";
+ File bakFile = new File(xmlFile.getPath() + suffix);
+ if (!xmlFile.renameTo(bakFile)) {
+ throw new IOException("can not rename configuration file.:"
+ + xmlFile);
}
- return new Iterable<Node>() {
- public Iterator<Node> iterator() {
- return new Iterator<Node>() {
- private int idx = 0;
- public boolean hasNext() {
- return idx < mx;
- }
- public Node next() {
- if (idx >= mx) {
- throw new NoSuchElementException();
- }
- return nodeList.item(idx++);
- }
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
- };
- }
- protected URL getEmbeddedResourceURL(String schemaName) {
- return this.getClass().getResource(schemaName);
+ // 削除されたディレクトリであることを識別できるようにディレクトリ名も変更する.
+ File parentBak = new File(baseDir.getPath() + suffix);
+ if (!baseDir.renameTo(parentBak)) {
+ throw new IOException("can't rename directory. " + baseDir);
+ }
}
/**
} else {
// 削除
if (sampleImageFile.exists()) {
- if (!sampleImageFile.delete()) {
- throw new IOException("sample pucture delete failed. :"
- + sampleImageFile);
- }
+ FileUtilities.delete(sampleImageFile);
}
}
}
import java.awt.image.BufferedImage;
import java.io.IOException;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import charactermanaj.model.CharacterData;
+import charactermanaj.model.CustomLayerOrder;
+import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.PartsIdentifier;
import charactermanaj.model.PartsSpec;
public interface CharacterDataWriter {
void writeExportProp(Properties prop) throws IOException;
-
+
void writeCharacterData(CharacterData characterData) throws IOException;
-
+
+ void writeCustomLayerPatterns(Map<CustomLayerOrderKey, List<CustomLayerOrder>> map) throws IOException;
+
void writeTextUTF16LE(String name, String contents) throws IOException;
-
+
void writeSamplePicture(BufferedImage samplePicture) throws IOException;
-
+
void writePartsImages(Map<PartsIdentifier, PartsSpec> partsImages) throws IOException;
-
+
void writePartsManageData(Map<PartsIdentifier, PartsSpec> partsImages) throws IOException;
void close() throws IOException;
public class CharacterDataZipArchiveFile extends AbstractCharacterDataArchiveFile {
protected ZipFile zipFile;
-
+
protected class ZipFileContent implements FileContent {
private ZipEntry entry;
-
+
protected ZipFileContent(ZipEntry entry) {
this.entry = entry;
}
-
+
+ @Override
public String getEntryName() {
return entry.getName();
}
-
+
+ @Override
public long lastModified() {
return entry.getTime();
}
-
+
+ @Override
+ public long length() {
+ return entry.getSize();
+ }
+
+ @Override
public InputStream openStream() throws IOException {
return zipFile.getInputStream(entry);
}
-
}
-
+
public void close() throws IOException {
zipFile.close();
}
-
+
public CharacterDataZipArchiveFile(File file) throws IOException {
super(file);
-
+
AppConfig appConfig = AppConfig.getInstance();
String encoding = appConfig.getZipNameEncoding();
-
+
zipFile = new ZipFile(file, encoding);
load();
}
-
+
private void load() {
@SuppressWarnings("unchecked")
Enumeration<ZipEntry> enm = zipFile.getEntries();
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
+import java.util.Collections;
import java.util.EventListener;
import java.util.EventObject;
import java.util.List;
import charactermanaj.util.FileUserData;
import charactermanaj.util.UserData;
+/**
+ * カスタムレイヤーパターンの読み込みと保存を行う。
+ */
public abstract class CustomLayerOrderPersist {
+ /**
+ * レイヤーパターンのXMLファイル名
+ */
+ public static final String CUSTOM_LAYER_ORDERS_XML_FILE = "customlayerorders.xml";
+
+ /**
+ * カスタムレイヤーパターンが変更(保存)されたことを通知するリスナ
+ */
public interface CustomLayerOrderPersistListener extends EventListener {
public static class Change extends EventObject {
void notifyChangeCustomLayerOrder(Change e);
}
+ /**
+ * 対象としているキャラクターデータ
+ */
protected final CharacterData characterData;
+ /**
+ * コンストラクタ
+ * @param characterData
+ */
protected CustomLayerOrderPersist(CharacterData characterData) {
if (characterData == null) {
throw new NullPointerException();
this.characterData = characterData;
}
+ /**
+ * 対象としているキャラクターデータ
+ * @return
+ */
public CharacterData getCharacterData() {
return characterData;
}
+ /**
+ * キャラクターデータを指定してインスタンスを構築する
+ * @param characterData
+ * @return
+ */
public static CustomLayerOrderPersist newInstance(CharacterData characterData) {
return new CustomLayerOrderXMLPersist(characterData);
}
+ /**
+ * カスタムレイヤーパターンが存在するか?
+ * @return 存在する場合はtrue(空の場合でもtrueとなる)
+ */
public abstract boolean exist();
+ /**
+ * カスタムレイヤーパターンを保存する
+ * @param map
+ * @throws IOException
+ */
public abstract void save(Map<CustomLayerOrderKey, List<CustomLayerOrder>> map) throws IOException;
+ /**
+ * カスタムレイヤーパターンをロードする。
+ * 存在しない場合はnullを返す。
+ * @return パターン、もしくはnull
+ * @throws IOException
+ */
public abstract Map<CustomLayerOrderKey, List<CustomLayerOrder>> load() throws IOException;
+
+ /**
+ * リスナーのマップ
+ */
private static final Map<URI, Queue<CustomLayerOrderPersistListener>> listenersMap =
new ConcurrentHashMap<URI, Queue<CustomLayerOrderPersistListener>>();
+ /**
+ * このキャラクターデータのカスタムレイヤーパターンの保存の通知を受け取るリスナを登録する
+ * @param l
+ */
public void addCustomLayerOrderPersistListener(CustomLayerOrderPersistListener l) {
URI uri = characterData.getDocBase();
if (l != null && uri != null) {
}
}
+ /**
+ * このキャラクターデータのカスタムレイヤーパターンの保存の通知を受け取るリスナを登録解除する
+ * @param l
+ */
public void removeCustomLayerOrderPersistListener(CustomLayerOrderPersistListener l) {
URI uri = characterData.getDocBase();
if (l != null && uri != null) {
if (listeners != null) {
listeners.remove(l);
if (listeners.isEmpty()) {
+ // これが最後のリスナであればマップのエントリも消す
listenersMap.remove(uri);
}
}
}
}
+ /**
+ * このキャラクターデータのカスタムレイヤーパターンの保存を全てのリスナーに通知する
+ * @param map
+ */
protected void fireEvent(Map<CustomLayerOrderKey, List<CustomLayerOrder>> map) {
URI uri = characterData.getDocBase();
if (uri != null) {
}
}
+/**
+ * カスタムレイヤーパターンをXML形式で保存する実装クラス
+ */
class CustomLayerOrderXMLPersist extends CustomLayerOrderPersist {
- /**
- * レイヤーパターンのXMLファイル名
- */
- public static final String CUSTOM_LAYER_ORDERS_XML_FILE = "customlayerorders.xml";
-
public CustomLayerOrderXMLPersist(CharacterData characterData) {
super(characterData);
}
+ /**
+ * 実際のXMLの保存先と関連づけられたユーザーデータ型を返す
+ * @return
+ */
private UserData getCustomLayerOrdersUserData() {
// xml形式の場合、キャラクターディレクトリ上に設定する.
URI docBase = characterData.getDocBase();
@Override
public void save(Map<CustomLayerOrderKey, List<CustomLayerOrder>> map) throws IOException {
+ if (map == null) {
+ map = Collections.emptyMap();
+ }
+
UserData xmlData = getCustomLayerOrdersUserData();
OutputStream outstm = xmlData.getOutputStream();
try {
@Override
public Map<CustomLayerOrderKey, List<CustomLayerOrder>> load() throws IOException {
UserData xmlData = getCustomLayerOrdersUserData();
- if (xmlData.exists() && xmlData.length() > 0) {
+ if (xmlData.exists()) {
+ if (xmlData.length() == 0) {
+ // 空ファイルは空エントリとみなす
+ return Collections.emptyMap();
+ }
+ // XMLの読み取り
InputStream is = xmlData.openStream();
try {
CustomLayerOrderXMLReader xmlReader = new CustomLayerOrderXMLReader(characterData);
}
return null;
}
-}
\ No newline at end of file
+}
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import charactermanaj.model.CharacterData;
import charactermanaj.model.CustomLayerOrder;
import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.Layer;
import charactermanaj.model.PartsCategory;
+import charactermanaj.model.PartsCategoryResolver;
public class CustomLayerOrderXMLReader {
- private CharacterData cd;
+ private PartsCategoryResolver categoryResolver;
- public CustomLayerOrderXMLReader(CharacterData cd) {
- if (cd == null) {
+ public CustomLayerOrderXMLReader(PartsCategoryResolver categoryResolver) {
+ if (categoryResolver == null) {
throw new NullPointerException("categories is required.");
}
- this.cd = cd;
+ this.categoryResolver = categoryResolver;
}
public Map<CustomLayerOrderKey, List<CustomLayerOrder>> read(InputStream is) throws IOException {
String layerId = elmMapping.getAttribute("layer");
float layerOrder = Float.parseFloat(elmMapping.getAttribute("order"));
- PartsCategory category = cd.getPartsCategory(categoryId);
+ PartsCategory category = categoryResolver.getPartsCategory(categoryId);
if (category != null) {
Layer layer = category.getLayer(layerId);
if (layer != null) {
import java.io.OutputStream;
import java.net.URI;
import java.util.Collection;
+import java.util.List;
+import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import charactermanaj.model.AppConfig;
import charactermanaj.model.CharacterData;
+import charactermanaj.model.CustomLayerOrder;
+import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.PartsAuthorInfo;
import charactermanaj.model.PartsCategory;
import charactermanaj.model.PartsManageData;
* インポートもとファイル
*/
private URI importSource;
-
+
/**
* プロファイル先のキャラクター定義、新規の場合はnull
*/
private CharacterData currentCharacterData;
-
-
+
+
/**
* インポートもとアーカイブ. ロードされた場合に非nullとなる.
*/
private CharacterDataArchiveFile archiveFile;
-
-
+
+
/**
* インポートされたキャラクター定義、なければnull
*/
private CharacterData sourceCharacterData;
-
+
+ /**
+ * インポートされたカスタムレイヤーパターン定義、なければnull
+ */
+ private Map<CustomLayerOrderKey, List<CustomLayerOrder>> sourceCustomLayerPatternMap;
+
/**
* インポートされたサンプルピクチャ、なければnull
*/
private BufferedImage samplePicture;
-
+
/**
* インポートされたreadme
*/
private String readme;
-
+
/**
* インポート先のキャラクター定義、もしくは現在のキャラクター定義のディレクトリ構成から 読み取ることのできるパーツのコレクション、なければ空.<br>
*/
private Collection<PartsImageContent> partsImageContentsMap;
-
+
/**
* パーツ管理データ、なければ空
*/
private PartsManageData partsManageData;
-
+
public void openImportSource(URI importSource, CharacterData currentCharacterData) throws IOException {
if (archiveFile != null || importSource == null) {
this.importSource = importSource;
this.currentCharacterData = currentCharacterData;
}
-
+
public void closeImportSource() throws IOException {
if (archiveFile != null) {
try {
}
}
}
-
+
public void loadContents(ProgressHandle progressHandle) throws IOException {
if (archiveFile != null) {
throw new IllegalStateException("既にアーカイブがオープンされています。");
}
CharacterDataFileReaderWriterFactory factory = CharacterDataFileReaderWriterFactory.getInstance();
-
+
progressHandle.setCaption("open archive...");
archiveFile = factory.openArchive(importSource);
sourceCharacterData.setDescription(readme);
}
}
-
+
} else {
// character.xmlがあった場合、favorites.xmlもあれば読み込む.
archiveFile.readFavorites(sourceCharacterData);
}
+ if (sourceCharacterData != null && sourceCharacterData.isEnableCustonLayerPattern()) {
+ // キャラクターデータの読み取りができ、且つ、カスタムレイヤーパターンが有効であれば
+ sourceCustomLayerPatternMap = archiveFile.readCustomLayerPatterns(sourceCharacterData);
+ }
+
// サンプルピクチャの読み込み、なければnull
progressHandle.setCaption("load sample picture...");
samplePicture = archiveFile.readSamplePicture();
-
+
// パーツセットの読み込み、なければ空
progressHandle.setCaption("load partssets...");
if (currentCharacterData != null) {
// インポート元にあるキャラクター定義をもとにパーツディレクトリを探索する場合
partsImageContentsMap = archiveFile.getPartsImageContents(sourceCharacterData, true);
}
-
+
// パーツ管理データの読み込み
progressHandle.setCaption("load parts definitions...");
partsManageData = archiveFile.getPartsManageData();
partsImageContentsMap = null;
partsManageData = null;
}
-
+
public URI getImportSource() {
return importSource;
}
-
+
protected void checkArchiveOpened() {
if (archiveFile == null) {
throw new IllegalStateException("アーカイブはオープンされていません。");
}
}
-
+
public CharacterData getCharacterData() {
checkArchiveOpened();
return sourceCharacterData;
}
+ public Map<CustomLayerOrderKey, List<CustomLayerOrder>> getCustomLayerPatternMap() {
+ checkArchiveOpened();
+ return sourceCustomLayerPatternMap;
+ }
+
public BufferedImage getSamplePicture() {
checkArchiveOpened();
return samplePicture;
return partsManageData;
}
-
-
+
+
/**
* パーツデータをプロファイルの画像ディレクトリに一括コピーする.<br>
- *
+ *
* @param partsImageContents
* コピー対象のパーツデータ
* @param cd
AppConfig appConfig = AppConfig.getInstance();
byte[] stmbuf = new byte[appConfig.getFileTransferBufferSize()];
-
+
// ファイルコピー
for (PartsImageContent content : partsImageContents) {
InputStream is = new BufferedInputStream(content.openStream());
} finally {
os.close();
}
-
+
if (!outFile.setLastModified(content.lastModified())) {
logger.log(Level.WARNING, "can't change the modified-date: " + outFile);
}
-
+
} finally {
is.close();
}
* パーツ管理情報がnullまたは空であれば何もしない.<br>
* そうでなければインポートするパーツに該当するパーツ管理情報を、現在のプロファイルのパーツ管理情報に追記・更新し、 それを書き出す.<br>
* インポートもとにパーツ管理情報がなく、既存にある場合、インポートしても管理情報は削除されません.(上書きセマンティクスのため)
- *
+ *
* @param partsImageContents
* インポートするパーツ
* @param partsManageData
if (target == null || !target.isValid()) {
throw new IllegalArgumentException();
}
-
+
if (partsImageContents == null || partsImageContents.isEmpty()
|| partsManageData == null || partsManageData.isEmpty()) {
// インポートするパーツが存在しないか、管理情報がない場合は更新しようがないので何もしないで戻る.
}
PartsInfoXMLReader xmlReader = new PartsInfoXMLReader();
-
+
PartsManageData mergedPartsManagedData;
if (current != null && current.isValid()) {
// 現在のプロファイルからパーツ管理情報を取得する.
// 新規の場合は空
mergedPartsManagedData = new PartsManageData();
}
-
+
// インポート対象のパーツに該当するパーツ管理情報のみを取り出して追記する.
for (PartsImageContent partsImageContent : partsImageContents) {
String partsName = partsImageContent.getPartsName();
for (CategoryLayerPair catLayerPair : partsImageContent.getCategoryLayerPairs()) {
PartsCategory partsCategory = catLayerPair.getPartsCategory();
String categoryId = partsCategory.getCategoryId();
-
+
PartsManageData.PartsKey partsKey = new PartsManageData.PartsKey(partsName, categoryId);
-
+
PartsAuthorInfo partsAuthorInfo = partsManageData.getPartsAuthorInfo(partsKey);
PartsManageData.PartsVersionInfo versionInfo = partsManageData.getVersion(partsKey);
String localizedName = partsManageData.getLocalizedName(partsKey);
-
+
if (partsAuthorInfo != null || versionInfo != null || localizedName != null) {
// いずれかの情報の登録がある場合、パーツ管理情報として追記する.
mergedPartsManagedData.putPartsInfo(partsKey, localizedName, partsAuthorInfo, versionInfo);
import charactermanaj.model.PartsIdentifier;
import charactermanaj.model.PartsSet;
import charactermanaj.model.WorkingSet;
+import charactermanaj.util.FileUtilities;
import charactermanaj.util.UserData;
import charactermanaj.util.UserDataFactory;
return;
}
for (File file : files) {
- boolean success = file.delete();
- logger.log(Level.INFO, "remove file: " + file + " /success="
- + success);
+ logger.log(Level.INFO, "remove file: " + file);
+ try {
+ FileUtilities.delete(file);
+ } catch (Exception ex) {
+ logger.log(Level.WARNING, "failed to remove file: " + file, ex);
+ }
}
}
}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
+import javax.swing.border.Border;
+import javax.swing.border.LineBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
* @return 編集されていればtrue、そうでなければfalse
*/
public boolean isModified() {
+ for (AppConfigRow rowItem : items) {
+ if (rowItem.isModified()) {
+ return true;
+ }
+ }
return false;
}
appConfigTable.setGridColor(appConfig.getGridColor());
appConfigTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
appConfigTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+ appConfigTable.setCellSelectionEnabled(true);
// データタイプがColorの場合のセルレンダラーとエディタを設定する
appConfigTable.setDefaultRenderer(Color.class, new ColorCellRender());
label = new JLabel();
label.setHorizontalAlignment(SwingConstants.CENTER);
box.add(label, BorderLayout.CENTER);
- box.setBorder(BorderFactory.createEtchedBorder());
- button = new JButton();
- Dimension dim = button.getPreferredSize();
- dim.width = 24;
- button.setPreferredSize(dim);
- button.addActionListener(new ActionListener() {
+ AbstractAction actColorChoose = new AbstractAction() {
+ private static final long serialVersionUID = 1L;
+
@Override
public void actionPerformed(ActionEvent e) {
onClick(e);
}
- });
+ };
+
+ button = new JButton(actColorChoose);
+ Dimension dim = button.getPreferredSize();
+ dim.width = 24;
+ button.setPreferredSize(dim);
add(box, BorderLayout.CENTER);
add(button, BorderLayout.EAST);
setSelectedColor(Color.BLACK);
+
+ // ボックスのダブルクリックで、ボタンクリックと同じ動きとする
+ box.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
+ onClick(null);
+ e.consume();
+ }
+ }
+ });
+
+ // このセルのスペースキー押下で、ボタンクリックと同じ動きとする
+ InputMap im = getInputMap(WHEN_FOCUSED);
+ im.put(KeyStroke.getKeyStroke(' '), "ON_CLICK_COLOR_CHOOSER");
+ ActionMap am = getActionMap();
+ am.put("ON_CLICK_COLOR_CHOOSER", actColorChoose);
+
+ setMinimumSize(new Dimension(50, 30));
}
public String getTitle() {
}
}
- protected void onClick(ActionEvent e) {
+ public Border getBoxBorder() {
+ return box.getBorder();
+ }
+
+ public void setBoxBorder(Border border) {
+ box.setBorder(border);
+ }
+
+ public void onClick(ActionEvent e) {
// ※ カラー選択ダイアログは、Java7以降でないとアルファ値の設定はできない。
// Java6で実行するとアルファチャネルが消されたものになる。
// (設定ファイルとしては手作業では設定可能なので、とりあえず、このまま。)
}
}
+ private Color bgColor = Color.WHITE;
+
private Color selectedColor;
public Color getSelectedColor() {
}
public void setSelectedColor(Color color) {
- if (color == null) {
- color = Color.BLACK;
- }
Color old = this.selectedColor;
if (old == null ? color != null : !old.equals(color)) {
this.selectedColor = color;
+ // nullの場合は黒と見なして処理をつづける
+ // (プロパティにはnullを格納したまま)
+ boolean dummyColor = false;
+ if (color == null) {
+ color = Color.BLACK;
+ dummyColor = true;
+ }
+
+ // テキスト色は塗りつぶし色と反転色にする (同系で重なりにくくするため)
Color colorForeground = new Color(color.getRGB() ^ 0xffffff).brighter();
int alpha = color.getAlpha();
// JPanelの背景色としてアルファの透過色をそのまま使うと
// 親コンポーネントの背景色と混じり、色のカタログとして用をなさないので
- // 白を背景色とした合成済みに補正しておく
- // (アルファが255の場合はそのままで良い)
+ // 固定された背景色(たとえば白)と予め合成済みに補正しておく
+ // (アルファが255の場合は合成する必要はない)
Color premultipliedColor;
if (alpha == 255) {
premultipliedColor = color;
} else {
float[] rgb = color.getRGBColorComponents(null);
- float[] bgRgb = Color.WHITE.getRGBColorComponents(null); // 背景色 = 白色
+ float[] bgRgb = bgColor.getRGBColorComponents(null); // 背景色
// アルファを合成済みにする
float a = ((float) alpha) / 255f;
rgb[0] = rgb[0] * a + bgRgb[0] * (1 - a);
label.setForeground(colorForeground);
String msg;
- if (alpha != 255) {
+ if (dummyColor) {
+ // NULLの場合はテキストは表示しない
+ msg = "";
+ } else if (alpha != 255) {
// アルファが255以外の場合はアルファ値も含めてARGBで表示する
msg = String.format("#%08X", ((long) color.getRGB()) & 0xffffffffL);
} else {
/**
* カラーセルのレンダラー
+ * 参考: https://github.com/haifengl/smile/blob/master/plot/src/main/java/smile/swing/table/ButtonCellRenderer.java
*/
class ColorCellRender extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
- private ColorCell panel = new ColorCell();
+ private ColorCell colorCell = new ColorCell();
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
- panel.setSelectedColor((Color) value);
- return panel;
+ Color color = (Color) value;
+ colorCell.setSelectedColor(color);
+
+ LineBorder focusedBorder = null;
+ if (hasFocus) {
+ // フォーカスがある場合はボーダーをつける
+ Color colorBorder = Color.CYAN;
+ focusedBorder = new LineBorder(colorBorder, 2);
+ }
+
+ colorCell.setBoxBorder(focusedBorder);
+
+ return colorCell;
}
}
private static final long serialVersionUID = 1L;
+ private Border focusedBorder = BorderFactory.createLineBorder(Color.WHITE, 2);
+
private ColorCell colorCell = new ColorCell(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
public Component getTableCellEditorComponent(final JTable table, final Object value,
final boolean isSelected, final int row, final int column) {
colorCell.setSelectedColor((Color) value);
+ colorCell.setBoxBorder(focusedBorder); // 編集中はボーターをつける
return colorCell;
}
}
try {
- // クリップボードでサポートされているフォーマットでもっともテキストに適したフレーバーを取得する
- DataFlavor[] flavors = trans.getTransferDataFlavors();
- final DataFlavor textFlavor = DataFlavor.selectBestTextFlavor(flavors);
- if (textFlavor == null) {
+ // 文字列を格納しているか?
+ if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) {
// テキストを持っていない
tk.beep();
return;
ColorConvertParameter org = param.clone(); // 変更有無の判定のため現在値をコピーする
List<String> errorLines = new ArrayList<String>();
- BufferedReader rd = new BufferedReader(textFlavor.getReaderForText(trans));
+ BufferedReader rd = new BufferedReader(DataFlavor.stringFlavor.getReaderForText(trans));
try {
// テキストを読み込みつつ、対応するパラメータを設定する。
for (;;) {
import charactermanaj.Main;
import charactermanaj.model.AppConfig;
import charactermanaj.model.CharacterData;
+import charactermanaj.model.CustomLayerOrder;
+import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.PartsCategory;
import charactermanaj.model.PartsIdentifier;
import charactermanaj.model.PartsSet;
import charactermanaj.model.PartsSpecResolver;
import charactermanaj.model.io.CharacterDataFileReaderWriterFactory;
import charactermanaj.model.io.CharacterDataWriter;
+import charactermanaj.model.io.CustomLayerOrderPersist;
import charactermanaj.model.io.ExportInfoKeys;
import charactermanaj.ui.model.AbstractTableModelWithComboBoxModel;
import charactermanaj.ui.progress.ProgressHandle;
public class ExportWizardDialog extends JDialog {
private static final long serialVersionUID = 1L;
-
+
protected static final String STRINGS_RESOURCE = "languages/exportwizdialog";
-
+
protected static ArchiveFileDialog archiveFileDialog = new ArchiveFileDialog();
-
+
private JPanel activePanel;
-
+
private AbstractAction actNext;
-
+
private AbstractAction actPrev;
private AbstractAction actFinish;
-
+
private ExportInformationPanel basicPanel;
-
+
private ExportPartsSelectPanel partsSelectPanel;
-
+
private ExportPresetSelectPanel presetSelectPanel;
private CharacterData source;
-
+
public static File getLastUsedDir() {
return archiveFileDialog.getLastUSedDir();
}
-
+
public static void setLastUsedDir(File lastUsedDir) {
archiveFileDialog.setLastUSedDir(lastUsedDir);
}
-
+
public ExportWizardDialog(JFrame parent, CharacterData characterData, BufferedImage samplePicture) {
super(parent, true);
initComponent(parent, characterData, samplePicture);
}
-
+
public ExportWizardDialog(JDialog parent, CharacterData characterData, BufferedImage samplePicture) {
super(parent, true);
initComponent(parent, characterData, samplePicture);
onClose();
}
});
-
+
Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
.getLocalizedProperties(STRINGS_RESOURCE);
// タイトル
setTitle(strings.getProperty("title"));
-
+
// メインパネル
-
+
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
final CardLayout mainPanelLayout = new CardLayout(5, 5);
mainPanel.setLayout(mainPanelLayout);
contentPane.add(mainPanel, BorderLayout.CENTER);
-
+
ComponentListener componentListener = new ComponentAdapter() {
public void componentShown(ComponentEvent e) {
onComponentShown((JPanel) e.getComponent());
}
};
-
+
// アクション
-
+
this.actNext = new AbstractAction(strings.getProperty("btn.next")) {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
updateBtnPanelState();
}
};
-
+
ChangeListener actPanelEnabler = new ChangeListener() {
public void stateChanged(ChangeEvent e) {
updatePanelStatus();
this.basicPanel.addChangeListener(actChangeValue);
this.basicPanel.addChangeListener(actPanelEnabler);
mainPanel.add(this.basicPanel, "basicPanel");
-
+
// panel2 : panelSelectPanel
this.partsSelectPanel = new ExportPartsSelectPanel(characterData);
this.partsSelectPanel.addComponentListener(componentListener);
this.partsSelectPanel.addChangeListener(actChangeValue);
mainPanel.add(this.partsSelectPanel, "partsSelectPanel");
-
+
// panel3 : presetSelectPanel
this.presetSelectPanel = new ExportPresetSelectPanel(
this.partsSelectPanel,
this.presetSelectPanel.addComponentListener(componentListener);
this.presetSelectPanel.addChangeListener(actChangeValue);
mainPanel.add(this.presetSelectPanel, "presetSelectPanel");
-
-
+
+
// button panel
JPanel btnPanel = new JPanel();
actPrev.setEnabled(false);
actNext.setEnabled(false);
actFinish.setEnabled(false);
-
+
GridBagConstraints gbc = new GridBagConstraints();
-
+
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 1;
gbc.weightx = 1.;
gbc.weighty = 0.;
btnPanel.add(Box.createHorizontalGlue(), gbc);
-
+
gbc.gridx = Main.isLinuxOrMacOSX() ? 2 : 1;
gbc.gridy = 0;
gbc.weightx = 0.;
btnPanel.add(new JButton(this.actPrev), gbc);
-
+
gbc.gridx = Main.isLinuxOrMacOSX() ? 3 : 2;
gbc.gridy = 0;
JButton btnNext = new JButton(this.actNext);
btnPanel.add(btnNext, gbc);
-
+
gbc.gridx = Main.isLinuxOrMacOSX() ? 4 : 3;
gbc.gridy = 0;
btnPanel.add(new JButton(this.actFinish), gbc);
btnPanel.add(btnCancel, gbc);
contentPane.add(btnPanel, BorderLayout.SOUTH);
-
+
// インプットマップ/アクションマップ
-
+
Toolkit tk = Toolkit.getDefaultToolkit();
JRootPane rootPane = getRootPane();
-
+
rootPane.setDefaultButton(btnNext);
-
+
InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap am = rootPane.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "closeExportWizDialog");
am.put("closeExportWizDialog", actCancel);
// 表示
-
+
setSize(500, 500);
setLocationRelativeTo(parent);
-
+
mainPanelLayout.first(mainPanel);
updateBtnPanelState();
updatePanelStatus();
}
-
+
protected void onComponentShown(JPanel panel) {
activePanel = panel;
updateBtnPanelState();
}
-
+
protected void updatePanelStatus() {
partsSelectPanel.setEnabled(basicPanel.isExportPartsImages());
presetSelectPanel.setEnabled(basicPanel.isExportPresets());
}
-
+
protected void updateBtnPanelState() {
actPrev.setEnabled(activePanel != null && activePanel != basicPanel);
actNext.setEnabled(activePanel != null && activePanel != presetSelectPanel);
actFinish.setEnabled(isComplete());
}
-
+
protected void checkMissingParts(Collection<PartsSet> partaSets) {
if (partaSets == null) {
partaSets = presetSelectPanel.getSelectedPresets();
}
partsSelectPanel.checkMissingPartsList(partaSets);
}
-
+
protected boolean isComplete() {
-
+
if (basicPanel.isExportPartsImages()) {
if (partsSelectPanel.getSelectedCount() == 0) {
// パーツイメージのエクスポートを指定した場合、エクスポートするパーツの選択は必須
return false;
}
}
-
+
return true;
}
-
+
protected void onClose() {
Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
.getLocalizedProperties(ExportWizardDialog.STRINGS_RESOURCE);
JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION) {
return;
}
-
+
dispose();
}
-
+
protected void onFinish() {
if (!isComplete()) {
Toolkit tk = Toolkit.getDefaultToolkit();
return null;
}
};
-
+
WorkerWithProgessDialog<Object> dlg
= new WorkerWithProgessDialog<Object>(this, worker);
dlg.startAndWait();
Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
.getLocalizedProperties(ExportWizardDialog.STRINGS_RESOURCE);
JOptionPane.showMessageDialog(this, strings.getProperty("complete"));
-
+
// 完了後、ウィンドウを閉じる.
dispose();
} catch (WorkerException ex) {
ErrorMessageHelper.showErrorDialog(this, ex.getCause());
-
+
} catch (Exception ex) {
ErrorMessageHelper.showErrorDialog(this, ex);
}
}
-
+
protected void doExport(File outFile) throws IOException {
CharacterDataFileReaderWriterFactory writerFactory = CharacterDataFileReaderWriterFactory.getInstance();
CharacterDataWriter exportWriter = writerFactory.createWriter(outFile);
// (プリセットとパーツイメージはリセットされている状態。)
CharacterData cd = source.duplicateBasicInfo();
cd.clearPartsSets(false);
-
+
boolean exportPresets = basicPanel.isExportPresets();
boolean exportSamplePicture = basicPanel.isExportSamplePicture();
boolean exportCharacterData = true;
// 基本情報を設定する.
cd.setAuthor(basicPanel.getAuthor());
cd.setDescription(basicPanel.getDescription());
-
+
// エクスポート情報を出力する.
Properties exportProp = new Properties();
exportProp.setProperty(ExportInfoKeys.EXPORT_PRESETS, Boolean.toString(exportPresets));
exportProp.setProperty(ExportInfoKeys.EXPORT_TIMESTAMP, Long.toString(System.currentTimeMillis()));
exportWriter.writeExportProp(exportProp);
-
+
// プリセットをエクスポートする場合、プリセット情報を登録する.
if (exportPresets) {
HashSet<String> registered = new HashSet<String>();
cd.setDefaultPartsSetId(defaultPresetId);
}
}
-
+
// キャラクターデータを出力する.
exportWriter.writeCharacterData(cd);
-
+
+ // カスタムレイヤーパターンを出力する(有効であれば)
+ if (cd.isEnableCustonLayerPattern()) {
+ Map<CustomLayerOrderKey, List<CustomLayerOrder>> customLayerPatternMap = CustomLayerOrderPersist
+ .newInstance(cd).load();
+ if (customLayerPatternMap != null) {
+ exportWriter.writeCustomLayerPatterns(customLayerPatternMap);
+ }
+ }
+
// readme.txtを出力する.
String readmeContents = cd.getDescription();
if (readmeContents != null && readmeContents.trim().length() > 0) {
if (exportPartsImages) {
Map<PartsIdentifier, PartsSpec> partsSpecMap = partsSelectPanel.getSelectedParts();
-
+
// パーツ管理情報を出力する
exportWriter.writePartsManageData(partsSpecMap);
-
+
// パーツイメージを出力する
exportWriter.writePartsImages(partsSpecMap);
}
}
interface ExportResolverBase {
-
+
void addChangeListener(ChangeListener l);
-
+
void removeChangeListener(ChangeListener l);
-
+
}
* @author seraphy
*/
interface ExportInformationResolver extends ExportResolverBase {
-
+
BufferedImage getSamplePicture();
-
+
boolean isExportSamplePicture();
-
+
boolean isExportPartsImages();
-
+
boolean isExportPresets();
-
+
String getAuthor();
-
+
String getDescription();
}
abstract class AbstractImportPanel extends JPanel implements ExportResolverBase {
-
+
private static final long serialVersionUID = 1L;
protected LinkedList<ChangeListener> listeners = new LinkedList<ChangeListener>();
listeners.add(l);
}
}
-
+
public void removeChangeListener(ChangeListener l) {
if (l != null) {
listeners.remove(l);
}
}
-
+
protected void fireChangeEvent() {
ChangeEvent e = new ChangeEvent(this);
for (ChangeListener listener : listeners) {
private static final long serialVersionUID = 1L;
private BufferedImage samplePicture;
-
+
private SamplePicturePanel sampleImagePanel;
-
+
private JTextField txtAuthor;
-
+
private JTextArea txtDescription;
-
+
private JCheckBox chkPartsImages;
-
+
private JCheckBox chkPresets;
-
+
private JCheckBox chkSampleImage;
-
-
+
+
protected ExportInformationPanel(final CharacterData characterData, final BufferedImage samplePicture) {
if (characterData == null) {
throw new IllegalArgumentException();
GridBagLayout basicPanelLayout = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
setLayout(basicPanelLayout);
-
+
JPanel contentsSpecPanel = new JPanel();
contentsSpecPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5),
BorderFactory.createTitledBorder(strings.getProperty("basic.contentsSpec"))));
BoxLayout contentsSpecPanelLayout = new BoxLayout(contentsSpecPanel, BoxLayout.PAGE_AXIS);
contentsSpecPanel.setLayout(contentsSpecPanelLayout);
-
+
JCheckBox chkCharacterDef = new JCheckBox(strings.getProperty("characterdef"));
- chkPartsImages = new JCheckBox(strings.getProperty("basic.chk.partsImages"));
+ chkPartsImages = new JCheckBox(strings.getProperty("basic.chk.partsImages"));
chkPresets = new JCheckBox(strings.getProperty("basic.chk.presets"));
chkSampleImage = new JCheckBox(strings.getProperty("basic.chk.samplePicture"));
contentsSpecPanel.add(chkSampleImage);
///
-
- JPanel commentPanel = new JPanel();
+
+ JPanel commentPanel = new JPanel();
Dimension archiveInfoPanelMinSize = new Dimension(300, 200);
commentPanel.setMinimumSize(archiveInfoPanelMinSize);
commentPanel.setPreferredSize(archiveInfoPanelMinSize);
BorderFactory.createTitledBorder(strings.getProperty("basic.comment"))));
GridBagLayout commentPanelLayout = new GridBagLayout();
commentPanel.setLayout(commentPanelLayout);
-
+
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 1;
gbc.weightx = 0.;
gbc.weighty = 0.;
commentPanel.add(new JLabel(strings.getProperty("description"), JLabel.RIGHT), gbc);
-
+
gbc.gridx = 1;
gbc.gridy = 1;
gbc.gridwidth = 1;
commentPanel.add(new JScrollPane(txtDescription), gbc);
///
-
+
sampleImagePanel = new SamplePicturePanel(samplePicture);
sampleImagePanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5),
BorderFactory.createTitledBorder(strings.getProperty("basic.sampleImage"))));
-
-
+
+
///
-
+
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 1;
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.BOTH;
add(sampleImagePanel, gbc);
-
+
loadBasicInfo(characterData);
// アクションリスナ
-
+
ActionListener modListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateSamplePicture();
chkPresets.addActionListener(modListener);
chkSampleImage.addActionListener(modListener);
}
-
+
protected void updateSamplePicture() {
sampleImagePanel.setVisiblePicture(chkSampleImage.isSelected());
}
-
+
protected void loadBasicInfo(CharacterData characterData) {
if (samplePicture == null) {
// サンプルイメージがなければディセーブル
public BufferedImage getSamplePicture() {
return samplePicture;
}
-
+
public boolean isExportSamplePicture() {
return chkSampleImage.isSelected();
}
-
+
public boolean isExportPartsImages() {
return chkPartsImages.isSelected();
}
-
+
public boolean isExportPresets() {
return chkPresets.isSelected();
}
-
+
public String getAuthor() {
return txtAuthor.getText();
}
-
+
public String getDescription() {
return txtDescription.getText();
}
interface ExportPartsResolver extends ExportResolverBase {
int getSelectedCount();
-
+
void selectByPartsSet(Collection<PartsSet> partsSet);
-
+
Map<PartsIdentifier, PartsSpec> getSelectedParts();
-
+
Map<PartsSet, List<PartsIdentifier>> checkMissingPartsList(Collection<PartsSet> partsSets);
}
private static final long serialVersionUID = 1L;
private ExportPartsTableModel partsTableModel;
-
+
private JTable partsTable;
-
+
private Action actSelectAll;
-
+
private Action actDeselectAll;
private Action actSort;
setBorder(BorderFactory.createTitledBorder(strings.getProperty("parts.title")));
setLayout(new BorderLayout());
-
+
partsTableModel = new ExportPartsTableModel();
-
+
partsTableModel.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
fireChangeEvent();
});
loadPartsInfo(partsSpecResolver);
-
+
AppConfig appConfig = AppConfig.getInstance();
-
+
final Color disabledForeground = appConfig.getDisabledCellForgroundColor();
-
+
partsTable = new JTable(partsTableModel) {
private static final long serialVersionUID = 1L;
@Override
partsTableModel.adjustColumnModel(partsTable.getColumnModel());
partsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
partsTable.setRowSelectionAllowed(true);
-
+
Action actPartsSetCheck = new AbstractAction(strings.getProperty("parts.popup.check")) {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
partsTableModel.setCheck(selRows, false);
}
};
-
+
final JPopupMenu partsTablePopupMenu = new JPopupMenu();
partsTablePopupMenu.add(actPartsSetCheck);
partsTablePopupMenu.add(actPartsUnsetCheck);
-
+
partsTable.setComponentPopupMenu(partsTablePopupMenu);
add(new JScrollPane(partsTable), BorderLayout.CENTER);
onSortByTimestamp();
}
};
-
+
JPanel btnPanel = new JPanel();
GridBagLayout btnPanelLayout = new GridBagLayout();
btnPanel.setLayout(btnPanelLayout);
-
+
GridBagConstraints gbc = new GridBagConstraints();
-
+
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 1;
gbc.ipady = 0;
JButton btnSelectAll = new JButton(actSelectAll);
btnPanel.add(btnSelectAll, gbc);
-
+
gbc.gridx = 1;
gbc.gridy = 0;
JButton btnDeselectAll = new JButton(actDeselectAll);
btnPanel.add(btnDeselectAll, gbc);
-
+
gbc.gridx = 2;
gbc.gridy = 0;
JButton btnSort = new JButton(actSort);
add(btnPanel, BorderLayout.SOUTH);
}
-
+
protected void loadPartsInfo(PartsSpecResolver partsSpecResolver) {
partsTableModel.clear();
for (PartsCategory partsCategory : partsSpecResolver.getPartsCategories()) {
}
partsTableModel.sort();
}
-
+
protected void onSelectAll() {
partsTableModel.selectAll();
}
-
+
protected void onDeselectAll() {
partsTableModel.deselectAll();
}
-
+
protected void onSort() {
partsTableModel.sort();
if (partsTableModel.getRowCount() > 0) {
partsTable.scrollRectToVisible(rct);
}
}
-
+
protected void onSortByTimestamp() {
partsTableModel.sortByTimestamp();
if (partsTableModel.getRowCount() > 0) {
partsTable.scrollRectToVisible(rct);
}
}
-
+
public Map<PartsIdentifier, PartsSpec> getSelectedParts() {
return partsTableModel.getSelectedParts();
}
-
+
public Map<PartsSet, List<PartsIdentifier>> checkMissingPartsList(Collection<PartsSet> partsSets) {
return partsTableModel.checkMissingPartsList(partsSets);
}
-
+
public void selectByPartsSet(Collection<PartsSet> partsSets) {
partsTableModel.selectByPartsSet(partsSets);
}
-
+
public int getSelectedCount() {
return partsTableModel.getSelectedCount();
}
-
+
@Override
public void setEnabled(boolean enabled) {
partsTable.setEnabled(enabled);
interface ExportPresetResolve extends ExportResolverBase {
-
+
int getSelectedCount();
-
+
List<PartsSet> getSelectedPresets();
}
private static final long serialVersionUID = 1L;
private ExportPartsResolver exportPartsResolver;
-
+
private ExportPresetTableModel presetTableModel;
-
+
private JTable presetTable;
-
+
private Action actSelectAll;
-
+
private Action actDeselectAll;
Collection<PartsSet> partsSets, String defaultPresetId) {
this.exportPartsResolver = exportPartsResolver;
-
+
setName("presetSelectPanel");
Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
setBorder(BorderFactory.createTitledBorder(strings.getProperty("preset.title")));
setLayout(new BorderLayout());
-
+
presetTableModel = new ExportPresetTableModel();
presetTableModel.addTableModelListener(new TableModelListener() {
});
loadPresetInfo(partsSets, defaultPresetId);
-
+
AppConfig appConfig = AppConfig.getInstance();
final Color warningForegroundColor = appConfig.getExportPresetWarningsForegroundColor();
final Color disabledForeground = appConfig.getDisabledCellForgroundColor();
-
+
presetTable = new JTable(presetTableModel) {
private static final long serialVersionUID = 1L;
@Override
public Component prepareRenderer(TableCellRenderer renderer,
int row, int column) {
Component comp = super.prepareRenderer(renderer, row, column);
-
+
if (comp instanceof JCheckBox) {
// BooleanのデフォルトのレンダラーはKCheckBoxを継承したJTable$BooleanRenderer
comp.setEnabled(isCellEditable(row, column) && isEnabled());
}
-
+
ExportPresetModel presetModel = presetTableModel.getRow(row);
if (presetModel.isPresetParts()) {
comp.setFont(getFont().deriveFont(Font.BOLD));
if (!isEnabled()) {
comp.setForeground(disabledForeground);
-
+
} else {
if (presetModel.isSelected() && presetModel.getMissingPartsIdentifiers().size() > 0) {
comp.setForeground(warningForegroundColor);
presetTable.setShowGrid(true);
presetTable.setGridColor(appConfig.getGridColor());
presetTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
-
+
final Action actSelectUsedParts = new AbstractAction(
strings.getProperty("preset.popup.selectUsedParts")) {
private static final long serialVersionUID = 1L;
exportUsedParts();
}
};
-
+
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add(actSelectUsedParts);
-
+
presetTable.setComponentPopupMenu(popupMenu);
-
-
+
+
presetTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
presetTableModel.adjustColumnModel(presetTable.getColumnModel());
onSort();
}
};
-
+
JPanel btnPanel = new JPanel();
GridBagLayout btnPanelLayout = new GridBagLayout();
btnPanel.setLayout(btnPanelLayout);
-
+
GridBagConstraints gbc = new GridBagConstraints();
-
+
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 1;
gbc.ipady = 0;
JButton btnSelectAll = new JButton(actSelectAll);
btnPanel.add(btnSelectAll, gbc);
-
+
gbc.gridx = 1;
gbc.gridy = 0;
JButton btnDeselectAll = new JButton(actDeselectAll);
btnPanel.add(btnDeselectAll, gbc);
-
+
gbc.gridx = 2;
gbc.gridy = 0;
JButton btnSort = new JButton(actSort);
add(btnPanel, BorderLayout.SOUTH);
}
-
+
protected void loadPresetInfo(Collection<PartsSet> partsSets, String defaultPresetId) {
presetTableModel.clear();
for (PartsSet orgPartsSet : partsSets) {
presetTableModel.sort();
checkMissingParts();
}
-
+
public void checkMissingParts() {
ArrayList<PartsSet> changedPartsSets = new ArrayList<PartsSet>();
HashMap<PartsSet, ExportPresetModel> partsSetModelMap = new HashMap<PartsSet, ExportPresetModel>();
presetTableModel.fireTableDataChanged();
}
}
-
+
protected void onSelectAll() {
presetTableModel.selectAll();
}
-
+
protected void onDeselectAll() {
presetTableModel.deselectAll();
}
-
+
protected void onSort() {
presetTableModel.sort();
if (presetTableModel.getRowCount() > 0) {
presetTable.scrollRectToVisible(rct);
}
}
-
+
public List<PartsSet> getSelectedPresets() {
return presetTableModel.getSelectedPresets();
}
-
+
protected void exportUsedParts() {
ArrayList<PartsSet> partsSets = new ArrayList<PartsSet>();
int[] selRows = presetTable.getSelectedRows();
ExportPresetModel presetModel = presetTableModel.getRow(selRow);
partsSets.add(presetModel.getPartsSet());
}
-
+
exportPartsResolver.selectByPartsSet(partsSets);
}
-
+
public int getSelectedCount() {
return presetTableModel.getSelectedCount();
}
-
+
public String getDefaultPresetId() {
return presetTableModel.getDefaultPresetId();
}
-
+
@Override
public void setEnabled(boolean enabled) {
this.presetTable.setEnabled(enabled);
private static final long serialVersionUID = 1L;
private static final String[] columnNames;
-
+
private static final int[] columnWidths;
-
+
private boolean enabled = true;
static {
strings.getProperty("parts.column.author"),
strings.getProperty("parts.column.version"),
};
-
+
columnWidths = new int[] {
Integer.parseInt(strings.getProperty("parts.column.selected.width")),
Integer.parseInt(strings.getProperty("parts.column.category.width")),
Integer.parseInt(strings.getProperty("parts.column.version.width")),
};
}
-
+
public void adjustColumnModel(TableColumnModel columnModel) {
for (int idx = 0; idx < columnWidths.length; idx++) {
columnModel.getColumn(idx).setPreferredWidth(columnWidths[idx]);
public int getColumnCount() {
return columnNames.length;
}
-
+
@Override
public String getColumnName(int column) {
return columnNames[column];
}
-
+
public Object getValueAt(int rowIndex, int columnIndex) {
ExportPartsSelectModel partsSelectModel = getRow(rowIndex);
switch (columnIndex) {
}
return "";
}
-
+
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
ExportPartsSelectModel partsSelectModel = getRow(rowIndex);
}
fireTableRowsUpdated(rowIndex, rowIndex);
}
-
+
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
}
return false;
}
-
+
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
}
return String.class;
}
-
+
public void sort() {
Collections.sort(elements);
fireTableDataChanged();
}
-
+
public void sortByTimestamp() {
Collections.sort(elements, new Comparator<ExportPartsSelectModel>() {
public int compare(ExportPartsSelectModel o1, ExportPartsSelectModel o2) {
});
fireTableDataChanged();
}
-
+
public void selectAll() {
for (ExportPartsSelectModel model : elements) {
model.setChecked(true);
}
fireTableDataChanged();
}
-
+
public void deselectAll() {
for (ExportPartsSelectModel model : elements) {
model.setChecked(false);
}
fireTableDataChanged();
}
-
+
/**
* 選択されているパーツイメージのマップを返す.<br>
* @return 選択されているパーツイメージのマップ
}
return selectedPartsMap;
}
-
+
/**
* パーツセットのコレクションを指定し、パーツセットの各パーツがすべてエクスポート対象になっているものだけを返す.<br>
* @param partsSets パーツセットのリスト
throw new IllegalArgumentException();
}
Map<PartsIdentifier, PartsSpec> selectedPartsMap = getSelectedParts();
- HashMap<PartsSet, List<PartsIdentifier>> missingPartsMap = new HashMap<PartsSet, List<PartsIdentifier>>();
+ HashMap<PartsSet, List<PartsIdentifier>> missingPartsMap = new HashMap<PartsSet, List<PartsIdentifier>>();
for (PartsSet partsSet : partsSets) {
ArrayList<PartsIdentifier> missingPartss = new ArrayList<PartsIdentifier>();
Collections.sort(missingPartss);
missingPartsMap.put(partsSet, missingPartss);
}
-
+
return missingPartsMap;
}
-
+
/**
* パーツセットで使用されているパーツを選択状態にする.
* @param partsSet パーツセットのコレクション
}
fireTableDataChanged();
}
-
+
/**
* 選択されているパーツ数を返す.
* @return パーツ数
}
return count;
}
-
+
public void setEnabled(boolean enabled) {
if (this.enabled != enabled) {
this.enabled = enabled;
fireTableDataChanged();
}
}
-
+
public boolean isEnabled() {
return enabled;
}
class ExportPartsSelectModel implements Comparable<ExportPartsSelectModel> {
-
+
private boolean checked;
-
+
private PartsIdentifier partsIdentifier;
-
+
private PartsSpec partsSpec;
-
+
private Timestamp timestamp;
public ExportPartsSelectModel(PartsIdentifier partsIdentifier, PartsSpec partsSpec, boolean selected) {
this.partsIdentifier = partsIdentifier;
this.partsSpec = partsSpec;
this.checked = selected;
-
+
long maxLastModified = partsSpec.getPartsFiles().lastModified();
if (maxLastModified > 0) {
timestamp = new Timestamp(maxLastModified);
timestamp = null;
}
}
-
+
@Override
public int hashCode() {
return partsIdentifier.hashCode();
}
-
+
@Override
public boolean equals(Object obj) {
if (obj == this) {
}
return false;
}
-
+
public int compareTo(ExportPartsSelectModel o) {
int ret = (checked ? 0 : 1) - (o.checked ? 0 : 1); // 逆順
if (ret == 0) {
}
return ret;
}
-
+
public PartsIdentifier getPartsIdentifier() {
return this.partsIdentifier;
}
-
+
public PartsSpec getPartsSpec() {
return this.partsSpec;
}
-
+
public boolean isChecked() {
return checked;
}
-
+
public void setChecked(boolean checked) {
this.checked = checked;
}
-
+
public PartsCategory getPartsCategory() {
return this.partsIdentifier.getPartsCategory();
}
-
+
public String getPartsName() {
return this.partsIdentifier.getLocalizedPartsName();
}
-
+
public Timestamp getTimestamp() {
return timestamp == null ? null : (Timestamp) timestamp.clone();
}
-
+
public String getAuthor() {
return partsSpec.getAuthor();
}
-
+
public String getVersion() {
double version = partsSpec.getVersion();
if (version <= 0) {
private static final long serialVersionUID = 1L;
private static final String[] columnNames;
-
+
private static final int[] columnWidths;
-
+
private boolean enabled = true;
static {
strings.getProperty("preset.column.name"),
strings.getProperty("preset.column.missingparts"),
};
-
+
columnWidths = new int[] {
Integer.parseInt(strings.getProperty("preset.column.selected.width")),
Integer.parseInt(strings.getProperty("preset.column.default.width")),
Integer.parseInt(strings.getProperty("preset.column.missingparts.width")),
};
}
-
+
private String defaultPresetId;
-
+
public void adjustColumnModel(TableColumnModel columnModel) {
for (int idx = 0; idx < columnWidths.length; idx++) {
columnModel.getColumn(idx).setPreferredWidth(columnWidths[idx]);
public int getColumnCount() {
return columnNames.length;
}
-
+
@Override
public String getColumnName(int column) {
return columnNames[column];
}
-
+
public Object getValueAt(int rowIndex, int columnIndex) {
ExportPresetModel presetModel = getRow(rowIndex);
switch (columnIndex) {
}
return "";
}
-
+
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
ExportPresetModel presetModel = getRow(rowIndex);
}
fireTableRowsUpdated(rowIndex, rowIndex);
}
-
+
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
}
return String.class;
}
-
+
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
if (columnIndex == 0 || columnIndex == 1) {
}
return false;
}
-
+
public void sort() {
Collections.sort(elements);
fireTableDataChanged();
}
-
+
public void selectAll() {
for (ExportPresetModel model : elements) {
model.setSelected(true);
}
fireTableDataChanged();
}
-
+
public void deselectAll() {
for (ExportPresetModel model : elements) {
model.setSelected(false);
}
fireTableDataChanged();
}
-
+
/**
* 選択されているパーツセットのリストを返す.<br>
* なにもなければ空.<br>
}
return partsSets;
}
-
+
public int getSelectedCount() {
int count = 0;
for (ExportPresetModel presetModel : elements) {
}
return count;
}
-
+
public String getDefaultPresetId() {
return defaultPresetId;
}
-
+
/**
* デフォルトのプリセットを設定する.<br>
* @param defaultPresetId
public void setDefaultPresetId(String defaultPresetId) {
this.defaultPresetId = defaultPresetId;
}
-
+
public void setEnabled(boolean enabled) {
if (this.enabled != enabled) {
this.enabled = enabled;
fireTableDataChanged();
}
}
-
+
public boolean isEnabled() {
return enabled;
}
class ExportPresetModel implements Comparable<ExportPresetModel> {
private boolean selected;
-
+
private PartsSet partsSet;
-
+
private List<PartsIdentifier> missingPartsIdentifiers;
-
+
public ExportPresetModel(PartsSet partsSet, boolean selected) {
if (partsSet == null) {
throw new IllegalArgumentException();
this.partsSet = partsSet;
this.selected = selected;
}
-
+
@Override
public int hashCode() {
return partsSet.hashCode();
}
-
+
@Override
public boolean equals(Object obj) {
if (obj == this) {
}
return false;
}
-
+
public int compareTo(ExportPresetModel o) {
int ret = (selected ? 0 : 1) - (o.selected ? 0 : 1);
if (ret == 0) {
}
return ret;
}
-
+
public String getPartsSetName() {
String name = partsSet.getLocalizedName();
return name == null ? "" : name;
}
-
+
public boolean isPresetParts() {
return partsSet.isPresetParts();
}
-
+
public boolean isSelected() {
return selected;
}
-
+
public void setSelected(boolean selected) {
this.selected = selected;
}
-
+
public PartsSet getPartsSet() {
return partsSet;
}
-
+
public void setMissingPartsIdentifiers(
List<PartsIdentifier> missingPartsIdentifiers) {
this.missingPartsIdentifiers = Collections.unmodifiableList(missingPartsIdentifiers);
}
-
+
public List<PartsIdentifier> getMissingPartsIdentifiers() {
if (missingPartsIdentifiers == null) {
return Collections.emptyList();
}
return missingPartsIdentifiers;
}
-
+
}
import charactermanaj.graphics.io.PNGFileImageHeader;
import charactermanaj.model.AppConfig;
import charactermanaj.model.CharacterData;
+import charactermanaj.model.CustomLayerOrder;
+import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.PartsAuthorInfo;
import charactermanaj.model.PartsCategory;
import charactermanaj.model.PartsIdentifier;
CharacterDataPersistent persist = CharacterDataPersistent.getInstance();
- CharacterData characterData = cd.duplicateBasicInfo();
+ CharacterData characterData = cd.duplicateBasicInfo(); // インポートしたキャラクターデータ
+ Map<CustomLayerOrderKey, List<CustomLayerOrder>> customLayerPatterns = importModel.getCustomLayerPatternMap();
// キャラクターセット名と作者名を設定する
characterData.setName(importTypeSelectPanel.getCharacterName());
// プロファイルの新規作成
// docBaseが設定されて返される.
- persist.createProfile(characterData);
+ persist.createProfile(characterData, customLayerPatterns);
// インポートするパーツの更新
if (importTypeSelectPanel.isImportPartsImages()) {
CharacterDataPersistent persist = CharacterDataPersistent.getInstance();
- CharacterData characterData = current.duplicateBasicInfo();
+ CharacterData characterData = current.duplicateBasicInfo(); // 現在のもの。(インポートしたものではない)
boolean imported = false;
boolean modCharacterDef = false;
// 画面構成の再構築
initComponent(cd);
+
+ // メニューの状態の更新
+ menuUpdater.run();
}
if (e.isReloadPartsAndFavorites()) {
// 画面コンポーネント作成
initComponent(characterData);
- JMenuBar menuBar = createMenuBar();
- setJMenuBar(menuBar);
+ initMenubar();
// お気に入り変更通知を受け取る
FavoritesChangeObserver.getDefault().addFavoritesChangeListener(
// Mac OS Xの場合はウィンドウにタイトルはつけない。
title = "";
} else {
- title = strings.getProperty("title");
+ title = strings.getProperty("title") + " - ";
}
setTitle(title + characterData.getName());
/**
* メニューバーを構築します.
- *
- * @return メニューバー
*/
- protected JMenuBar createMenuBar() {
+ protected void initMenubar() {
final Properties strings = LocalizedResourcePropertyLoader
.getCachedInstance().getLocalizedProperties(STRINGS_RESOURCE);
}
});
- return menuBar;
+ // メニューバーの設置
+ setJMenuBar(menuBar);
+
+ // メニューの状態を更新するハンドラ
+ menuUpdater = new Runnable() {
+ @Override
+ public void run() {
+ // カスタムレイヤーの有効状態によってメニュー項目の表示制御を行う.
+ mnuCustomLayer.setVisible(characterData.isEnableCustonLayerPattern());
+ }
+ };
+ menuUpdater.run();
}
+ /**
+ * メニューの状態を更新する
+ */
+ private Runnable menuUpdater;
}
*/
private JCheckBox chkWatchDir;
+ /**
+ * カスタムレイヤーの有効・無効
+ */
+ private JCheckBox chkEnableCustomLayer;
+
/**
* カラーグループのモデル
layersPanel.add(layersBtnPanel, BorderLayout.EAST);
chkWatchDir = new JCheckBox(strings.getProperty("layers.watchdir"));
- layersPanel.add(chkWatchDir, BorderLayout.SOUTH);
+ chkEnableCustomLayer = new JCheckBox(strings.getProperty("layers.enableCustomLayer"));
+
+ Box chkboxs = Box.createVerticalBox();
+ chkboxs.add(chkWatchDir);
+ chkboxs.add(chkEnableCustomLayer);
+ layersPanel.add(chkboxs, BorderLayout.SOUTH);
// Presets
JPanel partssetsPanel = new JPanel(new BorderLayout());
// ディレクトリ監視有無
chkWatchDir.setSelected(original.isWatchDirectory());
+ // カスタムレイヤーパターンの有効・無効
+ chkEnableCustomLayer.setSelected(original.isEnableCustonLayerPattern());
// パーツセット
ArrayList<PartsSet> partsSets = new ArrayList<PartsSet>();
// ディレクトリの監視
cd.setWatchDirectory(chkWatchDir.isSelected());
+ // カスタムレイヤーパターンの有効・無効
+ cd.setEnableCustomLayerPattern(chkEnableCustomLayer.isSelected());
// パーツセット情報
int mxPartssets = partssetsTableModel.getRowCount();
throw new IOException("開くことのできないキャラクターデータです。:" + characterData);
}
- // キャラクターデータのロード
+ // キャラクターデータの準備(バージョンアップに伴う補正等)
prepare(characterData);
+
+ // キャラクターデータのロード
loadCharacterData(characterData);
loadFavorites(characterData);
try {
characterData = loadRecent();
if (characterData != null) {
- // ã\82ã\83£ã\83©ã\82¯ã\82¿ã\83¼ã\83\87ã\83¼ã\82¿ã\82\92èªã\81¿è¾¼ã\82\80
+ // ã\82ã\83£ã\83©ã\82¯ã\82¿ã\83¼ã\83\87ã\83¼ã\82¿ã\81®æº\96å\82\99(ã\83\90ã\83¼ã\82¸ã\83§ã\83³ã\82¢ã\83\83ã\83\97ã\81«ä¼´ã\81\86è£\9cæ£ç\89)
prepare(characterData);
+
+ // キャラクターデータを読み込む
loadCharacterData(characterData);
loadFavorites(characterData);
}
logger.info("オープンできるプロファイルがないため、新規プロファイルを作成します。");
try {
CharacterDataDefaultProvider defProv = new CharacterDataDefaultProvider();
- characterData = defProv
- .createDefaultCharacterData(DefaultCharacterDataVersion.V3);
- persistent.createProfile(characterData);
+ characterData = defProv.createDefaultCharacterData(DefaultCharacterDataVersion.V3);
+ Map<CustomLayerOrderKey, List<CustomLayerOrder>> customLayerPatterns =
+ defProv.createDefaultCustomLayerOrderMap(characterData, DefaultCharacterDataVersion.V3);
+ persistent.createProfile(characterData, customLayerPatterns);
} catch (IOException ex) {
// デフォルトのプロファイルが作成できないことは致命的であるが、
}
/**
- * キャラクターデータの準備を行う
+ * キャラクターデータの準備を行う。(バージョンアップに伴う補正等)
* @param characterData
*/
public static void prepare(CharacterData characterData) {
- CustomLayerOrderPersist customLayerOrderPersist = CustomLayerOrderPersist.newInstance(characterData);
- if (!customLayerOrderPersist.exist()) {
- // まだカスタムレイヤーが登録されていない場合(空ファイルの登録は無視する)
- // カスタムレイヤーをまだ使ったことがないキャラクターデータを最初に開いた場合
- String structureSig = characterData.toStructureString();
-
- Map<CustomLayerOrderKey, List<CustomLayerOrder>> map = Collections.emptyMap();
-
- CharacterDataDefaultProvider defProv = new CharacterDataDefaultProvider();
- CharacterData v3 = defProv.createDefaultCharacterData(DefaultCharacterDataVersion.V3);
- if (v3.toStructureString().equals(structureSig)) {
- // デフォルトのキャラクターセット(v3)と同一構造であれば、
- // V3デフォルト用のカスタムレイヤー定義を事前にセットする
- map = defProv.createDefaultCustomLayerOrderMap(characterData, DefaultCharacterDataVersion.V3);
- }
+ if (characterData.isEnableCustonLayerPattern()) {
+ CustomLayerOrderPersist customLayerOrderPersist = CustomLayerOrderPersist.newInstance(characterData);
+ if (!customLayerOrderPersist.exist()) {
+ // まだカスタムレイヤーが登録されていない場合(空ファイルの登録は無視する)
+ // カスタムレイヤーをまだ使ったことがないキャラクターデータを最初に開いた場合
+ String structureSig = characterData.toStructureString();
- try {
- customLayerOrderPersist.save(map);
- } catch (Exception ex) {
- logger.log(Level.WARNING, "failed to save the custom layer mapping.", ex);
+ // 既定は空のパターン
+ Map<CustomLayerOrderKey, List<CustomLayerOrder>> map = Collections.emptyMap();
+
+ CharacterDataDefaultProvider defProv = new CharacterDataDefaultProvider();
+ CharacterData v3 = defProv.createDefaultCharacterData(DefaultCharacterDataVersion.V3);
+ if (v3.toStructureString().equals(structureSig)) {
+ // デフォルトのキャラクターセット(v3)と同一構造であれば、
+ // V3デフォルト用のカスタムレイヤー定義をセットする。
+ map = defProv.createDefaultCustomLayerOrderMap(characterData, DefaultCharacterDataVersion.V3);
+ }
+
+ // カスタムレイヤーパターンをファイルに保存する
+ try {
+ customLayerOrderPersist.save(map);
+ } catch (Exception ex) {
+ logger.log(Level.WARNING, "failed to save the custom layer mapping.", ex);
+ }
}
}
}
import java.io.StringWriter;
import java.net.URI;
import java.text.MessageFormat;
+import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import charactermanaj.model.CharacterDataChangeObserver;
import charactermanaj.model.CustomLayerOrder;
import charactermanaj.model.CustomLayerOrderKey;
+import charactermanaj.model.RecommendationURL;
import charactermanaj.model.io.CharacterDataDefaultProvider;
import charactermanaj.model.io.CharacterDataPersistent;
import charactermanaj.model.io.CustomLayerOrderPersist;
JComboBox comboTemplates = new JComboBox();
comboTemplates.setEditable(false);
- final JLabel lbl = new JLabel();
+ // テンプレート一覧のEntryを表示するので、カスタムレンダラーで描画する
comboTemplates.setRenderer(new ListCellRenderer() {
- public Component getListCellRendererComponent(JList list,
- Object value, int index, boolean isSelected,
- boolean cellHasFocus) {
- @SuppressWarnings("unchecked")
- Map.Entry<String, String> entry = (Map.Entry<String, String>) value;
- if (entry != null) {
- lbl.setText(entry.getValue());
+
+ private JLabel label = new JLabel();
+
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value, int index,
+ boolean isSelected, boolean cellHasFocus) {
+ // 背景色透過制御
+ label.setOpaque(isSelected && index >= 0);
+
+ if (isSelected) {
+ label.setBackground(list.getSelectionBackground());
+ label.setForeground(list.getSelectionForeground());
+ } else {
+ label.setBackground(list.getBackground());
+ label.setForeground(list.getForeground());
}
- return lbl;
+
+ if (value == null) {
+ label.setText("");
+ } else {
+ @SuppressWarnings("unchecked")
+ Map.Entry<String, String> entry = (Map.Entry<String, String>) value;
+
+ label.setFont(list.getFont());
+ label.setText(entry.getValue());
+ }
+ return label;
}
});
comboTemplates.addItem(entry);
}
+ // ブランク用のダミーテンプレートを追加する
+ comboTemplates.addItem(new AbstractMap.SimpleEntry<String, String>("",
+ strings.getProperty("template.blank")));
+
// コンボボックスの幅を広げる.
// (短いとInputBoxのタイトルが隠れるため)
Dimension preferredSize = comboTemplates.getPreferredSize();
return;
}
- // テンプレートを読み込む
+ // 選択したテンプレートを取得
String characterXmlName = selection.getKey();
- cd = defProv.loadPredefinedCharacterData(characterXmlName);
- customLayerOrderMap = defProv.loadPredefinedCustomLayerOrder(cd, characterXmlName);
+ if (characterXmlName != null && characterXmlName.length() > 0) {
+ // テンプレートを読み込む
+ cd = defProv.loadPredefinedCharacterData(characterXmlName);
+ customLayerOrderMap = defProv.loadPredefinedCustomLayerOrder(cd, characterXmlName);
+
+ } else {
+ // プランクを選択している場合は空のキャラクターデータを作成する
+ cd = new CharacterData();
+ // お勧めURLは空にする。(nullの場合は旧形式とみなして取得時にデフォルトのURLが設定されるため)
+ cd.setRecommendationURLList(new ArrayList<RecommendationURL>());
+ customLayerOrderMap = null;
+ }
} catch (Exception ex) {
ErrorMessageHelper.showErrorDialog(this, ex);
// 新規プロファイルを保存する.
try {
- persist.createProfile(newCd);
- persist.saveFavorites(newCd);
-
- // カスタムレイヤーマッピングを保存する
+ // キャラクターデータと、カスタムレイヤーマッピングを保存する
// ※ 設定ダイアログでキャラクターデータ構造を変更している場合には
// 最初にロードしたカスタムレイヤーの定義と合致しないかもしれないが、とりあえず登録しておく。
- if (customLayerOrderMap == null) {
- customLayerOrderMap = Collections.emptyMap();
- }
- CustomLayerOrderPersist.newInstance(newCd).save(customLayerOrderMap);
+ persist.createProfile(newCd, customLayerOrderMap);
+ persist.saveFavorites(newCd);
} catch (Exception ex) {
ErrorMessageHelper.showErrorDialog(this, ex);
defualtName = defualtName.replace(c, '_');
}
+ // カスタムレイヤーパターンのロード(なければnull)
+ CustomLayerOrderPersist customLayerPersist = CustomLayerOrderPersist.newInstance(cd);
+ Map<CustomLayerOrderKey, List<CustomLayerOrder>> customLayerPatterns = customLayerPersist.load();
+
// カスタマイズ用テンプレートファイルの格納場所を取得する.
final CharacterDataDefaultProvider defProv = new CharacterDataDefaultProvider();
- final File templDir = defProv.getTemplateDir(true);
+ final File templDir = defProv.getUserTemplateDir();
+ templDir.mkdirs();
// 指定されたディレクトリ以外に表示・移動できないファイルシステムビューを使用したファイルチューザ
JFileChooser fileChooser = new JFileChooser(
}
};
- // 保存先ファイル名
+ // 保存先ファイル名の入力
fileChooser.setSelectedFile(new File(templDir, defualtName));
int ret = fileChooser.showSaveDialog(this);
if (ret != JFileChooser.APPROVE_OPTION) {
return;
}
- // テンプレート名
+ // テンプレート名の入力
String localizedName = cd.getName();
final Properties strings = LocalizedResourcePropertyLoader
.getCachedInstance().getLocalizedProperties(STRINGS_RESOURCE);
return;
}
+ // テンプレートファイルの作成(上書き保存)
File outFile = fileChooser.getSelectedFile();
- defProv.saveTemplate(outFile.getName(), cd, localizedName);
+ defProv.saveTemplate(outFile.getName(), cd, localizedName, customLayerPatterns);
} catch (Exception ex) {
ErrorMessageHelper.showErrorDialog(this, ex);
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
+import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import charactermanaj.ui.util.FileDropTarget;
import charactermanaj.util.ErrorMessageHelper;
import charactermanaj.util.LocalizedResourcePropertyLoader;
+import charactermanaj.util.UIHelper;
/**
* 起動時にキャラクターデータディレクトリを選択するためのモーダルダイアログ.<br>
- *
+ *
* @author seraphy
*/
public class SelectCharatersDirDialog extends JDialog {
* 最後に使用したキャラクターデータディレクトリと、その履歴情報.
*/
private final RecentCharactersDir recentCharactersDir;
-
+
/**
* 既定のディレクトリ
*/
private File defaultCharactersDir;
-
-
+
+
/**
* 選択されたディレクトリ
*/
private File selectedCharacterDir;
-
+
/**
* 次回起動時に問い合わせない
*/
private boolean doNotAskAgain;
-
-
+
+
/**
* ディレクトリ選択コンボ
*/
private JComboBox combDir;
-
+
/**
* 次回起動時に問い合わせないチェックボックス
*/
private JCheckBox chkDoNotAsk;
-
-
-
+
+
+
public File getDefaultCharactersDir() {
return defaultCharactersDir;
}
public void setDefaultCharactersDir(File defaultCharactersDir) {
this.defaultCharactersDir = defaultCharactersDir;
}
-
+
public File getSelectedCharacterDir() {
return selectedCharacterDir;
}
-
+
public boolean isDoNotAskAgain() {
return doNotAskAgain;
}
-
+
/**
* コンストラクタ
- *
+ *
* @param parent
* 親(通常は、null)
* @param recentCharactersDir
"recentCharactersDirにnullは指定できません。");
}
this.recentCharactersDir = recentCharactersDir;
-
+
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
}
});
initComponent();
-
+
} catch (RuntimeException ex) {
logger.log(Level.SEVERE, "キャラクターディレクトリ選択ダイアログの生成に失敗しました。", ex);
dispose();
throw ex;
}
}
-
+
private void initComponent() {
Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
.getLocalizedProperties("languages/selectCharatersDirDialog");
-
+
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout(3, 3));
-
+
AbstractAction actOk = new AbstractAction(strings.getProperty("btn.ok")) {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
onOK();
}
};
-
+
AbstractAction actClose = new AbstractAction(strings.getProperty("btn.cancel")) {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
}
};
- AbstractAction actRemoveWorkingSets = new AbstractAction(
- strings.getProperty("btn.clearWorkingSets")) {
+ AbstractAction actRemoveWorkingSets = new AbstractAction(strings.getProperty("btn.clearWorkingSets")) {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
onRemoveWorkingSets();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, tk.getMenuShortcutKeyMask()), "close");
rootPane.getActionMap().put("close", actClose);
-
+
btnRemoveWorkingSets.addFocusListener(focusAdapter);
btnRemoveRecent.addFocusListener(focusAdapter);
btnOK.addFocusListener(focusAdapter);
JPanel dirPanel = new JPanel(new BorderLayout(3, 3));
dirPanel.setBorder(BorderFactory.createEmptyBorder(3, 10, 3, 3));
-
+
JLabel lbl = new JLabel(strings.getProperty("caption"), JLabel.CENTER);
lbl.setFont(lbl.getFont().deriveFont(Font.BOLD));
lbl.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
combDir = new JComboBox();
combDir.setEditable(true);
-
+
dirPanel.add(combDir, BorderLayout.CENTER);
-
+
dirPanel.add(new JLabel(strings.getProperty("lbl.dir")), BorderLayout.WEST);
dirPanel.add(btnBroseForDir, BorderLayout.EAST);
-
+
contentPane.add(dirPanel, BorderLayout.NORTH);
-
+
JPanel btnPanel = new JPanel();
GridBagLayout gbl = new GridBagLayout();
btnPanel.setLayout(gbl);
-
+
chkDoNotAsk = new JCheckBox(strings.getProperty("chk.doNotAskAgein"));
chkDoNotAsk.setSelected(recentCharactersDir.isDoNotAskAgain());
-
+
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.ipadx = 0;
gbc.ipady = 0;
gbc.insets = new Insets(3, 3, 3, 3);
-
+
btnPanel.add(chkDoNotAsk, gbc);
gbc.gridx = 0;
gbc.gridheight = 1;
gbc.weightx = 1.;
gbc.weighty = 0.;
-
+
btnPanel.add(Box.createGlue(), gbc);
gbc.gridx = Main.isLinuxOrMacOSX() ? 4 : 3;
gbc.weightx = 0.;
gbc.weighty = 0.;
btnPanel.add(btnCancel, gbc);
-
+
gbc.gridx = 5;
gbc.gridy = 1;
gbc.gridwidth = 1;
gbc.weighty = 0.;
gbc.ipadx = 32;
gbc.ipady = 0;
-
+
btnPanel.add(Box.createGlue(), gbc);
setTitle(strings.getProperty("title"));
setResizable(false);
-
+
contentPane.add(btnPanel, BorderLayout.SOUTH);
// フォルダのドロップによる入力を許可
pack();
setLocationRelativeTo(null);
}
-
+
/**
* ドロップによるファイル名の設定.<br>
* 最初の1つだけを使用する.<br>
* リストが空であるか、最初のファイルが、フォルダでなければ何もしない.<br>
- *
+ *
* @param dropFiles
* ドロップされたファイルリスト
*/
selectedCharacterDir = null;
dispose();
}
-
+
protected void onOK() {
try {
Object value = combDir.getSelectedItem();
if (value != null && value instanceof String) {
value = new File((String) value);
}
-
+
if (value != null && value instanceof File) {
File file = (File) value;
if (!file.exists()) {
ErrorMessageHelper.showErrorDialog(this, ex);
}
}
-
+
protected void onBrowse() {
try {
Object selectedItem = combDir.getSelectedItem();
}
// 全てのワーキングセットをクリアする.
- WorkingSetPersist workingSetPersist = WorkingSetPersist
- .getInstance();
+ WorkingSetPersist workingSetPersist = WorkingSetPersist.getInstance();
workingSetPersist.removeAllWorkingSet();
} catch (Exception ex) {
ErrorMessageHelper.showErrorDialog(this, ex);
}
}
-
+
protected void onRemoveRecent() {
try {
Object current = combDir.getSelectedItem();
ErrorMessageHelper.showErrorDialog(this, ex);
}
}
-
+
protected void setRecents() {
// 現在の候補をクリア.
while (combDir.getItemCount() > 0) {
combDir.setSelectedIndex(0);
}
}
-
+
/**
* キャラクターデータディレクトリを履歴および既定のディレクトリから、任意の使用するディレクトリを選択する.<br>
* 既定のディレクトリは常に選択候補とする.<br>
* 新しいディレクトリを指定した場合は、履歴に追加される.<br>
* 「再度問い合わせなし」を選択している場合で、そのディレクトリが実在すれば、選択ダイアログを表示せず、それを返す.<br>
- *
+ *
* @param defaultCharacterDir
* 既定のディレクトリ
* @return 選択したディレクトリ、キャンセルした場合はnull
recentChars.setDoNotAskAgain(false); // 不正である場合は「再度問い合わせ無し」をリセットする.
}
+ // タスクバーに表示するため、サイズ0の見えないダミーのフレームを作成する
+ // (タスクバーにないとダイアログが他のウィンドウの下にはいったら探すのが大変なため)
+ JFrame dummyFrame = new JFrame();
+ dummyFrame.setUndecorated(true);
+ dummyFrame.setSize(0, 0);
+ dummyFrame.setLocation(GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint()); // 主画面の中央
+ dummyFrame.setIconImage(UIHelper.getInstance().getImage("icons/icon.png")); // アイコンの設定(MainFrameと同じ)
+ dummyFrame.setVisible(true);
+
+ // キャラクターデータディレクトリ選択ダイアログを表示する
File selectedCharacterDir;
- SelectCharatersDirDialog dlg = new SelectCharatersDirDialog(null, recentChars);
+ SelectCharatersDirDialog dlg = new SelectCharatersDirDialog(dummyFrame, recentChars);
dlg.setDefaultCharactersDir(defaultCharacterDir);
dlg.setRecents();
dlg.setVisible(true);
-
+
+ // ダミーのフレームを破棄する
+ dummyFrame.dispose();
+
selectedCharacterDir = dlg.getSelectedCharacterDir();
if (selectedCharacterDir != null) {
recentChars.setLastUseCharacterDir(selectedCharacterDir);
if (file.isFile() && file.canWrite() && name.endsWith(".log")) {
long lastModified = file.lastModified();
if (lastModified > 0 && lastModified < expiredDate) {
- boolean result = file.delete();
+ boolean result = file.delete(); // 直接消す。ユーザ走査ではないのでゴミ箱にはいれない。
logger.log(Level.INFO, "remove file " + file + "/succeeded=" + result);
}
}
package charactermanaj.util;
+import java.awt.BorderLayout;
import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dialog;
import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.HeadlessException;
+import java.awt.Window;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
*/
private static final Logger logger = Logger.getLogger(ErrorMessageHelper.class.getName());
-
+
private ErrorMessageHelper() {
super();
}
// ログに記録する.
logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
-
+
// 例外を表示するパネルの生成
JTextArea textArea = new JTextArea();
-
+
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw); // 例外のコールスタックをパネルに表示できるように出力
pw.close();
textArea.setText(sw.toString());
-
+
textArea.setSelectionStart(0);
textArea.setSelectionEnd(0);
textArea.setEditable(false);
-
+
JScrollPane scr = new JScrollPane(textArea);
scr.setPreferredSize(new Dimension(400, 150));
scr.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scr.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
// ダイアログの表示
- JOptionPane.showMessageDialog(parent, scr, "ERROR", JOptionPane.ERROR_MESSAGE);
+ //JOptionPane.showMessageDialog(parent, scr, "ERROR", JOptionPane.ERROR_MESSAGE);
+
+ // 以下、JOptionPaneの既定の処理を真似つつ、リサイズ可能なダイアログを作成する
+
+ JOptionPane pane = new JOptionPane(scr, JOptionPane.ERROR_MESSAGE);
+
+ Window window = getWindowForComponent(parent);
+ System.out.println("window=" + window);
+
+ final JDialog dialog;
+ String title = "ERROR";
+ if (window instanceof Frame) {
+ dialog = new JDialog((Frame) window, title, true);
+ } else {
+ dialog = new JDialog((Dialog) window, title, true);
+ }
+ Container contentPane = dialog.getContentPane();
+
+ // xボタンでダイアログを破棄する
+ dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+
+ contentPane.setLayout(new BorderLayout());
+ contentPane.add(pane, BorderLayout.CENTER);
+ dialog.setResizable(true);
+
+ dialog.pack();
+ dialog.setLocationRelativeTo(parent);
+
+ pane.addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ if (dialog.isVisible() && event.getNewValue() != null) {
+ // ボタン押下等によりダイアログの結果が確定したらダイアログを破棄する
+ dialog.dispose();
+ }
+ }
+ });
+
+ dialog.setVisible(true);
}
+ static Window getWindowForComponent(Component parentComponent)
+ throws HeadlessException {
+ if (parentComponent == null)
+ return JOptionPane.getRootFrame();
+ if (parentComponent instanceof Frame || parentComponent instanceof Dialog)
+ return (Window) parentComponent;
+ return getWindowForComponent(parentComponent.getParent());
+ }
}
this.file = file;
}
+ @Override
public boolean exists() {
return file.exists() && file.isFile();
}
+ @Override
public long lastModified() {
return file.lastModified();
}
return file.length();
}
+ @Override
public InputStream openStream() throws IOException {
return new BufferedInputStream(new FileInputStream(file));
}
+ @Override
public OutputStream getOutputStream() throws IOException {
return new BufferedOutputStream(new FileOutputStream(file));
}
+ @Override
public boolean delete() {
try {
- return file.delete();
+ if (exists()) {
+ FileUtilities.delete(file);
+ }
+ return true;
} catch (Exception ex) {
// セキュリティ例外ぐらい.
public String toString() {
return "FileUserData{file:" + file + "}";
}
-}
\ No newline at end of file
+}
--- /dev/null
+package charactermanaj.util;
+
+import java.awt.Desktop;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import charactermanaj.model.AppConfig;
+
+public final class FileUtilities {
+
+ private static final Method methodMoveToTrash = getMethodMoveToTrash();
+
+ private FileUtilities() {
+ super();
+ }
+
+ private static Method getMethodMoveToTrash() {
+ try {
+ // MOVE_TO_TRASHアクションを取得する(定義されていないバージョンの場合は実行時例外)
+ Desktop.Action moveToTrashType = Enum.valueOf(Desktop.Action.class, "MOVE_TO_TRASH");
+
+ // MOVE_TO_TRASHアクションがサポートされているか?
+ Desktop desktop = Desktop.getDesktop();
+ if (!desktop.isSupported(moveToTrashType)) {
+ return null;
+ }
+
+ // moveToTrashメソッドを取得する。(定義されていなければ実行時例外)
+ return Desktop.class.getMethod("moveToTrash", File.class);
+
+ } catch (Exception ex) {
+ return null;
+ }
+ }
+
+ /**
+ * ゴミ箱が有効であるか?
+ * @return 有効であればtrue
+ */
+ public static boolean isSupportMoveToTrash() {
+ return methodMoveToTrash != null;
+ }
+
+ /**
+ * ゴミ箱にファイルまたはディレクトリを捨てる。
+ *
+ * @param file
+ * @throws IOException 削除に失敗した場合
+ */
+ public static void moveToTrash(File file) throws IOException {
+ if (file == null) {
+ throw new NullPointerException();
+ }
+
+ if (!isSupportMoveToTrash()) {
+ throw new UnsupportedOperationException("moveToTrash is not supported.");
+ }
+
+ if (!file.exists()) {
+ return;
+ }
+
+ try {
+ Desktop desktop = Desktop.getDesktop();
+ Boolean ret = (Boolean) methodMoveToTrash.invoke(desktop, file);
+ if (ret == null || !ret) {
+ throw new IOException("failed to move to recyclebin. " + file);
+ }
+
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException(ex);
+
+ } catch (InvocationTargetException ex) {
+ Throwable cause = ex.getCause();
+ throw new IOException("failed to move to recyclebin. " + file, cause);
+ }
+ }
+
+ /**
+ * 指定したファイルまたはディレクトリを削除します.<br>
+ * 指定した引数がディレクトリを示す場合、このディレクトリを含む配下のすべてのファイルとディレクトリを削除します.<br>
+ *
+ * @param file
+ * ファイル、またはディレクトリ
+ * @throws IOException
+ * 削除できない場合
+ */
+ public static void deleteRecursive(File file) throws IOException {
+ if (file == null) {
+ throw new IllegalArgumentException();
+ }
+ if (!file.exists()) {
+ return;
+ }
+ if (file.isDirectory()) {
+ File[] children = file.listFiles();
+ if (children != null) {
+ for (File child : children) {
+ deleteRecursive(child);
+ }
+ }
+ }
+ if (!file.delete()) {
+ throw new IOException("can't delete file. " + file);
+ }
+ }
+
+ /**
+ * ファイルまたはフォルダを削除します。
+ * @param file
+ * @throws IOException
+ */
+ public static void delete(File file) throws IOException {
+ AppConfig appConfig = AppConfig.getInstance();
+ if (isSupportMoveToTrash() && appConfig.isUseRecycleBinIfSupported()) {
+ moveToTrash(file);
+ } else {
+ deleteRecursive(file);
+ }
+ }
+}
* 順番に読み込んで重ね合わせる.<br>
* 一度読み込んだものはキャッシュに保存され次回以降は、それが用いられる.<br>
*/
-public class LocalizedResourcePropertyLoader extends ResourceLoader {
-
+public class LocalizedResourcePropertyLoader {
+
/**
* プロパティファイル群と、それに対するキャッシュ
*/
private Map<ResourceNames, Properties> propCache;
-
+
/**
* キャッシュを共有するシングルトンインスタンス.
*/
private static final LocalizedResourcePropertyLoader inst = new LocalizedResourcePropertyLoader(
new HashMap<ResourceNames, Properties>());
-
+
+ /**
+ * キャッシュしないローカライズされた読み込み順序をもつプロパティローダー
+ */
+ protected LocalizedResourcePropertyLoader() {
+ this.propCache = null;
+ }
+
/**
* 独立したキャッシュを指定することのできるコンストラクタ.<br>
- *
+ *
* @param propCache
* キャッシュ、不要であればnull可
*/
- public LocalizedResourcePropertyLoader(
- Map<ResourceNames, Properties> propCache) {
+ protected LocalizedResourcePropertyLoader(Map<ResourceNames, Properties> propCache) {
+ if (propCache == null) {
+ throw new NullPointerException("propCache is required.");
+ }
this.propCache = propCache;
}
-
+
/**
- * インスタンスを取得する
- *
+ * ã\83\97ã\83ã\83\91ã\83\86ã\82£ã\82\92ã\82ã\83£ã\83\83ã\82·ã\83¥ã\81\99ã\82\8bã\82¤ã\83³ã\82¹ã\82¿ã\83³ã\82¹ã\82\92å\8f\96å¾\97ã\81\99ã\82\8b
+ *
* @return インスタンス
*/
public static LocalizedResourcePropertyLoader getCachedInstance() {
return inst;
}
-
+
+ /**
+ * プロパティをキャッシュしないインスタンスを取得する。
+ * @return
+ */
+ public static LocalizedResourcePropertyLoader getNonCachedInstance() {
+ return new LocalizedResourcePropertyLoader();
+ }
+
/**
* リソース名を指定してデフォルトのロケールでローカライズされたリソースプロパティを読み込む.<br>
* リソースはxml形式である。リソース名には.xmlを付与しない.(自動的に内部で付与される.)
- *
+ *
* @param name
* リソース名
* @return プロパティ
public Properties getLocalizedProperties(String name) {
return getLocalizedProperties(name, null);
}
-
+
/**
* リソース名を指定して指定したロケールでローカライズされたリソースプロパティを読み込む.<br>
* リソースはxml形式である。リソース名には.xmlを付与しない.(自動的に内部で付与される.)
- *
+ *
* @param name
* リソース名
* @param locale
* @return プロパティ
*/
public Properties getLocalizedProperties(String name, Locale locale) {
- return getProperties(getResourceNames(name, locale));
+ return getLocalizedProperties(name, locale, false);
+ }
+
+ /**
+ * リソース名を指定して指定したロケールでローカライズされたリソースプロパティを読み込む.<br>
+ * リソースはxml形式である。リソース名には.xmlを付与しない.(自動的に内部で付与される.)
+ *
+ * @param name
+ * リソース名
+ * @param locale
+ * ロケール、nullの場合はデフォルトのロケール
+ * @param preferredNatural
+ * リソースの適用優先度を逆順にして、Naturalを優先させる場合はtrue
+ * @return プロパティ
+ */
+ public Properties getLocalizedProperties(String name, Locale locale, boolean preferredNatural) {
+ ResourceNames resNames = getResourceNames(name, locale);
+ if (preferredNatural) {
+ resNames = resNames.reverse();
+ }
+ return getProperties(resNames);
}
/**
* リソースはxml形式である。リソース名には.xmlを付与しない.(自動的に内部で付与される.)<br>
* 返される順序は、読み込み順となる。(順番に読み込んで上書きしてゆくことを想定する).<br>
* ロケール中立のものが先頭となり、指定したロケールにもっとも一致するものが最後となる.<br>
- *
+ *
* @param name
* リソース名
* @param locale
* ロケール、nullの場合はデフォルトのロケール
* @return プロパティリソースの一覧(読み込み順)
*/
- public static ResourceNames getResourceNames(String name, Locale locale) {
+ protected static ResourceNames getResourceNames(String name, Locale locale) {
if (name == null || name.length() == 0) {
throw new IllegalArgumentException();
}
String language = locale.getLanguage();
String country = locale.getCountry();
String variant = locale.getVariant();
-
+
String[] resourceNames = {
name + ".xml",
name + "_" + language + ".xml",
* キャッシュされていない場合はプロパティをロードして、それをキャッシュに格納する.<br>
* (共有キャッシュ時、もしくは独自のキャッシュが指定されている場合).<br>
* リソースが一つも存在しない場合は実行時例外を発生させる.<br>
- *
+ *
* @param resourceNames
* リソース名群
* @return プロパティ
/**
* リソース名群からリソースプロパティをロードして返す.<br>
+ * リソースはクラスパス上のリソースを探索した結果に、ローカルディレクトリ上の探索結果を上書きしたものが返される。
* 一つも存在しない場合はnullを返す.<br>
- *
+ *
* @param resourceNames
* リソース群名
* @return プロパティ
// バージョンアップによりキーが増えて、既存のローカルファイル上のプロパティファイルにキーが存在しない場合でも
// 安全なようにするためのもの。
ClassLoader[] loaders = new ClassLoader[] {
- getDefaultClassLoader(),
- getLocalizedClassLoader(null),
+ ResourceLoader.getDefaultClassLoader(), // クラスパス上のクラスローダー
+ ResourceLoader.getUsersResourceDirClassLoader(null, true), // ローカル用クラスローダ(親指定なし)
};
-
+
boolean foundResource = false;
Properties props = new Properties();
for (ClassLoader loader : loaders) {
throw new RuntimeException("resource loading error." + resource, ex);
}
foundResource = true;
-
+
props.putAll(org);
}
}
}
-
+
if (foundResource) {
return props;
}
/**
* リソースからローカライズされたテキストを取得する.<br>
- *
+ *
* @author seraphy
- *
+ *
*/
-public class LocalizedResourceTextLoader extends ResourceLoader {
+@Deprecated
+public class LocalizedResourceTextLoader {
private static final LocalizedResourceTextLoader inst = new LocalizedResourceTextLoader();
-
+
+ private final ResourceLoader resourceLoader = new ResourceLoader();
+
private LocalizedTextResource textResource = new LocalizedTextResource() {
@Override
protected URL getResource(String resourceName) {
- return LocalizedResourceTextLoader.this.getResource(resourceName);
+ return resourceLoader.getResource(resourceName);
}
};
private LocalizedResourceTextLoader() {
super();
}
-
+
public static LocalizedResourceTextLoader getInstance() {
return inst;
}
-
+
/**
* リソース名を指定して、テキストファイルを読み込んで、その文字列を返す.<br>
* リソースは現在のデフォルトロケールを優先で検索されます.<br>
* ファイルエンコーディングを引数csで指定する.<br>
- *
+ *
* @param name
* リソース名
* @param cs
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
-
/**
- * リソースをロードするための抽象基底クラス.
- *
+ * リソースをロードするためのクラス.
+ *
* @author seraphy
*/
public class ResourceLoader {
+ private final ClassLoader classLoader;
+
+ /**
+ * ローカル優先でリソースを探索するリソースローダーを構築します。
+ */
+ public ResourceLoader() {
+ this(true);
+ }
+
+ /**
+ * ローカル優先か、クラス優先のいずれかを指定してリソースローダーを構築します。
+ * @param preferredLocal
+ */
+ public ResourceLoader(boolean preferredLocal) {
+ this(getUsersResourceDirClassLoader(getDefaultClassLoader(), preferredLocal));
+ }
+
+ /**
+ * クラスローダーを指定してリソースローダーを構築します。
+ * @param classLoader
+ */
+ public ResourceLoader(ClassLoader classLoader) {
+ if (classLoader == null) {
+ throw new IllegalArgumentException("classLoader is required.");
+ }
+ this.classLoader = classLoader;
+ }
+
/**
* クラスローダを取得する.<br>
* まずローカルファイル上のリソースディレクトリがあれば、それを検索する.<br>
* つぎにスレッドに関連づけられているコンテキストクラスローダか、もしなければ、このクラスをロードしたクラスローダを用いて検索する.<br>
- *
+ *
* @return クラスローダ
*/
public ClassLoader getClassLoader() {
- return getLocalizedClassLoader(getDefaultClassLoader());
+ return classLoader;
}
-
+
+ /**
+ * クラスローダによりリソースをロードする.<br>
+ * 該当するリソースが存在しない場合はnullを返す.<br>
+ * リソース名がnullの場合もnullを返す.<br>
+ *
+ * @param name
+ * リソース名またはnull
+ * @return リソースがあれば、そのURL。なければnull
+ */
+ public URL getResource(String name) {
+ if (name == null) {
+ return null;
+ }
+ return getClassLoader().getResource(name);
+ }
+
/**
* クラスローダを取得する.<br>
* スレッドに関連づけられているコンテキストクラスローダか、もしなければ、このクラスをロードしたクラスローダを返す.<br>
- *
+ *
* @return クラスローダ
*/
- public ClassLoader getDefaultClassLoader() {
+ public static ClassLoader getDefaultClassLoader() {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
}
});
}
-
+
/**
- * ローカルファイル上のリソースディレクトリにアクセスするクラスローダ取得する.<br>
+ * ã\83¦ã\83¼ã\82¶ã\83¼ç\94¨ã\81®ã\83ã\83¼ã\82«ã\83«ã\83\95ã\82¡ã\82¤ã\83«ä¸\8aã\81®ã\83ªã\82½ã\83¼ã\82¹ã\83\87ã\82£ã\83¬ã\82¯ã\83\88ã\83ªã\81«ã\82¢ã\82¯ã\82»ã\82¹ã\81\99ã\82\8bã\82¯ã\83©ã\82¹ã\83ã\83¼ã\83\80å\8f\96å¾\97ã\81\99ã\82\8b.<br>
* 作成されていなければparentをそのまま返す.<br>
- * リソースはローカルファイル上のパスで検索されたのちにparentで検索されます.(標準のURLClassLoaderとは違う探索方法)<br>
- *
+ * ローカル優先の場合、リソースはローカルファイル上のパスで検索されたのちにparentで検索されます.(標準のURLClassLoaderとは違う探索方法)<br>
+ * ローカル優先ではない場合は通常どおり、親クラスローダを優先して検索されます.<br>
+ *
* @param parent
* 親クラスローダ、nullの場合は親の探索をしない.
+ * @param preferredLocal
+ * ローカル優先か?
* @return ローカルシステム上のリソースディレクトリにアクセスするクラスローダ、なければparentのまま
*/
- public ClassLoader getLocalizedClassLoader(final ClassLoader parent) {
+ public static ClassLoader getUsersResourceDirClassLoader(final ClassLoader parent, final boolean preferredLocal) {
try {
File baseDir = ConfigurationDirUtilities.getUserDataDir();
SetupLocalization localize = new SetupLocalization(baseDir);
URLClassLoader cl = AccessController.doPrivileged(new PrivilegedExceptionAction<URLClassLoader>() {
public URLClassLoader run() throws MalformedURLException {
URL[] urls = new URL[] { resourceDir.toURI().toURL() };
- return new URLClassLoader(urls, parent) {
- @Override
- public URL getResource(String name) {
- URL url = findResource(name); // 子が優先 (標準と逆)
- if (url == null) {
- ClassLoader parent = getParent();
- if (parent != null) {
- url = parent.getResource(name);
+ if (preferredLocal) {
+ // リソースの探索順序をローカル優先にするURLクラスローダ
+ return new URLClassLoader(urls, parent) {
+ @Override
+ public URL getResource(String name) {
+ URL url = findResource(name); // 子が優先 (標準と逆)
+ if (url == null) {
+ ClassLoader parent = getParent();
+ if (parent != null) {
+ url = parent.getResource(name);
+ }
}
+ return url;
}
- return url;
- }
- };
+ };
+ } else {
+ // リソースの探索順序を親優先(標準)にするURLクラスローダー
+ return new URLClassLoader(urls, parent);
+ }
}
});
return cl;
return null;
}
}
-
- /**
- * クラスローダによりリソースをロードする.<br>
- * 該当するリソースが存在しない場合はnullを返す.<br>
- * リソース名がnullの場合もnullを返す.<br>
- *
- * @param name
- * リソース名またはnull
- * @return リソースがあれば、そのURL。なければnull
- */
- public URL getResource(String name) {
- if (name == null) {
- return null;
- }
- return getClassLoader().getResource(name);
- }
}
/**
* 関連もしくは類似するリソースをまとめて取り扱うためにグループ化するためのクラス.<br>
- *
+ *
* @author seraphy
*/
public class ResourceNames extends AbstractList<String> {
-
+
private final String[] resourceNames;
-
+
public ResourceNames(String[] resourceNames) {
if (resourceNames == null) {
throw new IllegalArgumentException();
}
this.resourceNames = resourceNames;
}
-
+
/**
* 順次を逆転させた新しいインスタンスを返す
- *
+ *
* @return 順序を逆転させたインスタンス
*/
public ResourceNames reverse() {
public int hashCode() {
return Arrays.hashCode(resourceNames);
}
-
+
@Override
public boolean equals(Object obj) {
if (obj == this) {
}
return false;
}
-
+
@Override
public int size() {
return resourceNames.length;
}
-
+
@Override
public String get(int index) {
return resourceNames[index];
package charactermanaj.util;
import java.io.File;
+import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 言語リソースを管理する.
- *
+ *
* @author seraphy
*/
-public class SetupLocalization extends ResourceLoader {
-
+public class SetupLocalization {
+
private final Logger logger = Logger.getLogger(getClass().getName());
-
+
public static final String DIRNAME_RESOURCES = "resources";
/**
}
private File baseDir;
-
+
/**
* アプリケーションデータ用ディレクトリを指定して構築する.
- *
+ *
* @param baseDir
* データディレクトリ
*/
}
this.baseDir = baseDir;
}
-
+
/**
* コピー対象とするリソース一覧を取得する.<br>
- *
+ *
* @param resourceSet
* リソースディレクトリのサブディレクトリ名のリスト
* @return リソース一覧(言語関連リソース、テンプレートなど)
logger.log(Level.FINE, "resource list: " +resources);
return resources;
}
-
+
/**
* リソースをファイルにコピーする.<br>
- *
+ *
* @param fromURL
* @param toFile
* @throws IOException
is.close();
}
}
-
+
/**
* リソースディレクトリを返す.
- *
+ *
* @return リソースディレクトリ
*/
public File getResourceDir() {
throw new RuntimeException(ex);
}
}
-
+
/**
* ローカルシステム上のアプリケーションデータディレクトリに言語リソースをコピーする.
- *
+ *
* @param resourceSet
* コピーするリソースセット.
* @param overwrite
* 上書きを許可する場合はtrue、スキップする場合はfalse
+ * @param filter
+ * ファイルの出力先パスを得てコピーの有無を判断するフィルタ、nullの場合はすべて許可する
* @throws IOException
* 失敗
*/
- public void setupToLocal(EnumSet<Resources> resourceSet, boolean overwrite)
+ public void setupToLocal(EnumSet<Resources> resourceSet, boolean overwrite, FileFilter filter)
throws IOException {
File toDir = getResourceDir();
- ClassLoader cl = getDefaultClassLoader();
+ ClassLoader cl = ResourceLoader.getDefaultClassLoader();
for (String resourceName : getResourceList(resourceSet)) {
URL url = cl.getResource(resourceName);
if (url != null) {
File toFile = new File(toDir, resourceName).getCanonicalFile();
if (overwrite || !toFile.exists()) {
- // 上書き許可か、まだファイルが存在しなければコピーする.
- copyResource(url, toFile);
+ // 上書き許可か、まだファイルが存在しなければ
+ if (filter == null || filter.accept(toFile)) {
+ // フィルタが指定されていないか、フィルタによって許可された場合はコピーする
+ copyResource(url, toFile);
+ }
}
} else {
}
}
}
+
+ /**
+ * ローカルシステム上のアプリケーションデータディレクトリに言語リソースをコピーする.
+ *
+ * @param resourceSet
+ * コピーするリソースセット.
+ * @param overwrite
+ * 上書きを許可する場合はtrue、スキップする場合はfalse
+ * @throws IOException
+ * 失敗
+ */
+ public void setupToLocal(EnumSet<Resources> resourceSet, boolean overwrite) throws IOException {
+ setupToLocal(resourceSet, overwrite, null);
+ }
}
import javax.swing.JMenu;
-public final class UIHelper extends ResourceLoader {
+public final class UIHelper {
private static final UIHelper singleton = new UIHelper();
-
+
+ /**
+ * クラスパスからのみ探索するリソースローダー
+ */
+ private final ResourceLoader resourceLoader = new ResourceLoader(ResourceLoader.getDefaultClassLoader());
+
private UIHelper() {
super();
}
-
+
public static final UIHelper getInstance() {
return singleton;
}
-
+
/**
* 指定したコンテナに含まれる指定したコンポーネント型のすべてのコンポーネントを返す.<br>
* 一つも該当するものがなければ空を返す
getDescendantOfClass(clz, container, components);
return (Collection<T>) components;
}
-
+
private void getDescendantOfClass(Class<?> clz, Container container, Collection<Component> results) {
if (container == null) {
return;
}
}
}
-
+
/**
* 2つのステートをもつアイコンを作成します.<br>
* このアイコンは、使用するコンポーネントがAbstractButton派生クラスであれば、isSelectedの結果が
}
final BufferedImage pinIcon1 = getImage(iconName1);
final BufferedImage pinIcon2 = getImage(iconName2);
-
+
Icon icon = new Icon() {
public void paintIcon(Component c, Graphics g, int x, int y) {
boolean selected = false;
return pinIcon1.getWidth();
}
};
-
+
return icon;
}
}
JButton btn = new JButton();
btn.setIcon(new ImageIcon(getImage(iconName)));
-
+
return btn;
}
-
+
/**
* 通常時の画像のみをもつ透過ボタンを作成して返す.<br>
* リソースが取得できない場合は実行時例外が返される.<br>
return btn;
}
-
+
/**
* リソースから画像を取得する.<br>
* 画像が取得できない場合は実行時例外を返す.<br>
* @return 画像
*/
public BufferedImage getImage(String name) {
- URL url = getResource(name);
+ URL url = resourceLoader.getResource(name);
if (url == null) {
throw new RuntimeException("resource not found. " + name);
}
throw new RuntimeException("image load error." + ex.getMessage(), ex);
}
}
-
+
}
<entry key="noRemoveLog">34;No Remove Log</entry>
<entry key="purgeLogDays">35;a number in days until purge log</entry>
<entry key="informationDialogOpenMethod">36;Information Dialog Open Mode</entry>
+<entry key="useRecycleBinIfSupported">37;Use the recycle bin if it is supported.</entry>
<entry key="selectedItemBgColor">50;Selected Item's Background Color</entry>
<entry key="exportPresetWarningsForegroundColor">51;Export Preset's Warnings Foreground Color</entry>
<entry key="noRemoveLog">34;正常時でもログを終了時に消去しない.</entry>
<entry key="purgeLogDays">35;起動時に古いログを消去するまでの日数。(0の場合は削除しない)</entry>
<entry key="informationDialogOpenMethod">36;情報ダイアログのアクションを「開く」にする。(false時は「編集」)</entry>
+<entry key="useRecycleBinIfSupported">37;ファイルの削除にゴミ箱を使う。(サポートされている場合)</entry>
<entry key="selectedItemBgColor">50;アイテム選択行(フォーカス行)の背景色</entry>
<entry key="exportPresetWarningsForegroundColor">51;パーツセットのエクスポート時の警告色</entry>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>appConfig.xml</comment>
-<!-- だれか翻訳助けて Could someone please translate this.-->
<entry key="title">程序设置</entry>
<entry key="btn.apply">应用</entry>
<entry key="error.caption">错误</entry>
<entry key="error.message">请填充未填项</entry>
<entry key="caution">应用新设置需要重新启动程序</entry>
-<entry key="table.caption">设置/entry>
+<entry key="table.caption">设置</entry>
<entry key="btn.setupLocalization">自定义语言</entry>
<entry key="setupLocalization"><![CDATA[解压语言文件
<entry key="noRemoveLog">34;退出时不清除log</entry>
<entry key="purgeLogDays">35;启动时清除多少天以上的log(0表示不清除)</entry>
<entry key="informationDialogOpenMethod">36;信息栏动作(true为打开;false为编辑)</entry>
+<entry key="useRecycleBinIfSupported">37;使用回收站(如果支持)</entry>
<entry key="selectedItemBgColor">50;选择时的背景色</entry>
<entry key="exportPresetWarningsForegroundColor">51;警告时的背景色</entry>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties version="1.0">
- <entry key="title">CharacterManaJ - </entry>
+ <entry key="title">CharacterManaJ</entry>
<entry key="defaultPartsSetTitle">no name</entry>
<entry key="help.url">http://charactermanaj.sourceforge.jp/help/0.9/</entry>
<entry key="help.show">Help Document is here.</entry>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties version="1.0">
- <entry key="title">キャラクターなんとかJ - </entry>
+ <entry key="title">キャラクターなんとかJ</entry>
<entry key="defaultPartsSetTitle">無題</entry>
<entry key="help.url">http://charactermanaj.sourceforge.jp/help/0.9/</entry>
<entry key="help.show">ヘルプドキュメントは以下のURLにあります。</entry>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties version="1.0">
- <entry key="title">CharacterManaJ - </entry>
+ <entry key="title">CharacterManaJ</entry>
<entry key="defaultPartsSetTitle">无标题</entry>
<entry key="help.url">http://charactermanaj.sourceforge.jp/help/0.9/</entry>
<entry key="help.show">帮助文档(日)</entry>
<entry key="layers.moveup.caption">Up</entry>
<entry key="layers.movedown.caption">Down</entry>
<entry key="layers.watchdir">Watch directories</entry>
+ <entry key="layers.enableCustomLayer">Enable the Custom layer pattern</entry>
<entry key="panel.basicinfomation">Basic</entry>
<entry key="panel.colorgroup">Color Group</entry>
<entry key="panel.categories">Categories</entry>
<entry key="layers.moveup.caption">上へ</entry>
<entry key="layers.movedown.caption">下へ</entry>
<entry key="layers.watchdir">フォルダを監視し、パーツ画像の変更を検知できるようにする。</entry>
+ <entry key="layers.enableCustomLayer">カスタムレイヤーを有効にする</entry>
<entry key="panel.basicinfomation">基本</entry>
<entry key="panel.colorgroup">カラーグループ</entry>
<entry key="panel.categories">カテゴリ</entry>
<entry key="layers.moveup.caption">向上</entry>
<entry key="layers.movedown.caption">向下</entry>
<entry key="layers.watchdir">显示目录</entry>
+ <entry key="layers.enableCustomLayer">启用自定义图层模式</entry>
<entry key="panel.basicinfomation">基本设置</entry>
<entry key="panel.colorgroup">颜色组</entry>
<entry key="panel.categories">分类</entry>
<entry key="profile.column.location.width">300</entry>
<entry key="inputTemplateName">Template Name</entry>
+ <entry key="template.blank">Blank</entry>
<entry key="confirm">Confirm</entry>
<entry key="confirmOverwrite"><![CDATA[file already exists.
Do you want to replace it?]]></entry>
<entry key="confirmUpdateProfile">プロファイルの選択</entry>
<entry key="importToUpdateProfile">選択されたプロファイルへのインポートを行う。</entry>
<entry key="importToCreateProfile">新規にプロファイルを作成してインポートを行う。</entry>
-
+
<entry key="profile.column.name">名前</entry>
<entry key="profile.column.id">ID</entry>
<entry key="profile.column.revision">リビジョン</entry>
<entry key="profile.column.location.width">300</entry>
<entry key="inputTemplateName">テンプレートの名前</entry>
+ <entry key="template.blank">空</entry>
<entry key="confirm">確認</entry>
<entry key="confirmOverwrite"><![CDATA[ファイルは既に存在します。
上書きしてもよろしいですか?]]></entry>
<entry key="profile.column.location.width">300</entry>
<entry key="inputTemplateName">缓存名称</entry>
+ <entry key="template.blank">空白</entry>
<entry key="confirm">确认</entry>
<entry key="confirmOverwrite"><![CDATA[文件已存在
是否覆盖?]]></entry>