package ch.akuhn.util; import java.util.concurrent.CancellationException; public abstract class ProgressMonitor { public abstract boolean isCanceled(); public abstract CancellationException cancel(); public abstract void done(); public void worked(int work) { this.worked((double) work); } protected abstract void worked(double work); protected abstract String getName(); public abstract void setName(String name); public abstract void begin(int total); public ProgressMonitor spawn(String name, int ticks) { return new Spawn(this, name, ticks); } public static ProgressMonitor NULL = new Null(); static class Null extends ProgressMonitor { @Override public void begin(int total) { // ignore } @Override public CancellationException cancel() { return new CancellationException(); } @Override public void done() { // ignore } @Override public boolean isCanceled() { return false; } @Override public void setName(String name) { // ignore } @Override public ProgressMonitor spawn(String name, int ticks) { return this; } @Override public void worked(double work) { // ignore } protected String getName() { return null; } }; static class Spawn extends ProgressMonitor { private ProgressMonitor parent; private String parentName; private int beginCount = 0; private int parentWork; private double worked; private int total; public Spawn(ProgressMonitor parent, String name, int parentWork) { this.parent = parent; this.parentName = parent.getName(); if (name != null) this.setName(name); if (parentWork > 0) this.parentWork = parentWork; } @Override public void begin(int total) { if (++beginCount == 1) this.total = total; } @Override public CancellationException cancel() { return parent.cancel(); } @Override public void done() { if (beginCount-- == 1) { this.worked(total - worked); parent.setName(parentName); } } @Override public boolean isCanceled() { return parent.isCanceled(); } @Override public void worked(double work) { if (total > 0 || beginCount == 1) parent.worked(work / total * parentWork); } @Override public void setName(String task) { parent.setName(task); } @Override public Spawn spawn(String name, int subtotal) { return new Spawn(this, name, subtotal); } @Override protected String getName() { return parent.getName(); } } static class Console extends ProgressMonitor { private double worked; private boolean canceled = false; private String name = "Progress"; private int prev = -1; Console() { this.worked(0); // print initial 0% } @Override public void begin(int total) { throw new UnsupportedOperationException(); } @Override public CancellationException cancel() { canceled = true; return new CancellationException(); } @Override public void done() { throw new UnsupportedOperationException(); } @Override public boolean isCanceled() { return canceled; } @Override public void setName(String name) { this.name = name; } @Override public void worked(double work) { int curr = (int) (worked += work); if (curr == prev) return; System.out.printf("%5d%%\t%s\n", prev = curr, name); } @Override public String getName() { return name; } } public static ProgressMonitor console() { return new Console().spawn(null, 100); } }