1 package be
.nikiroo
.utils
;
3 import java
.util
.ArrayList
;
4 import java
.util
.EventListener
;
5 import java
.util
.HashMap
;
8 import java
.util
.Map
.Entry
;
12 * Progress reporting system, possibly nested.
16 public class Progress
{
17 public interface ProgressListener
extends EventListener
{
19 * A progression event.
22 * the {@link Progress} object that generated it, not
23 * necessarily the same as the one where the listener was
24 * attached (it could be a child {@link Progress} of this
27 * the first non-null name of the {@link Progress} step that
28 * generated this event
30 public void progress(Progress progress
, String name
);
34 private Map
<Progress
, Double
> children
;
35 private List
<ProgressListener
> listeners
;
38 private int localProgress
;
39 private int progress
; // children included
42 * Create a new default unnamed {@link Progress}, from 0 to 100.
49 * Create a new default {@link Progress}, from 0 to 100.
52 * the name of this {@link Progress} step
54 public Progress(String name
) {
59 * Create a new unnamed {@link Progress}, from min to max.
62 * the minimum progress value (and starting value) -- must be
65 * the maximum progress value
67 public Progress(int min
, int max
) {
72 * Create a new {@link Progress}, from min to max.
75 * the name of this {@link Progress} step
77 * the minimum progress value (and starting value) -- must be
80 * the maximum progress value
82 public Progress(String name
, int min
, int max
) {
84 this.children
= new HashMap
<Progress
, Double
>();
85 this.listeners
= new ArrayList
<Progress
.ProgressListener
>();
91 * The name of this {@link Progress} step.
95 public String
getName() {
100 * The name of this {@link Progress} step.
105 public void setName(String name
) {
107 // will fire an action event:
108 setProgress(this.localProgress
);
112 * The minimum progress value.
116 public int getMin() {
121 * The minimum progress value.
126 public void setMin(int min
) {
128 throw new Error("negative values not supported");
133 "The minimum progress value must be <= the maximum progress value");
140 * The maximum progress value.
144 public int getMax() {
149 * The maximum progress value (must be >= the minimum progress value).
154 public void setMax(int max
) {
157 "The maximum progress value must be >= the minimum progress value");
164 * Set both the minimum and maximum progress values.
171 public void setMinMax(int min
, int max
) {
173 throw new Error("negative values not supported");
178 "The minimum progress value must be <= the maximum progress value");
186 * Get the total progress value (including the optional children
187 * {@link Progress}) on a {@link Progress#getMin()} to
188 * {@link Progress#getMax()} scale.
190 * @return the progress the value
192 public int getProgress() {
197 * Set the local progress value (not including the optional children
198 * {@link Progress}), on a {@link Progress#getMin()} to
199 * {@link Progress#getMax()} scale.
202 * the progress to set
204 public void setProgress(int progress
) {
205 int diff
= this.progress
- this.localProgress
;
206 this.localProgress
= progress
;
207 setTotalProgress(this, name
, progress
+ diff
);
211 * Check if the action corresponding to this {@link Progress} is done (i.e.,
212 * if its progress value is >= its max value).
214 * @return TRUE if it is
216 public boolean isDone() {
217 return progress
>= max
;
221 * Get the total progress value (including the optional children
222 * {@link Progress}) on a 0.0 to 1.0 scale.
224 * @return the progress
226 public double getRelativeProgress() {
227 return (((double) progress
) / (max
- min
));
231 * Return the list of direct children of this {@link Progress}.
233 * @return the children (who will think of them??)
235 public Set
<Progress
> getChildren() {
236 return children
.keySet();
240 * Set the total progress value (including the optional children
241 * {@link Progress}), on a {@link Progress#getMin()} to
242 * {@link Progress#getMax()} scale.
245 * the {@link Progress} to report as the progression emitter
247 * the current name (if it is NULL, the first non-null name in
248 * the hierarchy will overwrite it) of the {@link Progress} who
249 * emitted this change
251 * the progress to set
253 private void setTotalProgress(Progress pg
, String name
, int progress
) {
254 this.progress
= progress
;
256 for (ProgressListener l
: listeners
) {
257 l
.progress(pg
, name
);
262 * Add a {@link ProgressListener} that will trigger on progress changes.
264 * Note: the {@link Progress} that will be reported will be the active
265 * progress, not necessarily the same as the current one (it could be a
266 * child {@link Progress} of this {@link Progress}).
271 public void addProgressListener(ProgressListener l
) {
272 this.listeners
.add(l
);
276 * Remove a {@link ProgressListener} that would trigger on progress changes.
281 * @return TRUE if it was found (and removed)
283 public boolean removeProgressListener(ProgressListener l
) {
284 return this.listeners
.remove(l
);
288 * Add a child {@link Progress} of the given weight.
291 * the child {@link Progress} to add
293 * the weight (on a {@link Progress#getMin()} to
294 * {@link Progress#getMax()} scale) of this child
295 * {@link Progress} in relation to its parent
297 public void addProgress(Progress progress
, double weight
) {
298 if (weight
< min
|| weight
> max
) {
300 "A Progress object cannot have a weight outside its parent range");
303 // Note: this is quite inefficient, especially with many children
305 progress
.addProgressListener(new ProgressListener() {
306 public void progress(Progress pg
, String name
) {
307 double total
= ((double) localProgress
) / (max
- min
);
308 for (Entry
<Progress
, Double
> entry
: children
.entrySet()) {
309 total
+= (entry
.getValue() / (max
- min
))
310 * entry
.getKey().getRelativeProgress();
314 name
= Progress
.this.name
;
317 setTotalProgress(pg
, name
,
318 (int) Math
.round(total
* (max
- min
)));
322 this.children
.put(progress
, weight
);