~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to libs/ksysguard/signalplotter/ksignalplotter.h

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    This file is part of the KDE project
 
3
 
 
4
    Copyright (c) 2006 - 2009 John Tapsell <tapsell@kde.org>
 
5
 
 
6
    This program is free software; you can redistribute it and/or
 
7
    modify it under the terms of the GNU General Public
 
8
    License version 2 or at your option version 3 as published by
 
9
    the Free Software Foundation.
 
10
 
 
11
    This program is distributed in the hope that it will be useful,
 
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
    GNU General Public License for more details.
 
15
 
 
16
    You should have received a copy of the GNU General Public License
 
17
    along with this program; if not, write to the Free Software
 
18
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
19
 
 
20
*/
 
21
 
 
22
#ifndef KSIGNALPLOTTER_H
 
23
#define KSIGNALPLOTTER_H
 
24
 
 
25
#include <QtCore/QList>
 
26
#include <QtCore/QString>
 
27
#include <QtGui/QColor>
 
28
#include <QtGui/QFont>
 
29
#include <QtGui/QWidget>
 
30
#include <klocalizedstring.h>
 
31
#include <kcomponentdata.h>
 
32
 
 
33
class QPaintEvent;
 
34
class QResizeEvent;
 
35
class QGraphicsSceneResizeEvent;
 
36
class KSignalPlotterPrivate;
 
37
 
 
38
//Make sure only declare KLocalizedString once
 
39
#ifndef KGRAPHICSSIGNALPLOTTER_H
 
40
Q_DECLARE_METATYPE(KLocalizedString)
 
41
#endif
 
42
 
 
43
/** \class KSignalPlotter
 
44
 * \brief The KSignalPlotter widget draws a real time graph of data that updates continually.
 
45
 *
 
46
 *  Features include:
 
47
 *  \li Points are joined by a bezier curve.
 
48
 *  \li Lines are anti-aliased
 
49
 *  \li Background can be set as a specified SVG
 
50
 *  \li The lines can be reordered
 
51
 *  \li Uses as little memory and CPU as possible
 
52
 *  \li Graph can be smoothed using the formula (value * 2 + last_value)/3
 
53
 *  \li Can cope with positive/negative infinity and NaN values.
 
54
 *
 
55
 *  Example usage:
 
56
 *  \code
 
57
 *    KSignalPlotter *s = KSignalPlotter(parent);
 
58
 *    s->addBeam(Qt::blue);
 
59
 *    s->addBeam(Qt::green);
 
60
 *    QList<qreal> data;
 
61
 *    data << 4.0 << 5.0;
 
62
 *    s->addSample(data);
 
63
 *  \endcode
 
64
 *
 
65
 *  Note that the number of horizontal lines is calculated automatically based on the axis font size, even if the axis labels are not shown.
 
66
 *
 
67
 *  Smoothing looks very nice visually and is enabled by default.  It can be disabled with setSmoothGraph().
 
68
 *
 
69
 *  \image KSignalPlotter.png  Example KSignalPlotter with two beams
 
70
 */
 
71
class KDE_EXPORT KSignalPlotter : public QWidget
 
