--- /dev/null
+/*
+ * busy status manager
+ *
+ * License : The MIT License
+ * Copyright(c) 2020 olyutorskii
+ */
+
+package jp.sfjp.jindolf;
+
+import java.awt.EventQueue;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import jp.sfjp.jindolf.view.TopFrame;
+import jp.sfjp.jindolf.view.TopView;
+
+/**
+ * ビジー状態の見た目を管理する。
+ *
+ * <p>ビジー状態を伴うタスクの管理も行う。
+ *
+ * <p>EDTで処理しきれない長時間タスクを実行している状況、
+ * およびその間のGUI操作が抑止される期間をビジーと呼ぶ。
+ */
+public class BusyStatus {
+
+ private static final Logger LOGGER = Logger.getAnonymousLogger();
+
+
+ private final TopFrame topFrame;
+ private final Executor executor = Executors.newCachedThreadPool();
+
+ private boolean isBusy = false;
+
+
+ /**
+ * コンストラクタ。
+ *
+ * @param topFrame TopFrameインスタンス
+ */
+ public BusyStatus(TopFrame topFrame){
+ super();
+ this.topFrame = topFrame;
+ return;
+ }
+
+
+ /**
+ * ビジー状態か否か返す。
+ *
+ * @return ビジーならtrue
+ */
+ public boolean isBusy(){
+ return this.isBusy;
+ }
+
+ /**
+ * ビジー状態を設定する。
+ *
+ * <p>ヘビーなタスク実行をアピールするために、
+ * プログレスバーとカーソルの設定を行う。
+ *
+ * <p>ビジー中のトップフレームのマウス操作、キーボード入力は
+ * 全てグラブされるため無視される。
+ *
+ * @param flag trueならプログレスバーのアニメ開始&WAITカーソル。
+ * falseなら停止&通常カーソル。
+ * @param msg フッタメッセージ。nullなら変更なし。
+ */
+ public void setBusy(boolean flag, String msg){
+ if(EventQueue.isDispatchThread()){
+ setBusyEdt(flag, msg);
+ return;
+ }
+
+ try{
+ EventQueue.invokeAndWait(() -> {
+ setBusyEdt(flag, msg);
+ });
+ }catch(InterruptedException | InvocationTargetException e){
+ LOGGER.log(Level.SEVERE, "ビジー処理で失敗", e);
+ }
+
+ return;
+ }
+
+ /**
+ * ビジー状態を設定する。
+ *
+ * <p>原則EDTから呼ばねばならない。
+ *
+ * @param flag trueならビジー
+ * @param msg メッセージ。nullなら変更なし。
+ */
+ public void setBusyEdt(boolean flag, String msg){
+ assert EventQueue.isDispatchThread();
+
+ this.isBusy = flag;
+
+ this.topFrame.setBusy(this.isBusy);
+
+ if(msg != null){
+ TopView topView = this.topFrame.getTopView();
+ topView.updateSysMessage(msg);
+ }
+
+ return;
+ }
+
+ /**
+ * 軽量タスクをEDTで実行する。
+ *
+ * <p>タスク実行中はビジー状態となる。
+ *
+ * <p>軽量タスク実行中はイベントループが停止するので、
+ * 入出力待ちを伴わなずに早急に終わるタスクでなければならない。
+ *
+ * @param task 軽量タスク
+ * @param beforeMsg ビジー中ステータス文字列
+ * @param afterMsg ビジー復帰時のステータス文字列
+ */
+ public void submitLightBusyTask(Runnable task,
+ String beforeMsg,
+ String afterMsg ){
+ EventQueue.invokeLater(() -> {
+ setBusy(true, beforeMsg);
+ });
+
+ EventQueue.invokeLater(task);
+
+ EventQueue.invokeLater(() -> {
+ setBusy(false, afterMsg);
+ });
+
+ return;
+ }
+
+ /**
+ * 重量級タスクをEDTとは別のスレッドで実行する。
+ *
+ * <p>タスク実行中はビジー状態となる。
+ *
+ * @param heavyTask 重量級タスク
+ * @param beforeMsg ビジー中ステータス文字列
+ * @param afterMsg ビジー復帰時のステータス文字列
+ */
+ public void submitHeavyBusyTask(final Runnable heavyTask,
+ final String beforeMsg,
+ final String afterMsg ){
+ setBusy(true, beforeMsg);
+
+ EventQueue.invokeLater(() -> {
+ fork(() -> {
+ try{
+ heavyTask.run();
+ }finally{
+ setBusy(false, afterMsg);
+ }
+ });
+ });
+
+ return;
+ }
+
+ /**
+ * スレッドプールを用いて非EDTなタスクを投入する。
+ *
+ * @param task タスク
+ */
+ private void fork(Runnable task){
+ this.executor.execute(task);
+ return;
+ }
+
+}
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
private final ChangeListener filterWatcher =
new FilterWatcher();
- private final Executor executor = Executors.newCachedThreadPool();
- private volatile boolean isBusyNow;
+ private final BusyStatus busyStatus;
/**
shutdown();
}
});
+ this.busyStatus = new BusyStatus(topFrame);
filterPanel.addChangeListener(this.filterWatcher);
}
/**
- * ビジー状態の設定を行う。
- *
- * <p>ヘビーなタスク実行をアピールするために、
- * プログレスバーとカーソルの設定を行う。
- *
- * <p>ビジー中のActionコマンド受信は無視される。
- *
- * <p>ビジー中のトップフレームのマウス操作、キーボード入力は
- * 全てグラブされるため無視される。
- *
- * @param isBusy trueならプログレスバーのアニメ開始&WAITカーソル。
- * falseなら停止&通常カーソル。
- * @param msg フッタメッセージ。nullなら変更なし。
- */
- private void setBusy(boolean isBusy, String msg){
- this.isBusyNow = isBusy;
-
- TopFrame topFrame = getTopFrame();
-
- topFrame.setBusy(isBusy);
- if(msg != null){
- this.topView.updateSysMessage(msg);
- }
-
- return;
- }
-
- /**
* ステータスバーを更新する。
* @param message メッセージ
*/
}
/**
- * ビジー状態を設定する。
- *
- * <p>EDT以外から呼ばれると実際の処理が次回のEDT移行に遅延される。
- *
- * @param isBusy ビジーならtrue
- * @param message ステータスバー表示。nullなら変更なし
- */
- public void submitBusyStatus(boolean isBusy, String message){
- Runnable task = () -> {
- setBusy(isBusy, message);
- };
-
- if(EventQueue.isDispatchThread()){
- task.run();
- }else{
- try{
- EventQueue.invokeAndWait(task);
- }catch(InvocationTargetException | InterruptedException e){
- LOGGER.log(Level.SEVERE, "ビジー処理で失敗", e);
- }
- }
-
- return;
- }
-
- /**
- * 軽量タスクをEDTで実行する。
- *
- * <p>タスク実行中はビジー状態となる。
- *
- * <p>軽量タスク実行中はイベントループが停止するので、
- * 入出力待ちを伴わなずに早急に終わるタスクでなければならない。
- *
- * @param task 軽量タスク
- * @param beforeMsg ビジー中ステータス文字列
- * @param afterMsg ビジー復帰時のステータス文字列
- */
- public void submitLightBusyTask(Runnable task,
- String beforeMsg,
- String afterMsg ){
- submitBusyStatus(true, beforeMsg);
- EventQueue.invokeLater(task);
- submitBusyStatus(false, afterMsg);
-
- return;
- }
-
- /**
- * 重量級タスクをEDTとは別のスレッドで実行する。
- *
- * <p>タスク実行中はビジー状態となる。
- *
- * @param heavyTask 重量級タスク
- * @param beforeMsg ビジー中ステータス文字列
- * @param afterMsg ビジー復帰時のステータス文字列
- */
- public void submitHeavyBusyTask(final Runnable heavyTask,
- final String beforeMsg,
- final String afterMsg ){
- submitBusyStatus(true, beforeMsg);
-
- EventQueue.invokeLater(() -> {
- fork(() -> {
- try{
- heavyTask.run();
- }finally{
- submitBusyStatus(false, afterMsg);
- }
- });
- });
-
- return;
- }
-
- /**
- * スレッドプールを用いて非EDTなタスクを投入する。
- *
- * @param task タスク
- */
- private void fork(Runnable task){
- this.executor.execute(task);
- return;
- }
-
- /**
* About画面を表示する。
*/
private void actionAbout(){
String className = this.actionManager.getSelectedLookAndFeel();
if(className == null) return;
- submitLightBusyTask(
+ this.busyStatus.submitLightBusyTask(
() -> {taskChangeLaF(className);},
"Look&Feelを更新中…",
"Look&Feelが更新されました"
});
};
- submitHeavyBusyTask(
+ this.busyStatus.submitHeavyBusyTask(
task,
"一括読み込み開始",
"一括読み込み完了"
* 一括検索処理。
*/
private void bulkSearch(){
- submitHeavyBusyTask(
+ this.busyStatus.submitHeavyBusyTask(
() -> {taskBulkSearch();},
null, null
);
* 全日程の一括ロード。
*/
private void actionLoadAllPeriod(){
- submitHeavyBusyTask(
+ this.busyStatus.submitHeavyBusyTask(
() -> {taskLoadAllPeriod();},
"一括読み込み開始",
"一括読み込み完了"
};
- submitHeavyBusyTask(
+ this.busyStatus.submitHeavyBusyTask(
task,
"ジャンプ先の読み込み中…",
null
if(result != JFileChooser.APPROVE_OPTION) return;
File selected = this.xmlFileChooser.getSelectedFile();
- submitHeavyBusyTask(() -> {
+ this.busyStatus.submitHeavyBusyTask(() -> {
Village village;
try{
* @param land 国
*/
private void submitReloadVillageList(final Land land){
- submitHeavyBusyTask(
+ this.busyStatus.submitHeavyBusyTask(
() -> {taskReloadVillageList(land);},
"村一覧を読み込み中…",
"村一覧の読み込み完了"
});
};
- submitHeavyBusyTask(
+ this.busyStatus.submitHeavyBusyTask(
task,
"会話の読み込み中",
"会話の表示が完了"
});
};
- submitHeavyBusyTask(
+ this.busyStatus.submitHeavyBusyTask(
task,
"村情報を読み込み中…",
"村情報の読み込み完了"
*/
@Override
public void actionPerformed(ActionEvent ev){
- if(this.isBusyNow) return;
+ if(this.busyStatus.isBusy()) return;
String cmd = ev.getActionCommand();
if(cmd == null) return;
}
};
- submitHeavyBusyTask(
+ this.busyStatus.submitHeavyBusyTask(
task,
"アンカーの展開中…",
null