・ninjin氏の連絡先を http://ninjinix.com へ変更。
・UIの各種文言を修正。
・L&Fを「MacOSX」から変更する際の例外に対処。(バグ報告#26564)
+ ・パッケージ構成の整理。
3.206.4 (2011-05-10)
・10億をこえる発言番号へのアンカー参照を抑止。(バグ報告#24477,#24946)
<checkstyle.config.location>${project.mainconf}/checks.xml</checkstyle.config.location>
<checkstyle.enable.rss>false</checkstyle.enable.rss>
- <project.mainentry>jp.sourceforge.jindolf.Jindolf</project.mainentry>
- <project.splash>jp/sourceforge/jindolf/resources/image/logo.png</project.splash>
+ <project.mainentry>jp.sfjp.jindolf.Jindolf</project.mainentry>
+ <project.splash>jp/sfjp/jindolf/resources/image/logo.png</project.splash>
</properties>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>2.3.2</version>
+ <version>2.4</version>
<configuration>
<archive>
<manifest>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
- <version>2.2.1</version>
+ <version>2.3</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/descriptor.xml</descriptor>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
- <version>2.8</version>
+ <version>2.8.1</version>
<configuration>
<skip>false</skip>
<notimestamp>true</notimestamp>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
- <version>2.10</version>
+ <version>2.12</version>
<configuration>
<showSuccess>false</showSuccess>
</configuration>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
- <version>2.3.2</version>
+ <version>2.4.0</version>
<configuration>
<skip>true</skip>
<effort>Max</effort>
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf;
import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.TreePath;
+import jp.sfjp.jindolf.config.AppSetting;
+import jp.sfjp.jindolf.config.ConfigStore;
+import jp.sfjp.jindolf.config.OptionInfo;
+import jp.sfjp.jindolf.data.Anchor;
+import jp.sfjp.jindolf.data.DialogPref;
+import jp.sfjp.jindolf.data.Land;
+import jp.sfjp.jindolf.data.LandsModel;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.RegexPattern;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.dxchg.CsvExporter;
+import jp.sfjp.jindolf.dxchg.WebIPCDialog;
+import jp.sfjp.jindolf.editor.TalkPreview;
+import jp.sfjp.jindolf.glyph.AnchorHitEvent;
+import jp.sfjp.jindolf.glyph.AnchorHitListener;
+import jp.sfjp.jindolf.glyph.Discussion;
+import jp.sfjp.jindolf.glyph.FontInfo;
+import jp.sfjp.jindolf.glyph.TalkDraw;
+import jp.sfjp.jindolf.log.LogFrame;
+import jp.sfjp.jindolf.log.LogUtils;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.net.ProxyInfo;
+import jp.sfjp.jindolf.net.ServerAccess;
+import jp.sfjp.jindolf.summary.DaySummary;
+import jp.sfjp.jindolf.summary.VillageDigest;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sfjp.jindolf.util.StringUtils;
+import jp.sfjp.jindolf.view.AccountPanel;
+import jp.sfjp.jindolf.view.ActionManager;
+import jp.sfjp.jindolf.view.FilterPanel;
+import jp.sfjp.jindolf.view.FindPanel;
+import jp.sfjp.jindolf.view.HelpFrame;
+import jp.sfjp.jindolf.view.LandsTree;
+import jp.sfjp.jindolf.view.OptionPanel;
+import jp.sfjp.jindolf.view.PeriodView;
+import jp.sfjp.jindolf.view.TabBrowser;
+import jp.sfjp.jindolf.view.TopView;
import jp.sourceforge.jindolf.corelib.LandDef;
import jp.sourceforge.jindolf.corelib.VillageState;
+import jp.sourceforge.jovsonz.JsObject;
/**
* いわゆるMVCでいうとこのコントローラ。
ChangeListener,
AnchorHitListener {
+ private static final String TITLE_LOGGER =
+ VerInfo.getFrameTitle("ログ表示");
+ private static final String TITLE_FILTER =
+ VerInfo.getFrameTitle("発言フィルタ");
+ private static final String TITLE_EDITOR =
+ VerInfo.getFrameTitle("発言エディタ");
+ private static final String TITLE_OPTION =
+ VerInfo.getFrameTitle("オプション設定");
+ private static final String TITLE_FIND =
+ VerInfo.getFrameTitle("発言検索");
+ private static final String TITLE_ACCOUNT =
+ VerInfo.getFrameTitle("アカウント管理");
+ private static final String TITLE_DIGEST =
+ VerInfo.getFrameTitle("村のダイジェスト");
+ private static final String TITLE_DAYSUMMARY =
+ VerInfo.getFrameTitle("発言集計");
+ private static final String TITLE_HELP =
+ VerInfo.getFrameTitle("ヘルプ");
+
+ private static final LogWrapper LOGGER = new LogWrapper();
+
+
+ private final AppSetting appSetting;
private final ActionManager actionManager;
private final TopView topView;
private final LandsModel model;
/**
* コントローラの生成。
+ * @param setting アプリ設定
* @param actionManager アクション管理
* @param topView 最上位ビュー
* @param model 最上位データモデル
*/
- public Controller(ActionManager actionManager,
+ @SuppressWarnings("LeakingThisInConstructor")
+ public Controller(AppSetting setting,
+ ActionManager actionManager,
TopView topView,
LandsModel model){
super();
+ this.appSetting = setting;
this.actionManager = actionManager;
this.topView = topView;
this.model = model;
reloadVillageListButton.setEnabled(false);
this.filterFrame = new FilterPanel(this.topFrame);
+ this.filterFrame.setTitle(TITLE_FILTER);
this.filterFrame.addChangeListener(this);
this.filterFrame.pack();
this.filterFrame.setVisible(false);
this.showlogFrame = new LogFrame(this.topFrame);
+ this.showlogFrame.setTitle(TITLE_LOGGER);
this.showlogFrame.pack();
this.showlogFrame.setSize(600, 500);
this.showlogFrame.setLocationByPlatform(true);
this.showlogFrame.setVisible(false);
- if(Jindolf.hasLoggingPermission()){
- Handler newHandler = this.showlogFrame.getHandler();
- Logger jre14Logger = Jindolf.logger().getJre14Logger();
- jre14Logger.addHandler(newHandler);
- Handler[] handlers = jre14Logger.getHandlers();
- for(Handler handler : handlers){
- if( ! (handler instanceof PileHandler) ) continue;
- PileHandler pile = (PileHandler) handler;
- pile.delegate(newHandler);
- pile.close();
- }
- }
+ Logger rootLogger = Logger.getLogger("");
+ Handler newHandler = this.showlogFrame.getHandler();
+ LogUtils.switchHandler(rootLogger, newHandler);
this.talkPreview = new TalkPreview();
+ this.talkPreview.setTitle(TITLE_EDITOR);
this.talkPreview.pack();
this.talkPreview.setSize(700, 500);
this.talkPreview.setVisible(false);
- this.talkPreview.loadDraft();
this.optionPanel = new OptionPanel(this.topFrame);
+ this.optionPanel.setTitle(TITLE_OPTION);
this.optionPanel.pack();
this.optionPanel.setSize(450, 500);
this.optionPanel.setVisible(false);
this.findPanel = new FindPanel(this.topFrame);
+ this.findPanel.setTitle(TITLE_FIND);
this.findPanel.pack();
this.findPanel.setVisible(false);
- this.findPanel.loadHistory();
this.windowMap.put(this.filterFrame, true);
this.windowMap.put(this.showlogFrame, false);
this.windowMap.put(this.optionPanel, false);
this.windowMap.put(this.findPanel, true);
- AppSetting setting = Jindolf.getAppSetting();
+ ConfigStore config = this.appSetting.getConfigStore();
+
+ JsObject draft = config.loadDraftConfig();
+ this.talkPreview.putJson(draft);
- FontInfo fontInfo = setting.getFontInfo();
+ JsObject history = config.loadHistoryConfig();
+ this.findPanel.putJson(history);
+
+ FontInfo fontInfo = this.appSetting.getFontInfo();
this.topView.getTabBrowser().setFontInfo(fontInfo);
this.talkPreview.setFontInfo(fontInfo);
this.optionPanel.getFontChooser().setFontInfo(fontInfo);
- ProxyInfo proxyInfo = setting.getProxyInfo();
+ ProxyInfo proxyInfo = this.appSetting.getProxyInfo();
this.optionPanel.getProxyChooser().setProxyInfo(proxyInfo);
- DialogPref pref = setting.getDialogPref();
+ DialogPref pref = this.appSetting.getDialogPref();
this.topView.getTabBrowser().setDialogPref(pref);
this.optionPanel.getDialogPrefPanel().setDialogPref(pref);
* About画面を表示する。
*/
private void actionAbout(){
- String message =
- Jindolf.TITLE
- + " Version " + Jindolf.VERSION + "\n"
- + Jindolf.COPYRIGHT + "\n"
- + "ライセンス: " + Jindolf.LICENSE + "\n"
- + "連絡先: " + Jindolf.CONTACT;
-
- if(Jindolf.COMMENT.length() > 0){
- message += "\n" + Jindolf.COMMENT;
- }
-
+ String message = VerInfo.getAboutMessage();
JOptionPane pane = new JOptionPane(message,
JOptionPane.INFORMATION_MESSAGE,
JOptionPane.DEFAULT_OPTION,
GUIUtils.getLogoIcon());
JDialog dialog = pane.createDialog(this.topFrame,
- Jindolf.TITLE + "について");
+ VerInfo.TITLE + "について");
dialog.pack();
dialog.setVisible(true);
return;
}
- this.helpFrame = new HelpFrame();
+ OptionInfo optInfo = this.appSetting.getOptionInfo();
+ ConfigStore configStore = this.appSetting.getConfigStore();
+
+ this.helpFrame = new HelpFrame(optInfo, configStore);
+ this.helpFrame.setTitle(TITLE_HELP);
this.helpFrame.pack();
this.helpFrame.setSize(450, 450);
* ポータルサイトをWebブラウザで表示する。
*/
private void actionShowPortal(){
- WebIPCDialog.showDialog(this.topFrame, Jindolf.CONTACT);
+ WebIPCDialog.showDialog(this.topFrame, VerInfo.CONTACT);
return;
}
* @param e 例外
*/
private void warnDialog(String title, String message, Throwable e){
- Jindolf.logger().warn(message, e);
+ LOGGER.warn(message, e);
JOptionPane.showMessageDialog(
this.topFrame,
message,
- title + " - " + Jindolf.TITLE,
+ VerInfo.getFrameTitle(title),
JOptionPane.WARNING_MESSAGE );
return;
}
return;
}
- Jindolf.logger().info(
+ LOGGER.info(
"Look&Feelが["
+lnf.getName()
+"]に変更されました。");
try{
SwingUtilities.invokeAndWait(updateUITask);
}catch(InvocationTargetException e){
- Jindolf.logger().warn(
+ LOGGER.warn(
"Look&Feelの更新に失敗しました。", e);
}catch(InterruptedException e){
- Jindolf.logger().warn(
+ LOGGER.warn(
"Look&Feelの更新に失敗しました。", e);
}finally{
updateStatusBar("Look&Feelが更新されました");
}
this.accountFrame = new AccountPanel(this.topFrame, this.model);
+ this.accountFrame.setTitle(TITLE_ACCOUNT);
this.accountFrame.pack();
this.accountFrame.setVisible(true);
* オプション設定画面を表示する。
*/
private void actionOption(){
- AppSetting setting = Jindolf.getAppSetting();
-
- FontInfo fontInfo = setting.getFontInfo();
+ FontInfo fontInfo = this.appSetting.getFontInfo();
this.optionPanel.getFontChooser().setFontInfo(fontInfo);
- ProxyInfo proxyInfo = setting.getProxyInfo();
+ ProxyInfo proxyInfo = this.appSetting.getProxyInfo();
this.optionPanel.getProxyChooser().setProxyInfo(proxyInfo);
- DialogPref dialogPref = setting.getDialogPref();
+ DialogPref dialogPref = this.appSetting.getDialogPref();
this.optionPanel.getDialogPrefPanel().setDialogPref(dialogPref);
this.optionPanel.setVisible(true);
* @param newFontInfo 新フォント設定
*/
private void updateFontInfo(final FontInfo newFontInfo){
- AppSetting setting = Jindolf.getAppSetting();
- FontInfo oldInfo = setting.getFontInfo();
+ FontInfo oldInfo = this.appSetting.getFontInfo();
if(newFontInfo.equals(oldInfo)) return;
- setting.setFontInfo(newFontInfo);
+ this.appSetting.setFontInfo(newFontInfo);
this.topView.getTabBrowser().setFontInfo(newFontInfo);
this.talkPreview.setFontInfo(newFontInfo);
* @param newProxyInfo 新プロクシ設定
*/
private void updateProxyInfo(ProxyInfo newProxyInfo){
- AppSetting setting = Jindolf.getAppSetting();
- ProxyInfo oldProxyInfo = setting.getProxyInfo();
+ ProxyInfo oldProxyInfo = this.appSetting.getProxyInfo();
if(newProxyInfo.equals(oldProxyInfo)) return;
- setting.setProxyInfo(newProxyInfo);
+ this.appSetting.setProxyInfo(newProxyInfo);
for(Land land : this.model.getLandList()){
ServerAccess server = land.getServerAccess();
* @param newDialogPref 表示設定
*/
private void updateDialogPref(DialogPref newDialogPref){
- AppSetting setting = Jindolf.getAppSetting();
- DialogPref oldDialogPref = setting.getDialogPref();
+ DialogPref oldDialogPref = this.appSetting.getDialogPref();
if(newDialogPref.equals(oldDialogPref)) return;
- setting.setDialogPref(newDialogPref);
+ this.appSetting.setDialogPref(newDialogPref);
this.topView.getTabBrowser().setDialogPref(newDialogPref);
) || ! village.isValid() ){
String message = "エピローグを正常に迎えていない村は\n"
+"ダイジェスト機能を利用できません";
- String title = "ダイジェスト不可 - " + Jindolf.TITLE;
+ String title = VerInfo.getFrameTitle("ダイジェスト不可");
JOptionPane pane = new JOptionPane(message,
JOptionPane.WARNING_MESSAGE,
JOptionPane.DEFAULT_OPTION );
if(this.digestPanel == null){
this.digestPanel = new VillageDigest(this.topFrame);
+ this.digestPanel.setTitle(TITLE_DIGEST);
this.digestPanel.pack();
this.digestPanel.setSize(600, 550);
this.windowMap.put(this.digestPanel, false);
}
}
loginfo += hitMessage;
- Jindolf.logger().info(loginfo);
+ LOGGER.info(loginfo);
return;
}
}
}
loginfo += hitMessage;
- Jindolf.logger().info(loginfo);
+ LOGGER.info(loginfo);
return;
}
if(this.daySummaryPanel == null){
this.daySummaryPanel = new DaySummary(this.topFrame);
+ this.daySummaryPanel.setTitle(TITLE_DAYSUMMARY);
this.daySummaryPanel.pack();
this.daySummaryPanel.setSize(400, 500);
}
}
});
}catch(InvocationTargetException e){
- Jindolf.logger().fatal(
+ LOGGER.fatal(
"タブ操作で致命的な障害が発生しました", e);
}catch(InterruptedException e){
- Jindolf.logger().fatal(
+ LOGGER.fatal(
"タブ操作で致命的な障害が発生しました", e);
}
updateStatusBar("村情報を読み直しました…");
}
});
}catch(InvocationTargetException e){
- Jindolf.logger().fatal(
+ LOGGER.fatal(
"ブラウザ表示で致命的な障害が発生しました", e);
}catch(InterruptedException e){
- Jindolf.logger().fatal(
+ LOGGER.fatal(
"ブラウザ表示で致命的な障害が発生しました", e);
}
EventQueue.invokeLater(new Runnable(){
* @param e ネットワークエラー
*/
public void showNetworkError(Land land, IOException e){
- Jindolf.logger().warn("ネットワークで障害が発生しました", e);
+ LOGGER.warn("ネットワークで障害が発生しました", e);
ServerAccess server = land.getServerAccess();
String message =
JOptionPane.WARNING_MESSAGE,
JOptionPane.DEFAULT_OPTION );
- JDialog dialog = pane.createDialog(this.topFrame,
- "通信異常発生 - " + Jindolf.TITLE);
+ String title = VerInfo.getFrameTitle("通信異常発生");
+ JDialog dialog = pane.createDialog(this.topFrame, title);
dialog.pack();
dialog.setVisible(true);
try{
SwingUtilities.invokeAndWait(microJob);
}catch(InvocationTargetException e){
- Jindolf.logger().fatal("ビジー処理で失敗", e);
+ LOGGER.fatal("ビジー処理で失敗", e);
}catch(InterruptedException e){
- Jindolf.logger().fatal("ビジー処理で失敗", e);
+ LOGGER.fatal("ビジー処理で失敗", e);
}
}
* タイトルは指定された国or村名 + " - Jindolf"
* @param name 国or村名
*/
- private void setFrameTitle(CharSequence name){
- String title = Jindolf.TITLE;
-
- if(name != null && name.length() > 0){
- title = name + " - " + title;
- }
-
+ private void setFrameTitle(String name){
+ String title = VerInfo.getFrameTitle(name);
this.topFrame.setTitle(title);
-
return;
}
* アプリ正常終了処理。
*/
private void shutdown(){
- this.findPanel.saveHistory();
- this.talkPreview.saveDraft();
- Jindolf.getAppSetting().saveConfig();
- Jindolf.exit(0);
+ ConfigStore configStore = this.appSetting.getConfigStore();
+
+ JsObject findConf = this.findPanel.getJson();
+ if( ! this.findPanel.hasConfChanged(findConf) ){
+ configStore.saveHistoryConfig(findConf);
+ }
+
+ JsObject draftConf = this.talkPreview.getJson();
+ if( ! this.talkPreview.hasConfChanged(draftConf) ){
+ configStore.saveDraftConfig(draftConf);
+ }
+
+ this.appSetting.saveConfig();
+
+ LOGGER.info("VMごとアプリケーションを終了します。");
+ System.exit(0); // invoke shutdown hooks... BYE !
+
+ assert false;
return;
}
--- /dev/null
+/*
+ * Jindolf main class
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+package jp.sfjp.jindolf;
+
+/**
+ * Jindolf スタートアップクラス。
+ * <p>JRE実行系の互換性検査を主目的とする。
+ * <p>このクラスではJRE1.0互換なランタイムライブラリのみが利用できる。
+ * <p>このクラスはJRE1.0でもコンパイルできなければならない。
+ * アプリ開始はstaticメソッド{@link #main(String[])}呼び出しから。
+ */
+public final class Jindolf {
+
+ /**
+ * 隠しコンストラクタ。
+ */
+ private Jindolf(){
+ super();
+ return;
+ }
+
+ /**
+ * Jindolf のスタートアップエントリ。
+ * @param args コマンドライン引数
+ */
+ public static void main(String[] args){
+ JreChecker.checkJre();
+
+ JindolfJre15.main(args);
+
+ return;
+ }
+
+}
--- /dev/null
+/*
+ * Jindolf main class
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+package jp.sfjp.jindolf;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.swing.JOptionPane;
+
+/**
+ * GUIとUnicode出力とリソースアクセスが解禁された
+ * Jindolf スタートアップクラス。
+ * <p>Jindolf_jre15の下請け。
+ */
+public final class JindolfGuiJp {
+
+ private static final String TITLE_INVOKEDBL = "多重起動";
+ private static final String MSG_INVOKEDBL =
+ "ERROR : 二度目以降の起動がキャンセルされました。";
+
+ /** 多重起動防止用セマフォ。 */
+ private static final AtomicBoolean INVOKE_FLAG =
+ new AtomicBoolean(false);
+
+
+ /**
+ * 隠しコンストラクタ。
+ */
+ private JindolfGuiJp(){
+ super();
+ assert false;
+ return;
+ }
+
+ /**
+ * JVM内で多重起動していないかチェックする。
+ * <p>多重起動を確認した場合は、GUIにダイアログを出力する。
+ * @return 多重起動していたらtrue
+ */
+ private static boolean hasInvokedCheck(){
+ boolean successed = INVOKE_FLAG.compareAndSet(false, true);
+ if(successed) return false;
+
+ JOptionPane.showMessageDialog(null,
+ MSG_INVOKEDBL,
+ TITLE_INVOKEDBL,
+ JOptionPane.ERROR_MESSAGE);
+
+ return true;
+ }
+
+ /**
+ * Jindolf のスタートアップエントリ。
+ * <p>ここからGUIとUnicode出力とリソースアクセスが解禁される。
+ * @param args コマンドライン引数
+ */
+ static void main(String... args){
+ if(hasInvokedCheck()) return;
+
+ JindolfOld.main(args);
+
+ return;
+ }
+
+}
--- /dev/null
+/*
+ * Jindolf main class
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+package jp.sfjp.jindolf;
+
+import java.awt.GraphicsEnvironment;
+import javax.swing.JOptionPane;
+
+/**
+ * JRE1.5の利用が解禁されたJindolfエントリ。
+ * <p>起動クラスJindolfの下請けとしての機能が想定される。
+ * <p>必ずしも必要ないが、異常系切り分けに有用な、
+ * 実行環境やビルドの成否に関する各種診断を行う。
+ */
+public final class JindolfJre15 {
+
+ /** exit code. */
+ public static final int EXIT_CODE_HEADLESS = 1;
+ /** exit code. */
+ public static final int EXIT_CODE_BUILDENCO = 1;
+ /** exit code. */
+ public static final int EXIT_CODE_INVMANIFEST = 1;
+
+
+ /**
+ * 隠しコンストラクタ。
+ */
+ private JindolfJre15(){
+ super();
+ assert false;
+ return;
+ }
+
+
+ /**
+ * GUI環境の有無をチェックする。
+ * GUI環境に接続できなければJVMを終了させる。
+ */
+ private static void checkGuiEnv(){
+ if( ! GraphicsEnvironment.isHeadless() ) return;
+
+ String dispEnv;
+ try{
+ dispEnv = System.getenv("DISPLAY");
+ }catch(SecurityException e){
+ dispEnv = null;
+ }
+
+ StringBuilder message = new StringBuilder();
+
+ message.append("ERROR : GUI session failed.");
+
+ if(dispEnv != null){
+ message.append('\n')
+ .append("Environment DISPLAY [")
+ .append(dispEnv)
+ .append("]");
+ }
+
+ System.err.println(message);
+ System.err.flush();
+
+ System.exit(EXIT_CODE_HEADLESS);
+
+ assert false;
+ return;
+ }
+
+ /**
+ * エラーダイアログの出力。
+ * @param errmsg エラーメッセージ
+ * @param title タイトル
+ */
+ private static void showErrorDialog(String errmsg, String title){
+ JOptionPane.showMessageDialog(null,
+ errmsg,
+ title,
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ /**
+ * ビルド時のエンコーディングミスを判定する。
+ * ※ 非Unicode系の開発環境を使いたい人は適当に無視してね。
+ */
+ private static void checkBuildError(){
+ if( '狼' == 0x72fc
+ && ' ' == 0x3000
+ && '~' == 0x007e
+ && '\\' == 0x005c // バックスラッシュ
+ && '¥' == 0x00a5 // 半角円通貨
+ && '~' == 0xff5e
+ && '�' == 0xfffd // Unicode専用特殊文字
+ ){
+ return;
+ }
+
+ String errmsg =
+ "ERROR : Invalid source-code encoding detected.\n"
+ +"Let's check encoding with compiler & source-file.";
+
+ showErrorDialog(errmsg, "Build failed");
+
+ System.exit(EXIT_CODE_BUILDENCO);
+
+ assert false;
+ return;
+ }
+
+ /**
+ * MANIFEST.MFパッケージ定義エラーの検出。
+ */
+ private static void checkPackageDefinition(){
+ Package rootPkg = ResourceManager.DEF_ROOT_PACKAGE;
+ String implTitle = rootPkg.getImplementationTitle();
+ String implVersion = rootPkg.getImplementationVersion();
+ String implVendor = rootPkg.getImplementationVendor();
+
+ String title = "ビルドエラー";
+
+ if(implTitle != null && ! VerInfo.TITLE.equals(implTitle) ){
+ String errmsg = "パッケージ定義とタイトルが一致しません。"
+ +"["+ implTitle +"]≠["+ VerInfo.TITLE +"]";
+ showErrorDialog(errmsg, title);
+ System.exit(EXIT_CODE_INVMANIFEST);
+ assert false;
+ }
+
+ if(implVersion != null && ! VerInfo.VERSION.equals(implVersion) ){
+ String errmsg = "パッケージ定義とバージョン番号が一致しません。"
+ +"["+ implVersion +"]≠["+ VerInfo.VERSION +"]";
+ showErrorDialog(errmsg, title);
+ System.exit(EXIT_CODE_INVMANIFEST);
+ assert false;
+ }
+
+ if(implVendor != null && ! VerInfo.AUTHOR.equals(implVendor) ){
+ String errmsg = "パッケージ定義とベンダが一致しません。"
+ +"["+ implVendor +"]≠["+ VerInfo.AUTHOR +"]";
+ showErrorDialog(errmsg, title);
+ System.exit(EXIT_CODE_INVMANIFEST);
+ assert false;
+ }
+
+ return;
+ }
+
+ /**
+ * Jindolf のスタートアップエントリ。
+ * <p>ここからJRE1.5の利用が解禁される。
+ * @param args コマンドライン引数
+ */
+ static void main(String... args){
+ checkGuiEnv();
+ // ここから異常系でのSwingGUI解禁
+
+ checkBuildError();
+ // ここからUnicode出力解禁。
+
+ checkPackageDefinition();
+
+ JindolfGuiJp.main(args);
+
+ return;
+ }
+
+}
--- /dev/null
+/*
+ * Jindolf main class
+ *
+ * License : The MIT License
+ * Copyright(c) 2008 olyutorskii
+ */
+
+package jp.sfjp.jindolf;
+
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Window;
+import java.lang.reflect.InvocationTargetException;
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.util.Date;
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JWindow;
+import javax.swing.UIManager;
+import jp.sfjp.jindolf.config.AppSetting;
+import jp.sfjp.jindolf.config.CmdOption;
+import jp.sfjp.jindolf.config.ConfigFile;
+import jp.sfjp.jindolf.config.ConfigStore;
+import jp.sfjp.jindolf.config.EnvInfo;
+import jp.sfjp.jindolf.config.OptionInfo;
+import jp.sfjp.jindolf.data.LandsModel;
+import jp.sfjp.jindolf.glyph.Discussion;
+import jp.sfjp.jindolf.glyph.GlyphDraw;
+import jp.sfjp.jindolf.log.LogUtils;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.log.LoggingDispatcher;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sfjp.jindolf.view.ActionManager;
+import jp.sfjp.jindolf.view.TabBrowser;
+import jp.sfjp.jindolf.view.TopView;
+
+/**
+ * Jindolf スタートアップクラス。
+ *
+ * コンストラクタは無いよ。
+ * アプリ開始はstaticメソッド{@link #main(String[])}呼び出しから。
+ */
+public final class JindolfOld {
+
+ /** このClass。 */
+ public static final Class<?> SELF_KLASS;
+ /** クラスローダ。 */
+ public static final ClassLoader LOADER;
+
+
+ /** クラスロード時のナノカウント。 */
+ public static final long NANOCT_LOADED;
+ /** クラスロード時刻(エポックmsec)。 */
+ public static final long EPOCHMS_LOADED;
+
+
+ /** ロガー。 */
+ private static final LogWrapper LOGGER = new LogWrapper();
+
+ /** スプラッシュロゴ。 */
+ private static final String RES_LOGOICON =
+ "resources/image/logo.png";
+
+ static{
+ SELF_KLASS = JindolfOld.class;
+
+ ClassLoader thisLoader;
+ try{
+ thisLoader = SELF_KLASS.getClassLoader();
+ }catch(SecurityException e){
+ thisLoader = null;
+ }
+ LOADER = thisLoader;
+
+ NANOCT_LOADED = System.nanoTime();
+ EPOCHMS_LOADED = System.currentTimeMillis();
+
+ new JindolfOld().hashCode();
+ }
+
+
+ /**
+ * 隠れコンストラクタ。
+ */
+ private JindolfOld(){
+ super();
+ assert this.getClass() == SELF_KLASS;
+ return;
+ }
+
+
+ /**
+ * 標準出力端末にヘルプメッセージ(オプションの説明)を表示する。
+ */
+ private static void showHelpMessage(){
+ System.out.flush();
+ System.err.flush();
+
+ CharSequence helpText = CmdOption.getHelpText();
+ System.out.print(helpText);
+
+ System.out.flush();
+ System.err.flush();
+
+ return;
+ }
+
+ /**
+ * スプラッシュウィンドウを表示する。
+ * <p>JRE1.6以降では何も表示しない。
+ * @return スプラッシュウィンドウ。JRE1.6以降ならnullを返す。
+ */
+ @SuppressWarnings("CallToThreadYield")
+ private static Window showSplash(){
+ if(JreChecker.has16Runtime()) return null;
+
+ Window splashWindow = new JWindow();
+
+ ImageIcon logo = ResourceManager.getImageIcon(RES_LOGOICON);
+ JLabel splashLabel = new JLabel(logo);
+ splashWindow.add(splashLabel);
+
+ splashWindow.pack();
+ splashWindow.setLocationRelativeTo(null); // locate center
+ splashWindow.setVisible(true);
+
+ Thread.yield();
+
+ return splashWindow;
+ }
+
+ /**
+ * スプラッシュウィンドウを隠す。
+ * @param splashWindow スプラッシュウィンドウ。nullならなにもしない。
+ */
+ @SuppressWarnings("CallToThreadYield")
+ private static void hideSplash(Window splashWindow){
+ if(splashWindow == null) return;
+
+ splashWindow.setVisible(false);
+ splashWindow.dispose();
+
+ Thread.yield();
+
+ return;
+ }
+
+ /**
+ * 起動時の諸々の情報をログ出力する。
+ * @param optinfo コマンドライン情報
+ * @param configStore 設定ディレクトリ情報
+ */
+ private static void dumpBootInfo(OptionInfo optinfo,
+ ConfigStore configStore ){
+ DateFormat dform = DateFormat.getDateTimeInstance();
+ NumberFormat nform = NumberFormat.getNumberInstance();
+
+ LOGGER.info(
+ VerInfo.ID + " は "
+ + dform.format(new Date(EPOCHMS_LOADED))
+ + " にVM上のクラス "
+ + SELF_KLASS.getName() + " としてロードされました。 " );
+
+ LOGGER.info("Initial Nano-Count : " + nform.format(NANOCT_LOADED));
+
+ Runtime runtime = Runtime.getRuntime();
+ LOGGER.info(
+ "Max-heap : "
+ + nform.format(runtime.maxMemory()) + " Byte"
+ + " Total-heap : "
+ + nform.format(runtime.totalMemory()) + " Byte");
+
+ StringBuilder bootArgs = new StringBuilder();
+ bootArgs.append("\n\n").append("起動時引数:\n");
+ for(String arg : optinfo.getInvokeArgList()){
+ bootArgs.append("\u0020\u0020").append(arg).append('\n');
+ }
+ bootArgs.append('\n');
+ bootArgs.append(EnvInfo.getVMInfo());
+ LOGGER.info(bootArgs);
+
+ if(configStore.useStoreFile()){
+ LOGGER.info("設定格納ディレクトリに[ "
+ + configStore.getConfigPath().getPath()
+ + " ]が指定されました。");
+ }else{
+ LOGGER.info("設定格納ディレクトリは使いません。");
+ }
+
+ if( JreChecker.has16Runtime()
+ && optinfo.hasOption(CmdOption.OPT_NOSPLASH) ){
+ LOGGER.warn(
+ "JRE1.6以降では、"
+ +"Jindolfの-nosplashオプションは無効です。"
+ + "Java実行系の方でスプラッシュ画面の非表示を"
+ + "指示してください(おそらく空の-splash:オプション)" );
+ }
+
+ if(LOADER == null){
+ LOGGER.warn(
+ "セキュリティ設定により、"
+ +"クラスローダを取得できませんでした");
+ }
+
+ return;
+ }
+
+ /**
+ * 任意のクラス群に対して一括ロード/初期化を単一スレッドで順に行う。
+ * どーしてもクラス初期化の順序に依存する障害が発生する場合や
+ * クラス初期化のオーバーヘッドでGUIの操作性が損なわれるときなどにどうぞ。
+ *
+ * @throws java.lang.LinkageError クラス間リンケージエラー。
+ * @throws java.lang.ExceptionInInitializerError クラス初期化で異常
+ */
+ private static void preInitClass()
+ throws LinkageError,
+ ExceptionInInitializerError {
+ Object[] classes = { // Class型 または String型
+ "java.lang.Object",
+ TabBrowser.class,
+ Discussion.class,
+ GlyphDraw.class,
+ java.net.HttpURLConnection.class,
+ java.text.SimpleDateFormat.class,
+ Void.class,
+ };
+
+ for(Object obj : classes){
+ String className;
+ if(obj instanceof Class){
+ className = ((Class<?>)obj).getName();
+ }else if(obj instanceof String){
+ className = obj.toString();
+ }else{
+ continue;
+ }
+
+ try{
+ if(LOADER != null){
+ Class.forName(className, true, LOADER);
+ }else{
+ Class.forName(className);
+ }
+ }catch(ClassNotFoundException e){
+ LOGGER.warn("クラスの明示的ロードに失敗しました", e);
+ continue;
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * JindolfOld のスタートアップエントリ。
+ *
+ * @param args コマンドライン引数
+ */
+ static void main(String... args){
+ OptionInfo optinfo;
+
+ try{
+ optinfo = OptionInfo.parseOptions(args);
+ }catch(IllegalArgumentException e){
+ String message = e.getLocalizedMessage();
+ System.err.println(message);
+ System.err.println(
+ "起動オプション一覧は、"
+ + "起動オプションに「"
+ + CmdOption.OPT_HELP.toString()
+ + "」を指定すると確認できます。" );
+ System.exit(1);
+ assert false;
+ return;
+ }
+
+ main(optinfo);
+
+ return;
+ }
+
+ /**
+ * JindolfOld のスタートアップエントリ。
+ *
+ * @param optinfo コマンドライン引数情報
+ */
+ static void main(OptionInfo optinfo){
+ if(optinfo.hasOption(CmdOption.OPT_HELP)){
+ showHelpMessage();
+ System.exit(0);
+ assert false;
+ return;
+ }
+
+ if(optinfo.hasOption(CmdOption.OPT_VERSION)){
+ System.out.println(VerInfo.ID);
+ System.exit(0);
+ assert false;
+ return;
+ }
+
+ // ここ以降、アプリウィンドウの生成と表示に向けてまっしぐら。
+
+ // あらゆるSwing文字列表示処理より前に必要。
+ // システムプロパティ swing.boldMetal は無視される。
+ Boolean boldFlag;
+ if(optinfo.hasOption(CmdOption.OPT_BOLDMETAL)){
+ // もの凄く日本語表示が汚くなるかもよ!注意
+ boldFlag = Boolean.TRUE;
+ }else{
+ boldFlag = Boolean.FALSE;
+ }
+ UIManager.put("swing.boldMetal", boldFlag);
+
+ // JRE1.5用スプラッシュウィンドウ
+ Window splashWindow = null;
+ if( ! optinfo.hasOption(CmdOption.OPT_NOSPLASH) ){
+ splashWindow = showSplash();
+ }
+
+ boolean hasError = false;
+ try{
+ hasError = splashedMain(optinfo);
+ }finally{
+ hideSplash(splashWindow);
+ }
+
+ if(hasError) System.exit(1);
+
+ return;
+ }
+
+ /**
+ * JindolfOld のスタートアップエントリ。
+ * <p>スプラッシュウィンドウが出ている状態。
+ * @param optinfo コマンドライン引数情報
+ * @return エラーがあればtrue
+ */
+ static boolean splashedMain(OptionInfo optinfo){
+ final AppSetting appSetting = new AppSetting();
+ appSetting.applyOptionInfo(optinfo);
+
+ if(optinfo.hasOption(CmdOption.OPT_VMINFO)){
+ System.out.println(EnvInfo.getVMInfo());
+ }
+
+ LogUtils.initRootLogger(optinfo.hasOption(CmdOption.OPT_CONSOLELOG));
+ // ここからロギング解禁
+
+ ConfigStore configStore = appSetting.getConfigStore();
+ dumpBootInfo(optinfo, configStore);
+
+ ConfigFile.setupConfigDirectory(configStore);
+ ConfigFile.setupLockFile(configStore);
+ // ここから設定格納ディレクトリ解禁
+
+ appSetting.loadConfig();
+
+ final Runtime runtime = Runtime.getRuntime();
+ runtime.addShutdownHook(new Thread(){
+ @Override
+ @SuppressWarnings("CallToThreadYield")
+ public void run(){
+ LOGGER.info("シャットダウン処理に入ります…");
+ System.out.flush();
+ System.err.flush();
+ runtime.gc();
+ Thread.yield();
+ runtime.runFinalization(); // 危険?
+ Thread.yield();
+ return;
+ }
+ });
+
+ preInitClass();
+
+ LoggingDispatcher.replaceEventQueue();
+
+ boolean hasError = false;
+ try{
+ EventQueue.invokeAndWait(new Runnable(){
+ public void run(){
+ startGUI(appSetting);
+ return;
+ }
+ });
+ }catch(InvocationTargetException e){
+ LOGGER.fatal("アプリケーション初期化に失敗しました", e);
+ e.printStackTrace(System.err);
+ hasError = true;
+ }catch(InterruptedException e){
+ LOGGER.fatal("アプリケーション初期化に失敗しました", e);
+ e.printStackTrace(System.err);
+ hasError = true;
+ }
+
+ return hasError;
+ }
+
+ /**
+ * AWTイベントディスパッチスレッド版スタートアップエントリ。
+ * @param appSetting アプリ設定
+ */
+ private static void startGUI(AppSetting appSetting){
+ LandsModel model = new LandsModel();
+ model.loadLandList();
+
+ JFrame topFrame = buildMVC(appSetting, model);
+
+ GUIUtils.modifyWindowAttributes(topFrame, true, false, true);
+
+ topFrame.pack();
+
+ Dimension initGeometry =
+ new Dimension(appSetting.initialFrameWidth(),
+ appSetting.initialFrameHeight());
+ topFrame.setSize(initGeometry);
+
+ if( appSetting.initialFrameXpos() <= Integer.MIN_VALUE
+ || appSetting.initialFrameYpos() <= Integer.MIN_VALUE ){
+ topFrame.setLocationByPlatform(true);
+ }else{
+ topFrame.setLocation(appSetting.initialFrameXpos(),
+ appSetting.initialFrameYpos() );
+ }
+
+ topFrame.setVisible(true);
+
+ return;
+ }
+
+ /**
+ * モデル・ビュー・コントローラの結合。
+ * @param appSetting アプリ設定
+ * @param model 最上位のデータモデル
+ * @return アプリケーションのトップフレーム
+ */
+ private static JFrame buildMVC(AppSetting appSetting, LandsModel model){
+ ActionManager actionManager = new ActionManager();
+ TopView topView = new TopView();
+
+ Controller controller =
+ new Controller(appSetting, actionManager, topView, model);
+
+ JFrame topFrame = controller.createTopFrame();
+
+ return topFrame;
+ }
+
+}
--- /dev/null
+/*
+ * JRE checker
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+package jp.sfjp.jindolf;
+
+import javax.swing.JOptionPane;
+
+/**
+ * JRE互換性のチェックを行う。
+ * <p>JREのバージョンと、
+ * JREに含まれるjava.langパッケージ仕様のバージョンは互換性があるものとする。
+ * <p>なるべく昔のJREでも動くように。
+ * 少なくとも1.2以降。できれば1.0以降。
+ * 原則、1.3以降の新設ライブラリは利用禁止。
+ * <p>なるべく昔のコンパイラでもコンパイルできるように。
+ * 少なくとも1.2以降。できれば1.0以降。
+ * 原則、assert文、総称ジェネリクス、アノテーションは禁止。
+ * <p>できればBasic-Latinに入らない文字(日本語)の出力も禁止。
+ * <p>ランタイム存在検査用のクラスは、ロードや初期化が軽いほうが望ましい。
+ * そしていずれJindolfの実行に必要なものであるのが望ましい。
+ * もしそうでない場合でも、
+ * Jindolfに関係ないクラスの連鎖ロードが起きにくいほうが望ましい。
+ */
+public final class JreChecker {
+
+ /** required JRE version. */
+ public static final String REQUIRED_JRE_VER = "1.5";
+
+ /** exit code. */
+ public static final int EXIT_CODE_INCOMPAT_JRE = 1;
+
+ private static final String DIALOG_TITLE =
+ "JRE Incompatibility detected...";
+
+ private static final int MAX_LINE = 40;
+
+
+ /**
+ * 隠しコンストラクタ。
+ */
+ private JreChecker(){
+ super();
+ return;
+ }
+
+
+ /**
+ * クラス名に相当するクラスがロードできるか判定する。
+ * @param klassName FQDNなクラス名
+ * @return ロードできたらtrue
+ */
+ private static boolean hasClass(String klassName){
+ boolean result = false;
+
+ try{
+ Class.forName(klassName); // 1.2Laterな3引数版メソッドは利用禁止
+ result = true;
+ }catch(ClassNotFoundException e){
+ result = false;
+ }catch(LinkageError e){
+ throw e;
+ }
+
+ return result;
+ }
+
+ /**
+ * JRE 1.1 相当のランタイムライブラリが提供されているか判定する。
+ * @return 提供されているならtrue
+ */
+ public static boolean has11Runtime(){
+ boolean result = hasClass("java.io.Serializable");
+ return result;
+ }
+
+ /**
+ * JRE 1.2 相当のランタイムライブラリが提供されているか判定する。
+ * @return 提供されているならtrue
+ */
+ public static boolean has12Runtime(){
+ boolean result;
+ if(has11Runtime()) result = hasClass("java.util.Iterator");
+ else result = false;
+ return result;
+ }
+
+ /**
+ * JRE 1.3 相当のランタイムライブラリが提供されているか判定する。
+ * @return 提供されているならtrue
+ */
+ public static boolean has13Runtime(){
+ boolean result;
+ if(has12Runtime()) result = hasClass("java.util.TimerTask");
+ else result = false;
+ return result;
+ }
+
+ /**
+ * JRE 1.4 相当のランタイムライブラリが提供されているか判定する。
+ * @return 提供されているならtrue
+ */
+ public static boolean has14Runtime(){
+ boolean result;
+ if(has13Runtime()) result = hasClass("java.lang.CharSequence");
+ else result = false;
+ return result;
+ }
+
+ /**
+ * JRE 1.5 相当のランタイムライブラリが提供されているか判定する。
+ * @return 提供されているならtrue
+ */
+ public static boolean has15Runtime(){
+ boolean result;
+ if(has14Runtime()) result = hasClass("java.lang.Appendable");
+ else result = false;
+ return result;
+ }
+
+ /**
+ * JRE 1.6 相当のランタイムライブラリが提供されているか判定する。
+ * @return 提供されているならtrue
+ */
+ public static boolean has16Runtime(){
+ boolean result;
+ if(has15Runtime()) result = hasClass("java.util.Deque");
+ else result = false;
+ return result;
+ }
+
+ /**
+ * JREもしくはjava.langパッケージの仕様バージョンを返す。
+ * @return 仕様バージョン文字列。不明ならnull
+ */
+ public static String getLangPkgSpec(){
+ String result;
+
+ try{
+ result = System.getProperty("java.specification.version");
+ }catch(SecurityException e){
+ result = null;
+ }
+ if(result != null) return result;
+
+ try{
+ result = System.getProperty("java.version");
+ }catch(SecurityException e){
+ result = null;
+ }
+ if(result != null) return result;
+
+ Package javaLangPkg = java.lang.Object.class.getPackage();
+ if(javaLangPkg == null) return null;
+
+ result = javaLangPkg.getSpecificationVersion();
+ return result;
+ }
+
+ /**
+ * JREのインストール情報を返す。
+ * @return インストール情報。不明ならnull
+ */
+ public static String getJreHome(){
+ String result;
+
+ try{
+ result = System.getProperty("java.home");
+ }catch(SecurityException e){
+ result = null;
+ }
+ if(result != null) return result;
+
+ return result;
+ }
+
+ /**
+ * 非互換エラーメッセージを組み立てる。
+ * @return エラーメッセージ
+ */
+ public static String buildErrMessage(){
+ StringBuffer message = new StringBuffer();
+
+ message.append("ERROR : Java JRE ")
+ .append(REQUIRED_JRE_VER)
+ .append(" compatible or later required.");
+
+ String specVer = getLangPkgSpec();
+ if(specVer != null){
+ message.append('\n')
+ .append("but").append('\u0020')
+ .append(specVer)
+ .append('\u0020').append("detected.");
+ }
+
+ String jreHome = getJreHome();
+ if(jreHome != null){
+ message.append(" [ ")
+ .append(jreHome)
+ .append(" ]");
+ }
+
+ return message.toString();
+ }
+
+ /**
+ * 指定された文字数で行の長さを揃える。
+ * <p>サロゲートペアは無視される。
+ * @param text 文字列
+ * @param limit 行ごとの最大文字数
+ * @return 改行済みの文字列
+ */
+ public static String alignLine(String text, int limit){
+ StringBuffer message = new StringBuffer();
+
+ int lineLength = 0;
+
+ int textLength = text.length();
+ for(int idx = 0; idx < textLength; idx++){
+ if(lineLength >= limit){
+ message.append('\n');
+ lineLength = 0;
+ }
+
+ char ch = text.charAt(idx);
+ message.append(ch);
+
+ if(ch == '\n') lineLength = 0;
+ else lineLength++;
+ }
+
+ String result = message.toString();
+ return result;
+ }
+
+ /**
+ * Swingダイアログでエラーを報告する。
+ * <p>ボタンを押すまでの間、実行はブロックされる。
+ * <p>JRE1.2環境が用意されていなければ何もしない。
+ * <p>GUIに接続できなければ何か例外を投げるかもしれない。
+ * @param text エラー文面
+ */
+ public static void showErrorDialog(String text){
+ if( ! has12Runtime() ) return;
+ String aligned = alignLine(text, MAX_LINE);
+ JOptionPane.showMessageDialog(
+ null,
+ aligned, DIALOG_TITLE,
+ JOptionPane.ERROR_MESSAGE );
+ return;
+ }
+
+ /**
+ * JRE環境をチェックする。(JRE1.5)
+ * <p>もしJREの非互換性が検出されたらエラーメッセージを報告し、
+ * 所定の終了コードでJVMを終了させる。
+ */
+ public static void checkJre(){
+ if(has15Runtime()) return;
+
+ // 以降、JVM終了へ向けて一直線。
+ try{
+ String message = buildErrMessage();
+ System.err.println(message);
+ System.err.flush();
+ showErrorDialog(message);
+ }finally{
+ System.exit(EXIT_CODE_INCOMPAT_JRE);
+ }
+
+ return;
+ }
+
+}
--- /dev/null
+/*
+ * resource manager
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+package jp.sfjp.jindolf;
+
+import java.awt.image.BufferedImage;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.Reader;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Properties;
+import javax.imageio.ImageIO;
+import javax.swing.ImageIcon;
+
+/**
+ * 各種リソースファイルの管理。
+ * <p>{@link Class}用と{@link ClassLoader}用とでは
+ * 微妙に絶対リソース名の形式が異なることに留意せよ。
+ * <p>基本的に、リソースファイルへのアクセスにおける異常系は
+ * リカバリの対象外とする。ビルド工程の不手際扱い。
+ * @see java.lang.Class#getResource
+ */
+public final class ResourceManager {
+
+ /** リソース名セパレータ文字。 */
+ public static final char RES_SEPCHAR = '/';
+ /** パッケージ名セパレータ文字。 */
+ public static final char PKG_SEPCHAR = '.';
+
+ /** リソース名セパレータ文字列。 */
+ public static final String RES_SEPARATOR =
+ Character.toString(RES_SEPCHAR);
+ /** パッケージ名セパレータ文字列。 */
+ public static final String PKG_SEPARATOR =
+ Character.toString(PKG_SEPCHAR);
+
+ /** デフォルトで用いられるルートパッケージ。 */
+ public static final Package DEF_ROOT_PACKAGE;
+ /** デフォルトで用いられるクラスローダ。 */
+ public static final ClassLoader DEF_LOADER;
+
+ private static final Charset CS_UTF8 = Charset.forName("UTF-8");
+
+ static{
+ Class<?> rootKlass = Jindolf.class;
+
+ DEF_ROOT_PACKAGE = rootKlass.getPackage();
+ DEF_LOADER = rootKlass.getClassLoader();
+ }
+
+
+ /**
+ * 隠しコンストラクタ。
+ */
+ private ResourceManager(){
+ super();
+ assert false;
+ return;
+ }
+
+
+ /**
+ * リソース名が絶対パスか否か判定する。
+ * <p>リソース名が「/」で始まる場合絶対パスとみなされる。
+ * <p>このリソース名は{@link Class}用であって
+ * {@link ClassLoader}用ではない。
+ * @param resPath リソース名
+ * @return 絶対パスならtrueを返す。
+ * @see java.lang.Class#getResource
+ */
+ public static boolean isAbsoluteResourcePath(String resPath){
+ if (resPath.startsWith(RES_SEPARATOR)) return true;
+ return false;
+ }
+
+ /**
+ * パッケージ情報を反映するリソース名前置詞を返す。
+ * <p>パッケージ名のセパレータ「.」は「/」に置き換えられる。
+ * 無名パッケージの場合は長さゼロの空文字列を返す。
+ * 無名パッケージを除き、リソース名前置詞は必ず「/」で終わる。
+ * <p>この前置詞は{@link ClassLoader}用であって
+ * {@link Class}用ではないので、
+ * 頭に「/」が付かない。
+ * @param pkg パッケージ設定。nullは無名パッケージと認識される。
+ * @return リソース名前置詞。無名パッケージの場合は空文字列が返る。
+ * @see java.lang.Class#getResource
+ */
+ public static String getResourcePrefix(Package pkg){
+ if(pkg == null) return ""; // 無名パッケージ
+
+ String pkgName = pkg.getName();
+ String result = pkgName.replace(PKG_SEPCHAR, RES_SEPCHAR);
+ if( ! result.isEmpty() ){
+ result += RES_SEPARATOR;
+ }
+
+ return result;
+ }
+
+ /**
+ * リソース名を用いて、
+ * デフォルトのクラスローダとデフォルトのルートパッケージから
+ * リソースのURLを取得する。
+ * @param resPath リソース名
+ * @return リソースのURL。リソースが見つからなければnull。
+ */
+ public static URL getResource(String resPath){
+ return getResource(DEF_ROOT_PACKAGE, resPath);
+ }
+
+ /**
+ * 任意のルートパッケージと相対リソース名を用いて、
+ * デフォルトのクラスローダからリソースのURLを取得する。
+ * @param rootPkg ルートパッケージ情報。
+ * 「/」で始まる絶対リソース名が指定された場合は無視される。
+ * @param resPath リソース名
+ * @return リソースのURL。リソースが見つからなければnull。
+ */
+ public static URL getResource(Package rootPkg, String resPath){
+ return getResource(DEF_LOADER, rootPkg, resPath);
+ }
+
+ /**
+ * 任意のルートパッケージと相対リソース名を用いて、
+ * 任意のクラスローダからリソースのURLを取得する。
+ * @param loader クラスローダ
+ * @param rootPkg ルートパッケージ情報。
+ * 「/」で始まる絶対リソース名が指定された場合は無視される。
+ * @param resPath リソース名
+ * @return リソースのURL。リソースが見つからなければnull。
+ */
+ public static URL getResource(ClassLoader loader,
+ Package rootPkg,
+ String resPath ){
+ String fullName;
+ if(isAbsoluteResourcePath(resPath)){
+ fullName = resPath.substring(1); // chop '/' heading
+ }else{
+ String pfx = getResourcePrefix(rootPkg);
+ fullName = pfx + resPath;
+ }
+
+ URL result = loader.getResource(fullName);
+
+ return result;
+ }
+
+ /**
+ * リソース名を用いて、
+ * デフォルトのクラスローダとデフォルトのルートパッケージから
+ * リソースの入力ストリームを取得する。
+ * @param resPath リソース名
+ * @return リソースの入力ストリーム。リソースが見つからなければnull。
+ */
+ public static InputStream getResourceAsStream(String resPath){
+ return getResourceAsStream(DEF_ROOT_PACKAGE, resPath);
+ }
+
+ /**
+ * 任意のルートパッケージと相対リソース名を用いて、
+ * デフォルトのクラスローダからリソースの入力ストリームを取得する。
+ * @param rootPkg ルートパッケージ情報。
+ * 「/」で始まる絶対リソース名が指定された場合は無視される。
+ * @param resPath リソース名
+ * @return リソースの入力ストリーム。リソースが見つからなければnull。
+ */
+ public static InputStream getResourceAsStream(Package rootPkg,
+ String resPath ){
+ return getResourceAsStream(DEF_LOADER, rootPkg, resPath);
+ }
+
+ /**
+ * 任意のルートパッケージと相対リソース名を用いて、
+ * 任意のクラスローダからリソースの入力ストリームを取得する。
+ * @param loader クラスローダ
+ * @param rootPkg ルートパッケージ情報。
+ * 「/」で始まる絶対リソース名が指定された場合は無視される。
+ * @param resPath リソース名
+ * @return リソースの入力ストリーム。リソースが見つからなければnull。
+ */
+ public static InputStream getResourceAsStream(ClassLoader loader,
+ Package rootPkg,
+ String resPath ){
+ URL url = getResource(loader, rootPkg, resPath);
+ if(url == null) return null;
+
+ InputStream result;
+ try{
+ result = url.openStream();
+ }catch (IOException e){
+ result = null;
+ }
+
+ return result;
+ }
+
+ /**
+ * リソース名を用いてイメージ画像を取得する。
+ * @param resPath 画像リソース名
+ * @return イメージ画像。リソースが見つからなければnull。
+ */
+ public static BufferedImage getBufferedImage(String resPath){
+ URL url = getResource(resPath);
+ if(url == null) return null;
+
+ BufferedImage result;
+ try{
+ result = ImageIO.read(url);
+ }catch(IOException e){
+ result = null;
+ }
+
+ return result;
+ }
+
+ /**
+ * リソース名を用いてアイコン画像を取得する。
+ * @param resPath アイコン画像リソース名
+ * @return アイコン画像。リソースが見つからなければnull。
+ */
+ public static ImageIcon getImageIcon(String resPath){
+ URL url = getResource(resPath);
+ if(url == null) return null;
+
+ ImageIcon result = new ImageIcon(url);
+
+ return result;
+ }
+
+ /**
+ * リソース名を用いてプロパティを取得する。
+ * @param resPath プロパティファイルのリソース名
+ * @return プロパティ。リソースが読み込めなければnull。
+ */
+ public static Properties getProperties(String resPath){
+ InputStream is = getResourceAsStream(resPath);
+ if(is == null) return null;
+ is = new BufferedInputStream(is);
+
+ Properties properties = new Properties();
+
+ try{
+ properties.load(is);
+ }catch(IOException e){
+ properties = null;
+ }
+
+ try{
+ is.close();
+ }catch(IOException e){
+ properties = null;
+ }
+
+ return properties;
+ }
+
+ /**
+ * リソース名を用いてUTF-8テキストファイルの内容を取得する。
+ * <p>「#」で始まる行はコメント行として無視される。
+ * @param resPath テキストファイルのリソース名
+ * @return テキスト。リソースが読み込めなければnull。
+ */
+ public static CharSequence getTextFile(String resPath){
+ InputStream is = getResourceAsStream(resPath);
+ if(is == null) return null;
+ is = new BufferedInputStream(is);
+
+ Reader reader = new InputStreamReader(is, CS_UTF8);
+ LineNumberReader lineReader = new LineNumberReader(reader);
+
+ StringBuilder result = new StringBuilder();
+
+ for(;;){
+ String line;
+ try{
+ line = lineReader.readLine();
+ }catch(IOException e){
+ result = null;
+ break;
+ }
+ if(line == null) break;
+ if(line.startsWith("#")) continue;
+ result.append(line).append('\n');
+ }
+
+ try{
+ lineReader.close();
+ }catch(IOException e){
+ result = null;
+ }
+
+ return result;
+ }
+
+}
--- /dev/null
+/*
+ * version information
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+package jp.sfjp.jindolf;
+
+import java.util.Properties;
+
+/**
+ * バージョンその他アプリに関する各種情報。
+ */
+public final class VerInfo {
+
+ /** タイトル。 */
+ public static final String TITLE;
+ /** バージョン。 */
+ public static final String VERSION;
+ /** 作者名。 */
+ public static final String AUTHOR;
+ /** 著作権表記。 */
+ public static final String COPYRIGHT;
+ /** ライセンス表記。 */
+ public static final String LICENSE;
+ /** 連絡先。 */
+ public static final String CONTACT;
+ /** 初出。 */
+ public static final String INCEPTION;
+ /** その他、何でも書きたいこと。 */
+ public static final String COMMENT;
+ /** クレジット。 */
+ public static final String ID;
+
+ private static final String RES_VERDEF = "resources/version.properties";
+
+ private static final String PFX_TITLE = "pkg-title.";
+ private static final String PFX_VERSION = "pkg-version.";
+ private static final String PFX_AUTHOR = "pkg-author.";
+ private static final String PFX_LICENSE = "pkg-license.";
+ private static final String PFX_CONTACT = "pkg-contact.";
+ private static final String PFX_INCEPTION = "pkg-inception.";
+ private static final String PFX_COMMENT = "pkg-comment.";
+
+ static{
+ Properties verProp = ResourceManager.getProperties(RES_VERDEF);
+ if(verProp == null) verProp = new Properties();
+
+ TITLE = getPackageInfo(verProp, PFX_TITLE, "Jindolf");
+ VERSION = getPackageInfo(verProp, PFX_VERSION, "0.0.1");
+ AUTHOR = getPackageInfo(verProp, PFX_AUTHOR, "nobody");
+ LICENSE = getPackageInfo(verProp, PFX_LICENSE, "Unknown");
+ CONTACT = getPackageInfo(verProp, PFX_CONTACT, "Unknown");
+ INCEPTION = getPackageInfo(verProp, PFX_INCEPTION, "2008");
+ COMMENT = getPackageInfo(verProp, PFX_COMMENT, "");
+
+ COPYRIGHT = "Copyright(c)" +"\u0020"+ INCEPTION +"\u0020"+ AUTHOR;
+
+ ID = TITLE
+ +"\u0020"+ "Ver." + VERSION
+ +"\u0020"+ COPYRIGHT
+ +"\u0020"+ "("+ LICENSE +")";
+ }
+
+ /**
+ * 隠しコンストラクタ。
+ */
+ private VerInfo(){
+ super();
+ assert false;
+ return;
+ }
+
+
+ /**
+ * プロパティからルートパッケージのパッケージ情報を取得する。
+ * @param prop プロパティ
+ * @param prefix 接頭辞
+ * @param defValue 見つからなかった場合のデフォルト値
+ * @return パッケージ情報
+ */
+ static String getPackageInfo(Properties prop,
+ String prefix,
+ String defValue ){
+ String result = getPackageInfo(prop, prefix,
+ ResourceManager.DEF_ROOT_PACKAGE,
+ defValue );
+ return result;
+ }
+
+ /**
+ * プロパティからパッケージに紐づけられたパッケージ情報を取得する。
+ * @param prop プロパティ
+ * @param prefix 接頭辞
+ * @param pkg 任意のパッケージ
+ * @param defValue 見つからなかった場合のデフォルト値
+ * @return パッケージ情報
+ */
+ static String getPackageInfo(Properties prop,
+ String prefix,
+ Package pkg,
+ String defValue ){
+ String propKeyName = prefix + pkg.getName();
+ String result = prop.getProperty(propKeyName, defValue);
+
+ // ignore Maven macro filtering
+ if(isMavenMacro(result)){
+ result = defValue;
+ }
+
+ return result;
+ }
+
+ /**
+ * 文字列がMavenのマクロフィルタ置換子でありうるか判定する。
+ * <p>「${」で始まり「}」で終わる文字列を置換子とみなす。
+ * <p>マクロ展開結果がさらに偶然引っかかった場合はあきらめる。
+ * @param text 文字列
+ * @return 置換子でありうるならtrue
+ */
+ public static boolean isMavenMacro(String text){
+ if(text.startsWith("$" + "{") && text.endsWith("}")){
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * ウィンドウタイトル名を生成する。
+ * <p>各ウィンドウタイトルには、他のアプリとの区別のため
+ * アプリ名が付加される。
+ * @param base タイトル基本部
+ * @return アプリ名が付加されたウィンドウタイトル。
+ */
+ public static String getFrameTitle(String base){
+ StringBuilder result = new StringBuilder();
+
+ if(base != null){
+ result.append(base).append("\u0020-\u0020");
+ }
+ result.append(TITLE);
+
+ String message = result.toString();
+ return message;
+ }
+
+ /**
+ * About画面用メッセージを生成する。
+ * @return About画面用メッセージ
+ */
+ public static String getAboutMessage(){
+ StringBuilder result = new StringBuilder();
+
+ result.append(TITLE)
+ .append("\u0020\u0020\u0020")
+ .append("Version")
+ .append('\u0020')
+ .append(VERSION)
+ .append('\n');
+ result.append(COPYRIGHT)
+ .append('\n');
+ result.append("ライセンス:\u0020")
+ .append(LICENSE)
+ .append('\n');
+ result.append("連絡先:\u0020")
+ .append(CONTACT);
+
+ if(COMMENT.length() > 0){
+ result.append('\n')
+ .append(COMMENT);
+ }
+
+ String message = result.toString();
+ return message;
+ }
+
+}
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.config;
import java.awt.Font;
-import java.awt.font.FontRenderContext;
import java.io.File;
+import jp.sfjp.jindolf.data.DialogPref;
+import jp.sfjp.jindolf.glyph.FontInfo;
+import jp.sfjp.jindolf.net.ProxyInfo;
import jp.sourceforge.jovsonz.JsBoolean;
import jp.sourceforge.jovsonz.JsObject;
import jp.sourceforge.jovsonz.JsPair;
*/
public class AppSetting{
- private static final String NETCONFIG_FILE = "netconfig.json";
private static final String HASH_PROXY = "proxy";
- private static final String TALKCONFIG_FILE = "talkconfig.json";
private static final String HASH_FONT = "font";
private static final String HASH_USEBODYICON = "useBodyIcon";
private static final String HASH_USEMONOTOMB = "useMonoTomb";
private static final String HASH_ALIGNBALOON = "alignBaloonWidth";
private OptionInfo optInfo;
-
- private boolean useConfigPath;
- private File configPath;
-
+ private ConfigStore configStore;
private FontInfo fontInfo = FontInfo.DEFAULT_FONTINFO;
private int frameWidth = 800;
}
/**
- * コマンドラインオプションからアプリ設定を展開する。
- * @param optionInfo オプション情報
+ * 設定格納ディレクトリ関係の解析。
+ * @param optionInfo コマンドライン情報
+ * @return 設定ディレクトリ情報
*/
- public void applyOptionInfo(OptionInfo optionInfo){
- this.optInfo = optionInfo;
- applyConfigPathSetting();
- applyFontSetting();
- applyGeometrySetting();
- return;
- }
+ private static ConfigStore parseConfigStore(OptionInfo optionInfo){
+ CmdOption opt =
+ optionInfo.getExclusiveOption(CmdOption.OPT_CONFDIR,
+ CmdOption.OPT_NOCONF );
+
+ boolean useConfig;
+ File configPath;
- /**
- * 設定格納ディレクトリ関係の設定。
- */
- private void applyConfigPathSetting(){
- CmdOption opt = this.optInfo
- .getExclusiveOption(CmdOption.OPT_CONFDIR,
- CmdOption.OPT_NOCONF );
if(opt == CmdOption.OPT_NOCONF){
- this.useConfigPath = false;
- this.configPath = null;
+ useConfig = false;
+ configPath = null;
}else if(opt == CmdOption.OPT_CONFDIR){
- this.useConfigPath = true;
- String path = this.optInfo.getStringArg(CmdOption.OPT_CONFDIR);
- this.configPath = FileUtils.supplyFullPath(new File(path));
+ String path = optionInfo.getStringArg(CmdOption.OPT_CONFDIR);
+ useConfig = true;
+ configPath = FileUtils.supplyFullPath(new File(path));
}else{
- this.useConfigPath = true;
+ useConfig = true;
File path = ConfigFile.getImplicitConfigDirectory();
- this.configPath = path;
+ configPath = path;
}
+ ConfigStore result = new ConfigStore(useConfig, configPath);
+
+ return result;
+ }
+
+ /**
+ * コマンドラインオプションからアプリ設定を展開する。
+ * @param optionInfo オプション情報
+ */
+ public void applyOptionInfo(OptionInfo optionInfo){
+ this.optInfo = optionInfo;
+ this.configStore = parseConfigStore(optionInfo);
+ applyFontSetting();
+ applyGeometrySetting();
return;
}
*/
private void applyFontSetting(){
String fontName = this.optInfo.getStringArg(CmdOption.OPT_INITFONT);
+
Boolean useAntiAlias =
this.optInfo.getBooleanArg(CmdOption.OPT_ANTIALIAS);
+ if(useAntiAlias == null){
+ useAntiAlias = this.fontInfo.isAntiAliased();
+ }
+
Boolean useFractional =
this.optInfo.getBooleanArg(CmdOption.OPT_FRACTIONAL);
+ if(useFractional == null){
+ useFractional = this.fontInfo.usesFractionalMetrics();
+ }
if(fontName != null){
Font font = Font.decode(fontName);
this.fontInfo = this.fontInfo.deriveFont(font);
}
- if(useAntiAlias != null){
- FontRenderContext context = this.fontInfo.getFontRenderContext();
- FontRenderContext newContext =
- new FontRenderContext(context.getTransform(),
- useAntiAlias.booleanValue(),
- context.usesFractionalMetrics() );
- this.fontInfo = this.fontInfo.deriveRenderContext(newContext);
- }
-
- if(useFractional != null){
- FontRenderContext context = this.fontInfo.getFontRenderContext();
- FontRenderContext newContext =
- new FontRenderContext(context.getTransform(),
- context.isAntiAliased(),
- useFractional.booleanValue() );
- this.fontInfo = this.fontInfo.deriveRenderContext(newContext);
- }
+ this.fontInfo =
+ this.fontInfo.deriveRenderContext(useAntiAlias,
+ useFractional );
return;
}
}
/**
- * 設定格納ディレクトリを返す。
- * @return 設定格納ディレクトリ。
- */
- public File getConfigPath(){
- return this.configPath;
- }
-
- /**
- * 設定格納ディレクトリを設定する。
- * @param path 設定格納ディレクトリ
+ * コマンドラインオプション情報を返す。
+ * @return コマンドラインオプション情報
*/
- public void setConfigPath(File path){
- this.configPath = path;
- return;
+ public OptionInfo getOptionInfo(){
+ return this.optInfo;
}
/**
- * 設定格納ディレクトリを使うか否かを返す。
- * @return 使うならtrue
+ * 設定格納情報を返す。
+ * @return 設定格納情報
*/
- public boolean useConfigPath(){
- return this.useConfigPath;
- }
-
- /**
- * 設定格納ディレクトリを使うか否か設定する。
- * @param need 使うならtrue
- */
- public void setUseConfigPath(boolean need){
- this.useConfigPath = need;
- return;
+ public ConfigStore getConfigStore(){
+ return this.configStore;
}
/**
* ネットワーク設定をロードする。
*/
private void loadNetConfig(){
- if( ! useConfigPath() ) return;
-
- JsValue value = ConfigFile.loadJson(new File(NETCONFIG_FILE));
- if(value == null) return;
- this.loadedNetConfig = value;
+ JsObject root = this.configStore.loadNetConfig();
+ if(root == null) return;
+ this.loadedNetConfig = root;
- if( ! (value instanceof JsObject) ) return;
- JsObject root = (JsObject) value;
-
- value = root.getValue(HASH_PROXY);
+ JsValue value = root.getValue(HASH_PROXY);
if( ! (value instanceof JsObject) ) return;
JsObject proxy = (JsObject) value;
* 会話表示設定をロードする。
*/
private void loadTalkConfig(){
- if( ! useConfigPath() ) return;
-
- JsValue value = ConfigFile.loadJson(new File(TALKCONFIG_FILE));
- if(value == null) return;
- this.loadedTalkConfig = value;
-
- if( ! (value instanceof JsObject) ) return;
- JsObject root = (JsObject) value;
+ JsObject root = this.configStore.loadTalkConfig();
+ if(root == null) return;
+ this.loadedTalkConfig = root;
- value = root.getValue(HASH_FONT);
+ JsValue value = root.getValue(HASH_FONT);
if(value instanceof JsObject){
JsObject font = (JsObject) value;
FontInfo info = FontInfo.decodeJson(font);
* ネットワーク設定をセーブする。
*/
private void saveNetConfig(){
- if( ! useConfigPath() ) return;
+ if( ! getConfigStore().useStoreFile() ) return;
JsObject root = new JsObject();
JsObject proxy = ProxyInfo.buildJson(getProxyInfo());
if(this.loadedNetConfig.equals(root)) return;
}
- ConfigFile.saveJson(new File(NETCONFIG_FILE), root);
+ this.configStore.saveNetConfig(root);
return;
}
* 会話表示設定をセーブする。
*/
private void saveTalkConfig(){
- if( ! useConfigPath() ) return;
+ if( ! getConfigStore().useStoreFile() ) return;
JsObject root = new JsObject();
if(this.loadedTalkConfig.equals(root)) return;
}
- ConfigFile.saveJson(new File(TALKCONFIG_FILE), root);
+ this.configStore.saveTalkConfig(root);
return;
}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.config;
-import java.io.IOException;
-import java.util.LinkedList;
+import java.util.Arrays;
import java.util.List;
+import jp.sfjp.jindolf.ResourceManager;
/**
* コマンドラインオプションの列挙。
*/
-public enum CmdOption{
+public enum CmdOption {
/** ヘルプ。 */
- OPT_HELP("help", "h", "-help", "?"),
+ OPT_HELP("-help", "-h", "--help", "-?"),
/** 版数表示。 */
- OPT_VERSION("version"),
+ OPT_VERSION("-version"),
/** UI文字制御。 */
- OPT_BOLDMETAL("boldMetal"),
+ OPT_BOLDMETAL("-boldMetal"),
/** スプラッシュ制御。 */
- OPT_NOSPLASH("nosplash"),
+ OPT_NOSPLASH("-nosplash"),
/** ウィンドウ位置指定。 */
- OPT_GEOMETRY("geometry"),
+ OPT_GEOMETRY("-geometry"),
/** 実行環境出力。 */
- OPT_VMINFO("vminfo"),
+ OPT_VMINFO("-vminfo"),
/** コンソールログ。 */
- OPT_CONSOLELOG("consolelog"),
+ OPT_CONSOLELOG("-consolelog"),
/** フォント指定。 */
- OPT_INITFONT("initfont"),
+ OPT_INITFONT("-initfont"),
/** アンチエイリアス。 */
- OPT_ANTIALIAS("antialias"),
+ OPT_ANTIALIAS("-antialias"),
/** サブピクセル制御。 */
- OPT_FRACTIONAL("fractional"),
+ OPT_FRACTIONAL("-fractional"),
/** 設定格納ディレクトリ指定。 */
- OPT_CONFDIR("confdir"),
+ OPT_CONFDIR("-confdir"),
/** 設定格納ディレクトリ不使用。 */
- OPT_NOCONF("noconfdir"),
+ OPT_NOCONF("-noconfdir"),
;
- private final List<String> nameList = new LinkedList<String>();
+ private static final String RES_HELPTEXT = "resources/help.txt";
+
+
+ private final List<String> nameList;
/**
* コンストラクタ。
* @param names 頭のハイフンを除いたオプション名の一覧
*/
- private CmdOption(CharSequence ... names){
- if(names == null) throw new NullPointerException();
- if(names.length <= 0) throw new IllegalArgumentException();
-
- for(CharSequence name : names){
- if(name == null) throw new NullPointerException();
- this.nameList.add(name.toString().intern());
- }
-
+ private CmdOption(String ... names){
+ assert names.length > 0;
+ this.nameList = Arrays.asList(names);
return;
}
/**
+ * ヘルプメッセージ(オプションの説明)を返す。
+ * @return ヘルプメッセージ
+ */
+ public static CharSequence getHelpText(){
+ CharSequence helpText =
+ ResourceManager.getTextFile(RES_HELPTEXT);
+
+ return helpText;
+ }
+
+ /**
* オプション名に合致するEnumを返す。
- * @param seq ハイフン付きオプション名
+ * @param arg 個別のコマンドライン引数
* @return 合致したEnum。どれとも合致しなければnull
*/
- public static CmdOption parseCmdOption(CharSequence seq){
+ public static CmdOption parseCmdOption(String arg){
for(CmdOption option : values()){
- if(option.matchHyphened(seq)) return option;
+ if(option.matches(arg)) return option;
}
return null;
}
/**
+ * 任意のオプション文字列がこのオプションに合致するか判定する。
+ * @param option ハイフンの付いたオプション文字列
+ * @return 合致すればtrue
+ */
+ public boolean matches(String option){
+ for(String name : this.nameList){
+ if(option.equals(name)) return true;
+ }
+
+ return false;
+ }
+
+ /**
* 単体で意味をなすオプションか判定する。
- * @param option オプション
* @return 単体で意味をなすならtrue
*/
- public static boolean isIndepOption(CmdOption option){
- switch(option){
+ public boolean isIndepOption(){
+ switch(this){
case OPT_HELP:
case OPT_VERSION:
case OPT_VMINFO:
/**
* 真偽指定を一つ必要とするオプションか判定する。
- * @param option オプション
* @return 真偽指定を一つ必要とするオプションならtrue
*/
- public static boolean isBooleanOption(CmdOption option){
- switch(option){
+ public boolean isBooleanOption(){
+ switch(this){
case OPT_ANTIALIAS:
case OPT_FRACTIONAL:
return true;
}
/**
- * ヘルプメッセージ(オプションの説明)を返す。
- * @return ヘルプメッセージ
- */
- public static CharSequence getHelpText(){
- CharSequence helpText;
-
- try{
- helpText = Jindolf.loadResourceText("resources/help.txt");
- }catch(IOException e){
- helpText = "";
- }
-
- return helpText;
- }
-
- /**
* 頭のハイフンを除いたオプション名を返す。
* オプション名が複数指定されていた場合は最初のオプション名
* @return オプション名
return this.nameList.get(0);
}
- /**
- * 頭のハイフンが付いたオプション名を返す。
- * オプション名が複数指定されていた場合は最初のオプション名
- * @return オプション名
- */
- public String toHyphened(){
- return "-" + toString();
- }
-
- /**
- * 任意のオプション文字列がこのオプションに合致するか判定する。
- * @param option ハイフンの付いたオプション文字列
- * @return 合致すればtrue
- */
- public boolean matchHyphened(CharSequence option){
- if(option == null) return false;
-
- for(String name : this.nameList){
- String hyphened = "-" + name;
- if(hyphened.equals(option.toString())) return true;
- }
-
- return false;
- }
-
}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
-
-import java.awt.Component;
-import java.awt.HeadlessException;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
+package jp.sfjp.jindolf.config;
+
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
-import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
-import javax.swing.ButtonGroup;
-import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
-import javax.swing.JRadioButton;
-import jp.sourceforge.jovsonz.JsComposition;
-import jp.sourceforge.jovsonz.JsParseException;
-import jp.sourceforge.jovsonz.JsVisitException;
-import jp.sourceforge.jovsonz.Json;
+import jp.sfjp.jindolf.VerInfo;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.view.LockErrorPane;
/**
* Jindolf設定格納ディレクトリに関するあれこれ。
public final class ConfigFile{
private static final String TITLE_BUILDCONF =
- Jindolf.TITLE + "設定格納ディレクトリの設定";
+ VerInfo.TITLE + "設定格納ディレクトリの設定";
private static final String JINCONF = "Jindolf";
private static final String JINCONF_DOT = ".jindolf";
private static final String MSG_POST =
"<ul>"
- + "<li><code>" + CmdOption.OPT_CONFDIR.toHyphened() + "</code>"
+ + "<li><code>" + CmdOption.OPT_CONFDIR + "</code>"
+ " オプション指定により、<br>"
+ "任意の設定格納ディレクトリを指定することができます。<br>"
- + "<li><code>" + CmdOption.OPT_NOCONF.toHyphened() + "</code>"
+ + "<li><code>" + CmdOption.OPT_NOCONF + "</code>"
+ " オプション指定により、<br>"
+ "設定格納ディレクトリを使わずに起動することができます。<br>"
+ "</ul>";
+ private static final LogWrapper LOGGER = new LogWrapper();
+
/**
* 隠れコンストラクタ。
/**
* 設定格納ディレクトリのセットアップ。
+ * @param configStore 設定ディレクトリ
* @return 設定格納ディレクトリ
*/
- public static File setupConfigDirectory(){
- AppSetting setting = Jindolf.getAppSetting();
+ public static File setupConfigDirectory(ConfigStore configStore){
File configPath;
- if( ! setting.useConfigPath() ){
+ if( ! configStore.useStoreFile() ){
configPath = null;
}else{
String optName;
- if(setting.getConfigPath() != null){
- configPath = setting.getConfigPath();
- optName = CmdOption.OPT_CONFDIR.toHyphened();
+ if(configStore.getConfigPath() != null){
+ configPath = configStore.getConfigPath();
+ optName = CmdOption.OPT_CONFDIR.toString();
}else{
configPath = ConfigFile.getImplicitConfigDirectory();
optName = null;
ConfigFile.checkAccessibility(configPath);
}
- setting.setConfigPath(configPath);
+ configStore.setConfigPath(configPath);
return configPath;
}
/**
* ロックファイルのセットアップ。
+ * @param configStore 設定ディレクトリ
* @return ロックオブジェクト
*/
- public static InterVMLock setupLockFile(){
- AppSetting setting = Jindolf.getAppSetting();
-
- File configPath = setting.getConfigPath();
+ public static InterVMLock setupLockFile(ConfigStore configStore){
+ File configPath = configStore.getConfigPath();
if(configPath == null) return null;
File lockFile = new File(configPath, "lock");
if( ! lock.isFileOwner() ){
confirmLockError(lock);
if( ! lock.isFileOwner() ){
- setting.setConfigPath(null);
- setting.setUseConfigPath(false);
+ configStore.setConfigPath(null);
+ configStore.setUseStoreFile(false);
}
}
public static File getImplicitConfigDirectory(){
File result;
- File jarParent = FileUtils.getJarDirectory(Jindolf.class);
+ File jarParent = FileUtils.getJarDirectory();
if(jarParent != null && FileUtils.isAccessibleDirectory(jarParent)){
result = new File(jarParent, JINCONF);
if(FileUtils.isAccessibleDirectory(result)){
}
/**
+ * VMを異常終了させる。
+ */
+ private static void abort(){
+ System.exit(1);
+ assert false;
+ return;
+ }
+
+ /**
* 設定ディレクトリのルートファイルシステムもしくはドライブレターに
* アクセスできないエラーをダイアログに提示し、VM終了する。
* @param path 設定ディレクトリ
+ "起動を中止します。<br>"
+ MSG_POST
+ "</html>" );
- Jindolf.exit(1);
+ abort();
return;
}
+ "起動を中止します。<br>"
+ MSG_POST
+ "</html>" );
- Jindolf.exit(1);
+ abort();
return;
}
+ "設定ディレクトリの作成をせずに起動を中止します。<br>"
+ MSG_POST
+ "</html>" );
- Jindolf.exit(1);
+ abort();
return;
}
+ "起動を中止します。<br>"
+ MSG_POST
+ "</html>" );
- Jindolf.exit(1);
+ abort();
return;
}
+ "読み書きできるようにしてください。<br>"
+ MSG_POST
+ "</html>" );
- Jindolf.exit(1);
+ abort();
return;
}
+ "への書き込みができません。"
+ "起動を中止します。<br>"
+ "</html>" );
- Jindolf.exit(1);
+ abort();
return;
}
dialog.dispose();
if(pane.isAborted() || pane.getValue() == null){
- Jindolf.exit(1);
+ abort();
break;
}else if(pane.isRadioRetry()){
lock.tryLock();
+ "設定ディレクトリを使わずに起動を続行します。<br>"
+ "今回、各種設定の読み込み・保存はできません。<br>"
+ "<code>"
- + CmdOption.OPT_NOCONF.toHyphened()
+ + CmdOption.OPT_NOCONF
+ "</code> オプション"
+ "を使うとこの警告は出なくなります。"
+ "</html>");
+ "を削除してください。<br>"
+ "起動を中止します。"
+ "</html>");
- Jindolf.exit(1);
+ abort();
break;
}
lock.tryLock();
+ "を確保することができません。<br>"
+ "起動を中止します。"
+ "</html>");
- Jindolf.exit(1);
+ abort();
break;
}
}
return;
}
- /**
- * 設定ディレクトリ上のJSONファイルを読み込む。
- * @param file JSONファイルの相対パス
- * @return JSON objectまたはarray。
- * 設定ディレクトリを使わない設定、
- * もしくはJSONファイルが存在しない、
- * もしくは入力エラーがあればnull
- */
- public static JsComposition loadJson(File file){
- AppSetting setting = Jindolf.getAppSetting();
- if( ! setting.useConfigPath() ) return null;
-
- File absFile;
- if(file.isAbsolute()){
- absFile = file;
- }else{
- File configPath = setting.getConfigPath();
- if(configPath == null) return null;
- absFile = new File(configPath, file.getPath());
- if( ! absFile.exists() ) return null;
- if( ! absFile.isAbsolute() ) return null;
- }
-
- InputStream istream;
- try{
- istream = new FileInputStream(absFile);
- }catch(FileNotFoundException e){
- assert false;
- return null;
- }
- istream = new BufferedInputStream(istream);
-
- Reader reader = new InputStreamReader(istream, CHARSET_JSON);
-
- JsComposition<?> root;
- try{
- root = Json.parseJson(reader);
- }catch(IOException e){
- Jindolf.logger().fatal(
- "JSONファイル["
- + absFile.getPath()
- + "]の読み込み時に支障がありました。", e);
- return null;
- }catch(JsParseException e){
- Jindolf.logger().fatal(
- "JSONファイル["
- + absFile.getPath()
- + "]の内容に不備があります。", e);
- return null;
- }finally{
- try{
- reader.close();
- }catch(IOException e){
- Jindolf.logger().fatal(
- "JSONファイル["
- + absFile.getPath()
- + "]を閉じることができません。", e);
- return null;
- }
- }
-
- return root;
- }
-
- /**
- * 設定ディレクトリ上のJSONファイルに書き込む。
- * @param file JSONファイルの相対パス
- * @param root JSON objectまたはarray
- * @return 正しくセーブが行われればtrue。
- * 何らかの理由でセーブが完了できなければfalse
- */
- public static boolean saveJson(File file, JsComposition root){
- AppSetting setting = Jindolf.getAppSetting();
- if( ! setting.useConfigPath() ) return false;
- File configPath = setting.getConfigPath();
- if(configPath == null) return false;
-
- // TODO テンポラリファイルを用いたより安全なファイル更新
- File absFile = new File(configPath, file.getPath());
- absFile.delete();
- try{
- if(absFile.createNewFile() != true) return false;
- }catch(IOException e){
- Jindolf.logger().fatal(
- "JSONファイル["
- + absFile.getPath()
- + "]の新規生成ができません。", e);
- return false;
- }
-
- OutputStream ostream;
- try{
- ostream = new FileOutputStream(absFile);
- }catch(FileNotFoundException e){
- assert false;
- return false;
- }
- ostream = new BufferedOutputStream(ostream);
- Writer writer = new OutputStreamWriter(ostream, CHARSET_JSON);
-
- try{
- Json.dumpJson(writer, root);
- }catch(JsVisitException e){
- Jindolf.logger().fatal(
- "JSONファイル["
- + absFile.getPath()
- + "]の出力処理で支障がありました。", e);
- return false;
- }catch(IOException e){
- Jindolf.logger().fatal(
- "JSONファイル["
- + absFile.getPath()
- + "]の書き込み時に支障がありました。", e);
- return false;
- }finally{
- try{
- writer.close();
- }catch(IOException e){
- Jindolf.logger().fatal(
- "JSONファイル["
- + absFile.getPath()
- + "]を閉じることができません。", e);
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * ロックエラー用ダイアログ。
- * <ul>
- * <li>強制解除
- * <li>リトライ
- * <li>設定ディレクトリを無視
- * <li>起動中止
- * </ul>
- * の選択を利用者に求める。
- */
- @SuppressWarnings("serial")
- private static class LockErrorPane
- extends JOptionPane
- implements ActionListener{
-
- private final InterVMLock lock;
-
- private final JRadioButton continueButton =
- new JRadioButton("設定ディレクトリを使わずに起動を続行");
- private final JRadioButton retryButton =
- new JRadioButton("再度ロック取得を試す");
- private final JRadioButton forceButton =
- new JRadioButton(
- "<html>"
- + "ロックを強制解除<br>"
- + " (※他のJindolfと設定ファイル書き込みが衝突するかも…)"
- + "</html>");
-
- private final JButton okButton = new JButton("OK");
- private final JButton abortButton = new JButton("起動中止");
-
- private boolean aborted = false;
-
- /**
- * コンストラクタ。
- * @param lock 失敗したロック
- */
- public LockErrorPane(InterVMLock lock){
- super();
-
- this.lock = lock;
-
- String htmlMessage =
- "<html>"
- + "設定ディレクトリのロックファイル<br>"
- + getCenteredFileName(this.lock.getLockFile())
- + "のロックに失敗しました。<br>"
- + "考えられる原因としては、<br>"
- + "<ul>"
- + "<li>前回起動したJindolfの終了が正しく行われなかった"
- + "<li>今どこかで他のJindolfが動いている"
- + "</ul>"
- + "などが考えられます。<br>"
- + "<hr>"
- + "</html>";
-
- ButtonGroup bgrp = new ButtonGroup();
- bgrp.add(this.continueButton);
- bgrp.add(this.retryButton);
- bgrp.add(this.forceButton);
- this.continueButton.setSelected(true);
-
- Object[] msg = {
- htmlMessage,
- this.continueButton,
- this.retryButton,
- this.forceButton,
- };
- setMessage(msg);
-
- Object[] opts = {
- this.okButton,
- this.abortButton,
- };
- setOptions(opts);
-
- setMessageType(JOptionPane.ERROR_MESSAGE);
-
- this.okButton .addActionListener(this);
- this.abortButton.addActionListener(this);
-
- return;
- }
-
- /**
- * 「設定ディレクトリを無視して続行」が選択されたか判定する。
- * @return 「無視して続行」が選択されていればtrue
- */
- public boolean isRadioContinue(){
- return this.continueButton.isSelected();
- }
-
- /**
- * 「リトライ」が選択されたか判定する。
- * @return 「リトライ」が選択されていればtrue
- */
- public boolean isRadioRetry(){
- return this.retryButton.isSelected();
- }
-
- /**
- * 「強制解除」が選択されたか判定する。
- * @return 「強制解除」が選択されていればtrue
- */
- public boolean isRadioForce(){
- return this.forceButton.isSelected();
- }
-
- /**
- * 「起動中止」が選択されたか判定する。
- * @return 「起動中止」が押されていたならtrue
- */
- public boolean isAborted(){
- return this.aborted;
- }
-
- /**
- * {@inheritDoc}
- * @param parentComponent {@inheritDoc}
- * @param title {@inheritDoc}
- * @return {@inheritDoc}
- * @throws HeadlessException {@inheritDoc}
- */
- @Override
- public JDialog createDialog(Component parentComponent,
- String title)
- throws HeadlessException{
- final JDialog dialog =
- super.createDialog(parentComponent, title);
-
- ActionListener listener = new ActionListener(){
- public void actionPerformed(ActionEvent event){
- dialog.setVisible(false);
- return;
- }
- };
-
- this.okButton .addActionListener(listener);
- this.abortButton.addActionListener(listener);
-
- return dialog;
- }
-
- /**
- * ボタン押下を受信する。
- * @param event イベント
- */
- public void actionPerformed(ActionEvent event){
- Object source = event.getSource();
- if(source == this.okButton) this.aborted = false;
- else this.aborted = true;
- return;
- }
-
- }
-
}
--- /dev/null
+/*
+ * config store
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf.config;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sourceforge.jovsonz.JsComposition;
+import jp.sourceforge.jovsonz.JsObject;
+import jp.sourceforge.jovsonz.JsParseException;
+import jp.sourceforge.jovsonz.JsTypes;
+import jp.sourceforge.jovsonz.JsVisitException;
+import jp.sourceforge.jovsonz.Json;
+
+/**
+ * 各種設定の永続化関連。
+ */
+public class ConfigStore {
+
+ /** 検索履歴ファイル。 */
+ public static final File HIST_FILE = new File("searchHistory.json");
+ /** 原稿ファイル。 */
+ public static final File DRAFT_FILE = new File("draft.json");
+ /** ネットワーク設定ファイル。 */
+ public static final File NETCONFIG_FILE = new File("netconfig.json");
+ /** 台詞表示設定ファイル。 */
+ public static final File TALKCONFIG_FILE = new File("talkconfig.json");
+
+ private static final Charset CHARSET_JSON = Charset.forName("UTF-8");
+
+ private static final LogWrapper LOGGER = new LogWrapper();
+
+
+ private boolean useStoreFile;
+ private File configPath;
+
+
+ /**
+ * コンストラクタ。
+ * @param useStoreFile 設定ディレクトリへの永続化機能を使うならtrue
+ * @param configPath 設定ディレクトリ。
+ * 設定ディレクトリを使わない場合は無視され、nullとして扱われる。
+ */
+ public ConfigStore(boolean useStoreFile, File configPath){
+ super();
+
+ this.useStoreFile = useStoreFile;
+
+ File path = null;
+ if(this.useStoreFile) path = configPath;
+ this.configPath = path;
+
+ return;
+ }
+
+ /**
+ * 設定ディレクトリを使うか否か判定する。
+ * @return 設定ディレクトリを使うならtrue。
+ */
+ public boolean useStoreFile(){
+ return this.useStoreFile;
+ }
+
+ /**
+ * 設定ディレクトリ利用の有無を変更する。
+ * @param sw 利用するならtrue
+ */
+ public void setUseStoreFile(boolean sw){
+ this.useStoreFile = sw;
+ if( ! this.useStoreFile ){
+ this.configPath = null;
+ }
+ return;
+ }
+
+ /**
+ * 設定ディレクトリを返す。
+ * @return 設定ディレクトリ。設定ディレクトリを使わない場合はnull
+ */
+ public File getConfigPath(){
+ File result;
+ if(this.useStoreFile) result = this.configPath;
+ else result = null;
+ return result;
+ }
+
+ /**
+ * 設定ディレクトリを変更する。
+ * @param path 設定ディレクトリ
+ */
+ public void setConfigPath(File path){
+ this.configPath = path;
+ return;
+ }
+
+ /**
+ * 設定ディレクトリ上のOBJECT型JSONファイルを読み込む。
+ * @param file JSONファイルの相対パス。
+ * @return JSON object。
+ * 設定ディレクトリを使わない設定、
+ * もしくはJSONファイルが存在しない、
+ * もしくはOBJECT型でなかった、
+ * もしくは入力エラーがあればnull
+ */
+ public JsObject loadJsObject(File file){
+ JsComposition<?> root = loadJson(file);
+ if(root == null || root.getJsTypes() != JsTypes.OBJECT) return null;
+ JsObject result = (JsObject) root;
+ return result;
+ }
+
+ /**
+ * 設定ディレクトリ上のJSONファイルを読み込む。
+ * @param file JSONファイルの相対パス
+ * @return JSON objectまたはarray。
+ * 設定ディレクトリを使わない設定、
+ * もしくはJSONファイルが存在しない、
+ * もしくは入力エラーがあればnull
+ */
+ public JsComposition<?> loadJson(File file){
+ if( ! this.useStoreFile ) return null;
+
+ File absFile;
+ if(file.isAbsolute()){
+ absFile = file;
+ }else{
+ if(this.configPath == null) return null;
+ absFile = new File(this.configPath, file.getPath());
+ if( ! absFile.exists() ) return null;
+ if( ! absFile.isAbsolute() ) return null;
+ }
+ String absPath = absFile.getPath();
+
+ InputStream istream;
+ try{
+ istream = new FileInputStream(absFile);
+ }catch(FileNotFoundException e){
+ assert false;
+ return null;
+ }
+ istream = new BufferedInputStream(istream);
+
+ JsComposition<?> root;
+ try{
+ root = loadJson(istream);
+ }catch(IOException e){
+ LOGGER.fatal(
+ "JSONファイル["
+ + absPath
+ + "]の読み込み時に支障がありました。", e);
+ return null;
+ }catch(JsParseException e){
+ LOGGER.fatal(
+ "JSONファイル["
+ + absPath
+ + "]の内容に不備があります。", e);
+ return null;
+ }finally{
+ try{
+ istream.close();
+ }catch(IOException e){
+ LOGGER.fatal(
+ "JSONファイル["
+ + absPath
+ + "]を閉じることができません。", e);
+ return null;
+ }
+ }
+
+ return root;
+ }
+
+ /**
+ * バイトストリーム上のJSONデータを読み込む。
+ * <p>バイトストリームはUTF-8と解釈される。
+ * @param is バイトストリーム
+ * @return JSON objectまたはarray。
+ * @throws IOException 入力エラー
+ * @throws JsParseException 構文エラー
+ */
+ protected JsComposition<?> loadJson(InputStream is)
+ throws IOException, JsParseException {
+ Reader reader = new InputStreamReader(is, CHARSET_JSON);
+ reader = new BufferedReader(reader);
+ JsComposition<?> root = loadJson(reader);
+ return root;
+ }
+
+ /**
+ * 文字ストリーム上のJSONデータを読み込む。
+ * @param reader 文字ストリーム
+ * @return JSON objectまたはarray。
+ * @throws IOException 入力エラー
+ * @throws JsParseException 構文エラー
+ */
+ protected JsComposition<?> loadJson(Reader reader)
+ throws IOException, JsParseException {
+ JsComposition<?> root = Json.parseJson(reader);
+ return root;
+ }
+
+ /**
+ * 設定ディレクトリ上のJSONファイルに書き込む。
+ * @param file JSONファイルの相対パス
+ * @param root JSON objectまたはarray
+ * @return 正しくセーブが行われればtrue。
+ * 何らかの理由でセーブが完了できなければfalse
+ */
+ public boolean saveJson(File file, JsComposition<?> root){
+ if( ! this.useStoreFile ) return false;
+
+ // TODO テンポラリファイルを用いたより安全なファイル更新
+ File absFile = new File(this.configPath, file.getPath());
+ String absPath = absFile.getPath();
+
+ absFile.delete();
+ try{
+ if(absFile.createNewFile() != true) return false;
+ }catch(IOException e){
+ LOGGER.fatal(
+ "JSONファイル["
+ + absPath
+ + "]の新規生成ができません。", e);
+ return false;
+ }
+
+ OutputStream ostream;
+ try{
+ ostream = new FileOutputStream(absFile);
+ }catch(FileNotFoundException e){
+ assert false;
+ return false;
+ }
+ ostream = new BufferedOutputStream(ostream);
+
+ try{
+ saveJson(ostream, root);
+ }catch(JsVisitException e){
+ LOGGER.fatal(
+ "JSONファイル["
+ + absPath
+ + "]の出力処理で支障がありました。", e);
+ return false;
+ }catch(IOException e){
+ LOGGER.fatal(
+ "JSONファイル["
+ + absPath
+ + "]の書き込み時に支障がありました。", e);
+ return false;
+ }finally{
+ try{
+ ostream.close();
+ }catch(IOException e){
+ LOGGER.fatal(
+ "JSONファイル["
+ + absPath
+ + "]を閉じることができません。", e);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * バイトストリームにJSONデータを書き込む。
+ * <p>バイトストリームはUTF-8と解釈される。
+ * @param os バイトストリーム出力
+ * @param root JSON objectまたはarray
+ * @throws IOException 出力エラー
+ * @throws JsVisitException 構造エラー
+ */
+ protected void saveJson(OutputStream os, JsComposition<?> root)
+ throws IOException, JsVisitException {
+ Writer writer = new OutputStreamWriter(os, CHARSET_JSON);
+ writer = new BufferedWriter(writer);
+ saveJson(writer, root);
+ return;
+ }
+
+ /**
+ * 文字ストリームにJSONデータを書き込む。
+ * @param writer 文字ストリーム出力
+ * @param root JSON objectまたはarray
+ * @throws IOException 出力エラー
+ * @throws JsVisitException 構造エラー
+ */
+ protected void saveJson(Writer writer, JsComposition<?> root)
+ throws IOException, JsVisitException {
+ Json.dumpJson(writer, root);
+ return;
+ }
+
+ /**
+ * 検索履歴ファイルを読み込む。
+ * @return 履歴データ。履歴を読まないもしくは読めない場合はnull
+ */
+ public JsObject loadHistoryConfig(){
+ JsObject result = loadJsObject(HIST_FILE);
+ return result;
+ }
+
+ /**
+ * 原稿ファイルを読み込む。
+ * @return 原稿データ。原稿を読まないもしくは読めない場合はnull
+ */
+ public JsObject loadDraftConfig(){
+ JsObject result = loadJsObject(DRAFT_FILE);
+ return result;
+ }
+
+ /**
+ * ネットワーク設定ファイルを読み込む。
+ * @return ネットワーク設定データ。
+ * 設定を読まないもしくは読めない場合はnull
+ */
+ public JsObject loadNetConfig(){
+ JsObject result = loadJsObject(NETCONFIG_FILE);
+ return result;
+ }
+
+ /**
+ * 台詞表示設定ファイルを読み込む。
+ * @return 台詞表示設定データ。
+ * 設定を読まないもしくは読めない場合はnull
+ */
+ public JsObject loadTalkConfig(){
+ JsObject result = loadJsObject(TALKCONFIG_FILE);
+ return result;
+ }
+
+ /**
+ * 検索履歴ファイルに書き込む。
+ * @param root 履歴データ
+ * @return 書き込まなかったもしくは書き込めなかった場合はfalse
+ */
+ public boolean saveHistoryConfig(JsComposition<?> root){
+ boolean result = saveJson(HIST_FILE, root);
+ return result;
+ }
+
+ /**
+ * 原稿ファイルに書き込む。
+ * @param root 原稿データ
+ * @return 書き込まなかったもしくは書き込めなかった場合はfalse
+ */
+ public boolean saveDraftConfig(JsComposition<?> root){
+ boolean result = saveJson(DRAFT_FILE, root);
+ return result;
+ }
+
+ /**
+ * ネットワーク設定ファイルに書き込む。
+ * @param root ネットワーク設定
+ * @return 書き込まなかったもしくは書き込めなかった場合はfalse
+ */
+ public boolean saveNetConfig(JsComposition<?> root){
+ boolean result = saveJson(NETCONFIG_FILE, root);
+ return result;
+ }
+
+ /**
+ * 台詞表示設定ファイルに書き込む。
+ * @param root 台詞表示設定
+ * @return 書き込まなかったもしくは書き込めなかった場合はfalse
+ */
+ public boolean saveTalkConfig(JsComposition<?> root){
+ boolean result = saveJson(TALKCONFIG_FILE, root);
+ return result;
+ }
+
+}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.config;
import java.io.File;
import java.text.NumberFormat;
/** Java実行形バージョン。 */
public static final String JAVA_VERSION;
+ /** 最大ヒープメモリ。 */
+ public static final long MAX_MEMORY;
+
private static final SortedMap<String, String> propertyMap =
new TreeMap<String, String>();
getSecureEnvironment("LANG");
getSecureEnvironment("DISPLAY");
+ Runtime runtime = Runtime.getRuntime();
+ MAX_MEMORY = runtime.maxMemory();
+
String classpath = getSecureProperty("java.class.path");
+ String[] pathVec;
if(classpath != null){
- classpaths = classpath.split(File.pathSeparator);
+ pathVec = classpath.split(File.pathSeparator);
}else{
- classpaths = new String[0];
+ pathVec = new String[0];
}
+ classpaths = pathVec;
+
}
StringBuilder result = new StringBuilder();
NumberFormat nform = NumberFormat.getNumberInstance();
- result.append("最大ヒープメモリ量: "
- + nform.format(Jindolf.RUNTIME.maxMemory()) + " bytes\n");
-
- result.append("\n");
-
- result.append("起動時引数:\n");
- for(String arg : Jindolf.getOptionInfo().getInvokeArgList()){
- result.append(" ").append(arg).append("\n");
- }
+ result.append("最大ヒープメモリ量: ")
+ .append(nform.format(MAX_MEMORY))
+ .append(" bytes\n");
result.append("\n");
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.config;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
*/
public final class FileUtils{
+ private static final Class<?> THISKLASS = FileUtils.class;
+
private static final String SCHEME_FILE = "file";
/** JRE1.6のjava.io.File#setReadableに相当。 */
METHOD_SETWRITABLE = method;
assert ! ( isMacOSXFs() && isWindowsOSFs() );
+ new FileUtils().hashCode();
}
* 隠しコンストラクタ。
*/
private FileUtils(){
- assert false;
- throw new AssertionError();
+ super();
+ assert this.getClass() == THISKLASS;
+ return;
}
}
/**
+ * このクラスがローカルJARファイルからロードされたのであれば
+ * その格納ディレクトリを返す。
+ * @return ロード元JARファイルの格納ディレクトリ。
+ * JARが見つからない、もしくはロード元がJARファイルでなければnull。
+ */
+ public static File getJarDirectory(){
+ return getJarDirectory(THISKLASS);
+ }
+
+ /**
* ホームディレクトリを得る。
* システムプロパティuser.homeで示されたホームディレクトリを返す。
* @return ホームディレクトリ。何らかの事情でnullを返す場合もあり。
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.config;
import java.io.File;
import java.io.FileNotFoundException;
--- /dev/null
+/*
+ * option argument information
+ *
+ * License : The MIT License
+ * Copyright(c) 2009 olyutorskii
+ */
+
+package jp.sfjp.jindolf.config;
+
+import java.text.MessageFormat;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * コマンドラインオプション情報。
+ * public static void main()の引数から展開される。
+ */
+public class OptionInfo{
+
+ private static final Pattern PATTERN_GEOMETRY =
+ Pattern.compile(
+ "([1-9][0-9]*)x([1-9][0-9]*)"
+ +"(?:(\\+|\\-)([1-9][0-9]*)(\\+|\\-)([1-9][0-9]*))?"
+ );
+
+ private static final String ERRFORM_UKNOWN =
+ "未定義の起動オプション[{0}]が指定されました。";
+ private static final String ERRFORM_NOARG =
+ "起動オプション[{0}]に引数がありません。";
+ private static final String ERRFORM_GEOM =
+ "起動オプション[{0}]のジオメトリ指定[{1}]が不正です。"
+ + "WIDTHxHEIGHT[(+|-)XPOS(+|-)YPOS]の形式で指定してください";
+ private static final String ERRFORM_BOOL =
+ "起動オプション[{0}]の真偽指定[{1}]が不正です。"
+ + "on, off, yes, no, true, falseのいずれかを指定してください。";
+ private static final String ERRFORM_NONBOOL =
+ "起動オプション[{0}]は真偽を指定するオプションではありません。";
+
+
+ private Integer frameWidth = null;
+ private Integer frameHeight = null;
+ private Integer frameXpos = null;
+ private Integer frameYpos = null;
+
+ private final List<String> invokeArgs = new LinkedList<String>();
+ private final List<CmdOption> optionList = new LinkedList<CmdOption>();
+ private final Map<CmdOption, Boolean> boolOptionMap =
+ new EnumMap<CmdOption, Boolean>(CmdOption.class);
+ private final Map<CmdOption, String> stringOptionMap =
+ new EnumMap<CmdOption, String>(CmdOption.class);
+
+
+ /**
+ * コンストラクタ。
+ */
+ protected OptionInfo(){
+ super();
+ return;
+ }
+
+
+ /**
+ * 文字列が可変引数のいずれかと英字大小無視で等しいか判定する。
+ * <p>※ JRE1.6のString#equalsIgnoreCase の代替も兼ねる。
+ * @param text 文字列
+ * @param names 文字列の可変引数
+ * @return 等しい物があればtrue
+ */
+ private static boolean equalsIgnoreCase(String text, String ... names){
+ for(String name : names){
+ if(text.compareToIgnoreCase(name) == 0) return true;
+ }
+ return false;
+ }
+
+ /**
+ * 真偽二値をとるオプション解析の下請け。
+ * @param info オプション情報格納先
+ * @param option オプション種別
+ * @param optTxt オプション名文字列
+ * @param onoff オプション引数
+ * @throws IllegalArgumentException 構文エラー
+ */
+ private static void parseBooleanSwitch(OptionInfo info,
+ CmdOption option,
+ String optTxt,
+ String onoff )
+ throws IllegalArgumentException{
+ Boolean flag;
+
+ if(equalsIgnoreCase(onoff, "on", "yes", "true")){
+ flag = Boolean.TRUE;
+ }else if(equalsIgnoreCase(onoff, "off", "no", "false")){
+ flag = Boolean.FALSE;
+ }else{
+ String errmsg =
+ MessageFormat.format(ERRFORM_BOOL, optTxt, onoff);
+ throw new IllegalArgumentException(errmsg);
+ }
+
+ info.boolOptionMap.put(option, flag);
+
+ return;
+ }
+
+ /**
+ * 文字列がマイナス記号で始まるか判定する。
+ * @param txt 文字列
+ * @return マイナス記号で始まればtrue
+ */
+ private static boolean isMinus(String txt){
+ if(txt.length() >= 1 && txt.charAt(0) == '-'){
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * ウィンドウジオメトリオプション解析。
+ * <p>例) WIDTHxHEIGHT+XPOS+YPOS
+ * @param info オプション情報格納先
+ * @param optTxt オプション名文字列
+ * @param geometry オプション引数
+ * @throws IllegalArgumentException 構文エラー
+ */
+ private static void parseGeometry(OptionInfo info,
+ String optTxt,
+ String geometry )
+ throws IllegalArgumentException{
+ Matcher matcher = PATTERN_GEOMETRY.matcher(geometry);
+ if( ! matcher.matches() ){
+ String errmsg = MessageFormat.format(ERRFORM_GEOM,
+ optTxt, geometry);
+ throw new IllegalArgumentException(errmsg);
+ }
+
+ int gpos = 1;
+ String width = matcher.group(gpos++);
+ String height = matcher.group(gpos++);
+ String xSign = matcher.group(gpos++);
+ String xPos = matcher.group(gpos++);
+ String ySign = matcher.group(gpos++);
+ String yPos = matcher.group(gpos++);
+
+ info.frameWidth = Integer.parseInt(width);
+ info.frameHeight = Integer.parseInt(height);
+
+ if(xPos != null){
+ info.frameXpos = Integer.parseInt(xPos);
+ if(isMinus(xSign)){
+ info.frameXpos = -info.frameXpos;
+ }
+ }
+
+ if(yPos != null){
+ info.frameYpos = Integer.parseInt(yPos);
+ if(isMinus(ySign)){
+ info.frameYpos = -info.frameYpos;
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * オプション引数を解析する。
+ * @param result オプション情報
+ * @param optTxt オプション文字列
+ * @param option オプション種別
+ * @param iterator オプション並び
+ * @return 引数と同じオプション情報
+ * @throws IllegalArgumentException 構文エラー
+ */
+ private static OptionInfo parseOptionArg(OptionInfo result,
+ String optTxt,
+ CmdOption option,
+ Iterator<String> iterator )
+ throws IllegalArgumentException {
+ String nextArg;
+ if(iterator.hasNext()){
+ nextArg = iterator.next();
+ }else{
+ String errMsg = MessageFormat.format(ERRFORM_NOARG, optTxt);
+ throw new IllegalArgumentException(errMsg);
+ }
+
+ if(option == CmdOption.OPT_GEOMETRY){
+ parseGeometry(result, optTxt, nextArg);
+ }else if(option.isBooleanOption()){
+ parseBooleanSwitch(result, option, optTxt, nextArg);
+ }else if( option == CmdOption.OPT_INITFONT
+ || option == CmdOption.OPT_CONFDIR ){
+ result.stringOptionMap.put(option, nextArg);
+ }else{
+ assert false;
+ }
+
+ return result;
+ }
+
+ /**
+ * オプション文字列を解析する。
+ * @param args main()に渡されるオプション文字列
+ * @return 解析済みのオプション情報。
+ * @throws IllegalArgumentException 構文エラー
+ */
+ public static OptionInfo parseOptions(String ... args)
+ throws IllegalArgumentException{
+ OptionInfo result = new OptionInfo();
+
+ for(String arg : args){
+ if(arg == null) continue;
+ result.invokeArgs.add(arg);
+ }
+ Iterator<String> iterator = result.invokeArgs.iterator();
+
+ while(iterator.hasNext()){
+ String arg = iterator.next();
+
+ CmdOption option = CmdOption.parseCmdOption(arg);
+ if(option == null){
+ String errmsg = MessageFormat.format(ERRFORM_UKNOWN, arg);
+ throw new IllegalArgumentException(errmsg);
+ }
+ result.optionList.add(option);
+
+ if( ! option.isIndepOption() ){
+ parseOptionArg(result, arg, option, iterator);
+ }
+ }
+
+ return result;
+ }
+
+
+ /**
+ * 全引数のリストを返す。
+ * @return 全引数のリスト
+ */
+ public List<String> getInvokeArgList(){
+ return Collections.unmodifiableList(this.invokeArgs);
+ }
+
+ /**
+ * オプションが指定されていたか否か判定する。
+ * @param option オプション
+ * @return 指定されていたらtrue
+ */
+ public boolean hasOption(CmdOption option){
+ if(this.optionList.contains(option)) return true;
+ return false;
+ }
+
+ /**
+ * 真偽値をとるオプション値を返す。
+ * 複数回指定された場合は最後の値。
+ * @param option オプション
+ * @return 真偽値。オプション指定がなかった場合はnull
+ * @throws IllegalArgumentException 真偽値を取るオプションではない。
+ */
+ public Boolean getBooleanArg(CmdOption option)
+ throws IllegalArgumentException{
+ if( ! option.isBooleanOption() ){
+ String errMsg =
+ MessageFormat.format(ERRFORM_NONBOOL, option.toString());
+ throw new IllegalArgumentException(errMsg);
+ }
+ Boolean result = this.boolOptionMap.get(option);
+ return result;
+ }
+
+ /**
+ * 文字列引数をとるオプション値を返す。
+ * 複数回指定された場合は最後の値。
+ * @param option オプション
+ * @return 文字列。オプション指定がなかった場合はnull
+ */
+ public String getStringArg(CmdOption option){
+ String result = this.stringOptionMap.get(option);
+ return result;
+ }
+
+ /**
+ * 排他的オプションのいずれかが指定されたか判定する。
+ * 後から指定された方が有効となる。
+ * @param options 排他的オプション群
+ * @return いずれかのオプション。どれも指定されなければnull
+ */
+ public CmdOption getExclusiveOption(CmdOption... options){
+ CmdOption result = null;
+ for(CmdOption option : this.optionList){
+ for(CmdOption excOption : options){
+ if(option == excOption){
+ result = option;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 初期のフレーム幅を返す。
+ * @return 初期のフレーム幅。オプション指定されてなければnull
+ */
+ public Integer initialFrameWidth(){
+ return this.frameWidth;
+ }
+
+ /**
+ * 初期のフレーム高を返す。
+ * @return 初期のフレーム高。オプション指定されてなければnull
+ */
+ public Integer initialFrameHeight(){
+ return this.frameHeight;
+ }
+
+ /**
+ * 初期のフレーム位置のX座標を返す。
+ * @return 初期のフレーム位置のX座標。オプション指定されてなければnull
+ */
+ public Integer initialFrameXpos(){
+ return this.frameXpos;
+ }
+
+ /**
+ * 初期のフレーム位置のY座標を返す。
+ * @return 初期のフレーム位置のY座標。オプション指定されてなければnull
+ */
+ public Integer initialFrameYpos(){
+ return this.frameYpos;
+ }
+
+}
--- /dev/null
+/*
+ * パッケージ情報
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+/**
+ * 各種アプリ設定や実行環境に関する一連のクラス。
+ */
+
+package jp.sfjp.jindolf.config;
+
+/* EOF */
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import jp.sfjp.jindolf.util.StringUtils;
/**
* 発言アンカー。
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
+import jp.sfjp.jindolf.dxchg.XmlUtils;
import jp.sourceforge.jindolf.corelib.PreDefAvatar;
import org.xml.sax.SAXException;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
/**
* 発言表示設定。
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.net.HtmlSequence;
+import jp.sfjp.jindolf.net.ServerAccess;
import jp.sourceforge.jindolf.corelib.LandDef;
import jp.sourceforge.jindolf.corelib.LandState;
import jp.sourceforge.jindolf.corelib.VillageState;
// 古国ID
private static final String ID_VANILLAWOLF = "wolf";
+ private static final LogWrapper LOGGER = new LogWrapper();
+
private final LandDef landDef;
private final ServerAccess serverAccess;
try{
uri = new URI(pureHREF);
}catch(URISyntaxException e){
- Jindolf.logger().warn(
+ LOGGER.warn(
"不正なURI["
+ hrefValue
+ "]を検出しました");
try{
image = server.downloadImage(imageURL);
}catch(IOException e){
- Jindolf.logger().warn(
+ LOGGER.warn(
"イメージ[" + imageURL + "]"
+ "のダウンロードに失敗しました",
e );
try{
this.parser.parseAutomatic(content);
}catch(HtmlParseException e){
- Jindolf.logger().warn("トップページを認識できない", e);
+ LOGGER.warn("トップページを認識できない", e);
}
List<Village> list = this.handler.getVillageList();
if(list != null){
try{
this.parser.parseAutomatic(content);
}catch(HtmlParseException e){
- Jindolf.logger().warn("村一覧ページを認識できない", e);
+ LOGGER.warn("村一覧ページを認識できない", e);
}
List<Village> list = this.handler.getVillageList();
if(list != null){
String villageID = getVillageIDFromHREF(href);
if( villageID == null
|| villageID.length() <= 0 ){
- Jindolf.logger().warn(
+ LOGGER.warn(
"認識できないURL[" + href + "]に遭遇しました。");
return;
}
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import java.io.IOException;
import java.net.URISyntaxException;
import javax.swing.tree.TreePath;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
+import jp.sfjp.jindolf.dxchg.XmlUtils;
+import jp.sfjp.jindolf.log.LogWrapper;
import jp.sourceforge.jindolf.corelib.LandDef;
import org.xml.sax.SAXException;
private static final String ROOT = "ROOT";
private static final int SECTION_INTERVAL = 100;
+ private static final LogWrapper LOGGER = new LogWrapper();
+
private final List<Land> landList = new LinkedList<Land>();
private final List<Land> unmodList =
DocumentBuilder builder = XmlUtils.createDocumentBuilder();
landDefList = LandDef.buildLandDefList(builder);
}catch(IOException e){
- Jindolf.logger().fatal("failed to load land list", e);
+ LOGGER.fatal("failed to load land list", e);
return;
}catch(SAXException e){
- Jindolf.logger().fatal("failed to load land list", e);
+ LOGGER.fatal("failed to load land list", e);
return;
}catch(URISyntaxException e){
- Jindolf.logger().fatal("failed to load land list", e);
+ LOGGER.fatal("failed to load land list", e);
return;
}catch(ParserConfigurationException e){
- Jindolf.logger().fatal("failed to load land list", e);
+ LOGGER.fatal("failed to load land list", e);
return;
}
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.net.HtmlSequence;
+import jp.sfjp.jindolf.net.ServerAccess;
+import jp.sfjp.jindolf.util.StringUtils;
import jp.sourceforge.jindolf.corelib.EventFamily;
import jp.sourceforge.jindolf.corelib.GameRole;
import jp.sourceforge.jindolf.corelib.LandDef;
private static final PeriodHandler HANDLER =
new PeriodHandler();
+ private static final LogWrapper LOGGER = new LogWrapper();
+
static{
PARSER.setBasicHandler (HANDLER);
PARSER.setSysEventHandler(HANDLER);
try{
PARSER.parseAutomatic(content);
}catch(HtmlParseException e){
- Jindolf.logger().warn("発言抽出に失敗", e);
+ LOGGER.warn("発言抽出に失敗", e);
}
if(wasHot && ! period.isHot() ){
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import jp.sourceforge.jindolf.corelib.Destiny;
import jp.sourceforge.jindolf.corelib.GameRole;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import java.util.Collections;
import java.util.HashSet;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import jp.sourceforge.jindolf.corelib.TalkType;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
/**
* プレイヤーの発言及びゲームシステムからのメッセージのスーパーインタフェース。
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.net.HtmlSequence;
+import jp.sfjp.jindolf.net.ServerAccess;
+import jp.sfjp.jindolf.util.GUIUtils;
import jp.sourceforge.jindolf.corelib.LandDef;
import jp.sourceforge.jindolf.corelib.LandState;
import jp.sourceforge.jindolf.corelib.PeriodType;
private static final VillageHeadHandler HANDLER =
new VillageHeadHandler();
+ private static final LogWrapper LOGGER = new LogWrapper();
+
static{
PARSER.setBasicHandler (HANDLER);
PARSER.setSysEventHandler(HANDLER);
try{
PARSER.parseAutomatic(content);
}catch(HtmlParseException e){
- Jindolf.logger().warn("村の状態が不明", e);
+ LOGGER.warn("村の状態が不明", e);
}
return;
if(villageState == VillageState.UNKNOWN){
this.village.setState(villageState);
this.village.periodList.clear();
- Jindolf.logger().warn("村の状況を読み取れません");
+ LOGGER.warn("村の状況を読み取れません");
return;
}
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.awt.Component;
import java.awt.GridBagConstraints;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.filechooser.FileFilter;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Topic;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.view.TopicFilter;
import jp.sourceforge.jindolf.corelib.TalkType;
/**
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.util.HashMap;
import java.util.Map;
+import jp.sfjp.jindolf.data.Avatar;
/**
* 顔アイコンWiki表記のセット。
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sfjp.jindolf.util.Monodizer;
/**
* Webブラウザ起動ボタン。
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.awt.Container;
import java.awt.Frame;
import javax.swing.TransferHandler;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
+import jp.sfjp.jindolf.JreChecker;
+import jp.sfjp.jindolf.VerInfo;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sfjp.jindolf.util.Monodizer;
/**
* Webブラウザ起動用の専用ダイアログ。
extends JDialog
implements ActionListener {
- private static final String FRAMETITLE =
- "URLへのアクセス確認 - " + Jindolf.TITLE;
+ private static final String TITLE_WWW =
+ VerInfo.getFrameTitle("URLへのアクセス確認");
+
+
+ private static final LogWrapper LOGGER = new LogWrapper();
private final String warnMessage;
* @param owner オーナーフレーム
*/
public WebIPCDialog(Frame owner){
- super(owner, FRAMETITLE, true);
+ super(owner);
+ setModal(true);
GUIUtils.modifyWindowAttributes(this, true, false, true);
this.ipc = webipc;
if(this.ipc == null){
- if( ! Jindolf.JRE_PACKAGE.isCompatibleWith("1.6") ){
+ if( ! JreChecker.has16Runtime() ){
this.warnMessage =
"この機能を利用するには、JRE1.6以上が必要です";
}else{
return;
}
-
/**
* Webブラウザ起動用のモーダルダイアログを表示する。
* @param owner オーナーフレーム
public static void showDialog(Frame owner, String url){
WebIPCDialog dialog = new WebIPCDialog(owner);
+ dialog.setTitle(TITLE_WWW);
dialog.setUrlText(url);
dialog.pack();
dialog.setLocationRelativeTo(owner);
if(this.ipc == null){
String title;
- if( ! Jindolf.JRE_PACKAGE.isCompatibleWith("1.6") ){
+ if( ! JreChecker.has16Runtime() ){
title = "新しいJavaを入手しましょう";
}else{
title = "報告";
String logmsg = "URL "
+ this.uri.toASCIIString()
+ " へのアクセスをWebブラウザに指示しました";
- Jindolf.logger().info(logmsg);
+ LOGGER.info(logmsg);
}finally{
close();
}
String logmsg = "文字列「"
+ uristring
+ "」をクリップボードにコピーしました";
- Jindolf.logger().info(logmsg);
+ LOGGER.info(logmsg);
}finally{
close();
}
String logmsg = "URL "
+ WebIPCDialog.this.uri.toASCIIString()
+ " がどこかへドラッグ&ドロップされました";
- Jindolf.logger().info(logmsg);
+ LOGGER.info(logmsg);
close();
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
+import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import jp.sfjp.jindolf.ResourceManager;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.log.LogWrapper;
import jp.sourceforge.jindolf.corelib.Destiny;
import jp.sourceforge.jindolf.corelib.GameRole;
Pattern.compile("[A-Z][a-z]+([A-Z])[a-z]+");
private static final String FACEICONSET =
- "resources/faceIconSet.properties";
+ "resources/wolfbbs/faceIconSet.properties";
private static final String ORDER_PREFIX = "iconset.order.";
private static final List<FaceIconSet> FACEICONSET_LIST =
new LinkedList<FaceIconSet>();
private static final String WOLFBBS_URL = "http://wolfbbs.jp/";
+ private static final LogWrapper LOGGER = new LogWrapper();
+
static{
- loadFaceIconSet();
+ try{
+ loadFaceIconSet();
+ }catch(FileNotFoundException e){
+ throw new ExceptionInInitializerError(e);
+ }
StringBuilder wikicomment = new StringBuilder();
wikicomment.append("// ");
/**
* アイコンセットのロード。
+ * @throws FileNotFoundException リソースが不明
*/
- private static void loadFaceIconSet(){
- InputStream is = Jindolf.getResourceAsStream(FACEICONSET);
- Properties properties = new Properties();
- try{
- properties.load(is);
- is.close();
- }catch(IOException e){
- Jindolf.logger().fatal(
- "顔アイコンセットの読み込みに失敗しました", e);
- Jindolf.exit(1);
+ private static void loadFaceIconSet() throws FileNotFoundException {
+ Properties properties = ResourceManager.getProperties(FACEICONSET);
+ if(properties == null){
+ LOGGER.fatal("顔アイコンセットの読み込みに失敗しました");
+ throw new FileNotFoundException();
}
loadFaceIconSet(properties);
/**
* アイコンセットのロード。
* @param properties プロパティ
+ * @throws FileNotFoundException リソースが不明
*/
- private static void loadFaceIconSet(Properties properties){
+ private static void loadFaceIconSet(Properties properties)
+ throws FileNotFoundException {
String codeCheck = properties.getProperty("codeCheck");
if( codeCheck == null
|| codeCheck.length() != 1
|| codeCheck.charAt(0) != '\u72fc'){ // 「狼」
- Jindolf.logger().fatal(
+ LOGGER.fatal(
"顔アイコンセットプロパティファイルの"
+"文字コードがおかしいようです。"
+"native2ascii は正しく適用しましたか?");
- Jindolf.exit(1);
- return;
+ throw new FileNotFoundException();
}
Set<Object> keySet = properties.keySet();
int resultLength;
- resultLength = result.length();
while(result.length() > 0 && result.charAt(0) == '/'){
result.deleteCharAt(0);
}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.io.IOException;
import java.io.InputStream;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.dxchg;
import java.io.IOException;
import java.io.InputStream;
--- /dev/null
+/*
+ * パッケージ情報
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+/**
+ * 他アプリやサービスとのデータ交換関連の一連のクラス。
+ */
+
+package jp.sfjp.jindolf.dxchg;
+
+/* EOF */
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.editor;
import java.awt.BorderLayout;
import java.awt.Color;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.editor;
import java.awt.Dimension;
import java.awt.EventQueue;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.editor;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.text.NavigationFilter;
import javax.swing.text.PlainDocument;
import javax.swing.text.Segment;
+import jp.sfjp.jindolf.dxchg.TextPopup;
/**
* 原稿作成支援エディタ。
* コンストラクタ。
* @param seqNumber 通し番号
*/
+ @SuppressWarnings("LeakingThisInConstructor")
private TalkEditor(int seqNumber){
super();
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.editor;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.JTextComponent;
+import jp.sfjp.jindolf.dxchg.ClipboardAction;
+import jp.sfjp.jindolf.dxchg.TextPopup;
+import jp.sfjp.jindolf.glyph.FontInfo;
+import jp.sfjp.jindolf.util.GUIUtils;
import jp.sourceforge.jovsonz.JsArray;
+import jp.sourceforge.jovsonz.JsComposition;
import jp.sourceforge.jovsonz.JsObject;
import jp.sourceforge.jovsonz.JsString;
+import jp.sourceforge.jovsonz.JsTypes;
import jp.sourceforge.jovsonz.JsValue;
/**
public class TalkPreview extends JFrame
implements ActionListener, ChangeListener{
- private static final String FRAMETITLE = "発言エディタ - " + Jindolf.TITLE;
+ /** 原稿ファイル。 */
+ public static final File DRAFT_FILE = new File("draft.json");
+
private static final Color COLOR_EDITORBACK = Color.BLACK;
- private static final String DRAFT_FILE = "draft.json";
private final JTextComponent freeMemo = new TextEditor();
/**
* コンストラクタ。
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public TalkPreview(){
- super(FRAMETITLE);
+ super();
GUIUtils.modifyWindowAttributes(this, true, false, true);
}
/**
- * 原稿のロード。
+ * JSON形式の原稿情報を返す。
+ * @return JSON形式の原稿情報
+ */
+ public JsObject getJson(){
+ JsObject result = new JsObject();
+ JsString memo = new JsString(this.freeMemo.getText());
+ result.putValue("freeMemo", memo);
+
+ JsArray array = new JsArray();
+ JsString text = new JsString(this.editArray.getAllText());
+ array.add(text);
+ result.putValue("drafts", array);
+
+ return result;
+ }
+
+ /**
+ * JSON形式の原稿情報を反映させる。
+ * @param root JSON形式の原稿情報。nullが来たら何もしない
*/
- public void loadDraft(){
- JsValue value = ConfigFile.loadJson(new File(DRAFT_FILE));
- if(value == null) return;
+ public void putJson(JsObject root){
+ if(root == null) return;
- if( ! (value instanceof JsObject) ) return;
- JsObject root = (JsObject) value;
+ JsValue value;
value = root.getValue("freeMemo");
- if(value instanceof JsString){
+ if(value.getJsTypes() == JsTypes.STRING){
JsString memo = (JsString) value;
this.freeMemo.setText(memo.toRawString());
}
value = root.getValue("drafts");
- if( ! (value instanceof JsArray) ) return;
+ if(value.getJsTypes() != JsTypes.ARRAY) return;
JsArray array = (JsArray) value;
StringBuilder draftAll = new StringBuilder();
for(JsValue elem : array){
- if( ! (elem instanceof JsString) ) continue;
+ if(elem.getJsTypes() != JsTypes.STRING) continue;
JsString draft = (JsString) elem;
draftAll.append(draft.toRawString());
}
}
/**
- * 原稿のセーブ。
+ * 起動時の原稿と等価か判定する。
+ * @param conf 比較対象
+ * @return 等価ならtrue
*/
- public void saveDraft(){
- AppSetting setting = Jindolf.getAppSetting();
- if( ! setting.useConfigPath() ) return;
- File configPath = setting.getConfigPath();
- if(configPath == null) return;
-
- JsObject root = new JsObject();
- JsString memo = new JsString(this.freeMemo.getText());
- root.putValue("freeMemo", memo);
-
- JsArray array = new JsArray();
- JsString text = new JsString(this.editArray.getAllText());
- array.add(text);
- root.putValue("drafts", array);
-
+ public boolean hasConfChanged(JsComposition<?> conf){
if(this.loadedDraft != null){
- if(this.loadedDraft.equals(root)) return;
+ if(this.loadedDraft.equals(conf)) return true;
}
-
- ConfigFile.saveJson(new File(DRAFT_FILE), root);
-
- return;
+ return false;
}
/**
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.editor;
import java.awt.Rectangle;
import java.awt.event.InputMethodEvent;
/**
* コンストラクタ。
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public TextEditor(){
super();
--- /dev/null
+/*
+ * パッケージ情報
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+/**
+ * 発言エディタ関連の一連のクラス。
+ */
+
+package jp.sfjp.jindolf.editor;
+
+/* EOF */
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Rectangle;
import java.awt.font.GlyphVector;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.regex.Pattern;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.DialogPref;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Village;
/**
* アンカー描画。
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Point;
import java.util.EventObject;
+import jp.sfjp.jindolf.data.Anchor;
/**
* 発言アンカーがクリックされたときのイベント。
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.util.EventListener;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Color;
import java.awt.Component;
import javax.swing.event.EventListenerList;
import javax.swing.event.MouseInputListener;
import javax.swing.text.DefaultEditorKit;
+import jp.sfjp.jindolf.data.Anchor;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.DialogPref;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.RegexPattern;
+import jp.sfjp.jindolf.data.SysEvent;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Topic;
+import jp.sfjp.jindolf.dxchg.ClipboardAction;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sfjp.jindolf.view.ActionManager;
+import jp.sfjp.jindolf.view.TopicFilter;
/**
* 発言表示画面。
/**
* 発言表示画面を作成する。
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public Discussion(){
super();
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.BorderLayout;
-import java.awt.Color;
import java.awt.Container;
-import java.awt.Dimension;
import java.awt.Font;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
-import java.awt.font.FontRenderContext;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.io.IOException;
+import java.text.MessageFormat;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
-import javax.swing.JComponent;
import javax.swing.JLabel;
-import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
+import jp.sfjp.jindolf.ResourceManager;
+import jp.sfjp.jindolf.dxchg.TextPopup;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.util.Monodizer;
/**
* 発言表示フォント選択パネル。
public class FontChooser extends JPanel
implements ListSelectionListener,
ActionListener,
- ItemListener{
+ ItemListener {
- private static final Integer[] POINT_SIZES = {
+ private static final int[] POINT_SIZES = {
8, 10, 12, 16, 18, 24, 32, 36, 48, 72, // TODO これで十分?
};
private static final CharSequence PREVIEW_CONTENT;
+ private static final int UNIT_INC = 8;
+
+ private static final LogWrapper LOGGER = new LogWrapper();
static{
- CharSequence resourceText;
- try{
- resourceText = Jindolf.loadResourceText("resources/preview.txt");
- }catch(IOException e){
- resourceText = "ABC";
- }
- PREVIEW_CONTENT = resourceText;
+ PREVIEW_CONTENT =
+ ResourceManager.getTextFile("resources/font/preview.txt");
}
private FontInfo fontInfo;
private FontInfo lastFontInfo;
- private final JList familySelector;
+ private final FontSelectList familySelector;
private final JComboBox sizeSelector;
private final JCheckBox isBoldCheck;
private final JCheckBox isItalicCheck;
private final JCheckBox useFractionalCheck;
private final JLabel maxBounds;
private final JTextField decodeName;
- private final FontPreview preview;
+ private final FontPreviewer preview;
private final JButton resetDefault;
private boolean maskListener = false;
this.fontInfo = fontInfo;
this.lastFontInfo = fontInfo;
- Jindolf.logger().info(
- "デフォルトの発言表示フォントに"
- + this.fontInfo.getFont()
- + "が選択されました" );
- Jindolf.logger().info(
- "発言表示のアンチエイリアス指定に"
- + this.fontInfo.getFontRenderContext().isAntiAliased()
- + "が指定されました" );
- Jindolf.logger().info(
- "発言表示のFractional指定に"
- + this.fontInfo.getFontRenderContext().usesFractionalMetrics()
- + "が指定されました" );
-
- this.familySelector = new JList(FontUtils.createFontSet().toArray());
- this.familySelector.setVisibleRowCount(-1);
- this.familySelector
- .setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ logging(this.fontInfo);
+
+ this.familySelector = new FontSelectList();
this.sizeSelector = new JComboBox();
this.sizeSelector.setEditable(true);
- this.sizeSelector.setActionCommand(ActionManager.CMD_FONTSIZESEL);
- for(Integer size : POINT_SIZES){
+ for(int size : POINT_SIZES){
this.sizeSelector.addItem(size);
}
this.decodeName.setComponentPopupMenu(new TextPopup());
Monodizer.monodize(this.decodeName);
- this.preview = new FontPreview(PREVIEW_CONTENT, this.fontInfo);
+ this.preview = new FontPreviewer(PREVIEW_CONTENT, this.fontInfo);
this.resetDefault = new JButton("出荷時に戻す");
- this.resetDefault.addActionListener(this);
design(this);
updateControlls();
- updatePreview();
this.familySelector.addListSelectionListener(this);
this.sizeSelector .addActionListener(this);
this.useTextAntiAliaseCheck.addItemListener(this);
this.useFractionalCheck .addItemListener(this);
+ this.resetDefault.addActionListener(this);
+
+ return;
+ }
+
+ /**
+ * フォント情報に関するログ出力。
+ * @param info フォント情報
+ */
+ private static void logging(FontInfo info){
+ String form;
+ String logMsg;
+
+ form = "発言表示フォントに{0}が選択されました。";
+ logMsg = MessageFormat.format(form, info.getFont());
+ LOGGER.info(logMsg);
+
+ form = "発言表示のアンチエイリアス指定に{0}が指定されました。";
+ logMsg = MessageFormat.format(form, info.isAntiAliased());
+ LOGGER.info(logMsg);
+
+ form = "発言表示のFractional指定に{0}が指定されました。";
+ logMsg = MessageFormat.format(form, info.usesFractionalMetrics());
+ LOGGER.info(logMsg);
+
return;
}
*/
private void design(Container content){
GridBagLayout layout = new GridBagLayout();
- GridBagConstraints constraints = new GridBagConstraints();
-
content.setLayout(layout);
- Border border;
- JPanel panel;
-
- JComponent fontPref = createFontPrefPanel();
-
+ GridBagConstraints constraints = new GridBagConstraints();
constraints.insets = new Insets(5, 5, 5, 5);
- constraints.weightx = 1.0;
- constraints.weighty = 0.0;
+ constraints.weightx = 1.0;
+ constraints.weighty = 0.0;
constraints.gridwidth = GridBagConstraints.REMAINDER;
- constraints.fill = GridBagConstraints.BOTH;
- content.add(fontPref, constraints);
+ constraints.fill = GridBagConstraints.BOTH;
+ content.add(createFontPrefPanel(), constraints);
- constraints.weightx = 1.0;
- constraints.weighty = 1.0;
+ constraints.weightx = 1.0;
+ constraints.weighty = 1.0;
constraints.gridwidth = GridBagConstraints.REMAINDER;
- constraints.fill = GridBagConstraints.BOTH;
- border = BorderFactory.createTitledBorder("プレビュー");
- panel = new JPanel();
- panel.add(this.preview);
- panel.setBorder(border);
+ constraints.fill = GridBagConstraints.BOTH;
content.add(createPreviewPanel(), constraints);
- constraints.weightx = 1.0;
- constraints.weighty = 0.0;
+ constraints.weightx = 1.0;
+ constraints.weighty = 0.0;
constraints.gridwidth = GridBagConstraints.REMAINDER;
- constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
content.add(createFontDecodePanel(), constraints);
- constraints.insets = new Insets(5, 5, 5, 5);
- constraints.weightx = 1.0;
- constraints.weighty = 0.0;
+ constraints.weightx = 1.0;
+ constraints.weighty = 0.0;
constraints.gridwidth = 1;
- constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
content.add(this.maxBounds, constraints);
- constraints.weightx = 0.0;
- constraints.weighty = 0.0;
+ constraints.weightx = 0.0;
+ constraints.weighty = 0.0;
constraints.gridwidth = GridBagConstraints.REMAINDER;
- constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
content.add(this.resetDefault, constraints);
return;
* フォント設定画面を生成する。
* @return フォント設定画面
*/
- private JComponent createFontPrefPanel(){
+ private JPanel createFontPrefPanel(){
JPanel result = new JPanel();
GridBagLayout layout = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
result.setLayout(layout);
- Border border;
+ JPanel familyBorderPanel = new JPanel();
+ Border familyBorder =
+ BorderFactory.createTitledBorder("フォントファミリ選択");
+ familyBorderPanel.setBorder(familyBorder);
- constraints.insets = new Insets(0, 0, 0, 5);
- constraints.weightx = 1.0;
- constraints.weighty = 0.0;
- constraints.gridheight = GridBagConstraints.REMAINDER;
- constraints.fill = GridBagConstraints.BOTH;
- border = BorderFactory.createEmptyBorder(1, 1, 1, 1);
- this.familySelector.setBorder(border);
+ JPanel sizeBorderPanel = new JPanel();
+ Border sizeBorder =
+ BorderFactory.createTitledBorder("ポイントサイズ指定");
+ sizeBorderPanel.setBorder(sizeBorder);
+
+ Border scrollBorder = BorderFactory.createEmptyBorder(1, 1, 1, 1);
+ this.familySelector.setBorder(scrollBorder);
JScrollPane familyScroller = new JScrollPane(this.familySelector);
- border = BorderFactory.createTitledBorder("フォントファミリ選択");
- JPanel familyPanel = new JPanel();
- familyPanel.setLayout(new BorderLayout());
- familyPanel.add(familyScroller, BorderLayout.CENTER);
- familyPanel.setBorder(border);
- result.add(familyPanel, constraints);
-
- constraints.insets = new Insets(0, 0, 0, 0);
- constraints.weightx = 0.0;
- constraints.gridheight = 1;
- constraints.fill = GridBagConstraints.HORIZONTAL;
- constraints.anchor = GridBagConstraints.WEST;
- border = BorderFactory.createTitledBorder("ポイントサイズ指定");
- JPanel panel = new JPanel();
- panel.add(this.sizeSelector);
- panel.setBorder(border);
- result.add(panel, constraints);
+ familyBorderPanel.setLayout(new BorderLayout());
+ familyBorderPanel.add(familyScroller);
+ constraints.insets = new Insets(0, 0, 0, 5);
+ constraints.weightx = 1.0;
+ constraints.weighty = 0.0;
+ constraints.gridheight = GridBagConstraints.REMAINDER;
+ constraints.fill = GridBagConstraints.BOTH;
+ result.add(familyBorderPanel, constraints);
+
+ sizeBorderPanel.setLayout(new BorderLayout());
+ sizeBorderPanel.add(this.sizeSelector);
+ constraints.insets = new Insets(0, 0, 0, 0);
+ constraints.weightx = 0.0;
+ constraints.gridheight = 1;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.anchor = GridBagConstraints.WEST;
+ result.add(sizeBorderPanel, constraints);
constraints.anchor = GridBagConstraints.NORTHWEST;
- result.add(this.isBoldCheck, constraints);
- result.add(this.isItalicCheck, constraints);
+ result.add(this.isBoldCheck, constraints);
+ result.add(this.isItalicCheck, constraints);
result.add(this.useTextAntiAliaseCheck, constraints);
- result.add(this.useFractionalCheck, constraints);
+ result.add(this.useFractionalCheck, constraints);
return result;
}
* プレビュー画面を生成する。
* @return プレビュー画面
*/
- private JComponent createPreviewPanel(){
+ private JPanel createPreviewPanel(){
JPanel result = new JPanel();
+ Border border =
+ BorderFactory.createTitledBorder("フォントプレビュー");
+ result.setBorder(border);
JScrollPane scroller = new JScrollPane(this.preview);
- scroller.getVerticalScrollBar().setUnitIncrement(8);
+ scroller.getVerticalScrollBar().setUnitIncrement(UNIT_INC);
- Border border;
- border = BorderFactory.createTitledBorder("プレビュー");
- result.setBorder(border);
result.setLayout(new BorderLayout());
- result.add(scroller, BorderLayout.CENTER);
+ result.add(scroller);
return result;
}
* フォントデコード名表示パネルを生成する。
* @return フォントデコード名表示パネル
*/
- private JComponent createFontDecodePanel(){
+ private JPanel createFontDecodePanel(){
JPanel result = new JPanel();
GridBagLayout layout = new GridBagLayout();
- GridBagConstraints constraints = new GridBagConstraints();
result.setLayout(layout);
- constraints.weightx = 0.0;
- constraints.weighty = 0.0;
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ JLabel label = new JLabel("Font.deode() 識別名:");
+
+ constraints.weightx = 0.0;
+ constraints.weighty = 0.0;
constraints.gridwidth = 1;
- constraints.fill = GridBagConstraints.NONE;
- result.add(new JLabel("Font.deode() 識別名:"), constraints);
+ constraints.fill = GridBagConstraints.NONE;
+ result.add(label, constraints);
- constraints.weightx = 1.0;
+ constraints.weightx = 1.0;
constraints.gridwidth = GridBagConstraints.REMAINDER;
- constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
result.add(this.decodeName, constraints);
return result;
this.fontInfo = newInfo;
updateControlls();
- updatePreview();
return;
}
/**
- * 選択されたフォントを返す。
- * @return フォント
- */
- private Font getSelectedFont(){
- return this.fontInfo.getFont();
- }
-
- /**
- * 設定されたフォント描画設定を返す。
- * @return 描画設定
- */
- protected FontRenderContext getFontRenderContext(){
- return this.fontInfo.getFontRenderContext();
- }
-
- /**
- * フォント設定に合わせてプレビュー画面を更新する。
- */
- private void updatePreview(){
- this.preview.setFontInfo(this.fontInfo);
- return;
- }
-
- /**
* フォント設定に合わせてGUIを更新する。
+ * <p>イベント発火は抑止される。
*/
private void updateControlls(){
this.maskListener = true;
- Font currentFont = getSelectedFont();
- FontRenderContext currentContext = getFontRenderContext();
+ Font currentFont = getFontInfo().getFont();
+ // フォント名リスト
String defaultFamily = currentFont.getFamily();
- this.familySelector.setSelectedValue(defaultFamily, true);
+ this.familySelector.setSelectedFamily(defaultFamily);
+ // サイズ指定コンボボックス
Integer selectedInteger = Integer.valueOf(currentFont.getSize());
this.sizeSelector.setSelectedItem(selectedInteger);
int sizeItems = this.sizeSelector.getItemCount();
- for(int index = 0; index <= sizeItems - 1; index++){
+ for(int index = 0; index < sizeItems; index++){
Object sizeItem = this.sizeSelector.getItemAt(index);
if(sizeItem.equals(selectedInteger)){
this.sizeSelector.setSelectedIndex(index);
}
}
+ // チェックボックス群
this.isBoldCheck .setSelected(currentFont.isBold());
this.isItalicCheck.setSelected(currentFont.isItalic());
-
this.useTextAntiAliaseCheck
- .setSelected(currentContext.isAntiAliased());
+ .setSelected(this.fontInfo.isAntiAliased());
this.useFractionalCheck
- .setSelected(currentContext.usesFractionalMetrics());
+ .setSelected(this.fontInfo.usesFractionalMetrics());
+ // デコード名
this.decodeName.setText(FontUtils.getFontDecodeName(currentFont));
this.decodeName.setCaretPosition(0);
- Rectangle2D r2d = currentFont.getMaxCharBounds(currentContext);
- Rectangle rect = r2d.getBounds();
- String boundInfo = "最大文字寸法 : "
- + rect.width
- + " pixel幅 × "
- + rect.height
- + " pixel高";
+ // 寸法
+ String form = "最大文字寸法\u0020:\u0020"
+ + "{0}\u0020pixel幅"
+ + "\u0020×\u0020"
+ + "{1}\u0020pixel高";
+ Rectangle rect = this.fontInfo.getMaxCharBounds();
+ String boundInfo =
+ MessageFormat.format(form, rect.width, rect.height);
this.maxBounds.setText(boundInfo);
+ // プレビュー
+ this.preview.setFontInfo(this.fontInfo);
+
this.maskListener = false;
return;
/**
* {@inheritDoc}
- * ダイアログの表示・非表示。
- * ダイアログが閉じられるまで制御を返さない。
* @param isVisible trueなら表示 {@inheritDoc}
*/
@Override
public void setVisible(boolean isVisible){
if(isVisible){
updateControlls();
- updatePreview();
}
this.lastFontInfo = this.fontInfo;
/**
* {@inheritDoc}
- * ã\83\81ã\82§ã\83\83ã\82¯ã\83\9cã\83\83ã\82¯ã\82¹操作のリスナ。
+ * ã\83\95ã\82©ã\83³ã\83\88ã\83\95ã\82¡ã\83\9fã\83ªã\83ªã\82¹ã\83\88é\81¸æ\8a\9e操作のリスナ。
* @param event 操作イベント {@inheritDoc}
*/
@Override
- public void itemStateChanged(ItemEvent event){
+ public void valueChanged(ListSelectionEvent event){
if(this.maskListener) return;
- Object source = event.getSource();
+ if(event.getSource() != this.familySelector) return;
+ if(event.getValueIsAdjusting()) return;
- if( source != this.isBoldCheck
- && source != this.isItalicCheck
- && source != this.useTextAntiAliaseCheck
- && source != this.useFractionalCheck ){
- return;
- }
+ String familyName = this.familySelector.getSelectedFamily();
+ if(familyName == null) return;
- int style = 0 | Font.PLAIN;
- if(this.isBoldCheck.isSelected()){
- style = style | Font.BOLD;
- }
- if(this.isItalicCheck.isSelected()){
- style = style | Font.ITALIC;
- }
- Font newFont = getSelectedFont();
- if(newFont.getStyle() != style){
- newFont = newFont.deriveFont(style);
- }
+ Font currentFont = getFontInfo().getFont();
+ int style = currentFont.getStyle();
+ int size = currentFont.getSize();
- AffineTransform tx = getFontRenderContext().getTransform();
- boolean isAntiAliases = this.useTextAntiAliaseCheck.isSelected();
- boolean useFractional = this.useFractionalCheck .isSelected();
- FontRenderContext newContext =
- new FontRenderContext(tx, isAntiAliases, useFractional);
+ Font newFont = new Font(familyName, style, size);
+ FontInfo newInfo = this.fontInfo.deriveFont(newFont);
- FontInfo newInfo = new FontInfo(newFont, newContext);
setFontInfo(newInfo);
return;
}
/**
+ * {@inheritDoc}
+ * ボタン操作及びフォントサイズ指定コンボボックス操作のリスナ。
+ * @param event 操作イベント {@inheritDoc}
+ */
+ @Override
+ public void actionPerformed(ActionEvent event){
+ if(this.maskListener) return;
+
+ Object source = event.getSource();
+
+ if(source == this.sizeSelector){
+ actionFontSizeSelected();
+ }else if(source == this.resetDefault){
+ setFontInfo(FontInfo.DEFAULT_FONTINFO);
+ }
+
+ return;
+ }
+
+ /**
* フォントサイズ変更処理。
*/
private void actionFontSizeSelected(){
try{
selectedInteger = Integer.valueOf(selected.toString());
}catch(NumberFormatException e){
- selectedInteger = Integer.valueOf(
- this.lastFontInfo.getFont().getSize()
- );
+ selectedInteger = this.lastFontInfo.getFont().getSize();
}
}
- if(selectedInteger.intValue() <= 0){
- selectedInteger =
- Integer.valueOf(this.lastFontInfo.getFont().getSize());
+ if(selectedInteger <= 0){
+ selectedInteger = this.lastFontInfo.getFont().getSize();
}
float fontSize = selectedInteger.floatValue();
- Font newFont = getSelectedFont().deriveFont(fontSize);
- FontInfo newInfo = this.fontInfo.deriveFont(newFont);
- setFontInfo(newInfo);
+ Font newFont = getFontInfo().getFont().deriveFont(fontSize);
+ FontInfo newInfo = getFontInfo().deriveFont(newFont);
- int sizeItems = this.sizeSelector.getItemCount();
- for(int index = 0; index <= sizeItems - 1; index++){
- Object sizeItem = this.sizeSelector.getItemAt(index);
- if(sizeItem.equals(selectedInteger)){
- this.sizeSelector.setSelectedIndex(index);
- break;
- }
- }
-
- updateControlls();
- updatePreview();
+ setFontInfo(newInfo);
return;
}
/**
* {@inheritDoc}
- * ã\83\9cã\82¿ã\83³æ\93\8dä½\9cå\8f\8aã\81³ã\83\95ã\82©ã\83³ã\83\88ã\82µã\82¤ã\82ºæ\8c\87å®\9aã\82³ã\83³ã\83\9cボックス操作のリスナ。
+ * ã\83\81ã\82§ã\83\83ã\82¯ボックス操作のリスナ。
* @param event 操作イベント {@inheritDoc}
*/
@Override
- public void actionPerformed(ActionEvent event){
+ public void itemStateChanged(ItemEvent event){
if(this.maskListener) return;
- String cmd = event.getActionCommand();
- if(cmd.equals(ActionManager.CMD_FONTSIZESEL)){
- actionFontSizeSelected();
- }
-
Object source = event.getSource();
- if(source == this.resetDefault){
- setFontInfo(FontInfo.DEFAULT_FONTINFO);
- }
-
- return;
- }
-
- /**
- * {@inheritDoc}
- * フォントファミリリスト選択操作のリスナ。
- * @param event 操作イベント {@inheritDoc}
- */
- @Override
- public void valueChanged(ListSelectionEvent event){
- if(this.maskListener) return;
-
- if(event.getSource() != this.familySelector) return;
- if(event.getValueIsAdjusting()) return;
-
- Object selected = this.familySelector.getSelectedValue();
- if(selected == null) return;
-
- String familyName = selected.toString();
- Font currentFont = getSelectedFont();
- int style = currentFont.getStyle();
- int size = currentFont.getSize();
-
- Font newFont = new Font(familyName, style, size);
- FontInfo newInfo = this.fontInfo.deriveFont(newFont);
-
- setFontInfo(newInfo);
-
- return;
- }
-
- /**
- * フォントプレビュー画面用コンポーネント。
- */
- private static class FontPreview extends JComponent{
-
- private static final int MARGIN = 5;
-
- private final GlyphDraw draw;
-
- private FontInfo fontInfo;
-
- /**
- * コンストラクタ。
- * @param source 文字列
- * @param fontInfo フォント設定
- */
- public FontPreview(CharSequence source,
- FontInfo fontInfo ){
- super();
-
- this.fontInfo = fontInfo;
- this.draw = new GlyphDraw(source, this.fontInfo);
- this.draw.setFontInfo(this.fontInfo);
-
- this.draw.setPos(MARGIN, MARGIN);
-
- this.draw.setColor(Color.BLACK);
- setBackground(Color.WHITE);
-
- updateBounds();
+ if( source != this.isBoldCheck
+ && source != this.isItalicCheck
+ && source != this.useTextAntiAliaseCheck
+ && source != this.useFractionalCheck ){
return;
}
- /**
- * サイズ更新。
- */
- private void updateBounds(){
- Rectangle bounds = this.draw.setWidth(Integer.MAX_VALUE);
- Dimension dimension = new Dimension(bounds.width + MARGIN * 2,
- bounds.height + MARGIN * 2 );
- setPreferredSize(dimension);
- revalidate();
- repaint();
- return;
- }
+ FontInfo newInfo = getFontInfo();
- /**
- * フォント設定の変更。
- * @param newFontInfo フォント設定
- */
- public void setFontInfo(FontInfo newFontInfo){
- this.fontInfo = newFontInfo;
- this.draw.setFontInfo(this.fontInfo);
+ int style = 0 | Font.PLAIN;
+ if(this.isBoldCheck.isSelected()){
+ style = style | Font.BOLD;
+ }
+ if(this.isItalicCheck.isSelected()){
+ style = style | Font.ITALIC;
+ }
+ Font newFont = newInfo.getFont();
+ if(newFont.getStyle() != style){
+ newFont = newFont.deriveFont(style);
+ newInfo = newInfo.deriveFont(newFont);
+ }
- updateBounds();
+ boolean isAntiAliases = this.useTextAntiAliaseCheck.isSelected();
+ boolean useFractional = this.useFractionalCheck .isSelected();
+ newInfo = newInfo.deriveRenderContext(isAntiAliases, useFractional);
- return;
- }
+ setFontInfo(newInfo);
- /**
- * {@inheritDoc}
- * 文字列の描画。
- * @param g {@inheritDoc}
- */
- @Override
- public void paintComponent(Graphics g){
- super.paintComponent(g);
- Graphics2D g2d = (Graphics2D) g;
- this.draw.paint(g2d);
- return;
- }
+ return;
}
}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Font;
+import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
import java.text.CharacterIterator;
import jp.sourceforge.jovsonz.JsBoolean;
import jp.sourceforge.jovsonz.JsNumber;
/** デフォルトのフォント設定。 */
public static final FontInfo DEFAULT_FONTINFO = new FontInfo();
- private static final String HASH_FAMILY = "family";
- private static final String HASH_SIZE = "size";
- private static final String HASH_ISBOLD = "isBold";
- private static final String HASH_ISITALIC = "isItalic";
- private static final String HASH_USEAA = "useAntiAlias";
+ private static final String HASH_FAMILY = "family";
+ private static final String HASH_SIZE = "size";
+ private static final String HASH_ISBOLD = "isBold";
+ private static final String HASH_ISITALIC = "isItalic";
+ private static final String HASH_USEAA = "useAntiAlias";
private static final String HASH_FRACTIONAL = "useFractional";
- private Font font;
- private FontRenderContext context;
+ private final Font font;
+ private final FontRenderContext context;
/**
/**
* フォントに応じた最適な描画設定を生成する。
+ * <p>ビットマップフォントと推測されるときは
+ * アンチエイリアスやサブピクセル補完を無効にする。
* @param font フォント
* @return 描画設定
+ * @see FontUtils#guessBitmapFont(Font)
*/
public static FontRenderContext createBestContext(Font font){
- FontRenderContext result;
-
- AffineTransform identity = ImtblAffineTx.IDENTITY;
+ boolean isAntiAliased = true;
+ boolean usesFractionalMetrics = true;
if(FontUtils.guessBitmapFont(font)){
- result = new FontRenderContext(identity, false, false);
- }else{
- result = new FontRenderContext(identity, true, true);
+ isAntiAliased = false;
+ usesFractionalMetrics = false;
}
+ AffineTransform identity = ImtblAffineTx.IDENTITY;
+ FontRenderContext result =
+ new FontRenderContext(identity,
+ isAntiAliased,
+ usesFractionalMetrics);
+
return result;
}
* @return JSON Object
*/
public static JsObject buildJson(FontInfo fontInfo){
- Font font = fontInfo.getFont();
+ Font font = fontInfo.getFont();
FontRenderContext frc = fontInfo.getFontRenderContext();
- JsPair type = new JsPair(HASH_FAMILY,
- FontUtils.getRootFamilyName(font) );
- JsPair size = new JsPair(HASH_SIZE, font.getSize());
- JsPair bold = new JsPair(HASH_ISBOLD, font.isBold());
+
+ JsPair family = new JsPair(HASH_FAMILY,
+ FontUtils.getRootFamilyName(font) );
+ JsPair size = new JsPair(HASH_SIZE, font.getSize());
+ JsPair bold = new JsPair(HASH_ISBOLD, font.isBold());
JsPair italic = new JsPair(HASH_ISITALIC, font.isItalic());
- JsPair host = new JsPair(HASH_USEAA, frc.isAntiAliased());
- JsPair port =
- new JsPair(HASH_FRACTIONAL, frc.usesFractionalMetrics());
+ JsPair aa = new JsPair(HASH_USEAA, frc.isAntiAliased());
+ JsPair frac = new JsPair(HASH_FRACTIONAL,
+ frc.usesFractionalMetrics() );
JsObject result = new JsObject();
- result.putPair(type);
+ result.putPair(family);
result.putPair(size);
result.putPair(bold);
result.putPair(italic);
- result.putPair(host);
- result.putPair(port);
+ result.putPair(aa);
+ result.putPair(frac);
return result;
}
/**
- * JSONã\81\8bã\82\89ã\81®ã\83\95ã\82©ã\83³ã\83\88è¨å®\9a復元。
+ * JSONã\81\8bã\82\89ã\83\95ã\82©ã\83³ã\83\88ã\82\92復元。
* @param obj JSON Object
- * @return フォント設定
+ * @return フォント
*/
- public static FontInfo decodeJson(JsObject obj){
+ private static Font decodeJsonFont(JsObject obj){
JsValue value;
- Font newFont = FontUtils.createDefaultSpeechFont();
- FontRenderContext newFrc = createBestContext(newFont);
- int style = newFont.getStyle();
-
+ Font font = null;
value = obj.getValue(HASH_FAMILY);
if(value instanceof JsString){
JsString string = (JsString) value;
Font decoded = Font.decode(string.toRawString());
if(decoded != null){
- newFont = decoded;
+ font = decoded;
}
}
-
- int size = newFont.getSize();
- value = obj.getValue(HASH_SIZE);
- if(value instanceof JsNumber){
- JsNumber number = (JsNumber) value;
- size = number.intValue();
+ if(font == null){
+ font = FontUtils.createDefaultSpeechFont();
}
- boolean isBold = newFont.isBold();
+ boolean isBold = false;
+ boolean isItalic = false;
+
value = obj.getValue(HASH_ISBOLD);
if(value instanceof JsBoolean){
JsBoolean bool = (JsBoolean) value;
isBold = bool.booleanValue();
}
- if(isBold) style |= Font.BOLD;
- boolean isItalic = newFont.isItalic();
value = obj.getValue(HASH_ISITALIC);
if(value instanceof JsBoolean){
JsBoolean bool = (JsBoolean) value;
isItalic = bool.booleanValue();
}
+
+ int style = Font.PLAIN;
+ if(isBold) style |= Font.BOLD;
if(isItalic) style |= Font.ITALIC;
- boolean isAntiAlias = newFrc.isAntiAliased();
+ int size = FontUtils.DEF_SIZE;
+ value = obj.getValue(HASH_SIZE);
+ if(value instanceof JsNumber){
+ JsNumber number = (JsNumber) value;
+ size = number.intValue();
+ }
+
+ Font derivedFont = font.deriveFont(style, (float)size);
+
+ return derivedFont;
+ }
+
+ /**
+ * JSONからフォント描画設定を復元。
+ * @param obj JSON Object
+ * @param font デフォルトフォント
+ * @return フォント描画設定
+ */
+ private static FontRenderContext decodeJsonFrc(JsObject obj,
+ Font font ){
+ FontRenderContext defFrc = createBestContext(font);
+ boolean isAntiAlias = defFrc.isAntiAliased();
+ boolean useFractional = defFrc.usesFractionalMetrics();
+
+ JsValue value;
+
value = obj.getValue(HASH_USEAA);
if(value instanceof JsBoolean){
JsBoolean bool = (JsBoolean) value;
isAntiAlias = bool.booleanValue();
}
- boolean useFractional = newFrc.usesFractionalMetrics();
value = obj.getValue(HASH_FRACTIONAL);
if(value instanceof JsBoolean){
JsBoolean bool = (JsBoolean) value;
useFractional = bool.booleanValue();
}
- newFont = newFont.deriveFont(style, (float)size);
+ FontRenderContext newFrc =
+ new FontRenderContext(ImtblAffineTx.IDENTITY,
+ isAntiAlias, useFractional );
- newFrc = new FontRenderContext(ImtblAffineTx.IDENTITY,
- isAntiAlias, useFractional);
+ return newFrc;
+ }
- FontInfo result = new FontInfo(newFont, newFrc);
+ /**
+ * JSONからのフォント設定復元。
+ * @param obj JSON Object
+ * @return フォント設定
+ */
+ public static FontInfo decodeJson(JsObject obj){
+ Font font = decodeJsonFont(obj);
+ FontRenderContext frc = decodeJsonFrc(obj, font);
+
+ FontInfo result = new FontInfo(font, frc);
return result;
}
}
/**
+ * アンチエイリアス機能を使うか判定する。
+ * @return アンチエイリアス機能を使うならtrue
+ */
+ public boolean isAntiAliased(){
+ boolean result = this.context.isAntiAliased();
+ return result;
+ }
+
+ /**
+ * サブピクセル精度を使うか判定する。
+ * @return サブピクセル精度を使うならtrue
+ */
+ public boolean usesFractionalMetrics(){
+ boolean result = this.context.usesFractionalMetrics();
+ return result;
+ }
+
+ /**
+ * フォントの最大寸法を返す。
+ * @return 最大寸法
+ * @see java.awt.Font#getMaxCharBounds(FontRenderContext)
+ */
+ public Rectangle getMaxCharBounds(){
+ Rectangle2D r2d = this.font.getMaxCharBounds(this.context);
+ Rectangle rect = r2d.getBounds();
+ return rect;
+ }
+
+ /**
* フォントのみ異なる設定を派生させる。
* @param newFont 新フォント
* @return 新設定
}
/**
+ * 描画属性のみ異なる設定を派生させる。
+ * @param isAntiAliases アンチエイリアス設定
+ * @param useFractional サブピクセル精度設定
+ * @return 新設定
+ */
+ public FontInfo deriveRenderContext(boolean isAntiAliases,
+ boolean useFractional){
+ AffineTransform tx = this.context.getTransform();
+ FontRenderContext newContext =
+ new FontRenderContext(tx, isAntiAliases, useFractional);
+ return deriveRenderContext(newContext);
+ }
+
+ /**
* 文字列からグリフ集合を生成する。
* @param iterator 文字列
* @return グリフ集合
--- /dev/null
+/*
+ * font list model
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf.glyph;
+
+import java.awt.EventQueue;
+import java.util.LinkedList;
+import java.util.List;
+import javax.swing.AbstractListModel;
+
+/**
+ * フォントファミリ名一覧表示用リストのデータモデル。
+ * <p>環境によってはフォントリストを完成させるのに
+ * 数千msかかる場合があるので、その対策として非同期に一覧を読み込む。
+ * <p>実際のリスト作成は裏で走るタスクにより行われ、
+ * リスト完成の暁にはEDTによりリスナに通知される。
+ * 一般的なリストモデルと同様、
+ * 基本的にスレッド間競合の問題はEDTで解決すること。
+ */
+@SuppressWarnings("serial")
+public class FontListModel extends AbstractListModel {
+
+ private final List<String> familyList = new LinkedList<String>();
+
+ private volatile boolean hasDone = false;
+
+ /**
+ * コンストラクタ。
+ * <p>コンストラクタ完了と同時にリスト生成タスクが裏で走り始める。
+ */
+ public FontListModel(){
+ super();
+
+ Runnable task = createFillTask();
+ startTask(task);
+
+ return;
+ }
+
+ /**
+ * フォントリスト埋めタスクを生成する。
+ * @return タスク
+ */
+ private Runnable createFillTask(){
+ Runnable task = new Runnable(){
+ /** {@inheritDoc} */
+ @Override
+ @SuppressWarnings("CallToThreadYield")
+ public void run(){
+ Thread.yield();
+ fillModel();
+ }
+ };
+
+ return task;
+ }
+
+ /**
+ * フォントファミリ名リストを設定する。
+ * @param familyNames フォントファミリ名のリスト
+ * @return リストの要素数
+ */
+ private int fillList(List<String> familyNames){
+ this.familyList.addAll(familyNames);
+ this.hasDone = true;
+ int size = this.familyList.size();
+ return size;
+ }
+
+ /**
+ * フォントリストを収集しモデルに反映させる。
+ */
+ private void fillModel(){
+ final List<String> fontList = FontUtils.createFontList();
+
+ // スレッド間競合を避けるため、ここより先の処理はEDT任せ。
+ EventQueue.invokeLater(new Runnable(){
+ /** {@inheritDoc} */
+ @Override
+ public void run(){
+ int size = fillList(fontList);
+ if(size <= 0) return;
+
+ int begin = 0;
+ int end = size - 1;
+ fireContentsChanged(this, begin, end);
+
+ return;
+ }
+ });
+
+ return;
+ }
+
+ /**
+ * フォントリスト埋めタスクを起動する。
+ * @param task タスク
+ */
+ private void startTask(Runnable task){
+ Thread thread = new Thread(task);
+ thread.start();
+ return;
+ }
+
+ /**
+ * モデルが完成済みか否か判定する。
+ * @return モデルが完成していればtrue
+ */
+ public boolean hasCompleted(){
+ return this.hasDone;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @param index {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @Override
+ public Object getElementAt(int index){
+ Object result = this.familyList.get(index);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @Override
+ public int getSize(){
+ int result = this.familyList.size();
+ return result;
+ }
+
+}
--- /dev/null
+/*
+ * font previewer
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf.glyph;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import javax.swing.JComponent;
+
+/**
+ * フォントプレビュー用コンポーネント。
+ * <p>発言表示部と同じビジュアルを再現する必要のため、GlyphDrawで描画する。
+ */
+@SuppressWarnings("serial")
+public class FontPreviewer extends JComponent {
+
+ private static final int MARGIN = 5;
+
+ private final GlyphDraw draw;
+ private FontInfo fontInfo;
+
+
+ /**
+ * コンストラクタ。
+ * @param source 文字列
+ * @param fontInfo フォント設定
+ */
+ public FontPreviewer(CharSequence source,
+ FontInfo fontInfo ){
+ super();
+
+ this.fontInfo = fontInfo;
+ this.draw = new GlyphDraw(source, this.fontInfo);
+ this.draw.setFontInfo(this.fontInfo);
+
+ this.draw.setPos(MARGIN, MARGIN);
+
+ this.draw.setColor(Color.BLACK);
+ setBackground(Color.WHITE);
+
+ updateBounds();
+
+ return;
+ }
+
+ /**
+ * サイズ更新。
+ */
+ private void updateBounds(){
+ Rectangle bounds = this.draw.setWidth(Integer.MAX_VALUE);
+ Dimension dimension = new Dimension(bounds.width + MARGIN * 2,
+ bounds.height + MARGIN * 2 );
+
+ setPreferredSize(dimension);
+ revalidate();
+ repaint();
+
+ return;
+ }
+
+ /**
+ * フォント設定の変更。
+ * @param newFontInfo フォント設定
+ */
+ public void setFontInfo(FontInfo newFontInfo){
+ this.fontInfo = newFontInfo;
+ this.draw.setFontInfo(this.fontInfo);
+
+ updateBounds();
+
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * 文字列の描画。
+ * @param g {@inheritDoc}
+ */
+ @Override
+ public void paintComponent(Graphics g){
+ super.paintComponent(g);
+ Graphics2D g2d = (Graphics2D) g;
+ this.draw.paint(g2d);
+ return;
+ }
+
+}
--- /dev/null
+/*
+ * font select list
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf.glyph;
+
+import javax.swing.JList;
+import javax.swing.ListModel;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+
+/**
+ * フォント選択リスト。
+ * <p>フォント一覧の遅延読み込みに対応。
+ */
+@SuppressWarnings("serial")
+public class FontSelectList extends JList
+ implements ListDataListener {
+
+ private String selectedFamily = null;
+
+
+ /**
+ * コンストラクタ。
+ */
+ public FontSelectList(){
+ super();
+
+ ListModel fontListModel = new FontListModel();
+ setModelImpl(fontListModel);
+ setVisibleRowCount(-1);
+ setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+ return;
+ }
+
+ /**
+ * {@link setModel(ListModel)} の下請けメソッド。
+ * 与えられたモデルの更新は監視対象となる。
+ * @param model リストモデル
+ */
+ private void setModelImpl(ListModel model){
+ ListModel oldModel = getModel();
+ if(oldModel != null){
+ oldModel.removeListDataListener(this);
+ }
+
+ model.addListDataListener(this);
+
+ super.setModel(model);
+
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * 与えられたモデルの更新は監視対象となる。
+ * @param model {@inheritDoc}
+ */
+ @Override
+ public void setModel(ListModel model){
+ setModelImpl(model);
+ return;
+ }
+
+ /**
+ * 指定したフォントファミリ名が選択された状態にする。
+ * @param family フォントファミリ名
+ */
+ public void setSelectedFamily(String family){
+ this.selectedFamily = family;
+ reSelectFamily();
+ return;
+ }
+
+ /**
+ * 選択されたファミリ名を返す。
+ * @return 選択されたファミリ名。何も選択されていなければnull
+ */
+ public String getSelectedFamily(){
+ Object selected = getSelectedValue();
+ if(selected == null) return null;
+ String result = selected.toString();
+ return result;
+ }
+
+ /**
+ * 過去に指示された選択ファミリを用いて再選択操作を試みる。
+ */
+ private void reSelectFamily(){
+ boolean shouldScroll = true;
+ setSelectedValue(this.selectedFamily, shouldScroll);
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * データモデル変更に伴い再選択処理を行う。
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void contentsChanged(ListDataEvent event){
+ reSelectFamily();
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * データモデル変更に伴い再選択処理を行う。
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void intervalAdded(ListDataEvent event){
+ reSelectFamily();
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * データモデル変更に伴い再選択処理を行う。
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void intervalRemoved(ListDataEvent event){
+ reSelectFamily();
+ return;
+ }
+
+}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
-import java.util.SortedSet;
-import java.util.TreeSet;
+import java.util.Set;
/**
* フォントユーティリティ。
/** Font.DIALOG代替品。 */
public static final String FAMILY_DIALOG = "Dialog";
- /** Locale.ROOT代替品。 */
- private static final Locale ROOT = new Locale("", "", "");
+ /** デフォルトのポイントサイズ。 */
+ public static final int DEF_SIZE = 16;
+
+ // Locale.ROOT代替品。@see Locale#ROOT
+ private static final Locale LOCALE_ROOT = new Locale("", "", "");
+
+ private static final int MS_BMP_LIMIT = 24;
private static final String[] INIT_FAMILY_NAMES = {
"Hiragino Kaku Gothic Pro", // for MacOS X
"Osaka",
"MS PGothic", // for WinXP
"MS Gothic",
+ "IPAMonaPGothic",
// TODO X11用のおすすめは?
};
/** JIS0208:1990 チェック用。 */
- private static final String JPCHECK_CODE = "9Aあゑアアヴヰ┼ЖΩ峠凜熙";
+ private static final String JPCHECK_CODE = "あ凜熙峠ゑアアヴヰ┼ЖΩ9A";
+
+ /** 二重引用符。 */
+ private static final char DQ = '"';
/**
/**
* システムに存在する有効なファミリ名か判定する。
- * @param family フォントファミリ名。
+ * @param familyName フォントファミリ名。
* @return 存在する有効なファミリ名ならtrue
*/
- public static boolean isValidFamilyName(String family){
+ public static boolean isValidFamilyName(String familyName){
int style = 0x00 | Font.PLAIN;
int size = 1;
- Font dummyFont = new Font(family, style, size);
+ Font dummyFont = new Font(familyName, style, size);
- String dummyFamily = getRootFamilyName(dummyFont);
- String dummyLocalFamily = dummyFont.getFamily();
- if(dummyFamily .equals(family)) return true;
- if(dummyLocalFamily.equals(family)) return true;
+ String dummyFamilyName = getRootFamilyName(dummyFont);
+ String dummyLocalFamilyName = dummyFont.getFamily();
+ if(dummyFamilyName .equals(familyName)) return true;
+ if(dummyLocalFamilyName.equals(familyName)) return true;
return false;
}
}
int style = 0x00 | Font.PLAIN;
- int size = 16;
+ int size = DEF_SIZE;
Font result = new Font(defaultFamilyName, style, size);
return result;
/**
* ソートされたフォントファミリ一覧表を生成する。
- * JISX0208:1990相当が表示できないファミリは弾かれる。
- * 結構実行時間がかかるかも。乱用禁物。
+ * <p>JISX0208:1990相当が表示できないファミリは弾かれる。
+ * <p>結構実行時間がかかるかも(数千ms)。乱用禁物。
* @return フォント一覧
*/
- public static SortedSet<String> createFontSet(){
+ public static List<String> createFontList(){
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
+ Font[] allFonts = ge.getAllFonts();
- SortedSet<String> result = new TreeSet<String>();
- for(Font font : ge.getAllFonts()){
- if(font.canDisplayUpTo(JPCHECK_CODE) >= 0) continue;
+ Set<String> checked = new HashSet<String>();
+ for(Font font : allFonts){
String familyName = font.getFamily();
- result.add(familyName.intern());
+ if(checked.contains(familyName)) continue;
+ if(font.canDisplayUpTo(JPCHECK_CODE) >= 0) continue;
+ checked.add(familyName);
}
+ List<String> result = new ArrayList<String>(checked);
+ Collections.sort(result);
- return Collections.unmodifiableSortedSet(result);
+ return result;
}
/**
*/
public static boolean guessBitmapFont(Font font){
String familyName = getRootFamilyName(font);
- if( font.getSize() < 24
+ if( font.getSize() < MS_BMP_LIMIT
&& familyName.startsWith("MS")
&& ( familyName.contains("Gothic")
|| familyName.contains("Mincho") ) ){
/**
* Font#decode()用の名前を返す。
+ * 空白が含まれる場合は二重引用符で囲まれる。
* @param font フォント
* @return Font#decode()用の名前
+ * @see Font#decode(String)
*/
public static String getFontDecodeName(Font font){
StringBuilder result = new StringBuilder();
+ String familyName = getRootFamilyName(font);
+
StringBuilder style = new StringBuilder();
- if(font.isBold()) style.append("BOLD");
- if(font.isItalic()) style.append("ITALIC");
+ if(font.isBold()) style.append("BOLD");
+ if(font.isItalic()) style.append("ITALIC");
if(style.length() <= 0) style.append("PLAIN");
- result.append(getRootFamilyName(font));
- result.append('-').append(style);
- result.append('-').append(font.getSize());
+ int fontSize = font.getSize();
+
+ result.append(familyName)
+ .append('-').append(style)
+ .append('-').append(fontSize);
if( result.indexOf("\u0020") >= 0
|| result.indexOf("\u3000") >= 0 ){
- result.insert(0, '"').append('"');
+ result.insert(0, DQ).append(DQ);
}
return result.toString();
* JRE1.5対策
* @param font フォント
* @return ファミリ名
+ * @see Font#getFamily(Locale)
*/
public static String getRootFamilyName(Font font){
- return font.getFamily(ROOT);
+ return font.getFamily(LOCALE_ROOT);
}
}
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Color;
import java.awt.FontMetrics;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.SwingConstants;
+import jp.sfjp.jindolf.data.Anchor;
+import jp.sfjp.jindolf.util.GUIUtils;
/**
* 複数行の文字列を矩形内に描画する。
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.geom.AffineTransform;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Point;
import java.io.IOException;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.text.CharacterIterator;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
+import jp.sfjp.jindolf.data.DialogPref;
+import jp.sfjp.jindolf.data.SysEvent;
import jp.sourceforge.jindolf.parser.DecodedContent;
/**
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Color;
import java.awt.Font;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
+import jp.sfjp.jindolf.data.Anchor;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.DialogPref;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.util.GUIUtils;
import jp.sourceforge.jindolf.corelib.TalkType;
/**
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.glyph;
import java.awt.Graphics2D;
import java.awt.Rectangle;
--- /dev/null
+/*
+ * パッケージ情報
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+/**
+ * 独自の文字列描画処理関連の一連のクラス。
+ */
+
+package jp.sfjp.jindolf.glyph;
+
+/* EOF */
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.log;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
-import java.util.logging.Formatter;
import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.SimpleFormatter;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.border.Border;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
+import jp.sfjp.jindolf.dxchg.TextPopup;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sfjp.jindolf.util.Monodizer;
/**
* ログ表示パネル。
*/
@SuppressWarnings("serial")
public class LogFrame extends JDialog
- implements WindowListener, ActionListener{
+ implements WindowListener, ActionListener, DocumentListener{
- private static final String FRAMETITLE = "ログ表示 - " + Jindolf.TITLE;
- private static final int DOCLIMIT = 100 * 1000; // 単位は文字
- private static final float CHOPRATIO = 0.9f;
- private static final int CHOPPEDLEN = (int)(DOCLIMIT * CHOPRATIO);
private static final Document DOC_EMPTY = new PlainDocument();
- static{
- assert DOCLIMIT > CHOPPEDLEN;
- }
-
- /**
- * ログハンドラ。
- */
- private class SwingLogger extends Handler{
-
- /**
- * ログハンドラの生成。
- */
- public SwingLogger(){
- super();
- Formatter formatter = new SimpleFormatter();
- setFormatter(formatter);
- return;
- }
-
- /**
- * {@inheritDoc}
- * @param record {@inheritDoc}
- */
- @Override
- public void publish(LogRecord record){
- if( ! isLoggable(record) ){
- return;
- }
- Formatter formatter = getFormatter();
- String message = formatter.format(record);
- try{
- LogFrame.this.document
- .insertString(LogFrame.this.document.getLength(),
- message,
- null );
- }catch(BadLocationException e){
- // IGNORE
- }
-
- int docLength = LogFrame.this.document.getLength();
- if(docLength > DOCLIMIT){
- int offset = docLength - CHOPPEDLEN;
- try{
- LogFrame.this.document.remove(0, offset);
- }catch(BadLocationException e){
- // IGNORE
- }
- }
-
- showLastPos();
-
- return;
- }
-
- /**
- * {@inheritDoc}
- * (何もしない)。
- */
- @Override
- public void flush(){
- return;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void close(){
- setLevel(Level.OFF);
- flush();
- return;
- }
- };
private final JTextArea textarea;
private final Document document = new PlainDocument();
* @param owner フレームオーナー
*/
public LogFrame(Frame owner){
- super(owner, FRAMETITLE, false);
+ super(owner);
+ setModal(false);
- if(Jindolf.hasLoggingPermission()){
- this.handler = new SwingLogger();
+ if(LogUtils.hasLoggingPermission()){
+ this.handler = new SwingDocHandler(this.document);
}else{
this.handler = null;
}
this.clearButton.addActionListener(this);
this.closeButton.addActionListener(this);
+ this.document.addDocumentListener(this);
+
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(this);
return;
}
+ /**
+ * {@inheritDoc}
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void changedUpdate(DocumentEvent event){
+ showLastPos();
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void insertUpdate(DocumentEvent event){
+ showLastPos();
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void removeUpdate(DocumentEvent event){
+ showLastPos();
+ return;
+ }
+
}
--- /dev/null
+/*
+ * logging common
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+package jp.sfjp.jindolf.log;
+
+import java.util.List;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Handler;
+import java.util.logging.Logger;
+import java.util.logging.LoggingPermission;
+
+/**
+ * ロギングの各種ユーティリティ。
+ */
+public final class LogUtils {
+
+ /** ログ管理用パーミッション。 */
+ public static final LoggingPermission PERM_LOGCTL =
+ new LoggingPermission("control", null);
+
+ /**
+ * 隠しコンストラクタ。
+ */
+ private LogUtils(){
+ super();
+ return;
+ }
+
+ /**
+ * ログ操作のアクセス権があるか否か判定する。
+ * @return アクセス権があればtrue
+ */
+ public static boolean hasLoggingPermission(){
+ SecurityManager manager = System.getSecurityManager();
+ boolean result = hasLoggingPermission(manager);
+ return result;
+ }
+
+ /**
+ * ログ操作のアクセス権があるか否か判定する。
+ * @param manager セキュリティマネージャ
+ * @return アクセス権があればtrue
+ */
+ public static boolean hasLoggingPermission(SecurityManager manager){
+ if(manager == null) return true;
+
+ try{
+ manager.checkPermission(PERM_LOGCTL);
+ }catch(SecurityException e){
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * ルートロガーの初期化を行う。
+ * ルートロガーの既存ハンドラを全解除し、
+ * {@link PileHandler}ハンドラを登録する。
+ * @param useConsoleLog trueなら
+ * {@link java.util.logging.ConsoleHandler}も追加する。
+ */
+ public static void initRootLogger(boolean useConsoleLog){
+ if( ! hasLoggingPermission() ){
+ System.err.println(
+ "セキュリティ設定により、"
+ + "ログ設定を変更できませんでした" );
+ return;
+ }
+
+ Logger rootLogger = Logger.getLogger("");
+
+ for(Handler handler : rootLogger.getHandlers()){
+ rootLogger.removeHandler(handler);
+ }
+
+ Handler pileHandler = new PileHandler();
+ rootLogger.addHandler(pileHandler);
+
+ if(useConsoleLog){
+ Handler consoleHandler = new ConsoleHandler();
+ rootLogger.addHandler(consoleHandler);
+ }
+
+ return;
+ }
+
+ /**
+ * ロガーに新ハンドラを追加する。
+ * ロガー中の全{@link PileHandler}型ハンドラに蓄積されていたログは、
+ * 新ハンドラに一気に転送される。
+ * {@link PileHandler}型ハンドラはロガーから削除される。
+ * ログ操作のパーミッションがない場合、何もしない。
+ * @param logger ロガー
+ * @param newHandler 新ハンドラ
+ */
+ public static void switchHandler(Logger logger, Handler newHandler){
+ if( ! hasLoggingPermission() ) return;
+
+ List<PileHandler> pileHandlers = PileHandler.getPileHandlers(logger);
+ PileHandler.removePileHandlers(logger);
+
+ logger.addHandler(newHandler);
+
+ for(PileHandler pileHandler : pileHandlers){
+ pileHandler.delegate(newHandler);
+ pileHandler.close();
+ }
+
+ return;
+ }
+
+}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.log;
import java.util.logging.Level;
import java.util.logging.LogRecord;
}
/**
+ * コンストラクタ。
+ * 新規生成された匿名ロガーを囲う。
+ */
+ public LogWrapper(){
+ this(Logger.getAnonymousLogger());
+ return;
+ }
+
+ /**
* ラップ対象のjava.util.loggingロガーを取得する。
* @return ラップ対象のjava.util.loggingロガー
*/
--- /dev/null
+/*
+ * event dispatcher with logging
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+package jp.sfjp.jindolf.log;
+
+import java.awt.AWTEvent;
+import java.awt.EventQueue;
+import java.awt.Toolkit;
+
+/**
+ * 異常系をロギングするイベントディスパッチャ。
+ */
+public class LoggingDispatcher extends EventQueue{
+
+ private static final String FATALMSG =
+ "イベントディスパッチ中に異常が起きました。";
+
+ private static final LogWrapper LOGGER = new LogWrapper();
+
+ /**
+ * コンストラクタ。
+ */
+ public LoggingDispatcher(){
+ super();
+ return;
+ }
+
+ /**
+ * 独自ロガーにエラーや例外を吐く、
+ * カスタム化されたイベントキューに差し替える。
+ */
+ public static void replaceEventQueue(){
+ Toolkit kit = Toolkit.getDefaultToolkit();
+ EventQueue oldQueue = kit.getSystemEventQueue();
+ EventQueue newQueue = new LoggingDispatcher();
+ oldQueue.push(newQueue);
+ return;
+ }
+
+ /**
+ * 異常系をログ出力。
+ * @param e 例外
+ */
+ private void errlog(Throwable e){
+ LOGGER.fatal(FATALMSG, e);
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * 発生した例外をログ出力する。
+ * @param event {@inheritDoc}
+ */
+ @Override
+ protected void dispatchEvent(AWTEvent event){
+ try{
+ super.dispatchEvent(event);
+ }catch(RuntimeException e){
+ errlog(e);
+ throw e;
+ }catch(Exception e){
+ errlog(e);
+ }catch(Error e){
+ errlog(e);
+ throw e;
+ }
+ // TODO Toolkit#beep()もするべきか
+ // TODO モーダルダイアログを出すべきか
+ // TODO 標準エラー出力抑止オプションを用意すべきか
+ // TODO セキュリティバイパス
+ return;
+ }
+
+}
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.log;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
+import java.util.logging.Logger;
/**
* なにもしないロギングハンドラ。
public class PileHandler extends Handler{
private final List<LogRecord> logList = new LinkedList<LogRecord>();
+ private final List<LogRecord> unmodList =
+ Collections.unmodifiableList(this.logList);
/**
* ロギングハンドラを生成する。
}
/**
+ * ロガーに含まれる{@link PileHandler}型ハンドラのリストを返す。
+ * @param logger ロガー
+ * @return {@link PileHandler}型ハンドラのリスト
+ */
+ public static List<PileHandler> getPileHandlers(Logger logger){
+ List<PileHandler> result = new LinkedList<PileHandler>();
+
+ for(Handler handler : logger.getHandlers()){
+ if( ! (handler instanceof PileHandler) ) continue;
+ PileHandler pileHandler = (PileHandler) handler;
+ result.add(pileHandler);
+ }
+
+ return result;
+ }
+
+ /**
+ * ロガーに含まれる{@link PileHandler}型ハンドラを全て削除する。
+ * @param logger ロガー
+ */
+ public static void removePileHandlers(Logger logger){
+ for(PileHandler pileHandler : getPileHandlers(logger)){
+ logger.removeHandler(pileHandler);
+ }
+ return;
+ }
+
+ /**
+ * 蓄積されたログレコードのリストを返す。
+ * 古いログが先頭に来る。
+ * @return ログレコードのリスト。変更不可。
+ */
+ public List<LogRecord> getRecordList(){
+ return this.unmodList;
+ }
+
+ /**
* {@inheritDoc}
* ログを内部に溜め込む。
* @param record {@inheritDoc}
*/
@Override
public void publish(LogRecord record){
+ if(record == null) return;
+
if( ! isLoggable(record) ){
return;
}
+
this.logList.add(record);
+
return;
}
/**
* 他のハンドラへ蓄積したログをまとめて出力する。
+ * 最後に自分自身をクローズし、蓄積されたログを解放する。
* @param handler 他のハンドラ
*/
public void delegate(Handler handler){
--- /dev/null
+/*
+ * Logging handler for Swing text component
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+package jp.sfjp.jindolf.log;
+
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.SimpleFormatter;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+/**
+ * Swingテキストコンポーネント用データモデル{@link javax.swing.text.Document}
+ * に出力する{@link java.util.logging.Handler}。
+ */
+public class SwingDocHandler extends Handler{
+
+ private static final int DOCLIMIT = 100 * 1000; // 単位は文字
+ private static final float CHOPRATIO = 0.9f;
+ private static final int CHOPPEDLEN = (int)(DOCLIMIT * CHOPRATIO);
+
+ static{
+ assert DOCLIMIT > CHOPPEDLEN;
+ }
+
+
+ private final Document document;
+
+ /**
+ * ログハンドラの生成。
+ * @param document ドキュメントモデル
+ */
+ public SwingDocHandler(Document document){
+ super();
+
+ this.document = document;
+
+ Formatter formatter = new SimpleFormatter();
+ setFormatter(formatter);
+
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @param record {@inheritDoc}
+ */
+ @Override
+ public void publish(LogRecord record){
+ if( ! isLoggable(record) ){
+ return;
+ }
+ Formatter formatter = getFormatter();
+ String message = formatter.format(record);
+ try{
+ this.document.insertString(this.document.getLength(),
+ message,
+ null );
+ }catch(BadLocationException e){
+ assert false;
+ }
+
+ int docLength = this.document.getLength();
+ if(docLength > DOCLIMIT){
+ int offset = docLength - CHOPPEDLEN;
+ try{
+ this.document.remove(0, offset);
+ }catch(BadLocationException e){
+ assert false;
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * (何もしない)。
+ */
+ @Override
+ public void flush(){
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close(){
+ setLevel(Level.OFF);
+ flush();
+ return;
+ }
+
+}
--- /dev/null
+/*
+ * パッケージ情報
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+/**
+ * ロギング関連の一連のクラス。
+ */
+
+package jp.sfjp.jindolf.log;
+
+/* EOF */
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.net;
import java.net.HttpURLConnection;
import java.net.URI;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.net;
import java.net.URL;
import jp.sourceforge.jindolf.parser.DecodedContent;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.net;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.text.NumberFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import jp.sfjp.jindolf.VerInfo;
+import jp.sfjp.jindolf.config.EnvInfo;
/**
* HTTP関連のユーティリティ群。
*/
public static String getUserAgentName(){
StringBuilder result = new StringBuilder();
- result.append(Jindolf.TITLE).append("/").append(Jindolf.VERSION);
+ result.append(VerInfo.TITLE).append("/").append(VerInfo.VERSION);
StringBuilder rawComment = new StringBuilder();
if(EnvInfo.OS_NAME != null){
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.net;
import java.awt.Component;
import java.awt.Container;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.border.Border;
+import jp.sfjp.jindolf.dxchg.TextPopup;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sfjp.jindolf.util.Monodizer;
/**
* プロクシサーバ選択画面。
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.net;
import java.net.InetSocketAddress;
import java.net.Proxy;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.net;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.log.LogWrapper;
import jp.sourceforge.jindolf.parser.ContentBuilder;
import jp.sourceforge.jindolf.parser.ContentBuilderSJ;
import jp.sourceforge.jindolf.parser.ContentBuilderUCS2;
private static final
Map<String, SoftReference<BufferedImage>> IMAGE_CACHE;
+ private static final LogWrapper LOGGER = new LogWrapper();
+
static{
Map<String, SoftReference<BufferedImage>> cache =
new HashMap<String, SoftReference<BufferedImage>>();
if(responseCode != HttpURLConnection.HTTP_OK){ // 200
String logMessage = "発言のダウンロードに失敗しました。";
logMessage += HttpUtils.formatHttpStat(connection, 0, 0);
- Jindolf.logger().warn(logMessage);
+ LOGGER.warn(logMessage);
return null;
}
if(responseCode != HttpURLConnection.HTTP_OK){
String logMessage = "イメージのダウンロードに失敗しました。";
logMessage += HttpUtils.formatHttpStat(connection, 0, 0);
- Jindolf.logger().warn(logMessage);
+ LOGGER.warn(logMessage);
return null;
}
int responseCode = connection.getResponseCode();
if(responseCode != HttpURLConnection.HTTP_MOVED_TEMP){ // 302
String logMessage = "認証情報の送信に失敗しました。";
- Jindolf.logger().warn(logMessage);
+ LOGGER.warn(logMessage);
connection.disconnect();
return false;
}
setAuthentication(loginCookie);
- Jindolf.logger().info("正しく認証が行われました。");
+ LOGGER.info("正しく認証が行われました。");
return true;
}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.net;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
+import jp.sfjp.jindolf.log.LogWrapper;
/**
* 読み込みバイト数を記録するHTTPコネクション由来のInputStream。
private static final int BUFSIZE = 2 * 1024;
+ private static final LogWrapper LOGGER = new LogWrapper();
+
private final HttpURLConnection conn;
private final InputStream in;
long span = System.nanoTime() - this.nanoLap;
String message = HttpUtils.formatHttpStat(this.conn, size, span);
- Jindolf.logger().info(message);
+ LOGGER.info(message);
this.hasClosed = true;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.net;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
+import jp.sfjp.jindolf.log.LogWrapper;
/**
* 書き込みバイト数をログ出力するHTTPコネクション由来のOutputStream。
private static final int BUFSIZE = 512;
+ private static final LogWrapper LOGGER = new LogWrapper();
+
private final HttpURLConnection conn;
private final OutputStream out;
long span = System.nanoTime() - this.nanoLap;
String message = HttpUtils.formatHttpStat(this.conn, size, span);
- Jindolf.logger().info(message);
+ LOGGER.info(message);
return;
}
--- /dev/null
+/*
+ * パッケージ情報
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+/**
+ * ネットワーク通信関連の一連のクラス。
+ */
+
+package jp.sfjp.jindolf.net;
+
+/* EOF */
/*
- * Jindolf パッケージコメント
- *
- * このファイルは、SunJDK5.0以降に含まれるJavadoc用に用意された、
- * 特別な名前を持つソースファイルです。
- * このファイルはソースコードを含まず、
- * パッケージコメントとパッケージ宣言のみが含まれます。
+ * パッケージ情報
*
* License : The MIT License
- * Copyright(c) 2008 olyutorskii
+ * Copyright(c) 2011 olyutorskii
*/
/**
* Jindolf開発プロジェクト</a>
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf;
/* EOF */
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.summary;
import java.awt.Color;
import java.awt.Component;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Topic;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.glyph.TalkDraw;
+import jp.sfjp.jindolf.util.GUIUtils;
import jp.sourceforge.jindolf.corelib.TalkType;
/**
public class DaySummary extends JDialog
implements WindowListener, ActionListener, ItemListener{
- private static final String FRAMETITLE =
- "発言集計 - " + Jindolf.TITLE;
private static final NumberFormat AVERAGE_FORM;
private static final String PUBTALK = "白発言";
private static final String WOLFTALK = "赤発言";
* @param owner オーナー
*/
public DaySummary(Frame owner){
- super(owner, FRAMETITLE, true);
+ super(owner);
+ setModal(true);
GUIUtils.modifyWindowAttributes(this, true, false, true);
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.summary;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import jp.sfjp.jindolf.VerInfo;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Player;
+import jp.sfjp.jindolf.data.SysEvent;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Topic;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.dxchg.FaceIconSet;
+import jp.sfjp.jindolf.dxchg.WolfBBS;
import jp.sourceforge.jindolf.corelib.Destiny;
import jp.sourceforge.jindolf.corelib.GameRole;
import jp.sourceforge.jindolf.corelib.SysEventType;
public static final Comparator<Player> COMPARATOR_CASTING =
new CastingComparator();
+ private static final String GENERATOR =
+ VerInfo.TITLE + "\u0020Ver." + VerInfo.VERSION;
+
private final Map<Avatar, Player> playerMap =
new HashMap<Avatar, Player>();
StringBuilder wikiText = new StringBuilder();
String vName = this.village.getVillageFullName();
- String generator = Jindolf.TITLE + " Ver." + Jindolf.VERSION;
String author = iconSet.getAuthor() + "氏"
+" [ "+iconSet.getUrlText()+" ]";
wikiText.append(WolfBBS.COMMENTLINE);
wikiText.append("// ↓キャスト表開始\n");
- wikiText.append("// Village : " + vName + "\n");
- wikiText.append("// Generator : " + generator + "\n");
- wikiText.append("// アイコン作者 : " + author + '\n');
- wikiText.append("// ※アイコン画像の著作財産権保持者"
- +"および画像サーバ運営者から\n");
- wikiText.append("// 新しい意向が示された場合、"
- +"そちらを最優先で尊重してください。\n");
+ wikiText.append("// Village : ")
+ .append(vName)
+ .append('\n');
+ wikiText.append("// Generator : ")
+ .append(GENERATOR)
+ .append('\n');
+ wikiText.append("// アイコン作者 : ")
+ .append(author)
+ .append('\n');
+ wikiText.append("// ※アイコン画像の著作財産権保持者")
+ .append("および画像サーバ運営者から\n");
+ wikiText.append("// 新しい意向が示された場合、")
+ .append("そちらを最優先で尊重してください。\n");
wikiText.append(WolfBBS.COMMENTLINE);
wikiText.append("|配役")
// PukiWikiではURL内の&のエスケープは不要?
wikiText.append("// ========== ");
- wikiText.append(name + " acts as [" + avatar.getName() + "]");
+ wikiText.append(name)
+ .append(" acts as [")
+ .append(avatar.getName())
+ .append("]");
wikiText.append(" ==========\n");
String teamColor = "BGCOLOR("
wikiText.append("RIGHT:");
wikiText.append("顔アイコン提供 : [[");
wikiText.append(WolfBBS.escapeWikiBracket(iconSet.getAuthor()));
- wikiText.append(">" + iconSet.getUrlText());
+ wikiText.append(">")
+ .append(iconSet.getUrlText());
wikiText.append("]]氏");
wikiText.append("|\n");
DateFormat.FULL);
String vName = this.village.getVillageFullName();
- String generator = Jindolf.TITLE + " Ver." + Jindolf.VERSION;
wikiText.append(WolfBBS.COMMENTLINE);
wikiText.append("// ↓村詳細開始\n");
- wikiText.append("// Village : " + vName + "\n");
- wikiText.append("// Generator : " + generator + "\n");
+ wikiText.append("// Village : ")
+ .append(vName)
+ .append('\n');
+ wikiText.append("// Generator : ")
+ .append(GENERATOR)
+ .append('\n');
wikiText.append("* 村の詳細\n");
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.summary;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.JTextArea;
import javax.swing.JViewport;
import javax.swing.border.Border;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Player;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.dxchg.ClipboardAction;
+import jp.sfjp.jindolf.dxchg.FaceIconSet;
+import jp.sfjp.jindolf.dxchg.TextPopup;
+import jp.sfjp.jindolf.dxchg.WebButton;
+import jp.sfjp.jindolf.dxchg.WolfBBS;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sfjp.jindolf.util.Monodizer;
import jp.sourceforge.jindolf.corelib.GameRole;
import jp.sourceforge.jindolf.corelib.Team;
implements ActionListener,
ItemListener {
- private static final String FRAMETITLE =
- "村のダイジェスト - " + Jindolf.TITLE;
private static final String ITEMDELIM = " : ";
* @param owner 親フレーム
*/
public VillageDigest(Frame owner){
- super(owner, FRAMETITLE, true);
+ super(owner);
+ setModal(true);
GUIUtils.modifyWindowAttributes(this, true, false, true);
--- /dev/null
+/*
+ * パッケージ情報
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 olyutorskii
+ */
+
+/**
+ * プレイ状況のサマライズ処理関連の一連のクラス。
+ */
+
+package jp.sfjp.jindolf.summary;
+
+/* EOF */
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.util;
-import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Dialog;
-import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorConvertOp;
-import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
-import java.net.URL;
-import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.Icon;
-import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
+import jp.sfjp.jindolf.ResourceManager;
+import jp.sfjp.jindolf.log.LogWrapper;
/**
* GUI関連のユーティリティクラス。
public void run(){}
};
+ private static final LogWrapper LOGGER = new LogWrapper();
+
static{
HINTS_QUALITY = new RenderingHints(null);
HINTS_SPEEDY = new RenderingHints(null);
}
/**
- * リソース名からイメージを取得する。
- * @param resource リソース名
- * @return イメージ
- * @throws java.io.IOException 入力エラー
- */
- public static BufferedImage loadImageFromResource(String resource)
- throws IOException{
- BufferedImage result;
-
- URL url = Jindolf.getResource(resource);
- result = ImageIO.read(url);
-
- return result;
- }
-
- /**
* ロゴイメージを得る。
* @return ロゴイメージ
*/
return logoImage;
}
- BufferedImage image;
- try{
- image = loadImageFromResource(RES_LOGOICON);
- }catch(IOException e){
- Jindolf.logger().warn("ロゴイメージの取得に失敗しました", e);
+ BufferedImage image =
+ ResourceManager.getBufferedImage(RES_LOGOICON);
+ if(image == null){
+ LOGGER.warn("ロゴイメージの取得に失敗しました");
image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
// TODO デカく "狼" とでも描くか?
}
return windowIconImage;
}
- BufferedImage image;
- try{
- image = loadImageFromResource(RES_WINDOWICON);
- }catch(IOException e){
- Jindolf.logger().warn("アイコンイメージの取得に失敗しました", e);
+ BufferedImage image =
+ ResourceManager.getBufferedImage(RES_WINDOWICON);
+ if(image == null){
+ LOGGER.warn("アイコンイメージの取得に失敗しました");
image = getLogoImage();
}
return logoIcon;
}
- Icon icon = new ImageIcon(getLogoImage());
-
+ Icon icon = ResourceManager.getImageIcon(RES_LOGOICON);
logoIcon = icon;
return logoIcon;
return wwwIcon;
}
- URL url = Jindolf.getResource(RES_WWWICON);
- wwwIcon = new ImageIcon(url);
+ wwwIcon = ResourceManager.getImageIcon(RES_WWWICON);
return wwwIcon;
}
return noImage;
}
- URL url = Jindolf.getResource(RES_NOIMAGE);
- try{
- noImage = ImageIO.read(url);
- }catch(IOException e){
+ noImage = ResourceManager.getBufferedImage(RES_NOIMAGE);
+ if(noImage == null){
assert false;
noImage = getLogoImage();
}
}
/**
- * 独自ロガーにエラーや例外を吐く、
- * カスタム化されたイベントキューに差し替える。
- */
- public static void replaceEventQueue(){
- Toolkit kit = Toolkit.getDefaultToolkit();
- EventQueue oldQueue = kit.getSystemEventQueue();
- EventQueue newQueue = new EventQueue(){
- private static final String FATALMSG =
- "イベントディスパッチ中に異常が起きました。";
- @Override
- protected void dispatchEvent(AWTEvent event){
- try{
- super.dispatchEvent(event);
- }catch(RuntimeException e){
- Jindolf.logger().fatal(FATALMSG, e);
- throw e;
- }catch(Exception e){
- Jindolf.logger().fatal(FATALMSG, e);
- }catch(Error e){
- Jindolf.logger().fatal(FATALMSG, e);
- throw e;
- }
- // TODO Toolkit#beep()もするべきか
- // TODO モーダルダイアログを出すべきか
- // TODO 標準エラー出力抑止オプションを用意すべきか
- // TODO セキュリティバイパス
- return;
- }
- };
- oldQueue.push(newQueue);
- return;
- }
-
- /**
* 任意のイメージを多階調モノクロ化する。
* 寸法は変わらない。
* @param image イメージ
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.util;
import java.awt.Component;
import java.awt.Font;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.util;
import java.util.regex.Matcher;
--- /dev/null
+/*
+ * パッケージ情報
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+/**
+ * 各種ユーティリティクラス。
+ */
+
+package jp.sfjp.jindolf.util;
+
+/* EOF */
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.Border;
+import jp.sfjp.jindolf.VerInfo;
+import jp.sfjp.jindolf.data.Land;
+import jp.sfjp.jindolf.data.LandsModel;
+import jp.sfjp.jindolf.dxchg.TextPopup;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.net.ServerAccess;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sfjp.jindolf.util.Monodizer;
import jp.sourceforge.jindolf.corelib.LandState;
/**
extends JDialog
implements ActionListener, ItemListener{
- private static final String FRAMETITLE =
- "アカウント管理 - " + Jindolf.TITLE;
+ private static final LogWrapper LOGGER = new LogWrapper();
+
private final Map<Land, String> landUserIDMap =
new HashMap<Land, String>();
* @param landsModel 国モデル
* @throws java.lang.NullPointerException 引数がnull
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public AccountPanel(Frame owner, LandsModel landsModel)
throws NullPointerException{
- super(owner, FRAMETITLE, true);
+ super(owner);
+ setModal(true);
if(landsModel == null) throw new NullPointerException();
for(Land land : landsModel.getLandList()){
* @param e ネットワークエラー
*/
protected void showNetworkError(IOException e){
- Jindolf.logger().warn(
+ LOGGER.warn(
"アカウント処理中にネットワークのトラブルが発生しました", e);
Land land = getSelectedLand();
JOptionPane.WARNING_MESSAGE,
JOptionPane.DEFAULT_OPTION );
- JDialog dialog = pane.createDialog(this,
- "通信異常発生 - " + Jindolf.TITLE);
+ String title = VerInfo.getFrameTitle("通信異常発生");
+ JDialog dialog = pane.createDialog(this, title);
dialog.pack();
dialog.setVisible(true);
JOptionPane.WARNING_MESSAGE,
JOptionPane.DEFAULT_OPTION );
- JDialog dialog =
- pane.createDialog(this, "ログイン認証失敗 - " + Jindolf.TITLE);
+ String title = VerInfo.getFrameTitle("ログイン認証失敗");
+ JDialog dialog = pane.createDialog(this, title);
dialog.pack();
dialog.setVisible(true);
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
-import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.Icon;
-import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
+import jp.sfjp.jindolf.ResourceManager;
+import jp.sfjp.jindolf.VerInfo;
+import jp.sfjp.jindolf.util.GUIUtils;
/**
* メニュー、ボタン、その他各種Actionを伴うイベントを生成する
KeyStroke.getKeyStroke("ctrl F");
static{
- URL iconurl;
+ ICON_FIND =
+ ResourceManager.getImageIcon("resources/image/tb_find.png");
- iconurl = Jindolf.getResource("resources/image/find.png");
- ICON_FIND = new ImageIcon(iconurl);
+ ICON_SEARCH_PREV =
+ ResourceManager.getImageIcon("resources/image/tb_findprev.png");
- iconurl = Jindolf.getResource("resources/image/findprev.png");
- ICON_SEARCH_PREV = new ImageIcon(iconurl);
+ ICON_SEARCH_NEXT =
+ ResourceManager.getImageIcon("resources/image/tb_findnext.png");
- iconurl = Jindolf.getResource("resources/image/findnext.png");
- ICON_SEARCH_NEXT = new ImageIcon(iconurl);
+ ICON_RELOAD =
+ ResourceManager.getImageIcon("resources/image/tb_reload.png");
- iconurl = Jindolf.getResource("resources/image/reload.png");
- ICON_RELOAD = new ImageIcon(iconurl);
+ ICON_FILTER =
+ ResourceManager.getImageIcon("resources/image/tb_filter.png");
- iconurl = Jindolf.getResource("resources/image/filter.png");
- ICON_FILTER = new ImageIcon(iconurl);
-
- iconurl = Jindolf.getResource("resources/image/editor.png");
- ICON_EDITOR = new ImageIcon(iconurl);
+ ICON_EDITOR =
+ ResourceManager.getImageIcon("resources/image/tb_editor.png");
}
private final Set<AbstractButton> actionItems =
buildMenuItem(CMD_SHOWLOG, "ログ表示", KeyEvent.VK_S);
buildMenuItem(CMD_HELPDOC, "ヘルプ表示", KeyEvent.VK_H);
buildMenuItem(CMD_SHOWPORTAL, "ポータルサイト...", KeyEvent.VK_P);
- buildMenuItem(CMD_ABOUT, Jindolf.TITLE + "について...", KeyEvent.VK_A);
+ buildMenuItem(CMD_ABOUT, VerInfo.TITLE + "について...", KeyEvent.VK_A);
buildToolButton(CMD_RELOAD, "選択中の日を強制リロード", ICON_RELOAD);
buildToolButton(CMD_SHOWFIND, "検索", ICON_FIND);
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.Container;
import java.awt.GridBagConstraints;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.Border;
+import jp.sfjp.jindolf.data.DialogPref;
/**
* 発言表示の各種設定パネル。
/**
* コンストラクタ。
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public DialogPrefPanel(){
this.resetDefault.addActionListener(this);
this.isSimpleMode.addItemListener(this);
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.Container;
import java.awt.Frame;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.SysEvent;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Topic;
+import jp.sfjp.jindolf.util.GUIUtils;
import jp.sourceforge.jindolf.corelib.EventFamily;
import jp.sourceforge.jindolf.corelib.TalkType;
private static final int COLS = 4;
- private static final String FRAMETITLE = "発言フィルタ - " + Jindolf.TITLE;
private final JCheckBox checkPublic = new JCheckBox("公開", true);
private final JCheckBox checkWolf = new JCheckBox("狼", true);
* 発言フィルタを生成する。
* @param owner フレームオーナー
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public FilterPanel(Frame owner){
- super(owner, FRAMETITLE, false);
+ super(owner);
+ setModal(false);
GUIUtils.modifyWindowAttributes(this, true, false, true);
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.text.JTextComponent;
+import jp.sfjp.jindolf.data.RegexPattern;
+import jp.sfjp.jindolf.dxchg.TextPopup;
+import jp.sfjp.jindolf.util.GUIUtils;
import jp.sourceforge.jovsonz.JsArray;
+import jp.sourceforge.jovsonz.JsComposition;
import jp.sourceforge.jovsonz.JsObject;
+import jp.sourceforge.jovsonz.JsTypes;
import jp.sourceforge.jovsonz.JsValue;
/**
ChangeListener,
PropertyChangeListener {
- private static final String HIST_FILE = "searchHistory.json";
- private static final String FRAMETITLE = "発言検索 - " + Jindolf.TITLE;
+ /** 検索履歴ファイル。 */
+ public static final File HIST_FILE = new File("searchHistory.json");
+
private static final String LABEL_REENTER = "再入力";
private static final String LABEL_IGNORE = "無視して検索をキャンセル";
* 検索パネルを生成する。
* @param owner 親フレーム。
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public FindPanel(Frame owner){
- super(owner, FRAMETITLE, true);
+ super(owner);
+ setModal(true);
GUIUtils.modifyWindowAttributes(this, true, false, true);
}
/**
- * 検索履歴をロードする。
+ * JSON形式の検索履歴情報を返す。
+ * @return JSON形式の検索履歴情報
*/
- public void loadHistory(){
- JsValue value = ConfigFile.loadJson(new File(HIST_FILE));
- if(value == null) return;
+ public JsObject getJson(){
+ JsObject result = new JsObject();
+
+ JsArray array = new JsArray();
+ result.putValue("history", array);
- if( ! (value instanceof JsObject) ) return;
- JsObject root = (JsObject) value;
+ List<RegexPattern> history = this.model.getOriginalHistoryList();
+ history = new ArrayList<RegexPattern>(history);
+ Collections.reverse(history);
+ for(RegexPattern regex : history){
+ JsObject obj = RegexPattern.encodeJson(regex);
+ array.add(obj);
+ }
+
+ return result;
+ }
+
+ /**
+ * JSON形式の検索履歴を反映させる。
+ * @param root JSON形式の検索履歴。nullが来たら何もしない
+ */
+ public void putJson(JsObject root){
+ if(root == null) return;
- value = root.getValue("history");
- if( ! (value instanceof JsArray) ) return;
+ JsValue value = root.getValue("history");
+ if(value.getJsTypes() != JsTypes.ARRAY) return;
JsArray array = (JsArray) value;
for(JsValue elem : array){
- if( ! (elem instanceof JsObject) ) continue;
+ if(elem.getJsTypes() != JsTypes.OBJECT) continue;
JsObject regObj = (JsObject) elem;
RegexPattern regex = RegexPattern.decodeJson(regObj);
if(regex == null) continue;
}
/**
- * 検索履歴をセーブする。
+ * 起動時の履歴設定と等価か判定する。
+ * @param conf 比較対象
+ * @return 等価ならtrue
*/
- public void saveHistory(){
- AppSetting setting = Jindolf.getAppSetting();
- if( ! setting.useConfigPath() ) return;
- File configPath = setting.getConfigPath();
- if(configPath == null) return;
-
- JsObject root = new JsObject();
- JsArray array = new JsArray();
- root.putValue("history", array);
-
- List<RegexPattern> history = this.model.getOriginalHistoryList();
- history = new ArrayList<RegexPattern>(history);
- Collections.reverse(history);
- for(RegexPattern regex : history){
- JsObject obj = RegexPattern.encodeJson(regex);
- array.add(obj);
- }
-
+ public boolean hasConfChanged(JsComposition<?> conf){
if(this.loadedHistory != null){
- if(this.loadedHistory.equals(root)) return;
+ if(this.loadedHistory.equals(conf)) return true;
}
-
- ConfigFile.saveJson(new File(HIST_FILE), root);
-
- return;
+ return false;
}
/**
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.Container;
import java.awt.GridBagConstraints;
import javax.swing.border.Border;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
+import jp.sfjp.jindolf.ResourceManager;
+import jp.sfjp.jindolf.config.ConfigStore;
+import jp.sfjp.jindolf.config.EnvInfo;
+import jp.sfjp.jindolf.config.OptionInfo;
+import jp.sfjp.jindolf.dxchg.TextPopup;
+import jp.sfjp.jindolf.log.LogWrapper;
+import jp.sfjp.jindolf.util.GUIUtils;
/**
* ヘルプ画面。
private static final String HELP_HTML = "resources/html/help.html";
+ private static final LogWrapper LOGGER = new LogWrapper();
+
+
private final JTabbedPane tabPanel = new JTabbedPane();
private final JEditorPane htmlView = new JEditorPane();
private final JTextArea vmInfo = new JTextArea();
/**
* コンストラクタ。
+ * @param optinfo コマンドラインオプション
+ * @param configStore 設定ディレクトリ情報
*/
- public HelpFrame(){
- super(Jindolf.TITLE + " ヘルプ");
+ @SuppressWarnings("LeakingThisInConstructor")
+ public HelpFrame(OptionInfo optinfo, ConfigStore configStore){
+ super();
GUIUtils.modifyWindowAttributes(this, true, false, true);
}
});
- URL topUrl = Jindolf.getResource(HELP_HTML);
+ URL topUrl = ResourceManager.getResource(HELP_HTML);
loadURL(topUrl);
StringBuilder info = new StringBuilder();
+
+ info.append("起動時引数:\n");
+ for(String arg : optinfo.getInvokeArgList()){
+ info.append("\u0020\u0020").append(arg).append('\n');
+ }
+ info.append('\n');
+
info.append(EnvInfo.getVMInfo());
- AppSetting setting = Jindolf.getAppSetting();
- if(setting.useConfigPath()){
- info.append("設定格納ディレクトリ : "
- + setting.getConfigPath().getPath() );
+
+ if(configStore.useStoreFile()){
+ info.append("設定格納ディレクトリ : ")
+ .append(configStore.getConfigPath().getPath());
}else{
info.append("※ 設定格納ディレクトリは使っていません。");
}
try{
this.htmlView.setPage(url);
}catch(IOException e){
- Jindolf.logger().warn("ヘルプファイルが読み込めません", e);
+ LOGGER.warn("ヘルプファイルが読み込めません", e);
assert false;
}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
+import jp.sfjp.jindolf.data.Land;
+import jp.sfjp.jindolf.dxchg.WebButton;
+import jp.sfjp.jindolf.util.Monodizer;
import jp.sourceforge.jindolf.corelib.LandDef;
import jp.sourceforge.jindolf.corelib.LandState;
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.net.URL;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
+import jp.sfjp.jindolf.ResourceManager;
+import jp.sfjp.jindolf.data.Land;
+import jp.sfjp.jindolf.data.LandsModel;
/**
* 国一覧Tree周辺コンポーネント群。
private static final ImageIcon ICON_DESCEND;
static{
- URL url;
- url = Jindolf.getResource("resources/image/ascend.png");
- ICON_ASCEND = new ImageIcon(url);
- url = Jindolf.getResource("resources/image/descend.png");
- ICON_DESCEND = new ImageIcon(url);
+ ICON_ASCEND =
+ ResourceManager.getImageIcon("resources/image/tb_ascend.png");
+ ICON_DESCEND =
+ ResourceManager.getImageIcon("resources/image/tb_descend.png");
}
private final JButton orderButton = new JButton();
/**
* コンストラクタ。
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public LandsTree(){
super();
this.orderButton.setActionCommand(ActionManager.CMD_SWITCHORDER);
this.orderButton.addActionListener(this);
- URL url;
- url = Jindolf.getResource("resources/image/reload.png");
- this.reloadButton.setIcon(new ImageIcon(url));
+ ImageIcon icon =
+ ResourceManager.getImageIcon("resources/image/tb_reload.png");
+ this.reloadButton.setIcon(icon);
this.reloadButton.setToolTipText(TIP_ORDER);
this.reloadButton.setMargin(new Insets(1, 1, 1, 1));
this.reloadButton.setActionCommand(ActionManager.CMD_VILLAGELIST);
--- /dev/null
+/*
+ * lock file warning dialog
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf.view;
+
+import java.awt.Component;
+import java.awt.HeadlessException;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButton;
+import jp.sfjp.jindolf.config.FileUtils;
+import jp.sfjp.jindolf.config.InterVMLock;
+
+/**
+ * ロックエラー用ダイアログ。
+ * <ul>
+ * <li>強制解除
+ * <li>リトライ
+ * <li>設定ディレクトリを無視
+ * <li>起動中止
+ * </ul>
+ * の選択を利用者に求める。
+ */
+@SuppressWarnings("serial")
+public class LockErrorPane extends JOptionPane implements ActionListener{
+
+ private final InterVMLock lock;
+
+ private final JRadioButton continueButton =
+ new JRadioButton("設定ディレクトリを使わずに起動を続行");
+ private final JRadioButton retryButton =
+ new JRadioButton("再度ロック取得を試す");
+ private final JRadioButton forceButton =
+ new JRadioButton(
+ "<html>"
+ + "ロックを強制解除<br>"
+ + " (※他のJindolfと設定ファイル書き込みが衝突するかも…)"
+ + "</html>");
+
+ private final JButton okButton = new JButton("OK");
+ private final JButton abortButton = new JButton("起動中止");
+
+ private boolean aborted = false;
+
+ /**
+ * コンストラクタ。
+ * @param lock 失敗したロック
+ */
+ @SuppressWarnings("LeakingThisInConstructor")
+ public LockErrorPane(InterVMLock lock){
+ super();
+
+ this.lock = lock;
+
+ String htmlMessage =
+ "<html>"
+ + "設定ディレクトリのロックファイル<br>"
+ + "<center>[ "
+ + FileUtils.getHtmledFileName(this.lock.getLockFile())
+ + " ]</center>"
+ + "<br>"
+ + "のロックに失敗しました。<br>"
+ + "考えられる原因としては、<br>"
+ + "<ul>"
+ + "<li>前回起動したJindolfの終了が正しく行われなかった"
+ + "<li>今どこかで他のJindolfが動いている"
+ + "</ul>"
+ + "などが考えられます。<br>"
+ + "<hr>"
+ + "</html>";
+
+ ButtonGroup bgrp = new ButtonGroup();
+ bgrp.add(this.continueButton);
+ bgrp.add(this.retryButton);
+ bgrp.add(this.forceButton);
+ this.continueButton.setSelected(true);
+
+ Object[] msg = {
+ htmlMessage,
+ this.continueButton,
+ this.retryButton,
+ this.forceButton,
+ };
+ setMessage(msg);
+
+ Object[] opts = {
+ this.okButton,
+ this.abortButton,
+ };
+ setOptions(opts);
+
+ setMessageType(JOptionPane.ERROR_MESSAGE);
+
+ this.okButton .addActionListener(this);
+ this.abortButton.addActionListener(this);
+
+ return;
+ }
+
+ /**
+ * 「設定ディレクトリを無視して続行」が選択されたか判定する。
+ * @return 「無視して続行」が選択されていればtrue
+ */
+ public boolean isRadioContinue(){
+ return this.continueButton.isSelected();
+ }
+
+ /**
+ * 「リトライ」が選択されたか判定する。
+ * @return 「リトライ」が選択されていればtrue
+ */
+ public boolean isRadioRetry(){
+ return this.retryButton.isSelected();
+ }
+
+ /**
+ * 「強制解除」が選択されたか判定する。
+ * @return 「強制解除」が選択されていればtrue
+ */
+ public boolean isRadioForce(){
+ return this.forceButton.isSelected();
+ }
+
+ /**
+ * 「起動中止」が選択されたか判定する。
+ * @return 「起動中止」が押されていたならtrue
+ */
+ public boolean isAborted(){
+ return this.aborted;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @param parentComponent {@inheritDoc}
+ * @param title {@inheritDoc}
+ * @return {@inheritDoc}
+ * @throws HeadlessException {@inheritDoc}
+ */
+ @Override
+ public JDialog createDialog(Component parentComponent,
+ String title)
+ throws HeadlessException{
+ final JDialog dialog =
+ super.createDialog(parentComponent, title);
+
+ ActionListener listener = new ActionListener(){
+ public void actionPerformed(ActionEvent event){
+ dialog.setVisible(false);
+ return;
+ }
+ };
+
+ this.okButton .addActionListener(listener);
+ this.abortButton.addActionListener(listener);
+
+ return dialog;
+ }
+
+ /**
+ * ボタン押下を受信する。
+ * @param event イベント
+ */
+ public void actionPerformed(ActionEvent event){
+ Object source = event.getSource();
+ if(source == this.okButton) this.aborted = false;
+ else this.aborted = true;
+ return;
+ }
+
+}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.Container;
import java.awt.Frame;
import javax.swing.JDialog;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
+import jp.sfjp.jindolf.glyph.FontChooser;
+import jp.sfjp.jindolf.glyph.FontInfo;
+import jp.sfjp.jindolf.net.ProxyChooser;
+import jp.sfjp.jindolf.util.GUIUtils;
/**
* オプション設定パネル。
extends JDialog
implements ActionListener, WindowListener{
- private static final String FRAMETITLE =
- "オプション設定 - " + Jindolf.TITLE;
-
private final JTabbedPane tabPane = new JTabbedPane();
private final FontChooser fontChooser;
* コンストラクタ。
* @param owner フレームオーナ
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public OptionPanel(Frame owner){
- super(owner, FRAMETITLE, true);
+ super(owner);
+ setModal(true);
GUIUtils.modifyWindowAttributes(this, true, false, true);
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JViewport;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.Border;
+import jp.sfjp.jindolf.data.DialogPref;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Talk;
+import jp.sfjp.jindolf.data.Topic;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.glyph.Discussion;
+import jp.sfjp.jindolf.glyph.FontInfo;
+import jp.sfjp.jindolf.glyph.TalkDraw;
import jp.sourceforge.jindolf.corelib.TalkType;
/**
* 発言ブラウザを内包するPeriodビューワを生成する。
* @param period 日
*/
+ @SuppressWarnings("LeakingThisInConstructor")
public PeriodView(Period period){
super();
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.Component;
import java.awt.event.ActionListener;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.event.EventListenerList;
+import jp.sfjp.jindolf.data.DialogPref;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.glyph.AnchorHitListener;
+import jp.sfjp.jindolf.glyph.Discussion;
+import jp.sfjp.jindolf.glyph.FontInfo;
/**
* タブを用いて村情報と各Periodを閲覧するためのコンポーネント。
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
+import jp.sfjp.jindolf.VerInfo;
+import jp.sfjp.jindolf.data.Land;
+import jp.sfjp.jindolf.data.Village;
+import jp.sfjp.jindolf.util.GUIUtils;
/**
* 最上位ビュー。
private static final String LANDCARD = "LANDINFO";
private static final String BROWSECARD = "BROWSER";
+ private static final String MSG_THANKS =
+ VerInfo.TITLE + "\u0020" + VerInfo.VERSION
+ + "\u0020を使ってくれてありがとう!";
+
+
private final JComponent cards;
private final CardLayout cardLayout = new CardLayout();
* @return ステータスバー
*/
private JComponent createStatusBar(){
- this.sysMessage.setText(
- Jindolf.TITLE + " " + Jindolf.VERSION
- + " を使ってくれてありがとう!" );
+ this.sysMessage.setText(MSG_THANKS);
this.sysMessage.setEditable(false);
Border inside = BorderFactory.createBevelBorder(BevelBorder.LOWERED);
Border outside = BorderFactory.createEmptyBorder(2, 5, 2, 2);
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
+
+import jp.sfjp.jindolf.data.Topic;
/**
* 発言Topicのフィルタリングを行うインタフェース。
public interface TopicFilter {
/**
- * フィルタの状態を表すインタフェース。
- */
- interface FilterContext{}
-
- /**
* 与えられたTopicをフィルタリングする。
* @param topic Topic
* @return フィルタリングするならtrue
*/
boolean isSame(FilterContext context);
+ /**
+ * フィルタの状態を表すインタフェース。
+ */
+ interface FilterContext{}
+
}
* Copyright(c) 2008 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.Component;
-import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
+import jp.sfjp.jindolf.ResourceManager;
+import jp.sfjp.jindolf.data.Village;
/**
* JTreeの村別アイコン表示。
private static final ImageIcon ICON_INVALID;
static{
- URL url;
- url = Jindolf.getResource("resources/image/prologue.png");
- ICON_PROLOGUE = new ImageIcon(url);
- url = Jindolf.getResource("resources/image/progress.png");
- ICON_PROGRESS = new ImageIcon(url);
- url = Jindolf.getResource("resources/image/epilogue.png");
- ICON_EPILOGUE = new ImageIcon(url);
- url = Jindolf.getResource("resources/image/gameover.png");
- ICON_GAMEOVER = new ImageIcon(url);
- url = Jindolf.getResource("resources/image/cross.png");
- ICON_INVALID = new ImageIcon(url);
+ ICON_PROLOGUE =
+ ResourceManager.getImageIcon("resources/image/vs_prologue.png");
+ ICON_PROGRESS =
+ ResourceManager.getImageIcon("resources/image/vs_progress.png");
+ ICON_EPILOGUE =
+ ResourceManager.getImageIcon("resources/image/vs_epilogue.png");
+ ICON_GAMEOVER =
+ ResourceManager.getImageIcon("resources/image/vs_gameover.png");
+ ICON_INVALID =
+ ResourceManager.getImageIcon("resources/image/vs_cross.png");
}
/**
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.view;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JLabel;
import javax.swing.JPanel;
+import jp.sfjp.jindolf.data.Village;
/**
* 村情報表示パネル。
--- /dev/null
+/*
+ * パッケージ情報
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+/**
+ * 各種ビュークラス。
+ */
+
+package jp.sfjp.jindolf.view;
+
+/* EOF */
+++ /dev/null
-/*
- * Jindolf main class
- *
- * License : The MIT License
- * Copyright(c) 2008 olyutorskii
- */
-
-package jp.sourceforge.jindolf;
-
-import java.awt.Dimension;
-import java.awt.EventQueue;
-import java.awt.GraphicsEnvironment;
-import java.awt.Window;
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.LineNumberReader;
-import java.io.Reader;
-import java.lang.reflect.InvocationTargetException;
-import java.net.URL;
-import java.security.Permission;
-import java.text.DateFormat;
-import java.text.NumberFormat;
-import java.util.Date;
-import java.util.Properties;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.logging.ConsoleHandler;
-import java.util.logging.Handler;
-import java.util.logging.Logger;
-import java.util.logging.LoggingPermission;
-import javax.swing.ImageIcon;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JWindow;
-import javax.swing.UIManager;
-
-/**
- * Jindolf スタートアップクラス。
- *
- * コンストラクタは無いよ。
- * アプリ開始はstaticメソッド{@link #main(String[])}呼び出しから。
- */
-public final class Jindolf{
-
- /** 実行に最低限必要なJREの版数。 */
- public static final String MINIMUM_JREVER = "1.5";
-
-
- /** このClass。 */
- public static final Class<?> SELF_KLASS;
- /** このPackage。 */
- public static final Package SELF_PACKAGE;
- /** ランタイムPackage。 */
- public static final Package JRE_PACKAGE;
- /** 実行環境。 */
- public static final Runtime RUNTIME;
- /** セキュリティマネージャ。 */
- public static final SecurityManager SEC_MANAGER;
- /** クラスローダ。 */
- public static final ClassLoader LOADER;
-
-
- /** クラスロード時のナノカウント。 */
- public static final long NANOCT_LOADED;
- /** クラスロード時刻(エポックmsec)。 */
- public static final long EPOCHMS_LOADED;
-
-
- /** タイトル。 */
- public static final String TITLE;
- /** バージョン。 */
- public static final String VERSION;
- /** 作者名。 */
- public static final String AUTHOR;
- /** 著作権表記。 */
- public static final String COPYRIGHT;
- /** ライセンス表記。 */
- public static final String LICENSE;
- /** 連絡先。 */
- public static final String CONTACT;
- /** 初出。 */
- public static final String DEBUT;
- /** その他、何でも書きたいこと。 */
- public static final String COMMENT;
- /** クレジット。 */
- public static final String ID;
-
- /** 共通ロガー。 */
- private static final LogWrapper COMMON_LOGGER;
-
- /** 多重起動防止用セマフォ。 */
- private static final AtomicBoolean INVOKE_FLAG;
-
- /** スプラッシュロゴ。 */
- private static final String RES_LOGOICON =
- "resources/image/logo.png";
-
- private static OptionInfo option;
- private static AppSetting setting;
-
- /** バージョン定義リソース。 */
- private static final String RES_VERDEF = "resources/version.properties";
-
- static{
- SELF_KLASS = Jindolf.class;
- SELF_PACKAGE = SELF_KLASS.getPackage();
- JRE_PACKAGE = java.lang.Object.class.getPackage();
- RUNTIME = Runtime.getRuntime();
- SEC_MANAGER = System.getSecurityManager();
-
- ClassLoader thisLoader;
- try{
- thisLoader = SELF_KLASS.getClassLoader();
- }catch(SecurityException e){
- thisLoader = null;
- }
- LOADER = thisLoader;
-
- if( ! JRE_PACKAGE.isCompatibleWith(MINIMUM_JREVER) ){
- String jreInstalled;
- try{
- jreInstalled = System.getProperty("java.home");
- }catch(SecurityException e){
- jreInstalled = "※インストール位置不明";
- }
- String errmsg =
- "今このプログラム " + SELF_KLASS.getName() + " は\n"
- +"[ " + jreInstalled
- +" ]\nにインストールされた"
- +" JRE" + JRE_PACKAGE.getSpecificationVersion()
- +" の実行環境で実行されようとしました。\n"
- +"しかしこのプログラムの実行には"
- +" JRE" + MINIMUM_JREVER
- + " 以降の実行環境が必要です。\n"
- +"おそらく http://www.java.com/ などからの"
- +"入手が可能でしょう。";
-
- errorDialog("実行系の不備", errmsg);
-
- RUNTIME.exit(1);
- }
-
- // ここからJRE1.5解禁。
-
- NANOCT_LOADED = System.nanoTime();
- EPOCHMS_LOADED = System.currentTimeMillis();
-
- Properties verProp = loadVersionDefinition(SELF_KLASS);
- TITLE = getPackageInfo(verProp, "pkg-title.", "Unknown");
- VERSION = getPackageInfo(verProp, "pkg-version.", "0");
- AUTHOR = getPackageInfo(verProp, "pkg-author.", "nobody");
- LICENSE = getPackageInfo(verProp, "pkg-license.", "Unknown");
- CONTACT = getPackageInfo(verProp, "pkg-contact.", "Unknown");
- DEBUT = getPackageInfo(verProp, "pkg-debut.", "2008");
- COMMENT = getPackageInfo(verProp, "pkg-comment.", "");
- COPYRIGHT = "Copyright(c)" +"\u0020"+ DEBUT +"\u0020"+ AUTHOR;
- ID = TITLE
- +"\u0020"+ "Ver." + VERSION
- +"\u0020"+ COPYRIGHT
- +"\u0020"+ "("+ LICENSE +")";
-
- Logger jre14Logger = Logger.getLogger(SELF_PACKAGE.getName());
- COMMON_LOGGER = new LogWrapper(jre14Logger);
-
- INVOKE_FLAG = new AtomicBoolean(false);
-
- new Jindolf();
- }
-
-
- /**
- * 隠れコンストラクタ。
- */
- private Jindolf(){
- super();
- assert this.getClass() == SELF_KLASS;
- return;
- }
-
-
- /**
- * 起動オプション情報を返す。
- * @return 起動オプション情報
- */
- public static OptionInfo getOptionInfo(){
- return option;
- }
-
- /**
- * アプリ設定を返す。
- * @return アプリ設定
- */
- public static AppSetting getAppSetting(){
- return setting;
- }
-
- /**
- * エラーダイアログをビットマップディスプレイに出現させる。
- * メインウィンドウが整備されるまでの間だけ一時的に使う。
- * 努力目標:なるべく昔のJRE環境でも例外無く動くように。
- * @param title タイトル
- * @param message メッセージ
- */
- private static void errorDialog(String title, String message){
- System.err.println(message);
- System.err.flush();
-
- if( ! JRE_PACKAGE.isCompatibleWith("1.2") ){
- return;
- }
-
- if( JRE_PACKAGE.isCompatibleWith("1.4")
- && GraphicsEnvironment.isHeadless()){
- return;
- }
-
- JOptionPane.showMessageDialog(null,
- message,
- title,
- JOptionPane.ERROR_MESSAGE);
-
- return;
- }
-
- /**
- * リソース上のパッケージ定義プロパティをロードする。
- * MANIFEST.MFが参照できない実行環境での代替品。
- * @param klass パッケージを構成する任意のクラス
- * @return プロパティ
- */
- private static Properties loadVersionDefinition(Class klass){
- Properties result = new Properties();
-
- InputStream istream = klass.getResourceAsStream(RES_VERDEF);
- try{
- result.load(istream);
- }catch(IOException e){
- return result;
- }finally{
- try{
- istream.close();
- }catch(IOException e){
- return result;
- }
- }
-
- return result;
- }
-
- /**
- * リソース上のプロパティから
- * このクラスのパッケージのパッケージ情報を取得する。
- * MANIFEST.MFが参照できない実行環境での代替品。
- * @param prop プロパティ
- * @param prefix 接頭辞
- * @param defValue 見つからなかった場合のデフォルト値
- * @return パッケージ情報
- */
- public static String getPackageInfo(Properties prop,
- String prefix,
- String defValue){
- return getPackageInfo(prop, SELF_PACKAGE, prefix, defValue);
- }
-
- /**
- * リソース上のプロパティからパッケージ情報を取得する。
- * MANIFEST.MFが参照できない実行環境での代替品。
- * @param prop プロパティ
- * @param pkg 任意のパッケージ
- * @param prefix 接頭辞
- * @param defValue デフォルト値
- * @return 見つからなかった場合のパッケージ情報
- */
- public static String getPackageInfo(Properties prop,
- Package pkg,
- String prefix,
- String defValue){
- String propName = prefix + pkg.getName();
- String result = prop.getProperty(propName, defValue);
- return result;
- }
-
- /**
- * Jindolf の実行が可能なGUI環境でなければ、即時VM実行を終了する。
- */
- private static void checkGUIEnvironment(){
- if(GraphicsEnvironment.isHeadless()){
- System.err.println(
- TITLE
- + " はGUI環境と接続できませんでした");
-
- String dispEnv;
- try{
- dispEnv = System.getenv("DISPLAY");
- }catch(SecurityException e){
- dispEnv = null;
- }
-
- // for X11 user
- if(dispEnv != null){
- System.err.println("環境変数 DISPLAY : " + dispEnv);
- }
-
- RUNTIME.exit(1);
- }
-
- return;
- }
-
- /**
- * コンパイル時のエラーを判定する。
- * ※ 非Unicode系の開発環境を使いたい人は適当に無視してね。
- */
- private static void checkCompileError(){
- String errmsg =
- "ソースコードの文字コードが"
- +"正しくコンパイルされていないかも。\n"
- +"あなたは今、オリジナル開発元の意図しない文字コード環境で"
- +"コンパイルされたプログラムを起動しようとしているよ。\n"
- +"ソースコードの入手に際して"
- +"どのような文字コード変換が行われたか認識しているかな?\n"
- +"コンパイルオプションで正しい文字コードを指定したかな?";
-
- if( '狼' != 0x72fc
- || ' ' != 0x3000
- || '~' != 0x007e
- || '\\' != 0x005c // バックスラッシュ
- || '¥' != 0x00a5 // 半角円通貨
- || '~' != 0xff5e
- || '�' != 0xfffd // Unicode専用特殊文字
- ){
- JOptionPane.showMessageDialog(null,
- errmsg,
- "コンパイルの不備",
- JOptionPane.ERROR_MESSAGE);
- RUNTIME.exit(1);
- }
- return;
- }
-
- /**
- * MANIFEST.MFパッケージ定義エラーの検出。
- * ビルド前にMANIFEST自動生成Antタスク「manifest」を忘れてないかい?
- */
- private static void checkPackageDefinition(){
- String implTitle = SELF_PACKAGE.getImplementationTitle();
- String implVersion = SELF_PACKAGE.getImplementationVersion();
- String implVendor = SELF_PACKAGE.getImplementationVendor();
-
- String errmsg = null;
-
- if( implTitle != null
- && ! implTitle.equals(TITLE) ){
- errmsg = "パッケージ定義とタイトルが一致しません。"
- +"["+ implTitle +"]≠["+ TITLE +"]";
- }else if( implVersion != null
- && ! implVersion.equals(VERSION) ){
- errmsg = "パッケージ定義とバージョン番号が一致しません。"
- +"["+ implVersion +"]≠["+ VERSION +"]";
- }else if( implVendor != null
- && ! implVendor.equals(AUTHOR) ){
- errmsg = "パッケージ定義とベンダが一致しません。"
- +"["+ implVendor +"]≠["+ AUTHOR +"]";
- }
-
- if(errmsg != null){
- JOptionPane.showMessageDialog(null,
- errmsg,
- "ビルドエラー",
- JOptionPane.ERROR_MESSAGE);
- RUNTIME.exit(1);
- }
-
- return;
- }
-
- /**
- * 標準出力端末にヘルプメッセージ(オプションの説明)を表示する。
- */
- private static void showHelpMessage(){
- System.out.flush();
- System.err.flush();
-
- CharSequence helpText = CmdOption.getHelpText();
- System.out.print(helpText);
-
- System.out.flush();
- System.err.flush();
-
- return;
- }
-
- /**
- * スプラッシュウィンドウを作成する。
- * JRE1.6以降では呼ばれないはず。
- * @return 未表示のスプラッシュウィンドウ。
- */
- private static Window createSplashWindow(){
- Window splashWindow = new JWindow();
-
- URL url = getResource(RES_LOGOICON);
- ImageIcon logo = new ImageIcon(url);
- JLabel splashLabel = new JLabel(logo);
-
- splashWindow.add(splashLabel);
- splashWindow.pack();
- splashWindow.setLocationRelativeTo(null); // locate center
-
- return splashWindow;
- }
-
- /**
- * ロギング初期化。
- * @param useConsoleLog trueならConsoleHandlerを使う。
- */
- private static void initLogging(boolean useConsoleLog){
- boolean hasPermission = hasLoggingPermission();
-
- if( ! hasPermission){
- System.out.println(
- "セキュリティ設定により、"
- + "ログ設定を変更できませんでした" );
- }
-
- Logger jre14Logger = COMMON_LOGGER.getJre14Logger();
-
- if(hasPermission){
- jre14Logger.setUseParentHandlers(false);
- Handler pileHandler = new PileHandler();
- jre14Logger.addHandler(pileHandler);
- }
-
- if(hasPermission && useConsoleLog){
- Handler consoleHandler = new ConsoleHandler();
- jre14Logger.addHandler(consoleHandler);
- }
-
- return;
- }
-
- /**
- * ログ操作のアクセス権があるか否か判定する。
- * @return アクセス権があればtrue
- */
- public static boolean hasLoggingPermission(){
- if(SEC_MANAGER == null) return true;
-
- Permission logPermission = new LoggingPermission("control", null);
- try{
- SEC_MANAGER.checkPermission(logPermission);
- }catch(SecurityException e){
- return false;
- }
-
- return true;
- }
-
- /**
- * 起動時の諸々の情報をログ出力する。
- */
- private static void dumpBootInfo(){
- DateFormat dform = DateFormat.getDateTimeInstance();
- NumberFormat nform = NumberFormat.getNumberInstance();
-
- logger().info(
- ID + " は "
- + dform.format(new Date(EPOCHMS_LOADED))
- + " にVM上のクラス "
- + SELF_KLASS.getName() + " としてロードされました。 " );
-
- logger().info("Initial Nano-Count : " + nform.format(NANOCT_LOADED));
-
- logger().info(
- "Max-heap : "
- + nform.format(RUNTIME.maxMemory()) + " Byte"
- + " Total-heap : "
- + nform.format(RUNTIME.totalMemory()) + " Byte");
-
- logger().info("\n" + EnvInfo.getVMInfo());
-
- if(getAppSetting().useConfigPath()){
- logger().info("設定格納ディレクトリに[ "
- + getAppSetting().getConfigPath().getPath()
- + " ]が指定されました。");
- }else{
- logger().info("設定格納ディレクトリは使いません。");
- }
-
- if( JRE_PACKAGE.isCompatibleWith("1.6")
- && option.hasOption(CmdOption.OPT_NOSPLASH) ){
- logger().warn(
- "JRE1.6以降では、"
- +"Jindolfの-nosplashオプションは無効です。"
- + "Java実行系の方でスプラッシュ画面の非表示を"
- + "指示してください(おそらく空の-splash:オプション)" );
- }
-
- if(LOADER == null){
- logger().warn(
- "セキュリティ設定により、"
- +"クラスローダを取得できませんでした");
- }
-
- return;
- }
-
- /**
- * 任意のクラス群に対して一括ロード/初期化を単一スレッドで順に行う。
- * どーしてもクラス初期化の順序に依存する障害が発生する場合や
- * クラス初期化のオーバーヘッドでGUIの操作性が損なわれるときなどにどうぞ。
- *
- * @throws java.lang.LinkageError クラス間リンケージエラー。
- * @throws java.lang.ExceptionInInitializerError クラス初期化で異常
- */
- private static void preInitClass()
- throws LinkageError,
- ExceptionInInitializerError {
- Object[] classes = { // Class型 または String型
- "java.lang.Object",
- TabBrowser.class,
- Discussion.class,
- GlyphDraw.class,
- java.net.HttpURLConnection.class,
- java.text.SimpleDateFormat.class,
- Void.class,
- };
-
- for(Object obj : classes){
- String className;
- if(obj instanceof Class){
- className = ((Class<?>)obj).getName();
- }else if(obj instanceof String){
- className = obj.toString();
- }else{
- continue;
- }
-
- try{
- if(LOADER != null){
- Class.forName(className, true, LOADER);
- }else{
- Class.forName(className);
- }
- }catch(ClassNotFoundException e){
- logger().warn("クラスの明示的ロードに失敗しました", e);
- continue;
- }
- }
-
- return;
- }
-
- /**
- * AWTイベントディスパッチスレッド版スタートアップエントリ。
- */
- private static void startGUI(){
- LandsModel model = new LandsModel();
- model.loadLandList();
-
- JFrame topFrame = buildMVC(model);
-
- GUIUtils.modifyWindowAttributes(topFrame, true, false, true);
-
- topFrame.pack();
-
- Dimension initGeometry =
- new Dimension(setting.initialFrameWidth(),
- setting.initialFrameHeight());
- topFrame.setSize(initGeometry);
-
- if( setting.initialFrameXpos() <= Integer.MIN_VALUE
- || setting.initialFrameYpos() <= Integer.MIN_VALUE ){
- topFrame.setLocationByPlatform(true);
- }else{
- topFrame.setLocation(setting.initialFrameXpos(),
- setting.initialFrameYpos() );
- }
-
- topFrame.setVisible(true);
-
- return;
- }
-
- /**
- * モデル・ビュー・コントローラの結合。
- *
- * @param model 最上位のデータモデル
- * @return アプリケーションのトップフレーム
- */
- private static JFrame buildMVC(LandsModel model){
- ActionManager actionManager = new ActionManager();
- TopView topView = new TopView();
-
- Controller controller = new Controller(actionManager, topView, model);
-
- JFrame topFrame = controller.createTopFrame();
-
- return topFrame;
- }
-
- /**
- * リソースからUTF-8で記述されたテキストデータをロードする。
- * @param resourceName リソース名
- * @return テキスト文字列
- * @throws java.io.IOException 入出力の異常。おそらくビルドミス。
- */
- public static CharSequence loadResourceText(String resourceName)
- throws IOException{
- InputStream is;
- is = getResourceAsStream(resourceName);
- is = new BufferedInputStream(is);
- Reader reader = new InputStreamReader(is, "UTF-8");
- LineNumberReader lineReader = new LineNumberReader(reader);
-
- StringBuilder result = new StringBuilder();
- try{
- for(;;){
- String line = lineReader.readLine();
- if(line == null) break;
- if(line.startsWith("#")) continue;
- result.append(line).append('\n');
- }
- }finally{
- lineReader.close();
- }
-
- return result;
- }
-
- /**
- * クラスローダを介してリソースからの入力を生成する。
- * @param name リソース名
- * @return リソースからの入力
- */
- public static InputStream getResourceAsStream(String name){
- return SELF_KLASS.getResourceAsStream(name);
- }
-
- /**
- * クラスローダを介してリソース読み込み用URLを生成する。
- * @param name リソース名
- * @return URL
- */
- public static URL getResource(String name){
- return SELF_KLASS.getResource(name);
- }
-
- /**
- * 共通ロガーを取得する。
- * @return 共通ロガー
- */
- public static LogWrapper logger(){
- return COMMON_LOGGER;
- }
-
- /**
- * VMごとプログラムを終了する。
- * ※おそらく随所でシャットダウンフックが起動されるはず。
- *
- * @param exitCode 終了コード
- * @throws java.lang.SecurityException セキュリティ違反
- */
- public static void exit(int exitCode) throws SecurityException{
- logger().info(
- "終了コード["
- + exitCode
- + "]でVMごとアプリケーションを終了します。" );
- RUNTIME.runFinalization();
- System.out.flush();
- System.err.flush();
- try{
- RUNTIME.exit(exitCode);
- }catch(SecurityException e){
- logger().warn(
- "セキュリティ設定により、"
- +"VMを終了させることができません。", e);
- throw e;
- }
- return;
- }
-
- /**
- * Jindolf のスタートアップエントリ。
- *
- * @param args コマンドライン引数
- */
- public static void main(final String[] args){
- // VM内二重起動チェック
- boolean hasInvoked = ! INVOKE_FLAG.compareAndSet(false, true);
- if(hasInvoked){
- String errmsg = "二度目以降の起動がキャンセルされました。";
- errorDialog("多重起動", errmsg);
-
- // exitせずに戻るのみ
- return;
- }
-
- checkGUIEnvironment();
-
- // ここからGUIウィンドウとマウス解禁
-
- checkCompileError();
- checkPackageDefinition();
-
- try{
- option = OptionInfo.parseOptions(args);
- }catch(IllegalArgumentException e){
- String message = e.getLocalizedMessage();
- System.err.println(message);
- System.err.println(
- "起動オプション一覧は、"
- + "起動オプションに「"
- + CmdOption.OPT_HELP.toHyphened()
- + "」を指定すると確認できます。" );
- Jindolf.RUNTIME.exit(1);
- assert false;
- return;
- }
-
- if(option.hasOption(CmdOption.OPT_HELP)){
- showHelpMessage();
- RUNTIME.exit(0);
- return;
- }
-
- if(option.hasOption(CmdOption.OPT_VERSION)){
- System.out.println(ID);
- RUNTIME.exit(0);
- return;
- }
-
- // あらゆるSwingコンポーネント操作より前に必要。
- if(option.hasOption(CmdOption.OPT_BOLDMETAL)){
- // もの凄く日本語表示が汚くなるかもよ!注意
- UIManager.put("swing.boldMetal", Boolean.TRUE);
- }else{
- UIManager.put("swing.boldMetal", Boolean.FALSE);
- }
-
- // JRE1.5用スプラッシュウィンドウ
- Window splashWindow = null;
- if( ! JRE_PACKAGE.isCompatibleWith("1.6")
- && ! option.hasOption(CmdOption.OPT_NOSPLASH) ){
- splashWindow = createSplashWindow();
- splashWindow.setVisible(true);
- Thread.yield();
- }
-
- setting = new AppSetting();
- setting.applyOptionInfo(option);
-
- if(option.hasOption(CmdOption.OPT_VMINFO)){
- System.out.println(EnvInfo.getVMInfo());
- }
-
- initLogging(option.hasOption(CmdOption.OPT_CONSOLELOG));
- // ここからロギング解禁
- // Jindolf.exit()もここから解禁
-
- dumpBootInfo();
-
- ConfigFile.setupConfigDirectory();
- ConfigFile.setupLockFile();
- // ここから設定格納ディレクトリ解禁
-
- setting.loadConfig();
-
- RUNTIME.addShutdownHook(new Thread(){
- @Override
- public void run(){
- logger().info("シャットダウン処理に入ります…");
- System.out.flush();
- System.err.flush();
- RUNTIME.gc();
- Thread.yield();
- RUNTIME.runFinalization(); // 危険?
- Thread.yield();
- return;
- }
- });
-
- preInitClass();
-
- GUIUtils.replaceEventQueue();
-
- boolean hasError = false;
- try{
- EventQueue.invokeAndWait(new Runnable(){
- public void run(){
- startGUI();
- return;
- }
- });
- }catch(InvocationTargetException e){
- logger().fatal("アプリケーション初期化に失敗しました", e);
- e.printStackTrace(System.err);
- hasError = true;
- }catch(InterruptedException e){
- logger().fatal("アプリケーション初期化に失敗しました", e);
- e.printStackTrace(System.err);
- hasError = true;
- }finally{
- if(splashWindow != null){
- splashWindow.setVisible(false);
- splashWindow.dispose();
- splashWindow = null;
- }
- }
-
- if(hasError) exit(1);
-
- return;
- }
-
-}
+++ /dev/null
-/*
- * option argument information
- *
- * License : The MIT License
- * Copyright(c) 2009 olyutorskii
- */
-
-package jp.sourceforge.jindolf;
-
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * コマンドラインオプション情報。
- * public static void main()の引数から展開される。
- */
-public class OptionInfo{
-
- private static final Pattern PATTERN_GEOMETRY =
- Pattern.compile(
- "([1-9][0-9]*)x([1-9][0-9]*)"
- +"(?:(\\+|\\-)([1-9][0-9]*)(\\+|\\-)([1-9][0-9]*))?"
- );
-
-
- private Integer frameWidth = null;
- private Integer frameHeight = null;
- private Integer frameXpos = null;
- private Integer frameYpos = null;
-
- private final List<String> invokeArgs = new LinkedList<String>();
- private final List<CmdOption> optionList = new LinkedList<CmdOption>();
- private final Map<CmdOption, Boolean> boolOptionMap =
- new EnumMap<CmdOption, Boolean>(CmdOption.class);
- private final Map<CmdOption, String> stringOptionMap =
- new EnumMap<CmdOption, String>(CmdOption.class);
-
-
- /**
- * コンストラクタ。
- */
- protected OptionInfo(){
- super();
- return;
- }
-
-
- /**
- * オプション文字列を解析する。
- * @param args main()に渡されるオプション文字列
- * @return 解析済みのオプション情報。
- * @throws IllegalArgumentException 構文エラー
- */
- public static OptionInfo parseOptions(String[] args)
- throws IllegalArgumentException{
- OptionInfo result = new OptionInfo();
-
- result.invokeArgs.clear();
- for(String arg : args){
- if(arg == null) continue;
- if(arg.length() <= 0) continue;
- result.invokeArgs.add(arg);
- }
- Iterator<String> iterator = result.invokeArgs.iterator();
-
- while(iterator.hasNext()){
- String arg = iterator.next();
-
- CmdOption option = CmdOption.parseCmdOption(arg);
- if(option == null){
- throw new IllegalArgumentException(
- "未定義の起動オプション["
- + arg
- + "]が指定されました。");
- }
- result.optionList.add(option);
-
- if(CmdOption.isIndepOption(option)){
- continue;
- }else if(CmdOption.isBooleanOption(option)){
- Boolean bool = parseBooleanSwitch(arg, iterator);
- result.boolOptionMap.put(option, bool);
- continue;
- }
-
- switch(option){
- case OPT_INITFONT:
- case OPT_CONFDIR:
- checkNextArg(arg, iterator);
- result.stringOptionMap.put(option, iterator.next());
- break;
- case OPT_GEOMETRY:
- checkNextArg(arg, iterator);
- String geometry = iterator.next();
- Matcher matcher = PATTERN_GEOMETRY.matcher(geometry);
- if( ! matcher.matches() ){
- throw new IllegalArgumentException(
- "起動オプション["
- +arg
- +"]の引数形式["
- +geometry
- +"]が不正です。" );
- }
- String width = matcher.group(1);
- String height = matcher.group(2);
- String xSign = matcher.group(3);
- String xPos = matcher.group(4);
- String ySign = matcher.group(5);
- String yPos = matcher.group(6);
- try{
- result.frameWidth = Integer.parseInt(width);
- result.frameHeight = Integer.parseInt(height);
- if(xPos != null && xPos.length() > 0){
- result.frameXpos = Integer.parseInt(xPos);
- if(xSign.equals("-")){
- result.frameXpos = -result.frameXpos;
- }
- }
- if(yPos != null && yPos.length() > 0){
- result.frameYpos = Integer.parseInt(yPos);
- if(ySign.equals("-")){
- result.frameYpos = -result.frameYpos;
- }
- }
- }catch(NumberFormatException e){
- assert false;
- throw new IllegalArgumentException(e);
- }
-
- break;
- default:
- assert false;
- break;
- }
- }
-
- return result;
- }
-
- /**
- * 真偽二値をとるオプション解析の下請け。
- * @param option オプション名
- * @param iterator 引数並び
- * @return 真偽
- * @throws IllegalArgumentException 構文エラー
- */
- private static Boolean parseBooleanSwitch(
- String option, Iterator<String> iterator )
- throws IllegalArgumentException{
- Boolean result;
- checkNextArg(option, iterator);
- String onoff = iterator.next();
- if( onoff.compareToIgnoreCase("on" ) == 0
- || onoff.compareToIgnoreCase("yes" ) == 0
- || onoff.compareToIgnoreCase("true") == 0){
- result = Boolean.TRUE;
- }else if( onoff.compareToIgnoreCase("off" ) == 0
- || onoff.compareToIgnoreCase("no" ) == 0
- || onoff.compareToIgnoreCase("false") == 0){
- result = Boolean.FALSE;
- }else{
- throw new IllegalArgumentException(
- "起動オプション["
- +option
- +"]の引数形式["
- +onoff
- +"]が不正です。"
- +"on, off, yes, no, true, false"
- +"のいずれかを指定してください。");
- }
- return result;
- }
-
- /**
- * 追加引数を持つオプションのチェック。
- * @param option オプション名
- * @param iterator 引数並び
- * @throws IllegalArgumentException 構文エラー
- */
- private static void checkNextArg(CharSequence option,
- Iterator<String> iterator )
- throws IllegalArgumentException{
- if( ! iterator.hasNext() ){
- throw new IllegalArgumentException(
- "起動オプション["
- +option
- +"]に引数がありません。");
- }
- return;
- }
-
-
- /**
- * 全引数のリストを返す。
- * @return 全引数のリスト
- */
- public List<String> getInvokeArgList(){
- return Collections.unmodifiableList(this.invokeArgs);
- }
-
- /**
- * オプションが指定されていたか否か判定する。
- * @param option オプション
- * @return 指定されていたらtrue
- */
- public boolean hasOption(CmdOption option){
- if(this.optionList.contains(option)) return true;
- return false;
- }
-
- /**
- * 真偽値をとるオプション値を返す。
- * 複数回指定された場合は最後の値。
- * @param option オプション
- * @return 真偽値。オプション指定がなかった場合はnull
- * @throws IllegalArgumentException 真偽値を取るオプションではない。
- */
- public Boolean getBooleanArg(CmdOption option)
- throws IllegalArgumentException{
- if( ! CmdOption.isBooleanOption(option) ){
- throw new IllegalArgumentException();
- }
- Boolean result = this.boolOptionMap.get(option);
- return result;
- }
-
- /**
- * 文字列引数をとるオプション値を返す。
- * 複数回指定された場合は最後の値。
- * @param option オプション
- * @return 文字列。オプション指定がなかった場合はnull
- */
- public String getStringArg(CmdOption option){
- String result = this.stringOptionMap.get(option);
- return result;
- }
-
- /**
- * 排他的オプションのいずれかが指定されたか判定する。
- * 後から指定された方が有効となる。
- * @param options 排他的オプション群
- * @return いずれかのオプション。どれも指定されなければnull
- */
- public CmdOption getExclusiveOption(CmdOption... options){
- CmdOption result = null;
- for(CmdOption option : this.optionList){
- for(CmdOption excOption : options){
- if(option == excOption){
- result = option;
- break;
- }
- }
- }
- return result;
- }
-
- /**
- * 初期のフレーム幅を返す。
- * @return 初期のフレーム幅。オプション指定されてなければnull
- */
- public Integer initialFrameWidth(){
- return this.frameWidth;
- }
-
- /**
- * 初期のフレーム高を返す。
- * @return 初期のフレーム高。オプション指定されてなければnull
- */
- public Integer initialFrameHeight(){
- return this.frameHeight;
- }
-
- /**
- * 初期のフレーム位置のX座標を返す。
- * @return 初期のフレーム位置のX座標。オプション指定されてなければnull
- */
- public Integer initialFrameXpos(){
- return this.frameXpos;
- }
-
- /**
- * 初期のフレーム位置のY座標を返す。
- * @return 初期のフレーム位置のY座標。オプション指定されてなければnull
- */
- public Integer initialFrameYpos(){
- return this.frameYpos;
- }
-
-}
--- /dev/null
+# Version definition
+# [ with Maven resource filtering ]
+
+pkg-title.jp.sfjp.jindolf = ${pom.name}
+pkg-version.jp.sfjp.jindolf = ${pom.version}
+pkg-author.jp.sfjp.jindolf = olyutorskii
+pkg-license.jp.sfjp.jindolf = The MIT License
+pkg-contact.jp.sfjp.jindolf = ${pom.url}
+pkg-inception.jp.sfjp.jindolf = ${pom.inceptionYear}
+pkg-comment.jp.sfjp.jindolf =
+
+# EOF #
+++ /dev/null
-# Version definition
-# [ with Maven resource filtering ]
-
-pkg-title.jp.sourceforge.jindolf = ${pom.name}
-pkg-version.jp.sourceforge.jindolf = ${pom.version}
-pkg-author.jp.sourceforge.jindolf = olyutorskii
-pkg-license.jp.sourceforge.jindolf = The MIT License
-pkg-contact.jp.sourceforge.jindolf = ${pom.url}
-pkg-debut.jp.sourceforge.jindolf = ${pom.inceptionYear}
-pkg-comment.jp.sourceforge.jindolf =
-
-# EOF #
--- /dev/null
+/*
+ * CmdOption test
+ *
+ * Copyright 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf.config;
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.LinkedList;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class CmdOptionTest {
+
+ public CmdOptionTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of values method, of class CmdOption.
+ */
+ @Test
+ public void testValues() {
+ System.out.println("values");
+
+ CmdOption[] values = CmdOption.values();
+
+ assertEquals(12, values.length);
+
+ List<CmdOption> list = Arrays.asList(values);
+
+ List<CmdOption> testList = new LinkedList<CmdOption>();
+ testList.add(CmdOption.OPT_HELP);
+ testList.add(CmdOption.OPT_VERSION);
+ testList.add(CmdOption.OPT_BOLDMETAL);
+ testList.add(CmdOption.OPT_NOSPLASH);
+ testList.add(CmdOption.OPT_GEOMETRY);
+ testList.add(CmdOption.OPT_VMINFO);
+ testList.add(CmdOption.OPT_CONSOLELOG);
+ testList.add(CmdOption.OPT_INITFONT);
+ testList.add(CmdOption.OPT_ANTIALIAS);
+ testList.add(CmdOption.OPT_FRACTIONAL);
+ testList.add(CmdOption.OPT_CONFDIR);
+ testList.add(CmdOption.OPT_NOCONF);
+
+ assertTrue(list.containsAll(testList));
+ assertTrue(testList.containsAll(list));
+ assertEquals(testList.size(), list.size());
+
+ return;
+ }
+
+ /**
+ * Test of valueOf method, of class CmdOption.
+ */
+ @Test
+ public void testValueOf() {
+ System.out.println("valueOf");
+
+ CmdOption expResult;
+ CmdOption result;
+
+ expResult = CmdOption.OPT_HELP;
+ result = CmdOption.valueOf("OPT_HELP");
+ assertEquals(expResult, result);
+
+ try{
+ CmdOption.valueOf("X");
+ fail();
+ }catch(IllegalArgumentException e){
+ // GOOD
+ }
+
+ return;
+ }
+
+ /**
+ * Test of getHelpText method, of class CmdOption.
+ */
+ @Test
+ public void testGetHelpText() {
+ System.out.println("getHelpText");
+
+ CharSequence result = CmdOption.getHelpText();
+
+ assertNotNull(result);
+ assertTrue(result.length() > 0);
+ assertTrue(result.toString().endsWith("\n"));
+
+ return;
+ }
+
+ /**
+ * Test of parseCmdOption method, of class CmdOption.
+ */
+ @Test
+ public void testParseCmdOption() {
+ System.out.println("parseCmdOption");
+
+ assertNull(CmdOption.parseCmdOption(""));
+ assertNull(CmdOption.parseCmdOption("X"));
+
+ assertEquals(CmdOption.OPT_HELP, CmdOption.parseCmdOption("-help"));
+ assertEquals(CmdOption.OPT_HELP, CmdOption.parseCmdOption("-?"));
+
+ assertEquals(CmdOption.OPT_NOCONF,
+ CmdOption.parseCmdOption("-noconfdir"));
+
+ return;
+ }
+
+ /**
+ * Test of matches method, of class CmdOption.
+ */
+ @Test
+ public void testMatches() {
+ System.out.println("matches");
+
+ assertFalse(CmdOption.OPT_HELP.matches(""));
+ assertFalse(CmdOption.OPT_HELP.matches("help"));
+
+ assertTrue(CmdOption.OPT_HELP.matches("-help"));
+ assertTrue(CmdOption.OPT_HELP.matches("-h"));
+ assertTrue(CmdOption.OPT_HELP.matches("--help"));
+ assertTrue(CmdOption.OPT_HELP.matches("-?"));
+
+ assertTrue(CmdOption.OPT_VERSION.matches("-version"));
+ assertTrue(CmdOption.OPT_BOLDMETAL.matches("-boldMetal"));
+ assertTrue(CmdOption.OPT_NOSPLASH.matches("-nosplash"));
+ assertTrue(CmdOption.OPT_GEOMETRY.matches("-geometry"));
+ assertTrue(CmdOption.OPT_VMINFO.matches("-vminfo"));
+ assertTrue(CmdOption.OPT_CONSOLELOG.matches("-consolelog"));
+ assertTrue(CmdOption.OPT_INITFONT.matches("-initfont"));
+ assertTrue(CmdOption.OPT_ANTIALIAS.matches("-antialias"));
+ assertTrue(CmdOption.OPT_FRACTIONAL.matches("-fractional"));
+ assertTrue(CmdOption.OPT_CONFDIR.matches("-confdir"));
+ assertTrue(CmdOption.OPT_NOCONF.matches("-noconfdir"));
+
+ return;
+ }
+
+ /**
+ * Test of isIndepOption method, of class CmdOption.
+ */
+ @Test
+ public void testIsIndepOption() {
+ System.out.println("isIndepOption");
+
+ for(CmdOption opt : CmdOption.values()){
+ switch(opt){
+ case OPT_HELP:
+ case OPT_VERSION:
+ case OPT_VMINFO:
+ case OPT_BOLDMETAL:
+ case OPT_NOSPLASH:
+ case OPT_CONSOLELOG:
+ case OPT_NOCONF:
+ assertTrue(opt.isIndepOption());
+ break;
+ default:
+ assertFalse(opt.isIndepOption());
+ break;
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * Test of isBooleanOption method, of class CmdOption.
+ */
+ @Test
+ public void testIsBooleanOption() {
+ System.out.println("isBooleanOption");
+
+ for(CmdOption opt : CmdOption.values()){
+ switch(opt){
+ case OPT_ANTIALIAS:
+ case OPT_FRACTIONAL:
+ assertTrue(opt.isBooleanOption());
+ break;
+ default:
+ assertFalse(opt.isBooleanOption());
+ break;
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * Test of toString method, of class CmdOption.
+ */
+ @Test
+ public void testToString() {
+ System.out.println("toString");
+
+ assertEquals("-help", CmdOption.OPT_HELP.toString());
+ assertEquals("-version", CmdOption.OPT_VERSION.toString());
+ assertEquals("-boldMetal", CmdOption.OPT_BOLDMETAL.toString());
+ assertEquals("-nosplash", CmdOption.OPT_NOSPLASH.toString());
+ assertEquals("-geometry", CmdOption.OPT_GEOMETRY.toString());
+ assertEquals("-vminfo", CmdOption.OPT_VMINFO.toString());
+ assertEquals("-consolelog", CmdOption.OPT_CONSOLELOG.toString());
+ assertEquals("-initfont", CmdOption.OPT_INITFONT.toString());
+ assertEquals("-antialias", CmdOption.OPT_ANTIALIAS.toString());
+ assertEquals("-fractional", CmdOption.OPT_FRACTIONAL.toString());
+ assertEquals("-confdir", CmdOption.OPT_CONFDIR.toString());
+ assertEquals("-noconfdir", CmdOption.OPT_NOCONF.toString());
+
+ return;
+ }
+}
--- /dev/null
+/*
+ * OptionInfo test
+ *
+ * Copyright 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf.config;
+
+import java.util.List;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class OptionInfoTest {
+
+ public OptionInfoTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of parseOptions method, of class OptionInfo.
+ */
+ @Test
+ public void testParseOptions() {
+ System.out.println("parseOptions");
+
+ OptionInfo result;
+
+ result = OptionInfo.parseOptions();
+ assertNotNull(result);
+
+ result = OptionInfo.parseOptions(null, null);
+ assertNotNull(result);
+ assertTrue(result.getInvokeArgList().isEmpty());
+
+ result = OptionInfo.parseOptions(new String[]{});
+ assertNotNull(result);
+
+ result = OptionInfo.parseOptions("-help");
+ assertNotNull(result);
+
+ try{
+ result = OptionInfo.parseOptions("X");
+ fail();
+ }catch(IllegalArgumentException e){
+ assertEquals("未定義の起動オプション[X]が指定されました。",
+ e.getMessage() );
+ }
+
+ try{
+ result = OptionInfo.parseOptions("");
+ fail();
+ }catch(IllegalArgumentException e){
+ assertEquals("未定義の起動オプション[]が指定されました。",
+ e.getMessage() );
+ }
+
+ return;
+ }
+
+ /**
+ * Test of getInvokeArgList method, of class OptionInfo.
+ */
+ @Test
+ public void testGetInvokeArgList() {
+ System.out.println("getInvokeArgList");
+
+ OptionInfo result;
+ List<String> list;
+
+ result = OptionInfo.parseOptions();
+ list = result.getInvokeArgList();
+ assertTrue(list.isEmpty());
+
+ result = OptionInfo.parseOptions("-help");
+ list = result.getInvokeArgList();
+ assertEquals(1, list.size());
+ assertEquals("-help", list.get(0));
+
+ result = OptionInfo.parseOptions("-initfont", "on", "-help");
+ list = result.getInvokeArgList();
+ assertEquals(3, list.size());
+ assertEquals("-initfont", list.get(0));
+ assertEquals("on", list.get(1));
+ assertEquals("-help", list.get(2));
+
+ return;
+ }
+
+ /**
+ * Test of hasOption method, of class OptionInfo.
+ */
+ @Test
+ public void testHasOption() {
+ System.out.println("hasOption");
+
+ OptionInfo result;
+
+ result = OptionInfo.parseOptions();
+ assertFalse(result.hasOption(CmdOption.OPT_HELP));
+ assertFalse(result.hasOption(CmdOption.OPT_INITFONT));
+
+ result = OptionInfo.parseOptions("-help");
+ assertTrue(result.hasOption(CmdOption.OPT_HELP));
+ assertFalse(result.hasOption(CmdOption.OPT_INITFONT));
+
+ result = OptionInfo.parseOptions("-initfont", "on", "-help");
+ assertTrue(result.hasOption(CmdOption.OPT_HELP));
+ assertTrue(result.hasOption(CmdOption.OPT_INITFONT));
+
+ result = OptionInfo.parseOptions("-initfont", "off", "-help");
+ assertTrue(result.hasOption(CmdOption.OPT_HELP));
+ assertTrue(result.hasOption(CmdOption.OPT_INITFONT));
+
+ return;
+ }
+
+ /**
+ * Test of getBooleanArg method, of class OptionInfo.
+ */
+ @Test
+ public void testGetBooleanArg() {
+ System.out.println("getBooleanArg");
+
+ OptionInfo result;
+
+ try{
+ result = OptionInfo.parseOptions("-antialias");
+ fail();
+ }catch(IllegalArgumentException e){
+ String expMsg =
+ "起動オプション[-antialias]に引数がありません。";
+ assertEquals(expMsg, e.getMessage());
+ }
+
+ try{
+ result = OptionInfo.parseOptions("-fractional");
+ fail();
+ }catch(IllegalArgumentException e){
+ String expMsg =
+ "起動オプション[-fractional]に引数がありません。";
+ assertEquals(expMsg, e.getMessage());
+ }
+
+ result = OptionInfo.parseOptions("-help");
+ try{
+ result.getBooleanArg(CmdOption.OPT_HELP);
+ fail();
+ }catch(IllegalArgumentException e){
+ String expMsg =
+ "起動オプション[-help]は"
+ + "真偽を指定するオプションではありません。";
+ assertEquals(expMsg, e.getMessage());
+ }
+
+ result = OptionInfo.parseOptions();
+ assertNull(result.getBooleanArg(CmdOption.OPT_ANTIALIAS));
+ assertNull(result.getBooleanArg(CmdOption.OPT_FRACTIONAL));
+
+
+ String[] flags;
+
+ flags = new String[]{"on", "yes", "true", "ON", "YES", "TRUE"};
+ for(String flag : flags){
+ result = OptionInfo.parseOptions("-antialias", flag);
+ assertTrue(result.getBooleanArg(CmdOption.OPT_ANTIALIAS));
+ result = OptionInfo.parseOptions("-fractional", flag);
+ assertTrue(result.getBooleanArg(CmdOption.OPT_FRACTIONAL));
+ }
+
+ flags = new String[]{"off", "no", "false", "OFF", "NO", "FALSE"};
+ for(String flag : flags){
+ result = OptionInfo.parseOptions("-antialias", flag);
+ assertFalse(result.getBooleanArg(CmdOption.OPT_ANTIALIAS));
+ result = OptionInfo.parseOptions("-fractional", flag);
+ assertFalse(result.getBooleanArg(CmdOption.OPT_FRACTIONAL));
+ }
+
+ try{
+ result = OptionInfo.parseOptions("-antialias", "X");
+ fail();
+ }catch(IllegalArgumentException e){
+ String expMsg =
+ "起動オプション[-antialias]の真偽指定[X]が不正です。"
+ + "on, off, yes, no, true, false"
+ + "のいずれかを指定してください。";
+ assertEquals(expMsg, e.getMessage());
+ }
+
+ try{
+ result = OptionInfo.parseOptions("-fractional", "X");
+ fail();
+ }catch(IllegalArgumentException e){
+ String expMsg =
+ "起動オプション[-fractional]の真偽指定[X]が不正です。"
+ + "on, off, yes, no, true, false"
+ + "のいずれかを指定してください。";
+ assertEquals(expMsg, e.getMessage());
+ }
+
+ result = OptionInfo.parseOptions("-antialias", "on",
+ "-antialias", "off" );
+ assertFalse(result.getBooleanArg(CmdOption.OPT_ANTIALIAS));
+
+ return;
+ }
+
+ /**
+ * Test of getStringArg method, of class OptionInfo.
+ */
+ @Test
+ public void testGetStringArg() {
+ System.out.println("getStringArg");
+
+ OptionInfo result;
+
+ try{
+ result = OptionInfo.parseOptions("-initfont");
+ fail();
+ }catch(IllegalArgumentException e){
+ String expMsg =
+ "起動オプション[-initfont]に引数がありません。";
+ assertEquals(expMsg, e.getMessage());
+ }
+
+ try{
+ result = OptionInfo.parseOptions("-confdir");
+ fail();
+ }catch(IllegalArgumentException e){
+ String expMsg =
+ "起動オプション[-confdir]に引数がありません。";
+ assertEquals(expMsg, e.getMessage());
+ }
+
+ result = OptionInfo.parseOptions();
+ assertNull(result.getStringArg(CmdOption.OPT_INITFONT));
+ assertNull(result.getStringArg(CmdOption.OPT_CONFDIR));
+
+ result = OptionInfo.parseOptions("-initfont", "Monospaced-PLAIN-16");
+ assertEquals("Monospaced-PLAIN-16",
+ result.getStringArg(CmdOption.OPT_INITFONT));
+
+ result = OptionInfo.parseOptions("-confdir", "/tmp/x");
+ assertEquals("/tmp/x",
+ result.getStringArg(CmdOption.OPT_CONFDIR));
+
+ result = OptionInfo.parseOptions("-confdir", "/tmp/x",
+ "-confdir", "/tmp/y" );
+ assertEquals("/tmp/y",
+ result.getStringArg(CmdOption.OPT_CONFDIR));
+
+ return;
+ }
+
+ /**
+ * Test of getExclusiveOption method, of class OptionInfo.
+ */
+ @Test
+ public void testGetExclusiveOption() {
+ System.out.println("getExclusiveOption");
+
+ OptionInfo result;
+ CmdOption opt;
+
+ result = OptionInfo.parseOptions();
+ opt = result.getExclusiveOption(CmdOption.OPT_CONFDIR,
+ CmdOption.OPT_NOCONF );
+ assertNull(opt);
+
+ result = OptionInfo.parseOptions("-help");
+ opt = result.getExclusiveOption(CmdOption.OPT_CONFDIR,
+ CmdOption.OPT_NOCONF );
+ assertNull(opt);
+
+ result = OptionInfo.parseOptions("-confdir", "/tmp/x");
+ opt = result.getExclusiveOption(CmdOption.OPT_CONFDIR,
+ CmdOption.OPT_NOCONF );
+ assertSame(CmdOption.OPT_CONFDIR, opt);
+
+ result = OptionInfo.parseOptions("-noconfdir");
+ opt = result.getExclusiveOption(CmdOption.OPT_CONFDIR,
+ CmdOption.OPT_NOCONF );
+ assertSame(CmdOption.OPT_NOCONF, opt);
+
+ result = OptionInfo.parseOptions("-confdir", "/tmp/x",
+ "-noconfdir" );
+ opt = result.getExclusiveOption(CmdOption.OPT_CONFDIR,
+ CmdOption.OPT_NOCONF );
+ assertSame(CmdOption.OPT_NOCONF, opt);
+
+ result = OptionInfo.parseOptions("-noconfdir",
+ "-confdir", "/tmp/x" );
+ opt = result.getExclusiveOption(CmdOption.OPT_CONFDIR,
+ CmdOption.OPT_NOCONF );
+ assertSame(CmdOption.OPT_CONFDIR, opt);
+
+ return;
+ }
+
+ /**
+ * Test of geometry option, of class OptionInfo.
+ */
+ @Test
+ public void testGeometry() {
+ System.out.println("initialFrameWidth");
+
+ OptionInfo result;
+
+ result = OptionInfo.parseOptions();
+ assertNull(result.initialFrameWidth());
+ assertNull(result.initialFrameHeight());
+ assertNull(result.initialFrameXpos());
+ assertNull(result.initialFrameYpos());
+
+ try{
+ result = OptionInfo.parseOptions("-geometry");
+ fail();
+ }catch(IllegalArgumentException e){
+ String expMsg =
+ "起動オプション[-geometry]に引数がありません。";
+ assertEquals(expMsg, e.getMessage());
+ }
+
+ try{
+ result = OptionInfo.parseOptions("-geometry", "Q");
+ fail();
+ }catch(IllegalArgumentException e){
+ String expMsg =
+ "起動オプション[-geometry]の"
+ + "ジオメトリ指定[Q]が不正です。"
+ + "WIDTHxHEIGHT[(+|-)XPOS(+|-)YPOS]"
+ + "の形式で指定してください";
+ assertEquals(expMsg, e.getMessage());
+ }
+
+ result = OptionInfo.parseOptions("-geometry", "800x600");
+ assertEquals(800, result.initialFrameWidth().intValue());
+ assertEquals(600, result.initialFrameHeight().intValue());
+ assertNull(result.initialFrameXpos());
+ assertNull(result.initialFrameYpos());
+
+ result = OptionInfo.parseOptions("-geometry", "800x600+100+200");
+ assertEquals(800, result.initialFrameWidth().intValue());
+ assertEquals(600, result.initialFrameHeight().intValue());
+ assertEquals(100, result.initialFrameXpos().intValue());
+ assertEquals(200, result.initialFrameYpos().intValue());
+
+ result = OptionInfo.parseOptions("-geometry", "800x600-100-200");
+ assertEquals(800, result.initialFrameWidth().intValue());
+ assertEquals(600, result.initialFrameHeight().intValue());
+ assertEquals(-100, result.initialFrameXpos().intValue());
+ assertEquals(-200, result.initialFrameYpos().intValue());
+
+ return;
+ }
+
+}
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.data;
import java.util.List;
import java.util.regex.Matcher;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.net;
import org.junit.After;
import org.junit.AfterClass;
* Copyright(c) 2009 olyutorskii
*/
-package jp.sourceforge.jindolf;
+package jp.sfjp.jindolf.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;