Add traffic monitor
[novacoin.git] / src / qt / trafficgraphwidget.cpp
1 // Copyright (c) 2011-2013 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "trafficgraphwidget.h"
6 #include "clientmodel.h"
7
8 #include <QPainter>
9 #include <QColor>
10 #include <QTimer>
11
12 #include <cmath>
13
14 #define DESIRED_SAMPLES         800
15
16 #define XMARGIN                 10
17 #define YMARGIN                 10
18
19 TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) :
20     QWidget(parent),
21     timer(0),
22     fMax(0.0f),
23     nMins(0),
24     vSamplesIn(),
25     vSamplesOut(),
26     nLastBytesIn(0),
27     nLastBytesOut(0),
28     clientModel(0)
29 {
30     timer = new QTimer(this);
31     connect(timer, SIGNAL(timeout()), SLOT(updateRates()));
32 }
33
34 void TrafficGraphWidget::setClientModel(ClientModel *model)
35 {
36     clientModel = model;
37     if(model) {
38         nLastBytesIn = model->getTotalBytesRecv();
39         nLastBytesOut = model->getTotalBytesSent();
40     }
41 }
42
43 int TrafficGraphWidget::getGraphRangeMins() const
44 {
45     return nMins;
46 }
47
48 void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
49 {
50     int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
51     int sampleCount = samples.size(), x = XMARGIN + w, y;
52     if(sampleCount > 0) {
53         path.moveTo(x, YMARGIN + h);
54         for(int i = 0; i < sampleCount; ++i) {
55             x = XMARGIN + w - w * i / DESIRED_SAMPLES;
56             y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
57             path.lineTo(x, y);
58         }
59         path.lineTo(x, YMARGIN + h);
60     }
61 }
62
63 void TrafficGraphWidget::paintEvent(QPaintEvent *)
64 {
65     QPainter painter(this);
66     painter.fillRect(rect(), Qt::black);
67
68     if(fMax <= 0.0f) return;
69
70     QColor axisCol(Qt::gray);
71     int h = height() - YMARGIN * 2;
72     painter.setPen(axisCol);
73     painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);
74
75     // decide what order of magnitude we are
76     int base = floor(log10(fMax));
77     float val = pow(10.0f, base);
78
79     const QString units     = tr("KB/s");
80     const float yMarginText = 2.0;
81     
82     // draw lines
83     painter.setPen(axisCol);
84     painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
85     for(float y = val; y < fMax; y += val) {
86         int yy = YMARGIN + h - h * y / fMax;
87         painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
88     }
89     // if we drew 3 or fewer lines, break them up at the next lower order of magnitude
90     if(fMax / val <= 3.0f) {
91         axisCol = axisCol.darker();
92         val = pow(10.0f, base - 1);
93         painter.setPen(axisCol);
94         painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
95         int count = 1;
96         for(float y = val; y < fMax; y += val, count++) {
97             // don't overwrite lines drawn above
98             if(count % 10 == 0)
99                 continue;
100             int yy = YMARGIN + h - h * y / fMax;
101             painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
102         }
103     }
104
105     if(!vSamplesIn.empty()) {
106         QPainterPath p;
107         paintPath(p, vSamplesIn);
108         painter.fillPath(p, QColor(0, 255, 0, 128));
109         painter.setPen(Qt::green);
110         painter.drawPath(p);
111     }
112     if(!vSamplesOut.empty()) {
113         QPainterPath p;
114         paintPath(p, vSamplesOut);
115         painter.fillPath(p, QColor(255, 0, 0, 128));
116         painter.setPen(Qt::red);
117         painter.drawPath(p);
118     }
119 }
120
121 void TrafficGraphWidget::updateRates()
122 {
123     if(!clientModel) return;
124
125     quint64 bytesIn = clientModel->getTotalBytesRecv(),
126             bytesOut = clientModel->getTotalBytesSent();
127     float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval();
128     float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval();
129     vSamplesIn.push_front(inRate);
130     vSamplesOut.push_front(outRate);
131     nLastBytesIn = bytesIn;
132     nLastBytesOut = bytesOut;
133
134     while(vSamplesIn.size() > DESIRED_SAMPLES) {
135         vSamplesIn.pop_back();
136     }
137     while(vSamplesOut.size() > DESIRED_SAMPLES) {
138         vSamplesOut.pop_back();
139     }
140
141     float tmax = 0.0f;
142     foreach(float f, vSamplesIn) {
143         if(f > tmax) tmax = f;
144     }
145     foreach(float f, vSamplesOut) {
146         if(f > tmax) tmax = f;
147     }
148     fMax = tmax;
149     update();
150 }
151
152 void TrafficGraphWidget::setGraphRangeMins(int mins)
153 {
154     nMins = mins;
155     int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES;
156     timer->stop();
157     timer->setInterval(msecsPerSample);
158
159     clear();
160 }
161
162 void TrafficGraphWidget::clear()
163 {
164     timer->stop();
165
166     vSamplesOut.clear();
167     vSamplesIn.clear();
168     fMax = 0.0f;
169
170     if(clientModel) {
171         nLastBytesIn = clientModel->getTotalBytesRecv();
172         nLastBytesOut = clientModel->getTotalBytesSent();
173     }
174     timer->start();
175 }