Line data Source code
1 : // Copyright (c) 2011-2013 The Bitcoin Core developers
2 : // Distributed under the MIT 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 0 : 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 0 : clientModel(0)
29 : {
30 0 : timer = new QTimer(this);
31 0 : connect(timer, SIGNAL(timeout()), SLOT(updateRates()));
32 0 : }
33 :
34 0 : void TrafficGraphWidget::setClientModel(ClientModel *model)
35 : {
36 0 : clientModel = model;
37 0 : if(model) {
38 0 : nLastBytesIn = model->getTotalBytesRecv();
39 0 : nLastBytesOut = model->getTotalBytesSent();
40 : }
41 0 : }
42 :
43 0 : int TrafficGraphWidget::getGraphRangeMins() const
44 : {
45 0 : return nMins;
46 : }
47 :
48 0 : void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
49 : {
50 0 : int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
51 0 : int sampleCount = samples.size(), x = XMARGIN + w, y;
52 0 : if(sampleCount > 0) {
53 0 : path.moveTo(x, YMARGIN + h);
54 0 : for(int i = 0; i < sampleCount; ++i) {
55 0 : x = XMARGIN + w - w * i / DESIRED_SAMPLES;
56 0 : y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
57 0 : path.lineTo(x, y);
58 : }
59 0 : path.lineTo(x, YMARGIN + h);
60 : }
61 0 : }
62 :
63 0 : void TrafficGraphWidget::paintEvent(QPaintEvent *)
64 : {
65 0 : QPainter painter(this);
66 0 : painter.fillRect(rect(), Qt::black);
67 :
68 0 : if(fMax <= 0.0f) return;
69 :
70 0 : QColor axisCol(Qt::gray);
71 0 : int h = height() - YMARGIN * 2;
72 0 : painter.setPen(axisCol);
73 0 : painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);
74 :
75 : // decide what order of magnitude we are
76 0 : int base = floor(log10(fMax));
77 0 : float val = pow(10.0f, base);
78 :
79 0 : const QString units = tr("KB/s");
80 0 : const float yMarginText = 2.0;
81 :
82 : // draw lines
83 0 : painter.setPen(axisCol);
84 0 : painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
85 0 : for(float y = val; y < fMax; y += val) {
86 0 : int yy = YMARGIN + h - h * y / fMax;
87 0 : 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 0 : if(fMax / val <= 3.0f) {
91 0 : axisCol = axisCol.darker();
92 0 : val = pow(10.0f, base - 1);
93 0 : painter.setPen(axisCol);
94 0 : painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units));
95 0 : int count = 1;
96 0 : for(float y = val; y < fMax; y += val, count++) {
97 : // don't overwrite lines drawn above
98 0 : if(count % 10 == 0)
99 : continue;
100 0 : int yy = YMARGIN + h - h * y / fMax;
101 0 : painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
102 : }
103 : }
104 :
105 0 : if(!vSamplesIn.empty()) {
106 0 : QPainterPath p;
107 0 : paintPath(p, vSamplesIn);
108 0 : painter.fillPath(p, QColor(0, 255, 0, 128));
109 0 : painter.setPen(Qt::green);
110 0 : painter.drawPath(p);
111 : }
112 0 : if(!vSamplesOut.empty()) {
113 0 : QPainterPath p;
114 0 : paintPath(p, vSamplesOut);
115 0 : painter.fillPath(p, QColor(255, 0, 0, 128));
116 0 : painter.setPen(Qt::red);
117 0 : painter.drawPath(p);
118 0 : }
119 : }
120 :
121 0 : void TrafficGraphWidget::updateRates()
122 : {
123 0 : if(!clientModel) return;
124 :
125 0 : quint64 bytesIn = clientModel->getTotalBytesRecv(),
126 0 : bytesOut = clientModel->getTotalBytesSent();
127 0 : float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval();
128 0 : float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval();
129 0 : vSamplesIn.push_front(inRate);
130 0 : vSamplesOut.push_front(outRate);
131 0 : nLastBytesIn = bytesIn;
132 0 : nLastBytesOut = bytesOut;
133 :
134 0 : while(vSamplesIn.size() > DESIRED_SAMPLES) {
135 0 : vSamplesIn.pop_back();
136 : }
137 0 : while(vSamplesOut.size() > DESIRED_SAMPLES) {
138 0 : vSamplesOut.pop_back();
139 : }
140 :
141 0 : float tmax = 0.0f;
142 0 : Q_FOREACH(float f, vSamplesIn) {
143 0 : if(f > tmax) tmax = f;
144 : }
145 0 : Q_FOREACH(float f, vSamplesOut) {
146 0 : if(f > tmax) tmax = f;
147 : }
148 0 : fMax = tmax;
149 0 : update();
150 : }
151 :
152 0 : void TrafficGraphWidget::setGraphRangeMins(int mins)
153 : {
154 0 : nMins = mins;
155 0 : int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES;
156 0 : timer->stop();
157 0 : timer->setInterval(msecsPerSample);
158 :
159 0 : clear();
160 0 : }
161 :
162 0 : void TrafficGraphWidget::clear()
163 : {
164 0 : timer->stop();
165 :
166 0 : vSamplesOut.clear();
167 0 : vSamplesIn.clear();
168 0 : fMax = 0.0f;
169 :
170 0 : if(clientModel) {
171 0 : nLastBytesIn = clientModel->getTotalBytesRecv();
172 0 : nLastBytesOut = clientModel->getTotalBytesSent();
173 : }
174 0 : timer->start();
175 0 : }
|