Wladimir J. van der Laan
11 years ago
13 changed files with 618 additions and 9 deletions
@ -0,0 +1,169 @@ |
|||||||
|
#include "trafficgraphwidget.h" |
||||||
|
#include "clientmodel.h" |
||||||
|
|
||||||
|
#include <QPainter> |
||||||
|
#include <QColor> |
||||||
|
#include <QTimer> |
||||||
|
|
||||||
|
#include <cmath> |
||||||
|
|
||||||
|
#define DESIRED_SAMPLES 800 |
||||||
|
|
||||||
|
#define XMARGIN 10 |
||||||
|
#define YMARGIN 10 |
||||||
|
|
||||||
|
TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) : |
||||||
|
QWidget(parent), |
||||||
|
timer(0), |
||||||
|
fMax(0.0f), |
||||||
|
nMins(0), |
||||||
|
vSamplesIn(), |
||||||
|
vSamplesOut(), |
||||||
|
nLastBytesIn(0), |
||||||
|
nLastBytesOut(0), |
||||||
|
clientModel(0) |
||||||
|
{ |
||||||
|
timer = new QTimer(this); |
||||||
|
connect(timer, SIGNAL(timeout()), SLOT(updateRates())); |
||||||
|
} |
||||||
|
|
||||||
|
void TrafficGraphWidget::setClientModel(ClientModel *model) |
||||||
|
{ |
||||||
|
clientModel = model; |
||||||
|
if(model) { |
||||||
|
nLastBytesIn = model->getTotalBytesRecv(); |
||||||
|
nLastBytesOut = model->getTotalBytesSent(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int TrafficGraphWidget::getGraphRangeMins() const |
||||||
|
{ |
||||||
|
return nMins; |
||||||
|
} |
||||||
|
|
||||||
|
void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples) |
||||||
|
{ |
||||||
|
int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2; |
||||||
|
int sampleCount = samples.size(), x = XMARGIN + w, y; |
||||||
|
if(sampleCount > 0) { |
||||||
|
path.moveTo(x, YMARGIN + h); |
||||||
|
for(int i = 0; i < sampleCount; ++i) { |
||||||
|
x = XMARGIN + w - w * i / DESIRED_SAMPLES; |
||||||
|
y = YMARGIN + h - (int)(h * samples.at(i) / fMax); |
||||||
|
path.lineTo(x, y); |
||||||
|
} |
||||||
|
path.lineTo(x, YMARGIN + h); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void TrafficGraphWidget::paintEvent(QPaintEvent *) |
||||||
|
{ |
||||||
|
QPainter painter(this); |
||||||
|
painter.fillRect(rect(), Qt::black); |
||||||
|
|
||||||
|
if(fMax <= 0.0f) return; |
||||||
|
|
||||||
|
QColor axisCol(Qt::gray); |
||||||
|
int h = height() - YMARGIN * 2; |
||||||
|
painter.setPen(axisCol); |
||||||
|
painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h); |
||||||
|
|
||||||
|
// decide what order of magnitude we are
|
||||||
|
int base = floor(log10(fMax)); |
||||||
|
float val = pow(10.0f, base); |
||||||
|
|
||||||
|
const QString units = tr("KB/s"); |
||||||
|
// draw lines
|
||||||
|
painter.setPen(axisCol); |
||||||
|
painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax, QString("%1 %2").arg(val).arg(units)); |
||||||
|
for(float y = val; y < fMax; y += val) { |
||||||
|
int yy = YMARGIN + h - h * y / fMax; |
||||||
|
painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy); |
||||||
|
} |
||||||
|
// if we drew 3 or fewer lines, break them up at the next lower order of magnitude
|
||||||
|
if(fMax / val <= 3.0f) { |
||||||
|
axisCol = axisCol.darker(); |
||||||
|
val = pow(10.0f, base - 1); |
||||||
|
painter.setPen(axisCol); |
||||||
|
painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax, QString("%1 %2").arg(val).arg(units)); |
||||||
|
int count = 1; |
||||||
|
for(float y = val; y < fMax; y += val, count++) { |
||||||
|
// don't overwrite lines drawn above
|
||||||
|
if(count % 10 == 0) |
||||||
|
continue; |
||||||
|
int yy = YMARGIN + h - h * y / fMax; |
||||||
|
painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if(!vSamplesIn.empty()) { |
||||||
|
QPainterPath p; |
||||||
|
paintPath(p, vSamplesIn); |
||||||
|
painter.fillPath(p, QColor(0, 255, 0, 128)); |
||||||
|
painter.setPen(Qt::green); |
||||||
|
painter.drawPath(p); |
||||||
|
} |
||||||
|
if(!vSamplesOut.empty()) { |
||||||
|
QPainterPath p; |
||||||
|
paintPath(p, vSamplesOut); |
||||||
|
painter.fillPath(p, QColor(255, 0, 0, 128)); |
||||||
|
painter.setPen(Qt::red); |
||||||
|
painter.drawPath(p); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void TrafficGraphWidget::updateRates() |
||||||
|
{ |
||||||
|
if(!clientModel) return; |
||||||
|
|
||||||
|
quint64 bytesIn = clientModel->getTotalBytesRecv(), |
||||||
|
bytesOut = clientModel->getTotalBytesSent(); |
||||||
|
float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval(); |
||||||
|
float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval(); |
||||||
|
vSamplesIn.push_front(inRate); |
||||||
|
vSamplesOut.push_front(outRate); |
||||||
|
nLastBytesIn = bytesIn; |
||||||
|
nLastBytesOut = bytesOut; |
||||||
|
|
||||||
|
while(vSamplesIn.size() > DESIRED_SAMPLES) { |
||||||
|
vSamplesIn.pop_back(); |
||||||
|
} |
||||||
|
while(vSamplesOut.size() > DESIRED_SAMPLES) { |
||||||
|
vSamplesOut.pop_back(); |
||||||
|
} |
||||||
|
|
||||||
|
float tmax = 0.0f; |
||||||
|
foreach(float f, vSamplesIn) { |
||||||
|
if(f > tmax) tmax = f; |
||||||
|
} |
||||||
|
foreach(float f, vSamplesOut) { |
||||||
|
if(f > tmax) tmax = f; |
||||||
|
} |
||||||
|
fMax = tmax; |
||||||
|
update(); |
||||||
|
} |
||||||
|
|
||||||
|
void TrafficGraphWidget::setGraphRangeMins(int mins) |
||||||
|
{ |
||||||
|
nMins = mins; |
||||||
|
int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES; |
||||||
|
timer->stop(); |
||||||
|
timer->setInterval(msecsPerSample); |
||||||
|
|
||||||
|
clear(); |
||||||
|
} |
||||||
|
|
||||||
|
void TrafficGraphWidget::clear() |
||||||
|
{ |
||||||
|
timer->stop(); |
||||||
|
|
||||||
|
vSamplesOut.clear(); |
||||||
|
vSamplesIn.clear(); |
||||||
|
fMax = 0.0f; |
||||||
|
|
||||||
|
if(clientModel) { |
||||||
|
nLastBytesIn = clientModel->getTotalBytesRecv(); |
||||||
|
nLastBytesOut = clientModel->getTotalBytesSent(); |
||||||
|
} |
||||||
|
timer->start(); |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
#ifndef TRAFFICGRAPHWIDGET_H |
||||||
|
#define TRAFFICGRAPHWIDGET_H |
||||||
|
|
||||||
|
#include <QWidget> |
||||||
|
#include <QQueue> |
||||||
|
|
||||||
|
class ClientModel; |
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE |
||||||
|
class QPaintEvent; |
||||||
|
class QTimer; |
||||||
|
QT_END_NAMESPACE |
||||||
|
|
||||||
|
class TrafficGraphWidget : public QWidget |
||||||
|
{ |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
explicit TrafficGraphWidget(QWidget *parent = 0); |
||||||
|
void setClientModel(ClientModel *model); |
||||||
|
int getGraphRangeMins() const; |
||||||
|
|
||||||
|
protected: |
||||||
|
void paintEvent(QPaintEvent *); |
||||||
|
|
||||||
|
public slots: |
||||||
|
void updateRates(); |
||||||
|
void setGraphRangeMins(int mins); |
||||||
|
void clear(); |
||||||
|
|
||||||
|
private: |
||||||
|
void paintPath(QPainterPath &path, QQueue<float> &samples); |
||||||
|
|
||||||
|
QTimer *timer; |
||||||
|
float fMax; |
||||||
|
int nMins; |
||||||
|
QQueue<float> vSamplesIn; |
||||||
|
QQueue<float> vSamplesOut; |
||||||
|
quint64 nLastBytesIn; |
||||||
|
quint64 nLastBytesOut; |
||||||
|
ClientModel *clientModel; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // TRAFFICGRAPHWIDGET_H
|
Loading…
Reference in new issue