OSDN Git Service

・ ver0.996リリース ver0.996
authorseraphy <seraphy@seraphyware.com>
Sun, 22 Jun 2014 17:17:22 +0000 (02:17 +0900)
committerseraphy <seraphy@seraphyware.com>
Sun, 22 Jun 2014 17:17:22 +0000 (02:17 +0900)
・ パーツのランダム選択ダイアログを作成した。
・ フォントサイズの変更に対応した。(ただし、Mac/Winのみ)
・ distの配布フォルダで、Mac/WinともにJREの同梱を可能にした。
(ただし、gitリポジトリには、JRE自身はコピーせず、ビルド時に設定すること。)

23 files changed:
dist/.gitignore [new file with mode: 0644]
dist/CharacterManaJ.app/Contents/Resources/Java/CharacterManaJ.jar
dist/CharacterManaJ.jar
dist/charactermanaj.exe
dist/java7mac/CharacterManaJ.app/Contents/Info.plist
dist/java7mac/CharacterManaJ.app/Contents/Java/CharacterManaJ.jar
dist/java7mac/CharacterManaJ.app/Contents/PlugIns/.gitignore [new file with mode: 0644]
dist/java7mac/CharacterManaJ.app/Contents/Resources/en.lproj/InfoPlist.strings [new file with mode: 0755]
extlib/build_for_java7mac.sh [new file with mode: 0755]
extlib/build_for_java7mac.xml
launch4j.xml
resources/languages/appconfigdialog.xml
resources/languages/appconfigdialog_ja.xml
resources/languages/partsrandomchooserdialog.xml [new file with mode: 0644]
resources/languages/partsrandomchooserdialog_ja.xml [new file with mode: 0644]
resources/menu/menu.xml
resources/menu/menu_ja.xml
resources/version.properties
src/charactermanaj/Main.java
src/charactermanaj/model/AppConfig.java
src/charactermanaj/ui/MainFrame.java
src/charactermanaj/ui/PartsRandomChooserDialog.java [new file with mode: 0644]
src/charactermanaj/util/JavaVersionUtils.java [new file with mode: 0644]

diff --git a/dist/.gitignore b/dist/.gitignore
new file mode 100644 (file)
index 0000000..ae49c27
--- /dev/null
@@ -0,0 +1 @@
+/jre\r
index 8d3d882..aac4512 100755 (executable)
Binary files a/dist/CharacterManaJ.app/Contents/Resources/Java/CharacterManaJ.jar and b/dist/CharacterManaJ.app/Contents/Resources/Java/CharacterManaJ.jar differ
index 8d3d882..aac4512 100755 (executable)
Binary files a/dist/CharacterManaJ.jar and b/dist/CharacterManaJ.jar differ
index ea394a4..90a75d5 100644 (file)
Binary files a/dist/charactermanaj.exe and b/dist/charactermanaj.exe differ
index 9098c67..b2b5b13 100644 (file)
@@ -1,47 +1,49 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>LSEnvironment</key>
-       <dict>
-               <key>LC_CTYPE</key>
-               <string>UTF-8</string>
-       </dict>
-       <key>LSApplicationCategoryType</key>
-       <string>public.app-category.graphics-design</string>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>ja_JP</string>
-       <key>CFBundleExecutable</key>
-       <string>JavaAppLauncher</string>
-       <key>CFBundleIconFile</key>
-       <string>icon.icns</string>
-       <key>CFBundleIdentifier</key>
-       <string>charactermanaj.CharacterManaJ</string>
-       <key>CFBundleDisplayName</key>
-       <string>CharacterManaJ</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>CharacterManaJ</string>
-       <key>CFBundlePackageType</key>
-       <string>APPL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-       <key>NSHumanReadableCopyright</key>
-       <string>seraphyware</string>
-       <key>JVMMainClassName</key>
-       <string>charactermanaj.CharacterManaJ</string>
-       <key>JVMOptions</key>
-       <array>
-               <string>-splash:$APP_ROOT/Contents/Resources/splash.png</string>
-               <string>-Xms96m</string>
-               <string>-Xmx128m</string>
-       </array>
-       <key>JVMArguments</key>
-       <array/>
-</dict>
-</plist>
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\r
+<plist version="1.0">\r
+<dict>\r
+       <key>LSEnvironment</key>\r
+       <dict>\r
+               <key>LC_CTYPE</key>\r
+               <string>UTF-8</string>\r
+       </dict>\r
+       <key>LSApplicationCategoryType</key>\r
+       <string>public.app-category.graphics-design</string>\r
+       <key>CFBundleDevelopmentRegion</key>\r
+       <string>ja_JP</string>\r
+       <key>CFBundleExecutable</key>\r
+       <string>JavaAppLauncher</string>\r
+       <key>CFBundleIconFile</key>\r
+       <string>icon.icns</string>\r
+       <key>CFBundleIdentifier</key>\r
+       <string>charactermanaj.CharacterManaJ</string>\r
+       <key>CFBundleDisplayName</key>\r
+       <string>CharacterManaJ</string>\r
+       <key>CFBundleInfoDictionaryVersion</key>\r
+       <string>6.0</string>\r
+       <key>CFBundleName</key>\r
+       <string>CharacterManaJ</string>\r
+       <key>CFBundlePackageType</key>\r
+       <string>APPL</string>\r
+       <key>CFBundleShortVersionString</key>\r
+       <string>1.0</string>\r
+       <key>CFBundleSignature</key>\r
+       <string>????</string>\r
+       <key>CFBundleVersion</key>\r
+       <string>1</string>\r
+       <key>NSHumanReadableCopyright</key>\r
+       <string>seraphyware</string>\r
+       <key>JVMMainClassName</key>\r
+       <string>charactermanaj.CharacterManaJ</string>\r
+       <key>JVMRuntime</key>\r
+       <string>jdk1.7.0_60.jdk</string>\r
+       <key>JVMOptions</key>\r
+       <array>\r
+               <string>-splash:$APP_ROOT/Contents/Resources/splash.png</string>\r
+               <string>-Xms96m</string>\r
+               <string>-Xmx128m</string>\r
+       </array>\r
+       <key>JVMArguments</key>\r
+       <array/>\r
+</dict>\r
+</plist>\r
index 8d3d882..aac4512 100755 (executable)
Binary files a/dist/java7mac/CharacterManaJ.app/Contents/Java/CharacterManaJ.jar and b/dist/java7mac/CharacterManaJ.app/Contents/Java/CharacterManaJ.jar differ
diff --git a/dist/java7mac/CharacterManaJ.app/Contents/PlugIns/.gitignore b/dist/java7mac/CharacterManaJ.app/Contents/PlugIns/.gitignore
new file mode 100644 (file)
index 0000000..af52f14
--- /dev/null
@@ -0,0 +1 @@
+/jdk1.7.0_60.jdk\r
diff --git a/dist/java7mac/CharacterManaJ.app/Contents/Resources/en.lproj/InfoPlist.strings b/dist/java7mac/CharacterManaJ.app/Contents/Resources/en.lproj/InfoPlist.strings
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/extlib/build_for_java7mac.sh b/extlib/build_for_java7mac.sh
new file mode 100755 (executable)
index 0000000..8a88ebc
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash\r
+export JAVA_HOME=$(/usr/libexec/java_home -v 1.7)\r
+echo "JAVA_HOME=${JAVA_HOME}"\r
+\r
+mkdir ../dist/java7mac\r
+\r
+ant -f build_for_java7mac.xml\r
index 53bc7d9..2e37ea5 100644 (file)
@@ -1,26 +1,31 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="CharacterManaJ_Java7Mac" default="app-bundle">
-    <description>CharacterManaJ(For Java7 On OSX)</description>
-
-       <taskdef name="bundleapp"
-                    classname="com.oracle.appbundler.AppBundlerTask"   
-                    classpath="appbundler-1.0.jar" />
-
-       <!--
-        Java7 for OSX用のアプリケーションバンドルを作成するためのタスクを実行する.
-        http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/packagingAppsForMac.html
-        ただし、これを実施したあとにinfo.plistの修正やリソースの追加が必要である。
-       -->
-    <target name="app-bundle">
-        <bundleapp outputdirectory="../java7mac"
-            name="CharacterManaJ"
-            displayname="キャラクターなんとかJ"
-               shortversion="1.0"
-               icon="icon.icns"
-            identifier="charactermanaj.Main"
-            mainclassname="charactermanaj.Main">
-            <classpath file="../CharacterManaJ.jar" />
-        </bundleapp>
-    </target>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>\r
+<project name="CharacterManaJ_Java7Mac" default="app-bundle">\r
+    <description>CharacterManaJ(For Java7 On OSX)</description>\r
+\r
+       <!-- Import environment variables -->\r
+       <property environment="env"/>\r
+\r
+       <taskdef name="bundleapp"\r
+                    classname="com.oracle.appbundler.AppBundlerTask"   \r
+                    classpath="appbundler-1.0.jar" />\r
+\r
+       <!--\r
+        Java7 for OSX用のアプリケーションバンドルを作成するためのタスクを実行する.\r
+        http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/packagingAppsForMac.html\r
+        ただし、これを実施したあとにinfo.plistの修正やリソースの追加が必要である。\r
+       -->\r
+<target name="app-bundle">\r
+       <echo message="JAVA_HOME=${env.JAVA_HOME}"/>\r
+       <bundleapp outputdirectory="../dist/java7mac"\r
+               name="CharacterManaJ"\r
+               displayname="キャラクターなんとかJ"\r
+               shortversion="1.0"\r
+               icon="../icon.icns"\r
+               identifier="charactermanaj.Main"\r
+               mainclassname="charactermanaj.Main">\r
+               <runtime dir="${env.JAVA_HOME}"/>\r
+               <classpath file="../CharacterManaJ.jar" />\r
+       </bundleapp>\r
+</target>\r
+\r
+</project>\r
index d99e8d8..481d27f 100644 (file)
@@ -1,36 +1,36 @@
-<launch4jConfig>
-  <dontWrapJar>false</dontWrapJar>
-  <headerType>gui</headerType>
-  <jar>dist\CharacterManaJ.jar</jar>
-  <outfile>dist\charactermanaj.exe</outfile>
-  <errTitle></errTitle>
-  <cmdLine></cmdLine>
-  <chdir></chdir>
-  <priority>normal</priority>
-  <downloadUrl>http://java.com/download</downloadUrl>
-  <supportUrl></supportUrl>
-  <customProcName>false</customProcName>
-  <stayAlive>false</stayAlive>
-  <manifest></manifest>
-  <icon>icon.ico</icon>
-  <jre>
-    <path></path>
-    <minVersion>1.5.0</minVersion>
-    <maxVersion></maxVersion>
-    <jdkPreference>preferJre</jdkPreference>
-    <initialHeapSize>64</initialHeapSize>
-    <maxHeapSize>128</maxHeapSize>
-  </jre>
-  <versionInfo>
-    <fileVersion>0.9.9.5</fileVersion>
-    <txtFileVersion>0.995</txtFileVersion>
-    <fileDescription>CharacterManaJ</fileDescription>
-    <copyright>http://sourceforge.jp/projects/charactermanaj/</copyright>
-    <productVersion>0.9.9.5</productVersion>
-    <txtProductVersion>0.995</txtProductVersion>
-    <productName>CharacterManaJ</productName>
-    <companyName>seraphy@users.sourceforge.jp</companyName>
-    <internalName>CharacterManaJ</internalName>
-    <originalFilename>charactermanaj.exe</originalFilename>
-  </versionInfo>
+<launch4jConfig>\r
+  <dontWrapJar>false</dontWrapJar>\r
+  <headerType>gui</headerType>\r
+  <jar>dist\CharacterManaJ.jar</jar>\r
+  <outfile>dist\charactermanaj.exe</outfile>\r
+  <errTitle></errTitle>\r
+  <cmdLine></cmdLine>\r
+  <chdir></chdir>\r
+  <priority>normal</priority>\r
+  <downloadUrl>http://java.com/download</downloadUrl>\r
+  <supportUrl></supportUrl>\r
+  <customProcName>false</customProcName>\r
+  <stayAlive>false</stayAlive>\r
+  <manifest></manifest>\r
+  <icon>icon.ico</icon>\r
+  <jre>\r
+    <path>jre</path>\r
+    <minVersion>1.5.0</minVersion>\r
+    <maxVersion></maxVersion>\r
+    <jdkPreference>preferJre</jdkPreference>\r
+    <initialHeapSize>64</initialHeapSize>\r
+    <maxHeapSize>128</maxHeapSize>\r
+  </jre>\r
+  <versionInfo>\r
+    <fileVersion>0.9.9.5</fileVersion>\r
+    <txtFileVersion>0.995</txtFileVersion>\r
+    <fileDescription>CharacterManaJ</fileDescription>\r
+    <copyright>http://sourceforge.jp/projects/charactermanaj/</copyright>\r
+    <productVersion>0.9.9.5</productVersion>\r
+    <txtProductVersion>0.995</txtProductVersion>\r
+    <productName>CharacterManaJ</productName>\r
+    <companyName>seraphy@users.sourceforge.jp</companyName>\r
+    <internalName>CharacterManaJ</internalName>\r
+    <originalFilename>charactermanaj.exe</originalFilename>\r
+  </versionInfo>\r
 </launch4jConfig>
