##// END OF EJS Templates
Fixes to barseries and pieseries model support. Started adding barseries model tests
Marek Rosa -
r1184:3138389fa706
parent child
Show More
@@ -1,94 +1,95
1 1 #include "qbarmodelmapper.h"
2 2
3 3 QTCOMMERCIALCHART_BEGIN_NAMESPACE
4 4
5 5 QBarModelMapper::QBarModelMapper(QObject *parent) :
6 6 QObject(parent),
7 7 m_first(0),
8 8 m_count(-1),
9 9 m_orientation(Qt::Vertical),
10 10 m_mapBarBottom(-1),
11 11 m_mapBarTop(-1),
12 12 m_mapCategories(-1)
13 13 {
14 14 }
15 15
16 16 int QBarModelMapper::first() const
17 17 {
18 18 return m_first;
19 19 }
20 20
21 21 void QBarModelMapper::setFirst(int first)
22 22 {
23 23 m_first = qMax(first, 0);
24 24 emit updated();
25 25 }
26 26
27 27 int QBarModelMapper::count() const
28 28 {
29 29 return m_count;
30 30 }
31 31
32 32 void QBarModelMapper::setCount(int count)
33 33 {
34 34 m_count = qMax(count, -1);
35 35 emit updated();
36 36 }
37 37
38 38 Qt::Orientation QBarModelMapper::orientation() const
39 39 {
40 40 return m_orientation;
41 41 }
42 42
43 43 void QBarModelMapper::setOrientation(Qt::Orientation orientation)
44 44 {
45 45 m_orientation = orientation;
46 46 emit updated();
47 47 }
48 48
49 49 int QBarModelMapper::mapBarBottom() const
50 50 {
51 51 return m_mapBarBottom;
52 52 }
53 53
54 54 void QBarModelMapper::setMapBarBottom(int mapValues)
55 55 {
56 56 m_mapBarBottom = mapValues;
57 57 emit updated();
58 58 }
59 59
60 60 int QBarModelMapper::mapBarTop() const
61 61 {
62 62 return m_mapBarTop;
63 63 }
64 64
65 65 void QBarModelMapper::setMapBarTop(int mapLabels)
66 66 {
67 67 m_mapBarTop = mapLabels;
68 68 emit updated();
69 69 }
70 70
71 71 int QBarModelMapper::mapCategories() const
72 72 {
73 73 return m_mapCategories;
74 74 }
75 75
76 76 void QBarModelMapper::setMapCategories(int mapCategories)
77 77 {
78 78 m_mapCategories = mapCategories;
79 79 emit updated();
80 80 }
81 81
82 82 void QBarModelMapper::reset()
83 83 {
84 84 m_first = 0;
85 85 m_count = -1;
86 86 m_orientation = Qt::Vertical;
87 87 m_mapBarBottom = -1;
88 88 m_mapBarTop = -1;
89 89 m_mapCategories = -1;
90 emit updated();
90 91 }
91 92
92 93 #include "moc_qbarmodelmapper.cpp"
93 94
94 95 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,592 +1,608
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 "qbarseries.h"
22 22 #include "qbarseries_p.h"
23 23 #include "qbarset.h"
24 24 #include "qbarset_p.h"
25 25 #include "domain_p.h"
26 26 #include "legendmarker_p.h"
27 27 #include "chartdataset_p.h"
28 28 #include "charttheme_p.h"
29 29 #include "chartanimator_p.h"
30 30
31 31 #include <QAbstractItemModel>
32 32 #include <QModelIndex>
33 33 #include <QBarModelMapper>
34 34
35 35 QTCOMMERCIALCHART_BEGIN_NAMESPACE
36 36
37 37 /*!
38 38 \class QBarSeries
39 39 \brief part of QtCommercial chart API.
40 40 \mainclass
41 41
42 42 QBarSeries represents a series of data shown as bars. One QBarSeries can contain multiple
43 43 QBarSet data sets. QBarSeries groups the data from sets to categories, which are defined
44 44 by QStringList.
45 45
46 46 See the \l {BarChart Example} {bar chart example} to learn how to create a simple bar chart.
47 47 \image examples_barchart.png
48 48
49 49 \sa QBarSet, QStackedBarSeries, QPercentBarSeries
50 50 */
51 51
52 52 /*!
53 53 \fn void QBarSeries::clicked(QBarSet *barset, QString category)
54 54
55 55 The signal is emitted if the user clicks with a mouse on top of QBarSet \a barset of category \a category
56 56 contained by the series.
57 57 */
58 58
59 59 /*!
60 60 \fn void QBarSeries::hovered(QBarSet* barset, bool status)
61 61
62 62 The signal is emitted if mouse is hovered on top of series.
63 63 Parameter \a barset is the pointer of barset, where hover happened.
64 64 Parameter \a status is true, if mouse entered on top of series, false if mouse left from top of series.
65 65 */
66 66
67 67 /*!
68 68 Constructs empty QBarSeries. Parameter \a categories defines the categories for chart.
69 69 QBarSeries is QObject which is a child of a \a parent.
70 70 */
71 71 QBarSeries::QBarSeries(/*QBarCategories categories,*/ QObject *parent) :
72 72 QAbstractSeries(*new QBarSeriesPrivate(/*categories,*/ this),parent)
73 73 {
74 74 }
75 75
76 76 /*!
77 77 Destructs barseries and owned barsets.
78 78 */
79 79 QBarSeries::~QBarSeries()
80 80 {
81 81 // NOTE: d_ptr destroyed by QObject
82 82 }
83 83
84 84 /*!
85 85 \internal
86 86 */
87 87 QBarSeries::QBarSeries(QBarSeriesPrivate &d, QObject *parent) :
88 88 QAbstractSeries(d,parent)
89 89 {
90 90 }
91 91
92 92 /*!
93 93 Returns the type of series. Derived classes override this.
94 94 */
95 95 QAbstractSeries::SeriesType QBarSeries::type() const
96 96 {
97 97 return QAbstractSeries::SeriesTypeBar;
98 98 }
99 99
100 100 void QBarSeries::setCategories(QBarCategories categories)
101 101 {
102 102 Q_D(QBarSeries);
103 103 d->setCategories(categories);
104 104 emit d->categoriesUpdated();
105 105 }
106 106
107 107 /*!
108 108 Adds a set of bars to series. Takes ownership of \a set.
109 109 */
110 110 bool QBarSeries::appendBarSet(QBarSet *set)
111 111 {
112 112 Q_D(QBarSeries);
113 113 if ((d->m_barSets.contains(set)) || (set == 0)) {
114 114 // Fail if set is already in list or set is null.
115 115 return false;
116 116 }
117 117 d->m_barSets.append(set);
118 118 QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), d, SLOT(barsetChanged()));
119 119 emit d->restructuredBars();
120 120 return true;
121 121 }
122 122
123 123 /*!
124 124 Removes a set of bars from series. Releases ownership of \a set. Doesn't delete \a set.
125 125 */
126 126 bool QBarSeries::removeBarSet(QBarSet *set)
127 127 {
128 128 Q_D(QBarSeries);
129 129 if (!d->m_barSets.contains(set)) {
130 130 // Fail if set is not in list
131 131 return false;
132 132 }
133 133 d->m_barSets.removeOne(set);
134 134 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), d, SLOT(barsetChanged()));
135 135 emit d->restructuredBars();
136 136 return true;
137 137 }
138 138
139 139 /*!
140 140 Adds a list of barsets to series. Takes ownership of \a sets.
141 141 */
142 142 bool QBarSeries::appendBarSets(QList<QBarSet* > sets)
143 143 {
144 144 Q_D(QBarSeries);
145 145 foreach (QBarSet* set, sets) {
146 146 if ((set == 0) || (d->m_barSets.contains(set))) {
147 147 // Fail if any of the sets is null or is already appended.
148 148 return false;
149 149 }
150 150 if (sets.count(set) != 1) {
151 151 // Also fail if same set is more than once in given list.
152 152 return false;
153 153 }
154 154 }
155 155
156 156 foreach (QBarSet* set, sets) {
157 157 d->m_barSets.append(set);
158 158 QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), d, SLOT(barsetChanged()));
159 159 }
160 160 emit d->restructuredBars();
161 161 return true;
162 162 }
163 163
164 164 /*!
165 165 Removes a list of barsets from series. Releases ownership of \a sets. Doesn't delete \a sets.
166 166 */
167 167 bool QBarSeries::removeBarSets(QList<QBarSet* > sets)
168 168 {
169 169 Q_D(QBarSeries);
170 170
171 171 bool setsRemoved = false;
172 172 foreach (QBarSet* set, sets) {
173 173 if (d->m_barSets.contains(set)) {
174 174 d->m_barSets.removeOne(set);
175 175 QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), d, SLOT(barsetChanged()));
176 176 setsRemoved = true;
177 177 }
178 178 }
179 179
180 180 if (setsRemoved) {
181 181 emit d->restructuredBars();
182 182 }
183 183 return setsRemoved;
184 184 }
185 185
186 186 /*!
187 187 Returns number of sets in series.
188 188 */
189 189 int QBarSeries::barsetCount() const
190 190 {
191 191 Q_D(const QBarSeries);
192 192 return d->m_barSets.count();
193 193 }
194 194
195 195 /*!
196 196 Returns number of categories in series
197 197 */
198 198 int QBarSeries::categoryCount() const
199 199 {
200 200 Q_D(const QBarSeries);
201 201 return d->m_categories.count();
202 202 }
203 203
204 204 /*!
205 205 Returns a list of sets in series. Keeps ownership of sets.
206 206 */
207 207 QList<QBarSet*> QBarSeries::barSets() const
208 208 {
209 209 Q_D(const QBarSeries);
210 210 return d->m_barSets;
211 211 }
212 212
213 213 /*!
214 214 \fn bool QBarSeries::setModel(QAbstractItemModel *model)
215 215 Sets the \a model to be used as a data source
216 216 */
217 217 void QBarSeries::setModel(QAbstractItemModel *model)
218 218 {
219 219 Q_D(QBarSeries);
220 220 // disconnect signals from old model
221 221 if(d->m_model)
222 222 {
223 223 disconnect(d->m_model, 0, this, 0);
224 224 }
225 225
226 226 // set new model
227 227 if(model)
228 228 {
229 229 d->m_model = model;
230 230
231 231 // connect the signals
232 232 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
233 233 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelDataAdded(QModelIndex,int,int)));
234 234 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelDataRemoved(QModelIndex,int,int)));
235 235 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelDataAdded(QModelIndex,int,int)));
236 236 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelDataRemoved(QModelIndex,int,int)));
237 237
238 238 if (d->m_mapper)
239 239 d->initializeDataFromModel();
240 240 }
241 241 else
242 242 {
243 243 d->m_model = 0;
244 244 }
245 245 }
246 246
247 247 void QBarSeries::setModelMapper(QBarModelMapper *mapper)
248 248 {
249 249 Q_D(QBarSeries);
250 250 // disconnect signals from old mapper
251 251 if (d->m_mapper) {
252 252 QObject::disconnect(d->m_mapper, 0, this, 0);
253 253 }
254 254
255 255 if (mapper) {
256 256 d->m_mapper = mapper;
257 257 // connect the signal from the mapper
258 connect(d->m_mapper, SIGNAL(updated()), d, SLOT(initializePieFromModel()));
258 connect(d->m_mapper, SIGNAL(updated()), d, SLOT(initializeDataFromModel()));
259 259
260 260 if (d->m_model)
261 261 d->initializeDataFromModel();
262 262 } else {
263 263 d->m_mapper = 0;
264 264 }
265 265 }
266 266
267 267 QBarModelMapper* QBarSeries::modelMapper() const
268 268 {
269 269 Q_D(const QBarSeries);
270 270 return d->m_mapper;
271 271 }
272 272
273 273 /*!
274 274 Returns the bar categories of the series.
275 275 */
276 276 QBarCategories QBarSeries::categories() const
277 277 {
278 278 Q_D(const QBarSeries);
279 279 return d->m_categories;
280 280 }
281 281
282 282 /*!
283 283 Sets the visibility of labels in series to \a visible
284 284 */
285 285 void QBarSeries::setLabelsVisible(bool visible)
286 286 {
287 287 foreach (QBarSet* s, barSets()) {
288 288 s->setLabelsVisible(visible);
289 289 }
290 290 }
291 291
292 292 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
293 293
294 294 QBarSeriesPrivate::QBarSeriesPrivate(QBarSeries *q) :
295 295 QAbstractSeriesPrivate(q),
296 296 m_barMargin(0.05), // Default value is 5% of category width
297 297 m_mapper(0)
298 298 // m_categories(categories),
299 299 {
300 300 }
301 301
302 302 void QBarSeriesPrivate::setCategories(QBarCategories categories)
303 303 {
304 304 m_categories = categories;
305 305 }
306 306
307 307 void QBarSeriesPrivate::setBarMargin(qreal margin)
308 308 {
309 309 if (margin > 1.0) {
310 310 margin = 1.0;
311 311 } else if (margin < 0.0) {
312 312 margin = 0.0;
313 313 }
314 314
315 315 m_barMargin = margin;
316 316 emit updatedBars();
317 317 }
318 318
319 319 qreal QBarSeriesPrivate::barMargin()
320 320 {
321 321 return m_barMargin;
322 322 }
323 323
324 324 QBarSet* QBarSeriesPrivate::barsetAt(int index)
325 325 {
326 326 return m_barSets.at(index);
327 327 }
328 328
329 329 QString QBarSeriesPrivate::categoryName(int category)
330 330 {
331 331 return m_categories.at(category);
332 332 }
333 333
334 334 qreal QBarSeriesPrivate::min()
335 335 {
336 336 if (m_barSets.count() <= 0) {
337 337 return 0;
338 338 }
339 339 qreal min = INT_MAX;
340 340
341 341 for (int i = 0; i < m_barSets.count(); i++) {
342 342 int categoryCount = m_barSets.at(i)->count();
343 343 for (int j = 0; j < categoryCount; j++) {
344 344 qreal temp = m_barSets.at(i)->at(j).y();
345 345 if (temp < min)
346 346 min = temp;
347 347 }
348 348 }
349 349 return min;
350 350 }
351 351
352 352 qreal QBarSeriesPrivate::max()
353 353 {
354 354 if (m_barSets.count() <= 0) {
355 355 return 0;
356 356 }
357 357 qreal max = INT_MIN;
358 358
359 359 for (int i = 0; i < m_barSets.count(); i++) {
360 360 int categoryCount = m_barSets.at(i)->count();
361 361 for (int j = 0; j < categoryCount; j++) {
362 362 qreal temp = m_barSets.at(i)->at(j).y();
363 363 if (temp > max)
364 364 max = temp;
365 365 }
366 366 }
367 367
368 368 return max;
369 369 }
370 370
371 371 qreal QBarSeriesPrivate::valueAt(int set, int category)
372 372 {
373 373 if ((set < 0) || (set >= m_barSets.count())) {
374 374 // No set, no value.
375 375 return 0;
376 376 } else if ((category < 0) || (category >= m_barSets.at(set)->count())) {
377 377 // No category, no value.
378 378 return 0;
379 379 }
380 380
381 381 return m_barSets.at(set)->at(category).y();
382 382 }
383 383
384 384 qreal QBarSeriesPrivate::percentageAt(int set, int category)
385 385 {
386 386 if ((set < 0) || (set >= m_barSets.count())) {
387 387 // No set, no value.
388 388 return 0;
389 389 } else if ((category < 0) || (category >= m_barSets.at(set)->count())) {
390 390 // No category, no value.
391 391 return 0;
392 392 }
393 393
394 394 qreal value = m_barSets.at(set)->at(category).y();
395 395 qreal sum = categorySum(category);
396 396 if ( qFuzzyIsNull(sum) ) {
397 397 return 0;
398 398 }
399 399
400 400 return value / sum;
401 401 }
402 402
403 403 qreal QBarSeriesPrivate::categorySum(int category)
404 404 {
405 405 qreal sum(0);
406 406 int count = m_barSets.count(); // Count sets
407 407 for (int set = 0; set < count; set++) {
408 408 if (category < m_barSets.at(set)->count())
409 409 sum += m_barSets.at(set)->at(category).y();
410 410 }
411 411 return sum;
412 412 }
413 413
414 414 qreal QBarSeriesPrivate::absoluteCategorySum(int category)
415 415 {
416 416 qreal sum(0);
417 417 int count = m_barSets.count(); // Count sets
418 418 for (int set = 0; set < count; set++) {
419 419 if (category < m_barSets.at(set)->count())
420 420 sum += qAbs(m_barSets.at(set)->at(category).y());
421 421 }
422 422 return sum;
423 423 }
424 424
425 425 qreal QBarSeriesPrivate::maxCategorySum()
426 426 {
427 427 qreal max = INT_MIN;
428 428 int count = m_categories.count();
429 429 for (int i = 0; i < count; i++) {
430 430 qreal sum = categorySum(i);
431 431 if (sum > max)
432 432 max = sum;
433 433 }
434 434 return max;
435 435 }
436 436
437 437 void QBarSeriesPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
438 438 {
439 if (m_model == 0 || m_mapper == 0)
440 return;
441
439 442 for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
440 443 for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
441 444 if (m_mapper->orientation() == Qt::Vertical)
442 445 {
443 446 // model update is relevant to BarSeries if the change was made to the part of the model that was mapped to BarSeries
444 447 if ( row >= m_mapper->first() && (m_mapper->count() == - 1 || row < m_mapper->first() + m_mapper->count())) {
445 448 if (column >= m_mapper->mapBarBottom() && column <= m_mapper->mapBarTop())
446 449 barsetAt(column - m_mapper->mapBarBottom())->replace(row - m_mapper->first(), m_model->data(topLeft, Qt::DisplayRole).toDouble());
447 450 // if (column == m_mapper->mapCategories());// TODO:
448 451 }
449 452 }
450 453 else
451 454 {
452 455 // model update is relevant to BarSeries if the change was made to the part of the model that was mapped to BarSeries
453 456 if (column >= m_mapper->first() && (m_mapper->count() == - 1 || column < m_mapper->first() + m_mapper->count())) {
454 457 if (row >= m_mapper->mapBarBottom() && row <= m_mapper->mapBarTop())
455 458 barsetAt(row - m_mapper->mapBarBottom())->replace(column - m_mapper->first(), m_model->data(topLeft, Qt::DisplayRole).toDouble());
456 459 // if (row == m_mapper->mapCategories());// TODO:
457 460 }
458 461 }
459 462 }
460 463 }
461 464 }
462 465
463 466 void QBarSeriesPrivate::modelDataAdded(QModelIndex parent, int start, int end)
464 467 {
465 468 Q_UNUSED(parent);
466 469 Q_UNUSED(start);
467 470 Q_UNUSED(end);
468 471 initializeDataFromModel();
469 472 }
470 473
471 474 void QBarSeriesPrivate::modelDataRemoved(QModelIndex parent, int start, int end)
472 475 {
473 476 Q_UNUSED(parent);
474 477 Q_UNUSED(start);
475 478 Q_UNUSED(end);
476 479 initializeDataFromModel();
477 480 }
478 481
479 482 void QBarSeriesPrivate::initializeDataFromModel()
480 483 {
481 484 Q_Q(QBarSeries);
482 485
483 if (m_model == 0 || m_mapper == 0)
484 return;
485
486 486 // create the initial bars
487 487 m_categories.clear();
488 488 m_barSets.clear();
489
490 if (m_model == 0 || m_mapper == 0)
491 return;
492
493 // check if mappings are set
494 if (m_mapper->mapBarBottom() == -1 || m_mapper->mapBarTop() == -1 || m_mapper->mapCategories() == -1)
495 return;
496
489 497 // emit restructuredBars();
490 498 if (m_mapper->orientation() == Qt::Vertical) {
499 if (m_mapCategories >= m_model->columnCount())
500 return;
491 501 int rowCount = 0;
492 502 if(m_mapper->count() == -1)
493 503 rowCount = m_model->rowCount() - m_mapper->first();
494 504 else
495 505 rowCount = qMin(m_mapper->count(), m_model->rowCount() - m_mapper->first());
496 506 for (int k = m_mapper->first(); k < m_mapper->first() + rowCount; k++) {
497 507 m_categories << m_model->data(m_model->index(k, m_mapper->mapCategories()), Qt::DisplayRole).toString();
498 508 }
499 509
500 for (int i = m_mapper->mapBarBottom(); i <= m_mapper->mapBarTop(); i++) {
510 int lastAvailableBarSet = qMin(m_model->columnCount() - 1, m_mapper->mapBarTop());
511 for (int i = m_mapper->mapBarBottom(); i <= lastAvailableBarSet; i++) {
512 // for (int i = m_mapper->mapBarBottom(); i <= m_mapper->mapBarTop(); i++) {
501 513 QBarSet* barSet = new QBarSet(m_model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString());
502 514 for(int m = m_mapper->first(); m < m_mapper->first() + rowCount; m++)
503 515 *barSet << m_model->data(m_model->index(m, i), Qt::DisplayRole).toDouble();
504 516 q->appendBarSet(barSet);
505 517 }
506 518 } else {
519 if (m_mapCategories >= m_model->rowCount())
520 return;
507 521 int columnCount = 0;
508 522 if(m_mapper->count() == -1)
509 523 columnCount = m_model->columnCount() - m_mapper->first();
510 524 else
511 525 columnCount = qMin(m_mapper->count(), m_model->columnCount() - m_mapper->first());
512 526 for (int k = m_mapper->first(); k < m_mapper->first() + columnCount; k++) {
513 527 m_categories << m_model->data(m_model->index(m_mapper->mapCategories(), k), Qt::DisplayRole).toString();
514 528 }
515 529
516 for (int i = m_mapper->mapBarBottom(); i <= m_mapper->mapBarTop(); i++) {
530 int lastAvailableBarSet = qMin(m_model->rowCount() - 1, m_mapper->mapBarTop());
531 for (int i = m_mapper->mapBarBottom(); i <= lastAvailableBarSet; i++) {
532 // for (int i = m_mapper->mapBarBottom(); i <= m_mapper->mapBarTop(); i++) {
517 533 QBarSet* barSet = new QBarSet(m_model->headerData(i, Qt::Vertical, Qt::DisplayRole).toString());
518 534 for(int m = m_mapper->first(); m < m_mapper->first() + columnCount; m++)
519 535 *barSet << m_model->data(m_model->index(i, m), Qt::DisplayRole).toDouble();
520 536 q->appendBarSet(barSet);
521 537 }
522 538 }
523 539 emit restructuredBars();
524 540 // emit updatedBars();
525 541 }
526 542
527 543 void QBarSeriesPrivate::insertCategory(int index, const QString category)
528 544 {
529 545 m_categories.insert(index, category);
530 546 emit categoriesUpdated();
531 547 }
532 548
533 549 void QBarSeriesPrivate::removeCategory(int index)
534 550 {
535 551 m_categories.removeAt(index);
536 552 emit categoriesUpdated();
537 553 }
538 554
539 555 void QBarSeriesPrivate::barsetChanged()
540 556 {
541 557 emit updatedBars();
542 558 }
543 559
544 560 void QBarSeriesPrivate::scaleDomain(Domain& domain)
545 561 {
546 562 qreal minX(domain.minX());
547 563 qreal minY(domain.minY());
548 564 qreal maxX(domain.maxX());
549 565 qreal maxY(domain.maxY());
550 566 int tickXCount(domain.tickXCount());
551 567 int tickYCount(domain.tickYCount());
552 568
553 569 qreal x = m_categories.count();
554 570 qreal y = max();
555 571 minX = qMin(minX, x);
556 572 minY = qMin(minY, y);
557 573 maxX = qMax(maxX, x);
558 574 maxY = qMax(maxY, y);
559 575 tickXCount = x+1;
560 576
561 577 domain.setRange(minX,maxX,minY,maxY,tickXCount,tickYCount);
562 578 }
563 579
564 580 Chart* QBarSeriesPrivate::createGraphics(ChartPresenter* presenter)
565 581 {
566 582 Q_Q(QBarSeries);
567 583
568 584 BarChartItem* bar = new BarChartItem(q,presenter);
569 585 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
570 586 presenter->animator()->addAnimation(bar);
571 587 }
572 588 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
573 589 return bar;
574 590
575 591 }
576 592
577 593 QList<LegendMarker*> QBarSeriesPrivate::createLegendMarker(QLegend* legend)
578 594 {
579 595 Q_Q(QBarSeries);
580 596 QList<LegendMarker*> markers;
581 597 foreach(QBarSet* set, q->barSets()) {
582 598 BarLegendMarker* marker = new BarLegendMarker(q,set,legend);
583 599 markers << marker;
584 600 }
585 601
586 602 return markers;
587 603 }
588 604
589 605 #include "moc_qbarseries.cpp"
590 606 #include "moc_qbarseries_p.cpp"
591 607
592 608 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,815 +1,815
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 "pieslicedata_p.h"
25 25 #include "chartdataset_p.h"
26 26 #include "charttheme_p.h"
27 27 #include "chartanimator_p.h"
28 28 #include "legendmarker_p.h"
29 29 #include <QAbstractItemModel>
30 30 #include "qpiemodelmapper.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 /*!
54 54 \property QPieSeries::horizontalPosition
55 55 \brief Defines the horizontal position of the pie.
56 56
57 57 The value is a relative value to the chart rectangle where:
58 58
59 59 \list
60 60 \o 0.0 is the absolute left.
61 61 \o 1.0 is the absolute right.
62 62 \endlist
63 63
64 64 Default value is 0.5 (center).
65 65 */
66 66
67 67 /*!
68 68 \property QPieSeries::verticalPosition
69 69 \brief Defines the vertical position of the pie.
70 70
71 71 The value is a relative value to the chart rectangle where:
72 72
73 73 \list
74 74 \o 0.0 is the absolute top.
75 75 \o 1.0 is the absolute bottom.
76 76 \endlist
77 77
78 78 Default value is 0.5 (center).
79 79 */
80 80
81 81 /*!
82 82 \property QPieSeries::size
83 83 \brief Defines the pie size.
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 minimum size (pie not drawn).
89 89 \o 1.0 is the maximum size that can fit the chart.
90 90 \endlist
91 91
92 92 Default value is 0.7.
93 93 */
94 94
95 95 /*!
96 96 \property QPieSeries::startAngle
97 97 \brief Defines the starting angle of the pie.
98 98
99 99 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
100 100
101 101 Default is value is 0.
102 102 */
103 103
104 104 /*!
105 105 \property QPieSeries::endAngle
106 106 \brief Defines the ending angle of the pie.
107 107
108 108 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
109 109
110 110 Default is value is 360.
111 111 */
112 112
113 113
114 114 /*!
115 115 Constructs a series object which is a child of \a parent.
116 116 */
117 117 QPieSeries::QPieSeries(QObject *parent) :
118 118 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
119 119 {
120 120
121 121 }
122 122
123 123 /*!
124 124 Destroys the series and its slices.
125 125 */
126 126 QPieSeries::~QPieSeries()
127 127 {
128 128 // NOTE: d_prt destroyed by QObject
129 129 }
130 130
131 131 /*!
132 132 Returns QChartSeries::SeriesTypePie.
133 133 */
134 134 QAbstractSeries::SeriesType QPieSeries::type() const
135 135 {
136 136 return QAbstractSeries::SeriesTypePie;
137 137 }
138 138
139 139 /*!
140 140 Appends an array of \a slices to the series.
141 141 Slice ownership is passed to the series.
142 142 */
143 143 bool QPieSeries::append(QList<QPieSlice*> slices)
144 144 {
145 145 Q_D(QPieSeries);
146 146
147 147 if (slices.count() == 0)
148 148 return false;
149 149
150 150 foreach (QPieSlice* s, slices) {
151 151 if (!s || d->m_slices.contains(s))
152 152 return false;
153 153 }
154 154
155 155 foreach (QPieSlice* s, slices) {
156 156 s->setParent(this);
157 157 d->m_slices << s;
158 158 }
159 159
160 160 d->updateDerivativeData();
161 161
162 162 foreach (QPieSlice* s, slices) {
163 163 connect(s, SIGNAL(changed()), d, SLOT(sliceChanged()));
164 164 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
165 165 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
166 166 }
167 167
168 168 emit d->added(slices);
169 169
170 170 return true;
171 171 }
172 172
173 173 /*!
174 174 Appends a single \a slice to the series.
175 175 Slice ownership is passed to the series.
176 176 */
177 177 bool QPieSeries::append(QPieSlice* slice)
178 178 {
179 179 return append(QList<QPieSlice*>() << slice);
180 180 }
181 181
182 182 /*!
183 183 Appends a single \a slice to the series and returns a reference to the series.
184 184 Slice ownership is passed to the series.
185 185 */
186 186 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
187 187 {
188 188 append(slice);
189 189 return *this;
190 190 }
191 191
192 192
193 193 /*!
194 194 Appends a single slice to the series with give \a value and \a name.
195 195 Slice ownership is passed to the series.
196 196 */
197 197 QPieSlice* QPieSeries::append(qreal value, QString name)
198 198 {
199 199 QPieSlice* slice = new QPieSlice(value, name);
200 200 append(slice);
201 201 return slice;
202 202 }
203 203
204 204 /*!
205 205 Inserts a single \a slice to the series before the slice at \a index position.
206 206 Slice ownership is passed to the series.
207 207 */
208 208 bool QPieSeries::insert(int index, QPieSlice* slice)
209 209 {
210 210 Q_D(QPieSeries);
211 211
212 212 if (index < 0 || index > d->m_slices.count())
213 213 return false;
214 214
215 215 if (!slice || d->m_slices.contains(slice))
216 216 return false;
217 217
218 218 slice->setParent(this);
219 219 d->m_slices.insert(index, slice);
220 220
221 221 d->updateDerivativeData();
222 222
223 223 connect(slice, SIGNAL(changed()), d, SLOT(sliceChanged()));
224 224 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
225 225 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
226 226
227 227 emit d->added(QList<QPieSlice*>() << slice);
228 228
229 229 return true;
230 230 }
231 231
232 232 /*!
233 233 Removes a single \a slice from the series and deletes the slice.
234 234
235 235 Do not reference the pointer after this call.
236 236 */
237 237 bool QPieSeries::remove(QPieSlice* slice)
238 238 {
239 239 Q_D(QPieSeries);
240 240
241 241 if (!d->m_slices.removeOne(slice))
242 242 return false;
243 243
244 244 d->updateDerivativeData();
245 245
246 246 emit d->removed(QList<QPieSlice*>() << slice);
247 247
248 248 delete slice;
249 249 slice = 0;
250 250
251 251 return true;
252 252 }
253 253
254 254 /*!
255 255 Clears all slices from the series.
256 256 */
257 257 void QPieSeries::clear()
258 258 {
259 259 Q_D(QPieSeries);
260 260 if (d->m_slices.count() == 0)
261 261 return;
262 262
263 263 QList<QPieSlice*> slices = d->m_slices;
264 264 foreach (QPieSlice* s, d->m_slices) {
265 265 d->m_slices.removeOne(s);
266 266 delete s;
267 267 }
268 268
269 269 d->updateDerivativeData();
270 270
271 271 emit d->removed(slices);
272 272 }
273 273
274 274 /*!
275 275 returns the number of the slices in this series.
276 276 */
277 277 int QPieSeries::count() const
278 278 {
279 279 Q_D(const QPieSeries);
280 280 return d->m_slices.count();
281 281 }
282 282
283 283 /*!
284 284 Returns true is the series is empty.
285 285 */
286 286 bool QPieSeries::isEmpty() const
287 287 {
288 288 Q_D(const QPieSeries);
289 289 return d->m_slices.isEmpty();
290 290 }
291 291
292 292 /*!
293 293 Returns a list of slices that belong to this series.
294 294 */
295 295 QList<QPieSlice*> QPieSeries::slices() const
296 296 {
297 297 Q_D(const QPieSeries);
298 298 return d->m_slices;
299 299 }
300 300
301 301 void QPieSeries::setHorizontalPosition(qreal relativePosition)
302 302 {
303 303 Q_D(QPieSeries);
304 304 if (d->setRealValue(d->m_pieRelativeHorPos, relativePosition, 1.0))
305 305 emit d->piePositionChanged();
306 306 }
307 307
308 308 void QPieSeries::setVerticalPosition(qreal relativePosition)
309 309 {
310 310 Q_D(QPieSeries);
311 311 if (d->setRealValue(d->m_pieRelativeVerPos, relativePosition, 1.0))
312 312 emit d->piePositionChanged();
313 313 }
314 314
315 315 qreal QPieSeries::horizontalPosition() const
316 316 {
317 317 Q_D(const QPieSeries);
318 318 return d->m_pieRelativeHorPos;
319 319 }
320 320
321 321 qreal QPieSeries::verticalPosition() const
322 322 {
323 323 Q_D(const QPieSeries);
324 324 return d->m_pieRelativeVerPos;
325 325 }
326 326
327 327 void QPieSeries::setPieSize(qreal relativeSize)
328 328 {
329 329 Q_D(QPieSeries);
330 330 if (d->setRealValue(d->m_pieRelativeSize, relativeSize, 1.0))
331 331 emit d->pieSizeChanged();
332 332 }
333 333
334 334 qreal QPieSeries::pieSize() const
335 335 {
336 336 Q_D(const QPieSeries);
337 337 return d->m_pieRelativeSize;
338 338 }
339 339
340 340
341 341 void QPieSeries::setPieStartAngle(qreal angle)
342 342 {
343 343 Q_D(QPieSeries);
344 344 if (d->setRealValue(d->m_pieStartAngle, angle, d->m_pieEndAngle))
345 345 d->updateDerivativeData();
346 346 }
347 347
348 348 qreal QPieSeries::pieStartAngle() const
349 349 {
350 350 Q_D(const QPieSeries);
351 351 return d->m_pieStartAngle;
352 352 }
353 353
354 354 /*!
355 355 Sets the end angle of the pie.
356 356
357 357 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
358 358
359 359 \a angle must be greater than start angle.
360 360
361 361 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
362 362 */
363 363 void QPieSeries::setPieEndAngle(qreal angle)
364 364 {
365 365 Q_D(QPieSeries);
366 366
367 367 if (d->setRealValue(d->m_pieEndAngle, angle, 360.0, d->m_pieStartAngle))
368 368 d->updateDerivativeData();
369 369 }
370 370
371 371 /*!
372 372 Returns the end angle of the pie.
373 373
374 374 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
375 375
376 376 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
377 377 */
378 378 qreal QPieSeries::pieEndAngle() const
379 379 {
380 380 Q_D(const QPieSeries);
381 381 return d->m_pieEndAngle;
382 382 }
383 383
384 384 /*!
385 385 Sets the all the slice labels \a visible or invisible.
386 386
387 387 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
388 388 */
389 389 void QPieSeries::setLabelsVisible(bool visible)
390 390 {
391 391 Q_D(QPieSeries);
392 392 foreach (QPieSlice* s, d->m_slices)
393 393 s->setLabelVisible(visible);
394 394 }
395 395
396 396 /*!
397 397 Returns the sum of all slice values in this series.
398 398
399 399 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
400 400 */
401 401 qreal QPieSeries::sum() const
402 402 {
403 403 Q_D(const QPieSeries);
404 404 return d->m_sum;
405 405 }
406 406
407 407 /*!
408 408 \fn void QPieSeries::clicked(QPieSlice* slice)
409 409
410 410 This signal is emitted when a \a slice has been clicked.
411 411
412 412 \sa QPieSlice::clicked()
413 413 */
414 414
415 415 /*!
416 416 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
417 417
418 418 This signal is emitted when user has hovered over or away from the \a slice.
419 419
420 420 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
421 421
422 422 \sa QPieSlice::hovered()
423 423 */
424 424
425 425 /*!
426 426 \fn bool QPieSeries::setModel(QAbstractItemModel *model)
427 427 Sets the \a model to be used as a data source
428 428 */
429 429 void QPieSeries::setModel(QAbstractItemModel* model)
430 430 {
431 431 Q_D(QPieSeries);
432 432 // disconnect signals from old model
433 433 if(d->m_model)
434 434 {
435 435 disconnect(d->m_model, 0, this, 0);
436 436 }
437 437
438 438 // set new model
439 439 if(model)
440 440 {
441 441 d->m_model = model;
442 442 // connect signals from the model
443 443 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
444 444 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelRowsAdded(QModelIndex,int,int)));
445 445 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelRowsRemoved(QModelIndex,int,int)));
446 446 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelColumnsAdded(QModelIndex,int,int)));
447 447 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelColumnsRemoved(QModelIndex,int,int)));
448 448
449 449 if (d->m_mapper)
450 450 d->initializePieFromModel();
451 451 }
452 452 else
453 453 {
454 454 d->m_model = 0;
455 455 }
456 456 }
457 457
458 458 void QPieSeries::setModelMapper(QPieModelMapper *mapper)
459 459 {
460 460 Q_D(QPieSeries);
461 461 // disconnect signals from old mapper
462 462 if (d->m_mapper) {
463 463 QObject::disconnect(d->m_mapper, 0, this, 0);
464 464 }
465 465
466 466 if (mapper) {
467 467 d->m_mapper = mapper;
468 468 // connect the signal from the mapper
469 469 connect(d->m_mapper, SIGNAL(updated()), d, SLOT(initializePieFromModel()));
470 470
471 471 if (d->m_model)
472 472 d->initializePieFromModel();
473 473 } else {
474 474 d->m_mapper = 0;
475 475 }
476 476 }
477 477
478 478 QPieModelMapper* QPieSeries::modelMapper() const
479 479 {
480 480 Q_D(const QPieSeries);
481 481 return d->m_mapper;
482 482 }
483 483
484 484 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
485 485
486 486
487 487 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
488 488 QAbstractSeriesPrivate(parent),
489 489 m_pieRelativeHorPos(0.5),
490 490 m_pieRelativeVerPos(0.5),
491 491 m_pieRelativeSize(0.7),
492 492 m_pieStartAngle(0),
493 493 m_pieEndAngle(360),
494 494 m_sum(0),
495 495 m_mapper(0)
496 496 {
497 497
498 498 }
499 499
500 500 QPieSeriesPrivate::~QPieSeriesPrivate()
501 501 {
502 502
503 503 }
504 504
505 505 void QPieSeriesPrivate::updateDerivativeData()
506 506 {
507 507 m_sum = 0;
508 508
509 509 // nothing to do?
510 510 if (m_slices.count() == 0)
511 511 return;
512 512
513 513 // calculate sum of all slices
514 514 foreach (QPieSlice* s, m_slices)
515 515 m_sum += s->value();
516 516
517 517 // nothing to show..
518 518 if (qFuzzyIsNull(m_sum))
519 519 return;
520 520
521 521 // update slice attributes
522 522 qreal sliceAngle = m_pieStartAngle;
523 523 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
524 524 QVector<QPieSlice*> changed;
525 525 foreach (QPieSlice* s, m_slices) {
526 526
527 527 PieSliceData data = PieSliceData::data(s);
528 528 data.m_percentage = s->value() / m_sum;
529 529 data.m_angleSpan = pieSpan * data.m_percentage;
530 530 data.m_startAngle = sliceAngle;
531 531 sliceAngle += data.m_angleSpan;
532 532
533 533 if (PieSliceData::data(s) != data) {
534 534 PieSliceData::data(s) = data;
535 535 changed << s;
536 536 }
537 537 }
538 538
539 539 // emit signals
540 540 foreach (QPieSlice* s, changed)
541 541 PieSliceData::data(s).emitChangedSignal(s);
542 542 }
543 543
544 544 QPieSeriesPrivate* QPieSeriesPrivate::seriesData(QPieSeries &series)
545 545 {
546 546 return series.d_func();
547 547 }
548 548
549 549 void QPieSeriesPrivate::sliceChanged()
550 550 {
551 551 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
552 552 updateDerivativeData();
553 553 }
554 554
555 555 void QPieSeriesPrivate::sliceClicked()
556 556 {
557 557 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
558 558 Q_ASSERT(m_slices.contains(slice));
559 559 Q_Q(QPieSeries);
560 560 emit q->clicked(slice);
561 561 }
562 562
563 563 void QPieSeriesPrivate::sliceHovered(bool state)
564 564 {
565 565 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
566 566 Q_ASSERT(m_slices.contains(slice));
567 567 Q_Q(QPieSeries);
568 568 emit q->hovered(slice, state);
569 569 }
570 570
571 571 void QPieSeriesPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
572 572 {
573 573 if (m_mapper) {
574 574 for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
575 575 for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
576 576 if (m_mapper->orientation() == Qt::Vertical)
577 577 {
578 578 if ( topLeft.row() >= m_mapper->first() && (m_mapper->count() == - 1 || topLeft.row() < m_mapper->first() + m_mapper->count())) {
579 579 if (topLeft.column() == m_mapper->mapValues())
580 580 m_slices.at(topLeft.row() - m_mapper->first())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
581 581 if (topLeft.column() == m_mapper->mapLabels())
582 582 m_slices.at(topLeft.row() - m_mapper->first())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
583 583 }
584 584 }
585 585 else
586 586 {
587 587 if (topLeft.column() >= m_mapper->first() && (m_mapper->count() == - 1 || topLeft.column() < m_mapper->first() + m_mapper->count())) {
588 588 if (topLeft.row() == m_mapper->mapValues())
589 589 m_slices.at(topLeft.column() - m_mapper->first())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
590 590 if (topLeft.row() == m_mapper->mapLabels())
591 591 m_slices.at(topLeft.column() - m_mapper->first())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
592 592 }
593 593 }
594 594 }
595 595 }
596 596 }
597 597 }
598 598
599 599
600 600 void QPieSeriesPrivate::modelRowsAdded(QModelIndex parent, int start, int end)
601 601 {
602 602 Q_UNUSED(parent);
603 603 if (m_mapper) {
604 604 if (m_mapper->orientation() == Qt::Vertical)
605 605 insertData(start, end);
606 606 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
607 607 initializePieFromModel();
608 608 }
609 609 }
610 610
611 611 void QPieSeriesPrivate::modelRowsRemoved(QModelIndex parent, int start, int end)
612 612 {
613 613 Q_UNUSED(parent);
614 614 if (m_mapper) {
615 615 if (m_mapper->orientation() == Qt::Vertical)
616 616 removeData(start, end);
617 617 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
618 618 initializePieFromModel();
619 619 }
620 620 }
621 621
622 622 void QPieSeriesPrivate::modelColumnsAdded(QModelIndex parent, int start, int end)
623 623 {
624 624 Q_UNUSED(parent);
625 625 if (m_mapper) {
626 626 if (m_mapper->orientation() == Qt::Horizontal)
627 627 insertData(start, end);
628 628 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
629 629 initializePieFromModel();
630 630 }
631 631 }
632 632
633 633 void QPieSeriesPrivate::modelColumnsRemoved(QModelIndex parent, int start, int end)
634 634 {
635 635 Q_UNUSED(parent);
636 636 if (m_mapper) {
637 637 if (m_mapper->orientation() == Qt::Horizontal)
638 638 removeData(start, end);
639 639 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
640 640 initializePieFromModel();
641 641 }
642 642 }
643 643
644 644 void QPieSeriesPrivate::insertData(int start, int end)
645 645 {
646 646 Q_Q(QPieSeries);
647 647 if (m_mapper) {
648 648 if (m_mapper->count() != -1 && start >= m_mapper->first() + m_mapper->count()) {
649 649 return;
650 650 } else {
651 651 int addedCount = end - start + 1;
652 652 if (m_mapper->count() != -1 && addedCount > m_mapper->count())
653 653 addedCount = m_mapper->count();
654 654 int first = qMax(start, m_mapper->first());
655 655 int last = qMin(first + addedCount - 1, m_mapper->orientation() == Qt::Vertical ? m_model->rowCount() - 1 : m_model->columnCount() - 1);
656 656 for (int i = first; i <= last; i++) {
657 657 QPieSlice *slice = new QPieSlice;
658 658 if (m_mapper->orientation() == Qt::Vertical) {
659 659 slice->setValue(m_model->data(m_model->index(i, m_mapper->mapValues()), Qt::DisplayRole).toDouble());
660 660 slice->setLabel(m_model->data(m_model->index(i, m_mapper->mapLabels()), Qt::DisplayRole).toString());
661 661 } else {
662 662 slice->setValue(m_model->data(m_model->index(m_mapper->mapValues(), i), Qt::DisplayRole).toDouble());
663 663 slice->setLabel(m_model->data(m_model->index(m_mapper->mapLabels(), i), Qt::DisplayRole).toString());
664 664 }
665 665 slice->setLabelVisible();
666 666 q->insert(i - m_mapper->first(), slice);
667 667 }
668 668 if (m_mapper->count() != -1 && m_slices.size() > m_mapper->count())
669 669 for (int i = m_slices.size() - 1; i >= m_mapper->count(); i--)
670 670 q->remove(q->slices().at(i));
671 671 }
672 672 }
673 673 }
674 674
675 675 void QPieSeriesPrivate::removeData(int start, int end)
676 676 {
677 677 Q_Q(QPieSeries);
678 678 if (m_mapper) {
679 679 int removedCount = end - start + 1;
680 680 if (m_mapper->count() != -1 && start >= m_mapper->first() + m_mapper->count()) {
681 681 return;
682 682 } else {
683 683 int toRemove = qMin(m_slices.size(), removedCount); // first find how many items can actually be removed
684 684 int first = qMax(start, m_mapper->first()); // get the index of the first item that will be removed.
685 685 int last = qMin(first + toRemove - 1, m_slices.size() + m_mapper->first() - 1); // get the index of the last item that will be removed.
686 686 for (int i = last; i >= first; i--)
687 687 q->remove(q->slices().at(i - m_mapper->first()));
688 688
689 689 if (m_mapper->count() != -1) {
690 690 int itemsAvailable; // check how many are available to be added
691 691 if (m_mapper->orientation() == Qt::Vertical)
692 692 itemsAvailable = m_model->rowCount() - m_mapper->first() - m_slices.size();
693 693 else
694 694 itemsAvailable = m_model->columnCount() - m_mapper->first() - m_slices.size();
695 695 int toBeAdded = qMin(itemsAvailable, m_mapper->count() - m_slices.size()); // add not more items than there is space left to be filled.
696 696 int currentSize = m_slices.size();
697 697 if (toBeAdded > 0)
698 698 for (int i = m_slices.size(); i < currentSize + toBeAdded; i++) {
699 699 QPieSlice *slice = new QPieSlice;
700 700 if (m_mapper->orientation() == Qt::Vertical) {
701 701 slice->setValue(m_model->data(m_model->index(i + m_mapper->first(), m_mapper->mapValues()), Qt::DisplayRole).toDouble());
702 702 slice->setLabel(m_model->data(m_model->index(i + m_mapper->first(), m_mapper->mapLabels()), Qt::DisplayRole).toString());
703 703 } else {
704 704 slice->setValue(m_model->data(m_model->index(m_mapper->mapValues(), i + m_mapper->first()), Qt::DisplayRole).toDouble());
705 705 slice->setLabel(m_model->data(m_model->index(m_mapper->mapLabels(), i + m_mapper->first()), Qt::DisplayRole).toString());
706 706 }
707 707 slice->setLabelVisible();
708 708 q->insert(i, slice);
709 709 }
710 710 }
711 711 }
712 712 }
713 713 }
714 714
715 715 void QPieSeriesPrivate::initializePieFromModel()
716 716 {
717 717 Q_Q(QPieSeries);
718 718
719 if (m_model == 0 || m_mapper == 0)
720 return;
721
722 719 // clear current content
723 720 q->clear();
724 721
722 if (m_model == 0 || m_mapper == 0)
723 return;
724
725 725 // check if mappings are set
726 726 if (m_mapper->mapValues() == -1 || m_mapper->mapLabels() == -1)
727 727 return;
728 728
729 729 // create the initial slices set
730 730 if (m_mapper->orientation() == Qt::Vertical) {
731 731 if (m_mapper->mapValues() >= m_model->columnCount() || m_mapper->mapLabels() >= m_model->columnCount())
732 732 return; // mapped columns are not existing
733 733
734 734 int sliceCount = 0;
735 735 if(m_mapper->count() == -1)
736 736 sliceCount = m_model->rowCount() - m_mapper->first();
737 737 else
738 738 sliceCount = qMin(m_mapper->count(), m_model->rowCount() - m_mapper->first());
739 739 for (int i = m_mapper->first(); i < m_mapper->first() + sliceCount; i++)
740 740 q->append(m_model->data(m_model->index(i, m_mapper->mapValues()), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(i, m_mapper->mapLabels()), Qt::DisplayRole).toString());
741 741 } else {
742 742 if (m_mapper->mapValues() >= m_model->rowCount() || m_mapper->mapLabels() >= m_model->rowCount())
743 743 return; // mapped columns are not existing
744 744
745 745 int sliceCount = 0;
746 746 if(m_mapper->count() == -1)
747 747 sliceCount = m_model->columnCount() - m_mapper->first();
748 748 else
749 749 sliceCount = qMin(m_mapper->count(), m_model->columnCount() - m_mapper->first());
750 750 for (int i = m_mapper->first(); i < m_mapper->first() + sliceCount; i++)
751 751 q->append(m_model->data(m_model->index(m_mapper->mapValues(), i), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(m_mapper->mapLabels(), i), Qt::DisplayRole).toString());
752 752 }
753 753 q->setLabelsVisible(true);
754 754 }
755 755
756 756 bool QPieSeriesPrivate::setRealValue(qreal &value, qreal newValue, qreal max, qreal min)
757 757 {
758 758 // Remove rounding errors
759 759 qreal roundedValue = newValue;
760 760 if (qFuzzyIsNull(min) && qFuzzyIsNull(newValue))
761 761 roundedValue = 0.0;
762 762 else if (qFuzzyCompare(newValue, max))
763 763 roundedValue = max;
764 764 else if (qFuzzyCompare(newValue, min))
765 765 roundedValue = min;
766 766
767 767 // Check if the position is valid after removing the rounding errors
768 768 if (roundedValue < min || roundedValue > max) {
769 769 qWarning("QPieSeries: Illegal value");
770 770 return false;
771 771 }
772 772
773 773 if (!qFuzzyIsNull(value - roundedValue)) {
774 774 value = roundedValue;
775 775 return true;
776 776 }
777 777
778 778 // The change was so small it is considered a rounding error
779 779 return false;
780 780 }
781 781
782 782 void QPieSeriesPrivate::scaleDomain(Domain& domain)
783 783 {
784 784 Q_UNUSED(domain);
785 785 #ifndef QT_NO_DEBUG
786 786 qWarning() << __FILE__<<__FUNCTION__<<"not implemented";
787 787 #endif
788 788 }
789 789
790 790 Chart* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
791 791 {
792 792 Q_Q(QPieSeries);
793 793 PieChartItem* pie = new PieChartItem(q,presenter);
794 794 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
795 795 presenter->animator()->addAnimation(pie);
796 796 }
797 797 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
798 798 return pie;
799 799 }
800 800
801 801 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
802 802 {
803 803 Q_Q(QPieSeries);
804 804 QList<LegendMarker*> markers;
805 805 foreach(QPieSlice* slice, q->slices()) {
806 806 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
807 807 markers << marker;
808 808 }
809 809 return markers;
810 810 }
811 811
812 812 #include "moc_qpieseries.cpp"
813 813 #include "moc_qpieseries_p.cpp"
814 814
815 815 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,347 +1,403
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include <QtTest/QtTest>
22 22 #include <qgroupedbarseries.h>
23 23 #include <qbarset.h>
24 24 #include <qchartview.h>
25 25 #include <qchart.h>
26 #include <QBarModelMapper>
27 #include <QStandardItemModel>
26 28
27 29 QTCOMMERCIALCHART_USE_NAMESPACE
28 30
29 31 Q_DECLARE_METATYPE(QBarSet*)
30 32
31 33 class tst_QGroupedBarSeries : public QObject
32 34 {
33 35 Q_OBJECT
34 36
35 37 public slots:
36 38 void initTestCase();
37 39 void cleanupTestCase();
38 40 void init();
39 41 void cleanup();
40 42
41 43 private slots:
42 44 void qgroupedbarseries_data();
43 45 void qgroupedbarseries();
44 46 void type_data();
45 47 void type();
46 48 void mouseclicked_data();
47 49 void mouseclicked();
48 50 void mousehovered_data();
49 51 void mousehovered();
52 void model();
50 53
51 54 private:
52 55 QGroupedBarSeries* m_barseries;
53 56 };
54 57
55 58 void tst_QGroupedBarSeries::initTestCase()
56 59 {
57 60 qRegisterMetaType<QBarSet*>("QBarSet*");
58 61 }
59 62
60 63 void tst_QGroupedBarSeries::cleanupTestCase()
61 64 {
62 65 }
63 66
64 67 void tst_QGroupedBarSeries::init()
65 68 {
66 69 m_barseries = new QGroupedBarSeries();
67 70 }
68 71
69 72 void tst_QGroupedBarSeries::cleanup()
70 73 {
71 74 delete m_barseries;
72 75 m_barseries = 0;
73 76 }
74 77
75 78 void tst_QGroupedBarSeries::qgroupedbarseries_data()
76 79 {
77 80 }
78 81
79 82 void tst_QGroupedBarSeries::qgroupedbarseries()
80 83 {
81 84 QGroupedBarSeries *barseries = new QGroupedBarSeries();
82 85 QVERIFY(barseries != 0);
83 86 }
84 87
85 88 void tst_QGroupedBarSeries::type_data()
86 89 {
87 90
88 91 }
89 92
90 93 void tst_QGroupedBarSeries::type()
91 94 {
92 95 QVERIFY(m_barseries->type() == QAbstractSeries::SeriesTypeGroupedBar);
93 96 }
94 97
95 98 void tst_QGroupedBarSeries::mouseclicked_data()
96 99 {
97 100
98 101 }
99 102
100 103 void tst_QGroupedBarSeries::mouseclicked()
101 104 {
102 105 QGroupedBarSeries* series = new QGroupedBarSeries();
103 106 QBarCategories categories;
104 107 categories << "test1" << "test2" << "test3";
105 108 series->setCategories(categories);
106 109
107 110 QBarSet* set1 = new QBarSet(QString("set 1"));
108 111 *set1 << 10 << 10 << 10;
109 112 series->appendBarSet(set1);
110 113
111 114 QBarSet* set2 = new QBarSet(QString("set 2"));
112 115 *set2 << 10 << 10 << 10;
113 116 series->appendBarSet(set2);
114 117
115 118 QSignalSpy setSpy1(set1, SIGNAL(clicked(QString)));
116 119 QSignalSpy setSpy2(set2, SIGNAL(clicked(QString)));
117 120 QSignalSpy seriesSpy(series,SIGNAL(clicked(QBarSet*,QString)));
118 121
119 122 QChartView view(new QChart());
120 123 view.resize(400,300);
121 124 view.chart()->addSeries(series);
122 125 view.show();
123 126 QTest::qWaitForWindowShown(&view);
124 127
125 128 //====================================================================================
126 129 // barset 1, category test1
127 130 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(100,180));
128 131 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
129 132
130 133 QCOMPARE(setSpy1.count(), 1);
131 134 QCOMPARE(setSpy2.count(), 0);
132 135 QCOMPARE(seriesSpy.count(), 1);
133 136 QList<QVariant> setSpyArg = setSpy1.takeFirst();
134 137 QVERIFY(setSpyArg.at(0).type() == QVariant::String);
135 138 QVERIFY(setSpyArg.at(0).toString().compare(QString("test1")) == 0);
136 139
137 140 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
138 141 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set1);
139 142
140 143 //====================================================================================
141 144 // barset 1, category test2
142 145 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(190,180));
143 146 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
144 147
145 148 QCOMPARE(setSpy1.count(), 1);
146 149 QCOMPARE(setSpy2.count(), 0);
147 150 QCOMPARE(seriesSpy.count(), 1);
148 151 setSpyArg = setSpy1.takeFirst();
149 152 QVERIFY(setSpyArg.at(0).type() == QVariant::String);
150 153 QVERIFY(setSpyArg.at(0).toString().compare(QString("test2")) == 0);
151 154
152 155 seriesSpyArg = seriesSpy.takeFirst();
153 156 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set1);
154 157
155 158 //====================================================================================
156 159 // barset 1, category test3
157 160 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(280,180));
158 161 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
159 162
160 163 QCOMPARE(setSpy1.count(), 1);
161 164 QCOMPARE(setSpy2.count(), 0);
162 165 QCOMPARE(seriesSpy.count(), 1);
163 166 setSpyArg = setSpy1.takeFirst();
164 167 QVERIFY(setSpyArg.at(0).type() == QVariant::String);
165 168 QVERIFY(setSpyArg.at(0).toString().compare(QString("test3")) == 0);
166 169
167 170 seriesSpyArg = seriesSpy.takeFirst();
168 171 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set1);
169 172
170 173 //====================================================================================
171 174 // barset 2, category test1
172 175 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(130,180));
173 176 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
174 177
175 178 QCOMPARE(setSpy1.count(), 0);
176 179 QCOMPARE(setSpy2.count(), 1);
177 180 QCOMPARE(seriesSpy.count(), 1);
178 181 setSpyArg = setSpy2.takeFirst();
179 182 QVERIFY(setSpyArg.at(0).type() == QVariant::String);
180 183 QVERIFY(setSpyArg.at(0).toString().compare(QString("test1")) == 0);
181 184
182 185 seriesSpyArg = seriesSpy.takeFirst();
183 186 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set2);
184 187
185 188 //====================================================================================
186 189 // barset 2, category test2
187 190 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(220,180));
188 191 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
189 192
190 193 QCOMPARE(setSpy1.count(), 0);
191 194 QCOMPARE(setSpy2.count(), 1);
192 195 QCOMPARE(seriesSpy.count(), 1);
193 196 setSpyArg = setSpy2.takeFirst();
194 197 QVERIFY(setSpyArg.at(0).type() == QVariant::String);
195 198 QVERIFY(setSpyArg.at(0).toString().compare(QString("test2")) == 0);
196 199
197 200 seriesSpyArg = seriesSpy.takeFirst();
198 201 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set2);
199 202
200 203 //====================================================================================
201 204 // barset 2, category test3
202 205 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(310,180));
203 206 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
204 207
205 208 QCOMPARE(setSpy1.count(), 0);
206 209 QCOMPARE(setSpy2.count(), 1);
207 210 QCOMPARE(seriesSpy.count(), 1);
208 211 setSpyArg = setSpy2.takeFirst();
209 212 QVERIFY(setSpyArg.at(0).type() == QVariant::String);
210 213 QVERIFY(setSpyArg.at(0).toString().compare(QString("test3")) == 0);
211 214
212 215 seriesSpyArg = seriesSpy.takeFirst();
213 216 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set2);
214 217
215 218 //====================================================================================
216 219 // no event cases
217 220 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(1,1)); // Outside of both sets
218 221 QTest::mouseClick(view.viewport(), Qt::RightButton, 0, QPoint(1,1)); // Right mouse button outside and inside sets
219 222 QTest::mouseClick(view.viewport(), Qt::RightButton, 0, QPoint(100,180)); // barset 1, category test1
220 223 QTest::mouseClick(view.viewport(), Qt::RightButton, 0, QPoint(190,180)); // barset 1, category test2
221 224 QTest::mouseClick(view.viewport(), Qt::RightButton, 0, QPoint(280,180)); // barset 1, category test3
222 225 QTest::mouseClick(view.viewport(), Qt::RightButton, 0, QPoint(130,180)); // barset 2, category test1
223 226 QTest::mouseClick(view.viewport(), Qt::RightButton, 0, QPoint(220,180)); // barset 2, category test2
224 227 QTest::mouseClick(view.viewport(), Qt::RightButton, 0, QPoint(310,180)); // barset 2, category test3
225 228
226 229 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
227 230 QCOMPARE(setSpy1.count(), 0);
228 231 QCOMPARE(setSpy2.count(), 0);
229 232 QCOMPARE(seriesSpy.count(), 0);
230 233 }
231 234
232 235 void tst_QGroupedBarSeries::mousehovered_data()
233 236 {
234 237
235 238 }
236 239
237 240 void tst_QGroupedBarSeries::mousehovered()
238 241 {
239 242 QGroupedBarSeries* series = new QGroupedBarSeries();
240 243 QBarCategories categories;
241 244 categories << "test1" << "test2" << "test3";
242 245 series->setCategories(categories);
243 246
244 247 QBarSet* set1 = new QBarSet(QString("set 1"));
245 248 *set1 << 10 << 10 << 10;
246 249 series->appendBarSet(set1);
247 250
248 251 QBarSet* set2 = new QBarSet(QString("set 2"));
249 252 *set2 << 10 << 10 << 10;
250 253 series->appendBarSet(set2);
251 254
252 255 QSignalSpy setSpy1(set1, SIGNAL(hovered(bool)));
253 256 QSignalSpy setSpy2(set2, SIGNAL(hovered(bool)));
254 257 QSignalSpy seriesSpy(series,SIGNAL(hovered(QBarSet*,bool)));
255 258
256 259 QChartView view(new QChart());
257 260 view.resize(400,300);
258 261 view.chart()->addSeries(series);
259 262 view.show();
260 263 QTest::qWaitForWindowShown(&view);
261 264
262 265 //this is hack since view does not get events otherwise
263 266 view.setMouseTracking(true);
264 267
265 268 //=======================================================================
266 269 // move mouse to left border
267 270 QTest::mouseMove(view.viewport(), QPoint(0, 180));
268 271
269 272 QVERIFY(setSpy1.count() == 0);
270 273 QVERIFY(setSpy2.count() == 0);
271 274 QVERIFY(seriesSpy.count() == 0);
272 275
273 276 //=======================================================================
274 277 // move mouse on top of set1
275 278 QTest::mouseMove(view.viewport(), QPoint(100,180));
276 279
277 280 QVERIFY(setSpy1.count() == 1);
278 281 QVERIFY(setSpy2.count() == 0);
279 282 QVERIFY(seriesSpy.count() == 1);
280 283
281 284 QList<QVariant> setSpyArg = setSpy1.takeFirst();
282 285 QVERIFY(setSpyArg.at(0).type() == QVariant::Bool);
283 286 QVERIFY(setSpyArg.at(0).toBool() == true);
284 287
285 288 QList<QVariant> seriesSpyArg = seriesSpy.takeFirst();
286 289 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set1);
287 290
288 291 //=======================================================================
289 292 // move mouse from top of set1 to top of set2
290 293 QTest::mouseMove(view.viewport(), QPoint(130,180));
291 294
292 295 QVERIFY(setSpy1.count() == 1);
293 296 QVERIFY(setSpy2.count() == 1);
294 297 QVERIFY(seriesSpy.count() == 2);
295 298
296 299 // should leave set1
297 300 setSpyArg = setSpy1.takeFirst();
298 301 QVERIFY(setSpyArg.at(0).type() == QVariant::Bool);
299 302 QVERIFY(setSpyArg.at(0).toBool() == false);
300 303
301 304 // should enter set2
302 305 setSpyArg = setSpy2.takeFirst();
303 306 QVERIFY(setSpyArg.at(0).type() == QVariant::Bool);
304 307 QVERIFY(setSpyArg.at(0).toBool() == true);
305 308
306 309 // should leave set1
307 310 seriesSpyArg = seriesSpy.takeFirst();
308 311 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set1);
309 312 QVERIFY(seriesSpyArg.at(1).type() == QVariant::Bool);
310 313 QVERIFY(seriesSpyArg.at(1).toBool() == false);
311 314
312 315 // should enter set2
313 316 seriesSpyArg = seriesSpy.takeFirst();
314 317 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set2);
315 318 QVERIFY(seriesSpyArg.at(1).type() == QVariant::Bool);
316 319 QVERIFY(seriesSpyArg.at(1).toBool() == true);
317 320
318 321 //=======================================================================
319 322 // move mouse from top of set2 to background
320 323 QTest::mouseMove(view.viewport(), QPoint(160,180));
321 324
322 325 QVERIFY(setSpy1.count() == 0);
323 326 QVERIFY(setSpy2.count() == 1);
324 327 QVERIFY(seriesSpy.count() == 1);
325 328
326 329 // should leave set2 (event via set)
327 330 setSpyArg = setSpy2.takeFirst();
328 331 QVERIFY(setSpyArg.at(0).type() == QVariant::Bool);
329 332 QVERIFY(setSpyArg.at(0).toBool() == false);
330 333
331 334 // should leave set2 (event via series)
332 335 seriesSpyArg = seriesSpy.takeFirst();
333 336 QCOMPARE(qvariant_cast<QBarSet*>(seriesSpyArg.at(0)), set2);
334 337 QVERIFY(seriesSpyArg.at(1).type() == QVariant::Bool);
335 338 QVERIFY(seriesSpyArg.at(1).toBool() == false);
336 339 }
337 340
341 void tst_QGroupedBarSeries::model()
342 {
343 QGroupedBarSeries *series = new QGroupedBarSeries;
344 QChart *chart = new QChart;
345 chart->addSeries(series);
346 QChartView *chartView = new QChartView(chart);
347 chartView->show();
348
349 int rowCount = 12;
350 int columnCount = 5;
351 QStandardItemModel *stdModel = new QStandardItemModel(rowCount, columnCount);
352 series->setModel(stdModel);
353 QVERIFY2((series->model()) == stdModel, "Model should be stdModel");
354
355
356 for (int row = 0; row < rowCount; ++row) {
357 for (int column = 0; column < columnCount; column++) {
358 QStandardItem *item = new QStandardItem(row * column);
359 stdModel->setItem(row, column, item);
360 }
361 }
362
363 // data has been added to the model, but mapper is not set the number of slices should still be 0
364 QVERIFY2(series->barsetCount() == 0, "Mapper has not been set, so the number of slices should be 0");
365
366 // set the mapper
367 QBarModelMapper *mapper = new QBarModelMapper;
368 mapper->setMapCategories(0);
369 mapper->setMapBarBottom(1);
370 mapper->setMapBarTop(3);
371 series->setModelMapper(mapper); // this should cause the Pie to get initialized from the model, since there is now both the model and the mapper defined
372 QCOMPARE(series->barsetCount(), 3);
373
374 // set the mappings to be outside of the model
375 mapper->setMapBarBottom(6);
376 mapper->setMapBarTop(7);
377 QCOMPARE(series->barsetCount(), 0); // Mappings are invalid, so the number of slices should be 0
378
379 // set back to correct ones
380 mapper->setMapBarBottom(1);
381 mapper->setMapBarTop(3);
382 QCOMPARE(series->barsetCount(), 3);
383
384 // reset the mappings
385 mapper->reset();
386 QCOMPARE(series->barsetCount(), 0); // Mappings have been reset and are invalid, so the number of slices should be 0
387
388 // unset the model and the mapper
389 series->setModel(0);
390 series->setModelMapper(0);
391 QVERIFY(series->model() == 0); // Model should be unset
392 QVERIFY(series->modelMapper() == 0); // Model mapper should be unset
393 }
338 394
339 395 /*
340 396 bool setModel(QAbstractItemModel *model);
341 397 void setModelMapping(int categories, int bottomBoundary, int topBoundary, Qt::Orientation orientation = Qt::Vertical);
342 398 void setModelMappingRange(int first, int count = -1);
343 399 */
344 400 QTEST_MAIN(tst_QGroupedBarSeries)
345 401
346 402 #include "tst_qgroupedbarseries.moc"
347 403
@@ -1,477 +1,477
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include <QtTest/QtTest>
22 22 #include <qchartview.h>
23 23 #include <qchart.h>
24 24 #include <qpieseries.h>
25 25 #include <qpieslice.h>
26 26 #include <qpiemodelmapper.h>
27 27 #include <QStandardItemModel>
28 28 #include <tst_definitions.h>
29 29
30 30 QTCOMMERCIALCHART_USE_NAMESPACE
31 31
32 32 Q_DECLARE_METATYPE(QPieSlice*)
33 33
34 34 class tst_qpieseries : public QObject
35 35 {
36 36 Q_OBJECT
37 37
38 38 public slots:
39 39 void initTestCase();
40 40 void cleanupTestCase();
41 41 void init();
42 42 void cleanup();
43 43
44 44 private slots:
45 45 void construction();
46 46 void append();
47 47 void insert();
48 48 void remove();
49 49 void calculatedValues();
50 50 void clickedSignal();
51 51 void hoverSignal();
52 52 void model();
53 53 void modelCustomMap();
54 54 void modelUpdate();
55 55
56 56 private:
57 57 void verifyCalculatedData(const QPieSeries &series, bool *ok);
58 58
59 59 private:
60 60
61 61 };
62 62
63 63 void tst_qpieseries::initTestCase()
64 64 {
65 65 qRegisterMetaType<QPieSlice*>("QPieSlice*");
66 66 }
67 67
68 68 void tst_qpieseries::cleanupTestCase()
69 69 {
70 70 }
71 71
72 72 void tst_qpieseries::init()
73 73 {
74 74
75 75 }
76 76
77 77 void tst_qpieseries::cleanup()
78 78 {
79 79
80 80 }
81 81
82 82 void tst_qpieseries::construction()
83 83 {
84 84 // verify default values
85 85 QPieSeries s;
86 86 QVERIFY(s.type() == QAbstractSeries::SeriesTypePie);
87 87 QVERIFY(s.count() == 0);
88 88 QVERIFY(s.isEmpty());
89 89 QCOMPARE(s.sum(), 0.0);
90 90 QCOMPARE(s.horizontalPosition(), 0.5);
91 91 QCOMPARE(s.verticalPosition(), 0.5);
92 92 QCOMPARE(s.pieSize(), 0.7);
93 93 QCOMPARE(s.pieStartAngle(), 0.0);
94 94 QCOMPARE(s.pieEndAngle(), 360.0);
95 95 }
96 96
97 97 void tst_qpieseries::append()
98 98 {
99 99 QPieSeries s;
100 100
101 101 // append pointer
102 102 QPieSlice *slice1 = 0;
103 103 QVERIFY(!s.append(slice1));
104 104 slice1 = new QPieSlice(1, "slice 1");
105 105 QVERIFY(s.append(slice1));
106 106 QVERIFY(!s.append(slice1));
107 107 QCOMPARE(s.count(), 1);
108 108
109 109 // append pointer list
110 110 QList<QPieSlice *> list;
111 111 QVERIFY(!s.append(list));
112 112 list << (QPieSlice *) 0;
113 113 QVERIFY(!s.append(list));
114 114 list.clear();
115 115 list << new QPieSlice(2, "slice 2");
116 116 list << new QPieSlice(3, "slice 3");
117 117 QVERIFY(s.append(list));
118 118 QVERIFY(!s.append(list));
119 119 QCOMPARE(s.count(), 3);
120 120
121 121 // append operator
122 122 s << new QPieSlice(4, "slice 4");
123 123 s << slice1; // fails because already added
124 124 QCOMPARE(s.count(), 4);
125 125
126 126 // append with params
127 127 QPieSlice *slice5 = s.append(5, "slice 5");
128 128 QVERIFY(slice5 != 0);
129 129 QCOMPARE(slice5->value(), 5.0);
130 130 QCOMPARE(slice5->label(), QString("slice 5"));
131 131 QCOMPARE(s.count(), 5);
132 132
133 133 // check slices
134 134 QVERIFY(!s.isEmpty());
135 135 for (int i=0; i<s.count(); i++) {
136 136 QCOMPARE(s.slices().at(i)->value(), (qreal) i+1);
137 137 QCOMPARE(s.slices().at(i)->label(), QString("slice ") + QString::number(i+1));
138 138 }
139 139 }
140 140
141 141 void tst_qpieseries::insert()
142 142 {
143 143 QPieSeries s;
144 144
145 145 // insert one slice
146 146 QPieSlice *slice1 = 0;
147 147 QVERIFY(!s.insert(0, slice1));
148 148 slice1 = new QPieSlice(1, "slice 1");
149 149 QVERIFY(!s.insert(-1, slice1));
150 150 QVERIFY(!s.insert(5, slice1));
151 151 QVERIFY(s.insert(0, slice1));
152 152 QVERIFY(!s.insert(0, slice1));
153 153 QCOMPARE(s.count(), 1);
154 154
155 155 // add some more slices
156 156 s.append(2, "slice 2");
157 157 s.append(4, "slice 4");
158 158 QCOMPARE(s.count(), 3);
159 159
160 160 // insert between slices
161 161 s.insert(2, new QPieSlice(3, "slice 3"));
162 162 QCOMPARE(s.count(), 4);
163 163
164 164 // check slices
165 165 for (int i=0; i<s.count(); i++) {
166 166 QCOMPARE(s.slices().at(i)->value(), (qreal) i+1);
167 167 QCOMPARE(s.slices().at(i)->label(), QString("slice ") + QString::number(i+1));
168 168 }
169 169 }
170 170
171 171 void tst_qpieseries::remove()
172 172 {
173 173 QPieSeries s;
174 174
175 175 // add some slices
176 176 QPieSlice *slice1 = s.append(1, "slice 1");
177 177 QPieSlice *slice2 = s.append(2, "slice 2");
178 178 QPieSlice *slice3 = s.append(3, "slice 3");
179 179 QSignalSpy spy1(slice1, SIGNAL(destroyed()));
180 180 QSignalSpy spy2(slice2, SIGNAL(destroyed()));
181 181 QSignalSpy spy3(slice3, SIGNAL(destroyed()));
182 182 QCOMPARE(s.count(), 3);
183 183
184 184 // null pointer remove
185 185 QVERIFY(!s.remove(0));
186 186
187 187 // remove first
188 188 QVERIFY(s.remove(slice1));
189 189 QVERIFY(!s.remove(slice1));
190 190 QCOMPARE(s.count(), 2);
191 191 QCOMPARE(s.slices().at(0)->label(), slice2->label());
192 192
193 193 // remove all
194 194 s.clear();
195 195 QVERIFY(s.isEmpty());
196 196 QVERIFY(s.slices().isEmpty());
197 197 QCOMPARE(s.count(), 0);
198 198
199 199 // check that slices were actually destroyed
200 200 TRY_COMPARE(spy1.count(), 1);
201 201 TRY_COMPARE(spy2.count(), 1);
202 202 TRY_COMPARE(spy3.count(), 1);
203 203 }
204 204
205 205 void tst_qpieseries::calculatedValues()
206 206 {
207 207 bool ok;
208 208 QPieSeries s;
209 209
210 210 // add a slice
211 211 QPieSlice *slice1 = s.append(1, "slice 1");
212 212 verifyCalculatedData(s, &ok);
213 213 if (!ok)
214 214 return;
215 215
216 216 // add some more slices
217 217 QList<QPieSlice *> list;
218 218 list << new QPieSlice(2, "slice 2");
219 219 list << new QPieSlice(3, "slice 3");
220 220 s.append(list);
221 221 verifyCalculatedData(s, &ok);
222 222 if (!ok)
223 223 return;
224 224
225 225 // remove a slice
226 226 s.remove(slice1);
227 227 verifyCalculatedData(s, &ok);
228 228 if (!ok)
229 229 return;
230 230
231 231 // insert a slice
232 232 s.insert(0, new QPieSlice(1, "Slice 4"));
233 233 verifyCalculatedData(s, &ok);
234 234 if (!ok)
235 235 return;
236 236
237 237 // clear all
238 238 s.clear();
239 239 verifyCalculatedData(s, &ok);
240 240 }
241 241
242 242 void tst_qpieseries::verifyCalculatedData(const QPieSeries &series, bool *ok)
243 243 {
244 244 *ok = false;
245 245
246 246 qreal sum = 0;
247 247 foreach (const QPieSlice *slice, series.slices())
248 248 sum += slice->value();
249 249 QCOMPARE(series.sum(), sum);
250 250
251 251 qreal startAngle = series.pieStartAngle();
252 252 qreal pieAngleSpan = series.pieEndAngle() - series.pieStartAngle();
253 253 foreach (const QPieSlice *slice, series.slices()) {
254 254 qreal ratio = slice->value() / sum;
255 255 qreal sliceSpan = pieAngleSpan * ratio;
256 256 QCOMPARE(slice->startAngle(), startAngle);
257 257 QCOMPARE(slice->endAngle(), startAngle + sliceSpan);
258 258 QCOMPARE(slice->percentage(), ratio);
259 259 startAngle += sliceSpan;
260 260 }
261 261
262 262 if (!series.isEmpty())
263 263 QCOMPARE(series.slices().last()->endAngle(), series.pieEndAngle());
264 264
265 265 *ok = true;
266 266 }
267 267
268 268
269 269 void tst_qpieseries::clickedSignal()
270 270 {
271 271 // create a pie series
272 272 QPieSeries *series = new QPieSeries();
273 273 series->setPieSize(1.0);
274 274 QPieSlice *s1 = series->append(1, "slice 1");
275 275 series->append(2, "slice 2");
276 276 series->append(3, "slice 3");
277 277 QSignalSpy clickSpy1(series, SIGNAL(clicked(QPieSlice*)));
278 278
279 279 // add series to the chart
280 280 QChartView view(new QChart());
281 281 view.resize(200, 200);
282 282 view.chart()->addSeries(series);
283 283 view.show();
284 284 QTest::qWaitForWindowShown(&view);
285 285
286 286 // simulate clicks
287 287 // pie rectangle: QRectF(60,60 121x121)
288 288 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(139, 85)); // inside slice 1
289 289 TRY_COMPARE(clickSpy1.count(), 1);
290 290 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy1.at(0).at(0)), s1);
291 291 }
292 292
293 293 void tst_qpieseries::hoverSignal()
294 294 {
295 295 // create a pie series
296 296 QPieSeries *series = new QPieSeries();
297 297 series->setPieSize(1.0);
298 298 QPieSlice *s1 = series->append(1, "slice 1");
299 299 series->append(2, "slice 2");
300 300 series->append(3, "slice 3");
301 301
302 302 // add series to the chart
303 303 QChartView view(new QChart());
304 304 view.resize(200, 200);
305 305 view.chart()->addSeries(series);
306 306 view.show();
307 307 QTest::qWaitForWindowShown(&view);
308 308
309 309 // first move to right top corner
310 310 QTest::mouseMove(view.viewport(), QPoint(200, 0));
311 311 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
312 312
313 313 // move inside the slice
314 314 // pie rectangle: QRectF(60,60 121x121)
315 315 QSignalSpy hoverSpy(series, SIGNAL(hovered(QPieSlice*,bool)));
316 316 QTest::mouseMove(view.viewport(), QPoint(139, 85));
317 317 TRY_COMPARE(hoverSpy.count(), 1);
318 318 QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(0).at(0)), s1);
319 319 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(0).at(1)), true);
320 320
321 321 // move outside the slice
322 322 QTest::mouseMove(view.viewport(), QPoint(200, 0));
323 323 TRY_COMPARE(hoverSpy.count(), 2);
324 324 QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(1).at(0)), s1);
325 325 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(1).at(1)), false);
326 326 }
327 327
328 328 void tst_qpieseries::model()
329 329 {
330 330 QPieSeries *series = new QPieSeries;
331 331 QChart *chart = new QChart;
332 332 chart->addSeries(series);
333 333 QChartView *chartView = new QChartView(chart);
334 334 chartView->show();
335 335
336 336 QStandardItemModel *stdModel = new QStandardItemModel(0, 2);
337 337 series->setModel(stdModel);
338 338 QVERIFY2((series->model()) == stdModel, "Model should be stdModel");
339 339
340 340 int rowCount = 3;
341 341 for (int row = 0; row < rowCount; ++row) {
342 342 for (int column = 0; column < 2; column++) {
343 343 QStandardItem *item = new QStandardItem(row * column);
344 344 stdModel->setItem(row, column, item);
345 345 }
346 346 }
347 347
348 348 // data has been added to the model, but mapper is not set the number of slices should still be 0
349 349 QVERIFY2(series->slices().count() == 0, "Mapper has not been set, so the number of slices should be 0");
350 350
351 351 // set the mapper
352 352 QPieModelMapper *mapper = new QPieModelMapper;
353 353 mapper->setMapValues(0);
354 354 mapper->setMapLabels(0);
355 355 series->setModelMapper(mapper); // this should cause the Pie to get initialized from the model, since there is now both the model and the mapper defined
356 356 QCOMPARE(series->slices().count(), rowCount);
357 357
358 358 // set the mappings to be outside of the model
359 359 mapper->setMapLabels(5);
360 360 mapper->setMapValues(4);
361 361 QCOMPARE(series->slices().count(), 0); // Mappings are invalid, so the number of slices should be 0
362 362
363 363 // set back to correct ones
364 364 mapper->setMapValues(0);
365 365 mapper->setMapLabels(0);
366 366 QCOMPARE(series->slices().count(), rowCount);
367 367
368 368 // reset the mappings
369 369 mapper->reset();
370 370 QCOMPARE(series->slices().count(), 0); // Mappings have been reset and are invalid, so the number of slices should be 0
371 371
372 372 // unset the model and the mapper
373 373 series->setModel(0);
374 374 series->setModelMapper(0);
375 375 QVERIFY(series->model() == 0); // Model should be unset
376 376 QVERIFY(series->modelMapper() == 0); // Model mapper should be unset
377 377 }
378 378
379 379 void tst_qpieseries::modelCustomMap()
380 380 {
381 381 int rowCount = 12;
382 382 int columnCount = 3;
383 383 QStandardItemModel *stdModel = new QStandardItemModel(0, 3);
384 384 for (int row = 0; row < rowCount; ++row) {
385 385 for (int column = 0; column < 2; column++) {
386 386 QStandardItem *item = new QStandardItem(row * column);
387 387 stdModel->setItem(row, column, item);
388 388 }
389 389 }
390 390
391 391 QPieSeries *series = new QPieSeries;
392 392 QChart *chart = new QChart;
393 393 chart->addSeries(series);
394 394 QChartView *chartView = new QChartView(chart);
395 395 chartView->show();
396 396 series->setModel(stdModel);
397 397
398 398 QPieModelMapper *mapper = new QPieModelMapper;
399 399 mapper->setMapValues(0);
400 400 mapper->setMapLabels(0);
401 401 series->setModelMapper(mapper);
402 402 QCOMPARE(series->slices().count(), rowCount);
403 403
404 404 // lets change the orientation to horizontal
405 405 mapper->setOrientation(Qt::Horizontal);
406 406 QCOMPARE(series->slices().count(), columnCount);
407 407
408 408 // change it back to vertical
409 409 mapper->setOrientation(Qt::Vertical);
410 410 QCOMPARE(series->slices().count(), rowCount);
411 411
412 412 // lets customize the mapping
413 413 int first = 3;
414 414 mapper->setFirst(first);
415 415 QCOMPARE(series->slices().count(), rowCount - first);
416 416 int count = 7;
417 417 mapper->setCount(count);
418 418 QCOMPARE(series->slices().count(), count);
419 419 first = 9;
420 420 mapper->setFirst(first);
421 421 QCOMPARE(series->slices().count(), qMin(count, rowCount - first));
422 422 }
423 423
424 424 void tst_qpieseries::modelUpdate()
425 425 {
426 426 int rowCount = 12;
427 427 int columnCount = 7;
428 QStandardItemModel *stdModel = new QStandardItemModel(0, 3);
428 QStandardItemModel *stdModel = new QStandardItemModel(rowCount, columnCount);
429 429 for (int row = 0; row < rowCount; ++row) {
430 for (int column = 0; column < 2; column++) {
430 for (int column = 0; column < columnCount; column++) {
431 431 QStandardItem *item = new QStandardItem(row * column);
432 432 stdModel->setItem(row, column, item);
433 433 }
434 434 }
435 435
436 436 QPieSeries *series = new QPieSeries;
437 437 QChart *chart = new QChart;
438 438 chart->addSeries(series);
439 439 QChartView *chartView = new QChartView(chart);
440 440 chartView->show();
441 441 series->setModel(stdModel);
442 442
443 443 QPieModelMapper *mapper = new QPieModelMapper;
444 444 mapper->setMapValues(0);
445 445 mapper->setMapLabels(0);
446 446 series->setModelMapper(mapper);
447 447
448 448 stdModel->insertRows(3, 5);
449 449 QCOMPARE(series->slices().count(), rowCount + 5);
450 450
451 451 stdModel->removeRows(10, 5);
452 452 QCOMPARE(series->slices().count(), rowCount);
453 453
454 454 // limit the number of slices taken from the model to 12
455 455 mapper->setCount(rowCount);
456 456 stdModel->insertRows(3, 5);
457 457 QCOMPARE(series->slices().count(), rowCount);
458 458
459 459 stdModel->removeRows(0, 10);
460 460 QCOMPARE(series->slices().count(), rowCount - 5);
461 461
462 462 // change the orientation to horizontal
463 463 mapper->setOrientation(Qt::Horizontal);
464 464 QCOMPARE(series->slices().count(), columnCount);
465 465
466 466 stdModel->insertColumns(3, 10);
467 467 QCOMPARE(series->slices().count(), rowCount); // count is limited to rowCount (12)
468 468
469 469 stdModel->removeColumns(5, 10);
470 470 QCOMPARE(series->slices().count(), columnCount);
471 471
472 472 }
473 473
474 474 QTEST_MAIN(tst_qpieseries)
475 475
476 476 #include "tst_qpieseries.moc"
477 477
General Comments 0
You need to be logged in to leave comments. Login now