// Copyright 1996, Marimba Inc. All Rights Reserved.


// @(#)ProgressIndicatorWidget.java, 1.17, 11/17/96





package marimba.gui;





import java.awt.*;


import marimba.persist.*;





/**


 * A progress indicator widget. A progress indicator can be used


 * to show the percentage of completion of a lengthy operation.


 * It consists of a rectangular bar that 'fills' from left to right.


 *


 * @author	Klaas Waslander


 * @version 	1.17, 11/17/96


 */


public class ProgressIndicatorWidget extends ValueWidget {


    final static Color  defaultBarColor = new Color(0, 0, 124);





    /**


     * The progress indicator can use blocks to indicate the progress.


     * @see #getBlockMode


     * @see #setBlockMode


     */


    public boolean  blockMode = true;





    /**


     * When blockMode is used, this determines the width of the blocks.


     * If the blockWidth is zero, the blocks are painted as square as


     * possible, using the method squareBlockWidth().


     * @see #getBlockWidth


     * @see #setBlockWidth


     * @see #squareBlockWidth


     */


    public int  blockWidth = 15;





    /**


     * The color of the bar.


     * @see #getBarColor


     * @see #setBarColor


     */


    public Color  barColor = defaultBarColor;





    /**


     * A progress indicator can show its percentage in the middle.


     * @see #getPercentage


     * @see #setPercentage


     */


    public boolean  showPercent = false;





    /**


     * A progress indicator can be filled.


     * @see #isFilled


     * @see #setFilled


     */


    public boolean  filled = false;








    /**


     * Constructor.


     */


    public ProgressIndicatorWidget() {


	this(0, 100, 50);


    }





    /**


     * Constructor; sets minValue, maxValue and value.


     */


    public ProgressIndicatorWidget(int min, int max, int val) {


	minValue = min;


	maxValue = max;


	value = val;


    }





    /**


     * Get the properties of the ProgressIndicatorWidget.


     */


    public void getProperties(PropertyList list) {


	super.getProperties(list);


	list.setColor("barColor", barColor, defaultBarColor);


	list.setBoolean("filled", filled, false);


	list.setBoolean("blockMode", blockMode, true);


	list.setInteger("blockWidth", blockWidth, 15);


	list.setBoolean("showPercent", showPercent, false);


    }





    /**


     * Set the properties of the ProgressIndicatorWidget.


     */


    public void setProperties(PropertyList list) {


	super.setProperties(list);


	barColor = list.getColor("barColor", defaultBarColor);


	filled = list.getBoolean("filled", false);


	blockMode = list.getBoolean("blockMode", true);


	setBlockWidth(list.getInteger("blockWidth", 15));


	showPercent = list.getBoolean("showPercent", false);


	transparent = !filled;


    }





    /**


     * Check whether the progress indicator is filled.


     * @see #filled


     */


    public boolean isFilled() {


	return filled;


    }





    /**


     * Let the progress indicator fill itself or not.


     * @see #filled


     */


    public void setFilled(boolean filled) {


	if (filled != this.filled) {


	    this.filled = filled;


	    repaint();


	}


    }





    /**


     * Check whether the progress indicator uses blocks.


     * @return true when blocks are being used, false otherwise.


     * @see #blockMode


     */


    public boolean getBlockMode() {


	return blockMode;


    }





    /**


     * Let the progress indicator use blocks or not.


     * @see #blockMode


     */


    public void setBlockMode(boolean blockMode) {


	if (this.blockMode != blockMode) {


	    this.blockMode = blockMode;


	    repaint();


	}


    }





    /**


     * Get the width of the blocks.


     * @see #blockWidth


     */


    public int getBlockWidth() {


	return blockWidth;


    }





    /**


     * Set the width of the blocks to a certain no. of pixels.


     * The width is not changed when the given blockwidth is 


     * less then zero.


     * @see #blockWidth


     */


    public void setBlockWidth(int blockWidth) {


	if (blockWidth >= 0 && this.blockWidth != blockWidth) {


	    this.blockWidth = blockWidth;


	    repaint();


	}


    }





    /**


     * Get the color of the bar.


     * @see #barColor


     */


    public Color getBarColor() {


	return barColor;


    }





    /**


     * Set the color of the bar. If the passed color


     * is null, the barColor is set to the default.


     * @see #barColor


     */


    public void setBarColor(Color barColor) {


	if (barColor == null) {


	    this.barColor = defaultBarColor;


	    repaint();


	} else if (!barColor.equals(this.barColor)) {


	    this.barColor = barColor;


	    repaint();


	}


    }





    /**


     * Check whether the progress indicator shows its pecentage


     * @see #showPercent


     */


    public boolean showsPercent() {


	return showPercent;


    }





    /**


     * Let the progress indicator show its percentage or not.


     * @see #showPercent


     */


    public void showPercent(boolean showPercent) {


	if (showPercent != this.showPercent) {


	    this.showPercent = showPercent;


	    repaint();


	}


    }





    /**


     * Get the current percentage of the progress indicator.


     * @see #getStringPercentage


     * @see #showPercent


     */


    public int getPercentage() {


	// translate value back to zero


	int  value = this.value - minValue;





	int  range = (getRange() == 0) ? 1 : getRange();


	return (value * 100) / range;


    }





    /**


     * Get the current percentage as a string, for example "50%".


     * @see #getPercentage


     * @see #showPercent


     */


