1 |
/* ProgressMonitor.java -- |
/* ProgressMonitor.java -- |
2 |
Copyright (C) 2002, 2004 Free Software Foundation, Inc. |
Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
38 |
package javax.swing; |
package javax.swing; |
39 |
|
|
40 |
import java.awt.Component; |
import java.awt.Component; |
41 |
|
import java.awt.event.ActionListener; |
42 |
|
import java.awt.event.ActionEvent; |
43 |
|
|
44 |
/** |
/** |
45 |
* ProgressMonitor |
* <p>Using this class you can easily monitor tasks where you cannot |
46 |
* @author Andrew Selkirk |
* estimate the duration exactly.</p> |
47 |
* @version 1.0 |
* |
48 |
|
* <p>A ProgressMonitor instance waits until the first time setProgress |
49 |
|
* is called. When <code>millisToDecideToPopup</code> time elapsed the |
50 |
|
* instance estimates the duration until the whole operation is completed. |
51 |
|
* If this duration exceeds <code>millisToPopup</code> a non-modal dialog |
52 |
|
* with a message and a progress bar is shown.</p> |
53 |
|
* |
54 |
|
* <p>The value of <code>millisToDecideToPopup</code> defaults to |
55 |
|
* <code>500</code> and <code>millisToPopup</code> to |
56 |
|
* <code>2000</code>.</p> |
57 |
|
* |
58 |
|
* @author Andrew Selkirk |
59 |
|
* @author Robert Schuster (robertschuster@fsfe.org) |
60 |
|
* @since 1.2 |
61 |
|
* @status updated to 1.2 |
62 |
*/ |
*/ |
63 |
public class ProgressMonitor |
public class ProgressMonitor |
64 |
{ |
{ |
65 |
/** |
/** |
66 |
* parentComponent |
* parentComponent |
67 |
*/ |
*/ |
68 |
private Component component; |
Component component; |
69 |
|
|
70 |
/** |
/** |
71 |
* note |
* note |
72 |
*/ |
*/ |
73 |
private String note; |
String note; |
74 |
|
|
75 |
/** |
/** |
76 |
* message |
* message |
77 |
*/ |
*/ |
78 |
private Object message; |
Object message; |
79 |
|
|
80 |
/** |
/** |
81 |
* millisToDecideToPopup |
* millisToDecideToPopup |
82 |
*/ |
*/ |
83 |
private int millisToDecideToPopup; |
int millisToDecideToPopup = 500; |
84 |
|
|
85 |
/** |
/** |
86 |
* millisToPopup |
* millisToPopup |
87 |
*/ |
*/ |
88 |
private int millisToPopup; |
int millisToPopup = 2000; |
89 |
|
|
90 |
/** |
int min, max, progress; |
|
* min |
|
|
*/ |
|
|
private int minimum; |
|
91 |
|
|
92 |
/** |
JProgressBar progressBar; |
93 |
* max |
|
94 |
*/ |
JLabel noteLabel; |
95 |
private int maximum; |
|
96 |
|
JDialog progressDialog; |
97 |
|
|
98 |
|
Timer timer; |
99 |
|
|
100 |
|
boolean canceled; |
101 |
|
|
102 |
/** |
/** |
103 |
* Constructor ProgressMonitor |
* Constructor ProgressMonitor |
104 |
* @param component TODO |
* @param component The parent component of the progress dialog or <code>null</code>. |
105 |
* @param message TODO |
* @param message A constant message object which works in the way it does in <code>JOptionPane</code>. |
106 |
* @param note TODO |
* @param note A string message which can be changed while the operation goes on. |
107 |
* @param minimum TODO |
* @param minimum The minimum value for the operation (start value). |
108 |
* @param maximum TODO |
* @param maximum The maximum value for the operation (end value). |
109 |
*/ |
*/ |
110 |
public ProgressMonitor(Component component, Object message, |
public ProgressMonitor(Component component, Object message, |
111 |
String note, int minimum, int maximum) |
String note, int minimum, int maximum) |
115 |
this.component = component; |
this.component = component; |
116 |
this.message = message; |
this.message = message; |
117 |
this.note = note; |
this.note = note; |
|
this.minimum = minimum; |
|
|
this.maximum = maximum; |
|
118 |
|
|
119 |
// TODO |
min = minimum; |
120 |
|
max = maximum; |
121 |
} |
} |
122 |
|
|
123 |
/** |
/** |
124 |
* close |
* <p>Hides the dialog and stops any measurements.</p> |
125 |
|
* |
126 |
|
* <p>Has no effect when <code>setProgress</code> is not at least |
127 |
|
* called once.</p> |
128 |
*/ |
*/ |
129 |
public void close() |
public void close() |
130 |
{ |
{ |
131 |
// TODO |
if ( progressDialog != null ) |
132 |
|
{ |
133 |
|
progressDialog.setVisible(false); |
134 |
|
} |
135 |
|
|
136 |
|
if ( timer != null ) |
137 |
|
{ |
138 |
|
timer.stop(); |
139 |
|
timer = null; |
140 |
|
} |
141 |
} |
} |
142 |
|
|
143 |
/** |
/** |
144 |
* setProgress |
* <p>Updates the progress value.</p> |
145 |
* @param progress TODO |
* |
146 |
|
* <p>When called for the first time this initializes a timer |
147 |
|
* which decides after <code>millisToDecideToPopup</code> time |
148 |
|
* whether to show a progress dialog or not.</p> |
149 |
|
* |
150 |
|
* <p>If the progress value equals or exceeds the maximum |
151 |
|
* value the progress dialog is closed automatically.</p> |
152 |
|
* |
153 |
|
* @param progress New progress value. |
154 |
*/ |
*/ |
155 |
public void setProgress(int progress) |
public void setProgress(int progress) |
156 |
{ |
{ |
157 |
// TODO |
this.progress = progress; |
158 |
|
|
159 |
|
// Initializes and starts a timer with a task |
160 |
|
// which measures the duration and displays |
161 |
|
// a progress dialog if neccessary. |
162 |
|
if ( timer == null && progressDialog == null ) |
163 |
|
{ |
164 |
|
timer = new Timer(25, null); |
165 |
|
timer.addActionListener(new TimerListener()); |
166 |
|
timer.start(); |
167 |
|
} |
168 |
|
|
169 |
|
// Cancels timer and hides progress dialog if the |
170 |
|
// maximum value is reached. |
171 |
|
if ( progressBar != null && this.progress >= progressBar.getMaximum() ) |
172 |
|
{ |
173 |
|
// The reason for using progressBar.getMaximum() instead of max is that |
174 |
|
// we want to prevent that changes to the value have any effect after the |
175 |
|
// progress dialog is visible (This is how the JDK behaves.). |
176 |
|
close(); |
177 |
|
} |
178 |
|
|
179 |
} |
} |
180 |
|
|
181 |
/** |
/** Returns the minimum or start value of the operation. |
182 |
* getMinimum |
* |
183 |
* @returns int |
* @returns Minimum or start value of the operation. |
184 |
*/ |
*/ |
185 |
public int getMinimum() |
public int getMinimum() |
186 |
{ |
{ |
187 |
return minimum; // TODO |
return min; |
188 |
} |
} |
189 |
|
|
190 |
/** |
/** |
191 |
* setMinimum |
* <p>Use this method to set the minimum or start value of |
192 |
* @param minimum TODO |
* your operation.</p> |
193 |
|
* |
194 |
|
* <p>For typical application like copy operation this will be |
195 |
|
* zero.</p> |
196 |
|
* |
197 |
|
* <p>Keep in mind that changing this value after the progress |
198 |
|
* dialog is made visible has no effect upon the progress bar.</p> |
199 |
|
* |
200 |
|
* @param minimum The new minimum value. |
201 |
*/ |
*/ |
202 |
public void setMinimum(int minimum) |
public void setMinimum(int minimum) |
203 |
{ |
{ |
204 |
this.minimum = minimum; |
min = minimum; |
|
// TODO |
|
205 |
} |
} |
206 |
|
|
207 |
/** |
/** |
208 |
* getMaximum |
* Return the maximum or end value of your operation. |
209 |
* @returns int |
* |
210 |
|
* @returns Maximum or end value. |
211 |
*/ |
*/ |
212 |
public int getMaximum() |
public int getMaximum() |
213 |
{ |
{ |
214 |
return maximum; // TODO |
return max; |
215 |
} |
} |
216 |
|
|
217 |
/** |
/** |
218 |
* setMaximum |
* <p>Sets the maximum or end value of the operation to the |
219 |
* @param maximum TODO |
* given integer.</p> |
220 |
|
* |
221 |
|
* @param maximum |
222 |
*/ |
*/ |
223 |
public void setMaximum(int maximum) |
public void setMaximum(int maximum) |
224 |
{ |
{ |
225 |
this.maximum = maximum; |
max = maximum; |
|
// TODO |
|
226 |
} |
} |
227 |
|
|
228 |
/** |
/** |
229 |
* isCanceled |
* Returns whether the user canceled the operation. |
230 |
* @returns boolean |
* |
231 |
|
* @returns Whether the operation was canceled. |
232 |
*/ |
*/ |
233 |
public boolean isCanceled() |
public boolean isCanceled() |
234 |
{ |
{ |
235 |
return false; // TODO |
// The value is predefined to false |
236 |
|
// and changes only when the user clicks |
237 |
|
// the cancel button in the progress dialog. |
238 |
|
return canceled; |
239 |
} |
} |
240 |
|
|
241 |
/** |
/** |
242 |
* getMillisToDecideToPopup |
* Returns the amount of milliseconds to wait |
243 |
* @returns int |
* until the ProgressMonitor should decide whether |
244 |
|
* a progress dialog is to be shown or not. |
245 |
|
* |
246 |
|
* @returns The duration in milliseconds. |
247 |
*/ |
*/ |
248 |
public int getMillisToDecideToPopup() |
public int getMillisToDecideToPopup() |
249 |
{ |
{ |
250 |
return millisToDecideToPopup; // TODO |
return millisToDecideToPopup; |
251 |
} |
} |
252 |
|
|
253 |
/** |
/** |
254 |
* setMillisToDecideToPopup |
* Sets the amount of milliseconds to wait until the |
255 |
* @param time TODO |
* ProgressMonitor should decide whether a progress dialog |
256 |
|
* is to be shown or not. |
257 |
|
* |
258 |
|
* <p>This method has no effect when the progress dialog |
259 |
|
* is already visible.</p> |
260 |
|
* |
261 |
|
* @param time The duration in milliseconds. |
262 |
*/ |
*/ |
263 |
public void setMillisToDecideToPopup(int time) |
public void setMillisToDecideToPopup(int time) |
264 |
{ |
{ |
265 |
millisToDecideToPopup = time; |
millisToDecideToPopup = time; |
|
// TODO |
|
266 |
} |
} |
267 |
|
|
268 |
/** |
/** |
271 |
*/ |
*/ |
272 |
public int getMillisToPopup() |
public int getMillisToPopup() |
273 |
{ |
{ |
274 |
return millisToPopup; // TODO |
return millisToPopup; |
275 |
} |
} |
276 |
|
|
277 |
/** |
/** |
281 |
public void setMillisToPopup(int time) |
public void setMillisToPopup(int time) |
282 |
{ |
{ |
283 |
millisToPopup = time; |
millisToPopup = time; |
|
// TODO |
|
284 |
} |
} |
285 |
|
|
286 |
/** |
/** |
287 |
* getNote |
* Returns a message which is shown in the progress dialog. |
288 |
* @returns String |
* |
289 |
|
* @returns The changeable message visible in the progress dialog. |
290 |
*/ |
*/ |
291 |
public String getNote() |
public String getNote() |
292 |
{ |
{ |
293 |
return note; // TODO |
return note; |
294 |
} |
} |
295 |
|
|
296 |
/** |
/** |
297 |
* setNote |
* <p>Set the message shown in the progess dialog.</p> |
298 |
* @param note TODO |
* |
299 |
|
* <p>Changing the note while the progress dialog is visible |
300 |
|
* is possible.</p> |
301 |
|
* |
302 |
|
* @param note A message shown in the progress dialog. |
303 |
*/ |
*/ |
304 |
public void setNote(String note) |
public void setNote(String note) |
305 |
{ |
{ |
306 |
this.note = note; |
if ( noteLabel != null ) |
307 |
// TODO |
{ |
308 |
|
noteLabel.setText(note); |
309 |
|
} |
310 |
|
else |
311 |
|
{ |
312 |
|
this.note = note; |
313 |
|
} |
314 |
|
} |
315 |
|
|
316 |
|
/** Internal method that creates the progress dialog. |
317 |
|
*/ |
318 |
|
void createDialog() |
319 |
|
{ |
320 |
|
// If there is no note we suppress the generation of the |
321 |
|
// label. |
322 |
|
Object[] tmp = (note == null) ? |
323 |
|
new Object[] |
324 |
|
{ |
325 |
|
message, |
326 |
|
progressBar = new JProgressBar(min, max) |
327 |
|
} |
328 |
|
: |
329 |
|
new Object[] |
330 |
|
{ |
331 |
|
message, |
332 |
|
noteLabel = new JLabel(note), |
333 |
|
progressBar = new JProgressBar(min, max) |
334 |
|
}; |
335 |
|
|
336 |
|
JOptionPane pane = new JOptionPane(tmp, JOptionPane.INFORMATION_MESSAGE); |
337 |
|
|
338 |
|
// FIXME: Internationalize the button |
339 |
|
JButton cancelButton = new JButton("Cancel"); |
340 |
|
cancelButton.addActionListener(new ActionListener() |
341 |
|
{ |
342 |
|
public void actionPerformed(ActionEvent ae) |
343 |
|
{ |
344 |
|
canceled = true; |
345 |
|
} |
346 |
|
}); |
347 |
|
|
348 |
|
pane.setOptions(new Object[] { cancelButton }); |
349 |
|
|
350 |
|
// FIXME: Internationalize the title |
351 |
|
progressDialog = pane.createDialog(component, "Progress ..."); |
352 |
|
progressDialog.setModal(false); |
353 |
|
progressDialog.setResizable(true); |
354 |
|
|
355 |
|
progressDialog.pack(); |
356 |
|
progressDialog.setVisible(true); |
357 |
|
|
358 |
|
} |
359 |
|
|
360 |
|
/** An ActionListener implementation which does the measurements |
361 |
|
* and estimations of the ProgressMonitor. |
362 |
|
*/ |
363 |
|
class TimerListener implements ActionListener |
364 |
|
{ |
365 |
|
long timestamp; |
366 |
|
|
367 |
|
int lastProgress; |
368 |
|
|
369 |
|
boolean first = true; |
370 |
|
|
371 |
|
TimerListener() |
372 |
|
{ |
373 |
|
timestamp = System.currentTimeMillis(); |
374 |
|
} |
375 |
|
|
376 |
|
public void actionPerformed(ActionEvent ae) |
377 |
|
{ |
378 |
|
long now = System.currentTimeMillis(); |
379 |
|
|
380 |
|
if ( first ) |
381 |
|
{ |
382 |
|
if (( now - timestamp ) > millisToDecideToPopup ) |
383 |
|
{ |
384 |
|
first = false; |
385 |
|
long expected = ( now - timestamp ) * ( max - min ) / ( progress - min ); |
386 |
|
|
387 |
|
if ( expected > millisToPopup ) |
388 |
|
{ |
389 |
|
createDialog(); |
390 |
|
} |
391 |
|
} |
392 |
|
else |
393 |
|
{ |
394 |
|
// We have not waited long enough to make a decision, |
395 |
|
// so return and try again when the timer is invoked. |
396 |
|
return; |
397 |
|
} |
398 |
|
} |
399 |
|
else if ( progressDialog != null ) |
400 |
|
{ |
401 |
|
// The progress dialog is being displayed. We now calculate |
402 |
|
// whether setting the progress bar to the current progress |
403 |
|
// value would result in a visual difference. |
404 |
|
int delta = progress - progressBar.getValue(); |
405 |
|
|
406 |
|
if ( ( delta * progressBar.getWidth() / (max - min) ) > 0 ) |
407 |
|
{ |
408 |
|
// At least one pixel would change. |
409 |
|
progressBar.setValue(progress); |
410 |
|
} |
411 |
|
} |
412 |
|
else |
413 |
|
{ |
414 |
|
// No dialog necessary |
415 |
|
timer.stop(); |
416 |
|
timer = null; |
417 |
|
} |
418 |
|
|
419 |
|
timestamp = now; |
420 |
|
} |
421 |
} |
} |
422 |
|
|
423 |
} |
} |