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