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.sfjp.jindolf.view.LocalAvatarImg;
29 import jp.sourceforge.jovsonz.JsBoolean;
30 import jp.sourceforge.jovsonz.JsObject;
31 import jp.sourceforge.jovsonz.JsPair;
32 import jp.sourceforge.jovsonz.JsString;
33 import jp.sourceforge.jovsonz.JsTypes;
34 import jp.sourceforge.jovsonz.JsValue;
39 public class AppSetting{
42 private static final int DEF_WIDTH = 800;
43 private static final int DEF_HEIGHT = 600;
45 private static final String HASH_FONT = "font";
46 private static final String HASH_USEBODYICON = "useBodyIcon";
47 private static final String HASH_USEMONOTOMB = "useMonoTomb";
48 private static final String HASH_SIMPLEMODE = "isSimpleMode";
49 private static final String HASH_ALIGNBALOON = "alignBaloonWidth";
50 private static final String HASH_PROXY = "proxy";
52 private static final Logger LOGGER = Logger.getAnonymousLogger();
55 private final OptionInfo optInfo;
56 private final ConfigStore configStore;
57 private final Rectangle frameRect;
59 private FontInfo fontInfo;
61 private ProxyInfo proxyInfo = ProxyInfo.DEFAULT;
63 private DialogPref dialogPref = new DialogPref();
65 private JsValue loadedNetConfig;
66 private JsValue loadedTalkConfig;
68 private final Map<String, BufferedImage> avatarFaceMap = new HashMap<>();
69 private final Map<String, BufferedImage> avatarBodyMap = new HashMap<>();
74 * @param info コマンドライン引数
76 public AppSetting(OptionInfo info){
80 this.configStore = parseConfigStore(this.optInfo);
81 this.frameRect = parseGeometrySetting(this.optInfo);
89 * @param option コマンドラインオプション情報
92 private static ConfigStore parseConfigStore(OptionInfo option){
93 CmdOption opt = option.getExclusiveOption(CmdOption.OPT_CONFDIR,
94 CmdOption.OPT_NOCONF );
97 boolean isImplicitPath;
100 if(opt == CmdOption.OPT_NOCONF){
102 isImplicitPath = true;
104 }else if(opt == CmdOption.OPT_CONFDIR){
106 isImplicitPath = false;
107 String optPath = option.getStringArg(opt);
108 configPath = FileUtils.supplyFullPath(new File(optPath));
111 isImplicitPath = true;
112 configPath = ConfigFile.getImplicitConfigDirectory();
116 new ConfigStore(useConfig, isImplicitPath, configPath);
123 * @param option コマンドラインオプション情報
126 private static Rectangle parseGeometrySetting(OptionInfo option){
127 Rectangle result = new Rectangle(Integer.MIN_VALUE,
134 ival = option.initialFrameWidth();
135 if(ival != null) result.width = ival;
137 ival = option.initialFrameHeight();
138 if(ival != null) result.height = ival;
140 ival = option.initialFrameXpos();
141 if(ival != null) result.x = ival;
143 ival = option.initialFrameYpos();
144 if(ival != null) result.y = ival;
152 * @param baseFont 元のフォント設定。
153 * @return コマンドライン設定で補正されたフォント設定
155 private FontInfo parseFontOption(FontInfo baseFont){
158 String fontName = this.optInfo.getStringArg(CmdOption.OPT_INITFONT);
159 if(fontName != null){
160 Font font = Font.decode(fontName);
161 result = baseFont.deriveFont(font);
166 Boolean useAntiAlias =
167 this.optInfo.getBooleanArg(CmdOption.OPT_ANTIALIAS);
168 if(useAntiAlias == null){
169 useAntiAlias = baseFont.isAntiAliased();
172 Boolean useFractional =
173 this.optInfo.getBooleanArg(CmdOption.OPT_FRACTIONAL);
174 if(useFractional == null){
175 useFractional = baseFont.usesFractionalMetrics();
178 result = result.deriveRenderContext(useAntiAlias,
186 * @return コマンドラインオプション情報
188 public OptionInfo getOptionInfo(){
196 public ConfigStore getConfigStore(){
197 return this.configStore;
204 public int initialFrameWidth(){
205 int width = this.frameRect.width;
213 public int initialFrameHeight(){
214 int height = this.frameRect.height;
220 * 特に指示されていなければInteger.MIN_VALUEを返す。
221 * @return 初期のフレーム位置のX座標
223 public int initialFrameXpos(){
224 int xPos = this.frameRect.x;
230 * 特に指示されていなければInteger.MIN_VALUEを返す。
231 * @return 初期のフレーム位置のY座標
233 public int initialFrameYpos(){
234 int yPos = this.frameRect.y;
242 public FontInfo getFontInfo(){
243 if(this.fontInfo == null){
244 this.fontInfo = parseFontOption(FontInfo.DEFAULT_FONTINFO);
246 return this.fontInfo;
251 * @param fontInfo フォント設定
253 public void setFontInfo(FontInfo fontInfo){
254 this.fontInfo = fontInfo;
262 public ProxyInfo getProxyInfo(){
263 return this.proxyInfo;
268 * @param proxyInfo プロクシ設定。nullならプロクシなしと解釈される。
270 public void setProxyInfo(ProxyInfo proxyInfo){
271 if(proxyInfo == null) this.proxyInfo = ProxyInfo.DEFAULT;
272 else this.proxyInfo = proxyInfo;
280 public DialogPref getDialogPref(){
281 return this.dialogPref;
288 public void setDialogPref(DialogPref pref){
289 if(pref == null) this.dialogPref = new DialogPref();
290 else this.dialogPref = pref;
297 private void loadNetConfig(){
298 JsObject root = this.configStore.loadNetConfig();
299 if(root == null) return;
300 this.loadedNetConfig = root;
302 JsValue value = root.getValue(HASH_PROXY);
303 if( ! (value instanceof JsObject) ) return;
304 JsObject proxy = (JsObject) value;
306 ProxyInfo info = ProxyInfo.decodeJson(proxy);
316 private void loadTalkConfig(){
317 JsObject root = this.configStore.loadTalkConfig();
318 if(root == null) return;
319 this.loadedTalkConfig = root;
321 JsValue value = root.getValue(HASH_FONT);
322 if(value instanceof JsObject){
323 JsObject font = (JsObject) value;
324 FontInfo info = Font2Json.decodeJson(font);
325 info = parseFontOption(info);
329 DialogPref pref = new DialogPref();
331 value = root.getValue(HASH_USEBODYICON);
332 if(value instanceof JsBoolean){
333 boolValue = (JsBoolean) value;
334 pref.setBodyImageSetting(boolValue.booleanValue());
336 value = root.getValue(HASH_USEMONOTOMB);
337 if(value instanceof JsBoolean){
338 boolValue = (JsBoolean) value;
339 pref.setMonoImageSetting(boolValue.booleanValue());
341 value = root.getValue(HASH_SIMPLEMODE);
342 if(value instanceof JsBoolean){
343 boolValue = (JsBoolean) value;
344 pref.setSimpleMode(boolValue.booleanValue());
346 value = root.getValue(HASH_ALIGNBALOON);
347 if(value instanceof JsBoolean){
348 boolValue = (JsBoolean) value;
349 pref.setAlignBalooonWidthSetting(boolValue.booleanValue());
357 * JSONをパースしAvatar-Image間マップに反映させる。
362 private void parseImgMap(JsObject json, Map<String, BufferedImage> map){
363 Path imgDir = this.configStore.getLocalImgDir();
365 List<JsPair> pairList = json.getPairList();
366 for(JsPair pair : pairList){
367 String avatarId = pair.getName();
368 JsValue value = pair.getValue();
370 if(value.getJsTypes() != JsTypes.STRING) continue;
371 JsString sVal = (JsString)value;
372 String imgName = sVal.toRawString();
374 Path imgPath = Paths.get(imgName);
375 Path full = imgDir.resolve(imgPath);
376 File file = full.toFile();
377 if( ! file.isAbsolute()
380 || ! file.canRead() ){
381 LOGGER.info("failed to access local image " + file.getPath());
387 image = ImageIO.read(file);
388 }catch(IOException e){
389 LOGGER.info("failed to load local image " + file.getPath());
393 map.put(avatarId, image);
402 private void loadLocalImageConfig(){
403 JsObject root = this.configStore.loadLocalImgConfig();
404 if(root == null) return;
406 JsValue faceConfig = root.getValue("avatarFace");
407 JsValue bodyConfig = root.getValue("avatarBody");
408 if(faceConfig.getJsTypes() != JsTypes.OBJECT) return;
409 if(bodyConfig.getJsTypes() != JsTypes.OBJECT) return;
411 JsObject jsonFace = (JsObject) faceConfig;
412 parseImgMap(jsonFace, this.avatarFaceMap);
415 JsObject jsonBody = (JsObject) bodyConfig;
416 parseImgMap(jsonBody, this.avatarBodyMap);
422 * ローカル代替イメージを画像キャッシュに反映させる。
424 * @param avatarPics 画像キャッシュ
426 public void applyLocalImage(AvatarPics avatarPics){
427 BufferedImage graveImage = this.avatarFaceMap.get("tomb");
428 BufferedImage graveBodyImage = this.avatarBodyMap.get("tomb");
430 if(graveImage == null){
431 graveImage = LocalAvatarImg.getGraveImage();
433 if(graveBodyImage == null){
434 graveBodyImage = LocalAvatarImg.getGraveBodyImage();
437 avatarPics.setGraveImage(graveImage);
438 avatarPics.setGraveBodyImage(graveBodyImage);
440 for(Avatar avatar : Avatar.getPredefinedAvatarList()){
441 String avatarId = avatar.getIdentifier();
443 BufferedImage faceImage = this.avatarFaceMap.get(avatarId);
444 BufferedImage bodyImage = this.avatarBodyMap.get(avatarId);
446 if(faceImage == null){
447 faceImage = LocalAvatarImg.getAvatarFaceImage(avatarId);
449 if(bodyImage == null){
450 bodyImage = LocalAvatarImg.getAvatarBodyImage(avatarId);
453 avatarPics.setAvatarFaceImage(avatar, faceImage);
454 avatarPics.setAvatarBodyImage(avatar, bodyImage);
463 private void saveNetConfig(){
464 if( ! getConfigStore().useStoreFile() ) return;
466 JsObject root = new JsObject();
467 JsObject proxy = ProxyInfo.buildJson(getProxyInfo());
468 root.putValue(HASH_PROXY, proxy);
470 if(this.loadedNetConfig != null){
471 if(this.loadedNetConfig.equals(root)) return;
474 this.configStore.saveNetConfig(root);
482 private void saveTalkConfig(){
483 if( ! getConfigStore().useStoreFile() ) return;
485 JsObject root = new JsObject();
487 JsObject font = Font2Json.buildJson(getFontInfo());
488 root.putValue(HASH_FONT, font);
490 DialogPref pref = getDialogPref();
492 new JsPair(HASH_USEBODYICON, pref.useBodyImage());
494 new JsPair(HASH_USEMONOTOMB, pref.useMonoImage());
496 new JsPair(HASH_SIMPLEMODE, pref.isSimpleMode());
498 new JsPair(HASH_ALIGNBALOON, pref.alignBaloonWidth());
499 root.putPair(useBodyIcon);
500 root.putPair(useMonoTomb);
501 root.putPair(isSimple);
502 root.putPair(alignBaloon);
504 if(this.loadedTalkConfig != null){
505 if(this.loadedTalkConfig.equals(root)) return;
508 this.configStore.saveTalkConfig(root);
514 * 各種設定を設定格納ディレクトリからロードする。
516 public void loadConfig(){
519 loadLocalImageConfig();
524 * 各種設定を設定格納ディレクトリへセーブする。
526 public void saveConfig(){