\ No newline at end of file
index 245026c..034d482 100644 (file)
@@ -61,6 +61,7 @@ If the file already exists, the file is overwritten.]]></entry>
 <entry key="gridColor">56;Grid Color</entry>\r
 <entry key="authorEditConflictBgColor">57;Author Conflict Background Color</entry>\r
 <entry key="selectPanelTitleColor">58;Parts Select Panel Hovering Color</entry>\r
+<entry key="defaultFontSize">59;Default Font Size</entry>\r
 \r
 <entry key="jarTransferBufferSize">90;Jar File Buffer</entry>\r
 <entry key="fileTransferBufferSize">91;File Buffer</entry>\r
@@ -71,4 +72,6 @@ If the file already exists, the file is overwritten.]]></entry>
 <entry key="previewUnfilledSpaceForCheckMode">A3;Unfilled space (check-mode only)</entry>\r
 <entry key="enableCheckInfoTooltip">A4;Enable CheckInfo tooltip (check-mode only)</entry>\r
 \r
+<entry key="randomChooserMaxHistory">B0;Limit Of The Random Parts History</entry>\r
+\r
 </properties>\r
index 0227d2d..b0d52f2 100644 (file)
@@ -61,6 +61,7 @@
 <entry key="gridColor">56;グリッド(罫線)の色</entry>\r
 <entry key="authorEditConflictBgColor">57;パーツ作者入力で複数作者選択時の入力ボックスの背景色</entry>\r
 <entry key="selectPanelTitleColor">58;パーツ選択パネルのホバー色</entry>\r
+<entry key="defaultFontSize">59;デフォルトのフォントサイズ</entry>\r
 \r
 <entry key="jarTransferBufferSize">90;JARファイル用バッファサイズ</entry>\r
 <entry key="fileTransferBufferSize">91;ファイル転送用バッファサイズ</entry>\r
@@ -71,4 +72,6 @@
 <entry key="previewUnfilledSpaceForCheckMode">A3;チェックモード時の余白</entry>\r
 <entry key="enableCheckInfoTooltip">A4;チェックモードの情報ツールチップの表示有無</entry>\r
 \r
+<entry key="randomChooserMaxHistory">B0;パーツのランダム選択の最大履歴数</entry>\r
+\r
 </properties>\r
diff --git a/resources/languages/partsrandomchooserdialog.xml b/resources/languages/partsrandomchooserdialog.xml
new file mode 100644 (file)
index 0000000..3ea3c57
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">\r
+<properties version="1.0">\r
+       <entry key="partsRandomChooser">Random Chooser</entry>\r
+       <entry key="close">Close</entry>\r
+       <entry key="random">Random</entry>\r
+       <entry key="reject">Ignore</entry>\r
+       <entry key="add">More</entry>\r
+       <entry key="randomAll">Random All</entry>\r
+       <entry key="back">Back</entry>\r
+</properties>\r
diff --git a/resources/languages/partsrandomchooserdialog_ja.xml b/resources/languages/partsrandomchooserdialog_ja.xml
new file mode 100644 (file)
index 0000000..504e0a6
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">\r
+<properties version="1.0">\r
+       <entry key="partsRandomChooser">パーツのランダム選択</entry>\r
+       <entry key="close">閉じる</entry>\r
+       <entry key="random">ランダム</entry>\r
+       <entry key="reject">除外</entry>\r
+       <entry key="add">追加</entry>\r
+       <entry key="randomAll">ランダム一括</entry>\r
+       <entry key="back">Back</entry>\r
+</properties>\r
index ce40a13..471d0b0 100644 (file)
        <entry key="menu.favorite.mnemonicDisp"></entry>\r
        <entry key="menu.favorite.ignoreMacOSX">false</entry>\r
 \r
+       <entry key="menu.tool.text">Tool</entry>\r
+       <entry key="menu.tool.mnemonic">T</entry>\r
+       <entry key="menu.tool.mnemonicDisp"></entry>\r
+       <entry key="menu.tool.ignoreMacOSX">false</entry>\r
+\r
        <entry key="menu.help.text">Help</entry>\r
        <entry key="menu.help.mnemonic">H</entry>\r
        <entry key="menu.help.mnemonicDisp"></entry>\r
        <entry key="favorite.manage.shortcut-key">? M</entry>\r
 \r
 \r
+       <entry key="tool.random.text">Random</entry>\r
+       <entry key="tool.random.mnemonic">R</entry>\r
+       <entry key="tool.random.mnemonicDisp"></entry>\r
+       <entry key="tool.random.ignoreMacOSX">false</entry>\r
+\r
+\r
        <entry key="help.help.text">Help</entry>\r
        <entry key="help.help.mnemonic">H</entry>\r
        <entry key="help.help.mnemonicDisp"></entry>\r
index 01b2ac4..6f1654e 100644 (file)
        <entry key="menu.favorite.mnemonic">A</entry>\r
        <entry key="menu.favorite.mnemonicDisp">(A)</entry>\r
 \r
+       <entry key="menu.tool.text">ツール</entry>\r
+       <entry key="menu.tool.mnemonic">T</entry>\r
+       <entry key="menu.tool.mnemonicDisp">(T)</entry>\r
+       <entry key="menu.tool.ignoreMacOSX">false</entry>\r
+\r
        <entry key="menu.help.text">ヘルプ</entry>\r
        <entry key="menu.help.mnemonic">H</entry>\r
        <entry key="menu.help.mnemonicDisp">(H)</entry>\r
        <entry key="favorite.manage.mnemonicDisp">(M)</entry>\r
 \r
 \r
+       <entry key="tool.random.text">ランダム</entry>\r
+       <entry key="tool.random.mnemonic">R</entry>\r
+       <entry key="tool.random.mnemonicDisp">(R)</entry>\r
+       <entry key="tool.random.ignoreMacOSX">false</entry>\r
+\r
+\r
        <entry key="help.help.text">ヘルプ</entry>\r
        <entry key="help.help.mnemonic">H</entry>\r
        <entry key="help.help.mnemonicDisp">(H)</entry>\r
index 14be796..d147912 100644 (file)
@@ -1,3 +1,3 @@
 vendor=seraphy@seraphyware\r
 specification_version=1.0\r
-implements_version=0.995\r
+implements_version=0.996\r
index 8128e2a..babd4d2 100644 (file)
@@ -12,6 +12,7 @@ import javax.swing.JOptionPane;
 import javax.swing.SwingUtilities;\r
 import javax.swing.UIDefaults;\r
 import javax.swing.UIManager;\r
+import javax.swing.plaf.FontUIResource;\r
 \r
 import charactermanaj.clipboardSupport.ImageSelection;\r
 import charactermanaj.graphics.io.ImageCacheMBeanImpl;\r
@@ -25,6 +26,7 @@ import charactermanaj.util.ApplicationLoggerConfigurator;
 import charactermanaj.util.ConfigurationDirUtilities;\r
 import charactermanaj.util.DirectoryConfig;\r
 import charactermanaj.util.ErrorMessageHelper;\r
+import charactermanaj.util.JavaVersionUtils;\r
 \r
 /**\r
  * エントリポイント用クラス\r
@@ -48,7 +50,6 @@ public final class Main implements Runnable {
         */\r
        private static final boolean isLinux;\r
 \r
-\r
        /**\r
         * クラスイニシャライザ.<br>\r
         * 実行環境に関する定数を取得・設定する.<br>\r
@@ -75,7 +76,7 @@ public final class Main implements Runnable {
                        // ログの設定を読み取る.(OSにより、設定ファイルの位置が異なることに注意)\r
                        ApplicationLoggerConfigurator.configure();\r
 \r
-                       if (getJavaVersion() >= 1.7) {\r
+                       if (JavaVersionUtils.getJavaVersion() >= 1.7) {\r
                                // java7以降は、sun.awt.exception.handlerが使えないので、\r
                                // EDTスレッドで未処理例外ハンドラを明示的に設定する.\r
                                final AWTExceptionLoggingHandler logHandler = new AWTExceptionLoggingHandler();\r
@@ -109,24 +110,6 @@ public final class Main implements Runnable {
                }\r
        }\r
 \r
-       /**\r
-        * Javaの簡易なバージョンを取得する.<br>\r
-        * 不明な場合は0を返す.<br>\r
-        * \r
-        * @return バージョン\r
-        */\r
-       public static double getJavaVersion() {\r
-               try {\r
-               String version = System.getProperty("java.version");\r
-               String[] versions = version.split("\\.");\r
-               if (versions.length > 2) {\r
-                   return Double.valueOf(versions[0] + "." + versions[1]);\r
-               }\r
-               } catch (RuntimeException ex) {\r
-                       ex.printStackTrace();\r
-               }\r
-               return 0d;\r
-       }\r
 \r
        /**\r
         * UIをセットアップする.\r
@@ -134,9 +117,9 @@ public final class Main implements Runnable {
         * @throws Exception\r
         *             いろいろな失敗\r
         */\r
