##// END OF EJS Templates
Added QDonutGroup class
Marek Rosa -
r1671:86eb2ea7496a
parent child
Show More
@@ -0,0 +1,39
1 #include "qdonutgroup.h"
2 #include "qdonutgroup_p.h"
3
4 QTCOMMERCIALCHART_BEGIN_NAMESPACE
5
6 QDonutGroup::QDonutGroup(QObject *parent) :
7 QObject(parent),
8 d_ptr(new QDonutGroupPrivate(this))
9 {
10 }
11
12 void QDonutGroup::append(QPieSeries *donut)
13 {
14 if (donut == 0)
15 return;
16
17 donut->setDonut();
18 Q_D(QDonutGroup);
19 d->m_donuts.append(donut);
20 qreal donutFraction = 1.0 / (d->m_donuts.count() + 1);
21 for(int i = 0; i < d->m_donuts.count(); i++) {
22 d->m_donuts[i]->setPieSize( (i + 2) * donutFraction);
23 d->m_donuts[i]->setDonutInnerSize( (i + 1) * donutFraction);
24 }
25 }
26
27 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
28
29 QDonutGroupPrivate::QDonutGroupPrivate(QDonutGroup *q):
30 QObject(q),
31 q_ptr(q)
32 {
33 //
34 }
35
36 #include "moc_qdonutgroup.cpp"
37 #include "moc_qdonutgroup_p.cpp"
38
39 QTCOMMERCIALCHART_END_NAMESPACE
@@ -0,0 +1,27
1 #ifndef QDONUTGROUP_H
2 #define QDONUTGROUP_H
3
4 #include <QObject>
5 #include <QPieSeries>
6
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8
9 //class QPieSeries;
10 class QDonutGroupPrivate;
11
12 class QTCOMMERCIALCHART_EXPORT QDonutGroup : public QObject
13 {
14 Q_OBJECT
15 public:
16 explicit QDonutGroup(QObject *parent = 0);
17
18 void append(QPieSeries *donut);
19
20 protected:
21 QDonutGroupPrivate * const d_ptr;
22 Q_DECLARE_PRIVATE(QDonutGroup)
23 };
24
25 QTCOMMERCIALCHART_END_NAMESPACE
26
27 #endif // QDONUTGROUP_H
@@ -0,0 +1,29
1 #ifndef QDONUTGROUP_P_H
2 #define QDONUTGROUP_P_H
3
4 #include <QObject>
5 #include <qdonutgroup.h>
6
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8
9 class QPieSeries;
10
11 class QDonutGroupPrivate : public QObject
12 {
13 Q_OBJECT
14 public:
15 explicit QDonutGroupPrivate(QDonutGroup *q);
16
17 void append(QPieSeries *donut);
18
19 private:
20 QList<QPieSeries *> m_donuts;
21
22 private:
23 QDonutGroup *q_ptr;
24 Q_DECLARE_PUBLIC(QDonutGroup)
25 };
26
27 QTCOMMERCIALCHART_END_NAMESPACE
28
29 #endif // QDONUTGROUP_P_H
@@ -1,568 +1,569
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 "qbarmodelmapper.h"
22 22 #include "qbarmodelmapper_p.h"
23 23 #include "qabstractbarseries.h"
24 24 #include "qbarset.h"
25 25 #include "qchart.h"
26 26 #include <QAbstractItemModel>
27 27
28 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29 29
30 30 QBarModelMapper::QBarModelMapper(QObject *parent) :
31 31 QObject(parent),
32 32 d_ptr(new QBarModelMapperPrivate(this))
33 33 {
34 34 }
35 35
36 36 QAbstractItemModel* QBarModelMapper::model() const
37 37 {
38 38 Q_D(const QBarModelMapper);
39 39 return d->m_model;
40 40 }
41 41
42 42 void QBarModelMapper::setModel(QAbstractItemModel *model)
43 43 {
44 44 if (model == 0)
45 45 return;
46 46
47 47 Q_D(QBarModelMapper);
48 48 if (d->m_model) {
49 49 disconnect(d->m_model, 0, d, 0);
50 50 }
51 51
52 52 d->m_model = model;
53 53 d->initializeBarFromModel();
54 54 // connect signals from the model
55 55 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
56 56 connect(d->m_model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), d, SLOT(modelHeaderDataUpdated(Qt::Orientation,int,int)));
57 57 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelRowsAdded(QModelIndex,int,int)));
58 58 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelRowsRemoved(QModelIndex,int,int)));
59 59 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelColumnsAdded(QModelIndex,int,int)));
60 60 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelColumnsRemoved(QModelIndex,int,int)));
61 61 connect(d->m_model, SIGNAL(destroyed()), d, SLOT(handleModelDestroyed()));
62 62 }
63 63
64 64 QAbstractBarSeries* QBarModelMapper::series() const
65 65 {
66 66 Q_D(const QBarModelMapper);
67 67 return d->m_series;
68 68 }
69 69
70 70 void QBarModelMapper::setSeries(QAbstractBarSeries *series)
71 71 {
72 72 Q_D(QBarModelMapper);
73 73 if (d->m_series) {
74 74 disconnect(d->m_series, 0, d, 0);
75 75 }
76 76
77 77 if (series == 0)
78 78 return;
79 79
80 80 d->m_series = series;
81 81 d->initializeBarFromModel();
82 82 // connect the signals from the series
83 83 connect(d->m_series, SIGNAL(barsetsAdded(QList<QBarSet*>)), d, SLOT(barSetsAdded(QList<QBarSet*>)));
84 84 connect(d->m_series, SIGNAL(barsetsRemoved(QList<QBarSet*>)), d, SLOT(barSetsRemoved(QList<QBarSet*>)));
85 85 connect(d->m_series, SIGNAL(destroyed()), d, SLOT(handleSeriesDestroyed()));
86 86 }
87 87
88 88 /*!
89 89 Returns which row/column of the model contains the first values of the QBarSets in the series.
90 90 The default value is 0.
91 91 */
92 92 int QBarModelMapper::first() const
93 93 {
94 94 Q_D(const QBarModelMapper);
95 95 return d->m_first;
96 96 }
97 97
98 98 /*!
99 99 Sets which row of the model contains the \a first values of the QBarSets in the series.
100 100 The default value is 0.
101 101 */
102 102 void QBarModelMapper::setFirst(int first)
103 103 {
104 104 Q_D(QBarModelMapper);
105 105 d->m_first = qMax(first, 0);
106 106 d->initializeBarFromModel();
107 107 }
108 108
109 109 /*!
110 110 Returns the number of rows/columns of the model that are mapped as the data for QAbstractBarSeries
111 111 Minimal and default value is: -1 (count limited by the number of rows/columns in the model)
112 112 */
113 113 int QBarModelMapper::count() const
114 114 {
115 115 Q_D(const QBarModelMapper);
116 116 return d->m_count;
117 117 }
118 118
119 119 /*!
120 120 Sets the \a count of rows/columns of the model that are mapped as the data for QAbstractBarSeries
121 121 Minimal and default value is: -1 (count limited by the number of rows/columns in the model)
122 122 */
123 123 void QBarModelMapper::setCount(int count)
124 124 {
125 125 Q_D(QBarModelMapper);
126 126 d->m_count = qMax(count, -1);
127 127 d->initializeBarFromModel();
128 128 }
129 129
130 130 /*!
131 131 Returns the orientation that is used when QBarModelMapper accesses the model.
132 132 This mean whether the consecutive values of the bar set are read from row (Qt::Horizontal)
133 133 or from columns (Qt::Vertical)
134 134 */
135 135 Qt::Orientation QBarModelMapper::orientation() const
136 136 {
137 137 Q_D(const QBarModelMapper);
138 138 return d->m_orientation;
139 139 }
140 140
141 141 /*!
142 142 Returns the \a orientation that is used when QBarModelMapper accesses the model.
143 143 This mean whether the consecutive values of the pie are read from row (Qt::Horizontal)
144 144 or from columns (Qt::Vertical)
145 145 */
146 146 void QBarModelMapper::setOrientation(Qt::Orientation orientation)
147 147 {
148 148 Q_D(QBarModelMapper);
149 149 d->m_orientation = orientation;
150 150 d->initializeBarFromModel();
151 151 }
152 152
153 153 /*!
154 154 Returns which section of the model is used as the data source for the first bar set
155 155 */
156 156 int QBarModelMapper::firstBarSetSection() const
157 157 {
158 158 Q_D(const QBarModelMapper);
159 159 return d->m_firstBarSetSection;
160 160 }
161 161
162 162 /*!
163 163 Sets the model section that is used as the data source for the first bar set
164 164 Parameter \a firstBarSetSection specifies the section of the model.
165 165 */
166 166 void QBarModelMapper::setFirstBarSetSection(int firstBarSetSection)
167 167 {
168 168 Q_D(QBarModelMapper);
169 169 d->m_firstBarSetSection = qMax(-1, firstBarSetSection);
170 170 d->initializeBarFromModel();
171 171 }
172 172
173 173 /*!
174 174 Returns which section of the model is used as the data source for the last bar set
175 175 */
176 176 int QBarModelMapper::lastBarSetSection() const
177 177 {
178 178 Q_D(const QBarModelMapper);
179 179 return d->m_lastBarSetSection;
180 180 }
181 181
182 182 /*!
183 183 Sets the model section that is used as the data source for the last bar set
184 184 Parameter \a lastBarSetSection specifies the section of the model.
185 185 */
186 186 void QBarModelMapper::setLastBarSetSection(int lastBarSetSection)
187 187 {
188 188 Q_D(QBarModelMapper);
189 189 d->m_lastBarSetSection = qMax(-1, lastBarSetSection);
190 190 d->initializeBarFromModel();
191 191 }
192 192
193 193 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
194 194
195 195 QBarModelMapperPrivate::QBarModelMapperPrivate(QBarModelMapper *q) :
196 QObject(q),
196 197 m_series(0),
197 198 m_model(0),
198 199 m_first(0),
199 200 m_count(-1),
200 201 m_orientation(Qt::Vertical),
201 202 m_firstBarSetSection(-1),
202 203 m_lastBarSetSection(-1),
203 204 m_seriesSignalsBlock(false),
204 205 m_modelSignalsBlock(false),
205 206 q_ptr(q)
206 207 {
207 208 }
208 209
209 210 void QBarModelMapperPrivate::blockModelSignals(bool block)
210 211 {
211 212 m_modelSignalsBlock = block;
212 213 }
213 214
214 215 void QBarModelMapperPrivate::blockSeriesSignals(bool block)
215 216 {
216 217 m_seriesSignalsBlock = block;
217 218 }
218 219
219 220 QBarSet* QBarModelMapperPrivate::barSet(QModelIndex index)
220 221 {
221 222 if (!index.isValid())
222 223 return 0;
223 224
224 225 if (m_orientation == Qt::Vertical && index.column() >= m_firstBarSetSection && index.column() <= m_lastBarSetSection) {
225 226 if (index.row() >= m_first && (m_count == - 1 || index.row() < m_first + m_count)) {
226 227 // if (m_model->index(index.row(), m_valuesSection).isValid() && m_model->index(index.row(), m_labelsSection).isValid())
227 228 return m_series->barSets().at(index.column() - m_firstBarSetSection);
228 229 // else
229 230 // return 0;
230 231 }
231 232 } else if (m_orientation == Qt::Horizontal && index.row() >= m_firstBarSetSection && index.row() <= m_lastBarSetSection) {
232 233 if (index.column() >= m_first && (m_count == - 1 || index.column() < m_first + m_count))
233 234 return m_series->barSets().at(index.row() - m_firstBarSetSection);
234 235 }
235 236 return 0; // This part of model has not been mapped to any slice
236 237 }
237 238
238 239 QModelIndex QBarModelMapperPrivate::barModelIndex(int barSection, int posInBar)
239 240 {
240 241 if (m_count != -1 && posInBar >= m_count)
241 242 return QModelIndex(); // invalid
242 243
243 244 if (barSection < m_firstBarSetSection || barSection > m_lastBarSetSection)
244 245 return QModelIndex(); // invalid
245 246
246 247 if (m_orientation == Qt::Vertical)
247 248 return m_model->index(posInBar + m_first, barSection);
248 249 else
249 250 return m_model->index(barSection, posInBar + m_first);
250 251 }
251 252
252 253 void QBarModelMapperPrivate::handleSeriesDestroyed()
253 254 {
254 255 m_series = 0;
255 256 }
256 257
257 258 void QBarModelMapperPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
258 259 {
259 260 Q_UNUSED(topLeft)
260 261 Q_UNUSED(bottomRight)
261 262
262 263 if (m_model == 0 || m_series == 0)
263 264 return;
264 265
265 266 if (m_modelSignalsBlock)
266 267 return;
267 268
268 269 blockSeriesSignals();
269 270 QModelIndex index;
270 271 for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
271 272 for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
272 273 index = topLeft.sibling(row, column);
273 274 QBarSet* bar = barSet(index);
274 275 if (bar) {
275 276 if (m_orientation == Qt::Vertical)
276 277 bar->replace(row - m_first, m_model->data(index).toReal());
277 278 else
278 279 bar->replace(column - m_first, m_model->data(index).toReal());
279 280 }
280 281 }
281 282 }
282 283 blockSeriesSignals(false);
283 284 }
284 285
285 286 void QBarModelMapperPrivate::modelHeaderDataUpdated(Qt::Orientation orientation, int first, int last)
286 287 {
287 288 if (m_model == 0 || m_series == 0)
288 289 return;
289 290
290 291 if (m_modelSignalsBlock)
291 292 return;
292 293
293 294 blockSeriesSignals();
294 295 if (orientation != m_orientation) {
295 296 for (int section = first; section <= last; section++) {
296 297 if (section >= m_firstBarSetSection && section <= m_lastBarSetSection) {
297 298 QBarSet* bar = m_series->barSets().at(section - m_firstBarSetSection);
298 299 if (bar)
299 300 bar->setLabel(m_model->headerData(section, orientation).toString());
300 301 }
301 302 }
302 303 }
303 304 blockSeriesSignals(false);
304 305 }
305 306
306 307 void QBarModelMapperPrivate::modelRowsAdded(QModelIndex parent, int start, int end)
307 308 {
308 309 Q_UNUSED(parent);
309 310 Q_UNUSED(end)
310 311 if (m_modelSignalsBlock)
311 312 return;
312 313
313 314 blockSeriesSignals();
314 315 if (m_orientation == Qt::Vertical)
315 316 // insertData(start, end);
316 317 initializeBarFromModel();
317 318 else if (start <= m_firstBarSetSection || start <= m_lastBarSetSection) // if the changes affect the map - reinitialize
318 319 initializeBarFromModel();
319 320 blockSeriesSignals(false);
320 321 }
321 322
322 323 void QBarModelMapperPrivate::modelRowsRemoved(QModelIndex parent, int start, int end)
323 324 {
324 325 Q_UNUSED(parent);
325 326 Q_UNUSED(end)
326 327 if (m_modelSignalsBlock)
327 328 return;
328 329
329 330 blockSeriesSignals();
330 331 if (m_orientation == Qt::Vertical)
331 332 // removeData(start, end);
332 333 initializeBarFromModel();
333 334 else if (start <= m_firstBarSetSection || start <= m_lastBarSetSection) // if the changes affect the map - reinitialize
334 335 initializeBarFromModel();
335 336 blockSeriesSignals(false);
336 337 }
337 338
338 339 void QBarModelMapperPrivate::modelColumnsAdded(QModelIndex parent, int start, int end)
339 340 {
340 341 Q_UNUSED(parent);
341 342 Q_UNUSED(end)
342 343 if (m_modelSignalsBlock)
343 344 return;
344 345
345 346 blockSeriesSignals();
346 347 if (m_orientation == Qt::Horizontal)
347 348 // insertData(start, end);
348 349 initializeBarFromModel();
349 350 else if (start <= m_firstBarSetSection || start <= m_lastBarSetSection) // if the changes affect the map - reinitialize
350 351 initializeBarFromModel();
351 352 blockSeriesSignals(false);
352 353 }
353 354
354 355 void QBarModelMapperPrivate::modelColumnsRemoved(QModelIndex parent, int start, int end)
355 356 {
356 357 Q_UNUSED(parent);
357 358 Q_UNUSED(end)
358 359 if (m_modelSignalsBlock)
359 360 return;
360 361
361 362 blockSeriesSignals();
362 363 if (m_orientation == Qt::Horizontal)
363 364 // removeData(start, end);
364 365 initializeBarFromModel();
365 366 else if (start <= m_firstBarSetSection || start <= m_lastBarSetSection) // if the changes affect the map - reinitialize
366 367 initializeBarFromModel();
367 368 blockSeriesSignals(false);
368 369 }
369 370
370 371 void QBarModelMapperPrivate::handleModelDestroyed()
371 372 {
372 373 m_model = 0;
373 374 }
374 375
375 376 void QBarModelMapperPrivate::insertData(int start, int end)
376 377 {
377 378 Q_UNUSED(end)
378 379 Q_UNUSED(start)
379 380 Q_UNUSED(end)
380 381 // To be implemented
381 382 }
382 383
383 384 void QBarModelMapperPrivate::removeData(int start, int end)
384 385 {
385 386 Q_UNUSED(end)
386 387 Q_UNUSED(start)
387 388 Q_UNUSED(end)
388 389 // To be implemented
389 390 }
390 391
391 392 void QBarModelMapperPrivate::barSetsAdded(QList<QBarSet*> sets)
392 393 {
393 394 if (m_seriesSignalsBlock)
394 395 return;
395 396
396 397 if (sets.count() == 0)
397 398 return;
398 399
399 400 int firstIndex = m_series->barSets().indexOf(sets.at(0));
400 401 if (firstIndex == -1)
401 402 return;
402 403
403 404 int maxCount = 0;
404 405 for(int i = 0; i < sets.count(); i++)
405 406 if (sets.at(i)->count() > m_count)
406 407 maxCount = sets.at(i)->count();
407 408
408 409 if (m_count != -1 && m_count < maxCount)
409 410 m_count = maxCount;
410 411
411 412 m_lastBarSetSection += sets.count();
412 413
413 414 blockModelSignals();
414 415 int modelCapacity = m_orientation == Qt::Vertical ? m_model->rowCount() - m_first : m_model->columnCount() - m_first;
415 416 if (maxCount > modelCapacity) {
416 417 if (m_orientation == Qt::Vertical)
417 418 m_model->insertRows(m_model->rowCount(), maxCount - modelCapacity);
418 419 else
419 420 m_model->insertColumns(m_model->columnCount(), maxCount - modelCapacity);
420 421 }
421 422
422 423 if (m_orientation == Qt::Vertical)
423 424 m_model->insertColumns(firstIndex + m_firstBarSetSection, sets.count());
424 425 else
425 426 m_model->insertRows(firstIndex + m_firstBarSetSection, sets.count());
426 427
427 428
428 429 for(int i = firstIndex + m_firstBarSetSection; i < firstIndex + m_firstBarSetSection + sets.count(); i++) {
429 430 m_model->setHeaderData(i, m_orientation == Qt::Vertical ? Qt::Horizontal : Qt::Vertical, sets.at(i - firstIndex - m_firstBarSetSection)->label());
430 431 for (int j = 0; j < sets.at(i - firstIndex - m_firstBarSetSection)->count(); j++)
431 432 m_model->setData(barModelIndex(i, j), sets.at(i - firstIndex - m_firstBarSetSection)->at(j));
432 433 }
433 434 blockModelSignals(false);
434 435 initializeBarFromModel();
435 436 }
436 437
437 438 void QBarModelMapperPrivate::barSetsRemoved(QList<QBarSet*> sets)
438 439 {
439 440 if (m_seriesSignalsBlock)
440 441 return;
441 442
442 443 if (sets.count() == 0)
443 444 return;
444 445
445 446 int firstIndex = m_barSets.indexOf(sets.at(0));
446 447 if (firstIndex == -1)
447 448 return;
448 449
449 450 m_lastBarSetSection -= sets.count();
450 451
451 452 for (int i = firstIndex + sets.count() - 1; i >= firstIndex; i--)
452 453 m_barSets.removeAt(i);
453 454
454 455 blockModelSignals();
455 456 if (m_orientation == Qt::Vertical)
456 457 m_model->removeColumns(firstIndex + m_firstBarSetSection, sets.count());
457 458 else
458 459 m_model->removeRows(firstIndex + m_firstBarSetSection, sets.count());
459 460 blockModelSignals(false);
460 461 initializeBarFromModel();
461 462 }
462 463
463 464 void QBarModelMapperPrivate::valuesAdded(int index, int count)
464 465 {
465 466 if (m_seriesSignalsBlock)
466 467 return;
467 468
468 469 if (m_count != -1)
469 470 m_count += count;
470 471
471 472 int barSetIndex = m_barSets.indexOf(qobject_cast<QBarSet *>(QObject::sender()));
472 473
473 474 blockModelSignals();
474 475 if (m_orientation == Qt::Vertical)
475 476 m_model->insertRows(index + m_first, count);
476 477 else
477 478 m_model->insertColumns(index + m_first, count);
478 479
479 480 for (int j = index; j < index + count; j++)
480 481 m_model->setData(barModelIndex(barSetIndex + m_firstBarSetSection, j), m_barSets.at(barSetIndex)->at(j));
481 482
482 483 blockModelSignals(false);
483 484 initializeBarFromModel();
484 485 }
485 486
486 487 void QBarModelMapperPrivate::valuesRemoved(int index, int count)
487 488 {
488 489 if (m_seriesSignalsBlock)
489 490 return;
490 491
491 492 if (m_count != -1)
492 493 m_count -= count;
493 494
494 495 blockModelSignals();
495 496 if (m_orientation == Qt::Vertical)
496 497 m_model->removeRows(index + m_first, count);
497 498 else
498 499 m_model->removeColumns(index + m_first, count);
499 500
500 501 blockModelSignals(false);
501 502 initializeBarFromModel();
502 503 }
503 504
504 505 void QBarModelMapperPrivate::barLabelChanged()
505 506 {
506 507 if (m_seriesSignalsBlock)
507 508 return;
508 509
509 510 int barSetIndex = m_barSets.indexOf(qobject_cast<QBarSet *>(QObject::sender()));
510 511
511 512 blockModelSignals();
512 513 m_model->setHeaderData(barSetIndex + m_firstBarSetSection, m_orientation == Qt::Vertical ? Qt::Horizontal : Qt::Vertical, m_barSets.at(barSetIndex)->label());
513 514 blockModelSignals(false);
514 515 initializeBarFromModel();
515 516 }
516 517
517 518 void QBarModelMapperPrivate::barValueChanged(int index)
518 519 {
519 520 if (m_seriesSignalsBlock)
520 521 return;
521 522
522 523 int barSetIndex = m_barSets.indexOf(qobject_cast<QBarSet *>(QObject::sender()));
523 524
524 525 blockModelSignals();
525 526 m_model->setData(barModelIndex(barSetIndex + m_firstBarSetSection, index), m_barSets.at(barSetIndex)->at(index));
526 527 blockModelSignals(false);
527 528 initializeBarFromModel();
528 529 }
529 530
530 531 void QBarModelMapperPrivate::initializeBarFromModel()
531 532 {
532 533 if (m_model == 0 || m_series == 0)
533 534 return;
534 535
535 536 blockSeriesSignals();
536 537 // clear current content
537 538 m_series->clear();
538 539 m_barSets.clear();
539 540
540 541 // create the initial bar sets
541 542 for (int i = m_firstBarSetSection; i <= m_lastBarSetSection; i++) {
542 543 int posInBar = 0;
543 544 QModelIndex barIndex = barModelIndex(i, posInBar);
544 545 // check if there is such model index
545 546 if (barIndex.isValid()) {
546 547 QBarSet *barSet = new QBarSet(m_model->headerData(i, m_orientation == Qt::Vertical ? Qt::Horizontal : Qt::Vertical).toString());
547 548 while (barIndex.isValid()) {
548 549 barSet->append(m_model->data(barIndex, Qt::DisplayRole).toDouble());
549 550 posInBar++;
550 551 barIndex = barModelIndex(i, posInBar);
551 552 }
552 553 connect(barSet, SIGNAL(valuesAdded(int, int)), this, SLOT(valuesAdded(int, int)));
553 554 connect(barSet, SIGNAL(valuesRemoved(int, int)), this, SLOT(valuesRemoved(int, int)));
554 555 connect(barSet, SIGNAL(valueChanged(int)), this, SLOT(barValueChanged(int)));
555 556 connect(barSet, SIGNAL(labelChanged()), this, SLOT(barLabelChanged()));
556 557 m_series->append(barSet);
557 558 m_barSets.append(barSet);
558 559 } else {
559 560 break;
560 561 }
561 562 }
562 563 blockSeriesSignals(false);
563 564 }
564 565
565 566 #include "moc_qbarmodelmapper.cpp"
566 567 #include "moc_qbarmodelmapper_p.cpp"
567 568
568 569 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,27 +1,29
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 $$PWD/qhpiemodelmapper.cpp
11 $$PWD/qhpiemodelmapper.cpp \
12 piechart/qdonutgroup.cpp
12 13
13 14 PRIVATE_HEADERS += \
14 15 $$PWD/pieslicedata_p.h \
15 16 $$PWD/piechartitem_p.h \
16 17 $$PWD/piesliceitem_p.h \
17 18 $$PWD/qpieslice_p.h \
18 19 $$PWD/qpieseries_p.h \
19 $$PWD/qpiemodelmapper_p.h
20 $$PWD/qpiemodelmapper_p.h \
21 $$PWD/qdonutgroup_p.h
20 22
21 23 PUBLIC_HEADERS += \
22 24 $$PWD/qpieseries.h \
23 25 $$PWD/qpieslice.h \
24 26 $$PWD/qpiemodelmapper.h \
25 27 $$PWD/qvpiemodelmapper.h \
26 $$PWD/qhpiemodelmapper.h
27
28 $$PWD/qhpiemodelmapper.h \
29 $$PWD/qdonutgroup.h
@@ -1,223 +1,226
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 24 #include "qpieslice_p.h"
25 25 #include "qpieseries.h"
26 26 #include "qpieseries_p.h"
27 27 #include "chartpresenter_p.h"
28 28 #include "chartdataset_p.h"
29 29 #include "chartanimator_p.h"
30 30 #include <QPainter>
31 31 #include <QTimer>
32 32
33 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
34 34
35 35 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
36 36 :ChartItem(presenter),
37 37 m_series(series)
38 38 {
39 39 Q_ASSERT(series);
40 40
41 41 QPieSeriesPrivate *p = QPieSeriesPrivate::fromSeries(series);
42 42 connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
43 43 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
44 44 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
45 45 connect(p, SIGNAL(horizontalPositionChanged()), this, SLOT(updateLayout()));
46 46 connect(p, SIGNAL(verticalPositionChanged()), this, SLOT(updateLayout()));
47 47 connect(p, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
48 48 connect(p, SIGNAL(calculatedDataChanged()), this, SLOT(updateLayout()));
49 49
50 50 // Note: the following does not affect as long as the item does not have anything to paint
51 51 setZValue(ChartPresenter::PieSeriesZValue);
52 52
53 53 // Note: will not create slice items until we have a proper rectangle to draw on.
54 54 }
55 55
56 56 PieChartItem::~PieChartItem()
57 57 {
58 58 // slices deleted automatically through QGraphicsItem
59 59 }
60 60
61 61 void PieChartItem::handleGeometryChanged(const QRectF& rect)
62 62 {
63 63 prepareGeometryChange();
64 64 m_rect = rect;
65 65 updateLayout();
66 66
67 67 // This is for delayed initialization of the slice items during startup.
68 68 // It ensures that startup animation originates from the correct position.
69 69 if (m_sliceItems.isEmpty())
70 70 handleSlicesAdded(m_series->slices());
71 71 }
72 72
73 73 void PieChartItem::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY)
74 74 {
75 75 Q_UNUSED(minX);
76 76 Q_UNUSED(maxX);
77 77 Q_UNUSED(minY);
78 78 Q_UNUSED(maxY);
79 79 // does not apply to pie
80 80 }
81 81
82 82 void PieChartItem::rangeXChanged(qreal min, qreal max, int tickXCount)
83 83 {
84 84 Q_UNUSED(min);
85 85 Q_UNUSED(max);
86 86 Q_UNUSED(tickXCount);
87 87 // does not apply to pie
88 88 }
89 89
90 90 void PieChartItem::rangeYChanged(qreal min, qreal max, int tickYCount)
91 91 {
92 92 Q_UNUSED(min);
93 93 Q_UNUSED(max);
94 94 Q_UNUSED(tickYCount);
95 95 // does not apply to pie
96 96 }
97 97
98 98 void PieChartItem::updateLayout()
99 99 {
100 100 // find pie center coordinates
101 101 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
102 102 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
103 103
104 104 // find maximum radius for pie
105 105 m_pieRadius = m_rect.height() / 2;
106 106 if (m_rect.width() < m_rect.height())
107 107 m_pieRadius = m_rect.width() / 2;
108 108
109 m_donutInnerRadius = m_pieRadius;
109 110 // apply size factor
110 111 m_pieRadius *= m_series->pieSize();
112 m_donutInnerRadius *= m_series->donutInnerSize();
111 113
112 114 // set layouts for existing slice items
113 115 foreach (QPieSlice* slice, m_series->slices()) {
114 116 PieSliceItem *sliceItem = m_sliceItems.value(slice);
115 117 if (sliceItem) {
116 118 PieSliceData sliceData = updateSliceGeometry(slice);
117 119 if (animator())
118 120 animator()->updateAnimation(this, sliceItem, sliceData);
119 121 else
120 122 sliceItem->setLayout(sliceData);
121 123 }
122 124 }
123 125
124 126 update();
125 127 }
126 128
127 129 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
128 130 {
129 131 // delay creating slice items until there is a proper rectangle
130 132 if (!m_rect.isValid() && m_sliceItems.isEmpty())
131 133 return;
132 134
133 135 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
134 136
135 137 bool startupAnimation = m_sliceItems.isEmpty();
136 138
137 139 foreach (QPieSlice *slice, slices) {
138 140 PieSliceItem* sliceItem = new PieSliceItem(this);
139 141 m_sliceItems.insert(slice, sliceItem);
140 142
141 143 // Note: no need to connect to slice valueChanged() etc.
142 144 // This is handled through calculatedDataChanged signal.
143 145 connect(slice, SIGNAL(labelChanged()), this, SLOT(handleSliceChanged()));
144 146 connect(slice, SIGNAL(labelVisibleChanged()), this, SLOT(handleSliceChanged()));
145 147 connect(slice, SIGNAL(penChanged()), this, SLOT(handleSliceChanged()));
146 148 connect(slice, SIGNAL(brushChanged()), this, SLOT(handleSliceChanged()));
147 149 connect(slice, SIGNAL(labelBrushChanged()), this, SLOT(handleSliceChanged()));
148 150 connect(slice, SIGNAL(labelFontChanged()), this, SLOT(handleSliceChanged()));
149 151
150 152 QPieSlicePrivate *p = QPieSlicePrivate::fromSlice(slice);
151 153 connect(p, SIGNAL(labelPositionChanged()), this, SLOT(handleSliceChanged()));
152 154 connect(p, SIGNAL(explodedChanged()), this, SLOT(handleSliceChanged()));
153 155 connect(p, SIGNAL(labelArmLengthFactorChanged()), this, SLOT(handleSliceChanged()));
154 156 connect(p, SIGNAL(explodeDistanceFactorChanged()), this, SLOT(handleSliceChanged()));
155 157
156 158 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
157 159 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
158 160
159 161 PieSliceData sliceData = updateSliceGeometry(slice);
160 162 if (animator())
161 163 animator()->addAnimation(this, sliceItem, sliceData, startupAnimation);
162 164 else
163 165 sliceItem->setLayout(sliceData);
164 166 }
165 167 }
166 168
167 169 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
168 170 {
169 171 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
170 172
171 173 foreach (QPieSlice *slice, slices) {
172 174
173 175 PieSliceItem *sliceItem = m_sliceItems.value(slice);
174 176
175 177 // this can happen if you call append() & remove() in a row so that PieSliceItem is not even created
176 178 if (!sliceItem)
177 179 continue;
178 180
179 181 m_sliceItems.remove(slice);
180 182
181 183 if (animator())
182 184 animator()->removeAnimation(this, sliceItem); // animator deletes the PieSliceItem
183 185 else
184 186 delete sliceItem;
185 187 }
186 188 }
187 189
188 190 void PieChartItem::handleSliceChanged()
189 191 {
190 192 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
191 193 if (!slice) {
192 194 QPieSlicePrivate* slicep = qobject_cast<QPieSlicePrivate *>(sender());
193 195 slice = slicep->q_ptr;
194 196 }
195 197 Q_ASSERT(m_sliceItems.contains(slice));
196 198
197 199 PieSliceItem *sliceItem = m_sliceItems.value(slice);
198 200 PieSliceData sliceData = updateSliceGeometry(slice);
199 201 if (animator())
200 202 animator()->updateAnimation(this, sliceItem, sliceData);
201 203 else
202 204 sliceItem->setLayout(sliceData);
203 205
204 206 update();
205 207 }
206 208
207 209 void PieChartItem::handleSeriesVisibleChanged()
208 210 {
209 211 setVisible(m_series->isVisible());
210 212 }
211 213
212 214 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
213 215 {
214 216 PieSliceData &sliceData = QPieSlicePrivate::fromSlice(slice)->m_data;
215 217 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
216 218 sliceData.m_radius = m_pieRadius;
217 219 sliceData.m_donut = m_series->donut();
220 sliceData.m_innerRadius = m_donutInnerRadius;
218 221 return sliceData;
219 222 }
220 223
221 224 #include "moc_piechartitem_p.cpp"
222 225
223 226 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,80 +1,81
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 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef PIECHARTITEM_H
31 31 #define PIECHARTITEM_H
32 32
33 33 #include "qpieseries.h"
34 34 #include "chartitem_p.h"
35 35 #include "piesliceitem_p.h"
36 36
37 37 class QGraphicsItem;
38 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39 39 class QPieSlice;
40 40 class ChartPresenter;
41 41
42 42 class PieChartItem : public ChartItem
43 43 {
44 44 Q_OBJECT
45 45
46 46 public:
47 47 explicit PieChartItem(QPieSeries *series, ChartPresenter *presenter);
48 48 ~PieChartItem();
49 49
50 50 // from QGraphicsItem
51 51 QRectF boundingRect() const { return m_rect; }
52 52 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
53 53
54 54 public Q_SLOTS:
55 55 // from Chart
56 56 virtual void handleGeometryChanged(const QRectF &rect);
57 57 virtual void handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY);
58 58 virtual void rangeXChanged(qreal min, qreal max, int tickXCount);
59 59 virtual void rangeYChanged(qreal min, qreal max, int tickYCount);
60 60
61 61 void updateLayout();
62 62 void handleSlicesAdded(QList<QPieSlice*> slices);
63 63 void handleSlicesRemoved(QList<QPieSlice*> slices);
64 64 void handleSliceChanged();
65 65 void handleSeriesVisibleChanged();
66 66
67 67 private:
68 68 PieSliceData updateSliceGeometry(QPieSlice *slice);
69 69
70 70 private:
71 71 QHash<QPieSlice*, PieSliceItem*> m_sliceItems;
72 72 QPieSeries *m_series;
73 73 QRectF m_rect;
74 74 QPointF m_pieCenter;
75 75 qreal m_pieRadius;
76 qreal m_donutInnerRadius;
76 77 };
77 78
78 79 QTCOMMERCIALCHART_END_NAMESPACE
79 80
80 81 #endif // PIECHARTITEM_H
@@ -1,144 +1,148
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 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef PIESLICEDATA_P_H
31 31 #define PIESLICEDATA_P_H
32 32
33 33 #include "qchartglobal.h"
34 34 #include "qpieslice.h"
35 35 #include <QPen>
36 36 #include <QBrush>
37 37
38 38 QTCOMMERCIALCHART_BEGIN_NAMESPACE
39 39
40 40 template <class T>
41 41 class Themed : public T
42 42 {
43 43 public:
44 44 Themed():m_isThemed(true) {}
45 45
46 46 inline T &operator=(const T &other) { return T::operator =(other); }
47 47
48 48 inline bool operator!=(const T &other) const { return T::operator !=(other); }
49 49 inline bool operator!=(const Themed &other) const
50 50 {
51 51 if (T::operator !=(other))
52 52 return true;
53 53
54 54 if (m_isThemed != other.m_isThemed)
55 55 return true;
56 56
57 57 return false;
58 58 }
59 59
60 60 inline void setThemed(bool state) { m_isThemed = state; }
61 61 inline bool isThemed() const { return m_isThemed; }
62 62
63 63 private:
64 64 bool m_isThemed;
65 65 };
66 66
67 67 class PieSliceData
68 68 {
69 69 public:
70 70 PieSliceData()
71 71 {
72 72 m_value = 0;
73 73
74 74 m_isExploded = false;
75 75 m_explodeDistanceFactor = 0.15;
76 76
77 77 m_isLabelVisible = false;
78 78 m_labelPosition = QPieSlice::LabelOutside;
79 79 m_labelArmLengthFactor = 0.15;
80 80
81 81 m_percentage = 0;
82 82 m_radius = 0;
83 83 m_startAngle = 0;
84 84 m_angleSpan = 0;
85
85 86 m_donut = false;
87 m_innerRadius = 0;
86 88 }
87 89
88 90 bool operator!=(const PieSliceData &other) const
89 91 {
90 92 if (!qFuzzyIsNull(m_value - other.m_value))
91 93 return true;
92 94
93 95 if (m_slicePen != other.m_slicePen ||
94 96 m_sliceBrush != other.m_sliceBrush)
95 97 return true;
96 98
97 99 if (m_isExploded != other.m_isExploded ||
98 100 !qFuzzyIsNull(m_explodeDistanceFactor - other.m_explodeDistanceFactor))
99 101 return true;
100 102
101 103 if (m_isLabelVisible != other.m_isLabelVisible ||
102 104 m_labelText != other.m_labelText ||
103 105 m_labelFont != other.m_labelFont ||
104 106 m_labelPosition != other.m_labelPosition ||
105 107 !qFuzzyIsNull(m_labelArmLengthFactor - other.m_labelArmLengthFactor) ||
106 108 m_labelBrush != other.m_labelBrush)
107 109 return true;
108 110
109 111 if (!qFuzzyIsNull(m_percentage - other.m_percentage) ||
110 112 m_center != other.m_center ||
111 113 !qFuzzyIsNull(m_radius - other.m_radius) ||
112 114 !qFuzzyIsNull(m_startAngle - other.m_startAngle) ||
113 115 !qFuzzyIsNull(m_angleSpan - other.m_angleSpan))
114 116 return true;
115 117
116 118 return false;
117 119 }
118 120
119 121 qreal m_value;
120 122
121 123 Themed<QPen> m_slicePen;
122 124 Themed<QBrush> m_sliceBrush;
123 125
124 126 bool m_isExploded;
125 127 qreal m_explodeDistanceFactor;
126 128
127 129 bool m_isLabelVisible;
128 130 QString m_labelText;
129 131 Themed<QFont> m_labelFont;
130 132 QPieSlice::LabelPosition m_labelPosition;
131 133 qreal m_labelArmLengthFactor;
132 134 Themed<QBrush> m_labelBrush;
133 135
134 136 qreal m_percentage;
135 137 QPointF m_center;
136 138 qreal m_radius;
137 139 qreal m_startAngle;
138 140 qreal m_angleSpan;
141
139 142 bool m_donut;
143 qreal m_innerRadius;
140 144 };
141 145
142 146 QTCOMMERCIALCHART_END_NAMESPACE
143 147
144 148 #endif // PIESLICEDATA_P_H
@@ -1,242 +1,241
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 #include <QDebug>
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 QPointF offset(qreal angle, qreal length)
35 35 {
36 36 qreal dx = qSin(angle*(M_PI/180)) * length;
37 37 qreal dy = qCos(angle*(M_PI/180)) * length;
38 38 return QPointF(dx, -dy);
39 39 }
40 40
41 41 PieSliceItem::PieSliceItem(QGraphicsItem* parent)
42 42 :QGraphicsObject(parent),
43 43 m_hovered(false)
44 44 {
45 45 setAcceptHoverEvents(true);
46 46 setAcceptedMouseButtons(Qt::MouseButtonMask);
47 47 setZValue(ChartPresenter::PieSeriesZValue);
48 48 }
49 49
50 50 PieSliceItem::~PieSliceItem()
51 51 {
52 52 // If user is hovering over the slice and it gets destroyed we do
53 53 // not get a hover leave event. So we must emit the signal here.
54 54 if (m_hovered)
55 55 emit hovered(false);
56 56 }
57 57
58 58 QRectF PieSliceItem::boundingRect() const
59 59 {
60 60 return m_boundingRect;
61 61 }
62 62
63 63 QPainterPath PieSliceItem::shape() const
64 64 {
65 65 // Don't include the label and label arm.
66 66 // This is used to detect a mouse clicks. We do not want clicks from label.
67 67 return m_slicePath;
68 68 }
69 69
70 70 void PieSliceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
71 71 {
72 72 painter->save();
73 73 painter->setClipRect(parentItem()->boundingRect());
74 74 painter->setPen(m_data.m_slicePen);
75 75 painter->setBrush(m_data.m_sliceBrush);
76 76 painter->drawPath(m_slicePath);
77 77 painter->restore();
78 78
79 79 if (m_data.m_isLabelVisible) {
80 80 painter->save();
81 81
82 82 // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
83 83 // Also, the drawText actually uses the pen color for the text color (unlike QGraphicsSimpleTextItem)
84 84 painter->setPen(m_data.m_labelBrush.color());
85 85 painter->setBrush(m_data.m_labelBrush);
86 86 painter->setFont(m_data.m_labelFont);
87 87 if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
88 88 painter->setClipRect(parentItem()->boundingRect());
89 89 painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
90 90 } else { // QPieSlice::LabelInside
91 91 painter->setClipPath(m_slicePath);
92 92 }
93 93 painter->drawText(m_labelTextRect, Qt::AlignCenter, m_data.m_labelText);
94 94
95 95 painter->restore();
96 96 }
97 97 }
98 98
99 99 void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
100 100 {
101 101 m_hovered = true;
102 102 emit hovered(true);
103 103 }
104 104
105 105 void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
106 106 {
107 107 m_hovered = false;
108 108 emit hovered(false);
109 109 }
110 110
111 111 void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
112 112 {
113 113 emit clicked(event->buttons());
114 114 }
115 115
116 116 void PieSliceItem::setLayout(const PieSliceData &sliceData)
117 117 {
118 118 m_data = sliceData;
119 119 updateGeometry();
120 120 update();
121 121 }
122 122
123 123 void PieSliceItem::updateGeometry()
124 124 {
125 125 if (m_data.m_radius <= 0)
126 126 return;
127 127
128 128 prepareGeometryChange();
129 129
130 130 // slice path
131 131 qreal centerAngle;
132 132 QPointF armStart;
133 133 m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
134 134
135 135 // text rect
136 136 QFontMetricsF fm(m_data.m_labelFont);
137 137 m_labelTextRect = QRectF(0, 0, fm.width(m_data.m_labelText), fm.height());
138 138
139 139 // label arm path
140 140 QPointF labelTextStart;
141 141 m_labelArmPath = labelArmPath(armStart, centerAngle, m_data.m_radius * m_data.m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart);
142 142
143 143 // text position
144 144 if (m_data.m_labelPosition == QPieSlice::LabelOutside)
145 145 m_labelTextRect.moveBottomLeft(labelTextStart);
146 146 else {// QPieSlice::LabelInside
147 147 QPointF sliceCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
148 148 m_labelTextRect.moveCenter(sliceCenter);
149 149 }
150 150
151 151 // bounding rect
152 152 if (m_data.m_isLabelVisible)
153 153 m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
154 154 else
155 155 m_boundingRect = m_slicePath.boundingRect();
156 156 }
157 157
158 158 QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
159 159 {
160 160 if (slice->isExploded()) {
161 161 qreal centerAngle = slice->startAngle() + (slice->angleSpan()/2);
162 162 qreal len = radius * slice->explodeDistanceFactor();
163 163 point += offset(centerAngle, len);
164 164 }
165 165 return point;
166 166 }
167 167
168 168 QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF* armStart)
169 169 {
170 170 // calculate center angle
171 171 *centerAngle = startAngle + (angleSpan/2);
172 172
173 173 // calculate slice rectangle
174 174 QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2);
175 175
176 176 // slice path
177 177 QPainterPath path;
178 178 if (m_data.m_donut) {
179 qreal donutFraction = 5.0;
180 QRectF insideRect = rect.adjusted(rect.width() / donutFraction, rect.height() / donutFraction, -rect.width() / donutFraction, -rect.height() / donutFraction);
179 QRectF insideRect(center.x() - m_data.m_innerRadius, center.y()-m_data.m_innerRadius, m_data.m_innerRadius*2, m_data.m_innerRadius*2);
181 180 path.arcMoveTo(rect, -startAngle + 90);
182 181 path.arcTo(rect, -startAngle + 90, -angleSpan);
183 182 path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
184 183 path.closeSubpath();
185 184 } else {
186 185 path.moveTo(rect.center());
187 186 path.arcTo(rect, -startAngle + 90, -angleSpan);
188 187 path.closeSubpath();
189 188 }
190 189
191 190 // calculate label arm start point
192 191 *armStart = center;
193 192 *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
194 193
195 194 return path;
196 195 }
197 196
198 197 QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
199 198 {
200 199 // Normalize the angle to 0-360 range
201 200 // NOTE: We are using int here on purpose. Depenging on platform and hardware
202 201 // qreal can be a double, float or something the user gives to the Qt configure
203 202 // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
204 203 // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
205 204 // that might break we just use int. Precision for this is just fine for our needs.
206 205 int normalized = angle * 10.0;
207 206 normalized = normalized % 3600;
208 207 if (normalized < 0)
209 208 normalized += 3600;
210 209 angle = (qreal) normalized / 10.0;
211 210
212 211 // prevent label arm pointing straight down because it will look bad
213 212 if (angle < 180 && angle > 170)
214 213 angle = 170;
215 214 if (angle > 180 && angle < 190)
216 215 angle = 190;
217 216
218 217 // line from slice to label
219 218 QPointF parm1 = start + offset(angle, length);
220 219
221 220 // line to underline the label
222 221 QPointF parm2 = parm1;
223 222 if (angle < 180) { // arm swings the other way on the left side
224 223 parm2 += QPointF(textWidth, 0);
225 224 *textStart = parm1;
226 225 }
227 226 else {
228 227 parm2 += QPointF(-textWidth,0);
229 228 *textStart = parm2;
230 229 }
231 230
232 231 QPainterPath path;
233 232 path.moveTo(start);
234 233 path.lineTo(parm1);
235 234 path.lineTo(parm2);
236 235
237 236 return path;
238 237 }
239 238
240 239 #include "moc_piesliceitem_p.cpp"
241 240
242 241 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,567 +1,568
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 "qpiemodelmapper_p.h"
22 22 #include "qpiemodelmapper.h"
23 23 #include "qpieseries.h"
24 24 #include "qpieslice.h"
25 25 #include <QAbstractItemModel>
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28
29 29 QPieModelMapper::QPieModelMapper(QObject *parent) :
30 30 QObject(parent),
31 31 d_ptr(new QPieModelMapperPrivate(this))
32 32 {
33 33 }
34 34
35 35 QAbstractItemModel* QPieModelMapper::model() const
36 36 {
37 37 Q_D(const QPieModelMapper);
38 38 return d->m_model;
39 39 }
40 40
41 41 void QPieModelMapper::setModel(QAbstractItemModel *model)
42 42 {
43 43 if (model == 0)
44 44 return;
45 45
46 46 Q_D(QPieModelMapper);
47 47 if (d->m_model) {
48 48 disconnect(d->m_model, 0, d, 0);
49 49 }
50 50
51 51 d->m_model = model;
52 52 d->initializePieFromModel();
53 53 // connect signals from the model
54 54 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
55 55 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelRowsAdded(QModelIndex,int,int)));
56 56 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelRowsRemoved(QModelIndex,int,int)));
57 57 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelColumnsAdded(QModelIndex,int,int)));
58 58 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelColumnsRemoved(QModelIndex,int,int)));
59 59 connect(d->m_model, SIGNAL(destroyed()), d, SLOT(handleModelDestroyed()));
60 60 }
61 61
62 62 QPieSeries* QPieModelMapper::series() const
63 63 {
64 64 Q_D(const QPieModelMapper);
65 65 return d->m_series;
66 66 }
67 67
68 68 void QPieModelMapper::setSeries(QPieSeries *series)
69 69 {
70 70 Q_D(QPieModelMapper);
71 71 if (d->m_series) {
72 72 disconnect(d->m_series, 0, d, 0);
73 73 }
74 74
75 75 if (series == 0)
76 76 return;
77 77
78 78 d->m_series = series;
79 79 d->initializePieFromModel();
80 80 // connect the signals from the series
81 81 connect(d->m_series, SIGNAL(added(QList<QPieSlice*>)), d, SLOT(slicesAdded(QList<QPieSlice*>)));
82 82 connect(d->m_series, SIGNAL(removed(QList<QPieSlice*>)), d, SLOT(slicesRemoved(QList<QPieSlice*>)));
83 83 connect(d->m_series, SIGNAL(destroyed()), d, SLOT(handleSeriesDestroyed()));
84 84 }
85 85
86 86 /*!
87 87 Defines which row/column of the model contains the first slice value.
88 88 Minimal and default value is: 0
89 89 */
90 90 int QPieModelMapper::first() const
91 91 {
92 92 Q_D(const QPieModelMapper);
93 93 return d->m_first;
94 94 }
95 95
96 96 /*!
97 97 Sets which row/column of the model contains the \a first slice value.
98 98 Minimal and default value is: 0
99 99 */
100 100 void QPieModelMapper::setFirst(int first)
101 101 {
102 102 Q_D(QPieModelMapper);
103 103 d->m_first = qMax(first, 0);
104 104 d->initializePieFromModel();
105 105 }
106 106
107 107 /*!
108 108 Defines the number of rows/columns of the model that are mapped as the data for QPieSeries
109 109 Minimal and default value is: -1 (count limited by the number of rows/columns in the model)
110 110 */
111 111 int QPieModelMapper::count() const
112 112 {
113 113 Q_D(const QPieModelMapper);
114 114 return d->m_count;
115 115 }
116 116
117 117 /*!
118 118 Defines the \a count of rows/columns of the model that are mapped as the data for QPieSeries
119 119 Minimal and default value is: -1 (count limited by the number of rows/columns in the model)
120 120 */
121 121 void QPieModelMapper::setCount(int count)
122 122 {
123 123 Q_D(QPieModelMapper);
124 124 d->m_count = qMax(count, -1);
125 125 d->initializePieFromModel();
126 126 }
127 127
128 128 /*!
129 129 Returns the orientation that is used when QPieModelMapper accesses the model.
130 130 This mean whether the consecutive values/labels of the pie are read from row (Qt::Horizontal)
131 131 or from columns (Qt::Vertical)
132 132 */
133 133 Qt::Orientation QPieModelMapper::orientation() const
134 134 {
135 135 Q_D(const QPieModelMapper);
136 136 return d->m_orientation;
137 137 }
138 138
139 139 /*!
140 140 Returns the \a orientation that is used when QPieModelMapper accesses the model.
141 141 This mean whether the consecutive values/labels of the pie are read from row (Qt::Horizontal)
142 142 or from columns (Qt::Vertical)
143 143 */
144 144 void QPieModelMapper::setOrientation(Qt::Orientation orientation)
145 145 {
146 146 Q_D(QPieModelMapper);
147 147 d->m_orientation = orientation;
148 148 d->initializePieFromModel();
149 149 }
150 150
151 151 /*!
152 152 Returns which section of the model is kept in sync with the values of the pie's slices
153 153 */
154 154 int QPieModelMapper::valuesSection() const
155 155 {
156 156 Q_D(const QPieModelMapper);
157 157 return d->m_valuesSection;
158 158 }
159 159
160 160 /*!
161 161 Sets the model section that is kept in sync with the pie slices values.
162 162 Parameter \a valuesSection specifies the section of the model.
163 163 */
164 164 void QPieModelMapper::setValuesSection(int valuesSection)
165 165 {
166 166 Q_D(QPieModelMapper);
167 167 d->m_valuesSection = qMax(-1, valuesSection);
168 168 d->initializePieFromModel();
169 169 }
170 170
171 171 /*!
172 172 Returns which section of the model is kept in sync with the labels of the pie's slices
173 173 */
174 174 int QPieModelMapper::labelsSection() const
175 175 {
176 176 Q_D(const QPieModelMapper);
177 177 return d->m_labelsSection;
178 178 }
179 179
180 180 /*!
181 181 Sets the model section that is kept in sync with the pie slices labels.
182 182 Parameter \a labelsSection specifies the section of the model.
183 183 */
184 184 void QPieModelMapper::setLabelsSection(int labelsSection)
185 185 {
186 186 Q_D(QPieModelMapper);
187 187 d->m_labelsSection = qMax(-1, labelsSection);
188 188 d->initializePieFromModel();
189 189 }
190 190
191 191 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
192 192
193 193 QPieModelMapperPrivate::QPieModelMapperPrivate(QPieModelMapper *q) :
194 QObject(q),
194 195 m_series(0),
195 196 m_model(0),
196 197 m_first(0),
197 198 m_count(-1),
198 199 m_orientation(Qt::Vertical),
199 200 m_valuesSection(-1),
200 201 m_labelsSection(-1),
201 202 m_seriesSignalsBlock(false),
202 203 m_modelSignalsBlock(false),
203 204 q_ptr(q)
204 205 {
205 206 }
206 207
207 208 void QPieModelMapperPrivate::blockModelSignals(bool block)
208 209 {
209 210 m_modelSignalsBlock = block;
210 211 }
211 212
212 213 void QPieModelMapperPrivate::blockSeriesSignals(bool block)
213 214 {
214 215 m_seriesSignalsBlock = block;
215 216 }
216 217
217 218
218 219 QPieSlice* QPieModelMapperPrivate::pieSlice(QModelIndex index) const
219 220 {
220 221 if (!index.isValid())
221 222 return 0; // index is invalid
222 223
223 224 if (m_orientation == Qt::Vertical && (index.column() == m_valuesSection || index.column() == m_labelsSection)) {
224 225 if (index.row() >= m_first && (m_count == - 1 || index.row() < m_first + m_count)) {
225 226 if (m_model->index(index.row(), m_valuesSection).isValid() && m_model->index(index.row(), m_labelsSection).isValid())
226 227 return m_series->slices().at(index.row() - m_first);
227 228 else
228 229 return 0;
229 230 }
230 231 } else if (m_orientation == Qt::Horizontal && (index.row() == m_valuesSection || index.row() == m_labelsSection)) {
231 232 if (index.column() >= m_first && (m_count == - 1 || index.column() < m_first + m_count)) {
232 233 if (m_model->index(m_valuesSection, index.column()).isValid() && m_model->index(m_labelsSection, index.column()).isValid())
233 234 return m_series->slices().at(index.column() - m_first);
234 235 else
235 236 return 0;
236 237 }
237 238 }
238 239 return 0; // This part of model has not been mapped to any slice
239 240 }
240 241
241 242 QModelIndex QPieModelMapperPrivate::valueModelIndex(int slicePos)
242 243 {
243 244 if (m_count != -1 && slicePos >= m_count)
244 245 return QModelIndex(); // invalid
245 246
246 247 if (m_orientation == Qt::Vertical)
247 248 return m_model->index(slicePos + m_first, m_valuesSection);
248 249 else
249 250 return m_model->index(m_valuesSection, slicePos + m_first);
250 251 }
251 252
252 253 QModelIndex QPieModelMapperPrivate::labelModelIndex(int slicePos)
253 254 {
254 255 if (m_count != -1 && slicePos >= m_count)
255 256 return QModelIndex(); // invalid
256 257
257 258 if (m_orientation == Qt::Vertical)
258 259 return m_model->index(slicePos + m_first, m_labelsSection);
259 260 else
260 261 return m_model->index(m_labelsSection, slicePos + m_first);
261 262 }
262 263
263 264 bool QPieModelMapperPrivate::isLabelIndex(QModelIndex index) const
264 265 {
265 266 if (m_orientation == Qt::Vertical && index.column() == m_labelsSection)
266 267 return true;
267 268 else if (m_orientation == Qt::Horizontal && index.row() == m_labelsSection)
268 269 return true;
269 270
270 271 return false;
271 272 }
272 273
273 274 bool QPieModelMapperPrivate::isValueIndex(QModelIndex index) const
274 275 {
275 276 if (m_orientation == Qt::Vertical && index.column() == m_valuesSection)
276 277 return true;
277 278 else if (m_orientation == Qt::Horizontal && index.row() == m_valuesSection)
278 279 return true;
279 280
280 281 return false;
281 282 }
282 283
283 284 void QPieModelMapperPrivate::slicesAdded(QList<QPieSlice*> slices)
284 285 {
285 286 if (m_seriesSignalsBlock)
286 287 return;
287 288
288 289 if (slices.count() == 0)
289 290 return;
290 291
291 292 int firstIndex = m_series->slices().indexOf(slices.at(0));
292 293 if (firstIndex == -1)
293 294 return;
294 295
295 296 if (m_count != -1)
296 297 m_count += slices.count();
297 298
298 299 for (int i = firstIndex; i < firstIndex + slices.count(); i++) {
299 300 m_slices.insert(i, slices.at(i - firstIndex));
300 301 connect(slices.at(i - firstIndex), SIGNAL(labelChanged()), this, SLOT(sliceLabelChanged()));
301 302 connect(slices.at(i - firstIndex), SIGNAL(valueChanged()), this, SLOT(sliceValueChanged()));
302 303 }
303 304
304 305 blockModelSignals();
305 306 if (m_orientation == Qt::Vertical)
306 307 m_model->insertRows(firstIndex + m_first, slices.count());
307 308 else
308 309 m_model->insertColumns(firstIndex + m_first, slices.count());
309 310
310 311 for(int i = firstIndex; i < firstIndex + slices.count(); i++) {
311 312 m_model->setData(valueModelIndex(i), slices.at(i - firstIndex)->value());
312 313 m_model->setData(labelModelIndex(i), slices.at(i - firstIndex)->label());
313 314 }
314 315 blockModelSignals(false);
315 316 }
316 317
317 318 void QPieModelMapperPrivate::slicesRemoved(QList<QPieSlice*> slices)
318 319 {
319 320 if (m_seriesSignalsBlock)
320 321 return;
321 322
322 323 if (slices.count() == 0)
323 324 return;
324 325
325 326 int firstIndex = m_slices.indexOf(slices.at(0));
326 327 if (firstIndex == -1)
327 328 return;
328 329
329 330 if (m_count != -1)
330 331 m_count -= slices.count();
331 332
332 333 for (int i = firstIndex + slices.count() - 1; i >= firstIndex; i--)
333 334 m_slices.removeAt(i);
334 335
335 336 blockModelSignals();
336 337 if (m_orientation == Qt::Vertical)
337 338 m_model->removeRows(firstIndex + m_first, slices.count());
338 339 else
339 340 m_model->removeColumns(firstIndex + m_first, slices.count());
340 341 blockModelSignals(false);
341 342 }
342 343
343 344 void QPieModelMapperPrivate::sliceLabelChanged()
344 345 {
345 346 if (m_seriesSignalsBlock)
346 347 return;
347 348
348 349 blockModelSignals();
349 350 QPieSlice *slice = qobject_cast<QPieSlice *>(QObject::sender());
350 351 m_model->setData(labelModelIndex(m_series->slices().indexOf(slice)), slice->label());
351 352 blockModelSignals(false);
352 353 }
353 354
354 355 void QPieModelMapperPrivate::sliceValueChanged()
355 356 {
356 357 if (m_seriesSignalsBlock)
357 358 return;
358 359
359 360 blockModelSignals();
360 361 QPieSlice *slice = qobject_cast<QPieSlice *>(QObject::sender());
361 362 m_model->setData(valueModelIndex(m_series->slices().indexOf(slice)), slice->value());
362 363 blockModelSignals(false);
363 364 }
364 365
365 366 void QPieModelMapperPrivate::handleSeriesDestroyed()
366 367 {
367 368 m_series = 0;
368 369 }
369 370
370 371 void QPieModelMapperPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
371 372 {
372 373 if (m_model == 0 || m_series == 0)
373 374 return;
374 375
375 376 if (m_modelSignalsBlock)
376 377 return;
377 378
378 379 blockSeriesSignals();
379 380 QModelIndex index;
380 381 QPieSlice *slice;
381 382 for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
382 383 for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
383 384 index = topLeft.sibling(row, column);
384 385 slice = pieSlice(index);
385 386 if (slice) {
386 387 if (isValueIndex(index))
387 388 slice->setValue(m_model->data(index, Qt::DisplayRole).toReal());
388 389 if (isLabelIndex(index))
389 390 slice->setLabel(m_model->data(index, Qt::DisplayRole).toString());
390 391 }
391 392 }
392 393 }
393 394 blockSeriesSignals(false);
394 395 }
395 396
396 397
397 398 void QPieModelMapperPrivate::modelRowsAdded(QModelIndex parent, int start, int end)
398 399 {
399 400 Q_UNUSED(parent);
400 401 if (m_modelSignalsBlock)
401 402 return;
402 403
403 404 blockSeriesSignals();
404 405 if (m_orientation == Qt::Vertical)
405 406 insertData(start, end);
406 407 else if (start <= m_valuesSection || start <= m_labelsSection) // if the changes affect the map - reinitialize the pie
407 408 initializePieFromModel();
408 409 blockSeriesSignals(false);
409 410 }
410 411
411 412 void QPieModelMapperPrivate::modelRowsRemoved(QModelIndex parent, int start, int end)
412 413 {
413 414 Q_UNUSED(parent);
414 415 if (m_modelSignalsBlock)
415 416 return;
416 417
417 418 blockSeriesSignals();
418 419 if (m_orientation == Qt::Vertical)
419 420 removeData(start, end);
420 421 else if (start <= m_valuesSection || start <= m_labelsSection) // if the changes affect the map - reinitialize the pie
421 422 initializePieFromModel();
422 423 blockSeriesSignals(false);
423 424 }
424 425
425 426 void QPieModelMapperPrivate::modelColumnsAdded(QModelIndex parent, int start, int end)
426 427 {
427 428 Q_UNUSED(parent);
428 429 if (m_modelSignalsBlock)
429 430 return;
430 431
431 432 blockSeriesSignals();
432 433 if (m_orientation == Qt::Horizontal)
433 434 insertData(start, end);
434 435 else if (start <= m_valuesSection || start <= m_labelsSection) // if the changes affect the map - reinitialize the pie
435 436 initializePieFromModel();
436 437 blockSeriesSignals(false);
437 438 }
438 439
439 440 void QPieModelMapperPrivate::modelColumnsRemoved(QModelIndex parent, int start, int end)
440 441 {
441 442 Q_UNUSED(parent);
442 443 if (m_modelSignalsBlock)
443 444 return;
444 445
445 446 blockSeriesSignals();
446 447 if (m_orientation == Qt::Horizontal)
447 448 removeData(start, end);
448 449 else if (start <= m_valuesSection || start <= m_labelsSection) // if the changes affect the map - reinitialize the pie
449 450 initializePieFromModel();
450 451 blockSeriesSignals(false);
451 452 }
452 453
453 454 void QPieModelMapperPrivate::handleModelDestroyed()
454 455 {
455 456 m_model = 0;
456 457 }
457 458
458 459 void QPieModelMapperPrivate::insertData(int start, int end)
459 460 {
460 461 if (m_model == 0 || m_series == 0)
461 462 return;
462 463
463 464 if (m_count != -1 && start >= m_first + m_count) {
464 465 return;
465 466 } else {
466 467 int addedCount = end - start + 1;
467 468 if (m_count != -1 && addedCount > m_count)
468 469 addedCount = m_count;
469 470 int first = qMax(start, m_first);
470 471 int last = qMin(first + addedCount - 1, m_orientation == Qt::Vertical ? m_model->rowCount() - 1 : m_model->columnCount() - 1);
471 472 for (int i = first; i <= last; i++) {
472 473 QModelIndex valueIndex = valueModelIndex(i - m_first);
473 474 QModelIndex labelIndex = labelModelIndex(i - m_first);
474 475 if (valueIndex.isValid() && labelIndex.isValid()) {
475 476 QPieSlice *slice = new QPieSlice;
476 477 slice->setValue(m_model->data(valueIndex, Qt::DisplayRole).toDouble());
477 478 slice->setLabel(m_model->data(labelIndex, Qt::DisplayRole).toString());
478 479 connect(slice, SIGNAL(labelChanged()), this, SLOT(sliceLabelChanged()));
479 480 connect(slice, SIGNAL(valueChanged()), this, SLOT(sliceValueChanged()));
480 481 m_series->insert(i - m_first, slice);
481 482 m_slices.insert(i - m_first, slice);
482 483 }
483 484 }
484 485
485 486 // remove excess of slices (abouve m_count)
486 487 if (m_count != -1 && m_series->slices().size() > m_count)
487 488 for (int i = m_series->slices().size() - 1; i >= m_count; i--) {
488 489 m_series->remove(m_series->slices().at(i));
489 490 m_slices.removeAt(i);
490 491 }
491 492 }
492 493 }
493 494
494 495 void QPieModelMapperPrivate::removeData(int start, int end)
495 496 {
496 497 if (m_model == 0 || m_series == 0)
497 498 return;
498 499
499 500 int removedCount = end - start + 1;
500 501 if (m_count != -1 && start >= m_first + m_count) {
501 502 return;
502 503 } else {
503 504 int toRemove = qMin(m_series->slices().size(), removedCount); // first find how many items can actually be removed
504 505 int first = qMax(start, m_first); // get the index of the first item that will be removed.
505 506 int last = qMin(first + toRemove - 1, m_series->slices().size() + m_first - 1); // get the index of the last item that will be removed.
506 507 for (int i = last; i >= first; i--) {
507 508 m_series->remove(m_series->slices().at(i - m_first));
508 509 m_slices.removeAt(i - m_first);
509 510 }
510 511
511 512 if (m_count != -1) {
512 513 int itemsAvailable; // check how many are available to be added
513 514 if (m_orientation == Qt::Vertical)
514 515 itemsAvailable = m_model->rowCount() - m_first - m_series->slices().size();
515 516 else
516 517 itemsAvailable = m_model->columnCount() - m_first - m_series->slices().size();
517 518 int toBeAdded = qMin(itemsAvailable, m_count - m_series->slices().size()); // add not more items than there is space left to be filled.
518 519 int currentSize = m_series->slices().size();
519 520 if (toBeAdded > 0)
520 521 for (int i = m_series->slices().size(); i < currentSize + toBeAdded; i++) {
521 522 QModelIndex valueIndex = valueModelIndex(i - m_first);
522 523 QModelIndex labelIndex = labelModelIndex(i - m_first);
523 524 if (valueIndex.isValid() && labelIndex.isValid()) {
524 525 QPieSlice *slice = new QPieSlice;
525 526 slice->setValue(m_model->data(valueIndex, Qt::DisplayRole).toDouble());
526 527 slice->setLabel(m_model->data(labelIndex, Qt::DisplayRole).toString());
527 528 m_series->insert(i, slice);
528 529 m_slices.insert(i, slice);
529 530 }
530 531 }
531 532 }
532 533 }
533 534 }
534 535
535 536 void QPieModelMapperPrivate::initializePieFromModel()
536 537 {
537 538 if (m_model == 0 || m_series == 0)
538 539 return;
539 540
540 541 blockSeriesSignals();
541 542 // clear current content
542 543 m_series->clear();
543 544 m_slices.clear();
544 545
545 546 // create the initial slices set
546 547 int slicePos = 0;
547 548 QModelIndex valueIndex = valueModelIndex(slicePos);
548 549 QModelIndex labelIndex = labelModelIndex(slicePos);
549 550 while (valueIndex.isValid() && labelIndex.isValid()) {
550 551 QPieSlice *slice = new QPieSlice;
551 552 slice->setLabel(m_model->data(labelIndex, Qt::DisplayRole).toString());
552 553 slice->setValue(m_model->data(valueIndex, Qt::DisplayRole).toDouble());
553 554 connect(slice, SIGNAL(labelChanged()), this, SLOT(sliceLabelChanged()));
554 555 connect(slice, SIGNAL(valueChanged()), this, SLOT(sliceValueChanged()));
555 556 m_series->append(slice);
556 557 m_slices.append(slice);
557 558 slicePos++;
558 559 valueIndex = valueModelIndex(slicePos);
559 560 labelIndex = labelModelIndex(slicePos);
560 561 }
561 562 blockSeriesSignals(false);
562 563 }
563 564
564 565 #include "moc_qpiemodelmapper_p.cpp"
565 566 #include "moc_qpiemodelmapper.cpp"
566 567
567 568 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,796 +1,816
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 24 #include "qpieslice_p.h"
25 25 #include "pieslicedata_p.h"
26 26 #include "chartdataset_p.h"
27 27 #include "charttheme_p.h"
28 28 #include "chartanimator_p.h"
29 29 #include "legendmarker_p.h"
30 30 #include "qabstractaxis.h"
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 /*!
35 35 \class QPieSeries
36 36 \brief Pie series API for QtCommercial Charts
37 37
38 38 The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
39 39 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
40 40 The actual slice size is determined by that relative value.
41 41
42 42 Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0
43 43 These relate to the actual chart rectangle.
44 44
45 45 By default the pie is defined as a full pie but it can also be a partial pie.
46 46 This can be done by setting a starting angle and angle span to the series.
47 47 Full pie is 360 degrees where 0 is at 12 a'clock.
48 48
49 49 See the \l {PieChart Example} {pie chart example} to learn how to create a simple pie chart.
50 50 \image examples_piechart.png
51 51 */
52 52 /*!
53 53 \qmlclass PieSeries QPieSeries
54 54 \inherits AbstractSeries
55 55
56 56 The following QML shows how to create a simple pie chart.
57 57
58 58 \snippet ../demos/qmlchart/qml/qmlchart/View1.qml 1
59 59
60 60 \beginfloatleft
61 61 \image demos_qmlchart1.png
62 62 \endfloat
63 63 \clearfloat
64 64 */
65 65
66 66 /*!
67 67 \property QPieSeries::horizontalPosition
68 68 \brief Defines the horizontal position of the pie.
69 69
70 70 The value is a relative value to the chart rectangle where:
71 71
72 72 \list
73 73 \o 0.0 is the absolute left.
74 74 \o 1.0 is the absolute right.
75 75 \endlist
76 76 Default value is 0.5 (center).
77 77 \sa verticalPosition
78 78 */
79 79
80 80 /*!
81 81 \qmlproperty real PieSeries::horizontalPosition
82 82
83 83 Defines the horizontal position of the pie.
84 84
85 85 The value is a relative value to the chart rectangle where:
86 86
87 87 \list
88 88 \o 0.0 is the absolute left.
89 89 \o 1.0 is the absolute right.
90 90 \endlist
91 91 Default value is 0.5 (center).
92 92 \sa verticalPosition
93 93 */
94 94
95 95 /*!
96 96 \property QPieSeries::verticalPosition
97 97 \brief Defines the vertical position of the pie.
98 98
99 99 The value is a relative value to the chart rectangle where:
100 100
101 101 \list
102 102 \o 0.0 is the absolute top.
103 103 \o 1.0 is the absolute bottom.
104 104 \endlist
105 105 Default value is 0.5 (center).
106 106 \sa horizontalPosition
107 107 */
108 108
109 109 /*!
110 110 \qmlproperty real PieSeries::verticalPosition
111 111
112 112 Defines the vertical position of the pie.
113 113
114 114 The value is a relative value to the chart rectangle where:
115 115
116 116 \list
117 117 \o 0.0 is the absolute top.
118 118 \o 1.0 is the absolute bottom.
119 119 \endlist
120 120 Default value is 0.5 (center).
121 121 \sa horizontalPosition
122 122 */
123 123
124 124 /*!
125 125 \property QPieSeries::size
126 126 \brief Defines the pie size.
127 127
128 128 The value is a relative value to the chart rectangle where:
129 129
130 130 \list
131 131 \o 0.0 is the minimum size (pie not drawn).
132 132 \o 1.0 is the maximum size that can fit the chart.
133 133 \endlist
134 134
135 135 Default value is 0.7.
136 136 */
137 137
138 138 /*!
139 139 \qmlproperty real PieSeries::size
140 140
141 141 Defines the pie size.
142 142
143 143 The value is a relative value to the chart rectangle where:
144 144
145 145 \list
146 146 \o 0.0 is the minimum size (pie not drawn).
147 147 \o 1.0 is the maximum size that can fit the chart.
148 148 \endlist
149 149
150 150 Default value is 0.7.
151 151 */
152 152
153 153 /*!
154 154 \property QPieSeries::startAngle
155 155 \brief Defines the starting angle of the pie.
156 156
157 157 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
158 158
159 159 Default is value is 0.
160 160 */
161 161
162 162 /*!
163 163 \qmlproperty real PieSeries::startAngle
164 164
165 165 Defines the starting angle of the pie.
166 166
167 167 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
168 168
169 169 Default is value is 0.
170 170 */
171 171
172 172 /*!
173 173 \property QPieSeries::endAngle
174 174 \brief Defines the ending angle of the pie.
175 175
176 176 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
177 177
178 178 Default is value is 360.
179 179 */
180 180
181 181 /*!
182 182 \qmlproperty real PieSeries::endAngle
183 183
184 184 Defines the ending angle of the pie.
185 185
186 186 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
187 187
188 188 Default is value is 360.
189 189 */
190 190
191 191 /*!
192 192 \property QPieSeries::count
193 193
194 194 Number of slices in the series.
195 195 */
196 196
197 197 /*!
198 198 \qmlproperty int PieSeries::count
199 199
200 200 Number of slices in the series.
201 201 */
202 202
203 203 /*!
204 204 \fn void QPieSeries::countChanged()
205 205 Emitted when the slice count has changed.
206 206 \sa count
207 207 */
208 208 /*!
209 209 \qmlsignal PieSeries::onCountChanged()
210 210 Emitted when the slice count has changed.
211 211 */
212 212
213 213 /*!
214 214 \property QPieSeries::sum
215 215
216 216 Sum of all slices.
217 217
218 218 The series keeps track of the sum of all slices it holds.
219 219 */
220 220
221 221 /*!
222 222 \qmlproperty real PieSeries::sum
223 223
224 224 Sum of all slices.
225 225
226 226 The series keeps track of the sum of all slices it holds.
227 227 */
228 228
229 229 /*!
230 230 \fn void QPieSeries::sumChanged()
231 231 Emitted when the sum of all slices has changed.
232 232 \sa sum
233 233 */
234 234 /*!
235 235 \qmlsignal PieSeries::onSumChanged()
236 236 Emitted when the sum of all slices has changed. This may happen for example if you add or remove slices, or if you
237 237 change value of a slice.
238 238 */
239 239
240 240 /*!
241 241 \fn void QPieSeries::added(QList<QPieSlice*> slices)
242 242
243 243 This signal is emitted when \a slices have been added to the series.
244 244
245 245 \sa append(), insert()
246 246 */
247 247 /*!
248 248 \qmlsignal PieSeries::onAdded(PieSlice slice)
249 249 Emitted when \a slice has been added to the series.
250 250 */
251 251
252 252 /*!
253 253 \fn void QPieSeries::removed(QList<QPieSlice*> slices)
254 254 This signal is emitted when \a slices have been removed from the series.
255 255 \sa remove()
256 256 */
257 257 /*!
258 258 \qmlsignal PieSeries::onRemoved(PieSlice slice)
259 259 Emitted when \a slice has been removed from the series.
260 260 */
261 261
262 262 /*!
263 263 \fn void QPieSeries::clicked(QPieSlice* slice)
264 264 This signal is emitted when a \a slice has been clicked.
265 265 \sa QPieSlice::clicked()
266 266 */
267 267 /*!
268 268 \qmlsignal PieSeries::onClicked(PieSlice slice)
269 269 This signal is emitted when a \a slice has been clicked.
270 270 */
271 271
272 272 /*!
273 273 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
274 274 This signal is emitted when user has hovered over or away from the \a slice.
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 \sa QPieSlice::hovered()
277 277 */
278 278 /*!
279 279 \qmlsignal PieSeries::onHovered(PieSlice slice, bool state)
280 280 This signal is emitted when user has hovered over or away from the \a slice. \a state is true when user has hovered
281 281 over the slice and false when hover has moved away from the slice.
282 282 */
283 283
284 284 /*!
285 285 \qmlmethod PieSlice PieSeries::at(int index)
286 286 Returns slice at \a index. Returns null if the index is not valid.
287 287 */
288 288
289 289 /*!
290 290 \qmlmethod PieSlice PieSeries::find(string label)
291 291 Returns the first slice with \a label. Returns null if the index is not valid.
292 292 */
293 293
294 294 /*!
295 295 \qmlmethod PieSlice PieSeries::append(string label, real value)
296 296 Adds a new slice with \a label and \a value to the pie.
297 297 */
298 298
299 299 /*!
300 300 \qmlmethod bool PieSeries::remove(PieSlice slice)
301 301 Removes the \a slice from the pie. Returns true if the removal was successfull, false otherwise.
302 302 */
303 303
304 304 /*!
305 305 \qmlmethod PieSeries::clear()
306 306 Removes all slices from the pie.
307 307 */
308 308
309 309 /*!
310 310 Constructs a series object which is a child of \a parent.
311 311 */
312 312 QPieSeries::QPieSeries(QObject *parent) :
313 313 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
314 314 {
315 315
316 316 }
317 317
318 318 /*!
319 319 Destroys the series and its slices.
320 320 */
321 321 QPieSeries::~QPieSeries()
322 322 {
323 323 // NOTE: d_prt destroyed by QObject
324 324 }
325 325
326 326 /*!
327 327 Returns QChartSeries::SeriesTypePie.
328 328 */
329 329 QAbstractSeries::SeriesType QPieSeries::type() const
330 330 {
331 331 return QAbstractSeries::SeriesTypePie;
332 332 }
333 333
334 334 /*!
335 335 Appends a single \a slice to the series.
336 336 Slice ownership is passed to the series.
337 337
338 338 Returns true if append was succesfull.
339 339 */
340 340 bool QPieSeries::append(QPieSlice* slice)
341 341 {
342 342 return append(QList<QPieSlice*>() << slice);
343 343 }
344 344
345 345 /*!
346 346 Appends an array of \a slices to the series.
347 347 Slice ownership is passed to the series.
348 348
349 349 Returns true if append was successfull.
350 350 */
351 351 bool QPieSeries::append(QList<QPieSlice*> slices)
352 352 {
353 353 Q_D(QPieSeries);
354 354
355 355 if (slices.count() == 0)
356 356 return false;
357 357
358 358 foreach (QPieSlice* s, slices) {
359 359 if (!s || d->m_slices.contains(s))
360 360 return false;
361 361 if (s->series()) // already added to some series
362 362 return false;
363 363 }
364 364
365 365 foreach (QPieSlice* s, slices) {
366 366 s->setParent(this);
367 367 QPieSlicePrivate::fromSlice(s)->m_series = this;
368 368 d->m_slices << s;
369 369 }
370 370
371 371 d->updateDerivativeData();
372 372
373 373 foreach (QPieSlice* s, slices) {
374 374 connect(s, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
375 375 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
376 376 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
377 377 }
378 378
379 379 emit added(slices);
380 380 emit countChanged();
381 381
382 382 return true;
383 383 }
384 384
385 385 /*!
386 386 Appends a single \a slice to the series and returns a reference to the series.
387 387 Slice ownership is passed to the series.
388 388 */
389 389 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
390 390 {
391 391 append(slice);
392 392 return *this;
393 393 }
394 394
395 395
396 396 /*!
397 397 Appends a single slice to the series with give \a value and \a label.
398 398 Slice ownership is passed to the series.
399 399 */
400 400 QPieSlice* QPieSeries::append(QString label, qreal value)
401 401 {
402 402 QPieSlice* slice = new QPieSlice(label, value);
403 403 append(slice);
404 404 return slice;
405 405 }
406 406
407 407 /*!
408 408 Inserts a single \a slice to the series before the slice at \a index position.
409 409 Slice ownership is passed to the series.
410 410
411 411 Returns true if insert was successfull.
412 412 */
413 413 bool QPieSeries::insert(int index, QPieSlice* slice)
414 414 {
415 415 Q_D(QPieSeries);
416 416
417 417 if (index < 0 || index > d->m_slices.count())
418 418 return false;
419 419
420 420 if (!slice || d->m_slices.contains(slice))
421 421 return false;
422 422
423 423 if (slice->series()) // already added to some series
424 424 return false;
425 425
426 426 slice->setParent(this);
427 427 QPieSlicePrivate::fromSlice(slice)->m_series = this;
428 428 d->m_slices.insert(index, slice);
429 429
430 430 d->updateDerivativeData();
431 431
432 432 connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
433 433 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
434 434 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
435 435
436 436 emit added(QList<QPieSlice*>() << slice);
437 437 emit countChanged();
438 438
439 439 return true;
440 440 }
441 441
442 442 /*!
443 443 Removes a single \a slice from the series and deletes the slice.
444 444
445 445 Do not reference the pointer after this call.
446 446
447 447 Returns true if remove was successfull.
448 448 */
449 449 bool QPieSeries::remove(QPieSlice* slice)
450 450 {
451 451 Q_D(QPieSeries);
452 452
453 453 if (!d->m_slices.removeOne(slice))
454 454 return false;
455 455
456 456 d->updateDerivativeData();
457 457
458 458 emit removed(QList<QPieSlice*>() << slice);
459 459 emit countChanged();
460 460
461 461 delete slice;
462 462 slice = 0;
463 463
464 464 return true;
465 465 }
466 466
467 467 /*!
468 468 Clears all slices from the series.
469 469 */
470 470 void QPieSeries::clear()
471 471 {
472 472 Q_D(QPieSeries);
473 473 if (d->m_slices.count() == 0)
474 474 return;
475 475
476 476 QList<QPieSlice*> slices = d->m_slices;
477 477 foreach (QPieSlice* s, d->m_slices) {
478 478 d->m_slices.removeOne(s);
479 479 delete s;
480 480 }
481 481
482 482 d->updateDerivativeData();
483 483
484 484 emit removed(slices);
485 485 emit countChanged();
486 486 }
487 487
488 488 /*!
489 489 Returns a list of slices that belong to this series.
490 490 */
491 491 QList<QPieSlice*> QPieSeries::slices() const
492 492 {
493 493 Q_D(const QPieSeries);
494 494 return d->m_slices;
495 495 }
496 496
497 497 /*!
498 498 returns the number of the slices in this series.
499 499 */
500 500 int QPieSeries::count() const
501 501 {
502 502 Q_D(const QPieSeries);
503 503 return d->m_slices.count();
504 504 }
505 505
506 506 /*!
507 507 Returns true is the series is empty.
508 508 */
509 509 bool QPieSeries::isEmpty() const
510 510 {
511 511 Q_D(const QPieSeries);
512 512 return d->m_slices.isEmpty();
513 513 }
514 514
515 515 /*!
516 516 Returns the sum of all slice values in this series.
517 517
518 518 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
519 519 */
520 520 qreal QPieSeries::sum() const
521 521 {
522 522 Q_D(const QPieSeries);
523 523 return d->m_sum;
524 524 }
525 525
526 526 void QPieSeries::setDonut(bool donut)
527 527 {
528 528 Q_D(QPieSeries);
529 529 d->m_donutChart = donut;
530 530 d->updateDerivativeData();
531 531 }
532 532
533 533 bool QPieSeries::donut() const
534 534 {
535 535 Q_D(const QPieSeries);
536 536 return d->m_donutChart;
537 537 }
538 538
539 void QPieSeries::setDonutInnerSize(qreal innerSize)
540 {
541 Q_D(QPieSeries);
542
543 if (innerSize < 0.0)
544 innerSize = 0.0;
545 if (innerSize > 1.0)
546 innerSize = 1.0;
547
548 d->m_donutRelativeInnerSize = innerSize;
549 d->updateDerivativeData();
550 emit d->pieSizeChanged();
551 }
552
553 qreal QPieSeries::donutInnerSize() const
554 {
555 Q_D(const QPieSeries);
556 return d->m_donutRelativeInnerSize;
557 }
558
539 559 void QPieSeries::setHorizontalPosition(qreal relativePosition)
540 560 {
541 561 Q_D(QPieSeries);
542 562
543 563 if (relativePosition < 0.0)
544 564 relativePosition = 0.0;
545 565 if (relativePosition > 1.0)
546 566 relativePosition = 1.0;
547 567
548 568 if (!qFuzzyIsNull(d->m_pieRelativeHorPos - relativePosition)) {
549 569 d->m_pieRelativeHorPos = relativePosition;
550 570 emit d->horizontalPositionChanged();
551 571 }
552 572 }
553 573
554 574 qreal QPieSeries::horizontalPosition() const
555 575 {
556 576 Q_D(const QPieSeries);
557 577 return d->m_pieRelativeHorPos;
558 578 }
559 579
560 580 void QPieSeries::setVerticalPosition(qreal relativePosition)
561 581 {
562 582 Q_D(QPieSeries);
563 583
564 584 if (relativePosition < 0.0)
565 585 relativePosition = 0.0;
566 586 if (relativePosition > 1.0)
567 587 relativePosition = 1.0;
568 588
569 589 if (!qFuzzyIsNull(d->m_pieRelativeVerPos - relativePosition)) {
570 590 d->m_pieRelativeVerPos = relativePosition;
571 591 emit d->verticalPositionChanged();
572 592 }
573 593 }
574 594
575 595 qreal QPieSeries::verticalPosition() const
576 596 {
577 597 Q_D(const QPieSeries);
578 598 return d->m_pieRelativeVerPos;
579 599 }
580 600
581 601 void QPieSeries::setPieSize(qreal relativeSize)
582 602 {
583 603 Q_D(QPieSeries);
584 604
585 605 if (relativeSize < 0.0)
586 606 relativeSize = 0.0;
587 607 if (relativeSize > 1.0)
588 608 relativeSize = 1.0;
589 609
590 610 if (!qFuzzyIsNull(d->m_pieRelativeSize - relativeSize)) {
591 611 d->m_pieRelativeSize = relativeSize;
592 612 emit d->pieSizeChanged();
593 613 }
594 614 }
595 615
596 616 qreal QPieSeries::pieSize() const
597 617 {
598 618 Q_D(const QPieSeries);
599 619 return d->m_pieRelativeSize;
600 620 }
601 621
602 622
603 623 void QPieSeries::setPieStartAngle(qreal angle)
604 624 {
605 625 Q_D(QPieSeries);
606 626 if (qFuzzyIsNull(d->m_pieStartAngle - angle))
607 627 return;
608 628 d->m_pieStartAngle = angle;
609 629 d->updateDerivativeData();
610 630 emit d->pieStartAngleChanged();
611 631 }
612 632
613 633 qreal QPieSeries::pieStartAngle() const
614 634 {
615 635 Q_D(const QPieSeries);
616 636 return d->m_pieStartAngle;
617 637 }
618 638
619 639 /*!
620 640 Sets the end angle of the pie.
621 641
622 642 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
623 643
624 644 \a angle must be greater than start angle.
625 645
626 646 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
627 647 */
628 648 void QPieSeries::setPieEndAngle(qreal angle)
629 649 {
630 650 Q_D(QPieSeries);
631 651 if (qFuzzyIsNull(d->m_pieEndAngle - angle))
632 652 return;
633 653 d->m_pieEndAngle = angle;
634 654 d->updateDerivativeData();
635 655 emit d->pieEndAngleChanged();
636 656 }
637 657
638 658 /*!
639 659 Returns the end angle of the pie.
640 660
641 661 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
642 662
643 663 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
644 664 */
645 665 qreal QPieSeries::pieEndAngle() const
646 666 {
647 667 Q_D(const QPieSeries);
648 668 return d->m_pieEndAngle;
649 669 }
650 670
651 671 /*!
652 672 Sets the all the slice labels \a visible or invisible.
653 673
654 674 Note that this affects only the current slices in the series.
655 675 If user adds a new slice the default label visibility is false.
656 676
657 677 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
658 678 */
659 679 void QPieSeries::setLabelsVisible(bool visible)
660 680 {
661 681 Q_D(QPieSeries);
662 682 foreach (QPieSlice* s, d->m_slices)
663 683 s->setLabelVisible(visible);
664 684 }
665 685
666 686 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
667 687
668 688
669 689 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
670 690 QAbstractSeriesPrivate(parent),
671 691 m_pieRelativeHorPos(0.5),
672 692 m_pieRelativeVerPos(0.5),
673 693 m_pieRelativeSize(0.7),
674 694 m_pieStartAngle(0),
675 695 m_pieEndAngle(360),
676 696 m_sum(0),
677 m_donutChart(false)
697 m_donutChart(false),
698 m_donutRelativeInnerSize(0.5)
678 699 {
679 700 }
680 701
681 702 QPieSeriesPrivate::~QPieSeriesPrivate()
682 703 {
683 704 }
684 705
685 706 void QPieSeriesPrivate::updateDerivativeData()
686 707 {
687 708 // calculate sum of all slices
688 709 qreal sum = 0;
689 710 foreach (QPieSlice* s, m_slices)
690 711 sum += s->value();
691 712
692 713 if (!qFuzzyIsNull(m_sum - sum)) {
693 714 m_sum = sum;
694 715 emit q_func()->sumChanged();
695 716 }
696 717
697 718 // nothing to show..
698 719 if (qFuzzyIsNull(m_sum))
699 720 return;
700 721
701 722 // update slice attributes
702 723 qreal sliceAngle = m_pieStartAngle;
703 724 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
704 725 QVector<QPieSlice*> changed;
705 726 foreach (QPieSlice* s, m_slices) {
706 727 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
707 728 d->setPercentage(s->value() / m_sum);
708 729 d->setStartAngle(sliceAngle);
709 730 d->setAngleSpan(pieSpan * s->percentage());
710 d->m_data.m_donut = m_donutChart;
711 731 sliceAngle += s->angleSpan();
712 732 }
713 733
714 734
715 735 emit calculatedDataChanged();
716 736 }
717 737
718 738 QPieSeriesPrivate* QPieSeriesPrivate::fromSeries(QPieSeries *series)
719 739 {
720 740 return series->d_func();
721 741 }
722 742
723 743 void QPieSeriesPrivate::sliceValueChanged()
724 744 {
725 745 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
726 746 updateDerivativeData();
727 747 }
728 748
729 749 void QPieSeriesPrivate::sliceClicked()
730 750 {
731 751 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
732 752 Q_ASSERT(m_slices.contains(slice));
733 753 Q_Q(QPieSeries);
734 754 emit q->clicked(slice);
735 755 }
736 756
737 757 void QPieSeriesPrivate::sliceHovered(bool state)
738 758 {
739 759 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
740 760 Q_ASSERT(m_slices.contains(slice));
741 761 Q_Q(QPieSeries);
742 762 emit q->hovered(slice, state);
743 763 }
744 764
745 765 void QPieSeriesPrivate::scaleDomain(Domain& domain)
746 766 {
747 767 Q_UNUSED(domain);
748 768 // does not apply to pie
749 769 }
750 770
751 771 Chart* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
752 772 {
753 773 Q_Q(QPieSeries);
754 774 PieChartItem* pie = new PieChartItem(q,presenter);
755 775 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
756 776 presenter->animator()->addAnimation(pie);
757 777 }
758 778 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
759 779 return pie;
760 780 }
761 781
762 782 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
763 783 {
764 784 Q_Q(QPieSeries);
765 785 QList<LegendMarker*> markers;
766 786 foreach(QPieSlice* slice, q->slices()) {
767 787 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
768 788 markers << marker;
769 789 }
770 790 return markers;
771 791 }
772 792
773 793 void QPieSeriesPrivate::initializeAxisX(QAbstractAxis* axis)
774 794 {
775 795 Q_UNUSED(axis);
776 796 }
777 797
778 798 void QPieSeriesPrivate::initializeAxisY(QAbstractAxis* axis)
779 799 {
780 800 Q_UNUSED(axis);
781 801 }
782 802
783 803 QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisXType() const
784 804 {
785 805 return QAbstractAxis::AxisTypeNoAxis;
786 806 }
787 807
788 808 QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisYType() const
789 809 {
790 810 return QAbstractAxis::AxisTypeNoAxis;
791 811 }
792 812
793 813 #include "moc_qpieseries.cpp"
794 814 #include "moc_qpieseries_p.cpp"
795 815
796 816 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,99 +1,102
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 PIESERIES_H
22 22 #define PIESERIES_H
23 23
24 24 #include <qabstractseries.h>
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27 class QPieSeriesPrivate;
28 28 class QPieSlice;
29 29
30 30 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QAbstractSeries
31 31 {
32 32 Q_OBJECT
33 33 Q_PROPERTY(qreal horizontalPosition READ horizontalPosition WRITE setHorizontalPosition)
34 34 Q_PROPERTY(qreal verticalPosition READ verticalPosition WRITE setVerticalPosition)
35 35 Q_PROPERTY(qreal size READ pieSize WRITE setPieSize)
36 36 Q_PROPERTY(qreal startAngle READ pieStartAngle WRITE setPieStartAngle)
37 37 Q_PROPERTY(qreal endAngle READ pieEndAngle WRITE setPieEndAngle)
38 38 Q_PROPERTY(int count READ count NOTIFY countChanged)
39 39 Q_PROPERTY(qreal sum READ sum NOTIFY sumChanged)
40 40
41 41 public:
42 42 explicit QPieSeries(QObject *parent = 0);
43 43 virtual ~QPieSeries();
44 44
45 45 QAbstractSeries::SeriesType type() const;
46 46
47 47 bool append(QPieSlice* slice);
48 48 bool append(QList<QPieSlice*> slices);
49 49 QPieSeries& operator << (QPieSlice* slice);
50 50 QPieSlice* append(QString label, qreal value);
51 51
52 52 bool insert(int index, QPieSlice* slice);
53 53
54 54 bool remove(QPieSlice* slice);
55 55 void clear();
56 56
57 57 QList<QPieSlice*> slices() const;
58 58 int count() const;
59 59
60 60 bool isEmpty() const;
61 61
62 62 qreal sum() const;
63 63
64 64 void setDonut(bool donut = true);
65 65 bool donut() const;
66 66
67 void setDonutInnerSize(qreal innerSize);
68 qreal donutInnerSize() const;
69
67 70 void setHorizontalPosition(qreal relativePosition);
68 71 qreal horizontalPosition() const;
69 72
70 73 void setVerticalPosition(qreal relativePosition);
71 74 qreal verticalPosition() const;
72 75
73 76 void setPieSize(qreal relativeSize);
74 77 qreal pieSize() const;
75 78
76 79 void setPieStartAngle(qreal startAngle);
77 80 qreal pieStartAngle() const;
78 81
79 82 void setPieEndAngle(qreal endAngle);
80 83 qreal pieEndAngle() const;
81 84
82 85 void setLabelsVisible(bool visible = true);
83 86
84 87 Q_SIGNALS:
85 88 void added(QList<QPieSlice*> slices);
86 89 void removed(QList<QPieSlice*> slices);
87 90 void clicked(QPieSlice* slice);
88 91 void hovered(QPieSlice* slice, bool state);
89 92 void countChanged();
90 93 void sumChanged();
91 94
92 95 private:
93 96 Q_DECLARE_PRIVATE(QPieSeries)
94 97 Q_DISABLE_COPY(QPieSeries)
95 98 };
96 99
97 100 QTCOMMERCIALCHART_END_NAMESPACE
98 101
99 102 #endif // PIESERIES_H
@@ -1,89 +1,90
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 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef QPIESERIES_P_H
31 31 #define QPIESERIES_P_H
32 32
33 33 #include "qpieseries.h"
34 34 #include "qabstractseries_p.h"
35 35
36 36 QTCOMMERCIALCHART_BEGIN_NAMESPACE
37 37 class QLegendPrivate;
38 38
39 39 class QPieSeriesPrivate : public QAbstractSeriesPrivate
40 40 {
41 41 Q_OBJECT
42 42
43 43 public:
44 44 QPieSeriesPrivate(QPieSeries *parent);
45 45 ~QPieSeriesPrivate();
46 46
47 47 void scaleDomain(Domain& domain);
48 48 Chart* createGraphics(ChartPresenter *presenter);
49 49 QList<LegendMarker*> createLegendMarker(QLegend *legend);
50 50 void initializeAxisX(QAbstractAxis* axis);
51 51 void initializeAxisY(QAbstractAxis* axis);
52 52 QAbstractAxis::AxisType defaultAxisXType() const;
53 53 QAbstractAxis::AxisType defaultAxisYType() const;
54 54
55 55 void updateDerivativeData();
56 56
57 57 static QPieSeriesPrivate* fromSeries(QPieSeries *series);
58 58
59 59 signals:
60 60 void calculatedDataChanged();
61 61 void pieSizeChanged();
62 62 void pieStartAngleChanged();
63 63 void pieEndAngleChanged();
64 64 void horizontalPositionChanged();
65 65 void verticalPositionChanged();
66 66
67 67 public Q_SLOTS:
68 68 void sliceValueChanged();
69 69 void sliceClicked();
70 70 void sliceHovered(bool state);
71 71
72 72 private:
73 73 QList<QPieSlice*> m_slices;
74 74 qreal m_pieRelativeHorPos;
75 75 qreal m_pieRelativeVerPos;
76 76 qreal m_pieRelativeSize;
77 77 qreal m_pieStartAngle;
78 78 qreal m_pieEndAngle;
79 79 qreal m_sum;
80 80 bool m_donutChart;
81 qreal m_donutRelativeInnerSize;
81 82
82 83 private:
83 84 friend class QLegendPrivate;
84 85 Q_DECLARE_PUBLIC(QPieSeries)
85 86 };
86 87
87 88 QTCOMMERCIALCHART_END_NAMESPACE
88 89
89 90 #endif // QPIESERIES_P_H
@@ -1,505 +1,506
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 "qxymodelmapper.h"
22 22 #include "qxymodelmapper_p.h"
23 23 #include "qxyseries.h"
24 24 #include <QAbstractItemModel>
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27
28 28 /*!
29 29 Constructs a mapper object which is a child of \a parent.
30 30 */
31 31 QXYModelMapper::QXYModelMapper(QObject *parent):
32 32 QObject(parent),
33 33 d_ptr(new QXYModelMapperPrivate(this))
34 34 {
35 35 }
36 36
37 37 /*!
38 38 \internal
39 39 */
40 40 QAbstractItemModel* QXYModelMapper::model() const
41 41 {
42 42 Q_D(const QXYModelMapper);
43 43 return d->m_model;
44 44 }
45 45
46 46 /*!
47 47 \internal
48 48 */
49 49 void QXYModelMapper::setModel(QAbstractItemModel *model)
50 50 {
51 51 if (model == 0)
52 52 return;
53 53
54 54 Q_D(QXYModelMapper);
55 55 if (d->m_model) {
56 56 disconnect(d->m_model, 0, d, 0);
57 57 }
58 58
59 59 d->m_model = model;
60 60 d->initializeXYFromModel();
61 61 // connect signals from the model
62 62 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
63 63 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelRowsAdded(QModelIndex,int,int)));
64 64 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelRowsRemoved(QModelIndex,int,int)));
65 65 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelColumnsAdded(QModelIndex,int,int)));
66 66 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelColumnsRemoved(QModelIndex,int,int)));
67 67 connect(d->m_model, SIGNAL(destroyed()), d, SLOT(handleModelDestroyed()));
68 68 }
69 69
70 70 /*!
71 71 \internal
72 72 */
73 73 QXYSeries* QXYModelMapper::series() const
74 74 {
75 75 Q_D(const QXYModelMapper);
76 76 return d->m_series;
77 77 }
78 78
79 79 /*!
80 80 \internal
81 81 */
82 82 void QXYModelMapper::setSeries(QXYSeries *series)
83 83 {
84 84 Q_D(QXYModelMapper);
85 85 if (d->m_series) {
86 86 disconnect(d->m_series, 0, d, 0);
87 87 }
88 88
89 89 if (series == 0)
90 90 return;
91 91
92 92 d->m_series = series;
93 93 d->initializeXYFromModel();
94 94 // connect the signals from the series
95 95 connect(d->m_series, SIGNAL(pointAdded(int)), d, SLOT(handlePointAdded(int)));
96 96 connect(d->m_series, SIGNAL(pointRemoved(int)), d, SLOT(handlePointRemoved(int)));
97 97 connect(d->m_series, SIGNAL(pointReplaced(int)), d, SLOT(handlePointReplaced(int)));
98 98 connect(d->m_series, SIGNAL(destroyed()), d, SLOT(handleSeriesDestroyed()));
99 99 }
100 100
101 101 /*!
102 102 \internal
103 103 */
104 104 int QXYModelMapper::first() const
105 105 {
106 106 Q_D(const QXYModelMapper);
107 107 return d->m_first;
108 108 }
109 109
110 110 /*!
111 111 \internal
112 112 */
113 113 void QXYModelMapper::setFirst(int first)
114 114 {
115 115 Q_D(QXYModelMapper);
116 116 d->m_first = qMax(first, 0);
117 117 d->initializeXYFromModel();
118 118 }
119 119
120 120 /*!
121 121 \internal
122 122 */
123 123 int QXYModelMapper::count() const
124 124 {
125 125 Q_D(const QXYModelMapper);
126 126 return d->m_count;
127 127 }
128 128
129 129 /*!
130 130 \internal
131 131 */
132 132 void QXYModelMapper::setCount(int count)
133 133 {
134 134 Q_D(QXYModelMapper);
135 135 d->m_count = qMax(count, -1);
136 136 d->initializeXYFromModel();
137 137 }
138 138
139 139 /*!
140 140 Returns the orientation that is used when QXYModelMapper accesses the model.
141 141 This mean whether the consecutive x/y values of the QXYSeries are read from rows (Qt::Horizontal)
142 142 or from columns (Qt::Vertical)
143 143 */
144 144 Qt::Orientation QXYModelMapper::orientation() const
145 145 {
146 146 Q_D(const QXYModelMapper);
147 147 return d->m_orientation;
148 148 }
149 149
150 150 /*!
151 151 Returns the \a orientation that is used when QXYModelMapper accesses the model.
152 152 This mean whether the consecutive x/y values of the QXYSeries are read from rows (Qt::Horizontal)
153 153 or from columns (Qt::Vertical)
154 154 */
155 155 void QXYModelMapper::setOrientation(Qt::Orientation orientation)
156 156 {
157 157 Q_D(QXYModelMapper);
158 158 d->m_orientation = orientation;
159 159 d->initializeXYFromModel();
160 160 }
161 161
162 162 /*!
163 163 Returns which section of the model is kept in sync with the x values of the QXYSeries
164 164 */
165 165 int QXYModelMapper::xSection() const
166 166 {
167 167 Q_D(const QXYModelMapper);
168 168 return d->m_xSection;
169 169 }
170 170
171 171 /*!
172 172 Sets the model section that is kept in sync with the x values of the QXYSeries.
173 173 Parameter \a xSection specifies the section of the model.
174 174 */
175 175 void QXYModelMapper::setXSection(int xSection)
176 176 {
177 177 Q_D(QXYModelMapper);
178 178 d->m_xSection = qMax(-1, xSection);
179 179 d->initializeXYFromModel();
180 180 }
181 181
182 182 /*!
183 183 Returns which section of the model is kept in sync with the y values of the QXYSeries
184 184 */
185 185 int QXYModelMapper::ySection() const
186 186 {
187 187 Q_D(const QXYModelMapper);
188 188 return d->m_ySection;
189 189 }
190 190
191 191 /*!
192 192 Sets the model section that is kept in sync with the y values of the QXYSeries.
193 193 Parameter \a ySection specifies the section of the model.
194 194 */
195 195 void QXYModelMapper::setYSection(int ySection)
196 196 {
197 197 Q_D(QXYModelMapper);
198 198 d->m_ySection = qMax(-1, ySection);
199 199 d->initializeXYFromModel();
200 200 }
201 201
202 202 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
203 203
204 204 QXYModelMapperPrivate::QXYModelMapperPrivate(QXYModelMapper *q) :
205 QObject(q),
205 206 m_series(0),
206 207 m_model(0),
207 208 m_first(0),
208 209 m_count(-1),
209 210 m_orientation(Qt::Vertical),
210 211 m_xSection(-1),
211 212 m_ySection(-1),
212 213 m_seriesSignalsBlock(false),
213 214 m_modelSignalsBlock(false),
214 215 q_ptr(q)
215 216 {
216 217 }
217 218
218 219 void QXYModelMapperPrivate::blockModelSignals(bool block)
219 220 {
220 221 m_modelSignalsBlock = block;
221 222 }
222 223
223 224 void QXYModelMapperPrivate::blockSeriesSignals(bool block)
224 225 {
225 226 m_seriesSignalsBlock = block;
226 227 }
227 228
228 229 QModelIndex QXYModelMapperPrivate::xModelIndex(int xPos)
229 230 {
230 231 if (m_count != -1 && xPos >= m_count)
231 232 return QModelIndex(); // invalid
232 233
233 234 if (m_orientation == Qt::Vertical)
234 235 return m_model->index(xPos + m_first, m_xSection);
235 236 else
236 237 return m_model->index(m_xSection, xPos + m_first);
237 238 }
238 239
239 240 QModelIndex QXYModelMapperPrivate::yModelIndex(int yPos)
240 241 {
241 242 if (m_count != -1 && yPos >= m_count)
242 243 return QModelIndex(); // invalid
243 244
244 245 if (m_orientation == Qt::Vertical)
245 246 return m_model->index(yPos + m_first, m_ySection);
246 247 else
247 248 return m_model->index(m_ySection, yPos + m_first);
248 249 }
249 250
250 251 void QXYModelMapperPrivate::handlePointAdded(int pointPos)
251 252 {
252 253 if (m_seriesSignalsBlock)
253 254 return;
254 255
255 256 if (m_count != -1)
256 257 m_count += 1;
257 258
258 259 blockModelSignals();
259 260 if (m_orientation == Qt::Vertical)
260 261 m_model->insertRows(pointPos + m_first, 1);
261 262 else
262 263 m_model->insertColumns(pointPos + m_first, 1);
263 264
264 265 m_model->setData(xModelIndex(pointPos), m_series->points().at(pointPos).x());
265 266 m_model->setData(yModelIndex(pointPos), m_series->points().at(pointPos).y());
266 267 blockModelSignals(false);
267 268 }
268 269
269 270 void QXYModelMapperPrivate::handlePointRemoved(int pointPos)
270 271 {
271 272 if (m_seriesSignalsBlock)
272 273 return;
273 274
274 275 if (m_count != -1)
275 276 m_count -= 1;
276 277
277 278 blockModelSignals();
278 279 if (m_orientation == Qt::Vertical)
279 280 m_model->removeRow(pointPos + m_first);
280 281 else
281 282 m_model->removeColumn(pointPos + m_first);
282 283 blockModelSignals(false);
283 284 }
284 285
285 286 void QXYModelMapperPrivate::handlePointReplaced(int pointPos)
286 287 {
287 288 if (m_seriesSignalsBlock)
288 289 return;
289 290
290 291 blockModelSignals();
291 292 m_model->setData(xModelIndex(pointPos), m_series->points().at(pointPos).x());
292 293 m_model->setData(yModelIndex(pointPos), m_series->points().at(pointPos).y());
293 294 blockModelSignals(false);
294 295 }
295 296
296 297 void QXYModelMapperPrivate::handleSeriesDestroyed()
297 298 {
298 299 m_series = 0;
299 300 }
300 301
301 302 void QXYModelMapperPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
302 303 {
303 304 if (m_model == 0 || m_series == 0)
304 305 return;
305 306
306 307 if (m_modelSignalsBlock)
307 308 return;
308 309
309 310 blockSeriesSignals();
310 311 QModelIndex index;
311 312 QPointF oldPoint;
312 313 QPointF newPoint;
313 314 for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
314 315 for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
315 316 index = topLeft.sibling(row, column);
316 317 if (m_orientation == Qt::Vertical && (index.column() == m_xSection || index.column() == m_ySection)) {
317 318 if (index.row() >= m_first && (m_count == - 1 || index.row() < m_first + m_count)) {
318 319 QModelIndex xIndex = xModelIndex(index.row() - m_first);
319 320 QModelIndex yIndex = yModelIndex(index.row() - m_first);
320 321 if (xIndex.isValid() && yIndex.isValid()) {
321 322 oldPoint = m_series->points().at(index.row() - m_first);
322 323 newPoint.setX(m_model->data(xIndex).toReal());
323 324 newPoint.setY(m_model->data(yIndex).toReal());
324 325 }
325 326 }
326 327 } else if (m_orientation == Qt::Horizontal && (index.row() == m_xSection || index.row() == m_ySection)) {
327 328 if (index.column() >= m_first && (m_count == - 1 || index.column() < m_first + m_count)) {
328 329 QModelIndex xIndex = xModelIndex(index.column() - m_first);
329 330 QModelIndex yIndex = yModelIndex(index.column() - m_first);
330 331 if (xIndex.isValid() && yIndex.isValid()) {
331 332 oldPoint = m_series->points().at(index.column() - m_first);
332 333 newPoint.setX(m_model->data(xIndex).toReal());
333 334 newPoint.setY(m_model->data(yIndex).toReal());
334 335 }
335 336 }
336 337 } else {
337 338 continue;
338 339 }
339 340 m_series->replace(oldPoint, newPoint);
340 341 }
341 342 }
342 343 blockSeriesSignals(false);
343 344 }
344 345
345 346 void QXYModelMapperPrivate::modelRowsAdded(QModelIndex parent, int start, int end)
346 347 {
347 348 Q_UNUSED(parent);
348 349 if (m_modelSignalsBlock)
349 350 return;
350 351
351 352 blockSeriesSignals();
352 353 if (m_orientation == Qt::Vertical)
353 354 insertData(start, end);
354 355 else if (start <= m_xSection || start <= m_ySection) // if the changes affect the map - reinitialize the xy
355 356 initializeXYFromModel();
356 357 blockSeriesSignals(false);
357 358 }
358 359
359 360 void QXYModelMapperPrivate::modelRowsRemoved(QModelIndex parent, int start, int end)
360 361 {
361 362 Q_UNUSED(parent);
362 363 if (m_modelSignalsBlock)
363 364 return;
364 365
365 366 blockSeriesSignals();
366 367 if (m_orientation == Qt::Vertical)
367 368 removeData(start, end);
368 369 else if (start <= m_xSection || start <= m_ySection) // if the changes affect the map - reinitialize the xy
369 370 initializeXYFromModel();
370 371 blockSeriesSignals(false);
371 372 }
372 373
373 374 void QXYModelMapperPrivate::modelColumnsAdded(QModelIndex parent, int start, int end)
374 375 {
375 376 Q_UNUSED(parent);
376 377 if (m_modelSignalsBlock)
377 378 return;
378 379
379 380 blockSeriesSignals();
380 381 if (m_orientation == Qt::Horizontal)
381 382 insertData(start, end);
382 383 else if (start <= m_xSection || start <= m_ySection) // if the changes affect the map - reinitialize the xy
383 384 initializeXYFromModel();
384 385 blockSeriesSignals(false);
385 386 }
386 387
387 388 void QXYModelMapperPrivate::modelColumnsRemoved(QModelIndex parent, int start, int end)
388 389 {
389 390 Q_UNUSED(parent);
390 391 if (m_modelSignalsBlock)
391 392 return;
392 393
393 394 blockSeriesSignals();
394 395 if (m_orientation == Qt::Horizontal)
395 396 removeData(start, end);
396 397 else if (start <= m_xSection || start <= m_ySection) // if the changes affect the map - reinitialize the xy
397 398 initializeXYFromModel();
398 399 blockSeriesSignals(false);
399 400 }
400 401
401 402 void QXYModelMapperPrivate::handleModelDestroyed()
402 403 {
403 404 m_model = 0;
404 405 }
405 406
406 407 void QXYModelMapperPrivate::insertData(int start, int end)
407 408 {
408 409 if (m_model == 0 || m_series == 0)
409 410 return;
410 411
411 412 if (m_count != -1 && start >= m_first + m_count) {
412 413 return;
413 414 } else {
414 415 int addedCount = end - start + 1;
415 416 if (m_count != -1 && addedCount > m_count)
416 417 addedCount = m_count;
417 418 int first = qMax(start, m_first);
418 419 int last = qMin(first + addedCount - 1, m_orientation == Qt::Vertical ? m_model->rowCount() - 1 : m_model->columnCount() - 1);
419 420 for (int i = first; i <= last; i++) {
420 421 QPointF point;
421 422 QModelIndex xIndex = xModelIndex(i - m_first);
422 423 QModelIndex yIndex = yModelIndex(i - m_first);
423 424 if (xIndex.isValid() && yIndex.isValid()) {
424 425 point.setX(m_model->data(xIndex, Qt::DisplayRole).toDouble());
425 426 point.setY(m_model->data(yIndex, Qt::DisplayRole).toDouble());
426 427 m_series->insert(i - m_first, point);
427 428 }
428 429 }
429 430
430 431 // remove excess of slices (abouve m_count)
431 432 if (m_count != -1 && m_series->points().size() > m_count)
432 433 for (int i = m_series->points().size() - 1; i >= m_count; i--) {
433 434 m_series->remove(m_series->points().at(i));
434 435 }
435 436 }
436 437 }
437 438
438 439 void QXYModelMapperPrivate::removeData(int start, int end)
439 440 {
440 441 if (m_model == 0 || m_series == 0)
441 442 return;
442 443
443 444 int removedCount = end - start + 1;
444 445 if (m_count != -1 && start >= m_first + m_count) {
445 446 return;
446 447 } else {
447 448 int toRemove = qMin(m_series->count(), removedCount); // first find how many items can actually be removed
448 449 int first = qMax(start, m_first); // get the index of the first item that will be removed.
449 450 int last = qMin(first + toRemove - 1, m_series->count() + m_first - 1); // get the index of the last item that will be removed.
450 451 for (int i = last; i >= first; i--) {
451 452 m_series->remove(m_series->points().at(i - m_first));
452 453 }
453 454
454 455 if (m_count != -1) {
455 456 int itemsAvailable; // check how many are available to be added
456 457 if (m_orientation == Qt::Vertical)
457 458 itemsAvailable = m_model->rowCount() - m_first - m_series->count();
458 459 else
459 460 itemsAvailable = m_model->columnCount() - m_first - m_series->count();
460 461 int toBeAdded = qMin(itemsAvailable, m_count - m_series->count()); // add not more items than there is space left to be filled.
461 462 int currentSize = m_series->count();
462 463 if (toBeAdded > 0)
463 464 for (int i = m_series->count(); i < currentSize + toBeAdded; i++) {
464 465 QPointF point;
465 466 QModelIndex xIndex = xModelIndex(i);
466 467 QModelIndex yIndex = yModelIndex(i);
467 468 if (xIndex.isValid() && yIndex.isValid()) {
468 469 point.setX(m_model->data(xIndex, Qt::DisplayRole).toDouble());
469 470 point.setY(m_model->data(yIndex, Qt::DisplayRole).toDouble());
470 471 m_series->insert(i, point);
471 472 }
472 473 }
473 474 }
474 475 }
475 476 }
476 477
477 478 void QXYModelMapperPrivate::initializeXYFromModel()
478 479 {
479 480 if (m_model == 0 || m_series == 0)
480 481 return;
481 482
482 483 blockSeriesSignals();
483 484 // clear current content
484 485 m_series->clear();
485 486
486 487 // create the initial slices set
487 488 int pointPos = 0;
488 489 QModelIndex xIndex = xModelIndex(pointPos);
489 490 QModelIndex yIndex = yModelIndex(pointPos);
490 491 while (xIndex.isValid() && yIndex.isValid()) {
491 492 QPointF point;
492 493 point.setX(m_model->data(xIndex, Qt::DisplayRole).toDouble());
493 494 point.setY(m_model->data(yIndex, Qt::DisplayRole).toDouble());
494 495 m_series->append(point);
495 496 pointPos++;
496 497 xIndex = xModelIndex(pointPos);
497 498 yIndex = yModelIndex(pointPos);
498 499 }
499 500 blockSeriesSignals(false);
500 501 }
501 502
502 503 #include "moc_qxymodelmapper.cpp"
503 504 #include "moc_qxymodelmapper_p.cpp"
504 505
505 506 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now