/**
*#########################################################################
*
* A component of the GAT application, part of the Greenstone digital
* library suite from the New Zealand Digital Library Project at the
* University of Waikato, New Zealand.
*
* Author: John Thompson, Greenstone Digital Library, University of Waikato
*
* Copyright (C) New Zealand Digital Library Project
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*########################################################################
*/
package org.greenstone.core.gui;
import java.math.BigInteger;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
/** A progress bar that doesn't pack a sad when you feed it longs (such as the sizes of files) which get mangled into negative numbers. I know how it feels, as I often have negative progress. Also tries to be efficent when updating the JProgressBar, so only updates when the value actually changes, which become necessary when you move a large number of files with millions of bytes (where upon shifting a file of a thousand bytes would be pretty insignificant, maybe not even a percent, but would fire several progress updates).
* @author John Thompson, Greenstone Digital Library, University of Waikato
* @version 2.3c
*/
final public class LongProgressBar
extends JProgressBar {
private BigInteger cur_value = null;
private BigInteger max_value = null;
private BigInteger min_value = null;
/** The previous percentage value. */
private int previous = -1;
private SafeSetIndeterminate safe_set_indeterminate = null;
private SafeSetString safe_set_string = null;
private SafeSetValue safe_set_value = null;
public LongProgressBar() {
super(0, 100);
cur_value = BigInteger.ZERO;
min_value = BigInteger.ZERO;
max_value = BigInteger.ZERO;
}
public void addMaximum(int size) {
///ystem.err.println("Add maximum " + size);
if(size > 0) {
max_value = max_value.add(new BigInteger((new Integer(size)).toString()));
update();
}
}
public void addMaximum(long size) {
///ystem.err.println("Add maximum " + size);
if(size > 0) {
max_value = max_value.add(new BigInteger((new Long(size)).toString()));
update();
}
}
public void addValue(int size) {
///ystem.err.println("Add value " + size);
if(size > 0) {
cur_value = cur_value.add(new BigInteger((new Integer(size)).toString()));
update();
}
}
public void addValue(long size) {
///ystem.err.println("Add value " + size);
if(size > 0) {
cur_value = cur_value.add(new BigInteger((new Long(size)).toString()));
update();
}
}
public void clear()
{
previous = -1;
update();
}
public void reset() {
cur_value = BigInteger.ZERO;
max_value = BigInteger.ZERO;
previous = -1;
update();
}
public void setIndeterminate(boolean state) {
if(safe_set_indeterminate == null) {
safe_set_indeterminate = new SafeSetIndeterminate(state);
}
else {
safe_set_indeterminate.setState(state);
}
SwingUtilities.invokeLater(safe_set_indeterminate);
}
public void setMaximum(int size) {
///ystem.err.println("Add maximum " + size);
if(size > 0) {
max_value = new BigInteger((new Integer(size)).toString());
update();
}
}
public void setMaximum(long size) {
///ystem.err.println("Add maximum " + size);
if(size > 0) {
max_value = new BigInteger((new Long(size)).toString());
update();
}
}
public void setString(String label) {
safeSetString(label);
}
public void setValue(int size) {
///ystem.err.println("Set value " + size);
cur_value = new BigInteger((new Integer(size)).toString());
update();
}
public void setValue(long size) {
///ystem.err.println("Set value " + size);
cur_value = new BigInteger((new Long(size)).toString());
update();
}
/** This method is an unsafe way to set the progress bar to be indeterminate, -unless- it is called from the Event Queue. */
private void unsafeSetIndeterminate(boolean state) {
super.setIndeterminate(state);
}
private void unsafeSetString(String label) {
super.setString(label);
}
private void unsafeSetValue(int value) {
super.setValue(value);
}
private void update() {
int percentage = -1;
if(cur_value.equals(BigInteger.ZERO) || max_value.equals(BigInteger.ZERO)) {
percentage = 0;
}
else {
BigInteger tmp_value = cur_value.multiply(new BigInteger("100"));
BigInteger per_value = tmp_value.divide(max_value);
percentage = per_value.intValue();
if(percentage > 100) {
percentage = 100;
}
}
if(percentage != previous) {
///ystem.err.println("Progress bar status: value = " + getValue());
previous = percentage;
safeSetValue(percentage);
safeSetString(percentage + "%");
}
}
/** Change the string displayed on the progress bar.
* @param label The name progress bar label as a String.
* Original code: Tad Frysinger (TeamB)
*/
private void safeSetString(String label) {
if(safe_set_string == null) {
safe_set_string = new SafeSetString(label);
}
else {
safe_set_string.setLabel(label);
}
SwingUtilities.invokeLater(safe_set_string);
}
/** Increase the value of the progress bar.
* @param ammount The ammount to increase as an int.
* Original code: Tad Frysinger (TeamB)
*/
private void safeSetValue(final int ammount) {
// Update progress bar,
if(safe_set_value == null) {
safe_set_value = new SafeSetValue(ammount);
}
else {
safe_set_value.setValue(ammount);
}
SwingUtilities.invokeLater(safe_set_value);
}
private class SafeSetIndeterminate
implements Runnable {
private boolean value;
public SafeSetIndeterminate(boolean value) {
this.value = value;
}
public void run() {
unsafeSetIndeterminate(value);
}
synchronized public void setState(boolean value) {
this.value = value;
}
}
private class SafeSetString
implements Runnable {
private String label = null;
public SafeSetString(String label) {
this.label = label;
}
public void run() {
unsafeSetString(label);
}
synchronized public void setLabel(String label) {
this.label = label;
}
}
private class SafeSetValue
implements Runnable {
private int value = -1;
public SafeSetValue(int value) {
this.value = value;
}
public void run() {
unsafeSetValue(value);
}
synchronized public void setValue(int value) {
this.value = value;
}
}
}