Vidalia 0.3.1
GraphFrame.cpp
Go to the documentation of this file.
1/*
2** This file is part of Vidalia, and is subject to the license terms in the
3** LICENSE file, found in the top level directory of this distribution. If you
4** did not receive the LICENSE file with this file, you may obtain it from the
5** Vidalia source package distributed by the Vidalia Project at
6** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7** including this file, may be copied, modified, propagated, or distributed
8** except according to the terms described in the LICENSE file.
9*/
10
11/*
12** \file GraphFrame.cpp
13** \brief Graphs a series of send and receive data points
14*/
15
16#include "GraphFrame.h"
17
18#include <QtGui>
19
20
21/** Default contructor */
22GraphFrame::GraphFrame(QWidget *parent)
23: QFrame(parent)
24{
25 /* Create Graph Frame related objects */
26 _recvData = new QList<qreal>();
27 _sendData = new QList<qreal>();
28 _painter = new QPainter();
30
31 /* Initialize graph values */
32 _recvData->prepend(0);
33 _sendData->prepend(0);
35 _maxPosition = 0;
36 _showRecv = true;
37 _showSend = true;
39 _scaleWidth = 0;
40}
41
42/** Default destructor */
44{
45 delete _painter;
46 delete _recvData;
47 delete _sendData;
48}
49
50/** Gets the width of the desktop, which is the maximum number of points
51 * we can plot in the graph. */
52int
54{
55 return size().width() - _scaleWidth;
56}
57
58/** Adds new data points to the graph. */
59void
60GraphFrame::addPoints(qreal recv, qreal send)
61{
62 /* If maximum number of points plotted, remove oldest */
63 if (_sendData->size() == _maxPoints) {
64 _sendData->removeLast();
65 _recvData->removeLast();
66 }
67
68 /* Update the displayed maximum */
69 if (_maxPosition >= _maxPoints) {
71 foreach(qreal send, *_sendData)
72 if(send > _maxValue)
73 _maxValue = send;
74 foreach(qreal recv, *_recvData)
75 if(recv > _maxValue)
76 _maxValue = recv;
77 _maxPosition = 0;
78 }
79
80 /* Add the points to their respective lists */
81 _sendData->prepend(send);
82 _recvData->prepend(recv);
83
84 /* Add to the total counters */
85 _totalSend += send;
86 _totalRecv += recv;
87
88 bool maxUpdated = false;
89 /* Check for a new maximum value */
90 if (send > _maxValue) {
91 _maxValue = send;
92 maxUpdated = true;
93 }
94
95 if (recv > _maxValue) {
96 _maxValue = recv;
97 maxUpdated = true;
98 }
99
100 if (maxUpdated) {
101 _maxPosition = 0;
102 } else {
103 _maxPosition++;
104 }
105
106 this->update();
107}
108
109/** Clears the graph. */
110void
112{
113 _recvData->clear();
114 _sendData->clear();
115 _recvData->prepend(0);
116 _sendData->prepend(0);
118 _totalSend = 0;
119 _totalRecv = 0;
120 this->update();
121}
122
123/** Toggles display of respective graph lines and counters. */
124void
125GraphFrame::setShowCounters(bool showRecv, bool showSend)
126{
127 _showRecv = showRecv;
128 _showSend = showSend;
129 this->update();
130}
131
132/** Overloads default QWidget::paintEvent. Draws the actual
133 * bandwidth graph. */
134void
135GraphFrame::paintEvent(QPaintEvent *event)
136{
137 Q_UNUSED(event);
138
139 /* Set current graph dimensions */
140 _rec = this->frameRect();
141
142 /* Start the painter */
143 _painter->begin(this);
144
145 /* We want antialiased lines and text */
146 _painter->setRenderHint(QPainter::Antialiasing);
147 _painter->setRenderHint(QPainter::TextAntialiasing);
148
149 /* Fill in the background */
150 _painter->fillRect(_rec, QBrush(BACK_COLOR));
151 _painter->drawRect(_rec);
152
153 /* Paint the scale */
154 paintScale();
155 /* Plot the send/receive data */
156 paintData();
157 /* Paint the send/recv totals */
158 paintTotals();
159
160 /* Stop the painter */
161 _painter->end();
162}
163
164/** Paints an integral and an outline of that integral for each data set (send
165 * and/or receive) that is to be displayed. The integrals will be drawn first,
166 * followed by the outlines, since we want the area of overlapping integrals
167 * to blend, but not the outlines of those integrals. */
168void
170{
171 QVector<QPointF> recvPoints, sendPoints;
172
173 /* Convert the bandwidth data points to graph points */
174 recvPoints = pointsFromData(_recvData);
175 sendPoints = pointsFromData(_sendData);
176
177 if (_graphStyle == AreaGraph) {
178 /* Plot the bandwidth data as area graphs */
179 if (_showRecv)
180 paintIntegral(recvPoints, RECV_COLOR, 0.6);
181 if (_showSend)
182 paintIntegral(sendPoints, SEND_COLOR, 0.4);
183 }
184
185 /* Plot the bandwidth as solid lines. If the graph style is currently an
186 * area graph, we end up outlining the integrals. */
187 if (_showRecv)
188 paintLine(recvPoints, RECV_COLOR);
189 if (_showSend)
190 paintLine(sendPoints, SEND_COLOR);
191}
192
193/** Returns a list of points on the bandwidth graph based on the supplied set
194 * of send or receive values. */
195QVector<QPointF>
196GraphFrame::pointsFromData(QList<qreal>* list)
197{
198 QVector<QPointF> points;
199 int x = _rec.width();
200 int y = _rec.height();
201 qreal scale = (y - (y/10)) / _maxValue;
202 qreal currValue;
203
204 /* Translate all data points to points on the graph frame */
205 points << QPointF(x, y);
206 for (int i = 0; i < list->size(); i++) {
207 currValue = y - (list->at(i) * scale);
208 if (x - SCROLL_STEP < _scaleWidth) {
209 points << QPointF(_scaleWidth, currValue);
210 break;
211 }
212 points << QPointF(x, currValue);
213 x -= SCROLL_STEP;
214 }
215 points << QPointF(_scaleWidth, y);
216 return points;
217}
218
219/** Plots an integral using the data points in <b>points</b>. The area will be
220 * filled in using <b>color</b> and an alpha-blending level of <b>alpha</b>
221 * (default is opaque). */
222void
223GraphFrame::paintIntegral(QVector<QPointF> points, QColor color, qreal alpha)
224{
225 /* Save the current brush, plot the integral, and restore the old brush */
226 QBrush oldBrush = _painter->brush();
227 color.setAlphaF(alpha);
228 _painter->setBrush(QBrush(color));
229 _painter->drawPolygon(points.data(), points.size());
230 _painter->setBrush(oldBrush);
231}
232
233/** Iterates the input list and draws a line on the graph in the appropriate
234 * color. */
235void
236GraphFrame::paintLine(QVector<QPointF> points, QColor color, Qt::PenStyle lineStyle)
237{
238 /* Save the current brush, plot the line, and restore the old brush */
239 QPen oldPen = _painter->pen();
240 _painter->setPen(QPen(color, lineStyle));
241 _painter->drawPolyline(points.data(), points.size());
242 _painter->setPen(oldPen);
243}
244
245/** Paints selected total indicators on the graph. */
246void
248{
249 int x = _scaleWidth + FONT_SIZE, y = 0;
250 int rowHeight = FONT_SIZE;
251
252#if !defined(Q_WS_MAC)
253 /* On Mac, we don't need vertical spacing between the text rows. */
254 rowHeight += 5;
255#endif
256
257 /* If total received is selected */
258 if (_showRecv) {
259 y = rowHeight;
260 _painter->setPen(RECV_COLOR);
261 _painter->drawText(x, y,
262 tr("Recv: ") + totalToStr(_totalRecv) +
263 " ("+tr("%1 KB/s").arg(_recvData->first(), 0, 'f', 2)+")");
264 }
265
266 /* If total sent is selected */
267 if (_showSend) {
268 y += rowHeight;
269 _painter->setPen(SEND_COLOR);
270 _painter->drawText(x, y,
271 tr("Sent: ") + totalToStr(_totalSend) +
272 " ("+tr("%1 KB/s").arg(_sendData->first(), 0, 'f', 2)+")");
273 }
274}
275
276/** Returns a formatted string with the correct size suffix. */
277QString
279{
280 /* Determine the correct size suffix */
281 if (total < 1024) {
282 /* Use KB suffix */
283 return tr("%1 KB").arg(total, 0, 'f', 2);
284 } else if (total < 1048576) {
285 /* Use MB suffix */
286 return tr("%1 MB").arg(total/1024.0, 0, 'f', 2);
287 } else {
288 /* Use GB suffix */
289 return tr("%1 GB").arg(total/1048576.0, 0, 'f', 2);
290 }
291}
292
293/** Returns the width in pixels of <b>label</b> using the current painter's
294 * font. */
295int
296GraphFrame::labelWidth(const QString &label)
297{
298 int width = 0;
299 QFontMetrics fm = fontMetrics();
300
301 for (int i = 0; i < label.length(); i++)
302 width += fm.charWidth(label, i);
303 return width;
304}
305
306/** Paints the scale on the graph. */
307void
309{
310 QString label[4];
311 int width[4];
312 int top = _rec.y();
313 int bottom = _rec.height();
314 int scaleWidth = 0;
315 qreal pos;
316 qreal markStep = _maxValue * .25;
317 qreal paintStep = (bottom - (bottom/8)) / 4;
318
319 /* Compute each of the y-axis labels */
320 for (int i = 0; i < 4; i++) {
321 pos = bottom - ((i+1) * paintStep);
322 label[i] = tr("%1 KB/s").arg(markStep*(i+1), 0, 'f', 2);
323 width[i] = labelWidth(label[i]);
324 scaleWidth = qMax(scaleWidth, 2+width[i]);
325 }
326
327 /* Include a 5px margin between the y-axis and its labels */
328 _scaleWidth = scaleWidth + 5;
329
330 /* Draw the y-axis labels and horizontal marks in their correctly scaled
331 * locations */
332 for (int i = 0; i < 4; i++) {
333 pos = bottom - ((i+1) * paintStep);
334 _painter->setPen(SCALE_COLOR);
335 _painter->drawText(QPointF(_scaleWidth-width[i]-5, pos), label[i]);
336
337 _painter->setPen(GRID_COLOR);
338 _painter->drawLine(QPointF(_scaleWidth, pos),
339 QPointF(_rec.width(), pos));
340 }
341
342 /* Draw the y-axis */
343 _painter->drawLine(_scaleWidth, top, _scaleWidth, bottom);
344}
345
346void
347GraphFrame::resizeEvent(QResizeEvent *ev)
348{
349 _maxPoints = ev->size().width() - _scaleWidth;
351}
#define MIN_SCALE
Definition: GraphFrame.h:27
#define SEND_COLOR
Definition: GraphFrame.h:34
#define BACK_COLOR
Definition: GraphFrame.h:30
#define SCALE_COLOR
Definition: GraphFrame.h:31
#define GRID_COLOR
Definition: GraphFrame.h:32
#define FONT_SIZE
Definition: GraphFrame.h:36
#define RECV_COLOR
Definition: GraphFrame.h:33
#define SCROLL_STEP
Definition: GraphFrame.h:28
QPainter * _painter
Definition: GraphFrame.h:97
void resizeEvent(QResizeEvent *ev)
Definition: GraphFrame.cpp:347
qreal _maxValue
Definition: GraphFrame.h:105
qreal _totalRecv
Definition: GraphFrame.h:112
bool _showRecv
Definition: GraphFrame.h:114
QList< qreal > * _recvData
Definition: GraphFrame.h:99
int _maxPoints
Definition: GraphFrame.h:109
void paintIntegral(QVector< QPointF > points, QColor color, qreal alpha=1.0)
Definition: GraphFrame.cpp:223
void addPoints(qreal recv, qreal send)
Definition: GraphFrame.cpp:60
void paintData()
Definition: GraphFrame.cpp:169
QRect _rec
Definition: GraphFrame.h:103
GraphFrame(QWidget *parent=0)
Definition: GraphFrame.cpp:22
void resetGraph()
Definition: GraphFrame.cpp:111
void paintLine(QVector< QPointF > points, QColor color, Qt::PenStyle lineStyle=Qt::SolidLine)
Definition: GraphFrame.cpp:236
int getNumPoints()
Definition: GraphFrame.cpp:53
int _scaleWidth
Definition: GraphFrame.h:118
void setShowCounters(bool showRecv, bool showSend)
Definition: GraphFrame.cpp:125
void paintEvent(QPaintEvent *event)
Definition: GraphFrame.cpp:135
QList< qreal > * _sendData
Definition: GraphFrame.h:101
qreal _totalSend
Definition: GraphFrame.h:111
GraphStyle _graphStyle
Definition: GraphFrame.h:95
void paintTotals()
Definition: GraphFrame.cpp:247
bool _showSend
Definition: GraphFrame.h:115
QString totalToStr(qreal total)
Definition: GraphFrame.cpp:278
void paintScale()
Definition: GraphFrame.cpp:308
int _maxPosition
Definition: GraphFrame.h:107
QVector< QPointF > pointsFromData(QList< qreal > *list)
Definition: GraphFrame.cpp:196
int labelWidth(const QString &label)
Definition: GraphFrame.cpp:296
QString i(QString str)
Definition: html.cpp:32