Source code: com/virtuosotechnologies/lib/swing/ModalProgressTracker.java
1 /*
2 ================================================================================
3
4 FILE: ModalProgressTracker.java
5
6 PROJECT:
7
8 Virtuoso Utilities
9
10 CONTENTS:
11
12 An object that spawns a modal progress tracker dialog for AsyncJobs
13
14 PROGRAMMERS:
15
16 Daniel Azuma (DA) <dazuma@kagi.com>
17
18 COPYRIGHT:
19
20 Copyright (C) 2003 Daniel Azuma (dazuma@kagi.com)
21
22 This program is free software; you can redistribute it and/or
23 modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2
25 of the License, or (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public
33 License along with this program; if not, write to
34 Free Software Foundation, Inc.
35 59 Temple Place, Suite 330
36 Boston, MA 02111-1307 USA
37
38 ================================================================================
39 */
40
41
42 package com.virtuosotechnologies.lib.swing;
43
44
45 import java.awt.Container;
46 import java.awt.Dialog;
47 import java.awt.Frame;
48 import java.awt.Rectangle;
49 import java.awt.GridBagLayout;
50 import java.awt.GridBagConstraints;
51 import java.awt.event.ActionListener;
52 import java.awt.event.ActionEvent;
53 import java.util.Map;
54 import java.util.HashMap;
55 import java.util.Iterator;
56 import javax.swing.Timer;
57 import javax.swing.JComponent;
58 import javax.swing.JDialog;
59 import javax.swing.JPanel;
60 import javax.swing.JScrollPane;
61 import javax.swing.SwingUtilities;
62
63 import com.virtuosotechnologies.lib.asyncjob.AsyncJobListener;
64 import com.virtuosotechnologies.lib.asyncjob.AsyncJobProgressEvent;
65 import com.virtuosotechnologies.lib.asyncjob.AsyncJobStartedEvent;
66 import com.virtuosotechnologies.lib.asyncjob.AsyncJobEvent;
67 import com.virtuosotechnologies.lib.asyncjob.AsyncJobCompletedEvent;
68 import com.virtuosotechnologies.lib.asyncjob.AsyncJobFailedEvent;
69 import com.virtuosotechnologies.lib.asyncjob.AsyncJob;
70
71
72 /**
73 * An object that spawns a modal progress tracker dialog for AsyncJobs.
74 *
75 * @author Daniel Azuma
76 */
77 public class ModalProgressTracker
78 implements AsyncJobListener
79 {
80 private static class JobInfo
81 {
82 ProgressTrackingPane pane;
83 AsyncJobProgressEvent lastProgress;
84
85 private JobInfo()
86 {
87 pane = null;
88 lastProgress = null;
89 }
90 }
91
92
93 private static final int INITIAL_DIALOG_WIDTH = 300;
94 private static final int INITIAL_DIALOG_HEIGHT = 150;
95 private static final int DEFAULT_UPDATE_INTERVAL = 100;
96
97
98 private JDialog dialog_;
99 private int dialogWidth_;
100 private int dialogHeight_;
101 private JComponent dialogContent_;
102 private JComponent dialogParent_;
103
104 private Map jobInfoMap_;
105 private JPanel innerPanel_;
106 private GridBagConstraints paneConstraints_;
107 private Timer timer_;
108
109
110 /**
111 * Constructor
112 */
113 public ModalProgressTracker(
114 JComponent parent)
115 {
116 this(parent, DEFAULT_UPDATE_INTERVAL, INITIAL_DIALOG_WIDTH, INITIAL_DIALOG_HEIGHT);
117 }
118
119
120 /**
121 * Constructor
122 */
123 public ModalProgressTracker(
124 JComponent parent,
125 int updateIntervalMillis)
126 {
127 this(parent, updateIntervalMillis, INITIAL_DIALOG_WIDTH, INITIAL_DIALOG_HEIGHT);
128 }
129
130
131 /**
132 * Constructor
133 */
134 public ModalProgressTracker(
135 JComponent parent,
136 int updateIntervalMillis,
137 int initialDialogWidth,
138 int initialDialogHeight)
139 {
140 dialogParent_ = parent;
141 dialogWidth_ = initialDialogWidth;
142 dialogHeight_ = initialDialogHeight;
143
144 jobInfoMap_ = new HashMap();
145 timer_ = new Timer(updateIntervalMillis,
146 new ActionListener()
147 {
148 public void actionPerformed(
149 ActionEvent ev)
150 {
151 doTimer();
152 }
153 });
154
155 innerPanel_ = new JPanel(new GridBagLayout());
156 paneConstraints_ = new GridBagConstraints();
157 paneConstraints_.gridx = 0;
158 paneConstraints_.weightx = 1.0;
159 paneConstraints_.weighty = 0.0;
160 paneConstraints_.fill = GridBagConstraints.HORIZONTAL;
161
162 JPanel outerPanel = new JPanel(new GridBagLayout());
163 GridBagConstraints gbc = new GridBagConstraints();
164 gbc.anchor = GridBagConstraints.NORTH;
165 gbc.fill = GridBagConstraints.HORIZONTAL;
166 gbc.weightx = 1.0;
167 gbc.weighty = 1.0;
168 outerPanel.add(innerPanel_, gbc);
169
170 dialogContent_ = new JScrollPane(outerPanel);
171 }
172
173
174 private void openDialog()
175 {
176 Container toplevel = dialogParent_.getTopLevelAncestor();
177 if (toplevel instanceof Dialog)
178 {
179 dialog_ = new JDialog((Dialog)toplevel, ResourceAccess.Strings.buildString(
180 "ProgressTracker_DialogName"), true);
181 }
182 else if (toplevel instanceof Frame)
183 {
184 dialog_ = new JDialog((Frame)toplevel, ResourceAccess.Strings.buildString(
185 "ProgressTracker_DialogName"), true);
186 }
187 else
188 {
189 // Bail
190 return;
191 }
192
193 dialog_.setContentPane(dialogContent_);
194 dialog_.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
195 dialog_.setSize(dialogWidth_, dialogHeight_);
196 dialog_.setLocationRelativeTo(dialogParent_);
197 dialog_.show();
198 }
199
200
201 private void closeDialog()
202 {
203 if (dialog_.getWidth() > 100)
204 {
205 dialogWidth_ = dialog_.getWidth();
206 }
207 if (dialog_.getHeight() > 50)
208 {
209 dialogHeight_ = dialog_.getHeight();
210 }
211 dialog_.dispose();
212 dialog_ = null;
213 }
214
215
216 /**
217 * A job has started
218 *
219 * @param event AsyncJobStartedEvent
220 */
221 public void jobStarted(
222 AsyncJobStartedEvent event)
223 {
224 final AsyncJob job = event.getAsyncJob();
225 final JobInfo info = new JobInfo();
226 synchronized(this)
227 {
228 jobInfoMap_.put(job, info);
229 }
230
231 SwingUtilities.invokeLater(
232 new Runnable()
233 {
234 public void run()
235 {
236 synchronized(ModalProgressTracker.this)
237 {
238 info.pane = new ProgressTrackingPane(job);
239 }
240 innerPanel_.add(info.pane, paneConstraints_);
241 if (innerPanel_.getComponentCount() == 1)
242 {
243 timer_.start();
244 openDialog();
245 }
246 }
247 });
248 }
249
250
251 /**
252 * Receive a progress update
253 *
254 * @param event AsyncJobProgressEvent
255 */
256 public synchronized void jobProgressed(
257 final AsyncJobProgressEvent event)
258 {
259 final JobInfo info = (JobInfo)jobInfoMap_.get(event.getAsyncJob());
260 if (info != null)
261 {
262 info.lastProgress = event;
263 }
264 }
265
266
267 /**
268 * A job has completed
269 *
270 * @param event AsyncJobCompletedEvent
271 */
272 public void jobCompleted(
273 AsyncJobCompletedEvent event)
274 {
275 closePane(event);
276 }
277
278
279 /**
280 * A job has failed
281 *
282 * @param event AsyncJobFailedEvent
283 */
284 public void jobFailed(
285 AsyncJobFailedEvent event)
286 {
287 closePane(event);
288 }
289
290
291 private synchronized void closePane(
292 AsyncJobEvent event)
293 {
294 final JobInfo info = (JobInfo)jobInfoMap_.remove(event.getAsyncJob());
295 SwingUtilities.invokeLater(
296 new Runnable()
297 {
298 public void run()
299 {
300 innerPanel_.remove(info.pane);
301 if (innerPanel_.getComponentCount() == 0)
302 {
303 timer_.stop();
304 closeDialog();
305 }
306 }
307 });
308 }
309
310
311 private synchronized void doTimer()
312 {
313 for (Iterator iter = jobInfoMap_.entrySet().iterator(); iter.hasNext(); )
314 {
315 Map.Entry entry = (Map.Entry)iter.next();
316 AsyncJob job = (AsyncJob)entry.getKey();
317 JobInfo info = (JobInfo)entry.getValue();
318 if (info.pane != null && info.lastProgress != null)
319 {
320 info.pane.jobProgressed(info.lastProgress);
321 }
322 }
323 }
324 }