/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.operator;
import com.rapidminer.tools.AbstractObservable;
/**
*
* The {@link OperatorProgress} can be used to report execution progress of an operator. If it is
* not intialized by calling {@link #setTotal(int)} the operator will be displayed with an
* indeterminate progress. If the progress has been initialized calls to {@link #setCompleted(int)},
* {@link #step()} or {@link #step(int)} can be used increase the current operator progress.
*
* @author Nils Woehler
* @since 7.0.0
*
*/
public final class OperatorProgress extends AbstractObservable<OperatorProgress> {
/**
* This value is the default value for the {@link #total} variable. It indicates that the
* {@link OperatorProgress} does not report a progress.
*/
public static final int NO_PROGRESS = -1;
/**
* Initially set to {@value #NO_PROGRESS} so Operators that do not use the
* {@link OperatorProgress} (i.e. do not call {@link #setTotal(int)} at all) will be displayed
* as indeterminate.
*/
private int total = NO_PROGRESS;
private int completed = 0;
private boolean indeterminate = false;
private boolean checkForStop = true;
/**
* The parent operator. Used to call {@link Operator#checkForStop()} when setting operator
* progress.
*/
private final Operator op;
/**
* Constructs a new {@link OperatorProgress} instance
*
* @param op
* the parent operator
*/
OperatorProgress(Operator op) {
if (op == null) {
throw new IllegalArgumentException("Operator must not be null");
}
this.op = op;
}
/**
* Changes the total amount of progress and sets the current progress to 0. If this method is
* not called or is called with a value <= 0 the progress of the operator will be indeterminate.
*
* @param total
* the total amount of progress
*/
public void setTotal(int total) {
this.completed = 0;
if (total > 0) {
this.total = total;
} else {
this.total = NO_PROGRESS;
}
fireUpdate(this);
}
/**
* Changes the completed amount of progress and calls the {@link Operator#checkForStop()} method
* if {@link #isCheckForStop()} returns {@code true}. If the provided amount is greater then
* {@link #getTotal()}, the amount will be set to the value returned by {@link #getTotal()}.
* <p>
* <b>CAUTION:</b> The calculation performance might decrease if this method is called too often
* and {@link #isCheckForStop()} returns {@code true} (default behavior)
*
* @throws ProcessStoppedException
* if the process has been stopped
*/
public void setCompleted(int completed) throws ProcessStoppedException {
if (completed <= this.completed) {
return;
} else if (completed > this.total) {
completed = total;
}
if (isCheckForStop()) {
op.checkForStop();
}
this.completed = completed;
fireUpdate(this);
}
/**
* Completes the current progress by setting total equal to completed.
*/
public void complete() {
this.completed = this.total;
}
/**
* Increases the completed amount of progress by one. Furthermore the
* {@link Operator#checkForStop()} method is called.
* <p>
* <b>CAUTION:</b> The calculation performance might decrease if this method is called too often
* and {@link #isCheckForStop()} returns {@code true} (default behavior)
*
* @throws ProcessStoppedException
* if the process has been stopped
*/
public void step() throws ProcessStoppedException {
step(1);
}
/**
* Increases the completed amount of progress by {@code amount}. Furthermore the
* {@link Operator#checkForStop()} method is called.
* <p>
* <b>CAUTION:</b> The calculation performance might decrease if this method is called too often
* and {@link #isCheckForStop()} returns {@code true} (default behavior)
*
* @param amount
* the amount you want to increase the completed progress.
*
* @throws ProcessStoppedException
* if the process has been stopped
*/
public void step(int amount) throws ProcessStoppedException {
setCompleted(this.completed + amount);
}
/**
* @return the total progress
*/
public int getTotal() {
return total;
}
/**
* @return the completed progress
*/
public int getCompleted() {
return completed;
}
/**
* Returns whether the progress is indeterminate or not. The progress is indeterminate if either
* {@link #indeterminate} has been explicitly set to {@code true} or if {@link #getTotal()}
* returns a value equal or lower than {@value #NO_PROGRESS}.
*
* @return whether the current progress is indeterminate or not
*/
public boolean isIndeterminate() {
return indeterminate || total <= NO_PROGRESS;
}
/**
* Allows to define whether the current progress is indeterminate. Changes the appearance of
* operator progress bar.
*/
public void setIndeterminate(boolean indeterminate) {
this.indeterminate = indeterminate;
fireUpdate(this);
}
/**
* Checks whether total equals completed
*
* @return <code>true</code> if {@link #total} equals {@link #completed}.
*/
public boolean isCompleted() {
return total == completed;
}
/**
* @return the current progress (between 0 and 100)
*/
public int getProgress() {
if (total > 0) {
// prevent integer overflow of completed * 100
return (int) (completed * (long) 100 / total);
}
return 0;
}
/**
* Resets completed to {@code 0}. Does not change the total amount of progress.
*/
public void reset() {
this.completed = 0;
fireUpdate(this);
}
/**
* @return whether the {@link #setCompleted(int)} method will call
* {@link Operator#checkForStop()}
*/
public boolean isCheckForStop() {
return checkForStop;
}
/**
* @param checkForStop
* whether the {@link #setCompleted(int)} method will call
* {@link Operator#checkForStop()}
*/
public void setCheckForStop(boolean checkForStop) {
this.checkForStop = checkForStop;
}
}