##// END OF EJS Templates
QPieSeries: label value is now also updated when the same row/column of the model is mapped for values and labels
Marek Rosa -
r638:61d3ed85e2c1
parent child
Show More
@@ -1,588 +1,604
1 1 #include "qpieseries.h"
2 2 #include "qpieslice.h"
3 3 #include <QDebug>
4 4
5 5 QTCOMMERCIALCHART_BEGIN_NAMESPACE
6 6
7 7 /*!
8 8 \class QPieSeries
9 9 \brief Pie series API for QtCommercial Charts
10 10
11 11 The pie series defines a pie chart which consists of pie slices which are QPieSlice objects.
12 12 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
13 13 The actual slice size is determined by that relative value.
14 14
15 15 By default the pie is defined as a full pie but it can be a partial pie.
16 16 This can be done by setting a starting angle and angle span to the series.
17 17 */
18 18
19 19 /*!
20 20 Constructs a series object which is a child of \a parent.
21 21 */
22 22 QPieSeries::QPieSeries(QObject *parent) :
23 23 QSeries(parent),
24 24 m_pieRelativeHorPos(0.5),
25 25 m_pieRelativeVerPos(0.5),
26 26 m_pieRelativeSize(0.7),
27 27 m_pieStartAngle(0),
28 28 m_pieEndAngle(360),
29 29 m_total(0)
30 30 {
31 31
32 32 }
33 33
34 34 /*!
35 35 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
36 36 */
37 37 QPieSeries::~QPieSeries()
38 38 {
39 39
40 40 }
41 41
42 42 /*!
43 43 Returns QChartSeries::SeriesTypePie.
44 44 */
45 45 QSeries::QSeriesType QPieSeries::type() const
46 46 {
47 47 return QSeries::SeriesTypePie;
48 48 }
49 49
50 50 /*!
51 51 Sets an array of \a slices to the series replacing the existing slices.
52 52 Slice ownership is passed to the series.
53 53 */
54 54 void QPieSeries::replace(QList<QPieSlice*> slices)
55 55 {
56 56 clear();
57 57 add(slices);
58 58 }
59 59
60 60 /*!
61 61 Adds an array of \a slices to the series.
62 62 Slice ownership is passed to the series.
63 63 */
64 64 void QPieSeries::add(QList<QPieSlice*> slices)
65 65 {
66 66 foreach (QPieSlice* s, slices) {
67 67 s->setParent(this);
68 68 m_slices << s;
69 69 }
70 70
71 71 updateDerivativeData();
72 72
73 73 foreach (QPieSlice* s, slices) {
74 74 connect(s, SIGNAL(changed()), this, SLOT(sliceChanged()));
75 75 connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked()));
76 76 connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
77 77 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
78 78 }
79 79
80 80 emit added(slices);
81 81 }
82 82
83 83 /*!
84 84 Adds a single \a slice to the series.
85 85 Slice ownership is passed to the series.
86 86 */
87 87 void QPieSeries::add(QPieSlice* slice)
88 88 {
89 89 add(QList<QPieSlice*>() << slice);
90 90 }
91 91
92 92 /*!
93 93 Adds a single \a slice to the series and returns a reference to the series.
94 94 Slice ownership is passed to the series.
95 95 */
96 96 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
97 97 {
98 98 add(slice);
99 99 return *this;
100 100 }
101 101
102 102
103 103 /*!
104 104 Adds a single slice to the series with give \a value and \a name.
105 105 Slice ownership is passed to the series.
106 106 */
107 107 QPieSlice* QPieSeries::add(qreal value, QString name)
108 108 {
109 109 QPieSlice* slice = new QPieSlice(value, name);
110 110 add(slice);
111 111 return slice;
112 112 }
113 113
114 114 void QPieSeries::insert(int i, QPieSlice* slice)
115 115 {
116 116 Q_ASSERT(i <= m_slices.count());
117 117 slice->setParent(this);
118 118 m_slices.insert(i, slice);
119 119
120 120 updateDerivativeData();
121 121
122 122 connect(slice, SIGNAL(changed()), this, SLOT(sliceChanged()));
123 123 connect(slice, SIGNAL(clicked()), this, SLOT(sliceClicked()));
124 124 connect(slice, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
125 125 connect(slice, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
126 126
127 127 emit added(QList<QPieSlice*>() << slice);
128 128 }
129 129
130 130 /*!
131 131 Removes a single \a slice from the series and deletes the slice.
132 132
133 133 Do not reference this pointer after this call.
134 134 */
135 135 void QPieSeries::remove(QPieSlice* slice)
136 136 {
137 137 if (!m_slices.removeOne(slice)) {
138 138 Q_ASSERT(0); // TODO: how should this be reported?
139 139 return;
140 140 }
141 141
142 142 updateDerivativeData();
143 143
144 144 emit removed(QList<QPieSlice*>() << slice);
145 145
146 146 delete slice;
147 147 slice = NULL;
148 148 }
149 149
150 150 /*!
151 151 Clears all slices from the series.
152 152 */
153 153 void QPieSeries::clear()
154 154 {
155 155 if (m_slices.count() == 0)
156 156 return;
157 157
158 158 QList<QPieSlice*> slices = m_slices;
159 159 foreach (QPieSlice* s, m_slices) {
160 160 m_slices.removeOne(s);
161 161 delete s;
162 162 }
163 163
164 164 updateDerivativeData();
165 165
166 166 emit removed(slices);
167 167 }
168 168
169 169 /*!
170 170 Counts the number of the slices in this series.
171 171 */
172 172 int QPieSeries::count() const
173 173 {
174 174 return m_slices.count();
175 175 }
176 176
177 177 /*!
178 178 Returns true is the series is empty.
179 179 */
180 180 bool QPieSeries::isEmpty() const
181 181 {
182 182 return m_slices.isEmpty();
183 183 }
184 184
185 185 /*!
186 186 Returns a list of slices that belong to this series.
187 187 */
188 188 QList<QPieSlice*> QPieSeries::slices() const
189 189 {
190 190 return m_slices;
191 191 }
192 192
193 193 /*!
194 194 Sets the center position of the pie by \a relativeHorizontalPosition and \a relativeVerticalPosition.
195 195
196 196 The factors are relative to the chart rectangle where:
197 197
198 198 \a relativeHorizontalPosition 0.0 means the absolute left.
199 199 \a relativeHorizontalPosition 1.0 means the absolute right.
200 200 \a relativeVerticalPosition 0.0 means the absolute top.
201 201 \a relativeVerticalPosition 1.0 means the absolute bottom.
202 202
203 203 By default both values are 0.5 which puts the pie in the middle of the chart rectangle.
204 204
205 205 \sa pieHorizontalPosition(), pieVerticalPosition(), setPieSize()
206 206 */
207 207 void QPieSeries::setPiePosition(qreal relativeHorizontalPosition, qreal relativeVerticalPosition)
208 208 {
209 209 if (relativeHorizontalPosition < 0.0 || relativeHorizontalPosition > 1.0 ||
210 210 relativeVerticalPosition < 0.0 || relativeVerticalPosition > 1.0)
211 211 return;
212 212
213 213 if (m_pieRelativeHorPos != relativeHorizontalPosition || m_pieRelativeVerPos != relativeVerticalPosition) {
214 214 m_pieRelativeHorPos = relativeHorizontalPosition;
215 215 m_pieRelativeVerPos = relativeVerticalPosition;
216 216 emit piePositionChanged();
217 217 }
218 218 }
219 219
220 220 /*!
221 221 Gets the horizontal position of the pie.
222 222
223 223 The returned value is relative to the chart rectangle where:
224 224
225 225 0.0 means the absolute left.
226 226 1.0 means the absolute right.
227 227
228 228 By default it is 0.5 which puts the pie in the horizontal middle of the chart rectangle.
229 229
230 230 \sa setPiePosition(), pieVerticalPosition(), setPieSize()
231 231 */
232 232 qreal QPieSeries::pieHorizontalPosition() const
233 233 {
234 234 return m_pieRelativeHorPos;
235 235 }
236 236
237 237 /*!
238 238 Gets the vertical position position of the pie.
239 239
240 240 The returned value is relative to the chart rectangle where:
241 241
242 242 0.0 means the absolute top.
243 243 1.0 means the absolute bottom.
244 244
245 245 By default it is 0.5 which puts the pie in the vertical middle of the chart rectangle.
246 246
247 247 \sa setPiePosition(), pieHorizontalPosition(), setPieSize()
248 248 */
249 249 qreal QPieSeries::pieVerticalPosition() const
250 250 {
251 251 return m_pieRelativeVerPos;
252 252 }
253 253
254 254 /*!
255 255 Sets the relative size of the pie.
256 256
257 257 The \a relativeSize is defined so that the 1.0 is the maximum that can fit the given chart rectangle.
258 258
259 259 Default value is 0.7.
260 260
261 261 \sa pieSize(), setPiePosition(), pieVerticalPosition(), pieHorizontalPosition()
262 262 */
263 263 void QPieSeries::setPieSize(qreal relativeSize)
264 264 {
265 265 if (relativeSize < 0.0 || relativeSize > 1.0)
266 266 return;
267 267
268 268 if (m_pieRelativeSize != relativeSize) {
269 269 m_pieRelativeSize = relativeSize;
270 270 emit pieSizeChanged();
271 271 }
272 272 }
273 273
274 274 /*!
275 275 Gets the relative size of the pie.
276 276
277 277 The size is defined so that the 1.0 is the maximum that can fit the given chart rectangle.
278 278
279 279 Default value is 0.7.
280 280
281 281 \sa setPieSize(), setPiePosition(), pieVerticalPosition(), pieHorizontalPosition()
282 282 */
283 283 qreal QPieSeries::pieSize() const
284 284 {
285 285 return m_pieRelativeSize;
286 286 }
287 287
288 288
289 289 /*!
290 290 Sets the end angle of the pie.
291 291
292 292 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
293 293
294 294 \a angle must be less than pie end angle. Default value is 0.
295 295
296 296 \sa pieStartAngle(), pieEndAngle(), setPieEndAngle()
297 297 */
298 298 void QPieSeries::setPieStartAngle(qreal angle)
299 299 {
300 300 if (angle >= 0 && angle <= 360 && angle != m_pieStartAngle && angle <= m_pieEndAngle) {
301 301 m_pieStartAngle = angle;
302 302 updateDerivativeData();
303 303 }
304 304 }
305 305
306 306 /*!
307 307 Gets the start angle of the pie.
308 308
309 309 Full pie is 360 degrees where 0 degrees is at 12 a'clock. Default value is 360.
310 310
311 311 \sa setPieStartAngle(), pieEndAngle(), setPieEndAngle()
312 312 */
313 313 qreal QPieSeries::pieStartAngle() const
314 314 {
315 315 return m_pieStartAngle;
316 316 }
317 317
318 318 /*!
319 319 Sets the end angle of the pie.
320 320
321 321 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
322 322
323 323 \a angle must be greater than start angle.
324 324
325 325 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
326 326 */
327 327 void QPieSeries::setPieEndAngle(qreal angle)
328 328 {
329 329 if (angle >= 0 && angle <= 360 && angle != m_pieEndAngle && angle >= m_pieStartAngle) {
330 330 m_pieEndAngle = angle;
331 331 updateDerivativeData();
332 332 }
333 333 }
334 334
335 335 /*!
336 336 Returns the end angle of the pie.
337 337
338 338 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
339 339
340 340 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
341 341 */
342 342 qreal QPieSeries::pieEndAngle() const
343 343 {
344 344 return m_pieEndAngle;
345 345 }
346 346
347 347 /*!
348 348 Sets the all the slice labels \a visible or invisible.
349 349
350 350 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
351 351 */
352 352 void QPieSeries::setLabelsVisible(bool visible)
353 353 {
354 354 foreach (QPieSlice* s, m_slices)
355 355 s->setLabelVisible(visible);
356 356 }
357 357
358 358 /*!
359 359 Returns the sum of all slice values in this series.
360 360
361 361 \sa QPieSlice::value(), QPieSlice::setValue()
362 362 */
363 363 qreal QPieSeries::total() const
364 364 {
365 365 return m_total;
366 366 }
367 367
368 368 /*!
369 369 \fn void QPieSeries::changed()
370 370
371 371 This signal emitted when something has changed in the series.
372 372
373 373 \sa QPieSeries::ChangeSet, QPieSlice::changed()
374 374 */
375 375
376 376 /*!
377 377 \fn void QPieSeries::clicked(QPieSlice* slice)
378 378
379 379 This signal is emitted when a \a slice has been clicked.
380 380
381 381 \sa QPieSlice::clicked()
382 382 */
383 383
384 384 /*!
385 385 \fn void QPieSeries::hoverEnter(QPieSlice* slice)
386 386
387 387 This signal is emitted when user has hovered over a \a slice.
388 388
389 389 \sa QPieSlice::hoverEnter()
390 390 */
391 391
392 392 /*!
393 393 \fn void QPieSeries::hoverLeave(QPieSlice* slice)
394 394
395 395 This signal is emitted when user has hovered away from a \a slice.
396 396
397 397 \sa QPieSlice::hoverLeave()
398 398 */
399 399
400 400 void QPieSeries::sliceChanged()
401 401 {
402 402 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
403 403 Q_ASSERT(m_slices.contains(slice));
404 404 updateDerivativeData();
405 405 }
406 406
407 407 void QPieSeries::sliceClicked()
408 408 {
409 409 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
410 410 Q_ASSERT(m_slices.contains(slice));
411 411 emit clicked(slice);
412 412 }
413 413
414 414 void QPieSeries::sliceHoverEnter()
415 415 {
416 416 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
417 417 Q_ASSERT(m_slices.contains(slice));
418 418 emit hoverEnter(slice);
419 419 }
420 420
421 421 void QPieSeries::sliceHoverLeave()
422 422 {
423 423 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
424 424 Q_ASSERT(m_slices.contains(slice));
425 425 emit hoverLeave(slice);
426 426 }
427 427
428 428 void QPieSeries::updateDerivativeData()
429 429 {
430 430 m_total = 0;
431 431
432 432 // nothing to do?
433 433 if (m_slices.count() == 0)
434 434 return;
435 435
436 436 // calculate total
437 437 foreach (QPieSlice* s, m_slices)
438 438 m_total += s->value();
439 439
440 440 // nothing to show..
441 441 if (m_total == 0)
442 442 return;
443 443
444 444 // update slice attributes
445 445 qreal sliceAngle = m_pieStartAngle;
446 446 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
447 447 QVector<QPieSlice*> changed;
448 448 foreach (QPieSlice* s, m_slices) {
449 449
450 450 bool isChanged = false;
451 451
452 452 qreal percentage = s->value() / m_total;
453 453 if (s->m_percentage != percentage) {
454 454 s->m_percentage = percentage;
455 455 isChanged = true;
456 456 }
457 457
458 458 qreal sliceSpan = pieSpan * percentage;
459 459 if (s->m_angleSpan != sliceSpan) {
460 460 s->m_angleSpan = sliceSpan;
461 461 isChanged = true;
462 462 }
463 463
464 464 if (s->m_startAngle != sliceAngle) {
465 465 s->m_startAngle = sliceAngle;
466 466 isChanged = true;
467 467 }
468 468 sliceAngle += sliceSpan;
469 469
470 470 if (isChanged)
471 471 changed << s;
472 472 }
473 473
474 474 // emit signals
475 475 foreach (QPieSlice* s, changed)
476 476 emit s->changed();
477 477 }
478 478
479 479 bool QPieSeries::setModel(QAbstractItemModel* model)
480 480 {
481 481 // disconnect signals from old model
482 482 if(m_model)
483 483 {
484 484 disconnect(m_model, 0, this, 0);
485 485 m_mapValues = -1;
486 486 m_mapLabels = -1;
487 487 m_mapOrientation = Qt::Vertical;
488 488 }
489 489
490 490 // set new model
491 491 if(model)
492 492 {
493 493 m_model = model;
494 494 return true;
495 495 }
496 496 else
497 497 {
498 498 m_model = NULL;
499 499 return false;
500 500 }
501 501 }
502 502
503 503 void QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation)
504 504 {
505 505 if (m_model == NULL)
506 506 return;
507 507 m_mapValues = modelValuesLine;
508 508 m_mapLabels = modelLabelsLine;
509 509 m_mapOrientation = orientation;
510 510
511 511 // connect the signals
512 512 if (m_mapOrientation == Qt::Vertical)
513 513 {
514 514 connect(m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelUpdated(QModelIndex, QModelIndex)));
515 515 connect(m_model,SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(modelDataAdded(QModelIndex,int,int)));
516 516 connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(modelDataRemoved(QModelIndex,int,int)));
517 517 }
518 518 else
519 519 {
520 520 connect(m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelUpdated(QModelIndex, QModelIndex)));
521 521 connect(m_model,SIGNAL(columnsInserted(QModelIndex, int, int)), this, SLOT(modelDataAdded(QModelIndex,int,int)));
522 522 connect(m_model, SIGNAL(columnsRemoved(QModelIndex, int, int)), this, SLOT(modelDataRemoved(QModelIndex,int,int)));
523 523 }
524 524
525 525 // create the initial slices set
526 526 if (m_mapOrientation == Qt::Vertical)
527 527 for (int i = 0; i < m_model->rowCount(); i++)
528 528 add(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString());
529 529 else
530 530 for (int i = 0; i < m_model->columnCount(); i++)
531 531 add(m_model->data(m_model->index(m_mapValues, i), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(m_mapLabels, i), Qt::DisplayRole).toString());
532 532
533 533
534 534 }
535 535
536 536 void QPieSeries::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
537 537 {
538 538 Q_UNUSED(bottomRight)
539 539
540 540 if (m_mapOrientation == Qt::Vertical)
541 541 {
542 542 // slices().at(topLeft.row())->setValue(m_model->data(m_model->index(topLeft.row(), topLeft.column()), Qt::DisplayRole).toDouble());
543 543 if (topLeft.column() == m_mapValues)
544 slices().at(topLeft.row())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
544 if (m_mapValues == m_mapLabels)
545 {
546 slices().at(topLeft.row())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
547 slices().at(topLeft.row())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
548 }
549 else
550 {
551 slices().at(topLeft.row())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
552 }
545 553 else if (topLeft.column() == m_mapLabels)
546 554 slices().at(topLeft.row())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
547 555 }
548 556 else
549 557 {
550 558 // slices().at(topLeft.column())->setValue(m_model->data(m_model->index(topLeft.row(), topLeft.column()), Qt::DisplayRole).toDouble());
551 559 if (topLeft.row() == m_mapValues)
552 slices().at(topLeft.column())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
560 if (m_mapValues == m_mapLabels)
561 {
562 slices().at(topLeft.column())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
563 slices().at(topLeft.column())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
564 }
565 else
566 {
567 slices().at(topLeft.column())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
568 }
553 569 else if (topLeft.row() == m_mapLabels)
554 570 slices().at(topLeft.column())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
555 571 }
556 572 }
557 573
558 574 void QPieSeries::modelDataAdded(QModelIndex parent, int start, int end)
559 575 {
560 576 Q_UNUSED(parent)
561 577 Q_UNUSED(end)
562 578
563 579 QPieSlice* newSlice = new QPieSlice;
564 580 newSlice->setLabelVisible(true);
565 581 if (m_mapOrientation == Qt::Vertical)
566 582 {
567 583 newSlice->setValue(m_model->data(m_model->index(start, m_mapValues), Qt::DisplayRole).toDouble());
568 584 newSlice->setLabel(m_model->data(m_model->index(start, m_mapLabels), Qt::DisplayRole).toString());
569 585 }
570 586 else
571 587 {
572 588 newSlice->setValue(m_model->data(m_model->index(m_mapValues, start), Qt::DisplayRole).toDouble());
573 589 newSlice->setLabel(m_model->data(m_model->index(m_mapLabels, start), Qt::DisplayRole).toString());
574 590 }
575 591
576 592 insert(start, newSlice);
577 593 }
578 594
579 595 void QPieSeries::modelDataRemoved(QModelIndex parent, int start, int end)
580 596 {
581 597 Q_UNUSED(parent)
582 598 Q_UNUSED(end)
583 599 remove(slices().at(start));
584 600 }
585 601
586 602 #include "moc_qpieseries.cpp"
587 603
588 604 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now