2020 *
2121 * Whereas a standard SwingWorker would execute done() long before the
2222 * asynchronous task completed, this class will wait until progress has been
23- * asynchronously set to 100 or the task is cancelled before executing that
24- * method.
23+ * asynchronously set greater or equal to its max value or the task is canceled
24+ * before executing that method.
2525 *
2626 * Three methods must be supplied by the subclass:
2727 *
3131 *
3232 * void doneAsync()
3333 *
34- * Both initAsync() and doneAsync() are technically optional - they may be empty.
35- * doInBackgroundAsync(), however, is the key method where, like SwingWorker's
36- * doInBackground, the main work is done. The supplied progress parameter
37- * reminds the subclass of where it is at, and the return value allows the
38- * subclass to update the progress field in both the SwingWorker and the
34+ * Both initAsync() and doneAsync() are technically optional - they may be
35+ * empty. doInBackgroundAsync(), however, is the key method where, like
36+ * SwingWorker's doInBackground, the main work is done. The supplied progress
37+ * parameter reminds the subclass of where it is at, and the return value allows
38+ * the subclass to update the progress field in both the SwingWorker and the
3939 * ProgressMonitor.
4040 *
4141 *
4545public abstract class AsyncSwingWorker extends SwingWorker <Void , Void > implements StateMachine {
4646
4747
48- protected int progress = 0 ;
48+ public static final String DONE_ASYNC = "DONE_ASYNC" ;
49+ public static final String CANCELED_ASYNC = "CANCELED_ASYNC" ;
50+
51+ protected int progressAsync ;
4952
5053 /**
5154 * Override to provide initial tasks.
@@ -54,23 +57,26 @@ public abstract class AsyncSwingWorker extends SwingWorker<Void, Void> implement
5457
5558 /**
5659 * Given the last progress, do some portion of the task that the SwingWorker would do in the background, and return the new progress.
57- * returning 100 will complete the task.
60+ * returning max or above will complete the task.
5861 *
5962 * @param progress
6063 * @return new progress
6164 */
6265 abstract public int doInBackgroundAsync (int progress );
6366
6467 /**
65- * Do something when the task is finished or cancelled .
68+ * Do something when the task is finished or canceled .
6669 *
6770 */
6871 abstract public void doneAsync ();
6972
7073
71- private ProgressMonitor progressMonitor ;
72- private int delayMillis ;
73- private String note ;
74+ protected ProgressMonitor progressMonitor ;
75+ protected int delayMillis ;
76+ protected String note ;
77+ protected int min ;
78+ protected int max ;
79+ protected int progressPercent ;
7480
7581 /**
7682 * Construct an asynchronous SwingWorker task that optionally will display a
@@ -83,15 +89,55 @@ public abstract class AsyncSwingWorker extends SwingWorker<Void, Void> implement
8389 * @param title A non-null title indicates we want to use a ProgressMonitor with that title line.
8490 *
8591 * @param delayMillis A positive number indicating the delay we want before executions, during which progress will be reported.
92+ *
93+ * @param min The first progress value. No range limit.
94+ *
95+ * @param max The last progress value. No range limit; may be greater than min.
96+ *
8697 */
87- public AsyncSwingWorker (Component owner , String title , int delayMillis ) {
98+ public AsyncSwingWorker (Component owner , String title , int delayMillis , int min , int max ) {
8899 if (title != null ) {
89- progressMonitor = new ProgressMonitor (owner , title , "" , 0 , 100 );
90- progressMonitor .setProgress (0 ); // displays monitor
100+ progressMonitor = new ProgressMonitor (owner , title , "" , Math . min ( min , max ), Math . max ( min , max ) );
101+ progressMonitor .setProgress (Math . min ( min , max ) ); // displays monitor
91102 }
92103 this .delayMillis = Math .max (1 , delayMillis );
104+ this .min = min ;
105+ this .max = max ;
106+ }
107+
108+ public int getMinimum () {
109+ return min ;
110+ }
111+
112+ public void setMinimum (int min ) {
113+ this .min = min ;
114+ if (progressMonitor != null )
115+ progressMonitor .setMinimum (min );
116+ }
117+
118+ public int getMaximum () {
119+ return max ;
120+ }
121+
122+ public void setMaximum (int max ) {
123+ if (progressMonitor != null )
124+ progressMonitor .setMaximum (max );
125+ this .max = max ;
126+ }
127+
128+
129+ public int getProgressPercent () {
130+ return progressPercent ;
131+ }
132+
133+ public void setNote (String note ) {
134+ this .note = note ;
135+ if (progressMonitor != null )
136+ progressMonitor .setNote (note );
93137 }
94138
139+
140+
95141 /**
96142 * Cancel the asynchronous process.
97143 *
@@ -101,12 +147,12 @@ public void cancelAsync() {
101147 }
102148
103149 /**
104- * Check to see if the asynchronous process has been cancelled .
150+ * Check to see if the asynchronous process has been canceled .
105151 *
106152 * @return true if StateHelper is not alive anymore
107153 *
108154 */
109- public boolean isCancelledAsync () {
155+ public boolean isCanceledAsync () {
110156 return !helper .isAlive ();
111157 }
112158
@@ -126,7 +172,7 @@ public boolean isDoneAsync() {
126172 * @param progress
127173 * @return
128174 */
129- public String setNote (int progress ) {
175+ public String getNote (int progress ) {
130176 return String .format ("Completed %d%%.\n " , progress );
131177 }
132178
@@ -140,9 +186,25 @@ public String getNote() {
140186 }
141187
142188 public int getProgressAsync () {
143- return progress ;
189+ return progressAsync ;
144190 }
145191
192+ /**
193+ * Set the [min,max] progress safely.
194+ *
195+ * SwingWorker only allows progress between 0 and 100.
196+ * This method safely translates [min,max] to [0,100].
197+ *
198+ * @param n
199+ */
200+ public void setProgressAsync (int n ) {
201+ n = (max > min ? Math .max (min , Math .min (n , max ))
202+ : Math .max (max , Math .min (n , min )));
203+ progressAsync = n ;
204+ n = (int ) ((n - min ) * 100 / (max - min ));
205+ n = (n < 0 ? 0 : n > 100 ? 100 : n );
206+ progressPercent = n ;
207+ }
146208
147209
148210 ///// the StateMachine /////
@@ -179,36 +241,41 @@ public boolean stateLoop() {
179241 while (helper .isAlive ()) {
180242 switch (helper .getState ()) {
181243 case STATE_INIT :
244+ setProgressAsync (min );
182245 initAsync ();
183246 helper .setState (STATE_WAIT );
184247 continue ;
185248 case STATE_LOOP :
186- progress = doInBackgroundAsync (progress );
187- progress = Math .min (progress , 100 );
188- note = setNote (progress );
189- if (progressMonitor != null ) {
190- progressMonitor .setNote (note );
191- progressMonitor .setProgress (progress );
192- }
193- if (progress >= 100 || isCancelled ()) {
249+ if (checkCanceled ()) {
194250 helper .setState (STATE_DONE );
251+ firePropertyChange ("state" , null , CANCELED_ASYNC );
252+ continue ;
195253 } else {
196- helper .setState (STATE_WAIT );
254+ progressAsync = doInBackgroundAsync (progressAsync );
255+ setProgressAsync (progressAsync );
256+ setNote (getNote (progressAsync ));
257+ setProgress (progressPercent );
258+ if (progressMonitor != null )
259+ progressMonitor .setProgress (max > min ? progressAsync : max + min - progressAsync );
260+ helper .setState (progressAsync == max ? STATE_DONE : STATE_WAIT );
261+ continue ;
197262 }
198- setProgress (progress );
199- continue ;
200263 case STATE_WAIT :
201264 helper .setState (STATE_LOOP );
202265 helper .sleep (delayMillis );
203266 return true ;
267+ default :
204268 case STATE_DONE :
205- // Put the reallyDone() method on the AWTEventQueue
206- // just as the done() method was.
269+ if (progressMonitor != null )
270+ progressMonitor .close ();
271+ // Put the doneAsync() method on the AWTEventQueue
272+ // just as for SwingWorker.done().
207273 SwingUtilities .invokeLater (new Runnable () {
208274
209275 @ Override
210276 public void run () {
211277 doneAsync ();
278+ firePropertyChange ("state" , null , DONE_ASYNC );
212279 }
213280
214281 });
@@ -218,16 +285,28 @@ public void run() {
218285 return false ;
219286 }
220287
221- //// final SwingWorker methods not to be used by subclasses ////
222-
288+ private boolean checkCanceled () {
289+ if (isMonitorCanceled () || isCancelled ()) {
290+ helper .interrupt ();
291+ return true ;
292+ }
293+ return false ;
294+ }
295+
296+ //// final SwingWorker methods not to be used by subclasses ////
297+
298+ private boolean isMonitorCanceled () {
299+ return (progressMonitor != null && progressMonitor .isCanceled ());
300+ }
301+
223302 /**
224303 * see SwingWorker, made final here.
225304 *
226305 */
227306 @ Override
228307 final protected Void doInBackground () throws Exception {
229- helper = new StateHelper (AsyncSwingWorker . this );
230- setProgress ( 0 );
308+ helper = new StateHelper (this );
309+ setProgressAsync ( min );
231310 helper .next (STATE_INIT );
232311 return null ;
233312 }
@@ -240,5 +319,4 @@ final protected Void doInBackground() throws Exception {
240319 final public void done () {
241320 }
242321
243-
244322}
0 commit comments