72
{
 
73
  Q_OBJECT
 
74
  Q_PROPERTY(qreal minimumValue READ minimumValue WRITE setMinimumValue)
 
75
  Q_PROPERTY(qreal maximumValue READ maximumValue WRITE setMaximumValue)
 
76
  Q_PROPERTY(bool useAutoRange READ useAutoRange WRITE setUseAutoRange)
 
77
  Q_PROPERTY(KLocalizedString unit READ unit WRITE setUnit)
 
78
  Q_PROPERTY(qreal scaleDownBy READ scaleDownBy WRITE setScaleDownBy)
 
79
  Q_PROPERTY(uint horizontalScale READ horizontalScale WRITE setHorizontalScale)
 
80
  Q_PROPERTY(bool showHorizontalLines READ showHorizontalLines WRITE setShowHorizontalLines)
 
81
  Q_PROPERTY(bool showVerticalLines READ showVerticalLines WRITE setShowVerticalLines)
 
82
  Q_PROPERTY(bool verticalLinesScroll READ verticalLinesScroll WRITE setVerticalLinesScroll)
 
83
  Q_PROPERTY(uint verticalLinesDistance READ verticalLinesDistance WRITE setVerticalLinesDistance)
 
84
  Q_PROPERTY(bool showAxis READ showAxis WRITE setShowAxis)
 
85
  Q_PROPERTY(QString svgBackground READ svgBackground WRITE setSvgBackground)
 
86
  Q_PROPERTY(bool thinFrame READ thinFrame WRITE setThinFrame)
 
87
  Q_PROPERTY(int maxAxisTextWidth READ maxAxisTextWidth WRITE setMaxAxisTextWidth)
 
88
  Q_PROPERTY(bool smoothGraph READ smoothGraph WRITE setSmoothGraph)
 
89
  Q_PROPERTY(bool stackGraph READ stackGraph WRITE setStackGraph)
 
90
  Q_PROPERTY(int fillOpacity READ fillOpacity WRITE setFillOpacity)
 
91
 
 
92
  public:
 
93
    KSignalPlotter( QWidget *parent = 0);
 
94
    virtual ~KSignalPlotter();
 
95
 
 
96
    /** \brief Add a new line to the graph plotter, with the specified color.
 
97
     *
 
98
     *  Note that the order you add the beams in must be the same order that
 
99
     *  the beam data is given in (Unless you reorder the beams).
 
100
     *
 
101
     *  \param color Color of beam - does not have to be unique.
 
102
     */
 
103
    void addBeam( const QColor &color );
 
104
 
 
105
    /** \brief Add data to the graph, and advance the graph by one time period.
 
106
     *
 
107
     *  The data must be given as a list in the same order that the beams were
 
108
     *  added (or consequently reordered).  If samples.count() != numBeams(),
 
109
     *  a warning is printed and the data discarded.
 
110
     *
 
111
     *  To indicate that no data is available for a given beam, set its value to
 
112
     *  (non-signalling) NaN.
 
113
     *
 
114
     *  For example:
 
115
     *
 
116
     *  \code
 
117
     *    KSignalPlotter *s = KSignalPlotter(parent);
 
118
     *    s->addBeam(Qt::red);
 
119
     *    s->addBeam(Qt::green);
 
120
     *    s->addBeam(Qt::blue);
 
121
     *    signalPlotter->addSample( QList<qreal>() << std::numeric_limits<double>::quiet_NaN() << 1.0/0 << 10.0 );
 
122
     *  \endcode
 
123
     *
 
124
     *  This indicates that no data is available yet for red (so the beam will not be drawn for this section),
 
125
     *  that's it positive infinity for green, and 10 for blue.
 
126
     *
 
127
     *  Infinity is handled by drawing a straight line up to the top or bottom of the display, and does not affect the range.
 
128
     *  For the above example, the displayed range would now be 0 to 10.
 
129
     */
 
130
    void addSample( const QList<qreal> &samples );
 
131
 
 
132
    /** \brief Reorder the beams into the order given.
 
133
     *
 
134
     * For example:
 
135
     * \code
 
136
     *   KSignalPlotter *s = KSignalPlotter(parent);
 
137
     *   s->addBeam(Qt::blue);
 
138
     *   s->addBeam(Qt::green);
 
139
     *   s->addBeam(Qt::red);
 
140
     *   QList<int> neworder;
 
141
     *   neworder << 2 << 0 << 1;
 
142
     *   s->reorderBeams( newOrder);
 
143
     *   //Now the order is red, blue then green
 
144
     * \endcode
 
145
     *
 
146
     * The size of the \p newOrder list must be equal to the result of numBeams().
 
147
     * \param newOrder New order of beams.
 
148
     */
 
149
    void reorderBeams( const QList<int>& newOrder );
 
150
 
 
151
    /** \brief Removes the beam at the specified index.
 
152
     *
 
153
     * This causes the graph to be redrawn with the specified beam completely
 
154
     * removed.
 
155
     */
 
156
    void removeBeam( int index );
 
157
 
 
158
    /** \brief Get the color of the beam at the specified index.
 
159
     *
 
160
     * For example:
 
161
     * \code
 
162
     *   KSignalPlotter *s = KSignalPlotter(parent);
 
163
     *   s->addBeam(Qt::blue);
 
164
     *   s->addBeam(Qt::green);
 
165
     *   s->addBeam(Qt::red);
 
166
     *
 
167
     *   QColor color = s->beamColor(0);  //returns blue
 
168
     * \endcode
 
169
     *
 
170
     * \sa setBeamColor()
 
171
     */
 
172
    QColor beamColor( int index ) const;
 
173
 
 
174
    /** \brief Set the color of the beam at the specified index.
 
175
     *
 
176
     * \sa beamColor()
 
177
     */
 
178
    void setBeamColor( int index, const QColor &color );
 
179
 
 
180
    /** \brief Returns the number of beams. */
 
181
    int numBeams() const;
 
182
 
 
183
    /** \brief Set the axis units with a localized string.
 
184
     *
 
185
     * The localized string must contain a placeholder "%1" which is substituted for the value.
 
186
     * The plural form (ki18np) can be used if the unit string changes depending on the number (for example
 
187
     * "1 second", "2 seconds").
 
188
     *
 
189
     * For example:
 
190
     *
 
191
     * \code
 
192
     *   KSignalPlotter plotter;
 
193
     *   plotter.setUnit( ki18ncp("Units", "%1 second", "%1 seconds") );
 
194
     *   QString formattedString = plotter.valueAsString(3.4); //returns "3.4 seconds"
 
195
     * \endcode
 
196
     *
 
197
     * Typically a new unit would be set when setScaleDownBy is called.
 
198
     * Note that even the singular should use "%1 second" instead of "1 second", so that a value of -1 works correctly.
 
199
     *
 
200
     * \see unit(), setScaleDownBy()
 
201
     */
 
202
    void setUnit( const KLocalizedString &unit );
 
203
 
 
204
    /** \brief The localizable units used on the vertical axis of the graph.
 
205
     *
 
206
     * The returns the localizable string set with setUnit().
 
207
     *
 
208
     * Default is the string "%1" - i.e. to just display the number.
 
209
     *
 
210
     * \see setUnit
 
211
     */
 
212
    KLocalizedString unit() const;
 
213
 
 
214
    /** \brief Scale all the values down by the given amount.
 
215
     *
 
216
     * This is useful when the data is given in, say, kilobytes, but you set
 
217
     * the units as megabytes.  Thus you would have to call this with @p value
 
218
     * set to 1024.  This affects all the data already entered.
 
219
     *
 
220
     * Typically this is followed by calling setUnit() to set the display axis
 
221
     * units.  Default value is 1.
 
222
     */
 
223
    void setScaleDownBy( qreal value );
 
224
 
 
225
    /** \brief Amount scaled down by.
 
226
     *
 
227
     * \sa setScaleDownBy */
 
228
    qreal scaleDownBy() const;
 
229
 
 
230
    /** \brief Set whether to scale the graph automatically beyond the given range.
 
231
     *
 
232
     * If true, the range on vertical axis is automatically expanded from the
 
233
     * data available, expanding beyond the range set by changeRange() if data
 
234
     * values are outside of this range.
 
235
     *
 
236
     * Regardless whether this is set of not, the range of the vertical axis
 
237
     * will never be less than the range given by maximumValue() and minimumvalue().
 
238
     *
 
239
     * \param value Whether to scale beyond the given range. Default is true.
 
240
     *
 
241
     * \sa useAutoRange
 
242
     */
 
243
    void setUseAutoRange( bool value );
 
244
 
 
245
    /** \brief Whether the vertical axis range is set automatically.
 
246
     */
 
247
    bool useAutoRange() const;
 
248
 
 
249
    /** \brief Change the minimum and maximum values drawn on the graph.
 
250
     *
 
251
     *  Note that these values are sanitised.  For example, if you
 
252
     *  set the minimum as 3, and the maximum as 97, then the graph
 
253
     *  would be drawn between 0 and 100.  The algorithm to determine
 
254
     *  this "nice range" attempts to minimize the number of non-zero
 
255
     *  digits.
 
256
     *
 
257
     *  If autoRange() is true, then this range is taking as a 'hint'.
 
258
     *  The range will never be smaller than the given range, but can grow
 
259
     *  if there are values larger than the given range.
 
260
     *
 
261
     *  This is equivalent to calling
 
262
     *  \code
 
263
     *    setMinimumValue(min);
 
264
     *    setMaximumValue(max);
 
265
     *  \endcode
 
266
     *
 
267
     *  \sa setMinimumValue(), setMaximumValue(), minimumValue(), maximumValue()
 
268
     */
 
269
    void changeRange( qreal min, qreal max );
 
270
 
 
271
    /** \brief Set the min value hint for the vertical axis.
 
272
     *
 
273
     * \sa changeRange(), minimumValue(), setMaximumValue(), maximumValue() */
 
274
    void setMinimumValue( qreal min );
 
275
 
 
276
    /** \brief Get the min value hint for the vertical axis.
 
277
     *
 
278
     * \sa changeRange(), minimumValue(), setMaximumValue(), maximumValue() */
 
279
    qreal minimumValue() const;
 
280
 
 
281
    /** \brief Set the max value hint for the vertical axis. *
 
282
     *
 
283
     * \sa changeRange(), minimumValue(), setMaximumValue(), maximumValue() */
 
284
    void setMaximumValue( qreal max );
 
285
 
 
286
    /** \brief Get the maximum value hint for the vertical axis.
 
287
     *
 
288
     * \sa changeRange(), minimumValue(), setMaximumValue(), maximumValue() */
 
289
    qreal maximumValue() const;
 
290
 
 
291
    /** \brief Get the current maximum value on the y-axis.
 
292
     *
 
293
     *  This will never be lower than maximumValue(), and if autoRange() is true,
 
294
     *  it will be equal or larger (due to rounding up to make it a nice number)
 
295
     *  than the highest value being shown.
 
296
     */
 
297
    qreal currentMaximumRangeValue() const;
 
298
    /** \brief Get the current minimum value on the y-axis.
 
299
     *
 
300
     *  This will never be lower than minimumValue(), and if autoRange() is true,
 
301
     *  it will be equal or larger (due to rounding up to make it a nice number)
 
302
     *  than the highest value being shown.
 
303
     */
 
304
    qreal currentMinimumRangeValue() const;
 
305
 
 
306
    /** \brief Set the number of pixels horizontally between data points.
 
307
     *  Default is 6. */
 
308
    void setHorizontalScale( uint scale );
 
309
    /** \brief The number of pixels horizontally between data points.
 
310
     *  Default is 6. */
 
311
    int horizontalScale() const;
 
312
 
 
313
    /** \brief Set whether to draw the vertical grid lines.
 
314
     *  Default is false. */
 
315
    void setShowVerticalLines( bool value );
 
316
    /** \brief Whether to draw the vertical grid lines.
 
317
     *  Default is false. */
 
318
    bool showVerticalLines() const;
 
319
 
 
320
    /** \brief Set the horizontal distance, in pixels, between the vertical grid lines.
 
321
     *  Must be a distance of 1 or more.
 
322
     *  Default is 30 pixels. */
 
323
    void setVerticalLinesDistance( uint distance );
 
324
    /** \brief The horizontal distance, in pixels, between the vertical grid lines.
 
325
      *  Default is 30 pixels. */
 
326
    uint verticalLinesDistance() const;
 
327
 
 
328
    /** \brief Set whether the vertical lines move with the data.
 
329
     *  Default is true. This has no effect is showVerticalLines is false. */
 
330
    void setVerticalLinesScroll( bool value );
 
331
    /** \brief Whether the vertical lines move with the data.
 
332
     *  Default is true. This has no effect is showVerticalLines is false. */
 
333
    bool verticalLinesScroll() const;
 
334
 
 
335
    /** \brief Set whether to draw the horizontal grid lines.
 
336
     *  Default is true. */
 
337
    void setShowHorizontalLines( bool value );
 
338
    /** \brief Whether to draw the horizontal grid lines.
 
339
     *  Default is true. */
 
340
    bool showHorizontalLines() const;
 
341
 
 
342
    /** \brief The number of decimal places used for the axis labels
 
343
     *
 
344
     *  This is calculated based on the current range */
 
345
    int currentAxisPrecision() const;
 
346
 
 
347
    /** \brief Set whether to show the vertical axis labels.
 
348
     *
 
349
     * Default is true.
 
350
     * \sa showAxis(), setAxisFont(), setAxisFontColor(), setMaxAxisTextWidth() */
 
351
    void setShowAxis( bool show );
 
352
    /** \brief Whether to show the vertical axis labels.
 
353
     *
 
354
     * Default is true.
 
355
     * \sa setShowAxis(), axisFont(), axisFontColor(), maxAxisTextWidth() */
 
356
    bool showAxis() const;
 
357
 
 
358
    /** \brief Set the filename of the SVG background.
 
359
     *
 
360
     * Set to empty (default) to disable again. */
 
361
    void setSvgBackground( const QString &filename );
 
362
 
 
363
    /** \brief The filename of the SVG background. */
 
364
    QString svgBackground() const;
 
365
 
 
366
    /** \brief Return the last value that we have for the given beam index.
 
367
     *
 
368
     * \return last value, or 0 if not known. */
 
369
    qreal lastValue( int index) const;
 
370
 
 
371
    /** \brief Return a translated string for the last value at the given index.
 
372
     *
 
373
     * Returns, for example,  "34 %" or "100 KB" for the given beam index,
 
374
     * using the last value set for the beam, using the given precision.
 
375
     *
 
376
     * If precision is -1 (the default) then if @p value is greater than 99.5, no decimal figures are shown,
 
377
     * otherwise if @p value is greater than 0.995, 1 decimal figure is used, otherwise 2.
 
378
     */
 
379
    QString lastValueAsString( int index, int precision = -1) const;
 
380
 
 
381
    /** \brief Return a translated string for the given value.
 
382
     *
 
383
     * Returns, for example, "34 %" or "100 KB" for the given value in unscaled units.
 
384
     *
 
385
     * If precision is -1 (the default) then if @p value is greater than 99.5, no decimal figures are shown,
 
386
     * otherwise if @p value is greater than 0.995, 1 decimal figure is used, otherwise 2.
 
387
     *
 
388
     * For example:
 
389
     * \code
 
390
     *   KSignalPlotter plotter;
 
391
     *   plotter.setUnit( ki18ncp("Units", "1 hour", "%1 hours") );
 
392
     *   plotter.scaleDownBy( 60 ); //The input will be in seconds, and there's 60 seconds in an hour
 
393
     *   QString formattedString = plotter.valueAsString(150); //returns "2.5 hours"
 
394
     * \endcode
 
395
     *
 
396
     */
 
397
    QString valueAsString( qreal value, int precision = -1) const;
 
398
 
 
399
    /** \brief Set the distance between the left of the widget and the left of the plotting region.
 
400
     *
 
401
     *  For example:
 
402
     *  \code
 
403
     *      int axisTextWidth = fontMetrics().width(i18nc("Largest axis title", "99999 XXXX"));
 
404
     *      plotter->setMaxAxisTextWidth(axisTextWidth);
 
405
     *  \endcode
 
406
     *
 
407
     *  If this is 0, the default, then the text will be shown inside the plotting area.
 
408
     */
 
409
    void setMaxAxisTextWidth(int maxAxisTextWidth);
 
410
    /** \brief Get the distance between the left of the widget and the left of the plotting region. */
 
411
    int maxAxisTextWidth() const;
 
412
 
 
413
    /** \brief Set whether to smooth the graph by averaging the points.
 
414
     *
 
415
     * This uses the formula:  (value*2 + last_value)/3.
 
416
     * Default is true. */
 
417
    void setSmoothGraph(bool smooth);
 
418
    /** \brief Whether to smooth the graph by averaging the points.
 
419
     *
 
420
     * This uses the formula:  (value*2 + last_value)/3.
 
421
     * Default is true. */
 
422
    bool smoothGraph() const;
 
423
 
 
424
    /** \brief Set whether to stack the beams on top of each other.
 
425
     *
 
426
     * Default is false */
 
427
    void setStackGraph(bool stack);
 
428
    /** \brief Whether to stack the beams on top of each other.
 
429
     *
 
430
     * Default is false */
 
431
    bool stackGraph() const;
 
432
 
 
433
    /** \brief Alpha value for filling the area underneath the graph lines.
 
434
     *
 
435
     * Set to 0 to disable filling the graph, and 255 for a solid fill. Default is 20*/
 
436
    void setFillOpacity(int fill);
 
437
    /** \brief Alpha value for filling the area underneath the graph lines. */
 
438
    int fillOpacity() const;
 
439
 
 
440
    /* Whether to show a thin line on the left and bottom of the widget, for a slight 3D effect */
 
441
    bool thinFrame() const;
 
442
    /* Set whether to show a thin line on the left and bottom of the widget, for a slight 3D effect */
 
443
    void setThinFrame(bool thinFrame);
 
444
 
 
445
  Q_SIGNALS:
 
446
    /** When the axis has changed this signal is emitted. */
 
447
    void axisScaleChanged();
 
448
 
 
449
  protected:
 
450
    /* Reimplemented */
 
451
    virtual void resizeEvent( QResizeEvent* );
 
452
    virtual void paintEvent( QPaintEvent* );
 
453
    virtual QSize sizeHint() const;
 
454
    virtual void changeEvent ( QEvent * event );
 
455
 
 
456
  private:
 
457
    KSignalPlotterPrivate * const d;
 
458
    friend class KSignalPlotterPrivate;
 
459
};
 
460
 
 
461
#endif