X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2FProgress.java;fp=src%2Fbe%2Fnikiroo%2Futils%2FProgress.java;h=8b6e10e5fc97ca6e5b2748aeb58c4829d80a3287;hb=b3aad1f93ce78c9806361ca1659defcf99b45bdc;hp=0000000000000000000000000000000000000000;hpb=86057589d5211fbad4b7cdbcd4dd0f1e3777d4c1;p=fanfix.git diff --git a/src/be/nikiroo/utils/Progress.java b/src/be/nikiroo/utils/Progress.java new file mode 100644 index 0000000..8b6e10e --- /dev/null +++ b/src/be/nikiroo/utils/Progress.java @@ -0,0 +1,279 @@ +package be.nikiroo.utils; + +import java.util.ArrayList; +import java.util.EventListener; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Progress reporting system, possibly nested. + * + * @author niki + */ +public class Progress { + public interface ProgressListener extends EventListener { + /** + * A progression event. + * + * @param progress + * the {@link Progress} object that generated it, or a parent + * @param name + * the first non-null name of the {@link Progress} step that + * generated this event + */ + public void progress(Progress progress, String name); + } + + private String name; + private Map children; + private List listeners; + private int min; + private int max; + private int localProgress; + private int progress; // children included + + /** + * Create a new default unnamed {@link Progress}, from 0 to 100. + */ + public Progress() { + this(null); + } + + /** + * Create a new default {@link Progress}, from 0 to 100. + * + * @param name + * the name of this {@link Progress} step + */ + public Progress(String name) { + this(name, 0, 100); + } + + /** + * Create a new unnamed {@link Progress}, from min to max. + * + * @param min + * the minimum progress value (and starting value) -- must be + * non-negative + * @param max + * the maximum progress value + */ + public Progress(int min, int max) { + this(null, min, max); + } + + /** + * Create a new {@link Progress}, from min to max. + * + * @param name + * the name of this {@link Progress} step + * @param min + * the minimum progress value (and starting value) -- must be + * non-negative + * @param max + * the maximum progress value + */ + public Progress(String name, int min, int max) { + this.name = name; + this.children = new HashMap(); + this.listeners = new ArrayList(); + setMinMax(min, max); + setProgress(min); + } + + /** + * The name of this {@link Progress} step. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * The minimum progress value. + * + * @return the min + */ + public int getMin() { + return min; + } + + /** + * The minimum progress value. + * + * @param min + * the min to set + */ + 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"); + } + + this.min = min; + } + + /** + * The maximum progress value. + * + * @return the max + */ + public int getMax() { + return max; + } + + /** + * The maximum progress value (must be >= the minimum progress value). + * + * @param max + * the max to set + */ + public void setMax(int max) { + if (max < min) { + throw new Error( + "The maximum progress value must be >= the minimum progress value"); + } + + this.max = max; + } + + /** + * Set both the minimum and maximum progress values. + * + * @param min + * the min + * @param max + * the max + */ + public void setMinMax(int min, int max) { + 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"); + } + + this.min = min; + this.max = max; + } + + /** + * Get the total progress value (including the optional children + * {@link Progress}) on a {@link Progress#getMin()} to + * {@link Progress#getMax()} scale. + * + * @return the progress the value + */ + public int getProgress() { + return progress; + } + + /** + * Set the local progress value (not including the optional children + * {@link Progress}), on a {@link Progress#getMin()} to + * {@link Progress#getMax()} scale. + * + * @param progress + * the progress to set + */ + public void setProgress(int progress) { + int diff = this.progress - this.localProgress; + this.localProgress = progress; + setTotalProgress(name, progress + diff); + } + + /** + * Check if the action corresponding to this {@link Progress} is done (i.e., + * if its progress value is >= its max value). + * + * @return TRUE if it is + */ + public boolean isDone() { + return progress >= max; + } + + /** + * Get the total progress value (including the optional children + * {@link Progress}) on a 0.0 to 1.0 scale. + * + * @return the progress + */ + public double getRelativeProgress() { + return (((double) progress) / (max - min)); + } + + /** + * Set the total progress value (including the optional children + * {@link Progress}), on a {@link Progress#getMin()} to + * {@link Progress#getMax()} scale. + * + * @param name + * the current name (if it is NULL, the first non-null name in + * the hierarchy will overwrite it) + * @param progress + * the progress to set + */ + private void setTotalProgress(String name, int progress) { + this.progress = progress; + + for (ProgressListener l : listeners) { + l.progress(this, name); + } + } + + /** + * Add a {@link ProgressListener} that will trigger on progress changes. + * + * @param l + * the listener + */ + public void addProgressListener(ProgressListener l) { + this.listeners.add(l); + } + + /** + * Add a child {@link Progress} of the given weight. + * + * @param progress + * the child {@link Progress} to add + * @param weight + * the weight (on a {@link Progress#getMin()} to + * {@link Progress#getMax()} scale) of this child + * {@link Progress} in relation to its 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"); + } + + // 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(); + } + + if (name == null) { + name = Progress.this.name; + } + + setTotalProgress(name, (int) (total * (max - min))); + } + }); + + this.children.put(progress, weight); + } +}