##// END OF EJS Templates
Merge remote-tracking branch 'origin/5.6' into 5.7...
Liang Qi -
r2866:bbf52870f4e3 merge
parent child
Show More
@@ -1,582 +1,585
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the 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 The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29 #include <private/chartpresenter_p.h>
30 30 #include <QtCharts/QChart>
31 31 #include <private/chartitem_p.h>
32 32 #include <private/qchart_p.h>
33 33 #include <QtCharts/QAbstractAxis>
34 34 #include <private/qabstractaxis_p.h>
35 35 #include <private/chartdataset_p.h>
36 36 #include <private/chartanimation_p.h>
37 37 #include <private/qabstractseries_p.h>
38 38 #include <QtCharts/QAreaSeries>
39 39 #include <private/chartaxiselement_p.h>
40 40 #include <private/chartbackground_p.h>
41 41 #include <private/cartesianchartlayout_p.h>
42 42 #include <private/polarchartlayout_p.h>
43 43 #include <private/charttitle_p.h>
44 44 #include <QtCore/QTimer>
45 45 #include <QtGui/QTextDocument>
46 46 #include <QtWidgets/QGraphicsScene>
47 47 #include <QtWidgets/QGraphicsView>
48 48
49 49 QT_CHARTS_BEGIN_NAMESPACE
50 50
51 51 ChartPresenter::ChartPresenter(QChart *chart, QChart::ChartType type)
52 52 : QObject(chart),
53 53 m_chart(chart),
54 54 m_options(QChart::NoAnimation),
55 55 m_animationDuration(ChartAnimationDuration),
56 56 m_animationCurve(QEasingCurve::OutQuart),
57 57 m_state(ShowState),
58 58 m_background(0),
59 59 m_plotAreaBackground(0),
60 60 m_title(0),
61 61 m_localizeNumbers(false)
62 62 #ifndef QT_NO_OPENGL
63 63 , m_glWidget(0)
64 64 , m_glUseWidget(true)
65 65 #endif
66 66 {
67 67 if (type == QChart::ChartTypeCartesian)
68 68 m_layout = new CartesianChartLayout(this);
69 69 else if (type == QChart::ChartTypePolar)
70 70 m_layout = new PolarChartLayout(this);
71 71 Q_ASSERT(m_layout);
72 72 }
73 73
74 74 ChartPresenter::~ChartPresenter()
75 75 {
76 76 #ifndef QT_NO_OPENGL
77 77 delete m_glWidget.data();
78 78 #endif
79 79 }
80 80
81 81 void ChartPresenter::setGeometry(const QRectF rect)
82 82 {
83 83 if (m_rect != rect) {
84 84 m_rect = rect;
85 85 foreach (ChartItem *chart, m_chartItems) {
86 86 chart->domain()->setSize(rect.size());
87 87 chart->setPos(rect.topLeft());
88 88 }
89 89 #ifndef QT_NO_OPENGL
90 90 if (!m_glWidget.isNull())
91 91 m_glWidget->setGeometry(m_rect.toRect());
92 92 #endif
93 93 emit plotAreaChanged(m_rect);
94 94 }
95 95 }
96 96
97 97 QRectF ChartPresenter::geometry() const
98 98 {
99 99 return m_rect;
100 100 }
101 101
102 102 void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
103 103 {
104 104 axis->d_ptr->initializeGraphics(rootItem());
105 105 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
106 106 ChartAxisElement *item = axis->d_ptr->axisItem();
107 107 item->setPresenter(this);
108 108 item->setThemeManager(m_chart->d_ptr->m_themeManager);
109 109 m_axisItems<<item;
110 110 m_axes<<axis;
111 111 m_layout->invalidate();
112 112 }
113 113
114 114 void ChartPresenter::handleAxisRemoved(QAbstractAxis *axis)
115 115 {
116 116 ChartAxisElement *item = axis->d_ptr->m_item.take();
117 117 if (item->animation())
118 118 item->animation()->stopAndDestroyLater();
119 119 item->hide();
120 120 item->disconnect();
121 121 item->deleteLater();
122 122 m_axisItems.removeAll(item);
123 123 m_axes.removeAll(axis);
124 124 m_layout->invalidate();
125 125 }
126 126
127 127
128 128 void ChartPresenter::handleSeriesAdded(QAbstractSeries *series)
129 129 {
130 130 series->d_ptr->initializeGraphics(rootItem());
131 131 series->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
132 132 series->d_ptr->setPresenter(this);
133 133 ChartItem *chart = series->d_ptr->chartItem();
134 134 chart->setPresenter(this);
135 135 chart->setThemeManager(m_chart->d_ptr->m_themeManager);
136 136 chart->setDataSet(m_chart->d_ptr->m_dataset);
137 137 chart->domain()->setSize(m_rect.size());
138 138 chart->setPos(m_rect.topLeft());
139 139 chart->handleDomainUpdated(); //this could be moved to intializeGraphics when animator is refactored
140 140 m_chartItems<<chart;
141 141 m_series<<series;
142 142 m_layout->invalidate();
143 143 }
144 144
145 145 void ChartPresenter::handleSeriesRemoved(QAbstractSeries *series)
146 146 {
147 147 ChartItem *chart = series->d_ptr->m_item.take();
148 148 chart->hide();
149 149 chart->disconnect();
150 150 chart->deleteLater();
151 151 if (chart->animation())
152 152 chart->animation()->stopAndDestroyLater();
153 153 m_chartItems.removeAll(chart);
154 154 m_series.removeAll(series);
155 155 m_layout->invalidate();
156 156 }
157 157
158 158 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
159 159 {
160 160 if (m_options != options) {
161 161 QChart::AnimationOptions oldOptions = m_options;
162 162 m_options = options;
163 163 if (options.testFlag(QChart::SeriesAnimations) != oldOptions.testFlag(QChart::SeriesAnimations)) {
164 164 foreach (QAbstractSeries *series, m_series)
165 165 series->d_ptr->initializeAnimations(m_options, m_animationDuration,
166 166 m_animationCurve);
167 167 }
168 168 if (options.testFlag(QChart::GridAxisAnimations) != oldOptions.testFlag(QChart::GridAxisAnimations)) {
169 169 foreach (QAbstractAxis *axis, m_axes)
170 170 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
171 171 }
172 172 m_layout->invalidate(); // So that existing animations don't just stop halfway
173 173 }
174 174 }
175 175
176 176 void ChartPresenter::setAnimationDuration(int msecs)
177 177 {
178 178 if (m_animationDuration != msecs) {
179 179 m_animationDuration = msecs;
180 180 foreach (QAbstractSeries *series, m_series)
181 181 series->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
182 182 foreach (QAbstractAxis *axis, m_axes)
183 183 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
184 184 m_layout->invalidate(); // So that existing animations don't just stop halfway
185 185 }
186 186 }
187 187
188 188 void ChartPresenter::setAnimationEasingCurve(const QEasingCurve &curve)
189 189 {
190 190 if (m_animationCurve != curve) {
191 191 m_animationCurve = curve;
192 192 foreach (QAbstractSeries *series, m_series)
193 193 series->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
194 194 foreach (QAbstractAxis *axis, m_axes)
195 195 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
196 196 m_layout->invalidate(); // So that existing animations don't just stop halfway
197 197 }
198 198 }
199 199
200 200 void ChartPresenter::setState(State state,QPointF point)
201 201 {
202 202 m_state=state;
203 203 m_statePoint=point;
204 204 }
205 205
206 206 QChart::AnimationOptions ChartPresenter::animationOptions() const
207 207 {
208 208 return m_options;
209 209 }
210 210
211 211 void ChartPresenter::createBackgroundItem()
212 212 {
213 213 if (!m_background) {
214 214 m_background = new ChartBackground(rootItem());
215 215 m_background->setPen(Qt::NoPen); // Theme doesn't touch pen so don't use default
216 216 m_background->setBrush(QChartPrivate::defaultBrush());
217 217 m_background->setZValue(ChartPresenter::BackgroundZValue);
218 218 }
219 219 }
220 220
221 221 void ChartPresenter::createPlotAreaBackgroundItem()
222 222 {
223 223 if (!m_plotAreaBackground) {
224 224 if (m_chart->chartType() == QChart::ChartTypeCartesian)
225 225 m_plotAreaBackground = new QGraphicsRectItem(rootItem());
226 226 else
227 227 m_plotAreaBackground = new QGraphicsEllipseItem(rootItem());
228 228 // Use transparent pen instead of Qt::NoPen, as Qt::NoPen causes
229 229 // antialising artifacts with axis lines for some reason.
230 230 m_plotAreaBackground->setPen(QPen(Qt::transparent));
231 231 m_plotAreaBackground->setBrush(Qt::NoBrush);
232 232 m_plotAreaBackground->setZValue(ChartPresenter::PlotAreaZValue);
233 233 m_plotAreaBackground->setVisible(false);
234 234 }
235 235 }
236 236
237 237 void ChartPresenter::createTitleItem()
238 238 {
239 239 if (!m_title) {
240 240 m_title = new ChartTitle(rootItem());
241 241 m_title->setZValue(ChartPresenter::BackgroundZValue);
242 242 }
243 243 }
244 244
245 245 void ChartPresenter::startAnimation(ChartAnimation *animation)
246 246 {
247 247 animation->stop();
248 248 QTimer::singleShot(0, animation, SLOT(startChartAnimation()));
249 249 }
250 250
251 251 void ChartPresenter::setBackgroundBrush(const QBrush &brush)
252 252 {
253 253 createBackgroundItem();
254 254 m_background->setBrush(brush);
255 255 m_layout->invalidate();
256 256 }
257 257
258 258 QBrush ChartPresenter::backgroundBrush() const
259 259 {
260 260 if (!m_background)
261 261 return QBrush();
262 262 return m_background->brush();
263 263 }
264 264
265 265 void ChartPresenter::setBackgroundPen(const QPen &pen)
266 266 {
267 267 createBackgroundItem();
268 268 m_background->setPen(pen);
269 269 m_layout->invalidate();
270 270 }
271 271
272 272 QPen ChartPresenter::backgroundPen() const
273 273 {
274 274 if (!m_background)
275 275 return QPen();
276 276 return m_background->pen();
277 277 }
278 278
279 279 void ChartPresenter::setBackgroundRoundness(qreal diameter)
280 280 {
281 281 createBackgroundItem();
282 282 m_background->setDiameter(diameter);
283 283 m_layout->invalidate();
284 284 }
285 285
286 286 qreal ChartPresenter::backgroundRoundness() const
287 287 {
288 288 if (!m_background)
289 289 return 0;
290 290 return m_background->diameter();
291 291 }
292 292
293 293 void ChartPresenter::setPlotAreaBackgroundBrush(const QBrush &brush)
294 294 {
295 295 createPlotAreaBackgroundItem();
296 296 m_plotAreaBackground->setBrush(brush);
297 297 m_layout->invalidate();
298 298 }
299 299
300 300 QBrush ChartPresenter::plotAreaBackgroundBrush() const
301 301 {
302 302 if (!m_plotAreaBackground)
303 303 return QBrush();
304 304 return m_plotAreaBackground->brush();
305 305 }
306 306
307 307 void ChartPresenter::setPlotAreaBackgroundPen(const QPen &pen)
308 308 {
309 309 createPlotAreaBackgroundItem();
310 310 m_plotAreaBackground->setPen(pen);
311 311 m_layout->invalidate();
312 312 }
313 313
314 314 QPen ChartPresenter::plotAreaBackgroundPen() const
315 315 {
316 316 if (!m_plotAreaBackground)
317 317 return QPen();
318 318 return m_plotAreaBackground->pen();
319 319 }
320 320
321 321 void ChartPresenter::setTitle(const QString &title)
322 322 {
323 323 createTitleItem();
324 324 m_title->setText(title);
325 325 m_layout->invalidate();
326 326 }
327 327
328 328 QString ChartPresenter::title() const
329 329 {
330 330 if (!m_title)
331 331 return QString();
332 332 return m_title->text();
333 333 }
334 334
335 335 void ChartPresenter::setTitleFont(const QFont &font)
336 336 {
337 337 createTitleItem();
338 338 m_title->setFont(font);
339 339 m_layout->invalidate();
340 340 }
341 341
342 342 QFont ChartPresenter::titleFont() const
343 343 {
344 344 if (!m_title)
345 345 return QFont();
346 346 return m_title->font();
347 347 }
348 348
349 349 void ChartPresenter::setTitleBrush(const QBrush &brush)
350 350 {
351 351 createTitleItem();
352 352 m_title->setDefaultTextColor(brush.color());
353 353 m_layout->invalidate();
354 354 }
355 355
356 356 QBrush ChartPresenter::titleBrush() const
357 357 {
358 358 if (!m_title)
359 359 return QBrush();
360 360 return QBrush(m_title->defaultTextColor());
361 361 }
362 362
363 363 void ChartPresenter::setBackgroundVisible(bool visible)
364 364 {
365 365 createBackgroundItem();
366 366 m_background->setVisible(visible);
367 367 }
368 368
369 369
370 370 bool ChartPresenter::isBackgroundVisible() const
371 371 {
372 372 if (!m_background)
373 373 return false;
374 374 return m_background->isVisible();
375 375 }
376 376
377 377 void ChartPresenter::setPlotAreaBackgroundVisible(bool visible)
378 378 {
379 379 createPlotAreaBackgroundItem();
380 380 m_plotAreaBackground->setVisible(visible);
381 381 }
382 382
383 383 bool ChartPresenter::isPlotAreaBackgroundVisible() const
384 384 {
385 385 if (!m_plotAreaBackground)
386 386 return false;
387 387 return m_plotAreaBackground->isVisible();
388 388 }
389 389
390 390 void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled)
391 391 {
392 392 createBackgroundItem();
393 393 m_background->setDropShadowEnabled(enabled);
394 394 }
395 395
396 396 bool ChartPresenter::isBackgroundDropShadowEnabled() const
397 397 {
398 398 if (!m_background)
399 399 return false;
400 400 return m_background->isDropShadowEnabled();
401 401 }
402 402
403 403 void ChartPresenter::setLocalizeNumbers(bool localize)
404 404 {
405 405 m_localizeNumbers = localize;
406 406 m_layout->invalidate();
407 407 }
408 408
409 409 void ChartPresenter::setLocale(const QLocale &locale)
410 410 {
411 411 m_locale = locale;
412 412 m_layout->invalidate();
413 413 }
414 414
415 415 AbstractChartLayout *ChartPresenter::layout()
416 416 {
417 417 return m_layout;
418 418 }
419 419
420 420 QLegend *ChartPresenter::legend()
421 421 {
422 422 return m_chart->legend();
423 423 }
424 424
425 425 void ChartPresenter::setVisible(bool visible)
426 426 {
427 427 m_chart->setVisible(visible);
428 428 }
429 429
430 430 ChartBackground *ChartPresenter::backgroundElement()
431 431 {
432 432 return m_background;
433 433 }
434 434
435 435 QAbstractGraphicsShapeItem *ChartPresenter::plotAreaElement()
436 436 {
437 437 return m_plotAreaBackground;
438 438 }
439 439
440 440 QList<ChartAxisElement *> ChartPresenter::axisItems() const
441 441 {
442 442 return m_axisItems;
443 443 }
444 444
445 445 QList<ChartItem *> ChartPresenter::chartItems() const
446 446 {
447 447 return m_chartItems;
448 448 }
449 449
450 450 ChartTitle *ChartPresenter::titleElement()
451 451 {
452 452 return m_title;
453 453 }
454 454
455 455 QRectF ChartPresenter::textBoundingRect(const QFont &font, const QString &text, qreal angle)
456 456 {
457 457 static QGraphicsTextItem dummyTextItem;
458 458 static bool initMargin = true;
459 459 if (initMargin) {
460 460 dummyTextItem.document()->setDocumentMargin(textMargin());
461 461 initMargin = false;
462 462 }
463 463
464 464 dummyTextItem.setFont(font);
465 465 dummyTextItem.setHtml(text);
466 466 QRectF boundingRect = dummyTextItem.boundingRect();
467 467
468 468 // Take rotation into account
469 469 if (angle) {
470 470 QTransform transform;
471 471 transform.rotate(angle);
472 472 boundingRect = transform.mapRect(boundingRect);
473 473 }
474 474
475 475 return boundingRect;
476 476 }
477 477
478 478 // boundingRect parameter returns the rotated bounding rect of the text
479 479 QString ChartPresenter::truncatedText(const QFont &font, const QString &text, qreal angle,
480 480 qreal maxWidth, qreal maxHeight, QRectF &boundingRect)
481 481 {
482 482 QString truncatedString(text);
483 483 boundingRect = textBoundingRect(font, truncatedString, angle);
484 484 if (boundingRect.width() > maxWidth || boundingRect.height() > maxHeight) {
485 485 // It can be assumed that almost any amount of string manipulation is faster
486 486 // than calculating one bounding rectangle, so first prepare a list of truncated strings
487 487 // to try.
488 488 static QRegExp truncateMatcher(QStringLiteral("&#?[0-9a-zA-Z]*;$"));
489 489
490 490 QVector<QString> testStrings(text.length());
491 491 int count(0);
492 492 static QLatin1Char closeTag('>');
493 493 static QLatin1Char openTag('<');
494 494 static QLatin1Char semiColon(';');
495 495 static QLatin1String ellipsis("...");
496 496 while (truncatedString.length() > 1) {
497 497 int chopIndex(-1);
498 498 int chopCount(1);
499 499 QChar lastChar(truncatedString.at(truncatedString.length() - 1));
500 500
501 501 if (lastChar == closeTag)
502 502 chopIndex = truncatedString.lastIndexOf(openTag);
503 503 else if (lastChar == semiColon)
504 504 chopIndex = truncateMatcher.indexIn(truncatedString, 0);
505 505
506 506 if (chopIndex != -1)
507 507 chopCount = truncatedString.length() - chopIndex;
508 508 truncatedString.chop(chopCount);
509 509 testStrings[count] = truncatedString + ellipsis;
510 510 count++;
511 511 }
512 512
513 513 // Binary search for best fit
514 514 int minIndex(0);
515 515 int maxIndex(count - 1);
516 516 int bestIndex(count);
517 517 QRectF checkRect;
518 518
519 519 while (maxIndex >= minIndex) {
520 520 int mid = (maxIndex + minIndex) / 2;
521 521 checkRect = textBoundingRect(font, testStrings.at(mid), angle);
522 522 if (checkRect.width() > maxWidth || checkRect.height() > maxHeight) {
523 523 // Checked index too large, all under this are also too large
524 524 minIndex = mid + 1;
525 525 } else {
526 526 // Checked index fits, all over this also fit
527 527 maxIndex = mid - 1;
528 528 bestIndex = mid;
529 529 boundingRect = checkRect;
530 530 }
531 531 }
532 532 // Default to "..." if nothing fits
533 533 if (bestIndex == count) {
534 534 boundingRect = textBoundingRect(font, ellipsis, angle);
535 535 truncatedString = ellipsis;
536 536 } else {
537 537 truncatedString = testStrings.at(bestIndex);
538 538 }
539 539 }
540 540
541 541 return truncatedString;
542 542 }
543 543
544 544 QString ChartPresenter::numberToString(double value, char f, int prec)
545 545 {
546 546 if (m_localizeNumbers)
547 547 return m_locale.toString(value, f, prec);
548 548 else
549 549 return QString::number(value, f, prec);
550 550 }
551 551
552 552 QString ChartPresenter::numberToString(int value)
553 553 {
554 554 if (m_localizeNumbers)
555 555 return m_locale.toString(value);
556 556 else
557 557 return QString::number(value);
558 558 }
559 559
560 void ChartPresenter::ensureGLWidget()
560 void ChartPresenter::updateGLWidget()
561 561 {
562 562 #ifndef QT_NO_OPENGL
563 563 // GLWidget pointer is wrapped in QPointer as its parent is not in our control, and therefore
564 564 // can potentially get deleted unexpectedly.
565 565 if (m_glWidget.isNull() && m_glUseWidget && m_chart->scene()) {
566 566 // Find the view of the scene. If the scene has multiple views, only the first view is
567 567 // chosen.
568 568 QList<QGraphicsView *> views = m_chart->scene()->views();
569 569 if (views.size()) {
570 570 QGraphicsView *firstView = views.at(0);
571 571 m_glWidget = new GLWidget(m_chart->d_ptr->m_dataset->glXYSeriesDataManager(),
572 572 firstView);
573 573 m_glWidget->setGeometry(m_rect.toRect());
574 574 m_glWidget->show();
575 575 }
576 576 }
577 // Make sure we update the widget in a timely manner
578 if (!m_glWidget.isNull())
579 m_glWidget->update();
577 580 #endif
578 581 }
579 582
580 583 #include "moc_chartpresenter_p.cpp"
581 584
582 585 QT_CHARTS_END_NAMESPACE
@@ -1,220 +1,220
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the 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 The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 // W A R N I N G
31 31 // -------------
32 32 //
33 33 // This file is not part of the Qt Chart API. It exists purely as an
34 34 // implementation detail. This header file may change from version to
35 35 // version without notice, or even be removed.
36 36 //
37 37 // We mean it.
38 38
39 39 #ifndef CHARTPRESENTER_H
40 40 #define CHARTPRESENTER_H
41 41
42 42 #include <QtCharts/QChartGlobal>
43 43 #include <QtCharts/QChart> //because of QChart::ChartThemeId
44 44 #include <private/glwidget_p.h>
45 45 #include <QtCore/QRectF>
46 46 #include <QtCore/QMargins>
47 47 #include <QtCore/QLocale>
48 48 #include <QtCore/QPointer>
49 49 #include <QtCore/QEasingCurve>
50 50
51 51 QT_CHARTS_BEGIN_NAMESPACE
52 52
53 53 class ChartItem;
54 54 class AxisItem;
55 55 class QAbstractSeries;
56 56 class ChartDataSet;
57 57 class AbstractDomain;
58 58 class ChartAxisElement;
59 59 class ChartAnimator;
60 60 class ChartBackground;
61 61 class ChartTitle;
62 62 class ChartAnimation;
63 63 class AbstractChartLayout;
64 64
65 65 class ChartPresenter: public QObject
66 66 {
67 67 Q_OBJECT
68 68 public:
69 69 enum ZValues {
70 70 BackgroundZValue = -1,
71 71 PlotAreaZValue,
72 72 ShadesZValue,
73 73 GridZValue,
74 74 AxisZValue,
75 75 SeriesZValue,
76 76 LineChartZValue = SeriesZValue,
77 77 SplineChartZValue = SeriesZValue,
78 78 BarSeriesZValue = SeriesZValue,
79 79 ScatterSeriesZValue = SeriesZValue,
80 80 PieSeriesZValue = SeriesZValue,
81 81 BoxPlotSeriesZValue = SeriesZValue,
82 82 LegendZValue,
83 83 TopMostZValue
84 84 };
85 85
86 86 enum State {
87 87 ShowState,
88 88 ScrollUpState,
89 89 ScrollDownState,
90 90 ScrollLeftState,
91 91 ScrollRightState,
92 92 ZoomInState,
93 93 ZoomOutState
94 94 };
95 95
96 96 ChartPresenter(QChart *chart, QChart::ChartType type);
97 97 virtual ~ChartPresenter();
98 98
99 99
100 100 void setGeometry(QRectF rect);
101 101 QRectF geometry() const;
102 102
103 103 QGraphicsItem *rootItem(){ return m_chart; }
104 104 ChartBackground *backgroundElement();
105 105 QAbstractGraphicsShapeItem *plotAreaElement();
106 106 ChartTitle *titleElement();
107 107 QList<ChartAxisElement *> axisItems() const;
108 108 QList<ChartItem *> chartItems() const;
109 109
110 110 QLegend *legend();
111 111
112 112 void setBackgroundBrush(const QBrush &brush);
113 113 QBrush backgroundBrush() const;
114 114
115 115 void setBackgroundPen(const QPen &pen);
116 116 QPen backgroundPen() const;
117 117
118 118 void setBackgroundRoundness(qreal diameter);
119 119 qreal backgroundRoundness() const;
120 120
121 121 void setPlotAreaBackgroundBrush(const QBrush &brush);
122 122 QBrush plotAreaBackgroundBrush() const;
123 123
124 124 void setPlotAreaBackgroundPen(const QPen &pen);
125 125 QPen plotAreaBackgroundPen() const;
126 126
127 127 void setTitle(const QString &title);
128 128 QString title() const;
129 129
130 130 void setTitleFont(const QFont &font);
131 131 QFont titleFont() const;
132 132
133 133 void setTitleBrush(const QBrush &brush);
134 134 QBrush titleBrush() const;
135 135
136 136 void setBackgroundVisible(bool visible);
137 137 bool isBackgroundVisible() const;
138 138
139 139 void setPlotAreaBackgroundVisible(bool visible);
140 140 bool isPlotAreaBackgroundVisible() const;
141 141
142 142 void setBackgroundDropShadowEnabled(bool enabled);
143 143 bool isBackgroundDropShadowEnabled() const;
144 144
145 145 void setLocalizeNumbers(bool localize);
146 146 inline bool localizeNumbers() const { return m_localizeNumbers; }
147 147 void setLocale(const QLocale &locale);
148 148 inline const QLocale &locale() const { return m_locale; }
149 149
150 150 void setVisible(bool visible);
151 151
152 152 void setAnimationOptions(QChart::AnimationOptions options);
153 153 QChart::AnimationOptions animationOptions() const;
154 154 void setAnimationDuration(int msecs);
155 155 int animationDuration() const { return m_animationDuration; }
156 156 void setAnimationEasingCurve(const QEasingCurve &curve);
157 157 QEasingCurve animationEasingCurve() const { return m_animationCurve; }
158 158
159 159 void startAnimation(ChartAnimation *animation);
160 160
161 161 void setState(State state,QPointF point);
162 162 State state() const { return m_state; }
163 163 QPointF statePoint() const { return m_statePoint; }
164 164 AbstractChartLayout *layout();
165 165
166 166 QChart::ChartType chartType() const { return m_chart->chartType(); }
167 167 QChart *chart() { return m_chart; }
168 168
169 169 static QRectF textBoundingRect(const QFont &font, const QString &text, qreal angle = 0.0);
170 170 static QString truncatedText(const QFont &font, const QString &text, qreal angle,
171 171 qreal maxWidth, qreal maxHeight, QRectF &boundingRect);
172 172 inline static qreal textMargin() { return qreal(0.5); }
173 173
174 174 QString numberToString(double value, char f = 'g', int prec = 6);
175 175 QString numberToString(int value);
176 176
177 void ensureGLWidget();
177 void updateGLWidget();
178 178 void glSetUseWidget(bool enable) { m_glUseWidget = enable; }
179 179
180 180 private:
181 181 void createBackgroundItem();
182 182 void createPlotAreaBackgroundItem();
183 183 void createTitleItem();
184 184
185 185 public Q_SLOTS:
186 186 void handleSeriesAdded(QAbstractSeries *series);
187 187 void handleSeriesRemoved(QAbstractSeries *series);
188 188 void handleAxisAdded(QAbstractAxis *axis);
189 189 void handleAxisRemoved(QAbstractAxis *axis);
190 190
191 191 Q_SIGNALS:
192 192 void plotAreaChanged(const QRectF &plotArea);
193 193
194 194 private:
195 195 QChart *m_chart;
196 196 QList<ChartItem *> m_chartItems;
197 197 QList<ChartAxisElement *> m_axisItems;
198 198 QList<QAbstractSeries *> m_series;
199 199 QList<QAbstractAxis *> m_axes;
200 200 QChart::AnimationOptions m_options;
201 201 int m_animationDuration;
202 202 QEasingCurve m_animationCurve;
203 203 State m_state;
204 204 QPointF m_statePoint;
205 205 AbstractChartLayout *m_layout;
206 206 ChartBackground *m_background;
207 207 QAbstractGraphicsShapeItem *m_plotAreaBackground;
208 208 ChartTitle *m_title;
209 209 QRectF m_rect;
210 210 bool m_localizeNumbers;
211 211 QLocale m_locale;
212 212 #ifndef QT_NO_OPENGL
213 213 QPointer<GLWidget> m_glWidget;
214 214 #endif
215 215 bool m_glUseWidget;
216 216 };
217 217
218 218 QT_CHARTS_END_NAMESPACE
219 219
220 220 #endif /* CHARTPRESENTER_H */
@@ -1,246 +1,246
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the 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 The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 #include <private/xychart_p.h>
31 31 #include <QtCharts/QXYSeries>
32 32 #include <private/qxyseries_p.h>
33 33 #include <private/chartpresenter_p.h>
34 34 #include <private/abstractdomain_p.h>
35 35 #include <private/chartdataset_p.h>
36 36 #include <private/glxyseriesdata_p.h>
37 37 #include <QtCharts/QXYModelMapper>
38 38 #include <private/qabstractaxis_p.h>
39 39 #include <QtGui/QPainter>
40 40 #include <QtCore/QAbstractItemModel>
41 41
42 42
43 43 QT_CHARTS_BEGIN_NAMESPACE
44 44
45 45 XYChart::XYChart(QXYSeries *series, QGraphicsItem *item):
46 46 ChartItem(series->d_func(),item),
47 47 m_series(series),
48 48 m_animation(0),
49 49 m_dirty(true)
50 50 {
51 51 QObject::connect(series, SIGNAL(pointReplaced(int)), this, SLOT(handlePointReplaced(int)));
52 52 QObject::connect(series, SIGNAL(pointsReplaced()), this, SLOT(handlePointsReplaced()));
53 53 QObject::connect(series, SIGNAL(pointAdded(int)), this, SLOT(handlePointAdded(int)));
54 54 QObject::connect(series, SIGNAL(pointRemoved(int)), this, SLOT(handlePointRemoved(int)));
55 55 QObject::connect(series, SIGNAL(pointsRemoved(int, int)), this, SLOT(handlePointsRemoved(int, int)));
56 56 QObject::connect(this, SIGNAL(clicked(QPointF)), series, SIGNAL(clicked(QPointF)));
57 57 QObject::connect(this, SIGNAL(hovered(QPointF,bool)), series, SIGNAL(hovered(QPointF,bool)));
58 58 QObject::connect(this, SIGNAL(pressed(QPointF)), series, SIGNAL(pressed(QPointF)));
59 59 QObject::connect(this, SIGNAL(released(QPointF)), series, SIGNAL(released(QPointF)));
60 60 QObject::connect(this, SIGNAL(doubleClicked(QPointF)), series, SIGNAL(doubleClicked(QPointF)));
61 61 }
62 62
63 63 void XYChart::setGeometryPoints(const QVector<QPointF> &points)
64 64 {
65 65 m_points = points;
66 66 }
67 67
68 68 void XYChart::setAnimation(XYAnimation *animation)
69 69 {
70 70 m_animation = animation;
71 71 }
72 72
73 73 void XYChart::setDirty(bool dirty)
74 74 {
75 75 m_dirty = dirty;
76 76 }
77 77
78 78 // Returns a vector with same size as geometryPoints vector, indicating
79 79 // the off grid status of points.
80 80 QVector<bool> XYChart::offGridStatusVector()
81 81 {
82 82 qreal minX = domain()->minX();
83 83 qreal maxX = domain()->maxX();
84 84 qreal minY = domain()->minY();
85 85 qreal maxY = domain()->maxY();
86 86
87 87 QVector<bool> returnVector;
88 88 returnVector.resize(m_points.size());
89 89 // During remove animation series may have different number of points,
90 90 // so ensure we don't go over the index. No need to check for zero points, this
91 91 // will not be called in such a situation.
92 92 const int seriesLastIndex = m_series->count() - 1;
93 93
94 94 for (int i = 0; i < m_points.size(); i++) {
95 95 const QPointF &seriesPoint = m_series->at(qMin(seriesLastIndex, i));
96 96 if (seriesPoint.x() < minX
97 97 || seriesPoint.x() > maxX
98 98 || seriesPoint.y() < minY
99 99 || seriesPoint.y() > maxY) {
100 100 returnVector[i] = true;
101 101 } else {
102 102 returnVector[i] = false;
103 103 }
104 104 }
105 105 return returnVector;
106 106 }
107 107
108 108 void XYChart::updateChart(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, int index)
109 109 {
110 110
111 111 if (m_animation) {
112 112 m_animation->setup(oldPoints, newPoints, index);
113 113 m_points = newPoints;
114 114 setDirty(false);
115 115 presenter()->startAnimation(m_animation);
116 116 } else {
117 117 m_points = newPoints;
118 118 updateGeometry();
119 119 }
120 120 }
121 121
122 122 void XYChart::updateGlChart()
123 123 {
124 presenter()->ensureGLWidget();
125 124 dataSet()->glXYSeriesDataManager()->setPoints(m_series, domain());
125 presenter()->updateGLWidget();
126 126 updateGeometry();
127 127 }
128 128
129 129 //handlers
130 130
131 131 void XYChart::handlePointAdded(int index)
132 132 {
133 133 Q_ASSERT(index < m_series->count());
134 134 Q_ASSERT(index >= 0);
135 135
136 136 if (m_series->useOpenGL()) {
137 137 updateGlChart();
138 138 } else {
139 139 QVector<QPointF> points;
140 140 if (m_dirty || m_points.isEmpty()) {
141 141 points = domain()->calculateGeometryPoints(m_series->pointsVector());
142 142 } else {
143 143 points = m_points;
144 144 QPointF point = domain()->calculateGeometryPoint(m_series->pointsVector().at(index),
145 145 m_validData);
146 146 if (!m_validData)
147 147 m_points.clear();
148 148 else
149 149 points.insert(index, point);
150 150 }
151 151 updateChart(m_points, points, index);
152 152 }
153 153 }
154 154
155 155 void XYChart::handlePointRemoved(int index)
156 156 {
157 157 Q_ASSERT(index <= m_series->count());
158 158 Q_ASSERT(index >= 0);
159 159
160 160 if (m_series->useOpenGL()) {
161 161 updateGlChart();
162 162 } else {
163 163 QVector<QPointF> points;
164 164 if (m_dirty || m_points.isEmpty()) {
165 165 points = domain()->calculateGeometryPoints(m_series->pointsVector());
166 166 } else {
167 167 points = m_points;
168 168 points.remove(index);
169 169 }
170 170 updateChart(m_points, points, index);
171 171 }
172 172 }
173 173
174 174 void XYChart::handlePointsRemoved(int index, int count)
175 175 {
176 176 Q_ASSERT(index <= m_series->count());
177 177 Q_ASSERT(index >= 0);
178 178
179 179 if (m_series->useOpenGL()) {
180 180 updateGlChart();
181 181 } else {
182 182 QVector<QPointF> points;
183 183 if (m_dirty || m_points.isEmpty()) {
184 184 points = domain()->calculateGeometryPoints(m_series->pointsVector());
185 185 } else {
186 186 points = m_points;
187 187 points.remove(index, count);
188 188 }
189 189 updateChart(m_points, points, index);
190 190 }
191 191 }
192 192
193 193 void XYChart::handlePointReplaced(int index)
194 194 {
195 195 Q_ASSERT(index < m_series->count());
196 196 Q_ASSERT(index >= 0);
197 197
198 198 if (m_series->useOpenGL()) {
199 199 updateGlChart();
200 200 } else {
201 201 QVector<QPointF> points;
202 202 if (m_dirty || m_points.isEmpty()) {
203 203 points = domain()->calculateGeometryPoints(m_series->pointsVector());
204 204 } else {
205 205 QPointF point = domain()->calculateGeometryPoint(m_series->pointsVector().at(index),
206 206 m_validData);
207 207 if (!m_validData)
208 208 m_points.clear();
209 209 points = m_points;
210 210 if (m_validData)
211 211 points.replace(index, point);
212 212 }
213 213 updateChart(m_points, points, index);
214 214 }
215 215 }
216 216
217 217 void XYChart::handlePointsReplaced()
218 218 {
219 219 if (m_series->useOpenGL()) {
220 220 updateGlChart();
221 221 } else {
222 222 // All the points were replaced -> recalculate
223 223 QVector<QPointF> points = domain()->calculateGeometryPoints(m_series->pointsVector());
224 224 updateChart(m_points, points, -1);
225 225 }
226 226 }
227 227
228 228 void XYChart::handleDomainUpdated()
229 229 {
230 230 if (m_series->useOpenGL()) {
231 231 updateGlChart();
232 232 } else {
233 233 if (isEmpty()) return;
234 234 QVector<QPointF> points = domain()->calculateGeometryPoints(m_series->pointsVector());
235 235 updateChart(m_points, points);
236 236 }
237 237 }
238 238
239 239 bool XYChart::isEmpty()
240 240 {
241 241 return domain()->isEmpty() || m_series->points().isEmpty();
242 242 }
243 243
244 244 #include "moc_xychart_p.cpp"
245 245
246 246 QT_CHARTS_END_NAMESPACE
@@ -1,1248 +1,1250
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the 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 The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 #include "declarativechart.h"
31 31 #include <QtGui/QPainter>
32 32 #include "declarativelineseries.h"
33 33 #include "declarativeareaseries.h"
34 34 #include "declarativebarseries.h"
35 35 #include "declarativepieseries.h"
36 36 #include "declarativesplineseries.h"
37 37 #include "declarativeboxplotseries.h"
38 38 #include "declarativescatterseries.h"
39 39 #include "declarativechartnode.h"
40 40 #include "declarativerendernode.h"
41 41 #include <QtCharts/QBarCategoryAxis>
42 42 #include <QtCharts/QValueAxis>
43 43 #include <QtCharts/QLogValueAxis>
44 44 #include <QtCharts/QCategoryAxis>
45 45 #include <private/qabstractseries_p.h>
46 46 #include "declarativemargins.h"
47 47 #include <private/chartdataset_p.h>
48 48 #include "declarativeaxes.h"
49 49 #include <private/qchart_p.h>
50 50 #include <private/chartpresenter_p.h>
51 51 #include <QtCharts/QPolarChart>
52 52
53 53 #ifndef QT_QREAL_IS_FLOAT
54 54 #include <QtCharts/QDateTimeAxis>
55 55 #endif
56 56
57 57 #include <QtWidgets/QGraphicsSceneMouseEvent>
58 58 #include <QtWidgets/QGraphicsSceneHoverEvent>
59 59 #include <QtWidgets/QApplication>
60 60 #include <QtCore/QTimer>
61 61 #include <QtCore/QThread>
62 62
63 63 QT_CHARTS_BEGIN_NAMESPACE
64 64
65 65 /*!
66 66 \qmltype ChartView
67 67 \instantiates DeclarativeChart
68 68 \inqmlmodule QtCharts
69 69
70 70 \brief Chart element.
71 71
72 72 ChartView element is the parent that is responsible for showing different chart series types.
73 73
74 74 The following QML shows how to create a simple chart with one pie series:
75 75 \snippet qmlpiechart/qml/qmlpiechart/main.qml 1
76 76 \snippet qmlpiechart/qml/qmlpiechart/main.qml 2
77 77 \snippet qmlpiechart/qml/qmlpiechart/main.qml 3
78 78
79 79 \beginfloatleft
80 80 \image examples_qmlpiechart.png
81 81 \endfloat
82 82 \clearfloat
83 83 */
84 84
85 85 /*!
86 86 \qmlproperty Theme ChartView::theme
87 87 Theme defines the visual appearance of the chart, including for example colors, fonts, line
88 88 widths and chart background.
89 89 */
90 90
91 91 /*!
92 92 \qmlproperty Animation ChartView::animationOptions
93 93 Animation configuration of the chart. One of ChartView.NoAnimation, ChartView.GridAxisAnimations,
94 94 ChartView.SeriesAnimations or ChartView.AllAnimations.
95 95 */
96 96
97 97 /*!
98 98 \qmlproperty int ChartView::animationDuration
99 99 The duration of the animation for the chart.
100 100 */
101 101
102 102 /*!
103 103 \qmlproperty easing ChartView::animationEasingCurve
104 104 The easing curve of the animation for the chart.
105 105 */
106 106
107 107 /*!
108 108 \qmlproperty Font ChartView::titleFont
109 109 The title font of the chart.
110 110
111 111 See the Qt documentation for more details of Font.
112 112 */
113 113
114 114 /*!
115 115 \qmlproperty string ChartView::title
116 116 The title of the chart, shown on top of the chart.
117 117 \sa ChartView::titleColor
118 118 */
119 119
120 120 /*!
121 121 \qmlproperty color ChartView::titleColor
122 122 The color of the title text.
123 123 */
124 124
125 125 /*!
126 126 \qmlproperty Legend ChartView::legend
127 127 The legend of the chart. Legend lists all the series, pie slices and bar sets added on the chart.
128 128 */
129 129
130 130 /*!
131 131 \qmlproperty int ChartView::count
132 132 The count of series added to the chart.
133 133 */
134 134
135 135 /*!
136 136 \qmlproperty color ChartView::backgroundColor
137 137 The color of the chart's background. By default background color is defined by chart theme.
138 138 \sa ChartView::theme
139 139 */
140 140
141 141 /*!
142 142 \qmlproperty real ChartView::backgroundRoundness
143 143 The diameter of the rounding circle at the corners of the chart background.
144 144 */
145 145
146 146 /*!
147 147 \qmlproperty color ChartView::plotAreaColor
148 148 The color of the background of the chart's plot area. By default plot area background uses chart's
149 149 background color.
150 150 \sa ChartView::backgroundColor
151 151 */
152 152
153 153 /*!
154 154 \qmlproperty list<AbstractAxis> ChartView::axes
155 155 The axes of the ChartView.
156 156 */
157 157
158 158 /*!
159 159 \qmlproperty bool ChartView::dropShadowEnabled
160 160 The chart's border drop shadow. Set to true to enable drop shadow.
161 161 */
162 162
163 163 /*!
164 164 \qmlproperty rect ChartView::plotArea
165 165 The area on the ChartView that is used for drawing series. This is the ChartView rect without the
166 166 margins.
167 167 \sa ChartView::margins
168 168 */
169 169
170 170 /*!
171 171 \qmlproperty Margins ChartView::margins
172 172 The minimum margins allowed between the outer bounds and the plotArea of the ChartView. Margins
173 173 area of ChartView is used for drawing title, axes and legend.
174 174 */
175 175
176 176 /*!
177 177 \qmlproperty bool ChartView::localizeNumbers
178 178 \since QtCharts 2.0
179 179 When \c{true}, all generated numbers appearing in various series and axis labels will be
180 180 localized using the default QLocale of the application, which defaults to the system locale.
181 181 When \c{false}, the "C" locale is always used.
182 182 Defaults to \c{false}.
183 183
184 184 \sa locale
185 185 */
186 186
187 187 /*!
188 188 \qmlproperty locale ChartView::locale
189 189 \since QtCharts 2.0
190 190 Sets the locale used to format various chart labels when localizeNumbers is \c{true}.
191 191 This also determines the locale used to format DateTimeAxis labels regardless of
192 192 localizeNumbers property.
193 193 Defaults to application default locale at the time the chart is constructed.
194 194
195 195 \sa localizeNumbers
196 196 */
197 197
198 198 /*!
199 199 \qmlmethod AbstractSeries ChartView::series(int index)
200 200 Returns the series with \a index on the chart. This allows you to loop through the series of a chart together with
201 201 the count property of the chart.
202 202 */
203 203
204 204 /*!
205 205 \qmlmethod AbstractSeries ChartView::series(string name)
206 206 Returns the first series on the chart with \a name. If there is no series with that name, returns null.
207 207 */
208 208
209 209 /*!
210 210 \qmlmethod AbstractSeries ChartView::createSeries(SeriesType type, string name, AbstractAxis axisX, AbstractAxis axisY)
211 211 Creates a series object of \a type to the chart with name \a name, optional axis \a axisX and
212 212 optional axis \a axisY. For example:
213 213 \code
214 214 // lineSeries is a LineSeries object that has already been added to the ChartView; re-use it's axes
215 215 var myAxisX = chartView.axisX(lineSeries);
216 216 var myAxisY = chartView.axisY(lineSeries);
217 217 var scatter = chartView.createSeries(ChartView.SeriesTypeScatter, "scatter series", myAxisX, myAxisY);
218 218 \endcode
219 219 */
220 220
221 221 /*!
222 222 \qmlmethod ChartView::removeSeries(AbstractSeries series)
223 223 Removes the \a series from the chart. The series object is also destroyed.
224 224 */
225 225
226 226 /*!
227 227 \qmlmethod ChartView::removeAllSeries()
228 228 Removes all series from the chart. All the series objects are also destroyed.
229 229 */
230 230
231 231 /*!
232 232 \qmlmethod Axis ChartView::axisX(AbstractSeries series)
233 233 The x-axis of the series.
234 234 */
235 235
236 236 /*!
237 237 \qmlmethod ChartView::setAxisX(AbstractAxis axis, AbstractSeries series)
238 238 Set the x-axis of the series.
239 239 */
240 240
241 241 /*!
242 242 \qmlmethod Axis ChartView::axisY(AbstractSeries series)
243 243 The y-axis of the series.
244 244 */
245 245
246 246 /*!
247 247 \qmlmethod ChartView::setAxisY(AbstractAxis axis, AbstractSeries series)
248 248 Set the y-axis of the series.
249 249 */
250 250
251 251 /*!
252 252 \qmlmethod ChartView::zoom(real factor)
253 253 Zooms in by \a factor on the center of the chart.
254 254
255 255 A factor over 1.0 zooms the view in and factor between 0.0 and 1.0 zooms out.
256 256 */
257 257
258 258 /*!
259 259 \qmlmethod ChartView::zoomIn()
260 260 Zooms in the view by a factor of two.
261 261 */
262 262
263 263 /*!
264 264 \qmlmethod ChartView::zoomIn(rect rectangle)
265 265 Zooms in the view to a maximum level at which \a rectangle is still fully visible.
266 266 \note This is not supported for polar charts.
267 267 */
268 268
269 269 /*!
270 270 \qmlmethod ChartView::zoomOut()
271 271 Zooms out the view by a factor of two.
272 272 */
273 273
274 274 /*!
275 275 \qmlmethod ChartView::zoomReset()
276 276 Resets the series domains to what they were before any zoom method was called.
277 277 Note that this will also reset any scrolls and explicit axis range settings done between
278 278 the first zoom operation and calling this method. If no zoom operation has been
279 279 done, this method does nothing.
280 280 */
281 281
282 282 /*!
283 283 \qmlmethod ChartView::isZoomed()
284 284 Returns true if any series has a zoomed domain.
285 285 */
286 286
287 287 /*!
288 288 \qmlmethod ChartView::scrollLeft(real pixels)
289 289 Scrolls to left by \a pixels. This is a convenience function that suits for example for key navigation.
290 290 */
291 291
292 292 /*!
293 293 \qmlmethod ChartView::scrollRight(real pixels)
294 294 Scrolls to right by \a pixels. This is a convenience function that suits for example for key navigation.
295 295 */
296 296
297 297 /*!
298 298 \qmlmethod ChartView::scrollUp(real pixels)
299 299 Scrolls up by \a pixels. This is a convenience function that suits for example for key navigation.
300 300 */
301 301
302 302 /*!
303 303 \qmlmethod ChartView::scrollDown(real pixels)
304 304 Scrolls down by \a pixels. This is a convenience function that suits for example for key navigation.
305 305 */
306 306
307 307 /*!
308 308 \qmlmethod point ChartView::mapToValue(point position, AbstractSeries series)
309 309 Returns the value in the \a series domain that corresponds to the \a position relative to the
310 310 chart.
311 311 */
312 312
313 313 /*!
314 314 \qmlmethod point ChartView::mapToPosition(point value, AbstractSeries series)
315 315 Returns the position on the chart that corresponds to the \a value in the \a series domain.
316 316 */
317 317
318 318 /*!
319 319 \qmlsignal ChartView::seriesAdded(AbstractSeries series)
320 320 The \a series has been added to the chart.
321 321 */
322 322
323 323 /*!
324 324 \qmlsignal ChartView::seriesRemoved(AbstractSeries series)
325 325 The \a series has been removed from the chart. Please note that \a series is no longer a valid
326 326 object after the signal handler has completed.
327 327 */
328 328
329 329 DeclarativeChart::DeclarativeChart(QQuickItem *parent)
330 330 : QQuickItem(parent)
331 331 {
332 332 initChart(QChart::ChartTypeCartesian);
333 333 }
334 334
335 335 DeclarativeChart::DeclarativeChart(QChart::ChartType type, QQuickItem *parent)
336 336 : QQuickItem(parent)
337 337 {
338 338 initChart(type);
339 339 }
340 340
341 341 void DeclarativeChart::initChart(QChart::ChartType type)
342 342 {
343 343 m_sceneImage = 0;
344 344 m_sceneImageDirty = false;
345 345 m_sceneImageNeedsClear = false;
346 346 m_guiThreadId = QThread::currentThreadId();
347 347 m_paintThreadId = 0;
348 348 m_updatePending = false;
349 349
350 350 setFlag(ItemHasContents, true);
351 351
352 352 if (type == QChart::ChartTypePolar)
353 353 m_chart = new QPolarChart();
354 354 else
355 355 m_chart = new QChart();
356 356
357 357 m_chart->d_ptr->m_presenter->glSetUseWidget(false);
358 358 m_glXYDataManager = m_chart->d_ptr->m_dataset->glXYSeriesDataManager();
359 359
360 360 m_scene = new QGraphicsScene(this);
361 361 m_scene->addItem(m_chart);
362 362
363 363 setAntialiasing(QQuickItem::antialiasing());
364 364 connect(m_scene, &QGraphicsScene::changed, this, &DeclarativeChart::sceneChanged);
365 365 connect(this, &DeclarativeChart::needRender, this, &DeclarativeChart::renderScene,
366 366 Qt::QueuedConnection);
367 367 connect(this, SIGNAL(antialiasingChanged(bool)), this, SLOT(handleAntialiasingChanged(bool)));
368 368
369 369 setAcceptedMouseButtons(Qt::AllButtons);
370 370 setAcceptHoverEvents(true);
371 371
372 372 m_margins = new DeclarativeMargins(this);
373 373 m_margins->setTop(m_chart->margins().top());
374 374 m_margins->setLeft(m_chart->margins().left());
375 375 m_margins->setRight(m_chart->margins().right());
376 376 m_margins->setBottom(m_chart->margins().bottom());
377 377 connect(m_margins, SIGNAL(topChanged(int,int,int,int)),
378 378 this, SLOT(changeMargins(int,int,int,int)));
379 379 connect(m_margins, SIGNAL(bottomChanged(int,int,int,int)),
380 380 this, SLOT(changeMargins(int,int,int,int)));
381 381 connect(m_margins, SIGNAL(leftChanged(int,int,int,int)),
382 382 this, SLOT(changeMargins(int,int,int,int)));
383 383 connect(m_margins, SIGNAL(rightChanged(int,int,int,int)),
384 384 this, SLOT(changeMargins(int,int,int,int)));
385 385 connect(m_chart->d_ptr->m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), this, SLOT(handleSeriesAdded(QAbstractSeries*)));
386 386 connect(m_chart->d_ptr->m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)), this, SIGNAL(seriesRemoved(QAbstractSeries*)));
387 387 connect(m_chart, &QChart::plotAreaChanged, this, &DeclarativeChart::plotAreaChanged);
388 388 }
389 389
390 390 void DeclarativeChart::handleSeriesAdded(QAbstractSeries *series)
391 391 {
392 392 emit seriesAdded(series);
393 393 }
394 394
395 395 void DeclarativeChart::changeMargins(int top, int bottom, int left, int right)
396 396 {
397 397 m_chart->setMargins(QMargins(left, top, right, bottom));
398 398 emit marginsChanged();
399 399 }
400 400
401 401 DeclarativeChart::~DeclarativeChart()
402 402 {
403 403 delete m_chart;
404 404 delete m_sceneImage;
405 405 }
406 406
407 407 void DeclarativeChart::childEvent(QChildEvent *event)
408 408 {
409 409 if (event->type() == QEvent::ChildAdded) {
410 410 if (qobject_cast<QAbstractSeries *>(event->child())) {
411 411 m_chart->addSeries(qobject_cast<QAbstractSeries *>(event->child()));
412 412 }
413 413 }
414 414 }
415 415
416 416 void DeclarativeChart::componentComplete()
417 417 {
418 418 foreach (QObject *child, children()) {
419 419 if (qobject_cast<QAbstractSeries *>(child)) {
420 420 // Add series to the chart
421 421 QAbstractSeries *series = qobject_cast<QAbstractSeries *>(child);
422 422 m_chart->addSeries(series);
423 423
424 424 // Connect to axis changed signals (unless this is a pie series)
425 425 if (!qobject_cast<DeclarativePieSeries *>(series)) {
426 426 connect(series, SIGNAL(axisXChanged(QAbstractAxis*)), this, SLOT(handleAxisXSet(QAbstractAxis*)));
427 427 connect(series, SIGNAL(axisXTopChanged(QAbstractAxis*)), this, SLOT(handleAxisXTopSet(QAbstractAxis*)));
428 428 connect(series, SIGNAL(axisYChanged(QAbstractAxis*)), this, SLOT(handleAxisYSet(QAbstractAxis*)));
429 429 connect(series, SIGNAL(axisYRightChanged(QAbstractAxis*)), this, SLOT(handleAxisYRightSet(QAbstractAxis*)));
430 430 }
431 431
432 432 initializeAxes(series);
433 433 }
434 434 }
435 435
436 436 QQuickItem::componentComplete();
437 437 }
438 438
439 439 void DeclarativeChart::seriesAxisAttachHelper(QAbstractSeries *series, QAbstractAxis *axis,
440 440 Qt::Orientations orientation,
441 441 Qt::Alignment alignment)
442 442 {
443 443 if (!series->attachedAxes().contains(axis)) {
444 444 // Remove & delete old axes that are not attached to any other series
445 445 foreach (QAbstractAxis* oldAxis, m_chart->axes(orientation, series)) {
446 446 bool otherAttachments = false;
447 447 if (oldAxis != axis) {
448 448 foreach (QAbstractSeries *oldSeries, m_chart->series()) {
449 449 if (oldSeries != series && oldSeries->attachedAxes().contains(oldAxis)) {
450 450 otherAttachments = true;
451 451 break;
452 452 }
453 453 }
454 454 if (!otherAttachments) {
455 455 m_chart->removeAxis(oldAxis);
456 456 delete oldAxis;
457 457 }
458 458 }
459 459 }
460 460 if (!m_chart->axes(orientation).contains(axis))
461 461 m_chart->addAxis(axis, alignment);
462 462
463 463 series->attachAxis(axis);
464 464 }
465 465 }
466 466
467 467 void DeclarativeChart::handleAxisXSet(QAbstractAxis *axis)
468 468 {
469 469 QAbstractSeries *s = qobject_cast<QAbstractSeries *>(sender());
470 470 if (axis && s) {
471 471 seriesAxisAttachHelper(s, axis, Qt::Horizontal, Qt::AlignBottom);
472 472 } else {
473 473 qWarning() << "Trying to set axisX to null.";
474 474 }
475 475 }
476 476
477 477 void DeclarativeChart::handleAxisXTopSet(QAbstractAxis *axis)
478 478 {
479 479 QAbstractSeries *s = qobject_cast<QAbstractSeries *>(sender());
480 480 if (axis && s) {
481 481 seriesAxisAttachHelper(s, axis, Qt::Horizontal, Qt::AlignTop);
482 482 } else {
483 483 qWarning() << "Trying to set axisXTop to null.";
484 484 }
485 485 }
486 486
487 487 void DeclarativeChart::handleAxisYSet(QAbstractAxis *axis)
488 488 {
489 489 QAbstractSeries *s = qobject_cast<QAbstractSeries *>(sender());
490 490 if (axis && s) {
491 491 seriesAxisAttachHelper(s, axis, Qt::Vertical, Qt::AlignLeft);
492 492 } else {
493 493 qWarning() << "Trying to set axisY to null.";
494 494 }
495 495 }
496 496
497 497 void DeclarativeChart::handleAxisYRightSet(QAbstractAxis *axis)
498 498 {
499 499 QAbstractSeries *s = qobject_cast<QAbstractSeries *>(sender());
500 500 if (axis && s) {
501 501 seriesAxisAttachHelper(s, axis, Qt::Vertical, Qt::AlignRight);
502 502 } else {
503 503 qWarning() << "Trying to set axisYRight to null.";
504 504 }
505 505 }
506 506
507 507 void DeclarativeChart::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
508 508 {
509 509 if (newGeometry.isValid()) {
510 510 if (newGeometry.width() > 0 && newGeometry.height() > 0) {
511 511 m_chart->resize(newGeometry.width(), newGeometry.height());
512 512 }
513 513 }
514 514 QQuickItem::geometryChanged(newGeometry, oldGeometry);
515 515 }
516 516
517 517 QSGNode *DeclarativeChart::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
518 518 {
519 519 DeclarativeChartNode *node = static_cast<DeclarativeChartNode *>(oldNode);
520 520
521 521 if (!node) {
522 522 node = new DeclarativeChartNode(window());
523 523 connect(window(), &QQuickWindow::beforeRendering,
524 524 node->glRenderNode(), &DeclarativeRenderNode::render);
525 525 }
526 526
527 527 const QRectF &bRect = boundingRect();
528 528
529 529 // Update GL data
530 530 if (m_glXYDataManager->dataMap().size() || m_glXYDataManager->mapDirty()) {
531 531 const QRectF &plotArea = m_chart->plotArea();
532 532 const QSizeF &chartAreaSize = m_chart->size();
533 533
534 534 // We can't use chart's plot area directly, as graphicscene has some internal minimum size
535 535 const qreal normalizedX = plotArea.x() / chartAreaSize.width();
536 536 const qreal normalizedY = plotArea.y() / chartAreaSize.height();
537 537 const qreal normalizedWidth = plotArea.width() / chartAreaSize.width();
538 538 const qreal normalizedHeight = plotArea.height() / chartAreaSize.height();
539 539
540 540 QRectF adjustedPlotArea(normalizedX * bRect.width(),
541 541 normalizedY * bRect.height(),
542 542 normalizedWidth * bRect.width(),
543 543 normalizedHeight * bRect.height());
544 544
545 545 const QSize &adjustedPlotSize = adjustedPlotArea.size().toSize();
546 546 if (adjustedPlotSize != node->glRenderNode()->textureSize())
547 547 node->glRenderNode()->setTextureSize(adjustedPlotSize);
548 548
549 549 node->glRenderNode()->setRect(adjustedPlotArea);
550 550 node->glRenderNode()->setSeriesData(m_glXYDataManager->mapDirty(),
551 551 m_glXYDataManager->dataMap());
552 552
553 553 // Clear dirty flags from original xy data
554 554 m_glXYDataManager->clearAllDirty();
555 555 }
556 556
557 557 // Copy chart (if dirty) to chart node
558 558 if (m_sceneImageDirty) {
559 559 node->createTextureFromImage(*m_sceneImage);
560 560 m_sceneImageDirty = false;
561 561 }
562 562
563 563 node->setRect(bRect);
564 564
565 565 return node;
566 566 }
567 567
568 568 void DeclarativeChart::sceneChanged(QList<QRectF> region)
569 569 {
570 570 const int count = region.size();
571 571 const qreal limitSize = 0.01;
572 572 if (count && !m_updatePending) {
573 573 qreal totalSize = 0.0;
574 574 for (int i = 0; i < count; i++) {
575 575 const QRectF &reg = region.at(i);
576 576 totalSize += (reg.height() * reg.width());
577 577 if (totalSize >= limitSize)
578 578 break;
579 579 }
580 580 // Ignore region updates that change less than small fraction of a pixel, as there is
581 581 // little point regenerating the image in these cases. These are typically cases
582 582 // where OpenGL series are drawn to otherwise static chart.
583 583 if (totalSize >= limitSize) {
584 584 m_updatePending = true;
585 585 // Do async render to avoid some unnecessary renders.
586 586 emit needRender();
587 587 } else {
588 588 // We do want to call update to trigger possible gl series updates.
589 589 update();
590 590 }
591 591 }
592 592 }
593 593
594 594 void DeclarativeChart::renderScene()
595 595 {
596 596 m_updatePending = false;
597 597 m_sceneImageDirty = true;
598 598 QSize chartSize = m_chart->size().toSize();
599 599 if (!m_sceneImage || chartSize != m_sceneImage->size()) {
600 600 delete m_sceneImage;
601 m_sceneImage = new QImage(chartSize, QImage::Format_ARGB32);
601 qreal dpr = window() ? window()->devicePixelRatio() : 1.0;
602 m_sceneImage = new QImage(chartSize * dpr, QImage::Format_ARGB32);
603 m_sceneImage->setDevicePixelRatio(dpr);
602 604 m_sceneImageNeedsClear = true;
603 605 }
604 606
605 607 if (m_sceneImageNeedsClear) {
606 608 m_sceneImage->fill(Qt::transparent);
607 609 // Don't clear the flag if chart background has any transparent element to it
608 610 if (m_chart->backgroundBrush().color().alpha() == 0xff && !m_chart->isDropShadowEnabled())
609 611 m_sceneImageNeedsClear = false;
610 612 }
611 613 QPainter painter(m_sceneImage);
612 614 if (antialiasing()) {
613 615 painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing
614 616 | QPainter::SmoothPixmapTransform);
615 617 }
616 618 QRect renderRect(QPoint(0, 0), chartSize);
617 619 m_scene->render(&painter, renderRect, renderRect);
618 620 update();
619 621 }
620 622
621 623 void DeclarativeChart::mousePressEvent(QMouseEvent *event)
622 624 {
623 625 m_mousePressScenePoint = event->pos();
624 626 m_mousePressScreenPoint = event->globalPos();
625 627 m_lastMouseMoveScenePoint = m_mousePressScenePoint;
626 628 m_lastMouseMoveScreenPoint = m_mousePressScreenPoint;
627 629 m_mousePressButton = event->button();
628 630 m_mousePressButtons = event->buttons();
629 631
630 632 QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMousePress);
631 633 mouseEvent.setWidget(0);
632 634 mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint);
633 635 mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint);
634 636 mouseEvent.setScenePos(m_mousePressScenePoint);
635 637 mouseEvent.setScreenPos(m_mousePressScreenPoint);
636 638 mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint);
637 639 mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint);
638 640 mouseEvent.setButtons(m_mousePressButtons);
639 641 mouseEvent.setButton(m_mousePressButton);
640 642 mouseEvent.setModifiers(event->modifiers());
641 643 mouseEvent.setAccepted(false);
642 644
643 645 QApplication::sendEvent(m_scene, &mouseEvent);
644 646 }
645 647
646 648 void DeclarativeChart::mouseReleaseEvent(QMouseEvent *event)
647 649 {
648 650 QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseRelease);
649 651 mouseEvent.setWidget(0);
650 652 mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint);
651 653 mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint);
652 654 mouseEvent.setScenePos(event->pos());
653 655 mouseEvent.setScreenPos(event->globalPos());
654 656 mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint);
655 657 mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint);
656 658 mouseEvent.setButtons(event->buttons());
657 659 mouseEvent.setButton(event->button());
658 660 mouseEvent.setModifiers(event->modifiers());
659 661 mouseEvent.setAccepted(false);
660 662
661 663 QApplication::sendEvent(m_scene, &mouseEvent);
662 664
663 665 m_mousePressButtons = event->buttons();
664 666 m_mousePressButton = Qt::NoButton;
665 667 }
666 668
667 669 void DeclarativeChart::hoverMoveEvent(QHoverEvent *event)
668 670 {
669 671 // Convert hover move to mouse move, since we don't seem to get actual mouse move events.
670 672 // QGraphicsScene generates hover events from mouse move events, so we don't need
671 673 // to pass hover events there.
672 674 QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
673 675 mouseEvent.setWidget(0);
674 676 mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint);
675 677 mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint);
676 678 mouseEvent.setScenePos(event->pos());
677 679 // Hover events do not have global pos in them, and the screen position doesn't seem to
678 680 // matter anyway in this use case, so just pass event pos instead of trying to
679 681 // calculate the real screen position.
680 682 mouseEvent.setScreenPos(event->pos());
681 683 mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint);
682 684 mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint);
683 685 mouseEvent.setButtons(m_mousePressButtons);
684 686 mouseEvent.setButton(m_mousePressButton);
685 687 mouseEvent.setModifiers(event->modifiers());
686 688 m_lastMouseMoveScenePoint = mouseEvent.scenePos();
687 689 m_lastMouseMoveScreenPoint = mouseEvent.screenPos();
688 690 mouseEvent.setAccepted(false);
689 691
690 692 QApplication::sendEvent(m_scene, &mouseEvent);
691 693 }
692 694
693 695 void DeclarativeChart::mouseDoubleClickEvent(QMouseEvent *event)
694 696 {
695 697 m_mousePressScenePoint = event->pos();
696 698 m_mousePressScreenPoint = event->globalPos();
697 699 m_lastMouseMoveScenePoint = m_mousePressScenePoint;
698 700 m_lastMouseMoveScreenPoint = m_mousePressScreenPoint;
699 701 m_mousePressButton = event->button();
700 702 m_mousePressButtons = event->buttons();
701 703
702 704 QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseDoubleClick);
703 705 mouseEvent.setWidget(0);
704 706 mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint);
705 707 mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint);
706 708 mouseEvent.setScenePos(m_mousePressScenePoint);
707 709 mouseEvent.setScreenPos(m_mousePressScreenPoint);
708 710 mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint);
709 711 mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint);
710 712 mouseEvent.setButtons(m_mousePressButtons);
711 713 mouseEvent.setButton(m_mousePressButton);
712 714 mouseEvent.setModifiers(event->modifiers());
713 715 mouseEvent.setAccepted(false);
714 716
715 717 QApplication::sendEvent(m_scene, &mouseEvent);
716 718 }
717 719
718 720 void DeclarativeChart::handleAntialiasingChanged(bool enable)
719 721 {
720 722 setAntialiasing(enable);
721 723 }
722 724
723 725 void DeclarativeChart::setTheme(DeclarativeChart::Theme theme)
724 726 {
725 727 QChart::ChartTheme chartTheme = (QChart::ChartTheme) theme;
726 728 if (chartTheme != m_chart->theme())
727 729 m_chart->setTheme(chartTheme);
728 730 }
729 731
730 732 DeclarativeChart::Theme DeclarativeChart::theme()
731 733 {
732 734 return (DeclarativeChart::Theme) m_chart->theme();
733 735 }
734 736
735 737 void DeclarativeChart::setAnimationOptions(DeclarativeChart::Animation animations)
736 738 {
737 739 QChart::AnimationOption animationOptions = (QChart::AnimationOption) animations;
738 740 if (animationOptions != m_chart->animationOptions())
739 741 m_chart->setAnimationOptions(animationOptions);
740 742 }
741 743
742 744 DeclarativeChart::Animation DeclarativeChart::animationOptions()
743 745 {
744 746 if (m_chart->animationOptions().testFlag(QChart::AllAnimations))
745 747 return DeclarativeChart::AllAnimations;
746 748 else if (m_chart->animationOptions().testFlag(QChart::GridAxisAnimations))
747 749 return DeclarativeChart::GridAxisAnimations;
748 750 else if (m_chart->animationOptions().testFlag(QChart::SeriesAnimations))
749 751 return DeclarativeChart::SeriesAnimations;
750 752 else
751 753 return DeclarativeChart::NoAnimation;
752 754 }
753 755
754 756 void DeclarativeChart::setAnimationDuration(int msecs)
755 757 {
756 758 if (msecs != m_chart->animationDuration()) {
757 759 m_chart->setAnimationDuration(msecs);
758 760 emit animationDurationChanged(msecs);
759 761 }
760 762 }
761 763
762 764 int DeclarativeChart::animationDuration() const
763 765 {
764 766 return m_chart->animationDuration();
765 767 }
766 768
767 769 void DeclarativeChart::setAnimationEasingCurve(const QEasingCurve &curve)
768 770 {
769 771 if (curve != m_chart->animationEasingCurve()) {
770 772 m_chart->setAnimationEasingCurve(curve);
771 773 emit animationEasingCurveChanged(curve);
772 774 }
773 775 }
774 776
775 777 QEasingCurve DeclarativeChart::animationEasingCurve() const
776 778 {
777 779 return m_chart->animationEasingCurve();
778 780 }
779 781
780 782 void DeclarativeChart::setTitle(QString title)
781 783 {
782 784 if (title != m_chart->title())
783 785 m_chart->setTitle(title);
784 786 }
785 787 QString DeclarativeChart::title()
786 788 {
787 789 return m_chart->title();
788 790 }
789 791
790 792 QAbstractAxis *DeclarativeChart::axisX(QAbstractSeries *series)
791 793 {
792 794 QList<QAbstractAxis *> axes = m_chart->axes(Qt::Horizontal, series);
793 795 if (axes.count())
794 796 return axes[0];
795 797 return 0;
796 798 }
797 799
798 800 QAbstractAxis *DeclarativeChart::axisY(QAbstractSeries *series)
799 801 {
800 802 QList<QAbstractAxis *> axes = m_chart->axes(Qt::Vertical, series);
801 803 if (axes.count())
802 804 return axes[0];
803 805 return 0;
804 806 }
805 807
806 808 QLegend *DeclarativeChart::legend()
807 809 {
808 810 return m_chart->legend();
809 811 }
810 812
811 813 void DeclarativeChart::setTitleColor(QColor color)
812 814 {
813 815 QBrush b = m_chart->titleBrush();
814 816 if (color != b.color()) {
815 817 b.setColor(color);
816 818 m_chart->setTitleBrush(b);
817 819 emit titleColorChanged(color);
818 820 }
819 821 }
820 822
821 823 QFont DeclarativeChart::titleFont() const
822 824 {
823 825 return m_chart->titleFont();
824 826 }
825 827
826 828 void DeclarativeChart::setTitleFont(const QFont &font)
827 829 {
828 830 m_chart->setTitleFont(font);
829 831 }
830 832
831 833 QColor DeclarativeChart::titleColor()
832 834 {
833 835 return m_chart->titleBrush().color();
834 836 }
835 837
836 838 void DeclarativeChart::setBackgroundColor(QColor color)
837 839 {
838 840 QBrush b = m_chart->backgroundBrush();
839 841 if (b.style() != Qt::SolidPattern || color != b.color()) {
840 842 if (color.alpha() < 0xff)
841 843 m_sceneImageNeedsClear = true;
842 844 b.setStyle(Qt::SolidPattern);
843 845 b.setColor(color);
844 846 m_chart->setBackgroundBrush(b);
845 847 emit backgroundColorChanged();
846 848 }
847 849 }
848 850
849 851 QColor DeclarativeChart::backgroundColor()
850 852 {
851 853 return m_chart->backgroundBrush().color();
852 854 }
853 855
854 856 void QtCharts::DeclarativeChart::setPlotAreaColor(QColor color)
855 857 {
856 858 QBrush b = m_chart->plotAreaBackgroundBrush();
857 859 if (b.style() != Qt::SolidPattern || color != b.color()) {
858 860 b.setStyle(Qt::SolidPattern);
859 861 b.setColor(color);
860 862 m_chart->setPlotAreaBackgroundBrush(b);
861 863 m_chart->setPlotAreaBackgroundVisible(true);
862 864 emit plotAreaColorChanged();
863 865 }
864 866 }
865 867
866 868 QColor QtCharts::DeclarativeChart::plotAreaColor()
867 869 {
868 870 return m_chart->plotAreaBackgroundBrush().color();
869 871 }
870 872
871 873 void DeclarativeChart::setLocalizeNumbers(bool localize)
872 874 {
873 875 if (m_chart->localizeNumbers() != localize) {
874 876 m_chart->setLocalizeNumbers(localize);
875 877 emit localizeNumbersChanged();
876 878 }
877 879 }
878 880
879 881 bool DeclarativeChart::localizeNumbers() const
880 882 {
881 883 return m_chart->localizeNumbers();
882 884 }
883 885
884 886 void QtCharts::DeclarativeChart::setLocale(const QLocale &locale)
885 887 {
886 888 if (m_chart->locale() != locale) {
887 889 m_chart->setLocale(locale);
888 890 emit localeChanged();
889 891 }
890 892 }
891 893
892 894 QLocale QtCharts::DeclarativeChart::locale() const
893 895 {
894 896 return m_chart->locale();
895 897 }
896 898
897 899 int DeclarativeChart::count()
898 900 {
899 901 return m_chart->series().count();
900 902 }
901 903
902 904 void DeclarativeChart::setDropShadowEnabled(bool enabled)
903 905 {
904 906 if (enabled != m_chart->isDropShadowEnabled()) {
905 907 m_sceneImageNeedsClear = true;
906 908 m_chart->setDropShadowEnabled(enabled);
907 909 dropShadowEnabledChanged(enabled);
908 910 }
909 911 }
910 912
911 913 bool DeclarativeChart::dropShadowEnabled()
912 914 {
913 915 return m_chart->isDropShadowEnabled();
914 916 }
915 917
916 918 qreal DeclarativeChart::backgroundRoundness() const
917 919 {
918 920 return m_chart->backgroundRoundness();
919 921 }
920 922
921 923 void DeclarativeChart::setBackgroundRoundness(qreal diameter)
922 924 {
923 925 if (m_chart->backgroundRoundness() != diameter) {
924 926 m_sceneImageNeedsClear = true;
925 927 m_chart->setBackgroundRoundness(diameter);
926 928 emit backgroundRoundnessChanged(diameter);
927 929 }
928 930 }
929 931
930 932 void DeclarativeChart::zoom(qreal factor)
931 933 {
932 934 m_chart->zoom(factor);
933 935 }
934 936
935 937 void DeclarativeChart::zoomIn()
936 938 {
937 939 m_chart->zoomIn();
938 940 }
939 941
940 942 void DeclarativeChart::zoomIn(const QRectF &rectangle)
941 943 {
942 944 m_chart->zoomIn(rectangle);
943 945 }
944 946
945 947 void DeclarativeChart::zoomOut()
946 948 {
947 949 m_chart->zoomOut();
948 950 }
949 951
950 952 void DeclarativeChart::zoomReset()
951 953 {
952 954 m_chart->zoomReset();
953 955 }
954 956
955 957 bool DeclarativeChart::isZoomed()
956 958 {
957 959 return m_chart->isZoomed();
958 960 }
959 961
960 962 void DeclarativeChart::scrollLeft(qreal pixels)
961 963 {
962 964 m_chart->scroll(-pixels, 0);
963 965 }
964 966
965 967 void DeclarativeChart::scrollRight(qreal pixels)
966 968 {
967 969 m_chart->scroll(pixels, 0);
968 970 }
969 971
970 972 void DeclarativeChart::scrollUp(qreal pixels)
971 973 {
972 974 m_chart->scroll(0, pixels);
973 975 }
974 976
975 977 void DeclarativeChart::scrollDown(qreal pixels)
976 978 {
977 979 m_chart->scroll(0, -pixels);
978 980 }
979 981
980 982 QQmlListProperty<QAbstractAxis> DeclarativeChart::axes()
981 983 {
982 984 return QQmlListProperty<QAbstractAxis>(this, 0,
983 985 &DeclarativeChart::axesAppendFunc,
984 986 &DeclarativeChart::axesCountFunc,
985 987 &DeclarativeChart::axesAtFunc,
986 988 &DeclarativeChart::axesClearFunc);
987 989 }
988 990
989 991 void DeclarativeChart::axesAppendFunc(QQmlListProperty<QAbstractAxis> *list, QAbstractAxis *element)
990 992 {
991 993 // Empty implementation
992 994 Q_UNUSED(list);
993 995 Q_UNUSED(element);
994 996 }
995 997
996 998 int DeclarativeChart::axesCountFunc(QQmlListProperty<QAbstractAxis> *list)
997 999 {
998 1000 if (qobject_cast<DeclarativeChart *>(list->object)) {
999 1001 DeclarativeChart *chart = qobject_cast<DeclarativeChart *>(list->object);
1000 1002 return chart->m_chart->axes(Qt::Horizontal | Qt::Vertical).count();
1001 1003 }
1002 1004 return 0;
1003 1005 }
1004 1006
1005 1007 QAbstractAxis *DeclarativeChart::axesAtFunc(QQmlListProperty<QAbstractAxis> *list, int index)
1006 1008 {
1007 1009 if (qobject_cast<DeclarativeChart *>(list->object)) {
1008 1010 DeclarativeChart *chart = qobject_cast<DeclarativeChart *>(list->object);
1009 1011 QList<QAbstractAxis *> axes = chart->m_chart->axes(Qt::Horizontal | Qt::Vertical, chart->m_chart->series()[0]);
1010 1012 return axes.at(index);
1011 1013 }
1012 1014 return 0;
1013 1015 }
1014 1016
1015 1017 void DeclarativeChart::axesClearFunc(QQmlListProperty<QAbstractAxis> *list)
1016 1018 {
1017 1019 // Empty implementation
1018 1020 Q_UNUSED(list);
1019 1021 }
1020 1022
1021 1023
1022 1024 QAbstractSeries *DeclarativeChart::series(int index)
1023 1025 {
1024 1026 if (index < m_chart->series().count()) {
1025 1027 return m_chart->series().at(index);
1026 1028 }
1027 1029 return 0;
1028 1030 }
1029 1031
1030 1032 QAbstractSeries *DeclarativeChart::series(QString seriesName)
1031 1033 {
1032 1034 foreach (QAbstractSeries *series, m_chart->series()) {
1033 1035 if (series->name() == seriesName)
1034 1036 return series;
1035 1037 }
1036 1038 return 0;
1037 1039 }
1038 1040
1039 1041 QAbstractSeries *DeclarativeChart::createSeries(int type, QString name, QAbstractAxis *axisX, QAbstractAxis *axisY)
1040 1042 {
1041 1043 QAbstractSeries *series = 0;
1042 1044
1043 1045 switch (type) {
1044 1046 case DeclarativeChart::SeriesTypeLine:
1045 1047 series = new DeclarativeLineSeries();
1046 1048 break;
1047 1049 case DeclarativeChart::SeriesTypeArea: {
1048 1050 DeclarativeAreaSeries *area = new DeclarativeAreaSeries();
1049 1051 DeclarativeLineSeries *line = new DeclarativeLineSeries();
1050 1052 line->setParent(area);
1051 1053 area->setUpperSeries(line);
1052 1054 series = area;
1053 1055 break;
1054 1056 }
1055 1057 case DeclarativeChart::SeriesTypeStackedBar:
1056 1058 series = new DeclarativeStackedBarSeries();
1057 1059 break;
1058 1060 case DeclarativeChart::SeriesTypePercentBar:
1059 1061 series = new DeclarativePercentBarSeries();
1060 1062 break;
1061 1063 case DeclarativeChart::SeriesTypeBar:
1062 1064 series = new DeclarativeBarSeries();
1063 1065 break;
1064 1066 case DeclarativeChart::SeriesTypeHorizontalBar:
1065 1067 series = new DeclarativeHorizontalBarSeries();
1066 1068 break;
1067 1069 case DeclarativeChart::SeriesTypeHorizontalPercentBar:
1068 1070 series = new DeclarativeHorizontalPercentBarSeries();
1069 1071 break;
1070 1072 case DeclarativeChart::SeriesTypeHorizontalStackedBar:
1071 1073 series = new DeclarativeHorizontalStackedBarSeries();
1072 1074 break;
1073 1075 case DeclarativeChart::SeriesTypeBoxPlot:
1074 1076 series = new DeclarativeBoxPlotSeries();
1075 1077 break;
1076 1078 case DeclarativeChart::SeriesTypePie:
1077 1079 series = new DeclarativePieSeries();
1078 1080 break;
1079 1081 case DeclarativeChart::SeriesTypeScatter:
1080 1082 series = new DeclarativeScatterSeries();
1081 1083 break;
1082 1084 case DeclarativeChart::SeriesTypeSpline:
1083 1085 series = new DeclarativeSplineSeries();
1084 1086 break;
1085 1087 default:
1086 1088 qWarning() << "Illegal series type";
1087 1089 }
1088 1090
1089 1091 if (series) {
1090 1092 // Connect to axis changed signals (unless this is a pie series)
1091 1093 if (!qobject_cast<DeclarativePieSeries *>(series)) {
1092 1094 connect(series, SIGNAL(axisXChanged(QAbstractAxis*)), this, SLOT(handleAxisXSet(QAbstractAxis*)));
1093 1095 connect(series, SIGNAL(axisXTopChanged(QAbstractAxis*)), this, SLOT(handleAxisXSet(QAbstractAxis*)));
1094 1096 connect(series, SIGNAL(axisYChanged(QAbstractAxis*)), this, SLOT(handleAxisYSet(QAbstractAxis*)));
1095 1097 connect(series, SIGNAL(axisYRightChanged(QAbstractAxis*)), this, SLOT(handleAxisYRightSet(QAbstractAxis*)));
1096 1098 }
1097 1099
1098 1100 series->setName(name);
1099 1101 m_chart->addSeries(series);
1100 1102
1101 1103 if (!axisX || !axisY)
1102 1104 initializeAxes(series);
1103 1105
1104 1106 if (axisX)
1105 1107 setAxisX(axisX, series);
1106 1108 if (axisY)
1107 1109 setAxisY(axisY, series);
1108 1110 }
1109 1111
1110 1112 return series;
1111 1113 }
1112 1114
1113 1115 void DeclarativeChart::removeSeries(QAbstractSeries *series)
1114 1116 {
1115 1117 if (series)
1116 1118 m_chart->removeSeries(series);
1117 1119 else
1118 1120 qWarning("removeSeries: cannot remove null");
1119 1121 }
1120 1122
1121 1123 void DeclarativeChart::setAxisX(QAbstractAxis *axis, QAbstractSeries *series)
1122 1124 {
1123 1125 if (axis && series)
1124 1126 seriesAxisAttachHelper(series, axis, Qt::Horizontal, Qt::AlignBottom);
1125 1127 }
1126 1128
1127 1129 void DeclarativeChart::setAxisY(QAbstractAxis *axis, QAbstractSeries *series)
1128 1130 {
1129 1131 if (axis && series)
1130 1132 seriesAxisAttachHelper(series, axis, Qt::Vertical, Qt::AlignLeft);
1131 1133 }
1132 1134
1133 1135 QAbstractAxis *DeclarativeChart::defaultAxis(Qt::Orientation orientation, QAbstractSeries *series)
1134 1136 {
1135 1137 if (!series) {
1136 1138 qWarning() << "No axis type defined for null series";
1137 1139 return 0;
1138 1140 }
1139 1141
1140 1142 foreach (QAbstractAxis *existingAxis, m_chart->axes(orientation)) {
1141 1143 if (existingAxis->type() == series->d_ptr->defaultAxisType(orientation))
1142 1144 return existingAxis;
1143 1145 }
1144 1146
1145 1147 switch (series->d_ptr->defaultAxisType(orientation)) {
1146 1148 case QAbstractAxis::AxisTypeValue:
1147 1149 return new QValueAxis(this);
1148 1150 case QAbstractAxis::AxisTypeBarCategory:
1149 1151 return new QBarCategoryAxis(this);
1150 1152 case QAbstractAxis::AxisTypeCategory:
1151 1153 return new QCategoryAxis(this);
1152 1154 #ifndef QT_QREAL_IS_FLOAT
1153 1155 case QAbstractAxis::AxisTypeDateTime:
1154 1156 return new QDateTimeAxis(this);
1155 1157 #endif
1156 1158 case QAbstractAxis::AxisTypeLogValue:
1157 1159 return new QLogValueAxis(this);
1158 1160 default:
1159 1161 // assume AxisTypeNoAxis
1160 1162 return 0;
1161 1163 }
1162 1164 }
1163 1165
1164 1166 void DeclarativeChart::initializeAxes(QAbstractSeries *series)
1165 1167 {
1166 1168 if (qobject_cast<DeclarativeLineSeries *>(series))
1167 1169 doInitializeAxes(series, qobject_cast<DeclarativeLineSeries *>(series)->m_axes);
1168 1170 else if (qobject_cast<DeclarativeScatterSeries *>(series))
1169 1171 doInitializeAxes(series, qobject_cast<DeclarativeScatterSeries *>(series)->m_axes);
1170 1172 else if (qobject_cast<DeclarativeSplineSeries *>(series))
1171 1173 doInitializeAxes(series, qobject_cast<DeclarativeSplineSeries *>(series)->m_axes);
1172 1174 else if (qobject_cast<DeclarativeAreaSeries *>(series))
1173 1175 doInitializeAxes(series, qobject_cast<DeclarativeAreaSeries *>(series)->m_axes);
1174 1176 else if (qobject_cast<DeclarativeBarSeries *>(series))
1175 1177 doInitializeAxes(series, qobject_cast<DeclarativeBarSeries *>(series)->m_axes);
1176 1178 else if (qobject_cast<DeclarativeStackedBarSeries *>(series))
1177 1179 doInitializeAxes(series, qobject_cast<DeclarativeStackedBarSeries *>(series)->m_axes);
1178 1180 else if (qobject_cast<DeclarativePercentBarSeries *>(series))
1179 1181 doInitializeAxes(series, qobject_cast<DeclarativePercentBarSeries *>(series)->m_axes);
1180 1182 else if (qobject_cast<DeclarativeHorizontalBarSeries *>(series))
1181 1183 doInitializeAxes(series, qobject_cast<DeclarativeHorizontalBarSeries *>(series)->m_axes);
1182 1184 else if (qobject_cast<DeclarativeHorizontalStackedBarSeries *>(series))
1183 1185 doInitializeAxes(series, qobject_cast<DeclarativeHorizontalStackedBarSeries *>(series)->m_axes);
1184 1186 else if (qobject_cast<DeclarativeHorizontalPercentBarSeries *>(series))
1185 1187 doInitializeAxes(series, qobject_cast<DeclarativeHorizontalPercentBarSeries *>(series)->m_axes);
1186 1188 else if (qobject_cast<DeclarativeBoxPlotSeries *>(series))
1187 1189 doInitializeAxes(series, qobject_cast<DeclarativeBoxPlotSeries *>(series)->m_axes);
1188 1190 // else: do nothing
1189 1191 }
1190 1192
1191 1193 void DeclarativeChart::doInitializeAxes(QAbstractSeries *series, DeclarativeAxes *axes)
1192 1194 {
1193 1195 qreal min;
1194 1196 qreal max;
1195 1197 // Initialize axis X
1196 1198 if (axes->axisX()) {
1197 1199 axes->emitAxisXChanged();
1198 1200 } else if (axes->axisXTop()) {
1199 1201 axes->emitAxisXTopChanged();
1200 1202 } else {
1201 1203 axes->setAxisX(defaultAxis(Qt::Horizontal, series));
1202 1204 findMinMaxForSeries(series, Qt::Horizontal, min, max);
1203 1205 axes->axisX()->setRange(min, max);
1204 1206 }
1205 1207
1206 1208 // Initialize axis Y
1207 1209 if (axes->axisY()) {
1208 1210 axes->emitAxisYChanged();
1209 1211 } else if (axes->axisYRight()) {
1210 1212 axes->emitAxisYRightChanged();
1211 1213 } else {
1212 1214 axes->setAxisY(defaultAxis(Qt::Vertical, series));
1213 1215 findMinMaxForSeries(series, Qt::Vertical, min, max);
1214 1216 axes->axisY()->setRange(min, max);
1215 1217 }
1216 1218 }
1217 1219
1218 1220 void DeclarativeChart::findMinMaxForSeries(QAbstractSeries *series, Qt::Orientations orientation,
1219 1221 qreal &min, qreal &max)
1220 1222 {
1221 1223 if (!series) {
1222 1224 min = 0.5;
1223 1225 max = 0.5;
1224 1226 } else {
1225 1227 AbstractDomain *domain = series->d_ptr->domain();
1226 1228 min = (orientation == Qt::Vertical) ? domain->minY() : domain->minX();
1227 1229 max = (orientation == Qt::Vertical) ? domain->maxY() : domain->maxX();
1228 1230
1229 1231 if (min == max) {
1230 1232 min -= 0.5;
1231 1233 max += 0.5;
1232 1234 }
1233 1235 }
1234 1236 }
1235 1237
1236 1238 QPointF DeclarativeChart::mapToValue(const QPointF &position, QAbstractSeries *series)
1237 1239 {
1238 1240 return m_chart->mapToValue(position, series);
1239 1241 }
1240 1242
1241 1243 QPointF DeclarativeChart::mapToPosition(const QPointF &value, QAbstractSeries *series)
1242 1244 {
1243 1245 return m_chart->mapToPosition(value, series);
1244 1246 }
1245 1247
1246 1248 #include "moc_declarativechart.cpp"
1247 1249
1248 1250 QT_CHARTS_END_NAMESPACE
@@ -1,18 +1,18
1 1 %modules = ( # path to module name map
2 2 "QtCharts" => "$basedir/src/charts",
3 3 );
4 4 %moduleheaders = ( # restrict the module headers to those found in relative path
5 5 );
6 6 %classnames = (
7 7 "qchartglobal.h" => "QChartGlobal"
8 8 );
9 9 # Module dependencies.
10 10 # Every module that is required to build this module should have one entry.
11 11 # Each of the module version specifiers can take one of the following values:
12 12 # - A specific Git revision.
13 13 # - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch)
14 14 #
15 15 %dependencies = (
16 "qtbase" => "refs/heads/dev",
17 "qtdeclarative" => "refs/heads/dev",
16 "qtbase" => "",
17 "qtdeclarative" => "",
18 18 );
General Comments 0
You need to be logged in to leave comments. Login now