/**
* Copyright (c) 2009 - 2010 AppWork UG(haftungsbeschränkt) <e-mail@appwork.org>
*
* This file is part of org.appwork.utils.swing
*
* This software is licensed under the Artistic License 2.0,
* see the LICENSE file or http://www.opensource.org/licenses/artistic-license-2.0.php
* for details
*/
package org.appwork.utils.swing;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.appwork.utils.formatter.SizeFormatter;
import org.appwork.utils.locale.APPWORKUTILS;
import org.appwork.utils.swing.graph.Limiter;
/**
* @author thomas
*
*/
abstract public class Graph extends JPanel {
private static final long serialVersionUID = 6943108941655020136L;
private int i;
private int[] cache;
private transient Thread fetcherThread;
private int interval = 1000;
private Timer painter;
private final Object LOCK = new Object();
private Color colorA;
private Color colorB;
public long average;
private int[] averageCache;
private Color averageColor = new Color(0x333333);
private Color averageTextColor = new Color(0);
private int capacity = 0;
private Color textColor = new Color(0);
private boolean running = false;
protected int value;
private Font textFont;
private int all;
private Limiter[] limiter;
public Graph() {
this(60, 1000);
}
public Graph(final int capacity, final int interval) {
this.colorA = new Color(100, 100, 100, 40);
this.colorB = new Color(100, 100, 100, 80);
this.average = 0;
this.setInterval(interval);
this.setCapacity(capacity);
this.setOpaque(false);
}
/**
* @return the averageColor
*/
public Color getAverageColor() {
return this.averageColor;
}
/**
* @return
*/
public String getAverageSpeedString() {
// TODO Auto-generated method stub
if (this.all <= 0) { return null; }
return APPWORKUTILS.T.AppWorkUtils_Graph_getAverageSpeedString(SizeFormatter.formatBytes(this.average / this.all));
}
/**
* @return the averageTextColor
*/
public Color getAverageTextColor() {
return this.averageTextColor;
}
/**
* @return the colorA
*/
public Color getColorA() {
return this.colorA;
}
/**
* @return the colorB
*/
public Color getColorB() {
return this.colorB;
}
public int getInterval() {
return this.interval;
}
/**
* @return
*/
public Limiter[] getLimiter() {
return this.limiter;
}
/**
* @return
*/
public String getSpeedString() {
// TODO Auto-generated method stub
if (this.all <= 0) { return null; }
return APPWORKUTILS.T.AppWorkUtils_Graph_getSpeedString(SizeFormatter.formatBytes(this.value));
}
/**
* @return the textColor
*/
public Color getTextColor() {
return this.textColor;
}
/**
* @return the textFont
*/
public Font getTextFont() {
return this.textFont;
}
/**
* @return
*/
abstract public int getValue();
@Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
if (this.fetcherThread != null) {
final Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1));
int id = this.i;
int max = 10;
for (final int element : this.cache) {
max = Math.max(element, max);
}
for (final int element : this.averageCache) {
max = Math.max(element, max);
}
if (this.getLimiter() != null) {
for (final Limiter l : this.getLimiter()) {
max = Math.max(l.getValue(), max);
}
}
final int height = this.getHeight();
final Polygon poly = new Polygon();
poly.addPoint(0, this.getHeight());
final Polygon apoly = new Polygon();
apoly.addPoint(0, this.getHeight());
for (int x = 0; x < this.cache.length; x++) {
poly.addPoint(x * this.getWidth() / (this.cache.length - 1), this.getHeight() - (int) (this.getHeight() * this.cache[id] * 0.9) / max);
if (this.averageColor != null) {
apoly.addPoint(x * this.getWidth() / (this.cache.length - 1), this.getHeight() - (int) (this.getHeight() * this.averageCache[id] * 0.9) / max);
}
id++;
id = id % this.cache.length;
}
poly.addPoint(this.getWidth(), height);
apoly.addPoint(this.getWidth(), height);
g2.setPaint(new GradientPaint(this.getWidth() / 2, 0, this.colorA, this.getWidth() / 2, height, this.colorB));
g2.fill(poly);
g2.setColor(this.colorB);
g2.draw(poly);
String speedString = this.getSpeedString();
int xText = this.getWidth();
if (this.textFont != null) {
g2.setFont(this.textFont);
}
if (speedString != null && this.running) {
g2.setColor(this.getTextColor());
g2.drawString(speedString, xText = xText - 3 - g2.getFontMetrics().stringWidth(speedString), 12);
}
if (this.averageColor != null) {
((Graphics2D) g).setColor(this.averageColor);
final AlphaComposite ac5 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
g2.setComposite(ac5);
g2.fill(apoly);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
g2.draw(apoly);
speedString = this.getAverageSpeedString();
if (speedString != null && this.running) {
g2.setColor(this.getAverageTextColor());
g2.drawString(speedString, xText - 3 - g2.getFontMetrics().stringWidth(speedString), 12);
}
}
if (this.getLimiter() != null) {
int h;
for (final Limiter l : this.getLimiter()) {
if (l.getValue() > 0) {
h = this.getHeight() - (int) (this.getHeight() * l.getValue() * 0.9) / max;
g2.setPaint(new GradientPaint(this.getWidth() / 2, h, l.getColorA(), this.getWidth() / 2, h + height / 10, l.getColorB()));
g2.fillRect(0, h, this.getWidth(), height / 10);
// g2.drawRect(0, h, this.getWidth(), height / 5);
}
}
}
}
}
/**
* resets the average cache and makes sure, that the average recalculates
* within a few cycles
*/
protected void resetAverage() {
final int tmp = this.all;
if (tmp == 0) {
this.average = 0;
} else {
this.average /= tmp;
}
this.average *= 3;
this.all = 3;
}
/**
* @param averageColor
* the averageColor to set
*/
public void setAverageColor(final Color averageColor) {
this.averageColor = averageColor;
}
/**
* @param averageTextColor
* the averageTextColor to set
*/
public void setAverageTextColor(final Color averageTextColor) {
this.averageTextColor = averageTextColor;
}
/**
* @param j
*/
protected void setCapacity(final int cap) {
if (this.fetcherThread != null) { throw new IllegalStateException("Already started"); }
this.capacity = cap;
this.cache = new int[cap];
for (int x = 0; x < cap; x++) {
this.cache[x] = 0;
}
this.averageCache = new int[cap];
for (int x = 0; x < cap; x++) {
this.averageCache[x] = 0;
}
}
/**
* @param colorA
* the colorA to set
*/
public void setColorA(final Color colorA) {
this.colorA = colorA;
}
/**
* @param colorB
* the colorB to set
*/
public void setColorB(final Color colorB) {
this.colorB = colorB;
}
public void setInterval(final int interval) {
this.interval = interval;
}
public void setLimiter(final Limiter[] limiter) {
this.limiter = limiter;
}
/**
* @param textColor
* the textColor to set
*/
public void setTextColor(final Color textColor) {
this.textColor = textColor;
}
/**
* @param textFont
* the textFont to set
*/
public void setTextFont(final Font textFont) {
this.textFont = textFont;
}
public void start() {
synchronized (this.LOCK) {
if (this.fetcherThread != null) {
// already running
return;
}
this.running = true;
this.painter = new Timer(this.getInterval(), new ActionListener() {
public void actionPerformed(final ActionEvent e) {
synchronized (Graph.this.LOCK) {
Graph.this.repaint();
}
}
});
this.painter.setRepeats(true);
this.painter.setInitialDelay(0);
this.i = 0;
this.fetcherThread = new Thread("Speedmeter updater") {
@Override
public void run() {
Graph.this.all = 0;
Graph.this.average = 0;
while (!this.isInterrupted()) {
synchronized (Graph.this.LOCK) {
Graph.this.value = Graph.this.getValue();
if (Graph.this.all == Graph.this.cache.length) {
Graph.this.average = Graph.this.average - Graph.this.cache[Graph.this.i] + Graph.this.value;
} else {
Graph.this.average = Graph.this.average + Graph.this.value;
}
Graph.this.all = Math.min(Graph.this.all + 1, Graph.this.cache.length);
Graph.this.averageCache[Graph.this.i] = (int) (Graph.this.average / Graph.this.all);
Graph.this.cache[Graph.this.i] = Graph.this.value;
Graph.this.i++;
Graph.this.i = Graph.this.i % Graph.this.cache.length;
}
if (this.isInterrupted()) { return; }
try {
Thread.sleep(Graph.this.getInterval());
} catch (final InterruptedException e) {
return;
}
}
}
};
this.fetcherThread.start();
this.painter.start();
}
}
public void stop() {
synchronized (this.LOCK) {
this.running = false;
if (this.fetcherThread != null) {
this.fetcherThread.interrupt();
this.fetcherThread = null;
}
if (this.painter != null) {
this.painter.stop();
this.painter = null;
}
Graph.this.repaint();
this.setCapacity(this.capacity);
}
}
}