-       private static void setupUIManager() throws Exception {\r
-               //System.setProperty("swing.aatext", "true");\r
-               //System.setProperty("awt.useSystemAAFontSettings", "on");\r
+       private static void setupUIManager(AppConfig appConfig) throws Exception {\r
+               // System.setProperty("swing.aatext", "true");\r
+               // System.setProperty("awt.useSystemAAFontSettings", "on");\r
 \r
                if (isMacOSX()) {\r
                        // MacOSXであれば、スクリーンメニューを有効化\r
@@ -146,7 +129,7 @@ public final class Main implements Runnable {
                                        "CharacterManaJ");\r
 \r
                        // Java7以降であればノーマライズをセットアップする.\r
-                       if (getJavaVersion() >= 1.7) {\r
+                       if (JavaVersionUtils.getJavaVersion() >= 1.7) {\r
                                charactermanaj.util.FileNameNormalizer.setupNFCNormalizer();\r
                        }\r
                }\r
@@ -157,6 +140,23 @@ public final class Main implements Runnable {
                // JSpliderのvalueを非表示 (GTKではデフォルトで有効のため)\r
                UIManager.put("Slider.paintValue", Boolean.FALSE);\r
 \r
+               // フォントサイズの変更\r
+               int fontSize = appConfig.getDefaultFontSize();\r
+               for (java.util.Map.Entry<?, ?> entry : UIManager.getDefaults()\r
+                               .entrySet()) {\r
+                       Object key = entry.getKey();\r
+                       if (key.toString().toLowerCase().endsWith("font")) {\r
+                               Object val = UIManager.get(key);\r
+                               if (val instanceof FontUIResource) {\r
+                                       FontUIResource fontUIResource = (FontUIResource) val;\r
+                                       fontUIResource = new FontUIResource(\r
+                                                       fontUIResource.getName(),\r
+                                                       fontUIResource.getStyle(), fontSize);\r
+                                       UIManager.put(entry.getKey(), fontUIResource);\r
+                               }\r
+                       }\r
+               }\r
+\r
                // JTextAreaの既定フォントを固定幅から、標準テキストと同じフォントに変更.\r
                // (Linuxなどで固定幅フォントでは日本語フォントを持っていないため。)\r
                Object textFieldFontUI = UIManager.get("TextField.font");\r
@@ -164,7 +164,8 @@ public final class Main implements Runnable {
                        // もし無ければダイアログUIフォントを使う.(これは日本語をサポートするであろう。)\r
                        textFieldFontUI = new UIDefaults.ProxyLazyValue(\r
                                        "javax.swing.plaf.FontUIResource", null, new Object[] {\r
-                                                       "dialog", Integer.valueOf(Font.PLAIN), Integer.valueOf(12)});\r
+                                                       "dialog", Integer.valueOf(Font.PLAIN),\r
+                                                       Integer.valueOf(fontSize) });\r
                }\r
                UIManager.put("TextArea.font", textFieldFontUI);\r
        }\r
@@ -174,10 +175,14 @@ public final class Main implements Runnable {
         * SwingのUIスレッドで実行される.<br>\r
         */\r
        public void run() {\r
-        try {\r
+               try {\r
+                       // アプリケーション設定の読み込み\r
+                       AppConfig appConfig = AppConfig.getInstance();\r
+                       appConfig.loadConfig();\r
+\r
                        // UIManagerのセットアップ.\r
                        try {\r
-                               setupUIManager();\r
+                               setupUIManager(appConfig);\r
 \r
                        } catch (Exception ex) {\r
                                // UIManagerの設定に失敗した場合はログに書いて継続する.\r
@@ -185,28 +190,29 @@ public final class Main implements Runnable {
                                logger.log(Level.WARNING, "UIManager setup failed.", ex);\r
                        }\r
 \r
-                       // アプリケーション設定の読み込み\r
-                       AppConfig appConfig = AppConfig.getInstance();\r
-                       appConfig.loadConfig();\r
-\r
                        // クリップボードサポートの設定\r
-                       if ( !ImageSelection.setupSystemFlavorMap()) {\r
-                               logger.log(Level.WARNING, "failed to set the clipboard-support.");\r
+                       if (!ImageSelection.setupSystemFlavorMap()) {\r
+                               logger.log(Level.WARNING,\r
+                                               "failed to set the clipboard-support.");\r
                        }\r
 \r
                        // LANG, またはLC_CTYPEが設定されていない場合はエラーを表示する\r
                        // OSXのJava7(Oracle)を実行する場合、環境変数LANGまたはLC_CTYPEに正しくファイル名の文字コードが設定されていないと\r
                        // ファイル名を正しく取り扱えず文字化けするため、実行前に確認し警告を表示する。\r
-                       if (isMacOSX() && getJavaVersion() >= 1.7) {\r
+                       // ただし、この挙動はJava7u60では修正されているので、それ以降であれば除外する.\r
+                       int[] versions = JavaVersionUtils.getJavaVersions();\r
+                       if (isMacOSX()\r
+                                       && (versions[0] == 1 && versions[1] == 7 && versions[3] < 60)) {\r
                                String lang = System.getenv("LANG");\r
                                String lcctype = System.getenv("LC_CTYPE");\r
-                               if ((lang == null || lang.trim().length() == 0) &&\r
-                                               (lcctype == null || lcctype.trim().length() == 0)) {\r
+                               if ((lang == null || lang.trim().length() == 0)\r
+                                               && (lcctype == null || lcctype.trim().length() == 0)) {\r
                                        JOptionPane\r
                                                        .showMessageDialog(\r
                                                                        null,\r
                                                                        "\"LANG\" or \"LC_CTYPE\" environment variable must be set.",\r
-                                                       "Configuration Error", JOptionPane.ERROR_MESSAGE);\r
+                                                                       "Configuration Error",\r
+                                                                       JOptionPane.ERROR_MESSAGE);\r
                                }\r
                        }\r
 \r
@@ -248,12 +254,15 @@ public final class Main implements Runnable {
                                        // OSXにしか存在しないクラスを利用するためリフレクションとしている.\r
                                        // ただしJDKによっては、Apple Java Extensionsがないことも予想されるので、\r
                                        // その場合はエラーにしない。\r
-                                       Class<?> clz = Class.forName("charactermanaj.ui.MainFramePartialForMacOSX");\r
-                                       Method mtd = clz.getMethod("setupScreenMenu", MainFrame.class);\r
+                                       Class<?> clz = Class\r
+                                                       .forName("charactermanaj.ui.MainFramePartialForMacOSX");\r
+                                       Method mtd = clz.getMethod("setupScreenMenu",\r
+                                                       MainFrame.class);\r
                                        mtd.invoke(null, mainFrame);\r
 \r
                                } catch (Throwable ex) {\r
-                                       logger.log(Level.CONFIG, "The Apple Java Extensions is not found.", ex);\r
+                                       logger.log(Level.CONFIG,\r
+                                                       "The Apple Java Extensions is not found.", ex);\r
                                }\r
                        }\r
 \r
@@ -284,13 +293,13 @@ public final class Main implements Runnable {
                initLogger();\r
 \r
                // MBeanのセットアップ\r
-        try {\r
-            ImageCacheMBeanImpl.setupMBean();\r
+               try {\r
+                       ImageCacheMBeanImpl.setupMBean();\r
 \r
-        } catch (JMException ex) {\r
+               } catch (JMException ex) {\r
                        // 失敗しても無視して継続する.\r
-            logger.log(Level.SEVERE, ex.getMessage(), ex);\r
-        }\r
+                       logger.log(Level.SEVERE, ex.getMessage(), ex);\r
+               }\r
 \r
                // フレームの生成等は、SwingのEDTで実行する.\r
                SwingUtilities.invokeLater(new Main());\r
index eae737d..368f9ec 100644 (file)
@@ -27,7 +27,7 @@ import charactermanaj.util.ConfigurationDirUtilities;
  * アプリケーションの全域にわたる設定.<br>\r
  * アプリケーション設定は、クラスパス上のリソース、コートベース直下のappConfig.xml、ユーザーごとのappConfig.xmlの順に読み込まれます\r
  * .<br>\r
- * \r
+ *\r
  * @author seraphy\r
  */\r
 public final class AppConfig {\r
@@ -46,23 +46,23 @@ public final class AppConfig {
         * 開発用仕様バージョン番号\r
         */\r
        private static final String DEFAULT_SPECIFICATION_VERSION = "1.0";\r
-       \r
-       \r
+\r
+\r
        /**\r
         * ロガー\r
         */\r
        private static final Logger logger = Logger.getLogger(AppConfig.class.getName());\r
-       \r
-       \r
+\r
+\r
        /**\r
         * シングルトンインスタンス\r
         */\r
        private static final AppConfig singleton = new AppConfig();\r
-       \r
-       \r
+\r
+\r
        /**\r
         * インスタンスを取得する.\r
-        * \r
+        *\r
         * @return インスタンス\r
         */\r
        public static AppConfig getInstance() {\r
@@ -75,16 +75,16 @@ public final class AppConfig {
        private AppConfig() {\r
                loadAppVersions();\r
        }\r
-       \r
+\r
        private String implementationVersion;\r
-       \r
+\r
        private String specificationVersion;\r
-       \r
+\r
        /**\r
         * 実装バージョンを取得する.<br>\r
         * ビルドされたjarパッケージからバージョン情報を取得する.<br>\r
         * クラスパスの実行からのバージョンは常に「develop」となる.<br>\r
-        * \r
+        *\r
         * @return 実装バージョン\r
         */\r
        public String getImplementationVersion() {\r
@@ -95,13 +95,13 @@ public final class AppConfig {
         * 仕様バージョンを取得する.<br>\r
         * ビルドされたjarパッケージからバージョン情報を取得する.<br>\r
         * クラスパスの実行からのバージョンは常に「develop」となる.<br>\r
-        * \r
+        *\r
         * @return 仕様バージョン\r
         */\r
        public String getSpecificationVersion() {\r
                return specificationVersion;\r
        }\r
-       \r
+\r
        /**\r
         * ビルドされたjarパッケージからバージョン情報を取得する.<br>\r
         * クラスパスの実行からのバージョンは常に「develop」となる.<br>\r
@@ -120,11 +120,11 @@ public final class AppConfig {
                                specificationVersion = specVInfo.trim();\r
                        }\r
                }\r
-               \r
+\r
                this.implementationVersion = implementationVersion;\r
                this.specificationVersion = specificationVersion;\r
        }\r
-       \r
+\r
        /**\r
         * 設定ファイルの読み込み順序で、読み込むべきURIのリストを返す.<br>\r
         * <ul>\r
@@ -135,7 +135,7 @@ public final class AppConfig {
         * </ul>\r
         * appConfigFileシステムプロパティがある場合は、(1)(2)の順。 <br>\r
         * 指定がない場合は、(1)(3)(4)の順に読み取る.<br>\r
-        * \r
+        *\r
         * @return 優先順位での設定ファイルの読み込み先URIのリスト\r
         * @throws IOException\r
         */\r
@@ -169,7 +169,7 @@ public final class AppConfig {
 \r
        /**\r
         * 保存先の試行順序ごとのファイルのリスト。\r
-        * \r
+        *\r
         * @return 保存先(優先順)\r
         */\r
        public List<File> getPrioritySaveFileList() {\r
@@ -227,7 +227,7 @@ public final class AppConfig {
                                        } finally {\r
                                                is.close();\r
                                        }\r
-                                       \r
+\r
                                } catch (FileNotFoundException ex) {\r
                                        logger.log(Level.CONFIG, "appConfig.xml is not found.: " + uri, ex);\r
                                        // 無視する (無い場合は十分にありえるので「情報」レベルでログ。)\r
@@ -247,7 +247,7 @@ public final class AppConfig {
 \r
        /**\r
         * プロパティをアプリケーションデータの指定した保存先に保存する.\r
-        * \r
+        *\r
         * @throws IOException\r
         *             保存に失敗した場合\r
         */\r
@@ -280,7 +280,7 @@ public final class AppConfig {
 \r
        /**\r
         * プロパティをアプリケーションデータの保存先に保存する.\r
-        * \r
+        *\r
         * @throws IOException\r
         *             保存に失敗した場合\r
         */\r
@@ -291,7 +291,7 @@ public final class AppConfig {
        /**\r
         * Propertiesの値を設定した場合に設定できない項目があるかチェックする.<br>\r
         * このメソッドを呼び出しても、アプリケーション設定自身は何も影響されない.<br>\r
-        * \r
+        *\r
         * @param props\r
         *            適用するプロパティ\r
         * @return 設定できなかったプロパティキーのコレクション、問題なければ空が返される.\r
@@ -306,7 +306,7 @@ public final class AppConfig {
 \r
        /**\r
         * Propertiesの値で設定を更新する.<br>\r
-        * \r
+        *\r
         * @param props\r
         *            適用するプロパティ\r
         * @return 設定できなかったプロパティキーのコレクション、問題なければ空が返される.\r
@@ -320,7 +320,7 @@ public final class AppConfig {
 \r
        /**\r
         * このアプリケーション設定をプロパティに書き出して返します.<br>\r
-        * \r
+        *\r
         * @return プロパティ\r
         */\r
        public Properties getProperties() {\r
@@ -328,140 +328,140 @@ public final class AppConfig {
                BeanPropertiesUtilities.saveToProperties(this, config);\r
                return config;\r
        }\r
-       \r
+\r
 \r
        /**\r
         * プロファイル選択ダイアログのプロファイルのサンプルイメージの背景色\r
-        * \r
+        *\r
         * @return サンプルイメージの背景色\r
         */\r
        public Color getSampleImageBgColor() {\r
                return sampleImageBgColor;\r
        }\r
-       \r
+\r
        public void setSampleImageBgColor(Color sampleImageBgColor) {\r
                if (sampleImageBgColor == null) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.sampleImageBgColor = sampleImageBgColor;\r
        }\r
-       \r
+\r
        private Color sampleImageBgColor = Color.white;\r
-       \r
+\r
 \r
        /**\r
         * デフォルトのイメージ背景色を取得する.\r
-        * \r
+        *\r
         * @return デフォルトのイメージ背景色\r
         */\r
        public Color getDefaultImageBgColor() {\r
                return defaultImageBgColor;\r
        }\r
-       \r
+\r
        public void setDefaultImageBgColor(Color defaultImageBgColor) {\r
                if (defaultImageBgColor == null) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.defaultImageBgColor = defaultImageBgColor;\r
        }\r
-       \r
+\r
        private Color defaultImageBgColor = Color.white;\r
 \r
        /**\r
         * 使用中アイテムの背景色を取得する.\r
-        * \r
+        *\r
         * @return 使用中アイテムの背景色\r
         */\r
        public Color getCheckedItemBgColor() {\r
                return checkedItemBgColor;\r
        }\r
-       \r
+\r
        public void setCheckedItemBgColor(Color checkedItemBgColor) {\r
                if (checkedItemBgColor == null) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.checkedItemBgColor = checkedItemBgColor;\r
        }\r
-       \r
+\r
        private Color checkedItemBgColor = Color.cyan.brighter();\r
-       \r
-       \r
+\r
+\r
        /**\r
         *  選択アイテムの背景色を取得する\r
-        * \r
+        *\r
         * @return 選択アイテムの背景色\r
         */\r
        public Color getSelectedItemBgColor() {\r
                return selectedItemBgColor;\r
        }\r
-       \r
+\r
        public void setSelectedItemBgColor(Color selectedItemBgColor) {\r
                this.selectedItemBgColor = selectedItemBgColor;\r
        }\r
-       \r
+\r
        private Color selectedItemBgColor = Color.orange;\r
-       \r
+\r
        /**\r
         * 不備のあるデータ行の背景色を取得する.\r
-        * \r
+        *\r
         * @return 不備のあるデータ行の背景色\r
         */\r
        public Color getInvalidBgColor() {\r
                return invalidBgColor;\r
        }\r
-       \r
+\r
        public void setInvalidBgColor(Color invalidBgColor) {\r
                if (invalidBgColor == null) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.invalidBgColor = invalidBgColor;\r
        }\r
-       \r
+\r
        private Color invalidBgColor = Color.red.brighter().brighter();\r
 \r
        /**\r
         * JPEG画像変換時の圧縮率を取得する.\r
-        * \r
+        *\r
         * @return 圧縮率\r
         */\r
        public float getCompressionQuality() {\r
                return compressionQuality;\r
        }\r
-       \r
+\r
        public void setCompressionQuality(float compressionQuality) {\r
                if (compressionQuality < .1f || compressionQuality > 1f) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.compressionQuality = compressionQuality;\r
        }\r
-       \r
+\r
        private float compressionQuality = .8f;\r
 \r
        /**\r
         * エクスポートウィザードのプリセットにパーツ不足時の警告色(前景色)を取得する.\r
-        * \r
+        *\r
         * @return エクスポートウィザードのプリセットにパーツ不足時の警告色(前景色)\r
         */\r
        public Color getExportPresetWarningsForegroundColor() {\r
                return exportPresetWarningsForegroundColor;\r
        }\r
-       \r
+\r
        public void setExportPresetWarningsForegroundColor(\r
                        Color exportPresetWarningsForegroundColor) {\r
                this.exportPresetWarningsForegroundColor = exportPresetWarningsForegroundColor;\r
        }\r
-       \r
+\r
        private Color exportPresetWarningsForegroundColor = Color.red;\r
-       \r
+\r
        /**\r
         * JARファイル転送用バッファサイズ.<br>\r
-        * \r
+        *\r
         * @return JARファイル転送用バッファサイズ.\r
         */\r
        public int getJarTransferBufferSize() {\r
                return jarTransferBufferSize;\r
        }\r
-       \r
+\r
        public void setJarTransferBufferSize(int jarTransferBufferSize) {\r
                if (jarTransferBufferSize <= 0) {\r
                        throw new IllegalArgumentException();\r
@@ -470,16 +470,16 @@ public final class AppConfig {
        }\r
 \r
        private int jarTransferBufferSize = 4096;\r
-       \r
+\r
        /**\r
         * ZIPファイル名のエンコーディング.<br>\r
-        * \r
+        *\r
         * @return ZIPファイル名のエンコーディング.<br>\r
         */\r
        public String getZipNameEncoding() {\r
                return zipNameEncoding;\r
        }\r
-       \r
+\r
        public void setZipNameEncoding(String zipNameEncoding) {\r
                if (zipNameEncoding == null) {\r
                        throw new IllegalArgumentException();\r
@@ -491,117 +491,117 @@ public final class AppConfig {
                }\r
                this.zipNameEncoding = zipNameEncoding;\r
        }\r
-       \r
+\r
        private String zipNameEncoding = "csWindows31J";\r
 \r
        /**\r
         * ディセーブルなテーブルのセルのフォアグラウンドカラーを取得する.\r
-        * \r
+        *\r
         * @return ディセーブルなテーブルのセルのフォアグラウンドカラー\r
         */\r
        public Color getDisabledCellForgroundColor() {\r
                return disabledCellForegroundColor;\r
        }\r
-       \r
+\r
        public void setDisabledCellForegroundColor(Color disabledCellForegroundColor) {\r
                if (disabledCellForegroundColor == null) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.disabledCellForegroundColor = disabledCellForegroundColor;\r
        }\r
-       \r
+\r
        private Color disabledCellForegroundColor = Color.gray;\r
-       \r
-       \r
+\r
+\r
        /**\r
         * ディレクトリを監視する間隔(mSec)を取得する.\r
-        * \r
+        *\r
         * @return ディレクトリを監視する間隔(mSec)\r
         */\r
        public int getDirWatchInterval() {\r
                return dirWatchInterval;\r
        }\r
-       \r
+\r
        public void setDirWatchInterval(int dirWatchInterval) {\r
                if (dirWatchInterval <= 0) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.dirWatchInterval = dirWatchInterval;\r
        }\r
-       \r
+\r
        private int dirWatchInterval = 7 * 1000;\r
-       \r
+\r
        /**\r
         * ディレクトリの監視を有効にするか?\r
-        * \r
+        *\r
         * @return ディレクトリの監視を有効にする場合はtrue\r
         */\r
        public boolean isEnableDirWatch() {\r
                return enableDirWatch;\r
        }\r
-       \r
+\r
        public void setEnableDirWatch(boolean enableDirWatch) {\r
                this.enableDirWatch = enableDirWatch;\r
        }\r
-       \r
+\r
        private boolean enableDirWatch = true;\r
-       \r
+\r
        /**\r
         * ファイル転送に使うバッファサイズ.<br>\r
-        * \r
+        *\r
         * @return バッファサイズ\r
         */\r
        public int getFileTransferBufferSize() {\r
                return fileTransferBufferSize;\r
        }\r
-       \r
+\r
        public void setFileTransferBufferSize(int fileTransferBufferSize) {\r
                if (fileTransferBufferSize <= 0) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.fileTransferBufferSize = fileTransferBufferSize;\r
        }\r
-       \r
+\r
        private int fileTransferBufferSize = 4096;\r
-       \r
+\r
        /**\r
         * プレビューのインジケータを表示するまでのディレイ(mSec)を取得する.\r
-        * \r
+        *\r
         * @return プレビューのインジケータを表示するまでのディレイ(mSec)\r
         */\r
        public long getPreviewIndicatorDelay() {\r
                return previewIndeicatorDelay;\r
        }\r
-       \r
+\r
        public void setPreviewIndeicatorDelay(long previewIndeicatorDelay) {\r
                if (previewIndeicatorDelay < 0) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.previewIndeicatorDelay = previewIndeicatorDelay;\r
        }\r
-       \r
+\r
        private long previewIndeicatorDelay = 300;\r
-       \r
+\r
        /**\r
         * 情報ダイアログの編集ボタンを「開く」アクションにする場合はtrue、「編集」アクションにする場合はfalse\r
-        * \r
+        *\r
         * @return trueならばOpen、falseならばEdit\r
         */\r
        public boolean isInformationDialogOpenMethod() {\r
                return informationDialogOpenMethod;\r
        }\r
-       \r
+\r
        public void setInformationDialogOpenMethod(\r
                        boolean informationDialogOpenMethod) {\r
                this.informationDialogOpenMethod = informationDialogOpenMethod;\r
        }\r
 \r
        private boolean informationDialogOpenMethod = true;\r
-       \r
+\r
        /**\r
         * ログを常に残すか?<br>\r
         * falseの場合は{@link ApplicationLogHandler}の実装に従って終了時に 必要なければログは削除される.<br>\r
-        * \r
+        *\r
         * @return 常に残す場合はtrue、そうでなければfalse\r
         */\r
        public boolean isNoRemoveLog() {\r
@@ -611,43 +611,43 @@ public final class AppConfig {
        public void setNoRemoveLog(boolean noRemoveLog) {\r
                this.noRemoveLog = noRemoveLog;\r
        }\r
-       \r
+\r
        private boolean noRemoveLog = false;\r
 \r
 \r
        /**\r
         * テーブルのグリッド色.<br>\r
-        * \r
+        *\r
         * @return テーブルのグリッド色\r
         */\r
        public Color getGridColor() {\r
                return gridColor;\r
        }\r
-       \r
+\r
        public void setGridColor(Color gridColor) {\r
                if (gridColor == null) {\r
                        throw new IllegalArgumentException();\r
                }\r
                this.gridColor = gridColor;\r
        }\r
-       \r
+\r
        private Color gridColor = Color.gray;\r
 \r
        /**\r
         * カラーダイアログの値が変更されたら、自動的にプレビューを更新するか?\r
-        * \r
+        *\r
         * @return カラーダイアログの値が変更されたら、自動的にプレビューを更新する場合はtrue (デフォルトはtrue)\r
         */\r
        public boolean isEnableAutoColorChange() {\r
                return enableAutoColorChange;\r
        }\r
-       \r
+\r
        public void setEnableAutoColorChange(boolean enableAutoColorChange) {\r
                this.enableAutoColorChange = enableAutoColorChange;\r
        }\r
-       \r
+\r
        private boolean enableAutoColorChange = true;\r
-       \r
+\r
        public void setAuthorEditConflictBgColor(Color authorEditConflictBgColor) {\r
                if (authorEditConflictBgColor == null) {\r
                        throw new IllegalArgumentException();\r
@@ -657,146 +657,146 @@ public final class AppConfig {
 \r
        /**\r
         * パーツの作者編集時に複数作者を選択した場合のに入力ボックスの背景色\r
-        * \r
+        *\r
         * @return 背景色\r
         */\r
        public Color getAuthorEditConflictBgColor() {\r
                return authorEditConflictBgColor;\r
        }\r
-       \r
+\r
        Color authorEditConflictBgColor = Color.yellow;\r
-       \r
-       \r
+\r
+\r
        public void setMainFrameMaxWidth(int width) {\r
                this.mainFrameMaxWidth = width;\r
        }\r
-       \r
+\r
        /**\r
         * メインフレームの初期表示時の最大幅\r
-        * \r
+        *\r
         * @return メインフレームの初期表示時の最大幅\r
         */\r
        public int getMainFrameMaxWidth() {\r
                return mainFrameMaxWidth;\r
        }\r
-       \r
+\r
        private int mainFrameMaxWidth = 800;\r
-       \r
+\r
        public void setMainFrameMaxHeight(int height) {\r
                this.mainFrameMaxHeight = height;\r
        }\r
 \r
        /**\r
         * メインフレームの初期表示時の最大高さ\r
-        * \r
+        *\r
         * @return メインフレームの初期表示時の最大高さ\r
         */\r
        public int getMainFrameMaxHeight() {\r
                return mainFrameMaxHeight;\r
        }\r
-       \r
+\r
        private int mainFrameMaxHeight = 600;\r
-       \r
-       \r
+\r
+\r
        /**\r
         * カラーダイアログで存在しないレイヤーをディセーブルにしない.\r
-        * \r
+        *\r
         * @return ディセーブルにしない場合はtrue\r
         */\r
        public boolean isNotDisableLayerTab() {\r
                return notDisableLayerTab;\r
        }\r
-       \r
+\r
        public void setNotDisableLayerTab(boolean notDisableLayerTab) {\r
                this.notDisableLayerTab = notDisableLayerTab;\r
        }\r
-       \r
+\r
        private boolean notDisableLayerTab;\r
-       \r
+\r
 \r
        /**\r
         * ログを消去する日数.<br>\r
         * この指定日を経過した古いログは削除される.<br>\r
         * 0の場合は削除されない.\r
-        * \r
+        *\r
         * @return\r
         */\r
        public long getPurgeLogDays() {\r
                return purgeLogDays;\r
        }\r
-       \r
+\r
        public void setPurgeLogDays(long purgeLogDays) {\r
                this.purgeLogDays = purgeLogDays;\r
        }\r
-       \r
+\r
        private long purgeLogDays = 10;\r
-       \r
+\r
        public String getPartsColorGroupPattern() {\r
                return partsColorGroupPattern;\r
        }\r
-       \r
+\r
        public void setPartsColorGroupPattern(String pattern) {\r
                if (pattern != null && pattern.trim().length() > 0) {\r
                        Pattern.compile(pattern);\r
                }\r
                partsColorGroupPattern = pattern;\r
        }\r
-       \r
+\r
        private String partsColorGroupPattern = "^.*\\(@\\).*$";\r
-       \r
+\r
        private Color selectPanelTitleColor = Color.BLUE;\r
-       \r
+\r
        public Color getSelectPanelTitleColor() {\r
                return selectPanelTitleColor;\r
        }\r
-       \r
+\r
        public void setSelectPanelTitleColor(Color color) {\r
                if (color == null) {\r
                        throw new IllegalArgumentException();\r
                }\r
                selectPanelTitleColor = color;\r
        }\r
-       \r
+\r
        private boolean enableAutoShrinkPanel;\r
-       \r
+\r
        public boolean isEnableAutoShrinkPanel() {\r
                return enableAutoShrinkPanel;\r
        }\r
-       \r
+\r
        public void setEnableAutoShrinkPanel(boolean enableAutoShrinkPanel) {\r
                this.enableAutoShrinkPanel = enableAutoShrinkPanel;\r
        }\r
-       \r
+\r
        public boolean isDisableWatchDirIfNotWritable() {\r
                return disableWatchDirIfNotWritable;\r
        }\r
-       \r
+\r
        public void setDisableWatchDirIfNotWritable(boolean disableWatchDirIfNotWritable) {\r
                this.disableWatchDirIfNotWritable = disableWatchDirIfNotWritable;\r
        }\r
-       \r
+\r
        private boolean disableWatchDirIfNotWritable = true;\r
-       \r
+\r
        public void setEnablePNGSupportForWindows(boolean enablePNGSupportForWindows) {\r
                this.enablePNGSupportForWindows = enablePNGSupportForWindows;\r
        }\r
-       \r
+\r
        public boolean isEnablePNGSupportForWindows() {\r
                return enablePNGSupportForWindows;\r
        }\r
-       \r
+\r
        private boolean enablePNGSupportForWindows = true;\r
-       \r
+\r
        /**\r
         * 画像表示(通常モード)でオプティマイズを有効にする最大倍率.\r
         */\r
        private double renderingOptimizeThresholdForNormal = 2.;\r
-       \r
+\r
        public void setRenderingOptimizeThresholdForNormal(\r
                        double renderingOptimizeThresholdForNormal) {\r
                this.renderingOptimizeThresholdForNormal = renderingOptimizeThresholdForNormal;\r
        }\r
-       \r
+\r
        public double getRenderingOptimizeThresholdForNormal() {\r
                return renderingOptimizeThresholdForNormal;\r
        }\r
@@ -804,12 +804,12 @@ public final class AppConfig {
         * 画像表示(チェックモード)でオプティマイズを有効にする最大倍率.\r
         */\r
        private double renderingOptimizeThresholdForCheck = 0.;\r
-       \r
+\r
        public void setRenderingOptimizeThresholdForCheck(\r
                        double renderingOptimizeThresholdForCheck) {\r
                this.renderingOptimizeThresholdForCheck = renderingOptimizeThresholdForCheck;\r
        }\r
-       \r
+\r
        public double getRenderingOptimizeThresholdForCheck() {\r
                return renderingOptimizeThresholdForCheck;\r
        }\r
@@ -818,7 +818,7 @@ public final class AppConfig {
         * バイキュービックをサポートする場合\r
         */\r
        private boolean enableInterpolationBicubic = true;\r
-       \r
+\r
        public void setEnableInterpolationBicubic(boolean enableInterpolationBicubic) {\r
                this.enableInterpolationBicubic = enableInterpolationBicubic;\r
        }\r
@@ -831,11 +831,11 @@ public final class AppConfig {
         * 事前定義済みの倍率候補.<br>\r
         */\r
        private String predefinedZoomRanges = "20, 50, 80, 100, 120, 150, 200, 300, 400, 800";\r
-       \r
+\r
        public String getPredefinedZoomRanges() {\r
                return predefinedZoomRanges;\r
        }\r
-       \r
+\r
        public void setPredefinedZoomRanges(String predefinedZoomRanges) {\r
                this.predefinedZoomRanges = predefinedZoomRanges;\r
        }\r
@@ -844,24 +844,24 @@ public final class AppConfig {
         * ズームパネルを初期状態で表示するか?\r
         */\r
        private boolean enableZoomPanel = true;\r
-       \r
+\r
        public boolean isEnableZoomPanel() {\r
                return enableZoomPanel;\r
        }\r
-       \r
+\r
        public void setEnableZoomPanel(boolean enableZoomPanel) {\r
                this.enableZoomPanel = enableZoomPanel;\r
        }\r
-       \r
+\r
        /**\r
         * ズームパネルをアクティブにする下部範囲\r
         */\r
        private int zoomPanelActivationArea = 30;\r
-       \r
+\r
        public int getZoomPanelActivationArea() {\r
                return zoomPanelActivationArea;\r
        }\r
-       \r
+\r
        public void setZoomPanelActivationArea(int zoomPanelActivationArea) {\r
                this.zoomPanelActivationArea = zoomPanelActivationArea;\r
        }\r
@@ -874,7 +874,7 @@ public final class AppConfig {
        public void setEnableRenderingHints(boolean enableRenderingHints) {\r
                this.enableRenderingHints = enableRenderingHints;\r
        }\r
-       \r
+\r
        public boolean isEnableRenderingHints() {\r
                return enableRenderingHints;\r
        }\r
@@ -883,40 +883,40 @@ public final class AppConfig {
         * グリッド描画とマスク\r
         */\r
        private int drawGridMask = 2;\r
-       \r
+\r
        public int getDrawGridMask() {\r
                return drawGridMask;\r
        }\r
-       \r
+\r
        public void setDrawGridMask(int drawGridMask) {\r
                this.drawGridMask = drawGridMask & 0x03;\r
        }\r
-       \r
+\r
        private int previewGridColor = 0x7f7f0000;\r
-       \r
+\r
        public int getPreviewGridColor() {\r
                return previewGridColor;\r
        }\r
-       \r
+\r
        public void setPreviewGridColor(int previewGridColor) {\r
                this.previewGridColor = previewGridColor;\r
        }\r
-       \r
+\r
        private int previewGridSize = 20;\r
-       \r
+\r
        public int getPreviewGridSize() {\r
                return previewGridSize;\r
        }\r
-       \r
+\r
        public void setPreviewGridSize(int previewGridSize) {\r
                this.previewGridSize = previewGridSize;\r
        }\r
-       \r
+\r
        /**\r
         * チェックモード時の余白サイズ(片側)\r
         */\r
        private int previewUnfilledSpaceForCheckMode = 0;\r
-       \r
+\r
        public int getPreviewUnfilledSpaceForCheckMode() {\r
                return previewUnfilledSpaceForCheckMode;\r
        }\r
@@ -925,57 +925,77 @@ public final class AppConfig {
                        int previewUnfilledSpaceForCheckMode) {\r
                this.previewUnfilledSpaceForCheckMode = previewUnfilledSpaceForCheckMode;\r
        }\r
-       \r
+\r
        /**\r
         * チェックモードでツールチップを表示するか?\r
         */\r
        private boolean enableCheckInfoTooltip = true;\r
-       \r
+\r
        public boolean isEnableCheckInfoTooltip() {\r
                return enableCheckInfoTooltip;\r
        }\r
-       \r
+\r
        public void setEnableCheckInfoTooltip(boolean enableCheckInfoTooltip) {\r
                this.enableCheckInfoTooltip = enableCheckInfoTooltip;\r
        }\r
-       \r
+\r
        /**\r
         * ホイールによるスクロールの単位.<br>\r
         */\r
        private int wheelScrollUnit = 10;\r
-       \r
+\r
        public int getWheelScrollUnit() {\r
                return wheelScrollUnit;\r
        }\r
-       \r
+\r
        public void setWheelScrollUnit(int wheelScrollUnit) {\r
                this.wheelScrollUnit = wheelScrollUnit;\r
        }\r
-       \r
+\r
        /**\r
         * 壁紙にオフスクリーン描画を使用するか?.<br>\r
         * (あまり劇的なパフォーマンス効果はない.)\r
         */\r
        private boolean enableOffscreenWallpaper = false;\r
-       \r
+\r
        public boolean isEnableOffscreenWallpaper() {\r
                return enableOffscreenWallpaper;\r
        }\r
-       \r
+\r
        public void setEnableOffscreenWallpaper(boolean enableOffscreenWallpaper) {\r
-               this.enableOffscreenWallpaper = enableOffscreenWallpaper;  \r
+               this.enableOffscreenWallpaper = enableOffscreenWallpaper;\r
        }\r
-       \r
+\r
        /**\r
         * 壁紙のオフスクリーンの既定サイズ.\r
         */\r
        private int offscreenWallpaperSize = 300;\r
-       \r
+\r
        public int getOffscreenWallpaperSize() {\r
                return offscreenWallpaperSize;\r
        }\r
-       \r
+\r
        public void setOffscreenWallpaperSize(int offscreenWallpaperSize) {\r
                this.offscreenWallpaperSize = offscreenWallpaperSize;\r
        }\r
+\r
+       private int randomChooserMaxHistory = 10;\r
+\r
+       public int getRandomChooserMaxHistory() {\r
+               return randomChooserMaxHistory;\r
+       }\r
+\r
+       public void setRandomChooserMaxHistory(int randomChooserMaxHistory) {\r
+               this.randomChooserMaxHistory = randomChooserMaxHistory;\r
+       }\r
+\r
+       private int defaultFontSize = 12;\r
+\r
+       public int getDefaultFontSize() {\r
+               return defaultFontSize;\r
+       }\r
+\r
+       public void setDefaultFontSize(int defaultFontSize) {\r
+               this.defaultFontSize = defaultFontSize;\r
+       }\r
 }\r
index cde5670..f538392 100644 (file)
@@ -29,6 +29,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.net.URI;\r
 import java.util.ArrayList;\r
 import java.util.Collections;\r
+import java.util.HashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Properties;\r
@@ -120,7 +121,7 @@ import charactermanaj.util.UIHelper;
 /**\r
  * メインフレーム.<br>\r
  * アプリケーションがアクティブである場合は最低でも1つのメインフレームが表示されている.<br>\r
- * \r
+ *\r
  * @author seraphy\r
  */\r
 public class MainFrame extends JFrame\r
@@ -249,6 +250,13 @@ public class MainFrame extends JFrame
        private ManageFavoriteDialog lastUseManageFavoritesDialog;\r
 \r
        /**\r
+        * 最後に使用したパーツのランダム選択ダイアログ.<br>\r
+        * nullであれば一度も使用していない.<br>\r
+        * (nullでなくとも閉じられている可能性がある.)\r
+        */\r
+       private PartsRandomChooserDialog lastUsePartsRandomChooserDialog;\r
+\r
+       /**\r
         * 最後に使用した壁紙情報\r
         */\r
        private WallpaperInfo wallpaperInfo;\r
@@ -256,7 +264,7 @@ public class MainFrame extends JFrame
 \r
        /**\r
         * アクティブなメインフレームを設定する.\r
-        * \r
+        *\r
         * @param mainFrame\r
         *            メインフレーム\r
         */\r
@@ -270,7 +278,7 @@ public class MainFrame extends JFrame
        /**\r
         * 現在アクティブなメインフレームを取得する. まだメインフレームが開かれていない場合はnull.<br>\r
         * 最後のメインフレームが破棄中、もしくは破棄済みであれば破棄されたフレームを示すことに注意.<br>\r
-        * \r
+        *\r
         * @return メインフレーム、もしくはnull\r
         */\r
        public static MainFrame getActivedMainFrame() {\r
@@ -320,7 +328,7 @@ public class MainFrame extends JFrame
 \r
        /**\r
         * お気に入りデータが変更された場合に通知される.\r
-        * \r
+        *\r
         * @param e\r
         */\r
        public void notifyChangeFavorites(FavoritesChangeEvent e) {\r
@@ -350,7 +358,7 @@ public class MainFrame extends JFrame
 \r
        /**\r
         * メインフレームを構築する.\r
-        * \r
+        *\r
         * @param characterData\r
         *            キャラクターデータ\r
         */\r
@@ -563,6 +571,9 @@ public class MainFrame extends JFrame
                // 開いているお気に入り管理ダイアログを閉じる\r
                closeManageFavoritesDialog();\r
 \r
+               // 開いているランダム選択ダイアログを閉じる.\r
+               closePartsRandomChooserDialog();\r
+\r
                PartsColorManager partsColorManager = characterData.getPartsColorManager();\r
 \r
                // デフォルトの背景色の設定\r
@@ -816,7 +827,7 @@ public class MainFrame extends JFrame
 \r
        /**\r
         * 指定したパーツカテゴリ以外のパーツ選択パネルを最小化する.\r
-        * \r
+        *\r
         * @param partsCategory\r
         *            パーツカテゴリ、nullの場合は全て最小化する.\r
         * @param dblClick\r
@@ -863,7 +874,7 @@ public class MainFrame extends JFrame
         * デフォルトパーツがなければお気に入りの最初のものを選択する.<br>\r
         * それもなければ空として表示する.<br>\r
         * パーツの適用に失敗した場合はfalseを返します.(例外は返されません.)<br>\r
-        * \r
+        *\r
         * @param force\r
         *            すでに選択があっても選択しなおす場合はtrue、falseの場合は選択があれば何もしない.\r
         * @return パーツ選択された場合。force=trueの場合はエラーがなければ常にtrueとなります。\r
@@ -913,7 +924,7 @@ public class MainFrame extends JFrame
        /**\r
         * プリセットを適用しキャラクターイメージを再構築します.<br>\r
         * 実行時エラーは画面のレポートされます.<br>\r
-        * \r
+        *\r
         * @param presetParts\r
         *            パーツセット, nullの場合は何もしない.\r
         */\r
@@ -938,7 +949,7 @@ public class MainFrame extends JFrame
 \r
        /**\r
         * プリセットとお気に入りを表示順に並べて返す.\r
-        * \r
+        *\r
         * @return プリセットとお気に入りのリスト(表示順)\r
         */\r
        protected List<PartsSet> getPartsSetList() {\r
@@ -1130,7 +1141,7 @@ public class MainFrame extends JFrame
 \r
                /**\r
                 * メニューアイテム上でホイールを上下させたときにメニューをスクロールさせるためのホイールハンドラを設定する.\r
-                * \r
+                *\r
                 * @param favoriteMenu\r
                 */\r
                protected void addMouseWheelListener(final JMenuItem favoriteMenu) {\r
@@ -1156,7 +1167,7 @@ public class MainFrame extends JFrame
 \r
        /**\r
         * お気に入りメニューが開いたとき\r
-        * \r
+        *\r
         * @param menu\r
         */\r
        protected void onSelectedFavoriteMenu(JMenu menu) {\r
@@ -1218,7 +1229,7 @@ public class MainFrame extends JFrame
 \r
        /**\r
         * ヘルプメニューを開いたときにお勧めメニューを構築する.\r
-        * \r
+        *\r
         * @param menu\r
         */\r
        protected void onSelectedRecommendationMenu(JMenu mnuRecomendation) {\r
@@ -1257,7 +1268,7 @@ public class MainFrame extends JFrame
         * 最後に選択されたお気に入りと同じ構成であれば、 このお気に入りの名前をプレビューペインのタイトルに設定する.<br>\r
         * そうでなければデフォルトのパーツセット名(no titleとか)を表示する.<br>\r
         * 色情報が異なる場合に末尾に「*」マークがつけられる.<br>\r
-        * \r
+        *\r
         * @param requestPartsSet\r
         *            表示するパーツセット(名前は設定されていなくて良い。お気に入り側を使うので。), nullの場合はデフォルトのパーツ名\r
         */\r
@@ -1273,7 +1284,7 @@ public class MainFrame extends JFrame
         * パーツセット名を推定する.<br>\r
         * 最後に選択されたお気に入りと同じ構成であれば、 このお気に入りの名前を返す.<br>\r
         * お気に入りが選択されていないか構成が異なる場合、お気に入りに名前がない場合はnullを返す.<br>\r
-        * \r
+        *\r
         * @param requestPartsSet\r
         *            表示するパーツセット(名前は設定されていなくて良い。お気に入り側を使うので。)\r
         * @param markColorChange\r
@@ -1457,7 +1468,7 @@ public class MainFrame extends JFrame
        /**\r
         * 背景色のみ変更し、背景を再描画する.<br>\r
         * 壁紙情報全体の更新よりも効率化するためのメソッドである.<br>\r
-        * \r
+        *\r
         * @param bgColor\r
         *            背景色\r
         */\r
@@ -1470,7 +1481,7 @@ public class MainFrame extends JFrame
        /**\r
         * 壁紙情報を保存し、その情報をもとに背景を再描画する.<br>\r
         * ignoreErrorがtrueである場合、適用に失敗した場合はログに記録するのみで、 壁紙情報は保存されず、壁紙も更新されない.<br>\r
-        * \r
+        *\r
         * @param wallpaperInfo\r
         *            壁紙情報、null不可\r
         * @param ignoreError\r
@@ -1712,8 +1723,20 @@ public class MainFrame extends JFrame
        }\r
 \r
        /**\r
+        * 「パーツのランダム選択ダイアログ」を閉じる\r
+        */\r
+       protected void closePartsRandomChooserDialog() {\r
+               if (lastUsePartsRandomChooserDialog != null) {\r
+                       if (lastUsePartsRandomChooserDialog.isDisplayable()) {\r
+                               lastUsePartsRandomChooserDialog.dispose();\r
+                       }\r
+                       lastUsePartsRandomChooserDialog = null;\r
+               }\r
+       }\r
+\r
+       /**\r
         * クリップボードにコピー\r
-        * \r
+        *\r
         * @param screenImage\r
         *            スクリーンイメージ\r
         */\r
@@ -1786,7 +1809,7 @@ public class MainFrame extends JFrame
         * 現在のプロファイルに対するインポートウィザードを実行する.<br>\r
         * インポートが実行された場合は、パーツをリロードする.<br>\r
         * インポートウィザード表示中は監視スレッドは停止される.<br>\r
-        * \r
+        *\r
         * @param initFile\r
         *            アーカイブファィルまたはディレクトリ、指定がなければnull\r
         */\r
@@ -1825,7 +1848,7 @@ public class MainFrame extends JFrame
         * まだロードされていない場合はあらたにロードする.<br>\r
         * 引数newCdが指定されている場合は、現在のキャラクター定義の説明文を更新する.<br>\r
         * (説明文の更新以外には使用されない.)<br>\r
-        * \r
+        *\r
         * @param newCd\r
         *            説明文更新のための更新されたキャラクターデータを指定する。null可\r
         * @param forceRepaint\r
@@ -2008,7 +2031,7 @@ public class MainFrame extends JFrame
 \r
        /**\r
         * 画面の作業状態を復元する.\r
-        * \r
+        *\r
         * @return ワーキングセットを読み込んだ場合はtrue、そうでなければfalse\r
         */\r
        protected boolean loadWorkingSet() {\r
@@ -2312,6 +2335,64 @@ public class MainFrame extends JFrame
        }\r
 \r
        /**\r
+        * ランダム選択ダイアログを開く.\r
+        */\r
+       protected void onToolRandom() {\r
+               if (!characterData.isValid()) {\r
+                       Toolkit tk = Toolkit.getDefaultToolkit();\r
+                       tk.beep();\r
+                       return;\r
+               }\r
+\r
+               if (lastUsePartsRandomChooserDialog != null) {\r
+                       // 開いているダイアログがあれば、それにフォーカスを当てる.\r
+                       if (lastUsePartsRandomChooserDialog.isDisplayable()\r
+                                       && lastUsePartsRandomChooserDialog.isVisible()) {\r
+                               lastUsePartsRandomChooserDialog.requestFocus();\r
+                               return;\r
+                       }\r
+               }\r
+\r
+               // お気に入り編集ダイアログを開く\r
+               PartsRandomChooserDialog dlg = new PartsRandomChooserDialog(this,\r
+                               characterData,\r
+                               new PartsRandomChooserDialog.PartsSetSynchronizer() {\r
+                                       public PartsSet getCurrentPartsSet() {\r
+                                               // 現在のパーツセットを生成\r
+                                               return partsSelectionManager.createPartsSet();\r
+                                       }\r
+\r
+                                       public void setPartsSet(PartsSet partsSet) {\r
+                                               selectPresetParts(partsSet);\r
+                                       }\r
+\r
+                                       public boolean\r
+                                                       isExcludePartsIdentifier(PartsIdentifier partsIdentifier) {\r
+                                               Boolean exclude = randomExcludePartsIdentifierMap\r
+                                                               .get(partsIdentifier);\r
+                                               return exclude != null && exclude.booleanValue();\r
+                                       }\r
+\r
+                                       public void\r
+                                                       setExcludePartsIdentifier(PartsIdentifier partsIdentifier,\r
+                                                                       boolean exclude) {\r
+                                               randomExcludePartsIdentifierMap.put(partsIdentifier,\r
+                                                               exclude);\r
+                                       }\r
+                               });\r
+\r
+               WindowAdjustLocationSupport.alignRight(this, dlg, 0, true);\r
+               dlg.setVisible(true);\r
+               lastUsePartsRandomChooserDialog = dlg;\r
+       }\r
+\r
+       /**\r
+        * ランダム選択パーツで選択候補から除外するパーツのマップ.\r
+        */\r
+       private HashMap<PartsIdentifier, Boolean> randomExcludePartsIdentifierMap =\r
+                       new HashMap<PartsIdentifier, Boolean>();\r
+\r
+       /**\r
         * すべての解除可能なパーツの選択を解除する。\r
         */\r
        protected void onDeselectAll() {\r
@@ -2336,7 +2417,7 @@ public class MainFrame extends JFrame
 \r
        /**\r
         * メニューバーを構築します.\r
-        * \r
+        *\r
         * @return メニューバー\r
         */\r
        protected JMenuBar createMenuBar() {\r
@@ -2477,7 +2558,6 @@ public class MainFrame extends JFrame
                                                                onChangeWallpaper();\r
                                                        }\r
                                                }),\r
-\r
                                }),\r
                                new MenuDataFactory("menu.favorite", new MenuDataFactory[] {\r
                                                new MenuDataFactory("favorite.register", new ActionListener() {\r
@@ -2492,6 +2572,13 @@ public class MainFrame extends JFrame
                                                }),\r
                                                null,\r
                                }),\r
+                               new MenuDataFactory("menu.tool",\r
+                                               new MenuDataFactory[]{new MenuDataFactory(\r
+                                                               "tool.random", new ActionListener() {\r
+                                                                       public void actionPerformed(ActionEvent e) {\r
+                                                                               onToolRandom();\r
+                                                                       }\r
+                                                               }),}),\r
                                new MenuDataFactory("menu.help", new MenuDataFactory[] {\r
                                                new MenuDataFactory("help.recommendations", (ActionListener) null),\r
                                                null,\r
diff --git a/src/charactermanaj/ui/PartsRandomChooserDialog.java b/src/charactermanaj/ui/PartsRandomChooserDialog.java
new file mode 100644 (file)
index 0000000..633e028
--- /dev/null
@@ -0,0 +1,728 @@
+package charactermanaj.ui;\r
+\r
+import java.awt.BorderLayout;\r
+import java.awt.Component;\r
+import java.awt.Container;\r
+import java.awt.GridBagConstraints;\r
+import java.awt.GridBagLayout;\r
+import java.awt.Toolkit;\r
+import java.awt.event.ActionEvent;\r
+import java.awt.event.ActionListener;\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.WindowAdapter;\r
+import java.awt.event.WindowEvent;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Properties;\r
+import java.util.Random;\r
+import java.util.concurrent.atomic.AtomicInteger;\r
+\r
+import javax.swing.AbstractAction;\r
+import javax.swing.Action;\r
+import javax.swing.ActionMap;\r
+import javax.swing.BorderFactory;\r
+import javax.swing.Box;\r
+import javax.swing.InputMap;\r
+import javax.swing.JButton;\r
+import javax.swing.JCheckBox;\r
+import javax.swing.JComboBox;\r
+import javax.swing.JComponent;\r
+import javax.swing.JDialog;\r
+import javax.swing.JFrame;\r
+import javax.swing.JPanel;\r
+import javax.swing.JRootPane;\r
+import javax.swing.JScrollBar;\r
+import javax.swing.JScrollPane;\r
+import javax.swing.JToggleButton;\r
+import javax.swing.KeyStroke;\r
+import javax.swing.event.EventListenerList;\r
+\r
+import charactermanaj.model.AppConfig;\r
+import charactermanaj.model.CharacterData;\r
+import charactermanaj.model.PartsCategory;\r
+import charactermanaj.model.PartsIdentifier;\r
+import charactermanaj.model.PartsSet;\r
+import charactermanaj.util.LocalizedResourcePropertyLoader;\r
+\r
+/**\r
+ * パーツのランダム選択ダイアログ.<br>\r
+ *\r
+ * @author seraphy\r
+ */\r
+public class PartsRandomChooserDialog extends JDialog {\r
+\r
+       private static final long serialVersionUID = -8427874726724107481L;\r
+\r
+       protected static final String STRINGS_RESOURCE = "languages/partsrandomchooserdialog";\r
+\r
+       /**\r
+        * メインフレームとの間でパーツの選択状態の取得・設定を行うためのインターフェイス.<br>\r
+        */\r
+       public interface PartsSetSynchronizer {\r
+\r
+               /**\r
+                * 現在フレームで設定されているパーツセットを取得する.\r
+                *\r
+                * @return\r
+                */\r
+               PartsSet getCurrentPartsSet();\r
+\r
+               /**\r
+                * ランダム選択パネルのパーツセットでフレームを設定する.\r
+                *\r
+                * @param partsSet\r
+                */\r
+               void setPartsSet(PartsSet partsSet);\r
+\r
+               /**\r
+                * 指定されたパーツがランダム選択対象外であるか?\r
+                *\r
+                * @param partsIdentifier\r
+                *            パーツ\r
+                * @return 対象外であればtrue\r
+                */\r
+               boolean isExcludePartsIdentifier(PartsIdentifier partsIdentifier);\r
+\r
+               /**\r
+                * 指定したパーツがランダム選択対象外であるか設定する.\r
+                *\r
+                * @param partsIdentifier\r
+                *            パーツ\r
+                * @param exclude\r
+                *            対象外であればtrue\r
+                */\r
+               void setExcludePartsIdentifier(PartsIdentifier partsIdentifier,\r
+                               boolean exclude);\r
+       }\r
+\r
+       /**\r
+        * ランダム選択パネルを縦に並べるボックス\r
+        */\r
+       private Box centerPnl;\r
+\r
+       /**\r
+        * キャラクターデータ\r
+        */\r
+       private CharacterData characterData;\r
+\r
+       /**\r
+        * メインフレームとの同期用\r
+        */\r
+       private PartsSetSynchronizer partsSync;\r
+\r
+       /**\r
+        * 一括ランダムアクション\r
+        */\r
+       private Action actRandomAll;\r
+\r
+       /**\r
+        * 選択を戻すアクション\r
+        */\r
+       private Action actBack;\r
+\r
+       /**\r
+        * 閉じるアクション\r
+        */\r
+       private Action actCancel;\r
+\r
+       /**\r
+        * 履歴\r
+        */\r
+       private LinkedList<Map<RandomChooserPanel, PartsIdentifier>> history = new LinkedList<Map<RandomChooserPanel, PartsIdentifier>>();\r
+\r
+       /**\r
+        * 最大の履歴保持数\r
+        */\r
+       private int maxHistory;\r
+\r
+       /**\r
+        * コンストラクタ\r
+        *\r
+        * @param parent\r
+        *            メインフレーム(親)\r
+        * @param characterData\r
+        *            キャラクターデータ\r
+        * @param partsSync\r
+        *            メインフレームとの同期用\r
+        */\r
+       public PartsRandomChooserDialog(JFrame parent, CharacterData characterData,\r
+                       PartsSetSynchronizer partsSync) {\r
+               super(parent, false);\r
+               try {\r
+                       if (characterData == null || partsSync == null) {\r
+                               throw new IllegalArgumentException();\r
+                       }\r
+\r
+                       setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);\r
+                       addWindowListener(new WindowAdapter() {\r
+                               @Override\r
+                               public void windowClosing(WindowEvent e) {\r
+                                       onClose();\r
+                               }\r
+                       });\r
+\r
+                       this.characterData = characterData;\r
+                       this.partsSync = partsSync;\r
+\r
+                       AppConfig appConfig = AppConfig.getInstance();\r
+                       this.maxHistory = appConfig.getRandomChooserMaxHistory();\r
+                       if (this.maxHistory < 0) {\r
+                               this.maxHistory = 0;\r
+                       }\r
+\r
+                       initLayout();\r
+\r
+                       pack();\r
+                       setLocationRelativeTo(parent);\r
+\r
+               } catch (RuntimeException ex) {\r
+                       dispose();\r
+                       throw ex;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * レイアウトを行う.\r
+        */\r
+       private void initLayout() {\r
+               Properties strings = LocalizedResourcePropertyLoader\r
+                               .getCachedInstance().getLocalizedProperties(STRINGS_RESOURCE);\r
+\r
+               setTitle(strings.getProperty("partsRandomChooser"));\r
+\r
+               Container contentPane = getContentPane();\r
+               contentPane.setLayout(new BorderLayout());\r
+\r
+               this.centerPnl = Box.createVerticalBox();\r
+\r
+               ActionListener changePartsIdentifierListener = new ActionListener() {\r
+                       public void actionPerformed(ActionEvent e) {\r
+                               if (eventLock.get() == 0) {\r
+                                       onChangePartsIdentifiers();\r
+                               }\r
+                       }\r
+               };\r
+\r
+               PartsSet partsSet = partsSync.getCurrentPartsSet();\r
+               eventLock.incrementAndGet();\r
+               try {\r
+                       for (PartsCategory category : characterData.getPartsCategories()) {\r
+                               List<PartsIdentifier> partsIdentifiers = partsSet.get(category);\r
+                               int partsLen = (partsIdentifiers != null) ? partsIdentifiers\r
+                                               .size() : 0;\r
+                               boolean enable = true;\r
+                               if (partsLen < 1) {\r
+                                       partsLen = 1; // 未選択の場合でも1つは作成する.\r
+                                       enable = false; // 未選択の場合はディセーブルとする.\r
+                               }\r
+\r
+                               for (int partsIdx = 0; partsIdx < partsLen; partsIdx++) {\r
+                                       PartsIdentifier partsIdentifier = null;\r
+                                       if (partsIdentifiers != null\r
+                                                       && partsIdx < partsIdentifiers.size()) {\r
+                                               partsIdentifier = partsIdentifiers.get(partsIdx);\r
+                                       }\r
+                                       boolean lastInCategory = (partsIdx == partsLen - 1);\r
+\r
+                                       int idx = centerPnl.getComponentCount();\r
+                                       RandomChooserPanel pnl = addPartsChooserPanel(centerPnl,\r
+                                                       idx, category, lastInCategory,\r
+                                                       changePartsIdentifierListener);\r
+\r
+                                       // 未選択の場合、もしくは複数選択カテゴリの場合はランダムはディセーブルとする\r
+                                       pnl.setEnableRandom(enable\r
+                                                       && !category.isMultipleSelectable());\r
+\r
+                                       if (partsIdentifier != null) {\r
+                                               pnl.setSelectedPartsIdentifier(partsIdentifier);\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+               } finally {\r
+                       eventLock.decrementAndGet();\r
+               }\r
+\r
+               JScrollPane scr = new JScrollPane(centerPnl) {\r
+                       private static final long serialVersionUID = 1L;\r
+\r
+                       @Override\r
+                       public JScrollBar createVerticalScrollBar() {\r
+                               JScrollBar sb = super.createVerticalScrollBar();\r
+                               sb.setUnitIncrement(12);\r
+                               return sb;\r
+                       }\r
+               };\r
+               scr.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);\r
+               contentPane.add(scr, BorderLayout.CENTER);\r
+\r
+               this.actRandomAll = new AbstractAction(strings.getProperty("randomAll")) {\r
+                       private static final long serialVersionUID = 1L;\r
+\r
+                       public void actionPerformed(ActionEvent e) {\r
+                               onRandomAll();\r
+                       }\r
+               };\r
+\r
+               this.actBack = new AbstractAction(strings.getProperty("back")) {\r
+                       private static final long serialVersionUID = 1L;\r
+\r
+                       public void actionPerformed(ActionEvent e) {\r
+                               onBack();\r
+                       }\r
+               };\r
+\r
+               this.actCancel = new AbstractAction(strings.getProperty("close")) {\r
+                       private static final long serialVersionUID = 1L;\r
+\r
+                       public void actionPerformed(ActionEvent e) {\r
+                               onClose();\r
+                       }\r
+               };\r
+\r
+               JButton btnClose = new JButton(actCancel);\r
+               JButton btnRandomAll = new JButton(actRandomAll);\r
+               JButton btnBack = new JButton(actBack);\r
+\r
+               Box btnPanel = Box.createHorizontalBox();\r
+               btnPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 42));\r
+\r
+               btnPanel.add(btnRandomAll);\r
+               btnPanel.add(btnBack);\r
+               btnPanel.add(Box.createHorizontalGlue());\r
+               btnPanel.add(btnClose);\r
+\r
+               contentPane.add(btnPanel, BorderLayout.SOUTH);\r
+\r
+               JRootPane rootPane = getRootPane();\r
+               rootPane.setDefaultButton(btnRandomAll);\r
+\r
+               Toolkit tk = Toolkit.getDefaultToolkit();\r
+               InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);\r
+               ActionMap am = rootPane.getActionMap();\r
+               im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "closeDialog");\r
+               im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W,\r
+                               tk.getMenuShortcutKeyMask()), "closeDialog");\r
+               am.put("closeDialog", actCancel);\r
+\r
+               addHistory(getSelection());\r
+               updateUIState();\r
+       }\r
+\r
+       /**\r
+        * ボタンの状態を設定する.\r
+        */\r
+       protected void updateUIState() {\r
+               actBack.setEnabled(history.size() > 1);\r
+       }\r
+\r
+       /**\r
+        * ダイアログを破棄して閉じる.\r
+        */\r
+       protected void onClose() {\r
+               dispose();\r
+       }\r
+\r
+       /**\r
+        * パネル構築時、および一括ランダム選択時などでパーツのコンボボックスの選択が複数変更される場合に\r
+        * イベントを一度だけ処理するようにグループ化するためのロック.\r
+        */\r
+       private final AtomicInteger eventLock = new AtomicInteger(0);\r
+\r
+       /**\r
+        * センターパネル上に配置したランダム選択パネルのリストを取得する.<br>\r
+        * (ランダム選択パネルの個数は実行時に自由に可変できるため.)\r
+        *\r
+        * @return ランダム選択パネルのリスト\r
+        */\r
+       protected List<RandomChooserPanel> getRandomChooserPanels() {\r
+               ArrayList<RandomChooserPanel> panels = new ArrayList<RandomChooserPanel>();\r
+               int mx = centerPnl.getComponentCount();\r
+               for (int idx = 0; idx < mx; idx++) {\r
+                       Component comp = centerPnl.getComponent(idx);\r
+                       if (comp instanceof RandomChooserPanel) {\r
+                               RandomChooserPanel pnl = (RandomChooserPanel) comp;\r
+                               panels.add(pnl);\r
+                       }\r
+               }\r
+               return panels;\r
+       }\r
+\r
+       /**\r
+        * 現在選択中の状態を取得する.\r
+        *\r
+        * @return\r
+        */\r
+       protected Map<RandomChooserPanel, PartsIdentifier> getSelection() {\r
+               HashMap<RandomChooserPanel, PartsIdentifier> selection = new HashMap<RandomChooserPanel, PartsIdentifier>();\r
+\r
+               for (RandomChooserPanel pnl : getRandomChooserPanels()) {\r
+                       PartsIdentifier partsIdentifier = pnl.getSelectedPartsIdentifier();\r
+                       selection.put(pnl, partsIdentifier);\r
+               }\r
+\r
+               return selection;\r
+       }\r
+\r
+       /**\r
+        * 履歴に追加する.\r
+        *\r
+        * @param selection\r
+        */\r
+       protected void\r
+                       addHistory(Map<RandomChooserPanel, PartsIdentifier> selection) {\r
+               if (selection == null || selection.isEmpty()) {\r
+                       return;\r
+               }\r
+\r
+               // 履歴に追加する.\r
+               history.addLast(selection);\r
+\r
+               // 最大数を越えた場合は除去する\r
+               while (history.size() > maxHistory) {\r
+                       history.removeFirst();\r
+               }\r
+               updateUIState();\r
+       }\r
+\r
+       /**\r
+        * 前回の選択状態に戻す\r
+        */\r
+       protected void onBack() {\r
+               if (history.size() <= 1) {\r
+                       return;\r
+               }\r
+\r
+               // ヒストリーの直前のものを取り出す\r
+               // 先頭のものは現在表示中のものなので、2つ取り出す必要がある.\r
+               history.removeLast();\r
+               Map<RandomChooserPanel, PartsIdentifier> selection = history.getLast();\r
+\r
+               // すべてのランダム選択パネルに再適用する.\r
+               eventLock.incrementAndGet();\r
+               try {\r
+                       for (Map.Entry<RandomChooserPanel, PartsIdentifier> entry : selection\r
+                                       .entrySet()) {\r
+                               RandomChooserPanel pnl = entry.getKey();\r
+                               PartsIdentifier partsIdentifier = entry.getValue();\r
+                               pnl.setSelectedPartsIdentifier(partsIdentifier);\r
+                       }\r
+\r
+                       PartsSet partsSet = makePartsSet(selection.values());\r
+                       if (!partsSet.isEmpty()) {\r
+                               partsSync.setPartsSet(partsSet);\r
+                       }\r
+\r
+               } finally {\r
+                       eventLock.decrementAndGet();\r
+               }\r
+\r
+               updateUIState();\r
+       }\r
+\r
+       /**\r
+        * 一括ランダム選択\r
+        */\r
+       protected void onRandomAll() {\r
+               eventLock.incrementAndGet();\r
+               try {\r
+                       for (RandomChooserPanel pnl : getRandomChooserPanels()) {\r
+                               if (pnl.isEnableRandom()) {\r
+                                       // ランダム選択を有効としているものだけを対象とする.\r
+                                       pnl.selectRandom();\r
+                               }\r
+                       }\r
+                       onChangePartsIdentifiers();\r
+\r
+               } finally {\r
+                       eventLock.decrementAndGet();\r
+               }\r
+       }\r
+\r
+       /**\r
+        * パーツの選択からパーツセットを生成して返す.\r
+        *\r
+        * @param selection\r
+        * @return\r
+        */\r
+       protected PartsSet makePartsSet(Collection<PartsIdentifier> selection) {\r
+               PartsSet partsSet = new PartsSet();\r
+               for (PartsIdentifier partsIdentifier : selection) {\r
+                       if (partsIdentifier != null) {\r
+                               PartsCategory category = partsIdentifier.getPartsCategory();\r
+                               partsSet.appendParts(category, partsIdentifier, null); // 色は不問とする\r
+                       }\r
+               }\r
+               return partsSet;\r
+       }\r
+\r
+       /**\r
+        * パーツの選択が変更されたことを通知される.<br>\r
+        * 現在のランダム選択状態を、プレビューの状態に反映させる.<brr>\r
+        */\r
+       protected void onChangePartsIdentifiers() {\r
+\r
+               Map<RandomChooserPanel, PartsIdentifier> selection = getSelection();\r
+\r
+               PartsSet partsSet = makePartsSet(selection.values());\r
+               if (!partsSet.isEmpty()) {\r
+                       partsSync.setPartsSet(partsSet);\r
+                       addHistory(selection);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * アイテムごとのランダム選択パネル\r
+        *\r
+        * @author seraphy\r
+        */\r
+       protected class RandomChooserPanel extends JPanel {\r
+               private static final long serialVersionUID = 1L;\r
+\r
+               private EventListenerList listeners = new EventListenerList();\r
+\r
+               private JCheckBox label;\r
+\r
+               private JComboBox partsCombo;\r
+\r
+               private JToggleButton btnReject;\r
+\r
+               public RandomChooserPanel(final PartsCategory category,\r
+                               final boolean lastInCategory) {\r
+                       Properties strings = LocalizedResourcePropertyLoader\r
+                                       .getCachedInstance().getLocalizedProperties(\r
+                                                       STRINGS_RESOURCE);\r
+\r
+                       setBorder(BorderFactory.createCompoundBorder(\r
+                                       BorderFactory.createEmptyBorder(3, 3, 3, 3),\r
+                                       BorderFactory.createCompoundBorder(\r
+                                                       BorderFactory.createEtchedBorder(),\r
+                                                       BorderFactory.createEmptyBorder(3, 3, 3, 3))));\r
+                       setLayout(new GridBagLayout());\r
+\r
+                       GridBagConstraints gbc = new GridBagConstraints();\r
+                       gbc.gridx = 0;\r
+                       gbc.gridy = 0;\r
+                       gbc.gridheight = 1;\r
+                       gbc.gridwidth = 1;\r
+                       gbc.anchor = GridBagConstraints.EAST;\r
+                       gbc.fill = GridBagConstraints.BOTH;\r
+                       gbc.weightx = 1.;\r
+                       gbc.weighty = 0.;\r
+\r
+                       String categoryName = category.getLocalizedCategoryName();\r
+                       this.label = new JCheckBox(categoryName, true);\r
+                       add(label, gbc);\r
+\r
+                       JButton btnRandom = new JButton(new AbstractAction(\r
+                                       strings.getProperty("random")) {\r
+                               private static final long serialVersionUID = -1;\r
+\r
+                               public void actionPerformed(ActionEvent e) {\r
+                                       onClickRandom(e);\r
+                               }\r
+                       });\r
+                       gbc.gridx = 1;\r
+                       gbc.weightx = 0;\r
+                       add(btnRandom, gbc);\r
+\r
+                       ArrayList<PartsIdentifier> partsList = new ArrayList<PartsIdentifier>();\r
+                       partsList.addAll(characterData.getPartsSpecMap(category).keySet());\r
+                       Collections.sort(partsList);\r
+                       if (category.isMultipleSelectable()) {\r
+                               // 複数選択カテゴリは未選択状態が可能なため先頭に空行を入れる.\r
+                               partsList.add(0, null);\r
+                       }\r
+\r
+                       this.partsCombo = new JComboBox(\r
+                                       partsList.toArray(new PartsIdentifier[partsList.size()]));\r
+\r
+                       partsCombo.addActionListener(new ActionListener() {\r
+                               public void actionPerformed(ActionEvent e) {\r
+                                       onSelectChangePartsIdentifier(e);\r
+                               }\r
+                       });\r
+\r
+                       gbc.gridx = 0;\r
+                       gbc.gridy = 1;\r
+                       gbc.weightx = 1.;\r
+                       add(partsCombo, gbc);\r
+\r
+                       this.btnReject = new JToggleButton(new AbstractAction(\r
+                                       strings.getProperty("reject")) {\r
+                               private static final long serialVersionUID = -1;\r
+\r
+                               public void actionPerformed(ActionEvent e) {\r
+                                       onClickReject(e);\r
+                               }\r
+                       });\r
+                       gbc.gridx = 1;\r
+                       gbc.gridy = 1;\r
+                       gbc.weightx = 0;\r
+                       add(btnReject, gbc);\r
+\r
+                       if (category.isMultipleSelectable() && lastInCategory) {\r
+                               JButton btnAdd = new JButton(new AbstractAction(\r
+                                               strings.getProperty("add")) {\r
+                                       private static final long serialVersionUID = -1;\r
+\r
+                                       public void actionPerformed(ActionEvent e) {\r
+                                               onClickAdd(e);\r
+                                       }\r
+                               });\r
+                               gbc.gridx = 1;\r
+                               gbc.gridy = 2;\r
+                               gbc.weightx = 0;\r
+                               add(btnAdd, gbc);\r
+                       }\r
+\r
+                       updateButtonState();\r
+               }\r
+\r
+               public void addActionListener(ActionListener l) {\r
+                       listeners.add(ActionListener.class, l);\r
+               }\r
+\r
+               public void removeActionListener(ActionListener l) {\r
+                       listeners.remove(ActionListener.class, l);\r
+               }\r
+\r
+               public boolean isEnableRandom() {\r
+                       return label.isSelected();\r
+               }\r
+\r
+               public void setEnableRandom(boolean selected) {\r
+                       label.setSelected(selected);\r
+               }\r
+\r
+               public PartsIdentifier getSelectedPartsIdentifier() {\r
+                       return (PartsIdentifier) partsCombo.getSelectedItem();\r
+               }\r
+\r
+               public void setSelectedPartsIdentifier(PartsIdentifier partsIdentifier) {\r
+                       partsCombo.setSelectedItem(partsIdentifier);\r
+               }\r
+\r
+               protected void updateButtonState() {\r
+                       PartsIdentifier partsIdentifier = getSelectedPartsIdentifier();\r
+                       if (partsIdentifier == null) {\r
+                               btnReject.setEnabled(false);\r
+                               return;\r
+                       }\r
+                       boolean exclude = partsSync\r
+                                       .isExcludePartsIdentifier(partsIdentifier);\r
+                       btnReject.setSelected(exclude);\r
+                       btnReject.setEnabled(true);\r
+               }\r
+\r
+               protected void onSelectChangePartsIdentifier(ActionEvent e) {\r
+                       updateButtonState();\r
+\r
+                       ActionEvent evt = new ActionEvent(this,\r
+                                       ActionEvent.ACTION_PERFORMED, "selectChangePartsIdentifier");\r
+                       for (ActionListener l : listeners\r
+                                       .getListeners(ActionListener.class)) {\r
+                               l.actionPerformed(evt);\r
+                       }\r
+               }\r
+\r
+               protected void onClickReject(ActionEvent e) {\r
+                       PartsIdentifier partsIdentifier = getSelectedPartsIdentifier();\r
+                       if (partsIdentifier == null) {\r
+                               return;\r
+                       }\r
+                       boolean exclude = partsSync\r
+                                       .isExcludePartsIdentifier(partsIdentifier);\r
+                       partsSync.setExcludePartsIdentifier(partsIdentifier, !exclude);\r
+                       updateButtonState();\r
+               }\r
+\r
+               protected void onClickRandom(ActionEvent e) {\r
+                       selectRandom();\r
+               }\r
+\r
+               public void selectRandom() {\r
+                       ArrayList<PartsIdentifier> partsIdentifiers = new ArrayList<PartsIdentifier>();\r
+                       int mx = partsCombo.getItemCount();\r
+                       for (int idx = 0; idx < mx; idx++) {\r
+                               PartsIdentifier partsIdentifier = (PartsIdentifier) partsCombo\r
+                                               .getItemAt(idx);\r
+                               if (partsIdentifier != null) {\r
+                                       if (!partsSync.isExcludePartsIdentifier(partsIdentifier)) {\r
+                                               partsIdentifiers.add(partsIdentifier);\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       int len = partsIdentifiers.size();\r
+                       if (len == 0) {\r
+                               // 選択しようがないので何もしない.\r
+                               return;\r
+                       }\r
+\r
+                       Random rng = new Random();\r
+                       int selidx = rng.nextInt(len);\r
+\r
+                       setSelectedPartsIdentifier(partsIdentifiers.get(selidx));\r
+               }\r
+\r
+               protected void onClickAdd(ActionEvent e) {\r
+                       // 何もしない.\r
+               }\r
+       }\r
+\r
+       /**\r
+        * カテゴリのパーツのランダム選択パネルを作成する.<br>\r
+        * パネルが追加ボタンをもつときには、作成されたパネルにもパーツ変更リスナは適用される.<br>\r
+        *\r
+        * @param centerPnl\r
+        *            追加されるパネル\r
+        * @param addPos\r
+        *            追加する位置\r
+        * @param category\r
+        *            カテゴリ\r
+        * @param lastInCategory\r
+        *            作成するパネルに、追加ボタンをつけるか?\r
+        * @param changePartsIdentifierListener\r
+        *            パーツ選択が変わった場合のリスナ\r
+        * @return 作成されたランダム選択パネル\r
+        */\r
+       protected RandomChooserPanel addPartsChooserPanel(final Box centerPnl,\r
+                       final int addPos,\r
+                       final PartsCategory category,\r
+                       final boolean lastInCategory,\r
+                       final ActionListener changePartsIdentifierListener) {\r
+               RandomChooserPanel pnl = new RandomChooserPanel(category,\r
+                               lastInCategory) {\r
+                       private static final long serialVersionUID = 1L;\r
+\r
+                       @Override\r
+                       protected void onClickAdd(ActionEvent e) {\r
+                               int mx = centerPnl.getComponentCount();\r
+                               for (int idx = 0; idx < mx; idx++) {\r
+                                       Component comp = centerPnl.getComponent(idx);\r
+                                       if (comp.equals(this)) {\r
+                                               // 同じカテゴリのものを追加する\r
+                                               addPartsChooserPanel(centerPnl, idx + 1, category,\r
+                                                               lastInCategory, changePartsIdentifierListener);\r
+                                               centerPnl.validate();\r
+                                               // Addボタンを非表示にする.\r
+                                               ((JButton) e.getSource()).setVisible(false);\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+               };\r
+\r
+               // パーツ選択変更を通知するリスナを設定する.\r
+               pnl.addActionListener(changePartsIdentifierListener);\r
+\r
+               centerPnl.add(pnl, addPos);\r
+               return pnl;\r
+       }\r
+}\r
diff --git a/src/charactermanaj/util/JavaVersionUtils.java b/src/charactermanaj/util/JavaVersionUtils.java
new file mode 100644 (file)
index 0000000..4e9d830
--- /dev/null
@@ -0,0 +1,65 @@
+package charactermanaj.util;\r
+\r
+\r
+public final class JavaVersionUtils {\r
+\r
+       private JavaVersionUtils() {\r
+               super();\r
+       }\r
+\r
+       /**\r
+        * Javaの簡易なバージョンを取得する.<br>\r
+        * 不明な場合は0を返す.<br>\r
+        * \r
+        * @return バージョン\r
+        */\r
+       public static double getJavaVersion() {\r
+               try {\r
+                       String version = System.getProperty("java.version");\r
+                       String[] versions = version.split("\\.");\r
+                       if (versions.length > 2) {\r
+                               return Double.valueOf(versions[0] + "." + versions[1]);\r
+                       }\r
+               } catch (RuntimeException ex) {\r
+                       ex.printStackTrace();\r
+               }\r
+               return 0d;\r
+       }\r
+\r
+       /**\r
+        * Javaの詳細なバージョンを取得する. メジャー・マイナー・メンテナンス・アップデートの4要素を返す.<br>\r
+        * \r
+        * @return\r
+        */\r
+       public static int[] getJavaVersions() {\r
+               return getJavaVersions(System.getProperty("java.version"));\r
+       }\r
+\r
+       private static int[] getJavaVersions(String version) {\r
+               int[] ret = new int[4];\r
+               try {\r
+                       int posIdentifier = version.indexOf('-');\r
+                       if (posIdentifier >= 0) {\r
+                               version = version.substring(0, posIdentifier);\r
+                       }\r
+\r
+                       int posUpdate = version.indexOf("_");\r
+                       int update = 0;\r
+                       if (posUpdate >= 0) {\r
+                               update = Integer.parseInt(version.substring(posUpdate + 1));\r
+                               version = version.substring(0, posUpdate);\r
+                       }\r
+\r
+                       String[] versions = version.split("\\.");\r
+\r
+                       for (int idx = 0; idx < 3 && idx < versions.length; idx++) {\r
+                               ret[idx] = Integer.parseInt(versions[idx]);\r
+                       }\r
+                       ret[3] = update;\r
+\r
+               } catch (RuntimeException ex) {\r
+                       ex.printStackTrace();\r
+               }\r
+               return ret;\r
+       }\r
+}\r