OSDN Git Service

アプリケーション設定のリセット機能の追加
authorseraphy <seraphy@users.osdn.me>
Fri, 14 Dec 2018 19:15:43 +0000 (04:15 +0900)
committerseraphy <seraphy@users.osdn.me>
Fri, 14 Dec 2018 19:15:43 +0000 (04:15 +0900)
src/main/java/charactermanaj/model/AppConfig.java
src/main/java/charactermanaj/ui/AppConfigDialog.java
src/main/java/charactermanaj/util/BeanPropertiesUtilities.java
src/main/resources/languages/appconfigdialog.xml
src/main/resources/languages/appconfigdialog_ja.xml
src/main/resources/languages/appconfigdialog_zh.xml

index 019095f..f7bfeff 100644 (file)
@@ -14,6 +14,8 @@ import java.net.URI;
 import java.net.URL;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
@@ -222,15 +224,12 @@ public final class AppConfig {
        public List<URI> getCandidateURIs() throws IOException {
                List<URI> uris = new ArrayList<URI>();
                // リソース中の既定 (ロケール識別あり)
-               for (File localizedFile : expandLocalizedSuffix(new File(getClass()
-                               .getResource("/" + CONFIG_NAME).getPath()), null)) {
-                       uris.add(localizedFile.toURI());
-               }
+               getAppConfigResourceURI(uris);
 
+               // システムプロパティでappConfig.xmlを明示している場合は、それを読み込む。
+               // (appConfigFileシステムプロパティが空の場合は、リソース埋め込みの既定の設定だけをよみこむ)
                String specifiedAppConfig = System.getProperty("appConfigFile");
                if (specifiedAppConfig != null) {
-                       // システムプロパティでappConfig.xmlを明示している場合は、それを読み込む。
-                       // (appConfigFileシステムプロパティが空の場合は、リソース埋め込みの既定の設定だけをよみこむ)
                        if (specifiedAppConfig.trim().length() > 0) {
                                File specifiedAppConfigFile = new File(specifiedAppConfig);
                                uris.add(specifiedAppConfigFile.toURI());
@@ -252,6 +251,17 @@ public final class AppConfig {
        }
 
        /**
+        * リソース上のAppConfigの読み込みURIを追記して返す
+        * @param uris
+        */
+       protected void getAppConfigResourceURI(List<URI> uris) {
+               for (File localizedFile : expandLocalizedSuffix(new File(getClass()
+                               .getResource("/" + CONFIG_NAME).getPath()), null)) {
+                       uris.add(localizedFile.toURI());
+               }
+       }
+
+       /**
         * 保存先の試行順序ごとのファイルのリスト。
         *
         * @return 保存先(優先順)
@@ -285,9 +295,25 @@ public final class AppConfig {
         * 存在しないか、読み取りに失敗した場合は、該当ファイルはスキップされる.<br>
         */
        public void loadConfig() {
+               try {
+                       loadConfig(getCandidateURIs());
+               } catch (IOException ex) {
+                       throw new RuntimeException("appConfig.xml loading failed.", ex);
+               }
+       }
+
+       /**
+        * プロパティをロードする.<br>
+        * 存在しないか、読み取りに失敗した場合は、該当ファイルはスキップされる.<br>
+        * @param uris パラメーターの読み込み順
+        */
+       public void loadConfig(List<URI> uris) {
+               if (uris == null) {
+                       uris = Collections.emptyList();
+               }
                Properties config = new Properties();
                try {
-                       for (URI uri : getCandidateURIs()) {
+                       for (URI uri : uris) {
                                if (uri == null) {
                                        continue; // リソースがない場合はnullになる
                                }
@@ -321,8 +347,6 @@ public final class AppConfig {
                                }
                        }
 
-               } catch (IOException ex) {
-                       throw new RuntimeException("appConfig.xml loading failed.", ex);
                } catch (RuntimeException ex) {
                        throw new RuntimeException("appConfig.xml loading failed.", ex);
                }
@@ -373,6 +397,33 @@ public final class AppConfig {
        }
 
        /**
+        * アプリケーション設定値のデフォルト値(リソース上のAppConfigのみ)を取得する
+        * @return
+        */
+       public static Map<String, Object> getDefaultProperties() {
+               PropertyAccessorMap<AppConfig> accessorMap = BeanPropertiesUtilities.getPropertyAccessorMap(AppConfig.class);
+
+               AppConfig dummy = new AppConfig(); // アプリケーションから参照されないダミーのインスタンスを作成する.
+
+               // リソース上のAppConfigのみ読み込み
+               List<URI> uris = new ArrayList<URI>();
+               dummy.getAppConfigResourceURI(uris);
+               dummy.loadConfig(uris);
+
+               accessorMap.setBean(dummy);
+
+               // 読み込んだプロパティの書き出し
+               Map<String, Object> defMap = new HashMap<String, Object>();
+               for (Map.Entry<String, PropertyAccessor> propEntry : accessorMap.entrySet()) {
+                       String name = propEntry.getKey();
+                       PropertyAccessor accessor = propEntry.getValue();
+                       Object value = accessor.getValue();
+                       defMap.put(name,  value);
+               }
+               return defMap;
+       }
+
+       /**
         * Propertiesの値を設定した場合に設定できない項目があるかチェックする.<br>
         * このメソッドを呼び出しても、アプリケーション設定自身は何も影響されない.<br>
         *
@@ -415,7 +466,7 @@ public final class AppConfig {
                }
                HashSet<String> rejectedNames = new HashSet<String>();
 
-               PropertyAccessorMap accessorMap = BeanPropertiesUtilities.getPropertyAccessorMap(AppConfig.class);
+               PropertyAccessorMap<AppConfig> accessorMap = BeanPropertiesUtilities.getPropertyAccessorMap(AppConfig.class);
                accessorMap.setBean(bean);
 
                for (Map.Entry<String, Object> propEntry : props.entrySet()) {
index 52f7698..ce9bfae 100644 (file)
@@ -379,6 +379,16 @@ public class AppConfigDialog extends JDialog {
                                onSetupLocalization();
                        }
                };
+               Action actResetSettings = new AbstractAction(strings.getProperty("btn.resetSettingsToDefault")) {
+                       private static final long serialVersionUID = 1L;
+                       public void actionPerformed(ActionEvent e) {
+                               onResetSettings();
+                       }
+               };
+
+               Box pnlButtons = Box.createHorizontalBox();
+               pnlButtons.add(new JButton(actLocalization));
+               pnlButtons.add(new JButton(actResetSettings));
 
                chkResetDoNotAskAgain = new JCheckBox(strings.getProperty("chk.askForCharactersDir"));
                chkResetDoNotAskAgain.addActionListener(new ActionListener() {
@@ -413,7 +423,7 @@ public class AppConfigDialog extends JDialog {
                gbc.ipady = 0;
                gbc.weightx = 1.;
                gbc.weighty = 0.;
-               btnPanel.add(new JButton(actLocalization), gbc);
+               btnPanel.add(pnlButtons, gbc);
 
                gbc.gridx = 0;
                gbc.gridy = 2;
@@ -627,7 +637,7 @@ public class AppConfigDialog extends JDialog {
                                .getLocalizedProperties("languages/appconfigdialog");
 
                // AppConfigへのアクセッサを取得する
-               PropertyAccessorMap accessorMap = BeanPropertiesUtilities.getPropertyAccessorMap(AppConfig.class);
+               PropertyAccessorMap<AppConfig> accessorMap = BeanPropertiesUtilities.getPropertyAccessorMap(AppConfig.class);
 
                AppConfig appConfig = AppConfig.getInstance();
                accessorMap.setBean(appConfig);
@@ -696,6 +706,29 @@ public class AppConfigDialog extends JDialog {
        }
 
        /**
+        * 設定値を初期化する
+        */
+       protected void onResetSettings() {
+               Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
+                               .getLocalizedProperties("languages/appconfigdialog");
+               if (JOptionPane.showConfirmDialog(this, strings.getProperty("confirm.resetSettingsToDefault"),
+                               strings.getProperty("confirm.close.caption"), JOptionPane.YES_NO_OPTION,
+                               JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION) {
+                       return;
+               }
+
+               Map<String, Object> defMap = AppConfig.getDefaultProperties();
+               for (AppConfigRow rowItem : appConfigTableModel.getItems()) {
+                       String name = rowItem.getName();
+                       if (defMap.containsKey(name)) {
+                               Object value = defMap.get(name);
+                               rowItem.setValue(value);
+                       }
+               }
+               appConfigTableModel.fireTableDataChanged();
+       }
+
+       /**
         * ローカライズリソースをユーザディレクトリ上に展開する.
         */
        protected void onSetupLocalization() {
index 4b740df..0f8f0e0 100644 (file)
@@ -82,22 +82,22 @@ public final class BeanPropertiesUtilities {
         * プロパティへのアクセッサをまとめたもの。
         * 実際にビーンにアクセスするためには、{@link #setBean(Object)}でビーンを設定する必要がある。
         */
-       public static class PropertyAccessorMap extends AbstractMap<String, PropertyAccessor> {
+       public static class PropertyAccessorMap<T> extends AbstractMap<String, PropertyAccessor> {
 
-               private final BeanHolder beanHolder;
+               private final BeanHolder<T> beanHolder;
 
                private final Map<String, PropertyAccessor> accessorMap;
 
-               public PropertyAccessorMap(Map<String, PropertyAccessor> accessorMap, BeanHolder beanHolder) {
+               public PropertyAccessorMap(Map<String, PropertyAccessor> accessorMap, BeanHolder<T> beanHolder) {
                        this.accessorMap = accessorMap;
                        this.beanHolder = beanHolder;
                }
 
-               public Object getBean() {
+               public T getBean() {
                        return beanHolder.getBean();
                }
 
-               public void setBean(Object bean) {
+               public void setBean(T bean) {
                        beanHolder.setBean(bean);
                }
 
@@ -111,15 +111,15 @@ public final class BeanPropertiesUtilities {
         * アクセッサからビーンを間接参照するためのホルダ。
         * (実際にビーンにアクセスするまでビーンの設定を遅延させるため。)
         */
-       public static class BeanHolder {
+       public static class BeanHolder<T> {
 
-               private Object bean;
+               private T bean;
 
-               public Object getBean() {
+               public T getBean() {
                        return bean;
                }
 
-               public void setBean(Object bean) {
+               public void setBean(T bean) {
                        this.bean = bean;
                }
        }
@@ -161,12 +161,12 @@ public final class BeanPropertiesUtilities {
         * @return
         * @throws IntrospectionException
         */
-       public static PropertyAccessorMap getPropertyAccessorMap(final Class<?> beanClass) {
+       public static <T> PropertyAccessorMap<T> getPropertyAccessorMap(final Class<T> beanClass) {
                if (beanClass == null) {
                        throw new NullPointerException("beanClass");
                }
                Map<String, PropertyAccessor> accessorMap = new TreeMap<String, PropertyAccessor>();
-               final BeanHolder beanHolder = new BeanHolder();
+               final BeanHolder<T> beanHolder = new BeanHolder<T>();
 
                BeanInfo beanInfo;
                try {
@@ -226,8 +226,8 @@ public final class BeanPropertiesUtilities {
                                        }
 
                                        @Override
-                                       public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
-                                               T annt = mtdReader.getAnnotation(annotationClass);
+                                       public <E extends Annotation> E getAnnotation(Class<E> annotationClass) {
+                                               E annt = mtdReader.getAnnotation(annotationClass);
                                                if (annt == null) {
                                                        annt = mtdWriter.getAnnotation(annotationClass);
                                                }
@@ -237,7 +237,7 @@ public final class BeanPropertiesUtilities {
                                accessorMap.put(name, accessor);
                        }
                }
-               return new PropertyAccessorMap(accessorMap, beanHolder);
+               return new PropertyAccessorMap<T>(accessorMap, beanHolder);
        }
 
        /**
@@ -257,7 +257,8 @@ public final class BeanPropertiesUtilities {
                }
                HashSet<String> rejectNames = new HashSet<String>();
 
-               PropertyAccessorMap accessorMap = getPropertyAccessorMap(bean.getClass());
+               @SuppressWarnings("unchecked")
+               PropertyAccessorMap<Object> accessorMap = (PropertyAccessorMap<Object>)getPropertyAccessorMap(bean.getClass());
                accessorMap.setBean(bean);
 
                for (Map.Entry<String, PropertyAccessor> accessorEntry : accessorMap.entrySet()) {
@@ -348,7 +349,9 @@ public final class BeanPropertiesUtilities {
                }
 
                try {
-                       PropertyAccessorMap accessorMap = getPropertyAccessorMap(bean.getClass());
+                       @SuppressWarnings("unchecked")
+                       PropertyAccessorMap<Object> accessorMap = (PropertyAccessorMap<Object>) getPropertyAccessorMap(
+                                       bean.getClass());
                        accessorMap.setBean(bean);
 
                        for (Map.Entry<String, PropertyAccessor> accessorEntry : accessorMap.entrySet()) {
index 19d707e..bbb4f14 100644 (file)
@@ -23,6 +23,9 @@
 If the file already exists, the file is overwritten.]]></entry>
 <entry key="confirm.setupLocalization.caption">Confirm</entry>
 
+<entry key="btn.resetSettingsToDefault">Reset settings to default.</entry>
+<entry key="confirm.resetSettingsToDefault">Are you sure you want to reset the setting?</entry>
+
 <entry key="compressionQuality">01;Compression Quality</entry>
 <entry key="enablePNGSupportForWindows">02;Use the transparency image in Clipboard.(Windows/OSX)</entry>
 <entry key="zipNameEncoding">03;ZIP File Encoding</entry>
index 37196c8..035e97f 100644 (file)
@@ -23,6 +23,9 @@
 既にファイルが存在する場合は上書きされます。]]></entry>
 <entry key="confirm.setupLocalization.caption">確認</entry>
 
+<entry key="btn.resetSettingsToDefault">設定のリセット</entry>
+<entry key="confirm.resetSettingsToDefault">設定をリセットしてもよろしいですか?</entry>
+
 <entry key="compressionQuality">01;JPEG圧縮時のクオリティ(1が最大、0.1が最小)</entry>
 <entry key="enablePNGSupportForWindows">02;クリップボードの透過サポートを有効にする.(Windows/OSX)</entry>
 <entry key="zipNameEncoding">03;ZIPファイルに格納されているファイル名のエンコーディング(csWindows31Jが標準)</entry>
index 0c939cf..5b91eb7 100644 (file)
@@ -23,6 +23,9 @@
 如果文件已存在则会被覆盖]]></entry>
 <entry key="confirm.setupLocalization.caption">确认</entry>
 
+<entry key="btn.resetSettingsToDefault">将设置重置为默认值</entry>
+<entry key="confirm.resetSettingsToDefault">您确定要重置设置吗?</entry>
+
 <entry key="compressionQuality">01;JPEG压缩质量(1最好,0.1最差)</entry>
 <entry key="enablePNGSupportForWindows">02;复制到剪贴板时使用透明图像(Windows/OSX)</entry>
 <entry key="zipNameEncoding">03;ZIP解码(默认为csWindows31J)</entry>