/** * MemoryStatusGraph displays a histogram of memory usage. * * Copyright &copy; 1996-1998 Martin Minow. All Rights Reserved.<p> * * Permission to use, copy, modify, and redistribute this software and its * documentation for personal, non-commercial use is hereby granted provided that * this copyright notice and appropriate documentation appears in all copies. This * software may not be distributed for fee or as part of commercial, "shareware," * and/or not-for-profit endevors including, but not limited to, CD-ROM collections, * online databases, and subscription services without specific license.<p> * * @author <a href="mailto:minow@apple.com">Martin Minow</a> * @version 1.0 * Set tabs every 4 characters. */import java.applet.Applet;import java.awt.*;public class MemoryStatusGraph extends Canvas{	private transient int[]		total				= new int[1];	private transient int[]		usage				= new int[1];	private transient int		graphMax			= 1;	private transient int		index				= 0;	private transient boolean	wrap				= false;	private transient int		width				= 0;	private transient int		height				= 0;		private Color		freeColor		= Color.green;	private Color		usageColor		= Color.yellow;	private Color		gridColor		= Color.blue;			/**	 * MemoryStatusGraph is a trivial ticker-tape histogram	 * display. Each ticker line is displayed as follows:	 *	base	.. usageK	Yellow	 *	usageK	.. totalK	Green	 *	totalK	.. topK		Background color	 */	public MemoryStatusGraph()	{		setBackground(Color.white);		resetGraph();	}	/**	 * initialize resets the statistics and restarts the display.	 */	public synchronized void resetGraph()	{		total				= new int[1];		usage				= new int[1];		index				= 0;		wrap				= false;		graphMax			= Integer.MIN_VALUE;		update(getGraphics(), -1, -1, false, true); 	}	/**	 * Add a new value to the histogram and slide it along.	 * Returns the value of the top of the histogram, which	 * should be greater than the largest value in the display.	 */	public synchronized int setValues(			int				totalValue,			int				usageValue		)	{		update(getGraphics(), totalValue, usageValue, false, false);		return (graphMax);	}	public void paint(			Graphics		g		)	{		update(g);	}	public void update(			Graphics		g		)	{		update(g, -1, -1, true, false);	}	public synchronized void update(			Graphics		g,			int				totalValue,			int				usageValue,			boolean			fullRepaint,			boolean			initialize		)	{		if (g == null) { return; }		Dimension d			= size();		/*		 * If the display shape changes or we are explicitly		 * re-initializing, reset the graph shadow.		 */		if (d.width != width		 || d.height != height		 || initialize) {			width			= d.width;			height			= d.height;			total			= new int[width];			usage			= new int[width];			fullRepaint		= true;			index			= 0;			wrap			= false;		}		if (fullRepaint || totalValue >= graphMax) {			/*			 * Clear the display and repaint all data			 */			if (totalValue >= graphMax) {				graphMax	= getGraphMax(totalValue);			}			fullRepaint		= true;		}		double scale		=  ((double) height) / ((double) graphMax);		int intervals		= getGraphPixelInterval(graphMax);		if (fullRepaint) {			g.clearRect(0, 0, width, height);			g.setColor(gridColor);			int interval = height / intervals;			for (int i = 0; i < height; i += interval) {				g.drawLine(0, i, width, i);			}			if (wrap) {				for (int i = index; i < width; i++) {					drawOneValue(g,							i,							total[i],							usage[i],							scale,							intervals						);				}			}			for (int i = 0; i < index; i++) {				drawOneValue(g,						i,						total[i],						usage[i], scale, intervals);			}		}		if (totalValue >= 0) {			/*			 * Add a new value			 */			if (index >= width) {				index		= 0;				wrap		= true;			}			total[index]	= totalValue;			usage[index]	= usageValue;			g.copyArea(0, 0, d.width, d.height, 1, 0);			g.clearRect(0, 0, 1, d.height);			drawOneValue(g, 0,					totalValue, usageValue, scale, intervals);		}	}	protected void drawOneValue(			Graphics		g,			int				x,			int				totalValue,			int				usageValue,			double			scale,			int				intervals		)	{		int	yTotal	= (int) Math.round(((double) totalValue) * scale);		int yUsage	= (int) Math.round(((double) usageValue) * scale);		g.setColor(usageColor);		g.drawLine(x, height, x, height - yUsage);		g.setColor(freeColor);		g.drawLine(x, height - yUsage, x, height - yTotal);		g.setColor(getBackground());		g.drawLine(x, 0, x, height - yTotal);		g.setColor(gridColor);		int interval = height / intervals;		for (int i = 0; i < height; i += interval) {			g.drawLine(x, i, x, i);		}	}	/**	 * Compute a value that is nicely larger than the current max value.	 */	public static final double	logE10		= Math.log(10.0);	public static final double	log2		= Math.log(2.0) / logE10;	public static final double	log5		= Math.log(5.0) / logE10;	public static final double	log7		= Math.log(7.0) / logE10;	public static final double	increase	= 1.01;	public static int getGraphMax(			double			maxValue		)	{		int					result;				if (maxValue < 1.0) {			maxValue		= 1.0;		}		double logValue		= Math.log(maxValue * increase) / logE10;		double exponent		= Math.floor(logValue);		double fraction		= logValue - exponent;		if (false) {			System.out.println(				"value = " + maxValue				+ ", logValue = " + logValue				+ ", exponent = " + exponent				+ ", fraction = " + fraction				+ ", logE10 = " + logE10				+ ", log2 = " + log2				+ ", log5 = " + log5				+ ", log7 = " + log7			);		}		if (fraction <= 0.0)		{ result = 1;	}		else if (fraction <= log2)	{ result = 2;	}		else if (fraction <= log5)	{ result = 5;	}		else if (fraction <= log7)	{ result = 7;	}		else						{ result = 10;	}		result *= (int) Math.round(Math.pow(10.0, exponent));		return (result);	}	/**	 * Compute a pixel interval that can be used to draw horizonta	 * grid lines. The graphMax parameter was computed by getGraphMax.	 */	public static int getGraphPixelInterval(			int				graphMax		)	{		int					intervals;				if (graphMax < 1) {			graphMax		= 1;		}		double logValue		= Math.log(((double) graphMax) * increase) / logE10;		double exponent		= Math.floor(logValue);		double fraction		= logValue - exponent;		if (fraction <= 0.0)					{ intervals = 5;	}		else if (fraction <= (log2 + 0.005))	{ intervals = 4;	}		else if (fraction <= (log5 + 0.005))	{ intervals = 5;	}		else if (fraction <= (log7 + 0.005))	{ intervals = 7;	}		else									{ intervals = 5;	}		return (intervals);	}	public Dimension preferredSize()	{		return (new Dimension(200, 96));	}	public Dimension getPreferredSize()	{		return (preferredSize());	}	/*	 * Accessor functions to allow MemoryStatusGraph to live	 * as a JavaBean. The range from the top of the memory area	 * to the top of the graph view area is drawn in the	 * background color.	 */	public Color	getGridColor()		{ return (gridColor);	}	public Color	getFreeColor()		{ return (freeColor);	}	public Color	getUsageColor()		{ return (usageColor);	}	public void		setGridColor(			Color			color		)	{		this.gridColor		= color;		repaint();	}	public void		setFreeColor(			Color			color		)	{		this.freeColor		= color;		repaint();	}	public void		setUsageColor(			Color			color		)	{		this.usageColor		= color;		repaint();	}	}