/* * Copyright (C) 2014 GG-Net GmbH - Oliver Günther * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.ggnet.dwoss.progress; import eu.ggnet.saft.api.progress.IMonitor; import org.slf4j.Logger; public final class SubMonitor implements IMonitor { /** * <p> * Converts an unknown (possibly null) IProgressMonitor into a SubMonitor. It is * not necessary to call done() on the result, but the caller is responsible for calling * done() on the argument. Calls beginTask on the argument.</p> * * <p> * This method should generally be called at the beginning of a method that accepts * an IProgressMonitor in order to convert the IProgressMonitor into a SubMonitor.</p> * * @param monitor monitor to convert to a SubMonitor instance or null. Treats null * as a new instance of <code>NullProgressMonitor</code>. * @return a SubMonitor instance that adapts the argument */ public static SubMonitor convert(IMonitor monitor) { if ( monitor == null ) { monitor = new NullMonitor(); } if ( monitor instanceof SubMonitor ) { return (SubMonitor)monitor; } return new SubMonitor(monitor); } /** * <p> * Converts an unknown (possibly null) IProgressMonitor into a SubMonitor allocated * with the given number of ticks. It is not necessary to call done() on the result, * but the caller is responsible for calling done() on the argument. Calls beginTask * on the argument.</p> * * <p> * This method should generally be called at the beginning of a method that accepts * an IProgressMonitor in order to convert the IProgressMonitor into a SubMonitor.</p> * * @param monitor monitor to convert to a SubMonitor instance or null. Treats null * as a new instance of <code>NullProgressMonitor</code>. * @param workRemaining number of ticks that will be available in the resulting monitor * @return a SubMonitor instance that adapts the argument */ public static SubMonitor convert(IMonitor monitor, int workRemaining) { SubMonitor result = convert(monitor); result.setWorkRemaining(workRemaining); return result; } /** * <p> * Converts an unknown (possibly null) IProgressMonitor into a SubMonitor allocated * with the given number of ticks. It is not necessary to call done() on the result, * but the caller is responsible for calling done() on the argument. Calls beginTask * on the argument.</p> * * <p> * This method should generally be called at the beginning of a method that accepts * an IProgressMonitor in order to convert the IProgressMonitor into a SubMonitor.</p> * * @param monitor to convert into a SubMonitor instance or null. If given a null argument, * the resulting SubMonitor will not report its progress anywhere. * @param title user readable name to pass to monitor.beginTask. Never null. * @param work calls {@link SubMonitor#setWorkRemaining(int) } * @return a new SubMonitor instance that is a child of the given monitor */ public static SubMonitor convert(IMonitor monitor, String title, int work) { SubMonitor result = convert(monitor, work); result.title(title); return result; } private SubMonitor(IMonitor monitor) { this.monitor = monitor; this.start(); } /** * Sets an instance of an slf4j Logger. If this is supplied, all messages are send to the debug * level of the Logger. * * @param logger */ public void setLogger(Logger logger) { this.logger = logger; } @Override public IMonitor start() { if ( !started ) { monitor.start(); started = true; } return this; } @Override public IMonitor title(String name) { monitor.title(name); return this; } @Override public IMonitor message(String subMessage) { monitor.message(subMessage); if ( logger != null ) logger.debug(subMessage); return this; } @Override public IMonitor worked(int workunits, String subMessage) { message(subMessage); worked(workunits); return this; } @Override public IMonitor finish() { monitor.finish(); return this; } @Override public int getAbsolutRemainingTicks() { return workRemaining; } /** * <p> * Sets the work remaining for this SubMonitor instance. This is the total number * of ticks that may be reported by all subsequent calls to message(int), newChild(int), etc. * This may be called many times for the same SubMonitor instance. When this method * is called, the remaining space on the progress monitor is redistributed into the given * number of ticks.</p> * * <p> * It doesn't matter how much progress has already been reported with this SubMonitor * instance. If you call setWorkRemaining(100), you will be able to report 100 more ticks of * work before the progress meter reaches 100%.</p> * * @param workRemaining total number of remaining ticks * @return the receiver */ public IMonitor setWorkRemaining(int workRemaining) { this.workRemaining = workRemaining; if ( workRemaining > 0 ) { barPerTick = (double)monitor.getAbsolutRemainingTicks() / workRemaining; } return this; } /* (non-Javadoc) * @see org.eclipse.core.runtime.IProgressMonitor#message(int) */ @Override public IMonitor worked(int work) { if ( work <= 0 ) { return this; } workRemaining = workRemaining - work; tempSmallWork = tempSmallWork + (barPerTick * work); monitor.worked((int)tempSmallWork); tempSmallWork -= (int)tempSmallWork; return this; } public SubMonitor newChild(final int work) { return SubMonitor.convert(new IMonitor() { private int totalWork = work; @Override public IMonitor start() { return this; } @Override public IMonitor title(String name) { monitor.title(name); return this; } @Override public IMonitor worked(int workunits) { if ( workunits < 1 || totalWork < 1 ) { return this; } if ( workunits > totalWork ) { workunits = totalWork; } totalWork -= workunits; SubMonitor.this.worked(workunits); return this; } @Override public IMonitor message(String subMessage) { monitor.message(subMessage); return this; } @Override public IMonitor worked(int workunits, String subMessage) { worked(workunits); message(subMessage); return this; } @Override public IMonitor finish() { worked(totalWork); return this; } @Override public int getAbsolutRemainingTicks() { return totalWork; } }); } /** * Used to communicate with the monitor of this progress monitor tree */ private final IMonitor monitor; private boolean started = false; /** * Bar length for one tick */ private double barPerTick; private int workRemaining; private double tempSmallWork = 0.0; private Logger logger; }