OSDN Git Service

dmg作成バージョンの取得方法の修正
[charactermanaj/CharacterManaJ.git] / src / main / java / charactermanaj / ui / progress / WorkerWithProgessDialog.java
1 package charactermanaj.ui.progress;\r
2 \r
3 import java.awt.BorderLayout;\r
4 import java.awt.Component;\r
5 import java.awt.Container;\r
6 import java.awt.Dimension;\r
7 import java.awt.event.ActionEvent;\r
8 import java.awt.event.ActionListener;\r
9 import java.lang.Thread.UncaughtExceptionHandler;\r
10 \r
11 import javax.swing.BorderFactory;\r
12 import javax.swing.JDialog;\r
13 import javax.swing.JFrame;\r
14 import javax.swing.JLabel;\r
15 import javax.swing.JProgressBar;\r
16 import javax.swing.JRootPane;\r
17 import javax.swing.SwingUtilities;\r
18 import javax.swing.Timer;\r
19 import javax.swing.border.BevelBorder;\r
20 \r
21 \r
22 /**\r
23  * ワーカースレッドの実行中、プログレスを表示するモーダルダイアログ.<br>\r
24  * ワーカースレッドの実行が完了するとダイアログは自動的に閉じられる.<br>\r
25  * モーダルダイアログであるため、ワーカースレッドの実行中はユーザはUIを操作することはできない.<br>\r
26  * @author seraphy\r
27  *\r
28  * @param <T> ワーカーの処理結果の戻り値の型\r
29  */\r
30 public class WorkerWithProgessDialog<T> extends JDialog {\r
31 \r
32         private static final long serialVersionUID = 1L;\r
33 \r
34         /**\r
35          * ワーカースレッドが停止したことを示すフラグ\r
36          */\r
37         private volatile boolean exitThread;\r
38         \r
39         /**\r
40          * ワーカースレッドの戻り値\r
41          */\r
42         private volatile T result;\r
43         \r
44         /**\r
45          * ワーカースレッドが例外により終了した場合の例外\r
46          */\r
47         private volatile Throwable occuredException;\r
48         \r
49         /**\r
50          * ワーカースレッド\r
51          */\r
52         private Thread thread;\r
53         \r
54         /**\r
55          * ワーカースレッドの状態を監視しプログレスに反映させるタイマー\r
56          */\r
57         private Timer timer;\r
58         \r
59         /**\r
60          * プログレスの更新頻度(タイマーのインターバル)\r
61          */\r
62         private static int interval = 200;\r
63         \r
64 \r
65         /**\r
66          * 親フレームとワーカーを指定して構築する.<br>\r
67          * @param parent 親フレーム\r
68          * @param worker ワーカー\r
69          */\r
70         public WorkerWithProgessDialog(JFrame parent, Worker<T> worker) {\r
71                 super(parent, true);\r
72                 try {\r
73                         if (worker == null) {\r
74                                 throw new IllegalArgumentException();\r
75                         }\r
76                         \r
77                         initComponent(parent, worker);\r
78                         \r
79                 } catch (RuntimeException ex) {\r
80                         dispose();\r
81                         throw ex;\r
82                 }\r
83         }\r
84         \r
85         /**\r
86          * 親ダイアログとワーカーを指定して構築する.<br>\r
87          * @param parent 親フレーム\r
88          * @param worker ワーカー\r
89          */\r
90         public WorkerWithProgessDialog(JDialog parent, Worker<T> worker) {\r
91                 super(parent, true);\r
92                 try {\r
93                         if (worker == null) {\r
94                                 throw new IllegalArgumentException();\r
95                         }\r
96                         \r
97                         initComponent(parent, worker);\r
98                         \r
99                 } catch (RuntimeException ex) {\r
100                         dispose();\r
101                         throw ex;\r
102                 }\r
103         }\r
104 \r
105         /**\r
106          * コンポーネントの初期化\r
107          * @param parent 親フレームまたは親ダイアログ\r
108          * @param worker ワーカー\r
109          */\r
110         private void initComponent(Component parent, Worker<T> worker) {\r
111                 // 閉じるボタンは無効\r
112                 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);\r
113 \r
114                 // リサイズ不可\r
115                 setResizable(false);\r
116                 // ウィンドウ装飾なし (閉じるボタンやタイトルバーなども無し)\r
117                 setUndecorated(true);\r
118 \r
119                 Container container = getContentPane();\r
120 \r
121                 // プログレスバー\r
122                 final JProgressBar progressBar = new JProgressBar();\r
123                 progressBar.setIndeterminate(true);\r
124                 progressBar.setStringPainted(false);\r
125                 \r
126                 container.add(progressBar, BorderLayout.SOUTH);\r
127                 \r
128                 // デフォルトのラベル表示 \r
129                 String title = "please wait for a while.";\r
130                 final JLabel lblCaption = new JLabel(title);\r
131                 container.add(lblCaption, BorderLayout.NORTH);\r
132 \r
133                 // ウィンドウ枠\r
134                 JRootPane rootPane = getRootPane();\r
135                 rootPane.setBorder(BorderFactory.createCompoundBorder(\r
136                                 BorderFactory.createBevelBorder(BevelBorder.RAISED),\r
137                                 BorderFactory.createEmptyBorder(5, 5, 5, 5))\r
138                                 );\r
139 \r
140                 // 親ウィンドウの幅の70%\r
141                 Dimension dim = progressBar.getPreferredSize();\r
142                 dim.width = (int)(parent.getWidth() * 0.7);\r
143                 progressBar.setPreferredSize(dim);\r
144 \r
145                 // パックする.\r
146                 pack();\r
147                 \r
148                 // 親の中央に表示\r
149                 setLocationRelativeTo(parent);\r
150 \r
151                 // ワーカースレッドとプログレスダイアログとの状態通信用オブジェクト\r
152                 final ProgressInfoHolder progressHandle = new ProgressInfoHolder() {\r
153                         @Override\r
154                         public synchronized void flush() {\r
155                                 final String caption = getCaption();\r
156                                 final Boolean indeterminate = getIndeterminate();\r
157                                 final Integer progressMaximum = getProgressMaximum();\r
158                                 final Integer progressCurrent = getProgressCurrent();\r
159 \r
160                                 if (caption != null || progressMaximum != null ||\r
161                                                 progressCurrent != null || indeterminate != null) {\r
162                                         SwingUtilities.invokeLater(new Runnable() {\r
163                                                 public void run() {\r
164                                                         // 設定されている値でプログレスダイアログに状態を反映する.\r
165                                                         if (caption != null) {\r
166                                                                 lblCaption.setText(caption);\r
167                                                         }\r
168                                                         if (progressMaximum != null) {\r
169                                                                 progressBar.setMaximum(progressMaximum.intValue());\r
170                                                         }\r
171                                                         if (progressCurrent != null) {\r
172                                                                 progressBar.setValue(progressCurrent.intValue());\r
173                                                         }\r
174                                                         if (indeterminate != null) {\r
175                                                                 progressBar.setIndeterminate(indeterminate.booleanValue());\r
176                                                                 progressBar.setStringPainted( !indeterminate.booleanValue());\r
177                                                         }\r
178                                                 }\r
179                                         });\r
180                                 }\r
181                                 \r
182                                 super.flush();\r
183                         }\r
184                 };\r
185                 \r
186                 // プログレスダイアログに状態を反映させるためのタイマー\r
187                 timer = new Timer(interval, new ActionListener() {\r
188                         public void actionPerformed(ActionEvent e) {\r
189                                 if (exitThread || !thread.isAlive()) {\r
190                                         // スレッドが終了していればスレッド停止を通知する.\r
191                                         onExitWork();\r
192 \r
193                                 } else {\r
194                                         // スレッドが生きていれば、スレッドの進行状態を\r
195                                         // プログレスダイアログに反映させる.\r
196                                         progressHandle.flush();\r
197                                 }\r
198                         }\r
199                 });\r
200 \r
201                 // ワーカースレッドの構築.\r
202                 thread = new Thread(createJob(worker, progressHandle));\r
203                 thread.setDaemon(true);\r
204 \r
205                 // ワーカースレッドが予期せぬハンドルされていない例外により終了した場合のハンドラ.\r
206                 thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {\r
207                         public void uncaughtException(Thread t, Throwable e) {\r
208                                 occuredException = e;\r
209                                 onExitWork();\r
210                         }\r
211                 });\r
212         }\r
213         \r
214         /**\r
215          * プログレスの表示間隔を取得する\r
216          * @return 表示間隔\r
217          */\r
218         public static int getInterval() {\r
219                 return interval;\r
220         }\r
221 \r
222         /**\r
223          * プログレスの表示間隔を設定する\r
224          * @param interval 表示間隔\r
225          */\r
226         public static void setInterval(int interval) {\r
227                 WorkerWithProgessDialog.interval = interval;\r
228         }\r
229 \r
230 \r
231         /**\r
232          * ワーカーをラップするワーカースレッドのジョブを作成する.<br>\r
233          * @param worker ワーカー\r
234          * @param progressHandle 進行状態の通知ハンドル\r
235          * @return ジョブ\r
236          */\r
237         protected Runnable createJob(final Worker<T> worker, final ProgressHandle progressHandle) {\r
238                 return new Runnable() {\r
239                         public void run() {\r
240                                 try {\r
241                                         try {\r
242                                                 worker.doWork(progressHandle);\r
243 \r
244                                         } catch (Throwable ex) {\r
245                                                 occuredException = ex;\r
246                                         }\r
247 \r
248                                 } finally {\r
249                                         onExitWork();\r
250                                 }\r
251                         }\r
252                 };\r
253         }\r
254         \r
255         /**\r
256          * ワーカースレッドより、スレッドが終了したことを通知される.<br>\r
257          * ワーカースレッド自身か、ワーカースレッドの例外ハンドラか、\r
258          * タイマーから呼び出されるため、2回以上呼び出される可能性がある.<br>\r
259          */\r
260         protected void onExitWork() {\r
261                 exitThread = true;\r
262                 SwingUtilities.invokeLater(new Runnable() {\r
263                         public void run() {\r
264                                 // プログレスダイアログが表示されている場合、\r
265                                 // それを破棄する.(モーダルの解除)\r
266                                 if (isDisplayable() && isVisible()) {\r
267                                         dispose();\r
268                                 }\r
269                         }\r
270                 });\r
271         }\r
272         \r
273         /**\r
274          * ワーカースレッドを開始し、プログレスダイアログを表示し、\r
275          * ワーカースレッドの完了まで待機する.<br>\r
276          * @throws WorkerException ワーカースレッドが例外により終了した場合\r
277          */\r
278         public void startAndWait() throws WorkerException {\r
279                 // 初期化\r
280                 result = null;\r
281                 occuredException = null;\r
282                 exitThread = false;\r
283                 \r
284                 // ワーカースレッドの開始\r
285                 thread.start();\r
286                 try {\r
287                         timer.start();\r
288                         try {\r
289                                 // モーダルダイアログの開始\r
290                                 // (モーダルダイアログが非表示されるまで制御を返さない.)\r
291                                 setVisible(true);\r
292 \r
293                         } finally {\r
294                                 timer.stop();\r
295                         }\r
296 \r
297                 } finally {\r
298                         for (;;) {\r
299                                 try {\r
300                                         // ワーカースレッドの停止を待機する.\r
301                                         thread.join();\r
302                                         break;\r
303 \r
304                                 } catch (InterruptedException ex) {\r
305                                         // 割り込みされた場合は、ワーカースレッドを割り込みする.\r
306                                         thread.interrupt();\r
307                                 }\r
308                         }\r
309                 }\r
310 \r
311                 // ワーカースレッドが例外により終了した場合\r
312                 // その例外を送出する.\r
313                 if (occuredException != null) {\r
314                         throw new WorkerException(\r
315                                         "worker has failed." + occuredException.getMessage(),\r
316                                         occuredException\r
317                                         );\r
318                 }\r
319         }\r
320 \r
321         /**\r
322          * ワーカースレッドの戻り値を取得する.<br>\r
323          * 正常終了していない場合、または処理中の場合は意味を持たない.<br>\r
324          * @return ワーカースレッドの戻り値\r
325          */\r
326         public T getResult() {\r
327                 return result;\r
328         }\r
329 }\r