@@ -57,10 +57,8 @@ public class Task {
5757 /** Designates task completion */
5858 private boolean completed = false ;
5959
60- private boolean hasElements = true ;
61-
62- /** Number of tasks utilized by the task */
63- private long tasks = 1 ;
60+ /** Number of tasks (this task + any subtasks) contained within this task */
61+ private long totalTasks = 1 ;
6462
6563 /** Progress in current stage */
6664 private final AtomicLong current = new AtomicLong (0 );
@@ -92,6 +90,9 @@ public Task(final Object progressible, //
9290 {
9391 this .progressible = progressible ;
9492 this .parent = parent ;
93+ if (this .parent != null ) {
94+ this .parent .subTasks .add (this );
95+ }
9596 this .description = description ;
9697 }
9798
@@ -109,24 +110,12 @@ public void complete() {
109110 }
110111 throw new IllegalStateException (msg );
111112 }
112- this . completed = true ;
113- if ( hasElements ) {
113+ else {
114+ // For tasks with undefined progress, we simply update current to be max.
114115 this .current .set (this .max .get ());
116+ this .totalTasks = subTasks .size () + 1 ;
115117 }
116- }
117-
118- /**
119- * Creates a subtask, recording it to keep track of progress.
120- *
121- * @return the subtask.
122- */
123- public synchronized Task createSubtask ( //
124- Object progressible , //
125- String description //
126- ) {
127- final Task sub = new Task (progressible , this , description );
128- subTasks .add (sub );
129- return sub ;
118+ this .completed = true ;
130119 }
131120
132121 /**
@@ -157,25 +146,24 @@ public void defineTotal(final long elements) {
157146 * used (as one subtask may run multiple times).
158147 */
159148 public void defineTotal (final long elements , final long subTasks ) {
160- if (tasksDefined ) {
161- throw new IllegalStateException (
162- "Progress has already been defined for this task" );
149+ // Nonzero number of elements
150+ if (elements > 0L ) {
151+ this .totalTasks = subTasks + 1 ;
152+ this .max .set (elements );
163153 }
164- // Total tasks = all subtasks, plus one iff there are also progress elements
165- // in this stage
166- this .tasks = subTasks + (elements == 0 ? 0 : 1 );
167-
168- if (elements == 0 ) {
169- this .hasElements = false ;
170- if (this .tasks == 0 ) {
171- this .tasks = 1 ;
172- this .current .set (1 );
173- this .max .set (1 );
174- return ;
175- }
154+ // Zero elements, nonzero subtasks
155+ else if (subTasks > 0L ) {
156+ this .totalTasks = subTasks ;
157+ this .max .set (1 );
176158 }
159+ // Zero elements & zero subtasks
160+ // NB one common example of this situation occurs when you
161+ // want to programmatically set the elements to the size of a list,
162+ // but then you get passed an empty list. In this case, there is one task,
163+ // which is already complete!.
177164 else {
178- this .max .set (elements );
165+ this .totalTasks = 1 ;
166+ this .current .set (1 );
179167 }
180168 this .tasksDefined = true ;
181169 }
@@ -202,9 +190,9 @@ public boolean isComplete() {
202190 public double progress () {
203191 double totalCompletion = current .doubleValue () / max .doubleValue ();
204192 for (Task t : subTasks ) {
205- totalCompletion += t .isComplete () ? 1.0 : t . progress ();
193+ totalCompletion += t .progress ();
206194 }
207- return totalCompletion / tasks ;
195+ return totalCompletion / totalTasks ;
208196 }
209197
210198 /**
0 commit comments