/*
* ProgressBar.java
* (FScape)
*
* Copyright (c) 2001-2016 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*
*
* Changelog:
* 14-Apr-06 created
* 24-Jun-06 copied from de.sciss.eisenkraut.gui.ProgressPanel
* 03-Oct-06 added methods required by ProcessPanel
*/
package de.sciss.fscape.gui;
import de.sciss.gui.ProgressComponent;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
/**
* A bit more sophisticated progression bar
* than the default one provided by Swing,
* a slim version of the one used in FScape.
* This class provides methods for changing
* the bar's colour and text. If no text is
* set, the bar will try to estimate the
* remaining progression time.
*/
public class ProgressBar
extends JProgressBar {
// -------- private variables --------
protected float p = 0.0f;
private long startTime; // time at which reset() was called
private long pauseTime;
private int remain;
private byte timeStr[];
protected int maximum = 0;
private String altString = null;
private static final Color COLOR_SUCCESS = new Color( 0x00, 0xFF, 0x00, 0x2F );
private static final Color COLOR_FAILURE = new Color( 0xFF, 0x00, 0x00, 0x2F );
private Paint pnt = null;
private boolean timePainted = false;
// -------- public --------
/**
* Constructs a new horizontal
* progression bar
*/
public ProgressBar() {
super(SwingConstants.HORIZONTAL, 0, 0x1000);
// web-laf uses different component heights; therefore leave this flag on
setStringPainted(true);
timeStr = "00:00:00".getBytes();
reset();
this.addComponentListener( new ComponentAdapter() {
public void componentResized( ComponentEvent e1 )
{
Dimension d = getSize();
maximum = d.width;
setMaximum( d.width );
setValue( (int) (p * maximum) );
}
});
}
/**
* Sets or clears the text that is displayed on top
* of the bar.
*
* @param altString the text to display on the
* bar or <code>null</code> to clear
* the text. in this case the bar will
* display a remaining-time string
*/
public void setText(String altString) {
this.altString = altString;
setString(altString == null ? "" : altString);
// setStringPainted( altString != null );
}
/**
* Sets the progression amount in percent.
*
* Warning: use only this method to change the progression,
* don't use the superclass's setValue method
*
* @param p progression, between 0 and 1 (i.e. 0 and 100%)
*/
public synchronized void setProgression(float p) {
int oldProgWidth = (int) (this.p * maximum);
this.p = Math.max( 0.0f, Math.min( 1.0f, p ));
int progWidth = (int) (this.p * maximum);
int lastRemain = remain;
int elapsed, hours, minutes, secs;
if( progWidth != oldProgWidth ) {
setValue( progWidth );
if( p > 0f ) {
elapsed = (int) (System.currentTimeMillis() - startTime) / 1000;
remain = (int) (elapsed / p) - elapsed;
if( (((elapsed >= 10) & (remain >= 10)) | timePainted) & (altString == null) & !isIndeterminate() ) {
// only update if changes are reasonable
if( (remain < lastRemain) || ((remain - lastRemain) >= 10) ) {
secs = remain % 60;
timeStr[ 6 ] = (byte) ((secs / 10) + 48);
timeStr[ 7 ] = (byte) ((secs % 10) + 48);
minutes = (remain / 60) % 60;
timeStr[ 3 ] = (byte) ((minutes / 10) + 48);
timeStr[ 4 ] = (byte) ((minutes % 10) + 48);
hours = (remain / 3600) % 100;
timeStr[ 0 ] = (byte) ((hours / 10) + 48);
timeStr[ 1 ] = (byte) ((hours % 10) + 48);
setString(new String(timeStr));
timePainted = true;
// setStringPainted(true);
} else {
remain = lastRemain; // vvv avoid flickering
}
}
}
}
}
/**
* Queries the progression
*
* @return the progression value between 0 and 1 (i.e. 0 and 100%)
*/
public float getProgression()
{
return p;
}
/**
* Reset progression to zero. Remove any
* custom text strings and custom bar colour.
* Initializes the remaining-time estimation
* with the current system time.
*/
public void reset() {
setIndeterminate(false);
setProgression(0f);
setPaint(null);
// setString(""); // null);
timePainted = false;
// setStringPainted( false );
setText(null);
remain = 1 << 29;
startTime = System.currentTimeMillis();
}
/**
* Pauses progression. You have to call
* this if the user pauses a progress
* because in this case the calculation
* of the remaining time should be paused
* as well.
*/
public void pause()
{
pauseTime = System.currentTimeMillis();
}
/**
* Resumes progression and calculation of
* remaining time.
*/
public void resume()
{
startTime += System.currentTimeMillis() - pauseTime;
}
/**
* Finish the progression. This clears
* custom text strings, clears indeterminate
* state and sets the bars colour depending
* on the success.
*/
public void finish(int result) {
setIndeterminate(false);
setValue(maximum);
setString(""); // null);
timePainted = false;
// setStringPainted(false);
if (result == ProgressComponent.DONE) {
setPaint(COLOR_SUCCESS);
} else if (result == ProgressComponent.FAILED) {
setPaint(COLOR_FAILURE);
}
}
/**
* Sets a custom bar color
*
* @param pnt the new color or <code>null</code>
* to remove custom color.
*/
public void setPaint(Paint pnt) {
this.pnt = pnt;
repaint();
}
/**
* Queries the custom bar color.
*
* @return the bar color or <code>null</code> if
* no custom color was set
*/
public Paint getPaint() {
return pnt;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (pnt == null) return;
final Dimension d = getSize();
final Graphics2D g2 = (Graphics2D) g;
final Paint op = g2.getPaint();
final String lafName = UIManager.getLookAndFeel().getName();
final boolean isWebLaF = lafName.equals("WebLaF");
final int top = isWebLaF ? 3 : 1;
final int left = isWebLaF ? 3 : 2;
final int bottom = isWebLaF ? 3 : 2;
final int right = isWebLaF ? 3 : 2;
g2.setPaint(pnt);
g2.fillRect(left, top, d.width - (left + right), d.height - (top + bottom));
g2.setPaint(op);
}
}