/** *######################################################################### * * 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; } } }