4 * License : The MIT License
5 * Copyright(c) 2008 olyutorskii
8 package jp.sfjp.jindolf.config;
11 import java.awt.Rectangle;
12 import java.awt.image.BufferedImage;
14 import java.io.IOException;
15 import java.nio.file.Path;
16 import java.nio.file.Paths;
17 import java.util.HashMap;
18 import java.util.List;
20 import java.util.logging.Logger;
21 import javax.imageio.ImageIO;
22 import jp.sfjp.jindolf.data.Avatar;
23 import jp.sfjp.jindolf.data.DialogPref;
24 import jp.sfjp.jindolf.glyph.Font2Json;
25 import jp.sfjp.jindolf.glyph.FontInfo;
26 import jp.sfjp.jindolf.net.ProxyInfo;
27 import jp.sfjp.jindolf.view.AvatarPics;
28 import jp.sourceforge.jovsonz.JsBoolean;
29 import jp.sourceforge.jovsonz.JsObject;
30 import jp.sourceforge.jovsonz.JsPair;
31 import jp.sourceforge.jovsonz.JsString;
32 import jp.sourceforge.jovsonz.JsTypes;
33 import jp.sourceforge.jovsonz.JsValue;
38 public class AppSetting{
41 private static final int DEF_WIDTH = 800;
42 private static final int DEF_HEIGHT = 600;
44 private static final String HASH_FONT = "font";
45 private static final String HASH_USEBODYICON = "useBodyIcon";
46 private static final String HASH_USEMONOTOMB = "useMonoTomb";
47 private static final String HASH_SIMPLEMODE = "isSimpleMode";
48 private static final String HASH_ALIGNBALOON = "alignBaloonWidth";
49 private static final String HASH_PROXY = "proxy";
51 private static final Logger LOGGER = Logger.getAnonymousLogger();
54 private final OptionInfo optInfo;
55 private final ConfigStore configStore;
56 private final Rectangle frameRect;
58 private FontInfo fontInfo;
60 private ProxyInfo proxyInfo = ProxyInfo.DEFAULT;
62 private DialogPref dialogPref = new DialogPref();
64 private JsValue loadedNetConfig;
65 private JsValue loadedTalkConfig;
67 private final Map<String, BufferedImage> avatarFaceMap = new HashMap<>();
68 private final Map<String, BufferedImage> avatarBodyMap = new HashMap<>();
73 * @param info コマンドライン引数
75 public AppSetting(OptionInfo info){
79 this.configStore = parseConfigStore(this.optInfo);
80 this.frameRect = parseGeometrySetting(this.optInfo);
88 * @param option コマンドラインオプション情報
91 private static ConfigStore parseConfigStore(OptionInfo option){
92 CmdOption opt = option.getExclusiveOption(CmdOption.OPT_CONFDIR,
93 CmdOption.OPT_NOCONF );
96 boolean isImplicitPath;
99 if(opt == CmdOption.OPT_NOCONF){
101 isImplicitPath = true;
103 }else if(opt == CmdOption.OPT_CONFDIR){
105 isImplicitPath = false;
106 String optPath = option.getStringArg(opt);
107 configPath = FileUtils.supplyFullPath(new File(optPath));
110 isImplicitPath = true;
111 configPath = ConfigFile.getImplicitConfigDirectory();
115 new ConfigStore(useConfig, isImplicitPath, configPath);
122 * @param option コマンドラインオプション情報
125 private static Rectangle parseGeometrySetting(OptionInfo option){
126 Rectangle result = new Rectangle(Integer.MIN_VALUE,
133 ival = option.initialFrameWidth();
134 if(ival != null) result.width = ival;
136 ival = option.initialFrameHeight();
137 if(ival != null) result.height = ival;
139 ival = option.initialFrameXpos();
140 if(ival != null) result.x = ival;
142 ival = option.initialFrameYpos();
143 if(ival != null) result.y = ival;
151 * @param baseFont 元のフォント設定。
152 * @return コマンドライン設定で補正されたフォント設定
154 private FontInfo parseFontOption(FontInfo baseFont){
157 String fontName = this.optInfo.getStringArg(CmdOption.OPT_INITFONT);
158 if(fontName != null){
159 Font font = Font.decode(fontName);
160 result = baseFont.deriveFont(font);
165 Boolean useAntiAlias =
166 this.optInfo.getBooleanArg(CmdOption.OPT_ANTIALIAS);
167 if(useAntiAlias == null){
168 useAntiAlias = baseFont.isAntiAliased();
171 Boolean useFractional =
172 this.optInfo.getBooleanArg(CmdOption.OPT_FRACTIONAL);
173 if(useFractional == null){
174 useFractional = baseFont.usesFractionalMetrics();
177 result = result.deriveRenderContext(useAntiAlias,
185 * @return コマンドラインオプション情報
187 public OptionInfo getOptionInfo(){
195 public ConfigStore getConfigStore(){
196 return this.configStore;
203 public int initialFrameWidth(){
204 int width = this.frameRect.width;
212 public int initialFrameHeight(){
213 int height = this.frameRect.height;
219 * 特に指示されていなければInteger.MIN_VALUEを返す。
220 * @return 初期のフレーム位置のX座標
222 public int initialFrameXpos(){
223 int xPos = this.frameRect.x;
229 * 特に指示されていなければInteger.MIN_VALUEを返す。
230 * @return 初期のフレーム位置のY座標
232 public int initialFrameYpos(){
233 int yPos = this.frameRect.y;
241 public FontInfo getFontInfo(){
242 if(this.fontInfo == null){
243 this.fontInfo = parseFontOption(FontInfo.DEFAULT_FONTINFO);
245 return this.fontInfo;
250 * @param fontInfo フォント設定
252 public void setFontInfo(FontInfo fontInfo){
253 this.fontInfo = fontInfo;
261 public ProxyInfo getProxyInfo(){
262 return this.proxyInfo;
267 * @param proxyInfo プロクシ設定。nullならプロクシなしと解釈される。
269 public void setProxyInfo(ProxyInfo proxyInfo){
270 if(proxyInfo == null) this.proxyInfo = ProxyInfo.DEFAULT;
271 else this.proxyInfo = proxyInfo;
279 public DialogPref getDialogPref(){
280 return this.dialogPref;
287 public void setDialogPref(DialogPref pref){
288 if(pref == null) this.dialogPref = new DialogPref();
289 else this.dialogPref = pref;
296 private void loadNetConfig(){
297 JsObject root = this.configStore.loadNetConfig();
298 if(root == null) return;
299 this.loadedNetConfig = root;
301 JsValue value = root.getValue(HASH_PROXY);
302 if( ! (value instanceof JsObject) ) return;
303 JsObject proxy = (JsObject) value;
305 ProxyInfo info = ProxyInfo.decodeJson(proxy);
315 private void loadTalkConfig(){
316 JsObject root = this.configStore.loadTalkConfig();
317 if(root == null) return;
318 this.loadedTalkConfig = root;
320 JsValue value = root.getValue(HASH_FONT);
321 if(value instanceof JsObject){
322 JsObject font = (JsObject) value;
323 FontInfo info = Font2Json.decodeJson(font);
324 info = parseFontOption(info);
328 DialogPref pref = new DialogPref();
330 value = root.getValue(HASH_USEBODYICON);
331 if(value instanceof JsBoolean){
332 boolValue = (JsBoolean) value;
333 pref.setBodyImageSetting(boolValue.booleanValue());
335 value = root.getValue(HASH_USEMONOTOMB);
336 if(value instanceof JsBoolean){
337 boolValue = (JsBoolean) value;
338 pref.setMonoImageSetting(boolValue.booleanValue());
340 value = root.getValue(HASH_SIMPLEMODE);
341 if(value instanceof JsBoolean){
342 boolValue = (JsBoolean) value;
343 pref.setSimpleMode(boolValue.booleanValue());
345 value = root.getValue(HASH_ALIGNBALOON);
346 if(value instanceof JsBoolean){
347 boolValue = (JsBoolean) value;
348 pref.setAlignBalooonWidthSetting(boolValue.booleanValue());
356 * JSONをパースしAvatar-Image間マップに反映させる。
361 private void parseImgMap(JsObject json, Map<String, BufferedImage> map){
362 Path imgDir = this.configStore.getLocalImgDir();
364 List<JsPair> pairList = json.getPairList();
365 for(JsPair pair : pairList){
366 String avatarId = pair.getName();
367 JsValue value = pair.getValue();
369 if(value.getJsTypes() != JsTypes.STRING) continue;
370 JsString sVal = (JsString)value;
371 String imgName = sVal.toRawString();
373 Path imgPath = Paths.get(imgName);
374 Path full = imgDir.resolve(imgPath);
375 File file = full.toFile();
376 if( ! file.isAbsolute()
379 || ! file.canRead() ){
380 LOGGER.info("failed to access local image " + file.getPath());
386 image = ImageIO.read(file);
387 }catch(IOException e){
388 LOGGER.info("failed to load local image " + file.getPath());
392 map.put(avatarId, image);
401 private void loadLocalImageConfig(){
402 JsObject root = this.configStore.loadLocalImgConfig();
403 if(root == null) return;
405 JsValue faceConfig = root.getValue("avatarFace");
406 JsValue bodyConfig = root.getValue("avatarBody");
407 if(faceConfig.getJsTypes() != JsTypes.OBJECT) return;
408 if(bodyConfig.getJsTypes() != JsTypes.OBJECT) return;
410 JsObject jsonFace = (JsObject) faceConfig;
411 parseImgMap(jsonFace, this.avatarFaceMap);
414 JsObject jsonBody = (JsObject) bodyConfig;
415 parseImgMap(jsonBody, this.avatarBodyMap);
421 * ローカル代替イメージを画像キャッシュに反映させる。
423 * @param avatarPics 画像キャッシュ
425 public void applyLocalImage(AvatarPics avatarPics){
426 BufferedImage graveImage = this.avatarFaceMap.get("tomb");
427 BufferedImage graveBodyImage = this.avatarBodyMap.get("tomb");
429 avatarPics.setGraveImage(graveImage);
430 avatarPics.setGraveBodyImage(graveBodyImage);
432 for(Avatar avatar : Avatar.getPredefinedAvatarList()){
433 String avatarId = avatar.getIdentifier();
435 BufferedImage faceImage = this.avatarFaceMap.get(avatarId);
436 BufferedImage bodyImage = this.avatarBodyMap.get(avatarId);
438 avatarPics.setAvatarFaceImage(avatar, faceImage);
439 avatarPics.setAvatarBodyImage(avatar, bodyImage);
448 private void saveNetConfig(){
449 if( ! getConfigStore().useStoreFile() ) return;
451 JsObject root = new JsObject();
452 JsObject proxy = ProxyInfo.buildJson(getProxyInfo());
453 root.putValue(HASH_PROXY, proxy);
455 if(this.loadedNetConfig != null){
456 if(this.loadedNetConfig.equals(root)) return;
459 this.configStore.saveNetConfig(root);
467 private void saveTalkConfig(){
468 if( ! getConfigStore().useStoreFile() ) return;
470 JsObject root = new JsObject();
472 JsObject font = Font2Json.buildJson(getFontInfo());
473 root.putValue(HASH_FONT, font);
475 DialogPref pref = getDialogPref();
477 new JsPair(HASH_USEBODYICON, pref.useBodyImage());
479 new JsPair(HASH_USEMONOTOMB, pref.useMonoImage());
481 new JsPair(HASH_SIMPLEMODE, pref.isSimpleMode());
483 new JsPair(HASH_ALIGNBALOON, pref.alignBaloonWidth());
484 root.putPair(useBodyIcon);
485 root.putPair(useMonoTomb);
486 root.putPair(isSimple);
487 root.putPair(alignBaloon);
489 if(this.loadedTalkConfig != null){
490 if(this.loadedTalkConfig.equals(root)) return;
493 this.configStore.saveTalkConfig(root);
499 * 各種設定を設定格納ディレクトリからロードする。
501 public void loadConfig(){
504 loadLocalImageConfig();
509 * 各種設定を設定格納ディレクトリへセーブする。
511 public void saveConfig(){