X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2FProgress.java;h=2872530b68542585783467e3241835072e75570a;hb=cd0c27d2e457ea19fcd9def879e1534a528292c2;hp=b31cde49456174ef5fd5487f2feab00324a451f6;hpb=88b36f83bb4bb9201339432c97e6d826aa9e1903;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/Progress.java b/src/be/nikiroo/utils/Progress.java index b31cde4..2872530 100644 --- a/src/be/nikiroo/utils/Progress.java +++ b/src/be/nikiroo/utils/Progress.java @@ -19,7 +19,10 @@ public class Progress { * A progression event. * * @param progress - * the {@link Progress} object that generated it + * the {@link Progress} object that generated it, not + * necessarily the same as the one where the listener was + * attached (it could be a child {@link Progress} of this + * {@link Progress}). * @param name * the first non-null name of the {@link Progress} step that * generated this event @@ -27,6 +30,8 @@ public class Progress { public void progress(Progress progress, String name); } + private Progress parent = null; + private Object lock = new Object(); private String name; private Map children; private List listeners; @@ -93,6 +98,17 @@ public class Progress { return name; } + /** + * The name of this {@link Progress} step. + * + * @param name + * the new name + */ + public void setName(String name) { + this.name = name; + changed(this); + } + /** * The minimum progress value. * @@ -107,18 +123,24 @@ public class Progress { * * @param min * the min to set + * + * + * @throws Error + * if min < 0 or if min > max */ public void setMin(int min) { if (min < 0) { throw new Error("negative values not supported"); } - if (min > max) { - throw new Error( - "The minimum progress value must be <= the maximum progress value"); - } + synchronized (getLock()) { + if (min > max) { + throw new Error( + "The minimum progress value must be <= the maximum progress value"); + } - this.min = min; + this.min = min; + } } /** @@ -135,14 +157,20 @@ public class Progress { * * @param max * the max to set + * + * + * @throws Error + * if max < min */ public void setMax(int max) { - if (max < min) { - throw new Error( - "The maximum progress value must be >= the minimum progress value"); - } + synchronized (getLock()) { + if (max < min) { + throw new Error( + "The maximum progress value must be >= the minimum progress value"); + } - this.max = max; + this.max = max; + } } /** @@ -152,6 +180,9 @@ public class Progress { * the min * @param max * the max + * + * @throws Error + * if min < 0 or if min > max */ public void setMinMax(int min, int max) { if (min < 0) { @@ -163,8 +194,10 @@ public class Progress { "The minimum progress value must be <= the maximum progress value"); } - this.min = min; - this.max = max; + synchronized (getLock()) { + this.min = min; + this.max = max; + } } /** @@ -187,14 +220,28 @@ public class Progress { * the progress to set */ public void setProgress(int progress) { - int diff = this.progress - this.localProgress; - this.localProgress = progress; - setTotalProgress(this, name, progress + diff); + synchronized (getLock()) { + int diff = this.progress - this.localProgress; + this.localProgress = progress; + setTotalProgress(this, name, progress + diff); + } + } + + /** + * Add some value to the current progression of this {@link Progress}. + * + * @param step + * the amount to add + */ + public void add(int step) { + synchronized (getLock()) { + setProgress(localProgress + step); + } } /** * Check if the action corresponding to this {@link Progress} is done (i.e., - * if its progress value is >= its max value). + * if its progress value == its max value). * * @return TRUE if it is */ @@ -202,6 +249,13 @@ public class Progress { return progress >= max; } + /** + * Mark the {@link Progress} as done by setting its value to max. + */ + public void done() { + setProgress(getMax()); + } + /** * Get the total progress value (including the optional children * {@link Progress}) on a 0.0 to 1.0 scale. @@ -209,13 +263,17 @@ public class Progress { * @return the progress */ public double getRelativeProgress() { + if (max == min) { + return 1; + } + return (((double) progress) / (max - min)); } /** * Return the list of direct children of this {@link Progress}. * - * @return the children (who will think of them??) + * @return the children (Who will think of the children??) */ public Set getChildren() { return children.keySet(); @@ -236,15 +294,42 @@ public class Progress { * the progress to set */ private void setTotalProgress(Progress pg, String name, int progress) { - this.progress = progress; + // TODO: name is not used... and this is probably a bug in this case + synchronized (getLock()) { + progress = Math.max(min, progress); + progress = Math.min(max, progress); + + if (progress != this.progress) { + this.progress = progress; + changed(pg); + } + } + } + + /** + * Notify the listeners that this {@link Progress} changed value. + * + * @param pg + * the emmiter + */ + private void changed(Progress pg) { + if (pg == null) { + pg = this; + } - for (ProgressListener l : listeners) { - l.progress(pg, name); + synchronized (getLock()) { + for (ProgressListener l : listeners) { + l.progress(pg, name); + } } } /** * Add a {@link ProgressListener} that will trigger on progress changes. + *

+ * Note: the {@link Progress} that will be reported will be the active + * progress, not necessarily the same as the current one (it could be a + * child {@link Progress} of this {@link Progress}). * * @param l * the listener @@ -253,6 +338,18 @@ public class Progress { this.listeners.add(l); } + /** + * Remove a {@link ProgressListener} that would trigger on progress changes. + * + * @param l + * the listener + * + * @return TRUE if it was found (and removed) + */ + public boolean removeProgressListener(ProgressListener l) { + return this.listeners.remove(l); + } + /** * Add a child {@link Progress} of the given weight. * @@ -262,32 +359,61 @@ public class Progress { * the weight (on a {@link Progress#getMin()} to * {@link Progress#getMax()} scale) of this child * {@link Progress} in relation to its parent + * + * @throws Error + * if weight exceed {@link Progress#getMax()} or if progress + * already has a parent */ public void addProgress(Progress progress, double weight) { if (weight < min || weight > max) { - throw new Error( - "A Progress object cannot have a weight outside its parent range"); + throw new Error(String.format( + "Progress object %s cannot have a weight of %f, " + + "it is outside of its parent (%s) range (%f)", + progress.name, weight, name, max)); + } + + if (progress.parent != null) { + throw new Error(String.format( + "Progress object %s cannot be added to %s, " + + "as it already has a parent (%s)", progress.name, + name, progress.parent.name)); } - // Note: this is quite inefficient, especially with many children - // TODO: improve it? progress.addProgressListener(new ProgressListener() { - public void progress(Progress progress, String name) { - double total = ((double) localProgress) / (max - min); - for (Entry entry : children.entrySet()) { - total += (entry.getValue() / (max - min)) - * entry.getKey().getRelativeProgress(); - } + @Override + public void progress(Progress pg, String name) { + synchronized (getLock()) { + double total = ((double) localProgress) / (max - min); + for (Entry entry : children.entrySet()) { + total += (entry.getValue() / (max - min)) + * entry.getKey().getRelativeProgress(); + } - if (name == null) { - name = Progress.this.name; - } + if (name == null) { + name = Progress.this.name; + } - setTotalProgress(progress, name, - (int) Math.round(total * (max - min))); + setTotalProgress(pg, name, + (int) Math.round(total * (max - min))); + } } }); this.children.put(progress, weight); } + + /** + * The lock object to use (this one or the recursively-parent one). + * + * @return the lock object to use + */ + private Object getLock() { + synchronized (lock) { + if (parent != null) { + return parent.getLock(); + } + + return lock; + } + } }