##// END OF EJS Templates
pie: added everything as a property in QPieSlice...
Jani Honkonen -
r1274:9c11726517fa
parent child
Show More
@@ -0,0 +1,43
1 #ifndef QPIESLICE_P_H
2 #define QPIESLICE_P_H
3
4 #include <QObject>
5 #include "qpieslice.h"
6 #include "pieslicedata_p.h"
7
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9
10 class QPieSlicePrivate : public QObject
11 {
12 Q_OBJECT
13
14 public:
15 QPieSlicePrivate(QPieSlice *parent);
16 ~QPieSlicePrivate();
17
18 static QPieSlicePrivate* fromSlice(QPieSlice *slice);
19
20 void setPen(const QPen &pen, bool themed);
21 void setBrush(const QBrush &brush, bool themed);
22 void setLabelPen(const QPen &pen, bool themed);
23 void setLabelFont(const QFont &font, bool themed);
24
25 void setPercentage(qreal percentage);
26 void setStartAngle(qreal angle);
27 void setAngleSpan(qreal span);
28
29 private:
30 PieSliceData m_data;
31
32 private:
33 friend class QPieSeriesPrivate;
34 friend class ChartTheme;
35 friend class PieChartItem;
36
37 QPieSlice * const q_ptr;
38 Q_DECLARE_PUBLIC(QPieSlice)
39 };
40
41 QTCOMMERCIALCHART_END_NAMESPACE
42
43 #endif // QPIESLICE_P_H
@@ -1,63 +1,63
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "drilldownslice.h"
22 22
23 23 QTCOMMERCIALCHART_USE_NAMESPACE
24 24
25 25 DrilldownSlice::DrilldownSlice(qreal value, QString prefix, QAbstractSeries* drilldownSeries)
26 26 :m_drilldownSeries(drilldownSeries),
27 27 m_prefix(prefix)
28 28 {
29 29 setValue(value);
30 30 updateLabel();
31 31 setLabelFont(QFont("Arial", 8));
32 connect(this, SIGNAL(calculatedDataChanged()), this, SLOT(updateLabel()));
32 connect(this, SIGNAL(percentageChanged()), this, SLOT(updateLabel()));
33 33 connect(this, SIGNAL(hovered(bool)), this, SLOT(showHighlight(bool)));
34 34 }
35 35
36 36 DrilldownSlice::~DrilldownSlice()
37 37 {
38 38
39 39 }
40 40
41 41 QAbstractSeries* DrilldownSlice::drilldownSeries() const
42 42 {
43 43 return m_drilldownSeries;
44 44 }
45 45
46 46 void DrilldownSlice::updateLabel()
47 47 {
48 48 QString label = m_prefix;
49 49 label += " $";
50 50 label += QString::number(this->value());
51 51 label += ", ";
52 52 label += QString::number(this->percentage()*100, 'f', 1);
53 53 label += "%";
54 54 setLabel(label);
55 55 }
56 56
57 57 void DrilldownSlice::showHighlight(bool show)
58 58 {
59 59 setLabelVisible(show);
60 60 setExploded(show);
61 61 }
62 62
63 63 #include "moc_drilldownslice.cpp"
@@ -1,397 +1,385
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "charttheme_p.h"
22 22 #include "qchart.h"
23 23 #include "qchart_p.h"
24 24 #include "qchartview.h"
25 25 #include "qlegend.h"
26 26 #include "qaxis.h"
27 27 #include <QTime>
28 28
29 29 //series
30 30 #include "qbarset.h"
31 31 #include "qbarseries.h"
32 32 #include "qstackedbarseries.h"
33 33 #include "qpercentbarseries.h"
34 34 #include "qlineseries.h"
35 35 #include "qareaseries.h"
36 36 #include "qscatterseries.h"
37 37 #include "qpieseries.h"
38 38 #include "qpieslice.h"
39 #include "qpieslice_p.h"
39 40 #include "qsplineseries.h"
40 41
41 42 //items
42 43 #include "chartaxis_p.h"
43 44 #include "barchartitem_p.h"
44 45 #include "stackedbarchartitem_p.h"
45 46 #include "percentbarchartitem_p.h"
46 47 #include "linechartitem_p.h"
47 48 #include "areachartitem_p.h"
48 49 #include "scatterchartitem_p.h"
49 50 #include "piechartitem_p.h"
50 51 #include "splinechartitem_p.h"
51 52
52 53 //themes
53 54 #include "chartthemesystem_p.h"
54 55 #include "chartthemelight_p.h"
55 56 #include "chartthemebluecerulean_p.h"
56 57 #include "chartthemedark_p.h"
57 58 #include "chartthemebrownsand_p.h"
58 59 #include "chartthemebluencs_p.h"
59 60 #include "chartthemehighcontrast_p.h"
60 61 #include "chartthemeblueicy_p.h"
61 62
62 63 QTCOMMERCIALCHART_BEGIN_NAMESPACE
63 64
64 65 ChartTheme::ChartTheme(QChart::ChartTheme id) :
65 66 m_masterFont(QFont("arial", 14)),
66 67 m_labelFont(QFont("arial", 10)),
67 68 m_titleBrush(QColor(QRgb(0x000000))),
68 69 m_axisLinePen(QPen(QRgb(0x000000))),
69 70 m_axisLabelBrush(QColor(QRgb(0x000000))),
70 71 m_backgroundShadesPen(Qt::NoPen),
71 72 m_backgroundShadesBrush(Qt::NoBrush),
72 73 m_backgroundShades(BackgroundShadesNone),
73 74 m_backgroundDropShadowEnabled(false),
74 75 m_gridLinePen(QPen(QRgb(0x000000))),
75 76 m_force(false)
76 77 {
77 78 m_id = id;
78 79 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
79 80 }
80 81
81 82
82 83 ChartTheme* ChartTheme::createTheme(QChart::ChartTheme theme)
83 84 {
84 85 switch(theme) {
85 86 case QChart::ChartThemeLight:
86 87 return new ChartThemeLight();
87 88 case QChart::ChartThemeBlueCerulean:
88 89 return new ChartThemeBlueCerulean();
89 90 case QChart::ChartThemeDark:
90 91 return new ChartThemeDark();
91 92 case QChart::ChartThemeBrownSand:
92 93 return new ChartThemeBrownSand();
93 94 case QChart::ChartThemeBlueNcs:
94 95 return new ChartThemeBlueNcs();
95 96 case QChart::ChartThemeHighContrast:
96 97 return new ChartThemeHighContrast();
97 98 case QChart::ChartThemeBlueIcy:
98 99 return new ChartThemeBlueIcy();
99 100 default:
100 101 return new ChartThemeSystem();
101 102 }
102 103 }
103 104
104 105 void ChartTheme::decorate(QChart *chart)
105 106 {
106 107 QBrush brush;
107 108
108 109 if(brush == chart->backgroundBrush() || m_force)
109 110 chart->setBackgroundBrush(m_chartBackgroundGradient);
110 111 chart->setTitleFont(m_masterFont);
111 112 chart->setTitleBrush(m_titleBrush);
112 113 chart->setBackgroundDropShadowEnabled(m_backgroundDropShadowEnabled);
113 114 }
114 115
115 116 void ChartTheme::decorate(QLegend *legend)
116 117 {
117 118 QPen pen;
118 119 QBrush brush;
119 120
120 121 if (pen == legend->pen() || m_force){
121 122 legend->setPen(Qt::NoPen);
122 123 }
123 124
124 125 if (brush == legend->brush() || m_force) {
125 126 legend->setBrush(m_chartBackgroundGradient);
126 127 }
127 128 }
128 129
129 130 void ChartTheme::decorate(QAreaSeries *series, int index)
130 131 {
131 132 QPen pen;
132 133 QBrush brush;
133 134
134 135 if (pen == series->pen() || m_force){
135 136 pen.setColor(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.0));
136 137 pen.setWidthF(2);
137 138 series->setPen(pen);
138 139 }
139 140
140 141 if (brush == series->brush() || m_force) {
141 142 QBrush brush(m_seriesColors.at(index % m_seriesColors.size()));
142 143 series->setBrush(brush);
143 144 }
144 145 }
145 146
146 147
147 148 void ChartTheme::decorate(QLineSeries *series,int index)
148 149 {
149 150 QPen pen;
150 151 if(pen == series->pen() || m_force ){
151 152 pen.setColor(m_seriesColors.at(index%m_seriesColors.size()));
152 153 pen.setWidthF(2);
153 154 series->setPen(pen);
154 155 }
155 156 }
156 157
157 158 void ChartTheme::decorate(QBarSeries *series, int index)
158 159 {
159 160 QBrush brush;
160 161 QPen pen;
161 162 QList<QBarSet *> sets = series->barSets();
162 163
163 164 qreal takeAtPos = 0.5;
164 165 qreal step = 0.2;
165 166 if (sets.count() > 1 ) {
166 167 step = 1.0 / (qreal) sets.count();
167 168 if (sets.count() % m_seriesGradients.count())
168 169 step *= m_seriesGradients.count();
169 170 else
170 171 step *= (m_seriesGradients.count() - 1);
171 172 }
172 173
173 174 for (int i(0); i < sets.count(); i++) {
174 175 int colorIndex = (index + i) % m_seriesGradients.count();
175 176 if (i > 0 && i % m_seriesGradients.count() == 0) {
176 177 // There is no dedicated base color for each sets, generate more colors
177 178 takeAtPos += step;
178 179 if (takeAtPos == 1.0)
179 180 takeAtPos += step;
180 181 takeAtPos -= (int) takeAtPos;
181 182 }
182 183 if (brush == sets.at(i)->brush() || m_force )
183 184 sets.at(i)->setBrush(colorAt(m_seriesGradients.at(colorIndex), takeAtPos));
184 185
185 186 // Pick label color from the opposite end of the gradient.
186 187 // 0.3 as a boundary seems to work well.
187 188 if (takeAtPos < 0.3)
188 189 sets.at(i)->setLabelBrush(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1));
189 190 else
190 191 sets.at(i)->setLabelBrush(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0));
191 192
192 193 if (pen == sets.at(i)->pen() || m_force) {
193 194 QColor c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.0);
194 195 sets.at(i)->setPen(c);
195 196 }
196 197 }
197 198 }
198 199
199 200 void ChartTheme::decorate(QScatterSeries *series, int index)
200 201 {
201 202 QPen pen;
202 203 QBrush brush;
203 204
204 205 if (pen == series->pen() || m_force) {
205 206 pen.setColor(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.0));
206 207 pen.setWidthF(2);
207 208 series->setPen(pen);
208 209 }
209 210
210 211 if (brush == series->brush() || m_force) {
211 212 QBrush brush(m_seriesColors.at(index % m_seriesColors.size()));
212 213 series->setBrush(brush);
213 214 }
214 215 }
215 216
216 217 void ChartTheme::decorate(QPieSeries *series, int index)
217 218 {
218 219
219 220 for (int i(0); i < series->slices().count(); i++) {
220 221
221 222 QColor penColor = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.0);
222 223
223 224 // Get color for a slice from a gradient linearly, beginning from the start of the gradient
224 225 qreal pos = (qreal) (i + 1) / (qreal) series->count();
225 226 QColor brushColor = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos);
226 227
227 228 QPieSlice *s = series->slices().at(i);
228 PieSliceData data = PieSliceData::fromSlice(s);
229 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
229 230
230 if (data.m_slicePen.isThemed() || m_force) {
231 data.m_slicePen = penColor;
232 data.m_slicePen.setThemed(true);
233 }
234
235 if (data.m_sliceBrush.isThemed() || m_force) {
236 data.m_sliceBrush = brushColor;
237 data.m_sliceBrush.setThemed(true);
238 }
231 if (d->m_data.m_slicePen.isThemed() || m_force)
232 d->setPen(penColor, true);
239 233
240 if (data.m_labelPen.isThemed() || m_force) {
241 data.m_labelPen = QPen(m_titleBrush.color());
242 data.m_labelPen.setThemed(true);
243 }
234 if (d->m_data.m_sliceBrush.isThemed() || m_force)
235 d->setBrush(brushColor, true);
244 236
245 if (data.m_labelFont.isThemed() || m_force) {
246 data.m_labelFont = m_labelFont;
247 data.m_labelFont.setThemed(true);
248 }
237 if (d->m_data.m_labelPen.isThemed() || m_force)
238 d->setLabelPen(QPen(m_titleBrush.color()), true);
249 239
250 if (PieSliceData::fromSlice(s) != data) {
251 PieSliceData::fromSlice(s) = data;
252 emit PieSliceData::emitAppearanceChanged(s);
253 }
240 if (d->m_data.m_labelFont.isThemed() || m_force)
241 d->setLabelFont(m_labelFont, true);
254 242 }
255 243 }
256 244
257 245 void ChartTheme::decorate(QSplineSeries *series, int index)
258 246 {
259 247 QPen pen;
260 248 if(pen == series->pen() || m_force){
261 249 pen.setColor(m_seriesColors.at(index%m_seriesColors.size()));
262 250 pen.setWidthF(2);
263 251 series->setPen(pen);
264 252 }
265 253 }
266 254
267 255 void ChartTheme::decorate(QAxis *axis,bool axisX)
268 256 {
269 257 QPen pen;
270 258 QBrush brush;
271 259 QFont font;
272 260
273 261 if (axis->isAxisVisible()) {
274 262
275 263 if(brush == axis->labelsBrush() || m_force){
276 264 axis->setLabelsBrush(m_axisLabelBrush);
277 265 }
278 266 if(pen == axis->labelsPen() || m_force){
279 267 axis->setLabelsPen(Qt::NoPen); // NoPen for performance reasons
280 268 }
281 269
282 270
283 271 if (axis->shadesVisible() || m_force) {
284 272
285 273 if(brush == axis->shadesBrush() || m_force){
286 274 axis->setShadesBrush(m_backgroundShadesBrush);
287 275 }
288 276
289 277 if(pen == axis->shadesPen() || m_force){
290 278 axis->setShadesPen(m_backgroundShadesPen);
291 279 }
292 280
293 281 if( m_force && (m_backgroundShades == BackgroundShadesBoth
294 282 || (m_backgroundShades == BackgroundShadesVertical && axisX)
295 283 || (m_backgroundShades == BackgroundShadesHorizontal && !axisX))){
296 284 axis->setShadesVisible(true);
297 285
298 286 }
299 287 }
300 288
301 289 if(pen == axis->axisPen() || m_force){
302 290 axis->setAxisPen(m_axisLinePen);
303 291 }
304 292
305 293 if(pen == axis->gridLinePen() || m_force){
306 294 axis->setGridLinePen(m_gridLinePen);
307 295 }
308 296
309 297 if(font == axis->labelsFont() || m_force){
310 298 axis->setLabelsFont(m_labelFont);
311 299 }
312 300 }
313 301 }
314 302
315 303 void ChartTheme::generateSeriesGradients()
316 304 {
317 305 // Generate gradients in HSV color space
318 306 foreach (const QColor& color, m_seriesColors) {
319 307 QLinearGradient g;
320 308 qreal h = color.hsvHueF();
321 309 qreal s = color.hsvSaturationF();
322 310
323 311 // TODO: tune the algorithm to give nice results with most base colors defined in
324 312 // most themes. The rest of the gradients we can define manually in theme specific
325 313 // implementation.
326 314 QColor start = color;
327 315 start.setHsvF(h, 0.0, 1.0);
328 316 g.setColorAt(0.0, start);
329 317
330 318 g.setColorAt(0.5, color);
331 319
332 320 QColor end = color;
333 321 end.setHsvF(h, s, 0.25);
334 322 g.setColorAt(1.0, end);
335 323
336 324 m_seriesGradients << g;
337 325 }
338 326 }
339 327
340 328
341 329 QColor ChartTheme::colorAt(const QColor &start, const QColor &end, qreal pos)
342 330 {
343 331 Q_ASSERT(pos >= 0.0 && pos <= 1.0);
344 332 qreal r = start.redF() + ((end.redF() - start.redF()) * pos);
345 333 qreal g = start.greenF() + ((end.greenF() - start.greenF()) * pos);
346 334 qreal b = start.blueF() + ((end.blueF() - start.blueF()) * pos);
347 335 QColor c;
348 336 c.setRgbF(r, g, b);
349 337 return c;
350 338 }
351 339
352 340 QColor ChartTheme::colorAt(const QGradient &gradient, qreal pos)
353 341 {
354 342 Q_ASSERT(pos >= 0 && pos <= 1.0);
355 343
356 344 QGradientStops stops = gradient.stops();
357 345 int count = stops.count();
358 346
359 347 // find previous stop relative to position
360 348 QGradientStop prev = stops.first();
361 349 for (int i = 0; i < count; i++) {
362 350 QGradientStop stop = stops.at(i);
363 351 if (pos > stop.first)
364 352 prev = stop;
365 353
366 354 // given position is actually a stop position?
367 355 if (pos == stop.first) {
368 356 //qDebug() << "stop color" << pos;
369 357 return stop.second;
370 358 }
371 359 }
372 360
373 361 // find next stop relative to position
374 362 QGradientStop next = stops.last();
375 363 for (int i = count - 1; i >= 0; i--) {
376 364 QGradientStop stop = stops.at(i);
377 365 if (pos < stop.first)
378 366 next = stop;
379 367 }
380 368
381 369 //qDebug() << "prev" << prev.first << "pos" << pos << "next" << next.first;
382 370
383 371 qreal range = next.first - prev.first;
384 372 qreal posDelta = pos - prev.first;
385 373 qreal relativePos = posDelta / range;
386 374
387 375 //qDebug() << "range" << range << "posDelta" << posDelta << "relativePos" << relativePos;
388 376
389 377 return colorAt(prev.second, next.second, relativePos);
390 378 }
391 379
392 380 void ChartTheme::setForced(bool enabled)
393 381 {
394 382 m_force=enabled;
395 383 }
396 384
397 385 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,195 +1,195
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "legendmarker_p.h"
22 22 #include "qxyseries.h"
23 23 #include "qxyseries_p.h"
24 24 #include "qlegend.h"
25 25 #include "qbarseries.h"
26 26 #include "qpieseries.h"
27 27 #include "qpieslice.h"
28 28 #include "qbarset.h"
29 29 #include "qbarset_p.h"
30 30 #include "qareaseries.h"
31 31 #include "qareaseries_p.h"
32 32 #include <QPainter>
33 33 #include <QGraphicsSceneEvent>
34 34 #include <QGraphicsSimpleTextItem>
35 35 #include <QDebug>
36 36
37 37 QTCOMMERCIALCHART_BEGIN_NAMESPACE
38 38
39 39 LegendMarker::LegendMarker(QAbstractSeries *series, QLegend *legend) : QGraphicsObject(legend),
40 40 m_series(series),
41 41 m_markerRect(0,0,10.0,10.0),
42 42 m_boundingRect(0,0,0,0),
43 43 m_legend(legend),
44 44 m_textItem(new QGraphicsSimpleTextItem(this)),
45 45 m_rectItem(new QGraphicsRectItem(this))
46 46 {
47 47 //setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton);
48 48 m_rectItem->setRect(m_markerRect);
49 49 updateLayout();
50 50 }
51 51
52 52 void LegendMarker::setPen(const QPen &pen)
53 53 {
54 54 m_textItem->setPen(pen);
55 55 updateLayout();
56 56 }
57 57
58 58 QPen LegendMarker::pen() const
59 59 {
60 60 return m_textItem->pen();
61 61 }
62 62
63 63 void LegendMarker::setBrush(const QBrush &brush)
64 64 {
65 65 m_rectItem->setBrush(brush);
66 66 }
67 67
68 68 QBrush LegendMarker::brush() const
69 69 {
70 70 return m_rectItem->brush();
71 71 }
72 72
73 73 void LegendMarker::setLabel(const QString name)
74 74 {
75 75 m_textItem->setText(name);
76 76 updateLayout();
77 77 }
78 78
79 79 void LegendMarker::setSize(const QSize& size)
80 80 {
81 81 m_markerRect = QRectF(0,0,size.width(),size.height());
82 82 }
83 83
84 84 QString LegendMarker::label() const
85 85 {
86 86 return m_textItem->text();
87 87 }
88 88
89 89 void LegendMarker::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
90 90 {
91 91 Q_UNUSED(option)
92 92 Q_UNUSED(widget)
93 93 Q_UNUSED(painter)
94 94 }
95 95
96 96 QRectF LegendMarker::boundingRect() const
97 97 {
98 98 return m_boundingRect;
99 99 }
100 100
101 101 void LegendMarker::updateLayout()
102 102 {
103 103
104 104 static const qreal margin = 2;
105 105 static const qreal space = 4;
106 106
107 107 const QRectF& textRect = m_textItem->boundingRect();
108 108 prepareGeometryChange();
109 109 m_boundingRect = QRectF(0,0,m_markerRect.width() + 2*margin + space + textRect.width(),qMax(m_markerRect.height()+2*margin,textRect.height()+2*margin));
110 110 m_textItem->setPos(m_markerRect.width() + space + margin,m_boundingRect.height()/2 - textRect.height()/2);
111 111 m_rectItem->setPos(margin,m_boundingRect.height()/2 - m_markerRect.height()/2);
112 112
113 113 }
114 114
115 115 void LegendMarker::mousePressEvent(QGraphicsSceneMouseEvent *event)
116 116 {
117 117 QGraphicsObject::mousePressEvent(event);
118 118 qDebug()<<"Not implemented"; //TODO: selected signal removed for now
119 119 }
120 120
121 121 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
122 122
123 123 AreaLegendMarker::AreaLegendMarker(QAreaSeries *series,QLegend *legend) : LegendMarker(series,legend),
124 124 m_series(series)
125 125 {
126 126 //QObject::connect(this, SIGNAL(selected()), series, SIGNAL(selected()));
127 127 QObject::connect(series->d_func(),SIGNAL(updated()), this, SLOT(updated()));
128 128 updated();
129 129 }
130 130
131 131 void AreaLegendMarker::updated()
132 132 {
133 133 setBrush(m_series->brush());
134 134 setLabel(m_series->name());
135 135 }
136 136
137 137 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
138 138
139 139 BarLegendMarker::BarLegendMarker(QBarSeries *barseries,QBarSet *barset, QLegend *legend) : LegendMarker(barseries,legend),
140 140 m_barset(barset)
141 141 {
142 142 //QObject::connect(this, SIGNAL(selected()),barset->d_ptr.data(), SIGNAL(selected()));
143 143 QObject::connect(barset->d_ptr.data(), SIGNAL(updatedBars()), this, SLOT(updated()));
144 144 updated();
145 145 }
146 146
147 147 void BarLegendMarker::updated()
148 148 {
149 149 setBrush(m_barset->brush());
150 150 setLabel(m_barset->name());
151 151 }
152 152
153 153 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
154 154
155 155 PieLegendMarker::PieLegendMarker(QPieSeries* series,QPieSlice *pieslice, QLegend *legend) : LegendMarker(series,legend),
156 156 m_pieslice(pieslice)
157 157 {
158 158 QObject::connect(pieslice, SIGNAL(labelChanged()), this, SLOT(updated()));
159 QObject::connect(pieslice, SIGNAL(appearanceChanged()), this, SLOT(updated()));
159 QObject::connect(pieslice, SIGNAL(brushChanged()), this, SLOT(updated()));
160 160 updated();
161 161 }
162 162
163 163 void PieLegendMarker::updated()
164 164 {
165 165 setBrush(m_pieslice->brush());
166 166 setLabel(m_pieslice->label());
167 167 }
168 168
169 169 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
170 170
171 171 XYLegendMarker::XYLegendMarker(QXYSeries *series, QLegend *legend) : LegendMarker(series,legend),
172 172 m_series(series)
173 173 {
174 174 //QObject::connect(this, SIGNAL(selected()), series, SIGNAL(selected()));
175 175 QObject::connect(series->d_func(),SIGNAL(updated()), this, SLOT(updated()));
176 176 updated();
177 177 }
178 178
179 179 void XYLegendMarker::updated()
180 180 {
181 181 setLabel(m_series->name());
182 182
183 183 if(m_series->type()== QAbstractSeries::SeriesTypeScatter)
184 184 {
185 185 setBrush(m_series->brush());
186 186
187 187 }
188 188 else {
189 189 setBrush(QBrush(m_series->pen().color()));
190 190 }
191 191 }
192 192
193 193 #include "moc_legendmarker_p.cpp"
194 194
195 195 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,25 +1,27
1 1 INCLUDEPATH += $$PWD
2 2 DEPENDPATH += $$PWD
3 3
4 4 SOURCES += \
5 5 $$PWD/qpieseries.cpp \
6 6 $$PWD/piesliceitem.cpp \
7 7 $$PWD/piechartitem.cpp \
8 8 $$PWD/qpieslice.cpp \
9 9 $$PWD/qpiemodelmapper.cpp \
10 10 $$PWD/qvpiemodelmapper.cpp \
11 11 $$PWD/qhpiemodelmapper.cpp
12 12
13 13 PRIVATE_HEADERS += \
14 14 $$PWD/pieslicedata_p.h \
15 15 $$PWD/piechartitem_p.h \
16 16 $$PWD/piesliceitem_p.h \
17 $$PWD/qpieslice_p.h \
17 18 $$PWD/qpieseries_p.h \
18 19 $$PWD/qpiemodelmapper_p.h
19 20
20 21 PUBLIC_HEADERS += \
21 22 $$PWD/qpieseries.h \
22 23 $$PWD/qpieslice.h \
23 24 $$PWD/qpiemodelmapper.h \
24 25 $$PWD/qvpiemodelmapper.h \
25 26 $$PWD/qhpiemodelmapper.h
27
@@ -1,194 +1,203
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piechartitem_p.h"
22 22 #include "piesliceitem_p.h"
23 23 #include "qpieslice.h"
24 #include "qpieslice_p.h"
24 25 #include "qpieseries.h"
25 26 #include "qpieseries_p.h"
26 27 #include "chartpresenter_p.h"
27 28 #include "chartdataset_p.h"
28 29 #include "chartanimator_p.h"
29 30 #include <QPainter>
30 31 #include <QTimer>
31 32
32 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 34
34 35 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
35 36 :ChartItem(presenter),
36 37 m_series(series)
37 38 {
38 39 Q_ASSERT(series);
39 40
40 41 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
41 42 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
42 43 connect(series, SIGNAL(horizontalPositionChanged()), this, SLOT(updateLayout()));
43 44 connect(series, SIGNAL(verticalPositionChanged()), this, SLOT(updateLayout()));
44 45 connect(series, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
46 connect(QPieSeriesPrivate::fromSeries(series), SIGNAL(calculatedDataChanged()), this, SLOT(updateLayout()));
45 47
46 48 // Note: the following does not affect as long as the item does not have anything to paint
47 49 setZValue(ChartPresenter::PieSeriesZValue);
48 50
49 51 // Note: will not create slice items until we have a proper rectangle to draw on.
50 52 }
51 53
52 54 PieChartItem::~PieChartItem()
53 55 {
54 56 // slices deleted automatically through QGraphicsItem
55 57 }
56 58
57 59 void PieChartItem::handleGeometryChanged(const QRectF& rect)
58 60 {
59 61 prepareGeometryChange();
60 62 m_rect = rect;
61 63 updateLayout();
62 64
63 65 // This is for delayed initialization of the slice items during startup.
64 66 // It ensures that startup animation originates from the correct position.
65 67 if (m_sliceItems.isEmpty())
66 68 handleSlicesAdded(m_series->slices());
67 69 }
68 70
69 71 void PieChartItem::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY)
70 72 {
71 73 Q_UNUSED(minX);
72 74 Q_UNUSED(maxX);
73 75 Q_UNUSED(minY);
74 76 Q_UNUSED(maxY);
75 77 // does not apply to pie
76 78 }
77 79
78 80 void PieChartItem::rangeXChanged(qreal min, qreal max, int tickXCount)
79 81 {
80 82 Q_UNUSED(min);
81 83 Q_UNUSED(max);
82 84 Q_UNUSED(tickXCount);
83 85 // does not apply to pie
84 86 }
85 87
86 88 void PieChartItem::rangeYChanged(qreal min, qreal max, int tickYCount)
87 89 {
88 90 Q_UNUSED(min);
89 91 Q_UNUSED(max);
90 92 Q_UNUSED(tickYCount);
91 93 // does not apply to pie
92 94 }
93 95
94 96 void PieChartItem::updateLayout()
95 97 {
96 98 // find pie center coordinates
97 99 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
98 100 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
99 101
100 102 // find maximum radius for pie
101 103 m_pieRadius = m_rect.height() / 2;
102 104 if (m_rect.width() < m_rect.height())
103 105 m_pieRadius = m_rect.width() / 2;
104 106
105 107 // apply size factor
106 108 m_pieRadius *= m_series->pieSize();
107 109
108 110 // set layouts for existing slice items
109 111 foreach (QPieSlice* slice, m_series->slices()) {
110 112 PieSliceItem *sliceItem = m_sliceItems.value(slice);
111 113 if (sliceItem) {
112 114 PieSliceData sliceData = updateSliceGeometry(slice);
113 115 if (animator())
114 116 animator()->updateAnimation(this, sliceItem, sliceData);
115 117 else
116 118 sliceItem->setLayout(sliceData);
117 119 }
118 120 }
119 121
120 122 update();
121 123 }
122 124
123 125 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
124 126 {
125 127 // delay creating slice items until there is a proper rectangle
126 128 if (!m_rect.isValid() && m_sliceItems.isEmpty())
127 129 return;
128 130
129 131 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
130 132
131 133 bool startupAnimation = m_sliceItems.isEmpty();
132 134
133 135 foreach (QPieSlice *slice, slices) {
134 136 PieSliceItem* sliceItem = new PieSliceItem(this);
135 137 m_sliceItems.insert(slice, sliceItem);
136 138
137 // note: do need to connect to slice valueChanged(). calculatedDataChanged() is enough.
138 // to update the slice.
139 connect(slice, SIGNAL(calculatedDataChanged()), this, SLOT(handleSliceChanged()));
139 // Note: do need to connect to slice valueChanged() etc.
140 // This is handled through calculatedDataChanged signal.
140 141 connect(slice, SIGNAL(labelChanged()), this, SLOT(handleSliceChanged()));
141 connect(slice, SIGNAL(appearanceChanged()), this, SLOT(handleSliceChanged()));
142 connect(slice, SIGNAL(labelVisibleChanged()), this, SLOT(handleSliceChanged()));
143 connect(slice, SIGNAL(explodedChanged()), this, SLOT(handleSliceChanged()));
144 connect(slice, SIGNAL(penChanged()), this, SLOT(handleSliceChanged()));
145 connect(slice, SIGNAL(brushChanged()), this, SLOT(handleSliceChanged()));
146 connect(slice, SIGNAL(labelPenChanged()), this, SLOT(handleSliceChanged()));
147 connect(slice, SIGNAL(labelFontChanged()), this, SLOT(handleSliceChanged()));
148 connect(slice, SIGNAL(labelArmLengthFactorChanged()), this, SLOT(handleSliceChanged()));
149 connect(slice, SIGNAL(explodeDistanceFactorChanged()), this, SLOT(handleSliceChanged()));
150
142 151 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
143 152 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
144 153
145 154 PieSliceData sliceData = updateSliceGeometry(slice);
146 155 if (animator())
147 156 animator()->addAnimation(this, sliceItem, sliceData, startupAnimation);
148 157 else
149 158 sliceItem->setLayout(sliceData);
150 159 }
151 160 }
152 161
153 162 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
154 163 {
155 164 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
156 165
157 166 foreach (QPieSlice *slice, slices) {
158 167 PieSliceItem *sliceItem = m_sliceItems.value(slice);
159 168 Q_ASSERT(sliceItem);
160 169 m_sliceItems.remove(slice);
161 170
162 171 if (animator())
163 172 animator()->removeAnimation(this, sliceItem); // animator deletes the PieSliceItem
164 173 else
165 174 delete sliceItem;
166 175 }
167 176 }
168 177
169 178 void PieChartItem::handleSliceChanged()
170 179 {
171 180 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
172 181 Q_ASSERT(m_sliceItems.contains(slice));
173 182
174 183 PieSliceItem *sliceItem = m_sliceItems.value(slice);
175 184 PieSliceData sliceData = updateSliceGeometry(slice);
176 185 if (animator())
177 186 animator()->updateAnimation(this, sliceItem, sliceData);
178 187 else
179 188 sliceItem->setLayout(sliceData);
180 189
181 190 update();
182 191 }
183 192
184 193 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
185 194 {
186 PieSliceData &sliceData = PieSliceData::fromSlice(slice);
195 PieSliceData &sliceData = QPieSlicePrivate::fromSlice(slice)->m_data;
187 196 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
188 197 sliceData.m_radius = m_pieRadius;
189 198 return sliceData;
190 199 }
191 200
192 201 #include "moc_piechartitem_p.cpp"
193 202
194 203 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,148 +1,130
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef PIESLICEDATA_P_H
22 22 #define PIESLICEDATA_P_H
23 23
24 24 #include "qchartglobal.h"
25 25 #include "qpieslice.h"
26 26 #include <QPen>
27 27 #include <QBrush>
28 28
29 29 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 30
31 31 template <class T>
32 32 class Themed : public T
33 33 {
34 34 public:
35 35 Themed():m_isThemed(true) {}
36 36
37 37 inline T &operator=(const T &other) { return T::operator =(other); }
38 38
39 39 inline bool operator!=(const T &other) const { return T::operator !=(other); }
40 40 inline bool operator!=(const Themed &other) const
41 41 {
42 42 if (T::operator !=(other))
43 43 return true;
44 44
45 45 if (m_isThemed != other.m_isThemed)
46 46 return true;
47 47
48 48 return false;
49 49 }
50 50
51 51 inline void setThemed(bool state) { m_isThemed = state; }
52 52 inline bool isThemed() const { return m_isThemed; }
53 53
54 54 private:
55 55 bool m_isThemed;
56 56 };
57 57
58 58 class PieSliceData
59 59 {
60 60 public:
61 61 PieSliceData()
62 62 {
63 63 m_value = 0;
64 64
65 65 m_isExploded = false;
66 66 m_explodeDistanceFactor = 0.15;
67 67
68 68 m_isLabelVisible = false;
69 69 m_labelArmLengthFactor = 0.15;
70 70
71 71 m_percentage = 0;
72 72 m_radius = 0;
73 73 m_startAngle = 0;
74 74 m_angleSpan = 0;
75 75 }
76 76
77 77 bool operator!=(const PieSliceData &other) const
78 78 {
79 79 if (!qFuzzyIsNull(m_value - other.m_value))
80 80 return true;
81 81
82 82 if (m_slicePen != other.m_slicePen ||
83 83 m_sliceBrush != other.m_sliceBrush)
84 84 return true;
85 85
86 86 if (m_isExploded != other.m_isExploded ||
87 87 !qFuzzyIsNull(m_explodeDistanceFactor - other.m_explodeDistanceFactor))
88 88 return true;
89 89
90 90 if (m_isLabelVisible != other.m_isLabelVisible ||
91 91 m_labelText != other.m_labelText ||
92 92 m_labelFont != other.m_labelFont ||
93 93 !qFuzzyIsNull(m_labelArmLengthFactor - other.m_labelArmLengthFactor) ||
94 94 m_labelPen != other.m_labelPen)
95 95 return true;
96 96
97 97 if (!qFuzzyIsNull(m_percentage - other.m_percentage) ||
98 98 m_center != other.m_center ||
99 99 !qFuzzyIsNull(m_radius - other.m_radius) ||
100 100 !qFuzzyIsNull(m_startAngle - other.m_startAngle) ||
101 101 !qFuzzyIsNull(m_angleSpan - other.m_angleSpan))
102 102 return true;
103 103
104 104 return false;
105 105 }
106 106
107 static void emitAppearanceChanged(QPieSlice *slice)
108 {
109 Q_ASSERT(slice);
110 emit slice->appearanceChanged();
111 }
112
113 static void emitCalculatedDataChanged(QPieSlice *slice)
114 {
115 Q_ASSERT(slice);
116 emit slice->calculatedDataChanged();
117 }
118
119 static PieSliceData &fromSlice(QPieSlice *slice)
120 {
121 Q_ASSERT(slice);
122 return *slice->d;
123 }
124
125 107 qreal m_value;
126 108
127 109 Themed<QPen> m_slicePen;
128 110 Themed<QBrush> m_sliceBrush;
129 111
130 112 bool m_isExploded;
131 113 qreal m_explodeDistanceFactor;
132 114
133 115 bool m_isLabelVisible;
134 116 QString m_labelText;
135 117 Themed<QFont> m_labelFont;
136 118 qreal m_labelArmLengthFactor;
137 119 Themed<QPen> m_labelPen;
138 120
139 121 qreal m_percentage;
140 122 QPointF m_center;
141 123 qreal m_radius;
142 124 qreal m_startAngle;
143 125 qreal m_angleSpan;
144 126 };
145 127
146 128 QTCOMMERCIALCHART_END_NAMESPACE
147 129
148 130 #endif // PIESLICEDATA_P_H
@@ -1,220 +1,220
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "piesliceitem_p.h"
22 22 #include "piechartitem_p.h"
23 23 #include "qpieseries.h"
24 24 #include "qpieslice.h"
25 25 #include "chartpresenter_p.h"
26 26 #include <QPainter>
27 27 #include <qmath.h>
28 28 #include <QGraphicsSceneEvent>
29 29 #include <QTime>
30 30
31 31 QTCOMMERCIALCHART_BEGIN_NAMESPACE
32 32
33 33 #define PI 3.14159265 // TODO: is this defined in some header?
34 34
35 35 QPointF offset(qreal angle, qreal length)
36 36 {
37 37 qreal dx = qSin(angle*(PI/180)) * length;
38 38 qreal dy = qCos(angle*(PI/180)) * length;
39 39 return QPointF(dx, -dy);
40 40 }
41 41
42 42 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
43 43 :QGraphicsObject(parent),
44 44 m_hovered(false)
45 45 {
46 46 setAcceptHoverEvents(true);
47 47 setAcceptedMouseButtons(Qt::MouseButtonMask);
48 48 setZValue(ChartPresenter::PieSeriesZValue);
49 49 }
50 50
51 51 PieSliceItem::~PieSliceItem()
52 52 {
53 53 // If user is hovering over the slice and it gets destroyed we do
54 54 // not get a hover leave event. So we must emit the signal here.
55 55 if (m_hovered)
56 56 emit hovered(false);
57 57 }
58 58
59 59 QRectF PieSliceItem::boundingRect() const
60 60 {
61 61 return m_boundingRect;
62 62 }
63 63
64 64 QPainterPath PieSliceItem::shape() const
65 65 {
66 66 // Don't include the label and label arm.
67 67 // This is used to detect a mouse clicks. We do not want clicks from label.
68 68 return m_slicePath;
69 69 }
70 70
71 71 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
72 72 {
73 73 painter->save();
74 74 painter->setClipRect(parentItem()->boundingRect());
75 75 painter->setPen(m_data.m_slicePen);
76 76 painter->setBrush(m_data.m_sliceBrush);
77 77 painter->drawPath(m_slicePath);
78 78 painter->restore();
79 79
80 80 if (m_data.m_isLabelVisible) {
81 81 painter->setClipRect(parentItem()->boundingRect());
82 82 painter->setPen(m_data.m_labelPen);
83 83 painter->drawPath(m_labelArmPath);
84 84 // the pen color will affect the font color as well
85 85 painter->setFont(m_data.m_labelFont);
86 86 painter->drawText(m_labelTextRect.bottomLeft(), m_data.m_labelText);
87 87 }
88 88 }
89 89
90 90 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
91 91 {
92 92 m_hovered = true;
93 93 emit hovered(true);
94 94 }
95 95
96 96 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
97 97 {
98 98 m_hovered = false;
99 99 emit hovered(false);
100 100 }
101 101
102 102 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
103 103 {
104 104 emit clicked(event->buttons());
105 105 }
106 106
107 107 void PieSliceItem::setLayout(const PieSliceData &sliceData)
108 108 {
109 109 m_data = sliceData;
110 110 updateGeometry();
111 111 update();
112 112 }
113 113
114 114 void PieSliceItem::updateGeometry()
115 115 {
116 116 if (m_data.m_radius <= 0)
117 117 return;
118 118
119 119 prepareGeometryChange();
120 120
121 121 // update slice path
122 122 qreal centerAngle;
123 123 QPointF armStart;
124 124 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
125 125
126 126 // update text rect
127 127 m_labelTextRect = labelTextRect(m_data.m_labelFont, m_data.m_labelText);
128 128
129 129 // update label arm path
130 130 QPointF labelTextStart;
131 131 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
132 132
133 133 // update text position
134 134 m_labelTextRect.moveBottomLeft(labelTextStart);
135 135
136 136 // update bounding rect
137 137 if (m_data.m_isLabelVisible)
138 138 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
139 139 else
140 140 m_boundingRect = m_slicePath.boundingRect();
141 141 }
142 142
143 143 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
144 144 {
145 145 if (slice->isExploded()) {
146 qreal centerAngle = slice->startAngle() + ((slice->endAngle() - slice->startAngle())/2);
146 qreal centerAngle = slice->startAngle() + (slice->angleSpan()/2);
147 147 qreal len = radius * slice->explodeDistanceFactor();
148 148 qreal dx = qSin(centerAngle*(PI/180)) * len;
149 149 qreal dy = -qCos(centerAngle*(PI/180)) * len;
150 150 point += QPointF(dx, dy);
151 151 }
152 152 return point;
153 153 }
154 154
155 155 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
156 156 {
157 157 // calculate center angle
158 158 *centerAngle = startAngle + (angleSpan/2);
159 159
160 160 // calculate slice rectangle
161 161 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
162 162
163 163 // slice path
164 164 // TODO: draw the shape so that it might have a hole in the center
165 165 QPainterPath path;
166 166 path.moveTo(rect.center());
167 167 path.arcTo(rect, -startAngle + 90, -angleSpan);
168 168 path.closeSubpath();
169 169
170 170 // calculate label arm start point
171 171 *armStart = center;
172 172 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
173 173
174 174 return path;
175 175 }
176 176
177 177 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
178 178 {
179 179 // prevent label arm pointing straight down because it will look bad
180 180 if (angle < 180 && angle > 170)
181 181 angle = 170;
182 182 if (angle > 180 && angle < 190)
183 183 angle = 190;
184 184
185 185 // line from slice to label
186 186 qreal dx = qSin(angle*(PI/180)) * length;
187 187 qreal dy = -qCos(angle*(PI/180)) * length;
188 188 QPointF parm1 = start + QPointF(dx, dy);
189 189
190 190 // line to underline the label
191 191 QPointF parm2 = parm1;
192 192 if (angle < 180) { // arm swings the other way on the left side
193 193 parm2 += QPointF(textWidth, 0);
194 194 *textStart = parm1;
195 195 }
196 196 else {
197 197 parm2 += QPointF(-textWidth,0);
198 198 *textStart = parm2;
199 199 }
200 200
201 201 // elevate the text position a bit so that it does not hit the line
202 202 *textStart += QPointF(0, -3);
203 203
204 204 QPainterPath path;
205 205 path.moveTo(start);
206 206 path.lineTo(parm1);
207 207 path.lineTo(parm2);
208 208
209 209 return path;
210 210 }
211 211
212 212 QRectF PieSliceItem::labelTextRect(QFont font, QString text)
213 213 {
214 214 QFontMetricsF fm(font);
215 215 return fm.boundingRect(text);
216 216 }
217 217
218 218 #include "moc_piesliceitem_p.cpp"
219 219
220 220 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,610 +1,604
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qpieseries.h"
22 22 #include "qpieseries_p.h"
23 23 #include "qpieslice.h"
24 #include "qpieslice_p.h"
24 25 #include "pieslicedata_p.h"
25 26 #include "chartdataset_p.h"
26 27 #include "charttheme_p.h"
27 28 #include "chartanimator_p.h"
28 29 #include "legendmarker_p.h"
29 30
30 31 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31 32
32 33 /*!
33 34 \class QPieSeries
34 35 \brief Pie series API for QtCommercial Charts
35 36
36 37 The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
37 38 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
38 39 The actual slice size is determined by that relative value.
39 40
40 41 Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0
41 42 These relate to the actual chart rectangle.
42 43
43 44 By default the pie is defined as a full pie but it can also be a partial pie.
44 45 This can be done by setting a starting angle and angle span to the series.
45 46 Full pie is 360 degrees where 0 is at 12 a'clock.
46 47
47 48 See the \l {PieChart Example} {pie chart example} to learn how to create a simple pie chart.
48 49 \image examples_piechart.png
49 50 */
50 51
51 52 /*!
52 53 \property QPieSeries::horizontalPosition
53 54 \brief Defines the horizontal position of the pie.
54 55
55 56 The value is a relative value to the chart rectangle where:
56 57
57 58 \list
58 59 \o 0.0 is the absolute left.
59 60 \o 1.0 is the absolute right.
60 61 \endlist
61 62
62 63 Default value is 0.5 (center).
63 64 */
64 65
65 66 /*!
66 67 \property QPieSeries::verticalPosition
67 68 \brief Defines the vertical position of the pie.
68 69
69 70 The value is a relative value to the chart rectangle where:
70 71
71 72 \list
72 73 \o 0.0 is the absolute top.
73 74 \o 1.0 is the absolute bottom.
74 75 \endlist
75 76
76 77 Default value is 0.5 (center).
77 78 */
78 79
79 80 /*!
80 81 \property QPieSeries::size
81 82 \brief Defines the pie size.
82 83
83 84 The value is a relative value to the chart rectangle where:
84 85
85 86 \list
86 87 \o 0.0 is the minimum size (pie not drawn).
87 88 \o 1.0 is the maximum size that can fit the chart.
88 89 \endlist
89 90
90 91 Default value is 0.7.
91 92 */
92 93
93 94 /*!
94 95 \property QPieSeries::startAngle
95 96 \brief Defines the starting angle of the pie.
96 97
97 98 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
98 99
99 100 Default is value is 0.
100 101 */
101 102
102 103 /*!
103 104 \property QPieSeries::endAngle
104 105 \brief Defines the ending angle of the pie.
105 106
106 107 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
107 108
108 109 Default is value is 360.
109 110 */
110 111
111 112 /*!
112 113 \property QPieSeries::count
113 114 \brief Number of slices in the series.
114 115
115 116 */
116 117
117 118 /*!
118 119 \property QPieSeries::sum
119 120 \brief Sum of all slices.
120 121
121 122 The series keeps track of the sum of all slices it holds.
122 123 */
123 124
124 125
125 126 /*!
126 127 Constructs a series object which is a child of \a parent.
127 128 */
128 129 QPieSeries::QPieSeries(QObject *parent) :
129 130 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
130 131 {
131 132
132 133 }
133 134
134 135 /*!
135 136 Destroys the series and its slices.
136 137 */
137 138 QPieSeries::~QPieSeries()
138 139 {
139 140 // NOTE: d_prt destroyed by QObject
140 141 }
141 142
142 143 /*!
143 144 Returns QChartSeries::SeriesTypePie.
144 145 */
145 146 QAbstractSeries::SeriesType QPieSeries::type() const
146 147 {
147 148 return QAbstractSeries::SeriesTypePie;
148 149 }
149 150
150 151 /*!
151 152 Appends an array of \a slices to the series.
152 153 Slice ownership is passed to the series.
153 154
154 155 Returns true if append was successfull.
155 156 */
156 157 bool QPieSeries::append(QList<QPieSlice*> slices)
157 158 {
158 159 Q_D(QPieSeries);
159 160
160 161 if (slices.count() == 0)
161 162 return false;
162 163
163 164 foreach (QPieSlice* s, slices) {
164 165 if (!s || d->m_slices.contains(s))
165 166 return false;
166 167 }
167 168
168 169 foreach (QPieSlice* s, slices) {
169 170 s->setParent(this);
170 171 d->m_slices << s;
171 172 }
172 173
173 174 d->updateDerivativeData();
174 175
175 176 foreach (QPieSlice* s, slices) {
176 connect(s, SIGNAL(valueChanged()), d, SLOT(sliceChanged()));
177 connect(s, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
177 178 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
178 179 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
179 180 }
180 181
181 182 emit added(slices);
182 183 emit countChanged();
183 184
184 185 return true;
185 186 }
186 187
187 188 /*!
188 189 Appends a single \a slice to the series.
189 190 Slice ownership is passed to the series.
190 191
191 192 Returns true if append was succesfull.
192 193 */
193 194 bool QPieSeries::append(QPieSlice* slice)
194 195 {
195 196 return append(QList<QPieSlice*>() << slice);
196 197 }
197 198
198 199 /*!
199 200 Appends a single \a slice to the series and returns a reference to the series.
200 201 Slice ownership is passed to the series.
201 202 */
202 203 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
203 204 {
204 205 append(slice);
205 206 return *this;
206 207 }
207 208
208 209
209 210 /*!
210 211 Appends a single slice to the series with give \a value and \a label.
211 212 Slice ownership is passed to the series.
212 213 */
213 214 QPieSlice* QPieSeries::append(QString label, qreal value)
214 215 {
215 216 QPieSlice* slice = new QPieSlice(label, value);
216 217 append(slice);
217 218 return slice;
218 219 }
219 220
220 221 /*!
221 222 Inserts a single \a slice to the series before the slice at \a index position.
222 223 Slice ownership is passed to the series.
223 224
224 225 Returns true if insert was successfull.
225 226 */
226 227 bool QPieSeries::insert(int index, QPieSlice* slice)
227 228 {
228 229 Q_D(QPieSeries);
229 230
230 231 if (index < 0 || index > d->m_slices.count())
231 232 return false;
232 233
233 234 if (!slice || d->m_slices.contains(slice))
234 235 return false;
235 236
236 237 slice->setParent(this);
237 238 d->m_slices.insert(index, slice);
238 239
239 240 d->updateDerivativeData();
240 241
241 connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceChanged()));
242 connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
242 243 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
243 244 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
244 245
245 246 emit added(QList<QPieSlice*>() << slice);
246 247 emit countChanged();
247 248
248 249 return true;
249 250 }
250 251
251 252 /*!
252 253 Removes a single \a slice from the series and deletes the slice.
253 254
254 255 Do not reference the pointer after this call.
255 256
256 257 Returns true if remove was successfull.
257 258 */
258 259 bool QPieSeries::remove(QPieSlice* slice)
259 260 {
260 261 Q_D(QPieSeries);
261 262
262 263 if (!d->m_slices.removeOne(slice))
263 264 return false;
264 265
265 266 d->updateDerivativeData();
266 267
267 268 emit removed(QList<QPieSlice*>() << slice);
268 269 emit countChanged();
269 270
270 271 delete slice;
271 272 slice = 0;
272 273
273 274 return true;
274 275 }
275 276
276 277 /*!
277 278 Clears all slices from the series.
278 279 */
279 280 void QPieSeries::clear()
280 281 {
281 282 Q_D(QPieSeries);
282 283 if (d->m_slices.count() == 0)
283 284 return;
284 285
285 286 QList<QPieSlice*> slices = d->m_slices;
286 287 foreach (QPieSlice* s, d->m_slices) {
287 288 d->m_slices.removeOne(s);
288 289 delete s;
289 290 }
290 291
291 292 d->updateDerivativeData();
292 293
293 294 emit removed(slices);
294 295 emit countChanged();
295 296 }
296 297
297 298 /*!
298 299 returns the number of the slices in this series.
299 300 */
300 301 int QPieSeries::count() const
301 302 {
302 303 Q_D(const QPieSeries);
303 304 return d->m_slices.count();
304 305 }
305 306
306 307 /*!
307 308 Returns true is the series is empty.
308 309 */
309 310 bool QPieSeries::isEmpty() const
310 311 {
311 312 Q_D(const QPieSeries);
312 313 return d->m_slices.isEmpty();
313 314 }
314 315
315 316 /*!
316 317 Returns a list of slices that belong to this series.
317 318 */
318 319 QList<QPieSlice*> QPieSeries::slices() const
319 320 {
320 321 Q_D(const QPieSeries);
321 322 return d->m_slices;
322 323 }
323 324
324 325 void QPieSeries::setHorizontalPosition(qreal relativePosition)
325 326 {
326 327 Q_D(QPieSeries);
327 328
328 329 if (relativePosition < 0.0)
329 330 relativePosition = 0.0;
330 331 if (relativePosition > 1.0)
331 332 relativePosition = 1.0;
332 333
333 334 if (!qFuzzyIsNull(d->m_pieRelativeHorPos - relativePosition)) {
334 335 d->m_pieRelativeHorPos = relativePosition;
335 336 emit horizontalPositionChanged();
336 337 }
337 338 }
338 339
339 340 void QPieSeries::setVerticalPosition(qreal relativePosition)
340 341 {
341 342 Q_D(QPieSeries);
342 343
343 344 if (relativePosition < 0.0)
344 345 relativePosition = 0.0;
345 346 if (relativePosition > 1.0)
346 347 relativePosition = 1.0;
347 348
348 349 if (!qFuzzyIsNull(d->m_pieRelativeVerPos - relativePosition)) {
349 350 d->m_pieRelativeVerPos = relativePosition;
350 351 emit verticalPositionChanged();
351 352 }
352 353 }
353 354
354 355 qreal QPieSeries::horizontalPosition() const
355 356 {
356 357 Q_D(const QPieSeries);
357 358 return d->m_pieRelativeHorPos;
358 359 }
359 360
360 361 qreal QPieSeries::verticalPosition() const
361 362 {
362 363 Q_D(const QPieSeries);
363 364 return d->m_pieRelativeVerPos;
364 365 }
365 366
366 367 void QPieSeries::setPieSize(qreal relativeSize)
367 368 {
368 369 Q_D(QPieSeries);
369 370
370 371 if (relativeSize < 0.0)
371 372 relativeSize = 0.0;
372 373 if (relativeSize > 1.0)
373 374 relativeSize = 1.0;
374 375
375 376 if (!qFuzzyIsNull(d->m_pieRelativeSize - relativeSize)) {
376 377 d->m_pieRelativeSize = relativeSize;
377 378 emit pieSizeChanged();
378 379 }
379 380 }
380 381
381 382 qreal QPieSeries::pieSize() const
382 383 {
383 384 Q_D(const QPieSeries);
384 385 return d->m_pieRelativeSize;
385 386 }
386 387
387 388
388 389 void QPieSeries::setPieStartAngle(qreal angle)
389 390 {
390 391 Q_D(QPieSeries);
391 392 if (qFuzzyIsNull(d->m_pieStartAngle - angle))
392 393 return;
393 394 d->m_pieStartAngle = angle;
394 395 d->updateDerivativeData();
395 396 emit pieStartAngleChanged();
396 397 }
397 398
398 399 qreal QPieSeries::pieStartAngle() const
399 400 {
400 401 Q_D(const QPieSeries);
401 402 return d->m_pieStartAngle;
402 403 }
403 404
404 405 /*!
405 406 Sets the end angle of the pie.
406 407
407 408 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
408 409
409 410 \a angle must be greater than start angle.
410 411
411 412 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
412 413 */
413 414 void QPieSeries::setPieEndAngle(qreal angle)
414 415 {
415 416 Q_D(QPieSeries);
416 417 if (qFuzzyIsNull(d->m_pieEndAngle - angle))
417 418 return;
418 419 d->m_pieEndAngle = angle;
419 420 d->updateDerivativeData();
420 421 emit pieEndAngleChanged();
421 422 }
422 423
423 424 /*!
424 425 Returns the end angle of the pie.
425 426
426 427 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
427 428
428 429 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
429 430 */
430 431 qreal QPieSeries::pieEndAngle() const
431 432 {
432 433 Q_D(const QPieSeries);
433 434 return d->m_pieEndAngle;
434 435 }
435 436
436 437 /*!
437 438 Sets the all the slice labels \a visible or invisible.
438 439
439 440 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
440 441 */
441 442 void QPieSeries::setLabelsVisible(bool visible)
442 443 {
443 444 Q_D(QPieSeries);
444 445 foreach (QPieSlice* s, d->m_slices)
445 446 s->setLabelVisible(visible);
446 447 }
447 448
448 449 /*!
449 450 Returns the sum of all slice values in this series.
450 451
451 452 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
452 453 */
453 454 qreal QPieSeries::sum() const
454 455 {
455 456 Q_D(const QPieSeries);
456 457 return d->m_sum;
457 458 }
458 459
459 460 /*!
460 461 \fn void QPieSeries::added(QList<QPieSlice*> slices)
461 462
462 463 This signal is emitted when \a slices have been added to the series.
463 464
464 465 \sa append(), insert()
465 466 */
466 467
467 468 /*!
468 469 \fn void QPieSeries::removed(QList<QPieSlice*> slices)
469 470
470 471 This signal is emitted when \a slices have been removed from the series.
471 472
472 473 \sa remove()
473 474 */
474 475
475 476 /*!
476 477 \fn void QPieSeries::clicked(QPieSlice* slice)
477 478
478 479 This signal is emitted when a \a slice has been clicked.
479 480
480 481 \sa QPieSlice::clicked()
481 482 */
482 483
483 484 /*!
484 485 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
485 486
486 487 This signal is emitted when user has hovered over or away from the \a slice.
487 488
488 489 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
489 490
490 491 \sa QPieSlice::hovered()
491 492 */
492 493
493 494
494 495
495 496 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
496 497
497 498
498 499 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
499 500 QAbstractSeriesPrivate(parent),
500 501 m_pieRelativeHorPos(0.5),
501 502 m_pieRelativeVerPos(0.5),
502 503 m_pieRelativeSize(0.7),
503 504 m_pieStartAngle(0),
504 505 m_pieEndAngle(360),
505 506 m_sum(0)
506 507 {
507 508 }
508 509
509 510 QPieSeriesPrivate::~QPieSeriesPrivate()
510 511 {
511 512 }
512 513
513 514 void QPieSeriesPrivate::updateDerivativeData()
514 515 {
515 516 // calculate sum of all slices
516 517 qreal sum = 0;
517 518 foreach (QPieSlice* s, m_slices)
518 519 sum += s->value();
519 520
520 521 if (!qFuzzyIsNull(m_sum - sum)) {
521 522 m_sum = sum;
522 523 emit q_func()->sumChanged();
523 524 }
524 525
525 526 // nothing to show..
526 527 if (qFuzzyIsNull(m_sum))
527 528 return;
528 529
529 530 // update slice attributes
530 531 qreal sliceAngle = m_pieStartAngle;
531 532 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
532 533 QVector<QPieSlice*> changed;
533 534 foreach (QPieSlice* s, m_slices) {
534
535 PieSliceData data = PieSliceData::fromSlice(s);
536 data.m_percentage = s->value() / m_sum;
537 data.m_angleSpan = pieSpan * data.m_percentage;
538 data.m_startAngle = sliceAngle;
539 sliceAngle += data.m_angleSpan;
540
541 if (PieSliceData::fromSlice(s) != data) {
542 PieSliceData::fromSlice(s) = data;
543 changed << s;
544 }
535 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
536 d->setPercentage(s->value() / m_sum);
537 d->setStartAngle(sliceAngle);
538 d->setAngleSpan(pieSpan * s->percentage());
539 sliceAngle += s->angleSpan();
545 540 }
546 541
547 // emit signals
548 foreach (QPieSlice* s, changed)
549 PieSliceData::emitCalculatedDataChanged(s);
542
543 emit calculatedDataChanged();
550 544 }
551 545
552 QPieSeriesPrivate* QPieSeriesPrivate::seriesData(QPieSeries &series)
546 QPieSeriesPrivate* QPieSeriesPrivate::fromSeries(QPieSeries *series)
553 547 {
554 return series.d_func();
548 return series->d_func();
555 549 }
556 550
557 void QPieSeriesPrivate::sliceChanged()
551 void QPieSeriesPrivate::sliceValueChanged()
558 552 {
559 553 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
560 554 updateDerivativeData();
561 555 }
562 556
563 557 void QPieSeriesPrivate::sliceClicked()
564 558 {
565 559 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
566 560 Q_ASSERT(m_slices.contains(slice));
567 561 Q_Q(QPieSeries);
568 562 emit q->clicked(slice);
569 563 }
570 564
571 565 void QPieSeriesPrivate::sliceHovered(bool state)
572 566 {
573 567 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
574 568 Q_ASSERT(m_slices.contains(slice));
575 569 Q_Q(QPieSeries);
576 570 emit q->hovered(slice, state);
577 571 }
578 572
579 573 void QPieSeriesPrivate::scaleDomain(Domain& domain)
580 574 {
581 575 Q_UNUSED(domain);
582 576 // does not apply to pie
583 577 }
584 578
585 579 Chart* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
586 580 {
587 581 Q_Q(QPieSeries);
588 582 PieChartItem* pie = new PieChartItem(q,presenter);
589 583 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
590 584 presenter->animator()->addAnimation(pie);
591 585 }
592 586 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
593 587 return pie;
594 588 }
595 589
596 590 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
597 591 {
598 592 Q_Q(QPieSeries);
599 593 QList<LegendMarker*> markers;
600 594 foreach(QPieSlice* slice, q->slices()) {
601 595 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
602 596 markers << marker;
603 597 }
604 598 return markers;
605 599 }
606 600
607 601 #include "moc_qpieseries.cpp"
608 602 #include "moc_qpieseries_p.cpp"
609 603
610 604 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,67 +1,70
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef QPIESERIES_P_H
22 22 #define QPIESERIES_P_H
23 23
24 24 #include "qpieseries.h"
25 25 #include "qabstractseries_p.h"
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28 class QLegendPrivate;
29 29
30 30 class QPieSeriesPrivate : public QAbstractSeriesPrivate
31 31 {
32 32 Q_OBJECT
33 33
34 34 public:
35 35 QPieSeriesPrivate(QPieSeries *parent);
36 36 ~QPieSeriesPrivate();
37 37
38 38 void scaleDomain(Domain& domain);
39 39 Chart* createGraphics(ChartPresenter *presenter);
40 40 QList<LegendMarker*> createLegendMarker(QLegend *legend);
41 41
42 42 void updateDerivativeData();
43 43
44 static QPieSeriesPrivate* seriesData(QPieSeries &series);
44 static QPieSeriesPrivate* fromSeries(QPieSeries *series);
45
46 signals:
47 void calculatedDataChanged();
45 48
46 49 public Q_SLOTS:
47 void sliceChanged();
50 void sliceValueChanged();
48 51 void sliceClicked();
49 52 void sliceHovered(bool state);
50 53
51 public:
54 private:
52 55 QList<QPieSlice*> m_slices;
53 56 qreal m_pieRelativeHorPos;
54 57 qreal m_pieRelativeVerPos;
55 58 qreal m_pieRelativeSize;
56 59 qreal m_pieStartAngle;
57 60 qreal m_pieEndAngle;
58 61 qreal m_sum;
59 62
60 63 private:
61 64 friend class QLegendPrivate;
62 65 Q_DECLARE_PUBLIC(QPieSeries)
63 66 };
64 67
65 68 QTCOMMERCIALCHART_END_NAMESPACE
66 69
67 70 #endif // QPIESERIES_P_H
@@ -1,436 +1,498
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qpieslice.h"
22 #include "pieslicedata_p.h"
22 #include "qpieslice_p.h"
23 23
24 24 QTCOMMERCIALCHART_BEGIN_NAMESPACE
25 25
26 26 /*!
27 27 \class QPieSlice
28 28 \brief Defines a slice in pie series.
29 29
30 30 This object defines the properties of a single slice in a QPieSeries.
31 31
32 32 In addition to the obvious value and label properties the user can also control
33 33 the visual appearance of a slice. By modifying the visual appearance also means that
34 34 the user is overriding the default appearance set by the theme. Even if the theme is
35 35 changed users settings will persist.
36 36
37 37 To enable user interaction customization with the slices some basic signals
38 38 are provided about clicking and hovering.
39 39 */
40 40
41 41 /*!
42 42 \property QPieSlice::label
43 43
44 44 Label of the slice.
45 45 */
46 46
47 47 /*!
48 48 \property QPieSlice::value
49 49
50 50 Value of the slice.
51 51
52 52 \sa percentage(), QPieSeries::sum()
53 53 */
54 54
55 55 /*!
56 56 Constructs an empty slice with a \a parent.
57 57
58 58 \sa QPieSeries::append(), QPieSeries::insert()
59 59 */
60 60 QPieSlice::QPieSlice(QObject *parent)
61 61 :QObject(parent),
62 d(new PieSliceData())
62 d_ptr(new QPieSlicePrivate(this))
63 63 {
64 64
65 65 }
66 66
67 67 /*!
68 68 Constructs an empty slice with given \a value, \a label and a \a parent.
69 69 \sa QPieSeries::append(), QPieSeries::insert()
70 70 */
71 71 QPieSlice::QPieSlice(QString label, qreal value, QObject *parent)
72 72 :QObject(parent),
73 d(new PieSliceData())
73 d_ptr(new QPieSlicePrivate(this))
74 74 {
75 d->m_value = value;
76 d->m_labelText = label;
75 d_ptr->m_data.m_value = value;
76 d_ptr->m_data.m_labelText = label;
77 77 }
78 78
79 79 /*!
80 80 Destroys the slice.
81 81 User should not delete the slice if it has been added to the series.
82 82 */
83 83 QPieSlice::~QPieSlice()
84 84 {
85 delete d;
85
86 86 }
87 87
88 88 /*!
89 89 Gets the value of the slice.
90 90 Note that all values in the series
91 91 \sa setValue()
92 92 */
93 93 qreal QPieSlice::value() const
94 94 {
95 return d->m_value;
95 return d_ptr->m_data.m_value;
96 96 }
97 97
98 98 /*!
99 99 Gets the label of the slice.
100 100 \sa setLabel()
101 101 */
102 102 QString QPieSlice::label() const
103 103 {
104 return d->m_labelText;
104 return d_ptr->m_data.m_labelText;
105 105 }
106 106
107 107 /*!
108 108 Returns true if label is set as visible.
109 109 \sa setLabelVisible()
110 110 */
111 111 bool QPieSlice::isLabelVisible() const
112 112 {
113 return d->m_isLabelVisible;
113 return d_ptr->m_data.m_isLabelVisible;
114 114 }
115 115
116 116 /*!
117 117 Returns true if slice is exloded from the pie.
118 118 \sa setExploded(), explodeDistanceFactor(), setExplodeDistanceFactor()
119 119 */
120 120 bool QPieSlice::isExploded() const
121 121 {
122 return d->m_isExploded;
122 return d_ptr->m_data.m_isExploded;
123 123 }
124 124
125 125 /*!
126 126 Returns the explode distance factor.
127 127
128 128 The factor is relative to pie radius. For example:
129 129 1.0 means the distance is the same as the radius.
130 130 0.5 means the distance is half of the radius.
131 131
132 132 Default value is 0.15.
133 133
134 134 \sa setExplodeDistanceFactor(), isExploded(), setExploded()
135 135 */
136 136 qreal QPieSlice::explodeDistanceFactor() const
137 137 {
138 return d->m_explodeDistanceFactor;
138 return d_ptr->m_data.m_explodeDistanceFactor;
139 139 }
140 140
141 141 /*!
142 142 Returns the percentage of this slice compared to the sum of all slices in the same series.
143 143 The returned value ranges from 0 to 1.0.
144 144
145 145 Updated internally after the slice is added to the series.
146 146
147 147 \sa QPieSeries::sum()
148 148 */
149 149 qreal QPieSlice::percentage() const
150 150 {
151 return d->m_percentage;
151 return d_ptr->m_data.m_percentage;
152 152 }
153 153
154 154 /*!
155 155 Returns the starting angle of this slice in the series it belongs to.
156 156
157 157 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
158 158
159 159 Updated internally after the slice is added to the series.
160 160 */
161 161 qreal QPieSlice::startAngle() const
162 162 {
163 return d->m_startAngle;
163 return d_ptr->m_data.m_startAngle;
164 164 }
165 165
166 166 /*!
167 167 Returns the end angle of this slice in the series it belongs to.
168 168
169 169 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
170 170
171 171 Updated internally after the slice is added to the series.
172 172 */
173 qreal QPieSlice::endAngle() const
173 qreal QPieSlice::angleSpan() const
174 174 {
175 return d->m_startAngle + d->m_angleSpan;
175 return d_ptr->m_data.m_angleSpan;
176 176 }
177 177
178 178 /*!
179 179 Returns the pen used to draw this slice.
180 180 \sa setPen()
181 181 */
182 182 QPen QPieSlice::pen() const
183 183 {
184 return d->m_slicePen;
184 return d_ptr->m_data.m_slicePen;
185 185 }
186 186
187 187 /*!
188 188 Returns the brush used to draw this slice.
189 189 \sa setBrush()
190 190 */
191 191 QBrush QPieSlice::brush() const
192 192 {
193 return d->m_sliceBrush;
193 return d_ptr->m_data.m_sliceBrush;
194 194 }
195 195
196 196 /*!
197 197 Returns the pen used to draw the label in this slice.
198 198 \sa setLabelPen()
199 199 */
200 200 QPen QPieSlice::labelPen() const
201 201 {
202 return d->m_labelPen;
202 return d_ptr->m_data.m_labelPen;
203 203 }
204 204
205 205 /*!
206 206 Returns the font used to draw label in this slice.
207 207 \sa setLabelFont()
208 208 */
209 209 QFont QPieSlice::labelFont() const
210 210 {
211 return d->m_labelFont;
211 return d_ptr->m_data.m_labelFont;
212 212 }
213 213
214 214 /*!
215 215 Gets the label arm length factor.
216 216
217 217 The factor is relative to pie radius. For example:
218 218 1.0 means the length is the same as the radius.
219 219 0.5 means the length is half of the radius.
220 220
221 221 Default value is 0.15
222 222
223 223 \sa setLabelArmLengthFactor()
224 224 */
225 225 qreal QPieSlice::labelArmLengthFactor() const
226 226 {
227 return d->m_labelArmLengthFactor;
227 return d_ptr->m_data.m_labelArmLengthFactor;
228 228 }
229 229
230 230 /*!
231 231 \fn void QPieSlice::labelChanged()
232 232
233 233 This signal is emitted when the slice label changes.
234 234
235 235 \sa setLabel()
236 236 */
237 237
238 238 /*!
239 239 \fn void QPieSlice::valueChanged()
240 240
241 241 This signal is emitted when the slice value changes.
242 242
243 243 \sa setValue()
244 244 */
245 245
246 246 /*!
247 247 \fn void QPieSlice::appearanceChanged()
248 248
249 249 This signal is emitted when visual appearance of the slice changes.
250 250
251 251 \sa setPen(), setBrush(), setLabelVisible(), setExploded()
252 252 */
253 253
254 254 /*!
255 255 \fn void QPieSlice::calculatedDataChanged()
256 256
257 257 This signal is emitted when calculated data for this slice changes.
258 258
259 259 \sa percentage(), startAngle(), endAngle()
260 260 */
261 261
262 262 /*!
263 263 \fn void QPieSlice::clicked()
264 264
265 265 This signal is emitted when user has clicked the slice.
266 266
267 267 \sa QPieSeries::clicked()
268 268 */
269 269
270 270 /*!
271 271 \fn void QPieSlice::hovered(bool state)
272 272
273 273 This signal is emitted when user has hovered over or away from the slice.
274 274
275 275 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
276 276
277 277 \sa QPieSeries::hovered()
278 278 */
279 279
280 280 /*!
281 281 Sets the \a value of this slice.
282 282 \sa value()
283 283 */
284 284 void QPieSlice::setValue(qreal value)
285 285 {
286 if (!qFuzzyIsNull(d->m_value - value)) {
287 d->m_value = value;
286 if (!qFuzzyIsNull(d_ptr->m_data.m_value - value)) {
287 d_ptr->m_data.m_value = value;
288 288 emit valueChanged();
289 289 }
290 290 }
291 291
292 292 /*!
293 293 Sets the \a label of the slice.
294 294 \sa label()
295 295 */
296 296 void QPieSlice::setLabel(QString label)
297 297 {
298 if (d->m_labelText != label) {
299 d->m_labelText = label;
298 if (d_ptr->m_data.m_labelText != label) {
299 d_ptr->m_data.m_labelText = label;
300 300 emit labelChanged();
301 301 }
302 302 }
303 303
304 304 /*!
305 305 Sets the label \a visible in this slice.
306 306 \sa isLabelVisible(), QPieSeries::setLabelsVisible()
307 307 */
308 308 void QPieSlice::setLabelVisible(bool visible)
309 309 {
310 if (d->m_isLabelVisible != visible) {
311 d->m_isLabelVisible = visible;
312 emit appearanceChanged();
310 if (d_ptr->m_data.m_isLabelVisible != visible) {
311 d_ptr->m_data.m_isLabelVisible = visible;
312 emit labelVisibleChanged();
313 313 }
314 314 }
315 315
316 316 /*!
317 317 Sets this slices \a exploded state.
318 318
319 319 If the slice is exploded it is moved away from the pie center. The distance is defined by the explode distance factor.
320 320
321 321 \sa isExploded(), explodeDistanceFactor(), setExplodeDistanceFactor()
322 322 */
323 323 void QPieSlice::setExploded(bool exploded)
324 324 {
325 if (d->m_isExploded != exploded) {
326 d->m_isExploded = exploded;
327 emit appearanceChanged();
325 if (d_ptr->m_data.m_isExploded != exploded) {
326 d_ptr->m_data.m_isExploded = exploded;
327 emit explodedChanged();
328 328 }
329 329 }
330 330
331 331 /*!
332 332 Sets the explode distance \a factor.
333 333
334 334 The factor is relative to pie radius. For example:
335 335 1.0 means the distance is the same as the radius.
336 336 0.5 means the distance is half of the radius.
337 337
338 338 Default value is 0.15
339 339
340 340 \sa explodeDistanceFactor(), isExploded(), setExploded()
341 341 */
342 342 void QPieSlice::setExplodeDistanceFactor(qreal factor)
343 343 {
344 if (!qFuzzyIsNull(d->m_explodeDistanceFactor - factor)) {
345 d->m_explodeDistanceFactor = factor;
346 emit appearanceChanged();
344 if (!qFuzzyIsNull(d_ptr->m_data.m_explodeDistanceFactor - factor)) {
345 d_ptr->m_data.m_explodeDistanceFactor = factor;
346 emit explodeDistanceFactorChanged();
347 347 }
348 348 }
349 349
350 350 /*!
351 351 Sets the \a pen used to draw this slice.
352 352
353 353 Overrides the pen set by the theme.
354 354
355 355 \sa pen()
356 356 */
357 357 void QPieSlice::setPen(const QPen &pen)
358 358 {
359 if (d->m_slicePen != pen) {
360 d->m_slicePen = pen;
361 d->m_slicePen.setThemed(false);
362 emit appearanceChanged();
363 }
359 d_ptr->setPen(pen, false);
364 360 }
365 361
366 362 /*!
367 363 Sets the \a brush used to draw this slice.
368 364
369 365 Overrides the brush set by the theme.
370 366
371 367 \sa brush()
372 368 */
373 369 void QPieSlice::setBrush(const QBrush &brush)
374 370 {
375 if (d->m_sliceBrush != brush) {
376 d->m_sliceBrush = brush;
377 d->m_sliceBrush.setThemed(false);
378 emit appearanceChanged();
379 }
371 d_ptr->setBrush(brush, false);
380 372 }
381 373
382 374 /*!
383 375 Sets the \a pen used to draw the label in this slice.
384 376
385 377 Overrides the pen set by the theme.
386 378
387 379 \sa labelPen()
388 380 */
389 381 void QPieSlice::setLabelPen(const QPen &pen)
390 382 {
391 if (d->m_labelPen != pen) {
392 d->m_labelPen = pen;
393 d->m_labelPen.setThemed(false);
394 emit appearanceChanged();
395 }
383 d_ptr->setLabelPen(pen, false);
396 384 }
397 385
398 386 /*!
399 387 Sets the \a font used to draw the label in this slice.
400 388
401 389 Overrides the font set by the theme.
402 390
403 391 \sa labelFont()
404 392 */
405 393 void QPieSlice::setLabelFont(const QFont &font)
406 394 {
407 if (d->m_labelFont != font) {
408 d->m_labelFont = font;
409 d->m_labelFont.setThemed(false);
410 emit appearanceChanged();
411 }
395 d_ptr->setLabelFont(font, false);
412 396 }
413 397
414 398 /*!
415 399 Sets the label arm length \a factor.
416 400
417 401 The factor is relative to pie radius. For example:
418 402 1.0 means the length is the same as the radius.
419 403 0.5 means the length is half of the radius.
420 404
421 405 Default value is 0.15
422 406
423 407 \sa labelArmLengthFactor()
424 408 */
425 409 void QPieSlice::setLabelArmLengthFactor(qreal factor)
426 410 {
427 if (!qFuzzyIsNull(d->m_labelArmLengthFactor - factor)) {
428 d->m_labelArmLengthFactor = factor;
429 emit appearanceChanged();
411 if (!qFuzzyIsNull(d_ptr->m_data.m_labelArmLengthFactor - factor)) {
412 d_ptr->m_data.m_labelArmLengthFactor = factor;
413 emit labelArmLengthFactorChanged();
414 }
415 }
416
417 QPieSlicePrivate::QPieSlicePrivate(QPieSlice *parent)
418 :QObject(parent),
419 q_ptr(parent)
420 {
421
422 }
423
424 QPieSlicePrivate::~QPieSlicePrivate()
425 {
426
427 }
428
429 QPieSlicePrivate *QPieSlicePrivate::fromSlice(QPieSlice *slice)
430 {
431 return slice->d_func();
432 }
433
434 void QPieSlicePrivate::setPen(const QPen &pen, bool themed)
435 {
436 if (m_data.m_slicePen != pen) {
437 m_data.m_slicePen = pen;
438 m_data.m_slicePen.setThemed(themed);
439 emit q_ptr->penChanged();
440 }
441 }
442
443 void QPieSlicePrivate::setBrush(const QBrush &brush, bool themed)
444 {
445 if (m_data.m_sliceBrush != brush) {
446 m_data.m_sliceBrush = brush;
447 m_data.m_sliceBrush.setThemed(themed);
448 emit q_ptr->brushChanged();
449 }
450 }
451
452 void QPieSlicePrivate::setLabelPen(const QPen &pen, bool themed)
453 {
454 if (m_data.m_labelPen != pen) {
455 m_data.m_labelPen = pen;
456 m_data.m_labelPen.setThemed(themed);
457 emit q_ptr->labelPenChanged();
458 }
459 }
460
461 void QPieSlicePrivate::setLabelFont(const QFont &font, bool themed)
462 {
463 if (m_data.m_labelFont != font) {
464 m_data.m_labelFont = font;
465 m_data.m_labelFont.setThemed(themed);
466 emit q_ptr->labelFontChanged();
467 }
468 }
469
470 void QPieSlicePrivate::setPercentage(qreal percentage)
471 {
472 if (!qFuzzyIsNull(m_data.m_percentage - percentage)) {
473 m_data.m_percentage = percentage;
474 emit q_ptr->percentageChanged();
475 }
476 }
477
478 void QPieSlicePrivate::setStartAngle(qreal angle)
479 {
480 if (!qFuzzyIsNull(m_data.m_startAngle - angle)) {
481 m_data.m_startAngle = angle;
482 emit q_ptr->startAngleChanged();
483 }
484 }
485
486 void QPieSlicePrivate::setAngleSpan(qreal span)
487 {
488 if (!qFuzzyIsNull(m_data.m_angleSpan - span)) {
489 m_data.m_angleSpan = span;
490 emit q_ptr->angleSpanChanged();
430 491 }
431 492 }
432 493
433 494 QTCOMMERCIALCHART_END_NAMESPACE
434 495
435 496 QTCOMMERCIALCHART_USE_NAMESPACE
436 497 #include "moc_qpieslice.cpp"
498 #include "moc_qpieslice_p.cpp"
@@ -1,101 +1,114
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #ifndef QPIESLICE_H
22 22 #define QPIESLICE_H
23 23
24 24 #include <qchartglobal.h>
25 25 #include <QObject>
26 26 #include <QPen>
27 27 #include <QBrush>
28 28 #include <QFont>
29 29
30 30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31 class PieSliceData;
31 class QPieSlicePrivate;
32 32
33 33 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
34 34 {
35 35 Q_OBJECT
36 36 Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged)
37 37 Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)
38 Q_PROPERTY(bool labelVisible READ isLabelVisible WRITE setLabelVisible)
39 Q_PROPERTY(bool exploded READ isExploded WRITE setExploded)
38 Q_PROPERTY(bool labelVisible READ isLabelVisible WRITE setLabelVisible NOTIFY labelVisibleChanged)
39 Q_PROPERTY(bool exploded READ isExploded WRITE setExploded NOTIFY explodedChanged)
40 Q_PROPERTY(QPen pen READ pen WRITE setPen NOTIFY penChanged)
41 Q_PROPERTY(QBrush brush READ brush WRITE setBrush NOTIFY brushChanged)
42 Q_PROPERTY(QPen labelPen READ labelPen WRITE setLabelPen NOTIFY labelPenChanged)
43 Q_PROPERTY(QFont labelFont READ labelFont WRITE setLabelFont NOTIFY labelFontChanged)
40 44 Q_PROPERTY(qreal LabelArmLengthFactor READ labelArmLengthFactor WRITE setLabelArmLengthFactor)
41 45 Q_PROPERTY(qreal explodeDistanceFactor READ explodeDistanceFactor WRITE setExplodeDistanceFactor)
42 Q_PROPERTY(qreal percentage READ percentage NOTIFY calculatedDataChanged)
43 Q_PROPERTY(qreal startAngle READ startAngle NOTIFY calculatedDataChanged)
44 Q_PROPERTY(qreal endAngle READ endAngle NOTIFY calculatedDataChanged)
46 Q_PROPERTY(qreal percentage READ percentage NOTIFY percentageChanged)
47 Q_PROPERTY(qreal startAngle READ startAngle NOTIFY startAngleChanged)
48 Q_PROPERTY(qreal angleSpan READ angleSpan NOTIFY angleSpanChanged)
45 49
46 50 public:
47 51 explicit QPieSlice(QObject *parent = 0);
48 52 QPieSlice(QString label, qreal value, QObject *parent = 0);
49 53 virtual ~QPieSlice();
50 54
51 55 void setLabel(QString label);
52 56 QString label() const;
53 57
54 58 void setValue(qreal value);
55 59 qreal value() const;
56 60
61 void setLabelVisible(bool visible = true);
62 bool isLabelVisible() const;
63
64 void setExploded(bool exploded = true);
65 bool isExploded() const;
66
57 67 void setPen(const QPen &pen);
58 68 QPen pen() const;
59 69
60 70 void setBrush(const QBrush &brush);
61 71 QBrush brush() const;
62 72
63 void setLabelVisible(bool visible = true);
64 bool isLabelVisible() const;
65
66 void setLabelArmLengthFactor(qreal factor);
67 qreal labelArmLengthFactor() const;
68
69 73 void setLabelPen(const QPen &pen);
70 74 QPen labelPen() const;
71 75
72 76 void setLabelFont(const QFont &font);
73 77 QFont labelFont() const;
74 78
75 void setExploded(bool exploded = true);
76 bool isExploded() const;
79 void setLabelArmLengthFactor(qreal factor);
80 qreal labelArmLengthFactor() const;
77 81
78 82 void setExplodeDistanceFactor(qreal factor);
79 83 qreal explodeDistanceFactor() const;
80 84
81 85 qreal percentage() const;
82 86 qreal startAngle() const;
83 qreal endAngle() const;
87 qreal angleSpan() const;
84 88
85 89 Q_SIGNALS:
86 90 void labelChanged();
87 91 void valueChanged();
88 void appearanceChanged();
89 void calculatedDataChanged();
92 void labelVisibleChanged();
93 void explodedChanged();
94 void penChanged();
95 void brushChanged();
96 void labelPenChanged();
97 void labelFontChanged();
98 void labelArmLengthFactorChanged();
99 void explodeDistanceFactorChanged();
100 void percentageChanged();
101 void startAngleChanged();
102 void angleSpanChanged();
90 103 void clicked();
91 104 void hovered(bool state);
92 105
93 106 private:
94 friend class PieSliceData;
95 PieSliceData * const d;
107 QPieSlicePrivate * const d_ptr;
108 Q_DECLARE_PRIVATE(QPieSlice)
96 109 Q_DISABLE_COPY(QPieSlice)
97 110 };
98 111
99 112 QTCOMMERCIALCHART_END_NAMESPACE
100 113
101 114 #endif // QPIESLICE_H
@@ -1,457 +1,472
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include <QtTest/QtTest>
22 22 #include <qchartview.h>
23 23 #include <qchart.h>
24 24 #include <qpieseries.h>
25 25 #include <qpieslice.h>
26 26 #include <qpiemodelmapper.h>
27 27 #include <QStandardItemModel>
28 28 #include <tst_definitions.h>
29 29
30 30 QTCOMMERCIALCHART_USE_NAMESPACE
31 31
32 32 Q_DECLARE_METATYPE(QPieSlice*)
33 33
34 34 class tst_qpieseries : public QObject
35 35 {
36 36 Q_OBJECT
37 37
38 38 public slots:
39 39 void initTestCase();
40 40 void cleanupTestCase();
41 41 void init();
42 42 void cleanup();
43 43
44 44 private slots:
45 45 void properties();
46 46 void append();
47 47 void insert();
48 48 void remove();
49 49 void calculatedValues();
50 50 void clickedSignal();
51 51 void hoverSignal();
52 52
53 53 private:
54 54 void verifyCalculatedData(const QPieSeries &series, bool *ok);
55 55
56 56 private:
57 57
58 58 };
59 59
60 60 void tst_qpieseries::initTestCase()
61 61 {
62 62 qRegisterMetaType<QPieSlice*>("QPieSlice*");
63 63 }
64 64
65 65 void tst_qpieseries::cleanupTestCase()
66 66 {
67 67 }
68 68
69 69 void tst_qpieseries::init()
70 70 {
71 71
72 72 }
73 73
74 74 void tst_qpieseries::cleanup()
75 75 {
76 76
77 77 }
78 78
79 79 void tst_qpieseries::properties()
80 80 {
81 81 QPieSeries s;
82 82
83 83 QSignalSpy countSpy(&s, SIGNAL(countChanged()));
84 84 QSignalSpy sumSpy(&s, SIGNAL(sumChanged()));
85 85 QSignalSpy sizeSpy(&s, SIGNAL(pieSizeChanged()));
86 86 QSignalSpy startAngleSpy(&s, SIGNAL(pieStartAngleChanged()));
87 87 QSignalSpy endAngleSpy(&s, SIGNAL(pieEndAngleChanged()));
88 88 QSignalSpy horPosSpy(&s, SIGNAL(horizontalPositionChanged()));
89 89 QSignalSpy verPosSpy(&s, SIGNAL(verticalPositionChanged()));
90 90
91 91 QVERIFY(s.type() == QAbstractSeries::SeriesTypePie);
92 92 QVERIFY(s.count() == 0);
93 93 QVERIFY(s.isEmpty());
94 94 QCOMPARE(s.sum(), 0.0);
95 95 QCOMPARE(s.horizontalPosition(), 0.5);
96 96 QCOMPARE(s.verticalPosition(), 0.5);
97 97 QCOMPARE(s.pieSize(), 0.7);
98 98 QCOMPARE(s.pieStartAngle(), 0.0);
99 99 QCOMPARE(s.pieEndAngle(), 360.0);
100 100
101 101 s.append("s1", 1);
102 102 s.append("s2", 1);
103 103 s.append("s3", 1);
104 104 s.insert(1, new QPieSlice("s4", 1));
105 105 s.remove(s.slices().first());
106 106 QCOMPARE(s.count(), 3);
107 107 QCOMPARE(s.sum(), 3.0);
108 108 s.clear();
109 109 QCOMPARE(s.count(), 0);
110 110 QCOMPARE(s.sum(), 0.0);
111 111 QCOMPARE(countSpy.count(), 6);
112 112 QCOMPARE(sumSpy.count(), 6);
113 113
114 114 s.setPieSize(-1.0);
115 115 QCOMPARE(s.pieSize(), 0.0);
116 116 s.setPieSize(0.0);
117 117 s.setPieSize(0.9);
118 118 s.setPieSize(2.0);
119 119 QCOMPARE(s.pieSize(), 1.0);
120 120 QCOMPARE(sizeSpy.count(), 3);
121 121
122 122 s.setPieStartAngle(0);
123 123 s.setPieStartAngle(-180);
124 124 s.setPieStartAngle(180);
125 125 QCOMPARE(startAngleSpy.count(), 2);
126 126
127 127 s.setPieEndAngle(360);
128 128 s.setPieEndAngle(-180);
129 129 s.setPieEndAngle(180);
130 130 QCOMPARE(endAngleSpy.count(), 2);
131 131
132 132 s.setHorizontalPosition(0.5);
133 133 s.setHorizontalPosition(-1.0);
134 134 QCOMPARE(s.horizontalPosition(), 0.0);
135 135 s.setHorizontalPosition(1.0);
136 136 s.setHorizontalPosition(2.0);
137 137 QCOMPARE(s.horizontalPosition(), 1.0);
138 138 QCOMPARE(horPosSpy.count(), 2);
139 139
140 140 s.setVerticalPosition(0.5);
141 141 s.setVerticalPosition(-1.0);
142 142 QCOMPARE(s.verticalPosition(), 0.0);
143 143 s.setVerticalPosition(1.0);
144 144 s.setVerticalPosition(2.0);
145 145 QCOMPARE(s.verticalPosition(), 1.0);
146 146 QCOMPARE(verPosSpy.count(), 2);
147 147 }
148 148
149 149 void tst_qpieseries::append()
150 150 {
151 151 QPieSeries s;
152 152
153 153 // append pointer
154 154 QPieSlice *slice1 = 0;
155 155 QVERIFY(!s.append(slice1));
156 156 slice1 = new QPieSlice("slice 1", 1);
157 157 QVERIFY(s.append(slice1));
158 158 QVERIFY(!s.append(slice1));
159 159 QCOMPARE(s.count(), 1);
160 160
161 161 // append pointer list
162 162 QList<QPieSlice *> list;
163 163 QVERIFY(!s.append(list));
164 164 list << (QPieSlice *) 0;
165 165 QVERIFY(!s.append(list));
166 166 list.clear();
167 167 list << new QPieSlice("slice 2", 2);
168 168 list << new QPieSlice("slice 3", 3);
169 169 QVERIFY(s.append(list));
170 170 QVERIFY(!s.append(list));
171 171 QCOMPARE(s.count(), 3);
172 172
173 173 // append operator
174 174 s << new QPieSlice("slice 4", 4);
175 175 s << slice1; // fails because already added
176 176 QCOMPARE(s.count(), 4);
177 177
178 178 // append with params
179 179 QPieSlice *slice5 = s.append("slice 5", 5);
180 180 QVERIFY(slice5 != 0);
181 181 QCOMPARE(slice5->value(), 5.0);
182 182 QCOMPARE(slice5->label(), QString("slice 5"));
183 183 QCOMPARE(s.count(), 5);
184 184
185 185 // check slices
186 186 QVERIFY(!s.isEmpty());
187 187 for (int i=0; i<s.count(); i++) {
188 188 QCOMPARE(s.slices().at(i)->value(), (qreal) i+1);
189 189 QCOMPARE(s.slices().at(i)->label(), QString("slice ") + QString::number(i+1));
190 190 }
191 191 }
192 192
193 193 void tst_qpieseries::insert()
194 194 {
195 195 QPieSeries s;
196 196
197 197 // insert one slice
198 198 QPieSlice *slice1 = 0;
199 199 QVERIFY(!s.insert(0, slice1));
200 200 slice1 = new QPieSlice("slice 1", 1);
201 201 QVERIFY(!s.insert(-1, slice1));
202 202 QVERIFY(!s.insert(5, slice1));
203 203 QVERIFY(s.insert(0, slice1));
204 204 QVERIFY(!s.insert(0, slice1));
205 205 QCOMPARE(s.count(), 1);
206 206
207 207 // add some more slices
208 208 s.append("slice 2", 2);
209 209 s.append("slice 4", 4);
210 210 QCOMPARE(s.count(), 3);
211 211
212 212 // insert between slices
213 213 s.insert(2, new QPieSlice("slice 3", 3));
214 214 QCOMPARE(s.count(), 4);
215 215
216 216 // check slices
217 217 for (int i=0; i<s.count(); i++) {
218 218 QCOMPARE(s.slices().at(i)->value(), (qreal) i+1);
219 219 QCOMPARE(s.slices().at(i)->label(), QString("slice ") + QString::number(i+1));
220 220 }
221 221 }
222 222
223 223 void tst_qpieseries::remove()
224 224 {
225 225 QPieSeries s;
226 226
227 227 // add some slices
228 228 QPieSlice *slice1 = s.append("slice 1", 1);
229 229 QPieSlice *slice2 = s.append("slice 2", 2);
230 230 QPieSlice *slice3 = s.append("slice 3", 3);
231 231 QSignalSpy spy1(slice1, SIGNAL(destroyed()));
232 232 QSignalSpy spy2(slice2, SIGNAL(destroyed()));
233 233 QSignalSpy spy3(slice3, SIGNAL(destroyed()));
234 234 QCOMPARE(s.count(), 3);
235 235
236 236 // null pointer remove
237 237 QVERIFY(!s.remove(0));
238 238
239 239 // remove first
240 240 QVERIFY(s.remove(slice1));
241 241 QVERIFY(!s.remove(slice1));
242 242 QCOMPARE(s.count(), 2);
243 243 QCOMPARE(s.slices().at(0)->label(), slice2->label());
244 244
245 245 // remove all
246 246 s.clear();
247 247 QVERIFY(s.isEmpty());
248 248 QVERIFY(s.slices().isEmpty());
249 249 QCOMPARE(s.count(), 0);
250 250
251 251 // check that slices were actually destroyed
252 252 TRY_COMPARE(spy1.count(), 1);
253 253 TRY_COMPARE(spy2.count(), 1);
254 254 TRY_COMPARE(spy3.count(), 1);
255 255 }
256 256
257 257 void tst_qpieseries::calculatedValues()
258 258 {
259 259 bool ok;
260 260 QPieSeries s;
261 261
262 262 QPieSlice *slice1 = new QPieSlice("slice 1", 1);
263 QSignalSpy calculatedDataSpy(slice1, SIGNAL(calculatedDataChanged()));
263 QSignalSpy percentageSpy(slice1, SIGNAL(percentageChanged()));
264 QSignalSpy startAngleSpy(slice1, SIGNAL(startAngleChanged()));
265 QSignalSpy angleSpanSpy(slice1, SIGNAL(angleSpanChanged()));
264 266
265 267 // add a slice
266 268 s.append(slice1);
267 269 verifyCalculatedData(s, &ok);
268 270 if (!ok)
269 271 return;
270 QCOMPARE(calculatedDataSpy.count(), 1);
272 QCOMPARE(percentageSpy.count(), 1);
273 QCOMPARE(startAngleSpy.count(), 0);
274 QCOMPARE(angleSpanSpy.count(), 1);
271 275
272 276 // add some more slices
273 277 QList<QPieSlice *> list;
274 278 list << new QPieSlice("slice 2", 2);
275 279 list << new QPieSlice("slice 3", 3);
276 280 s.append(list);
277 281 verifyCalculatedData(s, &ok);
278 282 if (!ok)
279 283 return;
280 QCOMPARE(calculatedDataSpy.count(), 2);
284 QCOMPARE(percentageSpy.count(), 2);
285 QCOMPARE(startAngleSpy.count(), 0);
286 QCOMPARE(angleSpanSpy.count(), 2);
281 287
282 288 // remove a slice
283 289 s.remove(list.first()); // remove slice 2
284 290 verifyCalculatedData(s, &ok);
285 291 if (!ok)
286 292 return;
287 QCOMPARE(calculatedDataSpy.count(), 3);
293 QCOMPARE(percentageSpy.count(), 3);
294 QCOMPARE(startAngleSpy.count(), 0);
295 QCOMPARE(angleSpanSpy.count(), 3);
288 296
289 297 // insert a slice
290 298 s.insert(0, new QPieSlice("Slice 4", 4));
291 299 verifyCalculatedData(s, &ok);
292 300 if (!ok)
293 301 return;
294 QCOMPARE(calculatedDataSpy.count(), 4);
302 QCOMPARE(percentageSpy.count(), 4);
303 QCOMPARE(startAngleSpy.count(), 1);
304 QCOMPARE(angleSpanSpy.count(), 4);
295 305
296 306 // modify pie angles
297 307 s.setPieStartAngle(-90);
298 308 s.setPieEndAngle(90);
299 309 verifyCalculatedData(s, &ok);
300 310 if (!ok)
301 311 return;
302 QCOMPARE(calculatedDataSpy.count(), 6);
312 QCOMPARE(percentageSpy.count(), 4);
313 QCOMPARE(startAngleSpy.count(), 3);
314 QCOMPARE(angleSpanSpy.count(), 6);
303 315
304 316 // clear all
305 317 s.clear();
306 318 verifyCalculatedData(s, &ok);
319 QCOMPARE(percentageSpy.count(), 4);
320 QCOMPARE(startAngleSpy.count(), 3);
321 QCOMPARE(angleSpanSpy.count(), 6);
307 322 }
308 323
309 324 void tst_qpieseries::verifyCalculatedData(const QPieSeries &series, bool *ok)
310 325 {
311 326 *ok = false;
312 327
313 328 qreal sum = 0;
314 329 foreach (const QPieSlice *slice, series.slices())
315 330 sum += slice->value();
316 331 QCOMPARE(series.sum(), sum);
317 332
318 333 qreal startAngle = series.pieStartAngle();
319 334 qreal pieAngleSpan = series.pieEndAngle() - series.pieStartAngle();
320 335 foreach (const QPieSlice *slice, series.slices()) {
321 336 qreal ratio = slice->value() / sum;
322 337 qreal sliceSpan = pieAngleSpan * ratio;
323 338 QCOMPARE(slice->startAngle(), startAngle);
324 QCOMPARE(slice->endAngle(), startAngle + sliceSpan);
339 QCOMPARE(slice->angleSpan(), sliceSpan);
325 340 QCOMPARE(slice->percentage(), ratio);
326 341 startAngle += sliceSpan;
327 342 }
328 343
329 344 if (!series.isEmpty())
330 QCOMPARE(series.slices().last()->endAngle(), series.pieEndAngle());
345 QCOMPARE(series.slices().last()->startAngle() + series.slices().last()->angleSpan(), series.pieEndAngle());
331 346
332 347 *ok = true;
333 348 }
334 349
335 350
336 351 void tst_qpieseries::clickedSignal()
337 352 {
338 353 // create a pie series
339 354 QPieSeries *series = new QPieSeries();
340 355 QPieSlice *s1 = series->append("slice 1", 1);
341 356 QPieSlice *s2 = series->append("slice 2", 1);
342 357 QPieSlice *s3 = series->append("slice 3", 1);
343 358 QPieSlice *s4 = series->append("slice 4", 1);
344 359 QSignalSpy clickSpy(series, SIGNAL(clicked(QPieSlice*)));
345 360
346 361 // add series to the chart
347 362 QChartView view(new QChart());
348 363 view.chart()->legend()->setVisible(false);
349 364 view.resize(200, 200);
350 365 view.chart()->addSeries(series);
351 366 view.show();
352 367 QTest::qWaitForWindowShown(&view);
353 368
354 369 // if you devide the chart in four equal tiles these
355 370 // are the center points of those tiles
356 371 QPoint p1(90.25, 90);
357 372 QPoint p2(150, 90);
358 373 QPoint p3(90, 150);
359 374 QPoint p4(150, 150);
360 375
361 376 QPoint center(120, 120);
362 377
363 378 series->setPieSize(1.0);
364 379 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p1);
365 380 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p2);
366 381 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p3);
367 382 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p4);
368 383 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, center);
369 384 TRY_COMPARE(clickSpy.count(), 5); // all hit
370 385 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(0).at(0)), s4);
371 386 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(1).at(0)), s1);
372 387 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(2).at(0)), s3);
373 388 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(3).at(0)), s2);
374 389 clickSpy.clear();
375 390
376 391 series->setPieSize(0.5);
377 392 series->setVerticalPosition(0.25);
378 393 series->setHorizontalPosition(0.25);
379 394 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p1); // hits
380 395 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p2);
381 396 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p3);
382 397 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p4);
383 398 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, center);
384 399 TRY_COMPARE(clickSpy.count(), 1);
385 400 clickSpy.clear();
386 401
387 402 series->setVerticalPosition(0.25);
388 403 series->setHorizontalPosition(0.75);
389 404 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p1);
390 405 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p2); // hits
391 406 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p3);
392 407 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p4);
393 408 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, center);
394 409 TRY_COMPARE(clickSpy.count(), 1);
395 410 clickSpy.clear();
396 411
397 412 series->setVerticalPosition(0.75);
398 413 series->setHorizontalPosition(0.25);
399 414 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p1);
400 415 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p2);
401 416 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p3); // hits
402 417 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p4);
403 418 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, center);
404 419 TRY_COMPARE(clickSpy.count(), 1);
405 420 clickSpy.clear();
406 421
407 422 series->setVerticalPosition(0.75);
408 423 series->setHorizontalPosition(0.75);
409 424 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p1);
410 425 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p2);
411 426 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p3);
412 427 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p4); // hits
413 428 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, center);
414 429 TRY_COMPARE(clickSpy.count(), 1);
415 430 clickSpy.clear();
416 431 }
417 432
418 433 void tst_qpieseries::hoverSignal()
419 434 {
420 435 // create a pie series
421 436 QPieSeries *series = new QPieSeries();
422 437 series->setPieSize(1.0);
423 438 QPieSlice *s1 = series->append("slice 1", 1);
424 439 series->append("slice 2", 2);
425 440 series->append("slice 3", 3);
426 441
427 442 // add series to the chart
428 443 QChartView view(new QChart());
429 444 view.chart()->legend()->setVisible(false);
430 445 view.resize(200, 200);
431 446 view.chart()->addSeries(series);
432 447 view.show();
433 448 QTest::qWaitForWindowShown(&view);
434 449
435 450 // first move to right top corner
436 451 QTest::mouseMove(view.viewport(), QPoint(200, 0));
437 452 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
438 453
439 454 // move inside the slice
440 455 // pie rectangle: QRectF(60,60 121x121)
441 456 QSignalSpy hoverSpy(series, SIGNAL(hovered(QPieSlice*,bool)));
442 457 QTest::mouseMove(view.viewport(), QPoint(139, 85));
443 458 TRY_COMPARE(hoverSpy.count(), 1);
444 459 QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(0).at(0)), s1);
445 460 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(0).at(1)), true);
446 461
447 462 // move outside the slice
448 463 QTest::mouseMove(view.viewport(), QPoint(200, 0));
449 464 TRY_COMPARE(hoverSpy.count(), 2);
450 465 QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(1).at(0)), s1);
451 466 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(1).at(1)), false);
452 467 }
453 468
454 469 QTEST_MAIN(tst_qpieseries)
455 470
456 471 #include "tst_qpieseries.moc"
457 472
@@ -1,278 +1,291
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include <QtTest/QtTest>
22 22 #include <tst_definitions.h>
23 23 #include <qchartview.h>
24 24 #include <qchart.h>
25 25 #include <qpieslice.h>
26 26 #include <qpieseries.h>
27 27
28 28 QTCOMMERCIALCHART_USE_NAMESPACE
29 29
30 30 class tst_qpieslice : public QObject
31 31 {
32 32 Q_OBJECT
33 33
34 34 public slots:
35 35 void initTestCase();
36 36 void cleanupTestCase();
37 37 void init();
38 38 void cleanup();
39 39
40 40 private slots:
41 41 void construction();
42 42 void changedSignals();
43 43 void customize();
44 44 void mouseClick();
45 45 void mouseHover();
46 46
47 47 private:
48 48
49 49
50 50 private:
51 51
52 52 };
53 53
54 54 void tst_qpieslice::initTestCase()
55 55 {
56 56 }
57 57
58 58 void tst_qpieslice::cleanupTestCase()
59 59 {
60 60 }
61 61
62 62 void tst_qpieslice::init()
63 63 {
64 64
65 65 }
66 66
67 67 void tst_qpieslice::cleanup()
68 68 {
69 69
70 70 }
71 71
72 72 void tst_qpieslice::construction()
73 73 {
74 74 // no params
75 75 QPieSlice slice1;
76 76 QCOMPARE(slice1.value(), 0.0);
77 77 QVERIFY(slice1.label().isEmpty());
78 78 QVERIFY(!slice1.isLabelVisible());
79 79 QVERIFY(!slice1.isExploded());
80 80 QCOMPARE(slice1.pen(), QPen());
81 81 QCOMPARE(slice1.brush(), QBrush());
82 82 QCOMPARE(slice1.labelPen(), QPen());
83 83 QCOMPARE(slice1.labelFont(), QFont());
84 84 QCOMPARE(slice1.labelArmLengthFactor(), 0.15); // default value
85 85 QCOMPARE(slice1.explodeDistanceFactor(), 0.15); // default value
86 86 QCOMPARE(slice1.percentage(), 0.0);
87 87 QCOMPARE(slice1.startAngle(), 0.0);
88 QCOMPARE(slice1.endAngle(), 0.0);
88 QCOMPARE(slice1.angleSpan(), 0.0);
89 89
90 90 // value and label params
91 91 QPieSlice slice2("foobar", 1.0);
92 92 QCOMPARE(slice2.value(), 1.0);
93 93 QCOMPARE(slice2.label(), QString("foobar"));
94 94 QVERIFY(!slice2.isLabelVisible());
95 95 QVERIFY(!slice2.isExploded());
96 96 QCOMPARE(slice2.pen(), QPen());
97 97 QCOMPARE(slice2.brush(), QBrush());
98 98 QCOMPARE(slice2.labelPen(), QPen());
99 99 QCOMPARE(slice2.labelFont(), QFont());
100 100 QCOMPARE(slice2.labelArmLengthFactor(), 0.15); // default value
101 101 QCOMPARE(slice2.explodeDistanceFactor(), 0.15); // default value
102 102 QCOMPARE(slice2.percentage(), 0.0);
103 103 QCOMPARE(slice2.startAngle(), 0.0);
104 QCOMPARE(slice2.endAngle(), 0.0);
104 QCOMPARE(slice2.angleSpan(), 0.0);
105 105 }
106 106
107 107 void tst_qpieslice::changedSignals()
108 108 {
109 109 QPieSlice slice;
110 110
111 111 QSignalSpy valueSpy(&slice, SIGNAL(valueChanged()));
112 112 QSignalSpy labelSpy(&slice, SIGNAL(labelChanged()));
113 QSignalSpy appearanceSpy(&slice, SIGNAL(appearanceChanged()));
114 // calculatedDataChanged signal is tested at tst_qpieseries::calculatedValues()
113 QSignalSpy explodedSpy(&slice, SIGNAL(explodedChanged()));
114 QSignalSpy penSpy(&slice, SIGNAL(penChanged()));
115 QSignalSpy brushSpy(&slice, SIGNAL(brushChanged()));
116 QSignalSpy labelPenSpy(&slice, SIGNAL(labelPenChanged()));
117 QSignalSpy labelFontSpy(&slice, SIGNAL(labelFontChanged()));
118 QSignalSpy labelArmLengthFactorSpy(&slice, SIGNAL(labelArmLengthFactorChanged()));
119 QSignalSpy explodeDistanceFactorSpy(&slice, SIGNAL(explodeDistanceFactorChanged()));
120
121 // percentageChanged(), startAngleChanged() and angleSpanChanged() signals tested at tst_qpieseries::calculatedValues()
115 122
116 123 // set everything twice to see we do not get unnecessary signals
117 124 slice.setValue(1);
118 125 slice.setValue(1);
119 126 slice.setLabel("foobar");
120 127 slice.setLabel("foobar");
121 128 slice.setLabelVisible();
122 129 slice.setLabelVisible();
123 130 slice.setExploded();
124 131 slice.setExploded();
125 132 slice.setPen(QPen(Qt::red));
126 133 slice.setPen(QPen(Qt::red));
127 134 slice.setBrush(QBrush(Qt::red));
128 135 slice.setBrush(QBrush(Qt::red));
129 136 slice.setLabelPen(QPen(Qt::green));
130 137 slice.setLabelPen(QPen(Qt::green));
131 138 slice.setLabelFont(QFont("Tahoma"));
132 139 slice.setLabelFont(QFont("Tahoma"));
133 140 slice.setLabelArmLengthFactor(0.1);
134 141 slice.setLabelArmLengthFactor(0.1);
135 142 slice.setExplodeDistanceFactor(0.1);
136 143 slice.setExplodeDistanceFactor(0.1);
137 144
138 145 TRY_COMPARE(valueSpy.count(), 1);
139 146 TRY_COMPARE(labelSpy.count(), 1);
140 TRY_COMPARE(appearanceSpy.count(), 8);
147 TRY_COMPARE(explodedSpy.count(), 1);
148 TRY_COMPARE(penSpy.count(), 1);
149 TRY_COMPARE(brushSpy.count(), 1);
150 TRY_COMPARE(labelPenSpy.count(), 1);
151 TRY_COMPARE(labelFontSpy.count(), 1);
152 TRY_COMPARE(labelArmLengthFactorSpy.count(), 1);
153 TRY_COMPARE(explodeDistanceFactorSpy.count(), 1);
141 154 }
142 155
143 156 void tst_qpieslice::customize()
144 157 {
145 158 // create a pie series
146 159 QPieSeries *series = new QPieSeries();
147 160 QPieSlice *s1 = series->append("slice 1", 1);
148 161 QPieSlice *s2 = series->append("slice 2", 2);
149 162 series->append("slice 3", 3);
150 163
151 164 // customize a slice
152 165 QPen p1(Qt::red);
153 166 s1->setPen(p1);
154 167 QBrush b1(Qt::red);
155 168 s1->setBrush(b1);
156 169 s1->setLabelPen(p1);
157 170 QFont f1("Consolas");
158 171 s1->setLabelFont(f1);
159 172
160 173 // add series to the chart
161 174 QChartView view(new QChart());
162 175 view.resize(200, 200);
163 176 view.chart()->addSeries(series);
164 177 view.show();
165 178 QTest::qWaitForWindowShown(&view);
166 179 //QTest::qWait(1000);
167 180
168 181 // check that customizations persist
169 182 QCOMPARE(s1->pen(), p1);
170 183 QCOMPARE(s1->brush(), b1);
171 184 QCOMPARE(s1->labelPen(), p1);
172 185 QCOMPARE(s1->labelFont(), f1);
173 186
174 187 // remove a slice
175 188 series->remove(s2);
176 189 QCOMPARE(s1->pen(), p1);
177 190 QCOMPARE(s1->brush(), b1);
178 191 QCOMPARE(s1->labelPen(), p1);
179 192 QCOMPARE(s1->labelFont(), f1);
180 193
181 194 // add a slice
182 195 series->append("slice 4", 4);
183 196 QCOMPARE(s1->pen(), p1);
184 197 QCOMPARE(s1->brush(), b1);
185 198 QCOMPARE(s1->labelPen(), p1);
186 199 QCOMPARE(s1->labelFont(), f1);
187 200
188 201 // insert a slice
189 202 series->insert(0, new QPieSlice("slice 5", 5));
190 203 QCOMPARE(s1->pen(), p1);
191 204 QCOMPARE(s1->brush(), b1);
192 205 QCOMPARE(s1->labelPen(), p1);
193 206 QCOMPARE(s1->labelFont(), f1);
194 207
195 208 // change theme
196 209 // theme will overwrite customizations
197 210 view.chart()->setTheme(QChart::ChartThemeHighContrast);
198 211 QVERIFY(s1->pen() != p1);
199 212 QVERIFY(s1->brush() != b1);
200 213 QVERIFY(s1->labelPen() != p1);
201 214 QVERIFY(s1->labelFont() != f1);
202 215 }
203 216
204 217 void tst_qpieslice::mouseClick()
205 218 {
206 219 // create a pie series
207 220 QPieSeries *series = new QPieSeries();
208 221 series->setPieSize(1.0);
209 222 QPieSlice *s1 = series->append("slice 1", 1);
210 223 QPieSlice *s2 = series->append("slice 2", 2);
211 224 QPieSlice *s3 = series->append("slice 3", 3);
212 225 QSignalSpy clickSpy1(s1, SIGNAL(clicked()));
213 226 QSignalSpy clickSpy2(s2, SIGNAL(clicked()));
214 227 QSignalSpy clickSpy3(s3, SIGNAL(clicked()));
215 228
216 229 // add series to the chart
217 230 QChartView view(new QChart());
218 231 view.chart()->legend()->setVisible(false);
219 232 view.resize(200, 200);
220 233 view.chart()->addSeries(series);
221 234 view.show();
222 235 QTest::qWaitForWindowShown(&view);
223 236
224 237 // simulate clicks
225 238 // pie rectangle: QRectF(60,60 121x121)
226 239 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(139, 85)); // inside slice 1
227 240 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(146, 136)); // inside slice 2
228 241 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(91, 119)); // inside slice 3
229 242 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(70, 70)); // inside pie rectangle but not inside a slice
230 243 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(170, 170)); // inside pie rectangle but not inside a slice
231 244 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
232 245 QCOMPARE(clickSpy1.count(), 1);
233 246 QCOMPARE(clickSpy2.count(), 1);
234 247 QCOMPARE(clickSpy3.count(), 1);
235 248 }
236 249
237 250 void tst_qpieslice::mouseHover()
238 251 {
239 252 // create a pie series
240 253 QPieSeries *series = new QPieSeries();
241 254 series->setPieSize(1.0);
242 255 QPieSlice *s1 = series->append("slice 1", 1);
243 256 series->append("slice 2", 2);
244 257 series->append("slice 3", 3);
245 258
246 259 // add series to the chart
247 260 QChartView view(new QChart());
248 261 view.chart()->legend()->setVisible(false);
249 262 view.resize(200, 200);
250 263 view.chart()->addSeries(series);
251 264 view.show();
252 265 QTest::qWaitForWindowShown(&view);
253 266
254 267 // first move to right top corner
255 268 QTest::mouseMove(view.viewport(), QPoint(200, 0));
256 269 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
257 270
258 271 // move inside slice rectangle but NOT the actual slice
259 272 // pie rectangle: QRectF(60,60 121x121)
260 273 QSignalSpy hoverSpy(s1, SIGNAL(hovered(bool)));
261 274 QTest::mouseMove(view.viewport(), QPoint(170, 70));
262 275 TRY_COMPARE(hoverSpy.count(), 0);
263 276
264 277 // move inside the slice
265 278 QTest::mouseMove(view.viewport(), QPoint(139, 85));
266 279 TRY_COMPARE(hoverSpy.count(), 1);
267 280 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(0).at(0)), true);
268 281
269 282 // move outside the slice
270 283 QTest::mouseMove(view.viewport(), QPoint(200, 0));
271 284 TRY_COMPARE(hoverSpy.count(), 2);
272 285 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(1).at(0)), false);
273 286 }
274 287
275 288 QTEST_MAIN(tst_qpieslice)
276 289
277 290 #include "tst_qpieslice.moc"
278 291
General Comments 0
You need to be logged in to leave comments. Login now