    public String getStringPercentage() {


	return (String.valueOf(getPercentage()) + "%");


    }





    /**


     * Determine the width of the blocks to let them be as square


     * as possible.


     * @see #blockWidth


     */


    public int squareBlockWidth() {


	int	nrOfBlocks = (width - 2) / height;


	return ((width - 2) / nrOfBlocks);


    }





    /**


     * The value translated into pixels.


     */


    public int valueToPixels(int value) {


	int  result;


	if (blockMode) {


	    // translate value back to zero


	    value = value - minValue;


	    int  range = maxValue - minValue;


	    range = (range == 0) ? 1 : range;


	    int  blockWidth = this.blockWidth > 0 ? this.blockWidth : squareBlockWidth();


	    int  nrOfBlocks = (width - 2) / blockWidth;


	    int  blocksToPaint = (nrOfBlocks * value) / range;


	    result = Math.max(0, blocksToPaint * blockWidth);


	} else {


	    result = (getPercentage() * (width - 5)) / 100;


	}


	return result;


    }





    /**


     * Assumes the given values are valid. Checks whether these values


     * would result in a new look that requires a repaint.


     */


    protected boolean repaintFor(int newValue, int newMin, int newMax) {


	boolean  result = false;


	// store old values


	int  oldPercentage = getPercentage();


	int  oldPixelValue = valueToPixels(value);





	// calculate new percentage


	newValue = newValue - newMin;


	int  range = maxValue - minValue;


	range = (range == 0) ? 1 : range;


	int  newPercentage = (newValue * 100) / range;





	// calculate new pixelvalue


	int  newPixelValue;


	if (blockMode) {


	    int  blockWidth = this.blockWidth > 0 ? this.blockWidth : squareBlockWidth();


	    int  nrOfBlocks = (width - 2) / blockWidth;


	    int  blocksToPaint = (nrOfBlocks * newValue) / range;


	    newPixelValue = Math.max(0, blocksToPaint * blockWidth);


	} else {


	    newPixelValue = (newPercentage * (width - 5)) / 100;


	}





	// check whether a repaint is necessary for the given values


	if (oldPixelValue != newPixelValue || (showPercent && oldPercentage != newPercentage)) {


	    result = true;


	}


	return result;


    }





    /**


     * Paint the progress indicator.


     */


    public void paint(Graphics g) {


	int  range = maxValue - minValue;


	range = (range == 0) ? 1 : range;





	// draw border


	g.setColor(background);


	


	// fill if necessary


	Bevel.drawRect(g, 0, 0, width, height, false, 1);


	if (filled) {


	    g.setColor(hilite);


	    int  margin = 1;


	    if (!blockMode) {


		margin += 1;


	    }


	    g.fillRect(margin, margin, width-margin*2, height-margin*2);


	}





	// translate value back to zero


	int  value = this.value - minValue;





	// paint the progress


	int pixelsToPaint = 0;


	g.setColor(this.barColor);


	if (blockMode) {


	    int  blockWidth = this.blockWidth > 0 ? this.blockWidth : squareBlockWidth();


	    int  nrOfBlocks = (width - 2) / blockWidth;


	    int  blocksToPaint = (nrOfBlocks * value) / range;





	    // paint the blocks


	    for (int blocks = 0; blocks < blocksToPaint; blocks++) {


		pixelsToPaint += blockWidth;


		g.fillRect(blocks * blockWidth + 2, 2, blockWidth - 2, height - 4);


	    }


	    pixelsToPaint = Math.max(0, pixelsToPaint-2);


	} else {


	    // paint bar


	    pixelsToPaint = (getPercentage() * (width - 5)) / 100;


	    g.fillRect(2, 2, pixelsToPaint, height - 4);





	    // paint extra border


	    g.setColor(Color.black);


	    g.drawLine(1, 1, width-2, 1);


	    g.drawLine(1, 2, 1, height-2);


	    g.setColor(background);


	    g.drawLine(1, height-2, width-2, height-2);


	    g.drawLine(width-2, height-2, width-2, 1);


	}





	if (showPercent) {


	    // calculate position to draw the percentage


	    FontMetrics	fm = getFontMetrics(getFont());


	    String  percent = getStringPercentage();


	    int  xPos = ( width - fm.stringWidth(percent) ) / 2;


	    int  yPos = (height + (fm.getHeight() / 2)) / 2 + 1;





	    // draw percentage inside bar


	    Graphics  gIn = g.create();


	    try {


		gIn.clipRect(0, 0, pixelsToPaint + 2, height);


		gIn.setColor((isFilled()) ? hilite : background);


		gIn.drawString(percent, xPos, yPos);


	    } finally {


		gIn.dispose();


	    }





	    // draw percentage-string outside bar


	    Graphics  gOut= g.create();


	    try {


		gOut.clipRect(pixelsToPaint + 2, 0, width - pixelsToPaint - 3, height);


		gOut.setColor(barColor);


		gOut.drawString(percent, xPos, yPos);


	    } finally {


		gOut.dispose();


	    }


	}


    }   





    /**


     * Debugging.


     */


    public void paramString(StringBuffer buf) {


	super.paramString(buf);


	buf.append(",blockWidth=");


	buf.append(blockWidth);


	buf.append(",color=");


	buf.append(barColor);


   }


}


