OSDN Git Service

019095f18a711a723397a2cb8383c42e1c8ab0c0
[charactermanaj/CharacterManaJ.git] / src / main / java / charactermanaj / model / AppConfig.java
1 package charactermanaj.model;
2
3 import java.awt.Color;
4 import java.beans.PropertyChangeListener;
5 import java.beans.PropertyChangeSupport;
6 import java.io.BufferedOutputStream;
7 import java.io.File;
8 import java.io.FileNotFoundException;
9 import java.io.FileOutputStream;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.io.OutputStream;
13 import java.net.URI;
14 import java.net.URL;
15 import java.nio.charset.Charset;
16 import java.util.ArrayList;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Locale;
20 import java.util.Map;
21 import java.util.Properties;
22 import java.util.Set;
23 import java.util.logging.Level;
24 import java.util.logging.Logger;
25 import java.util.regex.Pattern;
26
27 import charactermanaj.util.ApplicationLogHandler;
28 import charactermanaj.util.BeanPropertiesUtilities;
29 import charactermanaj.util.BeanPropertiesUtilities.PropertyAccessor;
30 import charactermanaj.util.BeanPropertiesUtilities.PropertyAccessorMap;
31 import charactermanaj.util.ConfigurationDirUtilities;
32
33 /**
34  * アプリケーションの全域にわたる設定.<br>
35  * アプリケーション設定は、クラスパス上のリソース、コートベース直下のappConfig.xml、ユーザーごとのappConfig.xmlの順に読み込まれます.<br>
36  * 設定値は{@link BeanPropertiesUtilities}によってXMLプロパティファイルとして永続化されます。<br>
37  *
38  * @author seraphy
39  * @see BeanPropertiesUtilities
40  */
41 public final class AppConfig {
42
43         /**
44          * アプリケーション設定ファイルの名前
45          */
46         private static final String CONFIG_NAME = "appConfig.xml";
47
48         /**
49          * 全ユーザー用キャラクターディレクトリのシステムプロパティのキー名.<br>
50          */
51         public static final String COMMON_CHARACTER_DIR_PROPERTY_NAME = "character.dir";
52
53         /**
54          * 開発用仕様バージョン番号
55          */
56         private static final String DEFAULT_SPECIFICATION_VERSION = "1.0";
57
58
59         /**
60          * ロガー
61          */
62         private static final Logger logger = Logger.getLogger(AppConfig.class.getName());
63
64
65         /**
66          * シングルトンインスタンス
67          */
68         private static final AppConfig singleton = new AppConfig();
69
70         /**
71          * プロパティ変更リスナのサポート
72          */
73         private final PropertyChangeSupport propChangeSupport = new PropertyChangeSupport(this);
74
75
76         public void addPropertyChangeListener(PropertyChangeListener listener) {
77                 propChangeSupport.addPropertyChangeListener(listener);
78         }
79
80         public void removePropertyChangeListener(PropertyChangeListener listener) {
81                 propChangeSupport.removePropertyChangeListener(listener);
82         }
83
84         public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
85                 propChangeSupport.addPropertyChangeListener(propertyName, listener);
86         }
87
88         public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
89                 propChangeSupport.removePropertyChangeListener(propertyName, listener);
90         }
91
92         /**
93          * インスタンスを取得する.
94          *
95          * @return インスタンス
96          */
97         public static AppConfig getInstance() {
98                 return singleton;
99         }
100
101         /**
102          * プライベートコンストラクタ
103          */
104         private AppConfig() {
105                 loadAppVersions();
106         }
107
108         private String implementationVersion;
109
110         private String specificationVersion;
111
112         /**
113          * 実装バージョンを取得する.<br>
114          * ビルドされたjarパッケージからバージョン情報を取得する.<br>
115          * クラスパスの実行からのバージョンは常に「develop」となる.<br>
116          *
117          * @return 実装バージョン
118          */
119         public String getImplementationVersion() {
120                 return implementationVersion;
121         }
122
123         /**
124          * 仕様バージョンを取得する.<br>
125          * ビルドされたjarパッケージからバージョン情報を取得する.<br>
126          * クラスパスの実行からのバージョンは常に「develop」となる.<br>
127          *
128          * @return 仕様バージョン
129          */
130         public String getSpecificationVersion() {
131                 return specificationVersion;
132         }
133
134         /**
135          * ビルドされたjarパッケージからバージョン情報を取得する.<br>
136          * クラスパスの実行からのバージョンは常に「develop」となる.<br>
137          */
138         private void loadAppVersions() {
139                 Package pak = this.getClass().getPackage();
140                 String implementationVersion = "develop";
141                 String specificationVersion = DEFAULT_SPECIFICATION_VERSION;
142                 if (pak != null) {
143                         String vInfo = pak.getImplementationVersion();
144                         if (vInfo != null && implementationVersion.trim().length() > 0) {
145                                 implementationVersion = vInfo.trim();
146                         }
147                         String specVInfo = pak.getSpecificationVersion();
148                         if (specVInfo != null && specVInfo.trim().length() > 0) {
149                                 specificationVersion = specVInfo.trim();
150                         }
151                 }
152
153                 this.implementationVersion = implementationVersion;
154                 this.specificationVersion = specificationVersion;
155         }
156
157         /**
158          * 設定ファイルのロケール固有版へのファイル末尾の修飾文字列を読み込み順に取得する.
159          * @param locale ロケール、nullの場合はデフォルト
160          * @return ロケールを表すファイル末尾の修飾文字列の読み込み順のリスト
161          */
162         private String[] getLocalizedSuffix(Locale locale) {
163                 if (locale == null) {
164                         locale = Locale.getDefault();
165                 }
166
167                 String language = locale.getLanguage();
168                 String country = locale.getCountry();
169                 String variant = locale.getVariant();
170
171                 return new String[] {
172                         "",
173                         "_" + language,
174                         "_" + language + "_" + country,
175                         "_" + language + "_" + country + "_" + variant,
176                 };
177         }
178
179         /**
180          * 指定されたファイル名の拡張子の前にロケール固有の修飾文字列を付与したリスト作成して返す.
181          * @param base ファイル名
182          * @param locale ロケール、nullの場合はデフォルト
183          * @return ロケールの検索順序でのロケール固有の修飾文字列が付与されたファイルのリスト
184          */
185         private List<File> expandLocalizedSuffix(File base, Locale locale) {
186                 String path = base.getPath();
187
188                 int pt = path.lastIndexOf(".");
189                 String left, right;
190                 if (pt >= 0) {
191                         left = path.substring(0, pt);
192                         right = path.substring(pt);
193
194                 } else {
195                         left = path;
196                         right = "";
197                 }
198
199                 ArrayList<File> files = new ArrayList<File>();
200                 for (String suffix : getLocalizedSuffix(locale)) {
201                         String newPath = left + suffix + right;
202                         //System.out.println("newpath=" + newPath);
203                         files.add(new File(newPath));
204                 }
205                 return files;
206         }
207
208         /**
209          * 設定ファイルの読み込み順序で、読み込むべきURIのリストを返す.<br>
210          * <ul>
211          * <li>(1) リソース上の/appConfig.xml</li>
212          * <li>(2) appConfigFileシステムプロパティで指定されたファイル</li>
213          * <li>(3) コードベース下のappConfig.xml</li>
214          * <li>(4) アプリケーションデータ保存先のappConfig.xml</li>
215          * </ul>
216          * appConfigFileシステムプロパティがある場合は、(1)(2)の順。 <br>
217          * 指定がない場合は、(1)(3)(4)の順に読み取る.<br>
218          *
219          * @return 優先順位での設定ファイルの読み込み先URIのリスト
220          * @throws IOException
221          */
222         public List<URI> getCandidateURIs() throws IOException {
223                 List<URI> uris = new ArrayList<URI>();
224                 // リソース中の既定 (ロケール識別あり)
225                 for (File localizedFile : expandLocalizedSuffix(new File(getClass()
226                                 .getResource("/" + CONFIG_NAME).getPath()), null)) {
227                         uris.add(localizedFile.toURI());
228                 }
229
230                 String specifiedAppConfig = System.getProperty("appConfigFile");
231                 if (specifiedAppConfig != null) {
232                         // システムプロパティでappConfig.xmlを明示している場合は、それを読み込む。
233                         // (appConfigFileシステムプロパティが空の場合は、リソース埋め込みの既定の設定だけをよみこむ)
234                         if (specifiedAppConfig.trim().length() > 0) {
235                                 File specifiedAppConfigFile = new File(specifiedAppConfig);
236                                 uris.add(specifiedAppConfigFile.toURI());
237                         }
238
239                 } else {
240                         // システムプロパティて明示していない場合は、まずコードベースを使用する.(ロケール識別あり)
241                         File codeBase = ConfigurationDirUtilities.getApplicationBaseDir();
242                         for (File localizedFile : expandLocalizedSuffix(new File(codeBase,
243                                         CONFIG_NAME).getCanonicalFile(), null)) {
244                                 uris.add(localizedFile.toURI());
245                         }
246
247                         // システムプロパティて明示していない場合は、次にユーザディレクトリを使用する.
248                         File userDataDir = ConfigurationDirUtilities.getUserDataDir();
249                         uris.add(new File(userDataDir, CONFIG_NAME).toURI());
250                 }
251                 return uris;
252         }
253
254         /**
255          * 保存先の試行順序ごとのファイルのリスト。
256          *
257          * @return 保存先(優先順)
258          */
259         public List<File> getPrioritySaveFileList() {
260                 ArrayList<File> saveFiles = new ArrayList<File>();
261
262                 String specifiedAppConfig = System.getProperty("appConfigFile");
263                 if (specifiedAppConfig != null) {
264                         // システムプロパティでappConfig.xmlを明示している場合
265                         if (specifiedAppConfig.trim().length() > 0) {
266                                 File specifiedAppConfigFile = new File(specifiedAppConfig);
267                                 if (!specifiedAppConfigFile.exists()
268                                                 || specifiedAppConfigFile.canWrite()) {
269                                         // まだ存在しないか、書き込み可能である場合のみ候補とする.
270                                         saveFiles.add(specifiedAppConfigFile);
271                                 }
272                         }
273                 } else {
274                         // システムプロパティappConfigFileがなければユーザディレクトリへ書き込む
275                         // ユーザディレクトリは常に候補とする.
276                         File userDataDir = ConfigurationDirUtilities.getUserDataDir();
277                         saveFiles.add(new File(userDataDir, CONFIG_NAME));
278                 }
279
280                 return saveFiles;
281         }
282
283         /**
284          * プロパティをロードする.<br>
285          * 存在しないか、読み取りに失敗した場合は、該当ファイルはスキップされる.<br>
286          */
287         public void loadConfig() {
288                 Properties config = new Properties();
289                 try {
290                         for (URI uri : getCandidateURIs()) {
291                                 if (uri == null) {
292                                         continue; // リソースがない場合はnullになる
293                                 }
294                                 // ファイルの実在チェック (チェックできる場合のみ)
295                                 if ("file".equals(uri.getScheme())) {
296                                         File file = new File(uri);
297                                         if (!file.exists()) {
298                                                 logger.log(Level.CONFIG, "appConfig.xml is not found.:" + file);
299                                                 continue;
300                                         }
301                                 }
302                                 // appConfig.xmlの読み込みを行う.
303                                 // Properties#loadFromXML() はXMLからキーを読み取り、既存のキーに対して上書きする.
304                                 // XMLに存在しないキーは読み込み前のままなので、繰り返し呼び出すことで「重ね合わせ」することができる.
305                                 try {
306                                         URL resourceURL = uri.toURL();
307                                         InputStream is = resourceURL.openStream();
308                                         try {
309                                                 config.loadFromXML(is);
310                                                 logger.log(Level.CONFIG, "appConfig.xml is loaded.:" + uri);
311                                         } finally {
312                                                 is.close();
313                                         }
314
315                                 } catch (FileNotFoundException ex) {
316                                         logger.log(Level.CONFIG, "appConfig.xml is not found.: " + uri, ex);
317                                         // 無視する (無い場合は十分にありえるので「情報」レベルでログ。)
318                                 } catch (Exception ex) {
319                                         logger.log(Level.WARNING, "appConfig.xml loading failed.: " + uri, ex);
320                                         // 無視する
321                                 }
322                         }
323
324                 } catch (IOException ex) {
325                         throw new RuntimeException("appConfig.xml loading failed.", ex);
326                 } catch (RuntimeException ex) {
327                         throw new RuntimeException("appConfig.xml loading failed.", ex);
328                 }
329                 BeanPropertiesUtilities.loadFromProperties(this, config);
330         }
331
332         /**
333          * プロパティをアプリケーションデータの指定した保存先に保存する.
334          *
335          * @throws IOException
336          *             保存に失敗した場合
337          */
338         public void saveConfig(List<File> prioritySaveFiles) throws IOException {
339                 Properties config = getProperties();
340                 IOException oex = null;
341                 for (File configStore : prioritySaveFiles) {
342                         try {
343                                 OutputStream os = new BufferedOutputStream(
344                                                 new FileOutputStream(configStore));
345                                 try {
346                                         config.storeToXML(os, CONFIG_NAME, "UTF-8");
347                                         return; // 成功した時点で終了
348
349                                 } finally {
350                                         os.close();
351                                 }
352
353                         } catch (IOException ex) {
354                                 logger.log(Level.WARNING, "アプリケーション設定の保存に失敗しました" + ex, ex);
355                                 oex = ex;
356                         }
357                 }
358
359                 // 例外が発生していれば、最後の例外を返す.
360                 if (oex != null) {
361                         throw oex;
362                 }
363         }
364
365         /**
366          * プロパティをアプリケーションデータの保存先に保存する.
367          *
368          * @throws IOException
369          *             保存に失敗した場合
370          */
371         public void saveConfig() throws IOException {
372                 saveConfig(getPrioritySaveFileList());
373         }
374
375         /**
376          * Propertiesの値を設定した場合に設定できない項目があるかチェックする.<br>
377          * このメソッドを呼び出しても、アプリケーション設定自身は何も影響されない.<br>
378          *
379          * @param props
380          *            適用するプロパティ
381          * @return 設定できなかったプロパティキーのコレクション、問題なければ空が返される.
382          */
383         public static Set<String> checkProperties(Map<String, Object> props) {
384                 if (props == null) {
385                         throw new IllegalArgumentException();
386                 }
387                 AppConfig dummy = new AppConfig(); // アプリケーションから参照されないダミーのインスタンスを作成する.
388                 return update(props, dummy);
389         }
390
391
392         /**
393          * Propertiesの値で設定を更新する.<br>
394          *
395          * @param props
396          *            適用するプロパティ
397          * @return 設定できなかったプロパティキーのコレクション、問題なければ空が返される.
398          */
399         public Set<String> update(Map<String, Object> props) {
400                 return update(props, this);
401         }
402
403         /**
404          * Propertiesの値で設定を更新する.<br>
405          *
406          * @param props
407          *            適用するプロパティ
408          * @param bean
409          *            適用するAppConfigのインスタンス(ドライランと本番の切り替え用)
410          * @return 設定できなかったプロパティキーのコレクション、問題なければ空が返される.
411          */
412         private static Set<String> update(Map<String, Object>  props, AppConfig bean) {
413                 if (props == null) {
414                         throw new IllegalArgumentException();
415                 }
416                 HashSet<String> rejectedNames = new HashSet<String>();
417
418                 PropertyAccessorMap accessorMap = BeanPropertiesUtilities.getPropertyAccessorMap(AppConfig.class);
419                 accessorMap.setBean(bean);
420
421                 for (Map.Entry<String, Object> propEntry : props.entrySet()) {
422                         String name = propEntry.getKey();
423                         Object value = propEntry.getValue();
424
425                         PropertyAccessor accessor = accessorMap.get(name);
426                         if (accessor == null) {
427                                 // プロパティがない
428                                 rejectedNames.add(name);
429                                 continue;
430                         }
431
432                         Class<?> propertyType = accessor.getPropertyType();
433                         if (propertyType.isPrimitive() && value == null) {
434                                 // プリミティブ型なのにnullは入れられない
435                                 rejectedNames.add(name);
436                                 continue;
437                         }
438
439                         try {
440                                 accessor.setValue(value);
441
442                         } catch (Exception ex) {
443                                 // 何らかの理由でプロパティの設定に失敗している場合
444                                 rejectedNames.add(name);
445                                 logger.log(Level.WARNING, "invalid propery: " + name + " /val=" + value, ex);
446                                 continue;
447                         }
448                 }
449                 return rejectedNames;
450         }
451
452         /**
453          * このアプリケーション設定をプロパティに書き出して返します.<br>
454          *
455          * @return プロパティ
456          */
457         public Properties getProperties() {
458                 Properties config = new Properties();
459                 BeanPropertiesUtilities.saveToProperties(this, config);
460                 return config;
461         }
462
463
464         /**
465          * プロファイル選択ダイアログのプロファイルのサンプルイメージの背景色
466          *
467          * @return サンプルイメージの背景色
468          */
469         public Color getSampleImageBgColor() {
470                 return sampleImageBgColor;
471         }
472
473         public static final String SAMPLE_IMAGE_BG_COLOR = "sampleImageBgColor";
474
475         public void setSampleImageBgColor(Color sampleImageBgColor) {
476                 if (sampleImageBgColor == null) {
477                         throw new IllegalArgumentException();
478                 }
479                 Color old = this.sampleImageBgColor;
480                 if (old == null ? sampleImageBgColor != null : !old.equals(sampleImageBgColor)) {
481                         this.sampleImageBgColor = sampleImageBgColor;
482                         propChangeSupport.firePropertyChange(SAMPLE_IMAGE_BG_COLOR, old, sampleImageBgColor);
483                 }
484         }
485
486         private Color sampleImageBgColor = Color.white;
487
488
489         /**
490          * デフォルトのイメージ背景色を取得する.
491          *
492          * @return デフォルトのイメージ背景色
493          */
494         public Color getDefaultImageBgColor() {
495                 return defaultImageBgColor;
496         }
497
498         public static final String DEFAULT_IMAGE_BG_COLOR = "defaultImageBgColor";
499
500         public void setDefaultImageBgColor(Color defaultImageBgColor) {
501                 if (defaultImageBgColor == null) {
502                         throw new IllegalArgumentException();
503                 }
504                 Color old = this.defaultImageBgColor;
505                 if (old == null ? defaultImageBgColor != null : !old.equals(defaultImageBgColor)) {
506                         this.defaultImageBgColor = defaultImageBgColor;
507                         propChangeSupport.firePropertyChange(DEFAULT_IMAGE_BG_COLOR, old, defaultImageBgColor);
508                 }
509         }
510
511         private Color defaultImageBgColor = Color.white;
512
513         /**
514          * 使用中アイテムの背景色を取得する.
515          *
516          * @return 使用中アイテムの背景色
517          */
518         public Color getCheckedItemBgColor() {
519                 return checkedItemBgColor;
520         }
521
522         public static final String CHECKED_ITEM_BG_COLOR = "checkedItemBgColor";
523
524         public void setCheckedItemBgColor(Color checkedItemBgColor) {
525                 if (checkedItemBgColor == null) {
526                         throw new IllegalArgumentException();
527                 }
528                 Color old = this.checkedItemBgColor;
529                 if (old == null ? checkedItemBgColor != null : !old.equals(checkedItemBgColor)) {
530                         this.checkedItemBgColor = checkedItemBgColor;
531                         propChangeSupport.firePropertyChange(CHECKED_ITEM_BG_COLOR, old, checkedItemBgColor);
532                 }
533         }
534
535         private Color checkedItemBgColor = Color.cyan.brighter();
536
537
538         /**
539          *  選択アイテムの背景色を取得する
540          *
541          * @return 選択アイテムの背景色
542          */
543         public Color getSelectedItemBgColor() {
544                 return selectedItemBgColor;
545         }
546
547         public static final String SELECTED_ITEM_BG_COLOR = "selectedItemBgColor";
548
549         public void setSelectedItemBgColor(Color selectedItemBgColor) {
550                 if (selectedItemBgColor == null) {
551                         throw new IllegalArgumentException();
552                 }
553                 Color old = this.selectedItemBgColor;
554                 if (old == null ? selectedItemBgColor != null : !old.equals(selectedItemBgColor)) {
555                         this.selectedItemBgColor = selectedItemBgColor;
556                         propChangeSupport.firePropertyChange(SELECTED_ITEM_BG_COLOR, old, selectedItemBgColor);
557                 }
558         }
559
560         private Color selectedItemBgColor = Color.orange;
561
562         /**
563          * 不備のあるデータ行の背景色を取得する.
564          *
565          * @return 不備のあるデータ行の背景色
566          */
567         public Color getInvalidBgColor() {
568                 return invalidBgColor;
569         }
570
571         public static final String INVALID_BG_COLOR = "invalidBgColor";
572
573         public void setInvalidBgColor(Color invalidBgColor) {
574                 if (invalidBgColor == null) {
575                         throw new IllegalArgumentException();
576                 }
577                 Color old = this.invalidBgColor;
578                 if (old == null ? invalidBgColor != null : !old.equals(invalidBgColor)) {
579                         this.invalidBgColor = invalidBgColor;
580                         propChangeSupport.firePropertyChange(INVALID_BG_COLOR, old, invalidBgColor);
581                 }
582         }
583
584         private Color invalidBgColor = Color.red.brighter().brighter();
585
586         /**
587          * JPEG画像変換時の圧縮率を取得する.
588          *
589          * @return 圧縮率
590          */
591         public float getCompressionQuality() {
592                 return compressionQuality;
593         }
594
595         public static final String COMPRESSION_QUALITY = "compressionQuality";
596
597         public void setCompressionQuality(float compressionQuality) {
598                 if (compressionQuality < .1f || compressionQuality > 1f) {
599                         throw new IllegalArgumentException();
600                 }
601                 float old = this.compressionQuality;
602                 if (old != compressionQuality) {
603                         this.compressionQuality = compressionQuality;
604                         propChangeSupport.firePropertyChange(COMPRESSION_QUALITY, old, compressionQuality);
605                 }
606         }
607
608         private float compressionQuality = .8f;
609
610         /**
611          * エクスポートウィザードのプリセットにパーツ不足時の警告色(前景色)を取得する.
612          *
613          * @return エクスポートウィザードのプリセットにパーツ不足時の警告色(前景色)
614          */
615         public Color getExportPresetWarningsForegroundColor() {
616                 return exportPresetWarningsForegroundColor;
617         }
618
619         public static final String EXPORT_PRESET_WARNINGS_FOREGROUND_COLOR = "exportPresetWarningsForegroundColor";
620
621         public void setExportPresetWarningsForegroundColor(Color exportPresetWarningsForegroundColor) {
622                 if (exportPresetWarningsForegroundColor == null) {
623                         throw new IllegalArgumentException();
624                 }
625                 Color old = this.exportPresetWarningsForegroundColor;
626                 if (old == null ? exportPresetWarningsForegroundColor != null
627                                 : !old.equals(exportPresetWarningsForegroundColor)) {
628                         this.exportPresetWarningsForegroundColor = exportPresetWarningsForegroundColor;
629                         propChangeSupport.firePropertyChange(EXPORT_PRESET_WARNINGS_FOREGROUND_COLOR, old,
630                                         exportPresetWarningsForegroundColor);
631                 }
632         }
633
634         private Color exportPresetWarningsForegroundColor = Color.red;
635
636         /**
637          * JARファイル転送用バッファサイズ.<br>
638          *
639          * @return JARファイル転送用バッファサイズ.
640          */
641         public int getJarTransferBufferSize() {
642                 return jarTransferBufferSize;
643         }
644
645         public static final String JAR_TRANSFER_BUFFER_SIZE = "jarTransferBufferSize";
646
647         public void setJarTransferBufferSize(int jarTransferBufferSize) {
648                 if (jarTransferBufferSize <= 0) {
649                         throw new IllegalArgumentException();
650                 }
651                 int old = this.jarTransferBufferSize;
652                 if (old != jarTransferBufferSize) {
653                         this.jarTransferBufferSize = jarTransferBufferSize;
654                         propChangeSupport.firePropertyChange(JAR_TRANSFER_BUFFER_SIZE, old, jarTransferBufferSize);
655                 }
656         }
657
658         private int jarTransferBufferSize = 4096;
659
660         /**
661          * ZIPファイル名のエンコーディング.<br>
662          *
663          * @return ZIPファイル名のエンコーディング.<br>
664          */
665         public String getZipNameEncoding() {
666                 return zipNameEncoding;
667         }
668
669         public static final String ZIP_NAME_ENCODING = "zipNameEncoding";
670
671         public void setZipNameEncoding(String zipNameEncoding) {
672                 if (zipNameEncoding == null) {
673                         throw new IllegalArgumentException();
674                 }
675                 try {
676                         Charset.forName(zipNameEncoding);
677                 } catch (Exception ex) {
678                         throw new RuntimeException("unsupported charset: " + zipNameEncoding);
679                 }
680                 String old = this.zipNameEncoding;
681                 if (old == null ? zipNameEncoding != null : !old.equals(zipNameEncoding)) {
682                         this.zipNameEncoding = zipNameEncoding;
683                         propChangeSupport.firePropertyChange(ZIP_NAME_ENCODING, old, zipNameEncoding);
684                 }
685         }
686
687         private String zipNameEncoding = "csWindows31J";
688
689         /**
690          * ディセーブルなテーブルのセルのフォアグラウンドカラーを取得する.
691          *
692          * @return ディセーブルなテーブルのセルのフォアグラウンドカラー
693          */
694         public Color getDisabledCellForgroundColor() {
695                 return disabledCellForegroundColor;
696         }
697
698         public static final String DISABLED_CELL_FOREGROUND_COLOR = "disabledCellForegroundColor";
699
700         public void setDisabledCellForegroundColor(Color disabledCellForegroundColor) {
701                 if (disabledCellForegroundColor == null) {
702                         throw new IllegalArgumentException();
703                 }
704                 Color old = this.disabledCellForegroundColor;
705                 if (old == null ? disabledCellForegroundColor != null : !old.equals(disabledCellForegroundColor)) {
706                         this.disabledCellForegroundColor = disabledCellForegroundColor;
707                         propChangeSupport.firePropertyChange(DISABLED_CELL_FOREGROUND_COLOR, old, disabledCellForegroundColor);
708                 }
709         }
710
711         private Color disabledCellForegroundColor = Color.gray;
712
713
714         /**
715          * ディレクトリを監視する間隔(mSec)を取得する.
716          *
717          * @return ディレクトリを監視する間隔(mSec)
718          */
719         public int getDirWatchInterval() {
720                 return dirWatchInterval;
721         }
722
723         public static final String DIR_WATCH_INTERVAL = "dirWatchInterval";
724
725         public void setDirWatchInterval(int dirWatchInterval) {
726                 if (dirWatchInterval <= 0) {
727                         throw new IllegalArgumentException();
728                 }
729                 int old = this.dirWatchInterval;
730                 if (old != dirWatchInterval) {
731                         this.dirWatchInterval = dirWatchInterval;
732                         propChangeSupport.firePropertyChange(DIR_WATCH_INTERVAL, old, dirWatchInterval);
733                 }
734         }
735
736         private int dirWatchInterval = 7 * 1000;
737
738         /**
739          * ディレクトリの監視を有効にするか?
740          *
741          * @return ディレクトリの監視を有効にする場合はtrue
742          */
743         public boolean isEnableDirWatch() {
744                 return enableDirWatch;
745         }
746
747         public static final String ENABLE_DIR_WATCH = "enableDirWatch";
748
749         public void setEnableDirWatch(boolean enableDirWatch) {
750                 boolean old = this.enableDirWatch;
751                 if (old != enableDirWatch) {
752                         this.enableDirWatch = enableDirWatch;
753                         propChangeSupport.firePropertyChange(ENABLE_DIR_WATCH, old, enableDirWatch);
754                 }
755         }
756
757         private boolean enableDirWatch = true;
758
759         /**
760          * ファイル転送に使うバッファサイズ.<br>
761          *
762          * @return バッファサイズ
763          */
764         public int getFileTransferBufferSize() {
765                 return fileTransferBufferSize;
766         }
767
768         public static final String FILE_TRANSFER_BUFFER_SIZE = "fileTransferBufferSize";
769
770         public void setFileTransferBufferSize(int fileTransferBufferSize) {
771                 if (fileTransferBufferSize <= 0) {
772                         throw new IllegalArgumentException();
773                 }
774                 int old = this.fileTransferBufferSize;
775                 if (old != fileTransferBufferSize) {
776                         this.fileTransferBufferSize = fileTransferBufferSize;
777                         propChangeSupport.firePropertyChange(FILE_TRANSFER_BUFFER_SIZE, old, fileTransferBufferSize);
778                 }
779         }
780
781         private int fileTransferBufferSize = 4096;
782
783         /**
784          * プレビューのインジケータを表示するまでのディレイ(mSec)を取得する.
785          *
786          * @return プレビューのインジケータを表示するまでのディレイ(mSec)
787          */
788         public long getPreviewIndicatorDelay() {
789                 return previewIndeicatorDelay;
790         }
791
792         public static final String PREVIEW_INDEICATOR_DELAY = "previewIndeicatorDelay";
793
794         public void setPreviewIndeicatorDelay(long previewIndeicatorDelay) {
795                 if (previewIndeicatorDelay < 0) {
796                         throw new IllegalArgumentException();
797                 }
798                 long old = this.previewIndeicatorDelay;
799                 if (old != previewIndeicatorDelay) {
800                         this.previewIndeicatorDelay = previewIndeicatorDelay;
801                         propChangeSupport.firePropertyChange(PREVIEW_INDEICATOR_DELAY, old, previewIndeicatorDelay);
802                 }
803         }
804
805         private long previewIndeicatorDelay = 300;
806
807         /**
808          * 情報ダイアログの編集ボタンを「開く」アクションにする場合はtrue、「編集」アクションにする場合はfalse
809          *
810          * @return trueならばOpen、falseならばEdit
811          */
812         public boolean isInformationDialogOpenMethod() {
813                 return informationDialogOpenMethod;
814         }
815
816         public static final String INFORMATION_DIALOG_OPEN_METHOD = "informationDialogOpenMethod";
817
818         public void setInformationDialogOpenMethod(
819                         boolean informationDialogOpenMethod) {
820                 boolean old = this.informationDialogOpenMethod;
821                 if (old != informationDialogOpenMethod) {
822                         this.informationDialogOpenMethod = informationDialogOpenMethod;
823                         propChangeSupport.firePropertyChange("informationDialogOpenMethod", old, informationDialogOpenMethod);
824                 }
825         }
826
827         private boolean informationDialogOpenMethod = true;
828
829         /**
830          * ログを常に残すか?<br>
831          * falseの場合は{@link ApplicationLogHandler}の実装に従って終了時に 必要なければログは削除される.<br>
832          *
833          * @return 常に残す場合はtrue、そうでなければfalse
834          */
835         public boolean isNoRemoveLog() {
836                 return noRemoveLog;
837         }
838
839         public static final String NO_REMOVE_LOG = "noRemoveLog";
840
841         public void setNoRemoveLog(boolean noRemoveLog) {
842                 boolean old = this.noRemoveLog;
843                 if (old != noRemoveLog) {
844                         this.noRemoveLog = noRemoveLog;
845                         propChangeSupport.firePropertyChange(NO_REMOVE_LOG, old, noRemoveLog);
846                 }
847         }
848
849         private boolean noRemoveLog = false;
850
851
852         /**
853          * テーブルのグリッド色.<br>
854          *
855          * @return テーブルのグリッド色
856          */
857         public Color getGridColor() {
858                 return gridColor;
859         }
860
861         public static final String GRID_COLOR = "gridColor";
862
863         public void setGridColor(Color gridColor) {
864                 if (gridColor == null) {
865                         throw new IllegalArgumentException();
866                 }
867                 Color old = this.gridColor;
868                 if (old == null ? gridColor != null : !old.equals(gridColor)) {
869                         this.gridColor = gridColor;
870                         propChangeSupport.firePropertyChange(GRID_COLOR, old, gridColor);
871                 }
872         }
873
874         private Color gridColor = Color.gray;
875
876         /**
877          * カラーダイアログの値が変更されたら、自動的にプレビューを更新するか?
878          *
879          * @return カラーダイアログの値が変更されたら、自動的にプレビューを更新する場合はtrue (デフォルトはtrue)
880          */
881         public boolean isEnableAutoColorChange() {
882                 return enableAutoColorChange;
883         }
884
885         public static final String ENABLE_AUTO_COLOR_CHANGE = "enableAutoColorChange";
886
887         public void setEnableAutoColorChange(boolean enableAutoColorChange) {
888                 boolean old = this.enableAutoColorChange;
889                 if (old != enableAutoColorChange) {
890                         this.enableAutoColorChange = enableAutoColorChange;
891                         propChangeSupport.firePropertyChange(ENABLE_AUTO_COLOR_CHANGE, old, enableAutoColorChange);
892                 }
893         }
894
895         private boolean enableAutoColorChange = true;
896
897         public static final String AUTHOR_EDIT_CONFLICT_BG_COLOR = "authorEditConflictBgColor";
898
899         public void setAuthorEditConflictBgColor(Color authorEditConflictBgColor) {
900                 if (authorEditConflictBgColor == null) {
901                         throw new IllegalArgumentException();
902                 }
903                 Color old = this.authorEditConflictBgColor;
904                 if (old == null ? authorEditConflictBgColor != null : !old.equals(authorEditConflictBgColor)) {
905                         this.authorEditConflictBgColor = authorEditConflictBgColor;
906                         propChangeSupport.firePropertyChange(AUTHOR_EDIT_CONFLICT_BG_COLOR, old, authorEditConflictBgColor);
907                 }
908         }
909
910         /**
911          * パーツの作者編集時に複数作者を選択した場合のに入力ボックスの背景色
912          *
913          * @return 背景色
914          */
915         public Color getAuthorEditConflictBgColor() {
916                 return authorEditConflictBgColor;
917         }
918
919         Color authorEditConflictBgColor = Color.yellow;
920
921
922         public static final String MAIN_FRAME_MAX_WIDTH = "mainFrameMaxWidth";
923
924         public void setMainFrameMaxWidth(int mainFrameMaxWidth) {
925                 int old = mainFrameMaxWidth;
926                 if (old != mainFrameMaxWidth) {
927                         this.mainFrameMaxWidth = mainFrameMaxWidth;
928                         propChangeSupport.firePropertyChange(MAIN_FRAME_MAX_WIDTH, old, mainFrameMaxWidth);
929                 }
930         }
931
932         /**
933          * メインフレームの初期表示時の最大幅
934          *
935          * @return メインフレームの初期表示時の最大幅
936          */
937         public int getMainFrameMaxWidth() {
938                 return mainFrameMaxWidth;
939         }
940
941         private int mainFrameMaxWidth = 800;
942
943         public static final String MAIN_FRAME_MAX_HEIGHT = "mainFrameMaxHeight";
944
945         public void setMainFrameMaxHeight(int mainFrameMaxHeight) {
946                 int old = this.mainFrameMaxHeight;
947                 if (old != mainFrameMaxHeight) {
948                         this.mainFrameMaxHeight = mainFrameMaxHeight;
949                         propChangeSupport.firePropertyChange(MAIN_FRAME_MAX_HEIGHT, old, mainFrameMaxHeight);
950                 }
951         }
952
953         /**
954          * メインフレームの初期表示時の最大高さ
955          *
956          * @return メインフレームの初期表示時の最大高さ
957          */
958         public int getMainFrameMaxHeight() {
959                 return mainFrameMaxHeight;
960         }
961
962         private int mainFrameMaxHeight = 600;
963
964
965         /**
966          * カラーダイアログで存在しないレイヤーをディセーブルにしない.
967          *
968          * @return ディセーブルにしない場合はtrue
969          */
970         public boolean isNotDisableLayerTab() {
971                 return notDisableLayerTab;
972         }
973
974         public static final String NOT_DISABLE_LAYER_TAB = "notDisableLayerTab";
975
976         public void setNotDisableLayerTab(boolean notDisableLayerTab) {
977                 boolean old = this.notDisableLayerTab;
978                 if (old != notDisableLayerTab) {
979                         this.notDisableLayerTab = notDisableLayerTab;
980                         propChangeSupport.firePropertyChange(NOT_DISABLE_LAYER_TAB, old, notDisableLayerTab);
981                 }
982         }
983
984         private boolean notDisableLayerTab;
985
986
987         /**
988          * ログを消去する日数.<br>
989          * この指定日を経過した古いログは削除される.<br>
990          * 0の場合は削除されない.
991          *
992          * @return
993          */
994         public long getPurgeLogDays() {
995                 return purgeLogDays;
996         }
997
998         public static final String PURGE_LOG_DAYS = "purgeLogDays";
999
1000         public void setPurgeLogDays(long purgeLogDays) {
1001                 long old = this.purgeLogDays;
1002                 if (old != purgeLogDays) {
1003                         this.purgeLogDays = purgeLogDays;
1004                         propChangeSupport.firePropertyChange(PURGE_LOG_DAYS, old, purgeLogDays);
1005                 }
1006         }
1007
1008         private long purgeLogDays = 10;
1009
1010         public String getPartsColorGroupPattern() {
1011                 return partsColorGroupPattern;
1012         }
1013
1014         public static final String PARTS_COLOR_GROUP_PATTERN = "partsColorGroupPattern";
1015
1016         public void setPartsColorGroupPattern(String pattern) {
1017                 if (pattern != null && pattern.trim().length() > 0) {
1018                         Pattern.compile(pattern);
1019                 }
1020                 String old = this.partsColorGroupPattern;
1021                 if (old == null ? pattern != null : !old.equals(pattern)) {
1022                         this.partsColorGroupPattern = pattern;
1023                         propChangeSupport.firePropertyChange(PARTS_COLOR_GROUP_PATTERN, old, pattern);
1024                 }
1025         }
1026
1027         private String partsColorGroupPattern = "^.*\\(@\\).*$";
1028
1029         private Color selectPanelTitleColor = Color.BLUE;
1030
1031         public Color getSelectPanelTitleColor() {
1032                 return selectPanelTitleColor;
1033         }
1034
1035         public static final String SELECT_PANEL_TITLE_COLOR = "selectPanelTitleColor";
1036
1037         public void setSelectPanelTitleColor(Color selectPanelTitleColor) {
1038                 if (selectPanelTitleColor == null) {
1039                         throw new IllegalArgumentException();
1040                 }
1041                 Color old = this.selectPanelTitleColor;
1042                 if (old == null ? selectPanelTitleColor != null : !old.equals(selectPanelTitleColor)) {
1043                         this.selectPanelTitleColor = selectPanelTitleColor;
1044                         propChangeSupport.firePropertyChange(SELECT_PANEL_TITLE_COLOR, old, selectPanelTitleColor);
1045                 }
1046         }
1047
1048         private boolean enableAutoShrinkPanel;
1049
1050         public boolean isEnableAutoShrinkPanel() {
1051                 return enableAutoShrinkPanel;
1052         }
1053
1054         public static final String ENABLE_AUTO_SHRINK_PANEL = "enableAutoShrinkPanel";
1055
1056         public void setEnableAutoShrinkPanel(boolean enableAutoShrinkPanel) {
1057                 boolean old = this.enableAutoShrinkPanel;
1058                 if (old != enableAutoShrinkPanel) {
1059                         this.enableAutoShrinkPanel = enableAutoShrinkPanel;
1060                         propChangeSupport.firePropertyChange(ENABLE_AUTO_SHRINK_PANEL, old, enableAutoShrinkPanel);
1061                 }
1062         }
1063
1064         public boolean isDisableWatchDirIfNotWritable() {
1065                 return disableWatchDirIfNotWritable;
1066         }
1067
1068         public static final String DISABLE_WATCH_DIR_IF_NOT_WRITABLE = "disableWatchDirIfNotWritable";
1069
1070         public void setDisableWatchDirIfNotWritable(boolean disableWatchDirIfNotWritable) {
1071                 boolean old = this.disableWatchDirIfNotWritable;
1072                 if (old != disableWatchDirIfNotWritable) {
1073                         this.disableWatchDirIfNotWritable = disableWatchDirIfNotWritable;
1074                         propChangeSupport.firePropertyChange(DISABLE_WATCH_DIR_IF_NOT_WRITABLE, old, disableWatchDirIfNotWritable);
1075                 }
1076         }
1077
1078         private boolean disableWatchDirIfNotWritable = true;
1079
1080         public static final String ENABLE_PNG_SUPPORT_FOR_WINDOWS = "enablePNGSupportForWindows";
1081
1082         public void setEnablePNGSupportForWindows(boolean enablePNGSupportForWindows) {
1083                 boolean old = this.enablePNGSupportForWindows;
1084                 if (old != enablePNGSupportForWindows) {
1085                         this.enablePNGSupportForWindows = enablePNGSupportForWindows;
1086                         propChangeSupport.firePropertyChange(ENABLE_PNG_SUPPORT_FOR_WINDOWS, old, enablePNGSupportForWindows);
1087                 }
1088         }
1089
1090         public boolean isEnablePNGSupportForWindows() {
1091                 return enablePNGSupportForWindows;
1092         }
1093
1094         private boolean enablePNGSupportForWindows = true;
1095
1096         /**
1097          * 画像表示(通常モード)でオプティマイズを有効にする最大倍率.
1098          */
1099         private double renderingOptimizeThresholdForNormal = 2.;
1100
1101         public static final String RENDERING_OPTIMIZE_THRESHOLD_FOR_NORMAL = "renderingOptimizeThresholdForNormal";
1102
1103         public void setRenderingOptimizeThresholdForNormal(
1104                         double renderingOptimizeThresholdForNormal) {
1105                 double old = this.renderingOptimizeThresholdForNormal;
1106                 if (old != renderingOptimizeThresholdForNormal) {
1107                         this.renderingOptimizeThresholdForNormal = renderingOptimizeThresholdForNormal;
1108                         propChangeSupport.firePropertyChange(RENDERING_OPTIMIZE_THRESHOLD_FOR_NORMAL, old,
1109                                         renderingOptimizeThresholdForNormal);
1110                 }
1111         }
1112
1113         public double getRenderingOptimizeThresholdForNormal() {
1114                 return renderingOptimizeThresholdForNormal;
1115         }
1116         /**
1117          * 画像表示(チェックモード)でオプティマイズを有効にする最大倍率.
1118          */
1119         private double renderingOptimizeThresholdForCheck = 0.;
1120
1121         public static final String RENDERING_OPTIMIZE_THRESHOLD_FOR_CHECK = "renderingOptimizeThresholdForCheck";
1122
1123         public void setRenderingOptimizeThresholdForCheck(
1124                         double renderingOptimizeThresholdForCheck) {
1125                 double old = this.renderingOptimizeThresholdForCheck;
1126                 if (old != renderingOptimizeThresholdForCheck) {
1127                         this.renderingOptimizeThresholdForCheck = renderingOptimizeThresholdForCheck;
1128                         propChangeSupport.firePropertyChange(RENDERING_OPTIMIZE_THRESHOLD_FOR_CHECK, old,
1129                                         renderingOptimizeThresholdForCheck);
1130                 }
1131         }
1132
1133         public double getRenderingOptimizeThresholdForCheck() {
1134                 return renderingOptimizeThresholdForCheck;
1135         }
1136
1137         /**
1138          * バイキュービックをサポートする場合
1139          */
1140         private boolean enableInterpolationBicubic = true;
1141
1142         public static final String ENABLE_INTERPOLATION_BICUBIC = "enableInterpolationBicubic";
1143
1144         public void setEnableInterpolationBicubic(boolean enableInterpolationBicubic) {
1145                 boolean old = this.enableInterpolationBicubic;
1146                 if (old != enableInterpolationBicubic) {
1147                         this.enableInterpolationBicubic = enableInterpolationBicubic;
1148                         propChangeSupport.firePropertyChange(ENABLE_INTERPOLATION_BICUBIC, old, enableInterpolationBicubic);
1149                 }
1150         }
1151
1152         public boolean isEnableInterpolationBicubic() {
1153                 return enableInterpolationBicubic;
1154         }
1155
1156         /**
1157          * 事前定義済みの倍率候補.<br>
1158          */
1159         private String predefinedZoomRanges = "20, 50, 80, 100, 120, 150, 200, 300, 400, 800";
1160
1161         public String getPredefinedZoomRanges() {
1162                 return predefinedZoomRanges;
1163         }
1164
1165         public static final String PREDEFINED_ZOOM_RANGES = "predefinedZoomRanges";
1166
1167         public void setPredefinedZoomRanges(String predefinedZoomRanges) {
1168                 if (predefinedZoomRanges == null) {
1169                         throw new IllegalArgumentException();
1170                 }
1171                 String old = this.predefinedZoomRanges;
1172                 if (old == null ? predefinedZoomRanges != null : !old.equals(predefinedZoomRanges)) {
1173                         this.predefinedZoomRanges = predefinedZoomRanges;
1174                         propChangeSupport.firePropertyChange(PREDEFINED_ZOOM_RANGES, old, predefinedZoomRanges);
1175                 }
1176         }
1177
1178         /**
1179          * ズームパネルを初期状態で表示するか?
1180          */
1181         private boolean enableZoomPanel = true;
1182
1183         public boolean isEnableZoomPanel() {
1184                 return enableZoomPanel;
1185         }
1186
1187         public static final String ENABLE_ZOOM_PANEL = "enableZoomPanel";
1188
1189         public void setEnableZoomPanel(boolean enableZoomPanel) {
1190                 boolean old = this.enableZoomPanel;
1191                 if (old != enableZoomPanel) {
1192                         this.enableZoomPanel = enableZoomPanel;
1193                         propChangeSupport.firePropertyChange(ENABLE_ZOOM_PANEL, old, enableZoomPanel);
1194                 }
1195         }
1196
1197         /**
1198          * ズームパネルをアクティブにする下部範囲
1199          */
1200         private int zoomPanelActivationArea = 30;
1201
1202         public int getZoomPanelActivationArea() {
1203                 return zoomPanelActivationArea;
1204         }
1205
1206         public static final String ZOOM_PANEL_ACTIVATION_AREA = "zoomPanelActivationArea";
1207
1208         public void setZoomPanelActivationArea(int zoomPanelActivationArea) {
1209                 int old = this.zoomPanelActivationArea;
1210                 if (old != zoomPanelActivationArea) {
1211                         this.zoomPanelActivationArea = zoomPanelActivationArea;
1212                         propChangeSupport.firePropertyChange(ZOOM_PANEL_ACTIVATION_AREA, old, zoomPanelActivationArea);
1213                 }
1214         }
1215
1216         /**
1217          * レンダリングヒントを使用するか?
1218          */
1219         private boolean enableRenderingHints = true;
1220
1221         public static final String ENABLE_RENDERING_HINTS = "enableRenderingHints";
1222
1223         public void setEnableRenderingHints(boolean enableRenderingHints) {
1224                 boolean old = this.enableRenderingHints;
1225                 if (old != enableRenderingHints) {
1226                         this.enableRenderingHints = enableRenderingHints;
1227                         propChangeSupport.firePropertyChange(ENABLE_RENDERING_HINTS, old, enableRenderingHints);
1228                 }
1229         }
1230
1231         public boolean isEnableRenderingHints() {
1232                 return enableRenderingHints;
1233         }
1234
1235         /**
1236          * グリッド描画とマスク
1237          */
1238         private int drawGridMask = 2;
1239
1240         public int getDrawGridMask() {
1241                 return drawGridMask;
1242         }
1243
1244         public static final String DRAW_GRID_MASK = "drawGridMask";
1245
1246         public void setDrawGridMask(int drawGridMask) {
1247                 drawGridMask &= 0x03;
1248                 int old = this.drawGridMask;
1249                 if (old != drawGridMask) {
1250                         this.drawGridMask = drawGridMask;
1251                         propChangeSupport.firePropertyChange(DRAW_GRID_MASK, old, drawGridMask);
1252                 }
1253         }
1254
1255         private Color previewGridColor = new Color(0x7f7f0000, true);
1256
1257         public Color getPreviewGridColor() {
1258                 return previewGridColor;
1259         }
1260
1261         public static final String PREVIEW_GRID_COLOR = "previewGridColor";
1262
1263         public void setPreviewGridColor(Color previewGridColor) {
1264                 Color old = this.previewGridColor;
1265                 if (old == null ? previewGridColor != null : !old.equals(previewGridColor)) {
1266                         this.previewGridColor = previewGridColor;
1267                         propChangeSupport.firePropertyChange(PREVIEW_GRID_COLOR, old, previewGridColor);
1268                 }
1269         }
1270
1271         private int previewGridSize = 20;
1272
1273         public int getPreviewGridSize() {
1274                 return previewGridSize;
1275         }
1276
1277         public static final String PREVIEW_GRID_SIZE = "previewGridSize";
1278
1279         public void setPreviewGridSize(int previewGridSize) {
1280                 int old = this.previewGridSize;
1281                 if (old != previewGridSize) {
1282                         this.previewGridSize = previewGridSize;
1283                         propChangeSupport.firePropertyChange(PREVIEW_GRID_SIZE, old, previewGridSize);
1284                 }
1285         }
1286
1287         /**
1288          * チェックモード時の余白サイズ(片側)
1289          */
1290         private int previewUnfilledSpaceForCheckMode = 0;
1291
1292         public int getPreviewUnfilledSpaceForCheckMode() {
1293                 return previewUnfilledSpaceForCheckMode;
1294         }
1295
1296         public static final String PREVIEW_UNFILLED_SPACE_FOR_CHECK_MODE = "previewUnfilledSpaceForCheckMode";
1297
1298         public void setPreviewUnfilledSpaceForCheckMode(int previewUnfilledSpaceForCheckMode) {
1299                 int old = this.previewUnfilledSpaceForCheckMode;
1300                 if (old != previewUnfilledSpaceForCheckMode) {
1301                         this.previewUnfilledSpaceForCheckMode = previewUnfilledSpaceForCheckMode;
1302                         propChangeSupport.firePropertyChange(PREVIEW_UNFILLED_SPACE_FOR_CHECK_MODE, old,
1303                                         previewUnfilledSpaceForCheckMode);
1304                 }
1305         }
1306
1307         /**
1308          * チェックモードでツールチップを表示するか?
1309          */
1310         private boolean enableCheckInfoTooltip = true;
1311
1312         public boolean isEnableCheckInfoTooltip() {
1313                 return enableCheckInfoTooltip;
1314         }
1315
1316         public static final String ENABLE_CHECK_INFO_TOOLTIP = "enableCheckInfoTooltip";
1317
1318         public void setEnableCheckInfoTooltip(boolean enableCheckInfoTooltip) {
1319                 boolean old = this.enableCheckInfoTooltip;
1320                 if (old != enableCheckInfoTooltip) {
1321                         this.enableCheckInfoTooltip = enableCheckInfoTooltip;
1322                         propChangeSupport.firePropertyChange(ENABLE_CHECK_INFO_TOOLTIP, old, enableCheckInfoTooltip);
1323                 }
1324         }
1325
1326         /**
1327          * ホイールによるスクロールの単位.<br>
1328          */
1329         private int wheelScrollUnit = 10;
1330
1331         public int getWheelScrollUnit() {
1332                 return wheelScrollUnit;
1333         }
1334
1335         public static final String WHEEL_SCROLL_UNIT = "wheelScrollUnit";
1336
1337         public void setWheelScrollUnit(int wheelScrollUnit) {
1338                 int old = this.wheelScrollUnit;
1339                 if (old != wheelScrollUnit) {
1340                         this.wheelScrollUnit = wheelScrollUnit;
1341                         propChangeSupport.firePropertyChange(WHEEL_SCROLL_UNIT, old, wheelScrollUnit);
1342                 }
1343         }
1344
1345         /**
1346          * 壁紙にオフスクリーン描画を使用するか?.<br>
1347          * (あまり劇的なパフォーマンス効果はない.)
1348          */
1349         private boolean enableOffscreenWallpaper = false;
1350
1351         public boolean isEnableOffscreenWallpaper() {
1352                 return enableOffscreenWallpaper;
1353         }
1354
1355         public static final String ENABLE_OFFSCREEN_WALLPAPER = "enableOffscreenWallpaper";
1356
1357         public void setEnableOffscreenWallpaper(boolean enableOffscreenWallpaper) {
1358                 boolean old = this.enableOffscreenWallpaper;
1359                 if (old != enableOffscreenWallpaper) {
1360                         this.enableOffscreenWallpaper = enableOffscreenWallpaper;
1361                         propChangeSupport.firePropertyChange(ENABLE_OFFSCREEN_WALLPAPER, old, enableOffscreenWallpaper);
1362                 }
1363         }
1364
1365         /**
1366          * 壁紙のオフスクリーンの既定サイズ.
1367          */
1368         private int offscreenWallpaperSize = 300;
1369
1370         public int getOffscreenWallpaperSize() {
1371                 return offscreenWallpaperSize;
1372         }
1373
1374         private static final String OFFSCREEN_WALLPAPER_SIZE = "offscreenWallpaperSize";
1375
1376         public void setOffscreenWallpaperSize(int offscreenWallpaperSize) {
1377                 int old = this.offscreenWallpaperSize;
1378                 if (old != offscreenWallpaperSize) {
1379                         this.offscreenWallpaperSize = offscreenWallpaperSize;
1380                         propChangeSupport.firePropertyChange(OFFSCREEN_WALLPAPER_SIZE, old, offscreenWallpaperSize);
1381                 }
1382         }
1383
1384
1385         /**
1386          * ランダム選択パーツの履歴数
1387          */
1388         private int randomChooserMaxHistory = 10;
1389
1390         public int getRandomChooserMaxHistory() {
1391                 return randomChooserMaxHistory;
1392         }
1393
1394         public static final String RANDOM_CHOOSER_MAX_HISTORY = "randomChooserMaxHistory";
1395
1396         public void setRandomChooserMaxHistory(int randomChooserMaxHistory) {
1397                 int old = this.randomChooserMaxHistory;
1398                 if (old != randomChooserMaxHistory) {
1399                         this.randomChooserMaxHistory = randomChooserMaxHistory;
1400                         propChangeSupport.firePropertyChange(RANDOM_CHOOSER_MAX_HISTORY, old, randomChooserMaxHistory);
1401                 }
1402         }
1403
1404         /**
1405          * デフォルトのフォントサイズ、0以下の場合はシステム既定のまま
1406          */
1407         private int defaultFontSize = 12;
1408
1409         public int getDefaultFontSize() {
1410                 return defaultFontSize;
1411         }
1412
1413         public static final String DEFAULT_FONT_SIZE = "defaultFontSize";
1414
1415         public void setDefaultFontSize(int defaultFontSize) {
1416                 int old = this.defaultFontSize;
1417                 if (old != defaultFontSize) {
1418                         this.defaultFontSize = defaultFontSize;
1419                         propChangeSupport.firePropertyChange(DEFAULT_FONT_SIZE, old, defaultFontSize);
1420                 }
1421         }
1422
1423         /**
1424          * デフォルトのフォントファミリー、カンマ区切り
1425          */
1426         private String fontPriority = "Lucida Grande";
1427
1428         public String getFontPriority() {
1429                 return fontPriority;
1430         }
1431
1432         public static final String FONT_PRIORITY = "fontPriority";
1433
1434         public void setFontPriority(String fontPriority) {
1435                 if (fontPriority == null) {
1436                         throw new IllegalArgumentException();
1437                 }
1438                 String old = this.fontPriority;
1439                 if (old == null ? fontPriority != null : !old.equals(fontPriority)) {
1440                         this.fontPriority = fontPriority;
1441                         propChangeSupport.firePropertyChange(FONT_PRIORITY, old, fontPriority);
1442                 }
1443         }
1444
1445         /**
1446          * ウィンドウの位置、サイズ、スクロールバーの位置、ズームの状態を復元するか?
1447          */
1448         private boolean enableRestoreWindow = false;
1449
1450         public boolean isEnableRestoreWindow() {
1451                 return enableRestoreWindow;
1452         }
1453
1454         public static final String ENABLE_RESTORE_WINDOW = "enableRestoreWindow";
1455
1456         public void setEnableRestoreWindow(boolean enableRestoreWindow) {
1457                 boolean old = this.enableRestoreWindow;
1458                 if (old != enableRestoreWindow) {
1459                         this.enableRestoreWindow = enableRestoreWindow;
1460                         propChangeSupport.firePropertyChange(ENABLE_RESTORE_WINDOW, old, enableRestoreWindow);
1461                 }
1462         }
1463
1464         private boolean enableColorAdvancedSettings = true;
1465
1466         public boolean isEnableColorAdvancedSettings() {
1467                 return enableColorAdvancedSettings;
1468         }
1469
1470         public static final String ENABLE_COLOR_ADVANCED_SETTINGS = "enableColorAdvancedSettings";
1471
1472         public void setEnableColorAdvancedSettings(boolean enableColorAdvancedSettings) {
1473                 boolean old = this.enableColorAdvancedSettings;
1474                 if (old != enableColorAdvancedSettings) {
1475                         this.enableColorAdvancedSettings = enableColorAdvancedSettings;
1476                         propChangeSupport.firePropertyChange(ENABLE_COLOR_ADVANCED_SETTINGS, old, enableRestoreWindow);
1477                 }
1478         }
1479 }