You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeutils/ksim/library/chart.cpp

628 lines
14 KiB

/* ksim - a system monitor for kde
*
* Copyright (C) 2001 Robbie Ward <linuxphreak@gmx.co.uk>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "chart.h"
#include "chart.moc"
#include <qrect.h>
#include <qpainter.h>
#include <qimage.h>
#include <qcolor.h>
#include <qtimer.h>
#include <qvaluelist.h>
#include <qbitmap.h>
#include <kdebug.h>
#include <klocale.h>
#include <kglobalsettings.h>
#include <kconfig.h>
#include <themeloader.h>
#include <led.h>
#include <ksimconfig.h>
#include "themetypes.h"
class KSim::Chart::Timer
{
public:
static void syncChart(KSim::Chart *chart)
{
if (!m_timer) {
m_timer = new QTimer;
m_timer->start(1000);
qAddPostRoutine(cleanup);
}
QObject::connect(m_timer, SIGNAL(timeout()),
chart, SLOT(updateDisplay()));
}
static void disconnect(KSim::Chart *chart)
{
if (!m_timer)
return;
QObject::disconnect(m_timer, SIGNAL(timeout()),
chart, SLOT(updateDisplay()));
}
private:
static void cleanup()
{
if (!m_timer)
return;
delete m_timer;
m_timer = 0;
}
static QTimer *m_timer;
};
QTimer *KSim::Chart::Timer::m_timer = 0;
class KSim::Chart::Private
{
public:
typedef QPair<int, int> ValuePair;
QSize size;
int type;
bool showShadow;
bool showKrell;
QString inText;
QString outText;
QString title;
QPixmap chartPixmap;
QPixmap gridPixmap;
QPixmap graphData;
QColor mColour;
QColor sColour;
QColor dataInColour;
QColor dataOutColour;
Chart::LabelType labelType;
KSim::Label *krell;
// first will be data In and second will be data out
QValueList<ValuePair> values;
QValueList<int> maxValues;
int minValue;
int maxValue;
bool variableGraphs;
};
KSim::Chart::Chart(bool showKrell, int maxValue,
const QString &title, QWidget *parent, const char *name,
WFlags fl) : QWidget(parent, name, fl)
{
init(showKrell, maxValue, title);
}
KSim::Chart::Chart(bool showKrell, int maxValue,
QWidget *parent, const char *name, WFlags fl)
: QWidget(parent, name, fl)
{
init(showKrell, maxValue, i18n("None"));
}
KSim::Chart::~Chart()
{
delete d->krell;
delete d;
}
const QString &KSim::Chart::text(DataType type) const
{
if (type == DataIn)
return d->inText;
return d->outText;
}
const QString &KSim::Chart::title() const
{
return d->title;
}
bool KSim::Chart::displayMeter() const
{
return d->showKrell;
}
int KSim::Chart::minValue() const
{
return d->minValue;
}
int KSim::Chart::maxValue() const
{
return d->maxValue;
}
int KSim::Chart::value(DataType dataType) const
{
switch (dataType) {
case DataIn:
return d->values.first().first;
break;
case DataOut:
return d->values.first().second;
break;
}
return 0;
}
void KSim::Chart::setLabelType(LabelType labelType)
{
d->labelType = labelType;
// return if d->krell is not NULL and if the label type is the
// same or if showKrell is set to false
if ((d->krell && d->labelType == labelType) || !d->showKrell)
return;
delete d->krell;
switch (labelType) {
case Label:
d->krell = new KSim::Label(this);
break;
case Progress:
d->krell = new KSim::Progress(maxValue(), KSim::Types::None,
KSim::Progress::Panel, this);
break;
case Led:
d->krell = new KSim::LedLabel(maxValue(), KSim::Types::None, this);
break;
}
int height = d->krell->height() - 2;
d->krell->setText(title());
d->krell->setFixedSize(width(), height);
d->krell->move(0, d->size.height() - height);
d->krell->show();
}
KSim::Chart::LabelType KSim::Chart::labelType() const
{
return d->labelType;
}
void KSim::Chart::buildPixmaps()
{
QImage image(themeLoader().current().chartPixmap());
KSim::ThemeLoader::self().reColourImage(image);
d->chartPixmap.convertFromImage(image.smoothScale(chartSize()));
// We need to reset the image data just
// incase the krellDataIn image doesn't exist
image.reset();
image.load(themeLoader().current().gridPixmap());
KSim::ThemeLoader::self().reColourImage(image);
d->gridPixmap.convertFromImage(image.smoothScale(chartSize().width(), 1));
// load these values here so we dont need to keep accessing them while
// painting to keep the cpu usage down
d->dataInColour = themeLoader().current().chartInColour();
d->dataOutColour = themeLoader().current().chartOutColour();
image.reset();
image.load(themeLoader().current().dataInPixmap());
KSim::ThemeLoader::self().reColourImage(image);
if (!image.isNull()) {
d->dataInColour = image.smoothScale(chartSize()).pixel(2, 2);
kdDebug(2003) << className() << ": Using krellDataIn() = "
<< themeLoader().current().dataInPixmap() << endl;
}
else {
kdDebug(2003) << className() << ": Using chartInColor() = "
<< d->dataInColour.name() << endl;
}
image.reset();
image.load(themeLoader().current().dataOutPixmap());
KSim::ThemeLoader::self().reColourImage(image);
if (!image.isNull()) {
d->dataOutColour = image.smoothScale(chartSize()).pixel(2, 2);
kdDebug(2003) << className() << ": Using krellDataOut() = "
<< themeLoader().current().dataOutPixmap() << endl;
}
else {
kdDebug(2003) << className() << ": Using chartOutColor() = "
<< d->dataOutColour.name() << endl;
}
}
void KSim::Chart::configureObject(bool repaintWidget)
{
QSize oldSize = sizeHint();
KSim::Config::config()->setGroup("Misc");
d->size = KSim::Config::config()->readSizeEntry("GraphSize");
if (d->krell && d->showKrell) {
int krellHeight = d->krell->fontMetrics().height() - 2;
d->size.setHeight(d->size.height() + krellHeight);
d->krell->setFixedHeight(krellHeight);
d->krell->move(0, d->size.height() - krellHeight);
d->krell->show();
}
// Update our geometry if we need to let any
// layout know about our sizeHint() change
if (oldSize != sizeHint()) {
// Using resize() here seems to be needed
resize(sizeHint());
updateGeometry();
}
buildPixmaps();
setConfigValues();
if (repaintWidget)
update();
}
QSize KSim::Chart::sizeHint() const
{
return d->size;
}
QSize KSim::Chart::minimumSizeHint() const
{
return sizeHint();
}
void KSim::Chart::resizeEvent(QResizeEvent *re)
{
if (d->chartPixmap.size() != chartSize())
buildPixmaps();
QWidget::resizeEvent(re);
}
void KSim::Chart::disableAutomaticUpdates()
{
KSim::Chart::Timer::disconnect(this);
}
void KSim::Chart::clear()
{
d->values.clear();
d->maxValues.clear();
updateDisplay();
}
void KSim::Chart::setTitle(const QString &name)
{
if (d->krell) {
d->title = name;
d->krell->setText(name);
}
}
void KSim::Chart::setDisplayMeter(bool value)
{
if (d->showKrell == value)
return;
d->showKrell = value;
setLabelType(d->labelType);
// delete the meter if value is false
if (!value) {
delete d->krell;
d->krell = 0;
}
}
void KSim::Chart::setText(const QString &in, const QString &out)
{
bool repaint = false;
if (d->inText != in) {
repaint = true;
d->inText = in;
}
if (d->outText != out) {
repaint = true;
d->outText = out;
}
if (repaint)
update();
}
void KSim::Chart::setMinValue(int minValue)
{
if (d->minValue == minValue)
return;
d->minValue = minValue;
if (d->krell && labelType() != Label)
static_cast<KSim::Progress *>(d->krell)->setMinValue(minValue);
}
void KSim::Chart::setMaxValue(int maxValue)
{
if (d->maxValue == maxValue)
return;
d->maxValue = maxValue;
if (d->krell && labelType() != Label)
static_cast<KSim::Progress *>(d->krell)->setMaxValue(maxValue);
}
void KSim::Chart::setValue(int valueIn, int valueOut)
{
d->values.prepend(qMakePair(range(valueIn), range(valueOut)));
if (d->variableGraphs) {
d->maxValues.prepend(valueIn > valueOut ? valueIn : valueOut);
}
else {
if (valueIn > maxValue())
setMaxValue(valueIn);
if (valueOut > maxValue())
setMaxValue(valueOut);
}
if (d->krell && labelType() != Label)
static_cast<KSim::Progress *>(d->krell)->setValue(valueIn ? valueIn
: valueOut);
// Remove the first entry from our lists to
// make sure we only have a list the size of
// our widgets width
if (d->values.count() == (uint)(width() + 1)) {
d->values.remove(--(d->values.end()));
d->maxValues.remove(--(d->maxValues.end()));
}
if (d->krell && labelType() == Led) {
static_cast<KSim::LedLabel *>(d->krell)->toggle(KSim::Led::First);
static_cast<KSim::LedLabel *>(d->krell)->toggle(KSim::Led::Second);
}
}
void KSim::Chart::setConfigValues()
{
QFont newFont = font();
bool repaint = themeLoader().current().fontColours(this,
newFont, d->mColour, d->sColour, d->showShadow);
if (font() != newFont)
setFont(newFont);
if (repaint)
update();
}
void KSim::Chart::extraTypeCall()
{
setConfigValues();
}
QColor KSim::Chart::chartColour(const DataType &dataType, int, int) const
{
switch (dataType) {
case DataIn:
return d->dataInColour;
break;
case DataOut:
return d->dataOutColour;
break;
}
return QColor(); // avoid a g++ warning
}
void KSim::Chart::paintEvent(QPaintEvent *)
{
if (d->krell && labelType() == Led) {
static_cast<KSim::LedLabel *>(d->krell)->setOff(KSim::Led::First);
static_cast<KSim::LedLabel *>(d->krell)->setOff(KSim::Led::Second);
}
const QSize &size = chartSize();
QPixmap pixmap(size);
QPainter painter;
painter.begin(&pixmap, this);
int location = size.height() / 5;
painter.drawPixmap(0, 0, d->chartPixmap);
// draw the plotted data onto the graph
painter.drawPixmap(0, 0, d->graphData);
painter.drawPixmap(0, location, d->gridPixmap);
painter.drawPixmap(0, location * 2, d->gridPixmap);
painter.drawPixmap(0, location * 3, d->gridPixmap);
painter.drawPixmap(0, location * 4, d->gridPixmap);
painter.drawPixmap(0, location * 5, d->gridPixmap);
if (d->showShadow) {
painter.setPen(d->sColour);
location = (fontMetrics().height() / 2) + 5;
painter.drawText(3, location, d->inText);
if (!d->outText.isNull())
painter.drawText(3, location * 2, d->outText);
}
painter.setPen(d->mColour);
location = (fontMetrics().height() / 2) + 3;
painter.drawText(1, location, d->inText);
if (!d->outText.isNull())
painter.drawText(1, location * 2, d->outText);
painter.end();
bitBlt(this, 0, 0, &pixmap);
}
void KSim::Chart::fontChange(const QFont &)
{
if (d->krell)
d->krell->setFont(font());
}
void KSim::Chart::updateDisplay()
{
drawChart();
update();
}
int KSim::Chart::yLocation(int value) const
{
int krellHeight = (d->krell ? d->krell->height() : 0);
int rangePos = maxValue() - minValue();
int valuePos = value - minValue();
int returnValue = 0;
if (rangePos)
returnValue = (height() - krellHeight) * valuePos / rangePos;
// Make sure we dont return a negative value
return returnValue >= 0 ? returnValue : 0;
}
void KSim::Chart::drawChart()
{
if (chartSize() != d->graphData.size())
d->graphData.resize(chartSize());
if (d->variableGraphs) {
int maxValue = 0;
QValueList<int>::ConstIterator max;
for (max = d->maxValues.begin(); max != d->maxValues.end(); ++max) {
if ((*max) > maxValue)
maxValue = (*max);
}
setMaxValue(maxValue);
}
QPainter painter;
d->graphData.setMask(drawMask(&painter));
painter.begin(&d->graphData, this);
int position = width() - 1;
QValueList<Private::ValuePair>::ConstIterator it;
for (it = d->values.begin(); it != d->values.end(); ++it) {
// Draw the data In lines first if its higher than the data out lines
if ((*it).first >= (*it).second) {
drawIn(&painter, (*it).first, position);
drawOut(&painter, (*it).second, position);
}
else {
drawOut(&painter, (*it).second, position);
drawIn(&painter, (*it).first, position);
}
--position;
}
painter.end();
}
QSize KSim::Chart::chartSize() const
{
QSize sz(size());
if (d->krell && d->showKrell)
sz.setHeight(sz.height() - d->krell->height());
return sz;
}
QBitmap KSim::Chart::drawMask(QPainter *painter)
{
QBitmap bitmap(chartSize(), true);
painter->begin(&bitmap, this);
painter->setPen(color1);
int position = width() - 1;
QValueList<Private::ValuePair>::ConstIterator it;
for (it = d->values.begin(); it != d->values.end(); ++it) {
drawIn(painter, (*it).first, position, true);
drawOut(painter, (*it).second, position, true);
--position;
}
painter->end();
return bitmap;
}
void KSim::Chart::drawIn(QPainter *painter, int value, int pos, bool dontSet)
{
if (!dontSet) {
painter->setPen(chartColour(DataIn));
}
int location = yLocation(value);
painter->moveTo(0, 0);
painter->drawLine(pos, d->graphData.size().height(),
pos, d->graphData.size().height() - location);
}
void KSim::Chart::drawOut(QPainter *painter, int value, int pos, bool dontSet)
{
if (!dontSet) {
painter->setPen(chartColour(DataOut));
}
int location = yLocation(value);
painter->moveTo(0, 0);
painter->drawLine(pos, d->graphData.size().height(),
pos, d->graphData.size().height() - location);
}
int KSim::Chart::range(int value) const
{
if (value > maxValue())
return maxValue();
if (value < minValue())
return minValue();
return value;
}
void KSim::Chart::init(bool krell, int maxValue, const QString &title)
{
setConfigString("StyleChart");
setThemeConfigOnly(false);
setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed));
d = new Private;
KSim::Config::config()->setGroup("Misc");
d->variableGraphs = KSim::Config::config()->readBoolEntry("UseVariableGraphs", true);
d->showKrell = krell;
d->krell = 0L;
d->title = title;
d->minValue = 0;
d->maxValue = 0;
KSim::Chart::Timer::syncChart(this);
setBackgroundMode(NoBackground);
setLabelType(Label);
setMaxValue(maxValue);
configureObject(false);
}