##// END OF EJS Templates
Added missing include to fix Android compile error...
Miikka Heikkinen -
r2843:d011d783e487
parent child
Show More
@@ -1,570 +1,571
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2015 The Qt Company Ltd
4 4 ** All rights reserved.
5 5 ** For any questions to The Qt Company, please use contact form at http://qt.io
6 6 **
7 7 ** This file is part of the Qt Charts module.
8 8 **
9 9 ** Licensees holding valid commercial license for Qt may use this file in
10 10 ** accordance with the Qt License Agreement provided with the Software
11 11 ** or, alternatively, in accordance with the terms contained in a written
12 12 ** agreement between you and The Qt Company.
13 13 **
14 14 ** If you have questions regarding the use of this file, please use
15 15 ** contact form at http://qt.io
16 16 **
17 17 ****************************************************************************/
18 18 #include <private/chartpresenter_p.h>
19 19 #include <QtCharts/QChart>
20 20 #include <private/chartitem_p.h>
21 21 #include <private/qchart_p.h>
22 22 #include <QtCharts/QAbstractAxis>
23 23 #include <private/qabstractaxis_p.h>
24 24 #include <private/chartdataset_p.h>
25 25 #include <private/chartanimation_p.h>
26 26 #include <private/qabstractseries_p.h>
27 27 #include <QtCharts/QAreaSeries>
28 28 #include <private/chartaxiselement_p.h>
29 29 #include <private/chartbackground_p.h>
30 30 #include <private/cartesianchartlayout_p.h>
31 31 #include <private/polarchartlayout_p.h>
32 32 #include <private/charttitle_p.h>
33 33 #include <QtCore/QTimer>
34 34 #include <QtGui/QTextDocument>
35 35 #include <QtWidgets/QGraphicsScene>
36 #include <QtWidgets/QGraphicsView>
36 37
37 38 QT_CHARTS_BEGIN_NAMESPACE
38 39
39 40 ChartPresenter::ChartPresenter(QChart *chart, QChart::ChartType type)
40 41 : QObject(chart),
41 42 m_chart(chart),
42 43 m_options(QChart::NoAnimation),
43 44 m_animationDuration(ChartAnimationDuration),
44 45 m_animationCurve(QEasingCurve::OutQuart),
45 46 m_state(ShowState),
46 47 m_background(0),
47 48 m_plotAreaBackground(0),
48 49 m_title(0),
49 50 m_localizeNumbers(false)
50 51 #ifndef QT_NO_OPENGL
51 52 , m_glWidget(0)
52 53 , m_glUseWidget(true)
53 54 #endif
54 55 {
55 56 if (type == QChart::ChartTypeCartesian)
56 57 m_layout = new CartesianChartLayout(this);
57 58 else if (type == QChart::ChartTypePolar)
58 59 m_layout = new PolarChartLayout(this);
59 60 Q_ASSERT(m_layout);
60 61 }
61 62
62 63 ChartPresenter::~ChartPresenter()
63 64 {
64 65 #ifndef QT_NO_OPENGL
65 66 delete m_glWidget.data();
66 67 #endif
67 68 }
68 69
69 70 void ChartPresenter::setGeometry(const QRectF rect)
70 71 {
71 72 if (m_rect != rect) {
72 73 m_rect = rect;
73 74 foreach (ChartItem *chart, m_chartItems) {
74 75 chart->domain()->setSize(rect.size());
75 76 chart->setPos(rect.topLeft());
76 77 }
77 78 #ifndef QT_NO_OPENGL
78 79 if (!m_glWidget.isNull())
79 80 m_glWidget->setGeometry(m_rect.toRect());
80 81 #endif
81 82 emit plotAreaChanged(m_rect);
82 83 }
83 84 }
84 85
85 86 QRectF ChartPresenter::geometry() const
86 87 {
87 88 return m_rect;
88 89 }
89 90
90 91 void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
91 92 {
92 93 axis->d_ptr->initializeGraphics(rootItem());
93 94 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
94 95 ChartAxisElement *item = axis->d_ptr->axisItem();
95 96 item->setPresenter(this);
96 97 item->setThemeManager(m_chart->d_ptr->m_themeManager);
97 98 m_axisItems<<item;
98 99 m_axes<<axis;
99 100 m_layout->invalidate();
100 101 }
101 102
102 103 void ChartPresenter::handleAxisRemoved(QAbstractAxis *axis)
103 104 {
104 105 ChartAxisElement *item = axis->d_ptr->m_item.take();
105 106 if (item->animation())
106 107 item->animation()->stopAndDestroyLater();
107 108 item->hide();
108 109 item->disconnect();
109 110 item->deleteLater();
110 111 m_axisItems.removeAll(item);
111 112 m_axes.removeAll(axis);
112 113 m_layout->invalidate();
113 114 }
114 115
115 116
116 117 void ChartPresenter::handleSeriesAdded(QAbstractSeries *series)
117 118 {
118 119 series->d_ptr->initializeGraphics(rootItem());
119 120 series->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
120 121 series->d_ptr->setPresenter(this);
121 122 ChartItem *chart = series->d_ptr->chartItem();
122 123 chart->setPresenter(this);
123 124 chart->setThemeManager(m_chart->d_ptr->m_themeManager);
124 125 chart->setDataSet(m_chart->d_ptr->m_dataset);
125 126 chart->domain()->setSize(m_rect.size());
126 127 chart->setPos(m_rect.topLeft());
127 128 chart->handleDomainUpdated(); //this could be moved to intializeGraphics when animator is refactored
128 129 m_chartItems<<chart;
129 130 m_series<<series;
130 131 m_layout->invalidate();
131 132 }
132 133
133 134 void ChartPresenter::handleSeriesRemoved(QAbstractSeries *series)
134 135 {
135 136 ChartItem *chart = series->d_ptr->m_item.take();
136 137 chart->hide();
137 138 chart->disconnect();
138 139 chart->deleteLater();
139 140 if (chart->animation())
140 141 chart->animation()->stopAndDestroyLater();
141 142 m_chartItems.removeAll(chart);
142 143 m_series.removeAll(series);
143 144 m_layout->invalidate();
144 145 }
145 146
146 147 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
147 148 {
148 149 if (m_options != options) {
149 150 QChart::AnimationOptions oldOptions = m_options;
150 151 m_options = options;
151 152 if (options.testFlag(QChart::SeriesAnimations) != oldOptions.testFlag(QChart::SeriesAnimations)) {
152 153 foreach (QAbstractSeries *series, m_series)
153 154 series->d_ptr->initializeAnimations(m_options, m_animationDuration,
154 155 m_animationCurve);
155 156 }
156 157 if (options.testFlag(QChart::GridAxisAnimations) != oldOptions.testFlag(QChart::GridAxisAnimations)) {
157 158 foreach (QAbstractAxis *axis, m_axes)
158 159 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
159 160 }
160 161 m_layout->invalidate(); // So that existing animations don't just stop halfway
161 162 }
162 163 }
163 164
164 165 void ChartPresenter::setAnimationDuration(int msecs)
165 166 {
166 167 if (m_animationDuration != msecs) {
167 168 m_animationDuration = msecs;
168 169 foreach (QAbstractSeries *series, m_series)
169 170 series->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
170 171 foreach (QAbstractAxis *axis, m_axes)
171 172 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
172 173 m_layout->invalidate(); // So that existing animations don't just stop halfway
173 174 }
174 175 }
175 176
176 177 void ChartPresenter::setAnimationEasingCurve(const QEasingCurve &curve)
177 178 {
178 179 if (m_animationCurve != curve) {
179 180 m_animationCurve = curve;
180 181 foreach (QAbstractSeries *series, m_series)
181 182 series->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
182 183 foreach (QAbstractAxis *axis, m_axes)
183 184 axis->d_ptr->initializeAnimations(m_options, m_animationDuration, m_animationCurve);
184 185 m_layout->invalidate(); // So that existing animations don't just stop halfway
185 186 }
186 187 }
187 188
188 189 void ChartPresenter::setState(State state,QPointF point)
189 190 {
190 191 m_state=state;
191 192 m_statePoint=point;
192 193 }
193 194
194 195 QChart::AnimationOptions ChartPresenter::animationOptions() const
195 196 {
196 197 return m_options;
197 198 }
198 199
199 200 void ChartPresenter::createBackgroundItem()
200 201 {
201 202 if (!m_background) {
202 203 m_background = new ChartBackground(rootItem());
203 204 m_background->setPen(Qt::NoPen); // Theme doesn't touch pen so don't use default
204 205 m_background->setBrush(QChartPrivate::defaultBrush());
205 206 m_background->setZValue(ChartPresenter::BackgroundZValue);
206 207 }
207 208 }
208 209
209 210 void ChartPresenter::createPlotAreaBackgroundItem()
210 211 {
211 212 if (!m_plotAreaBackground) {
212 213 if (m_chart->chartType() == QChart::ChartTypeCartesian)
213 214 m_plotAreaBackground = new QGraphicsRectItem(rootItem());
214 215 else
215 216 m_plotAreaBackground = new QGraphicsEllipseItem(rootItem());
216 217 // Use transparent pen instead of Qt::NoPen, as Qt::NoPen causes
217 218 // antialising artifacts with axis lines for some reason.
218 219 m_plotAreaBackground->setPen(QPen(Qt::transparent));
219 220 m_plotAreaBackground->setBrush(Qt::NoBrush);
220 221 m_plotAreaBackground->setZValue(ChartPresenter::PlotAreaZValue);
221 222 m_plotAreaBackground->setVisible(false);
222 223 }
223 224 }
224 225
225 226 void ChartPresenter::createTitleItem()
226 227 {
227 228 if (!m_title) {
228 229 m_title = new ChartTitle(rootItem());
229 230 m_title->setZValue(ChartPresenter::BackgroundZValue);
230 231 }
231 232 }
232 233
233 234 void ChartPresenter::startAnimation(ChartAnimation *animation)
234 235 {
235 236 animation->stop();
236 237 QTimer::singleShot(0, animation, SLOT(startChartAnimation()));
237 238 }
238 239
239 240 void ChartPresenter::setBackgroundBrush(const QBrush &brush)
240 241 {
241 242 createBackgroundItem();
242 243 m_background->setBrush(brush);
243 244 m_layout->invalidate();
244 245 }
245 246
246 247 QBrush ChartPresenter::backgroundBrush() const
247 248 {
248 249 if (!m_background)
249 250 return QBrush();
250 251 return m_background->brush();
251 252 }
252 253
253 254 void ChartPresenter::setBackgroundPen(const QPen &pen)
254 255 {
255 256 createBackgroundItem();
256 257 m_background->setPen(pen);
257 258 m_layout->invalidate();
258 259 }
259 260
260 261 QPen ChartPresenter::backgroundPen() const
261 262 {
262 263 if (!m_background)
263 264 return QPen();
264 265 return m_background->pen();
265 266 }
266 267
267 268 void ChartPresenter::setBackgroundRoundness(qreal diameter)
268 269 {
269 270 createBackgroundItem();
270 271 m_background->setDiameter(diameter);
271 272 m_layout->invalidate();
272 273 }
273 274
274 275 qreal ChartPresenter::backgroundRoundness() const
275 276 {
276 277 if (!m_background)
277 278 return 0;
278 279 return m_background->diameter();
279 280 }
280 281
281 282 void ChartPresenter::setPlotAreaBackgroundBrush(const QBrush &brush)
282 283 {
283 284 createPlotAreaBackgroundItem();
284 285 m_plotAreaBackground->setBrush(brush);
285 286 m_layout->invalidate();
286 287 }
287 288
288 289 QBrush ChartPresenter::plotAreaBackgroundBrush() const
289 290 {
290 291 if (!m_plotAreaBackground)
291 292 return QBrush();
292 293 return m_plotAreaBackground->brush();
293 294 }
294 295
295 296 void ChartPresenter::setPlotAreaBackgroundPen(const QPen &pen)
296 297 {
297 298 createPlotAreaBackgroundItem();
298 299 m_plotAreaBackground->setPen(pen);
299 300 m_layout->invalidate();
300 301 }
301 302
302 303 QPen ChartPresenter::plotAreaBackgroundPen() const
303 304 {
304 305 if (!m_plotAreaBackground)
305 306 return QPen();
306 307 return m_plotAreaBackground->pen();
307 308 }
308 309
309 310 void ChartPresenter::setTitle(const QString &title)
310 311 {
311 312 createTitleItem();
312 313 m_title->setText(title);
313 314 m_layout->invalidate();
314 315 }
315 316
316 317 QString ChartPresenter::title() const
317 318 {
318 319 if (!m_title)
319 320 return QString();
320 321 return m_title->text();
321 322 }
322 323
323 324 void ChartPresenter::setTitleFont(const QFont &font)
324 325 {
325 326 createTitleItem();
326 327 m_title->setFont(font);
327 328 m_layout->invalidate();
328 329 }
329 330
330 331 QFont ChartPresenter::titleFont() const
331 332 {
332 333 if (!m_title)
333 334 return QFont();
334 335 return m_title->font();
335 336 }
336 337
337 338 void ChartPresenter::setTitleBrush(const QBrush &brush)
338 339 {
339 340 createTitleItem();
340 341 m_title->setDefaultTextColor(brush.color());
341 342 m_layout->invalidate();
342 343 }
343 344
344 345 QBrush ChartPresenter::titleBrush() const
345 346 {
346 347 if (!m_title)
347 348 return QBrush();
348 349 return QBrush(m_title->defaultTextColor());
349 350 }
350 351
351 352 void ChartPresenter::setBackgroundVisible(bool visible)
352 353 {
353 354 createBackgroundItem();
354 355 m_background->setVisible(visible);
355 356 }
356 357
357 358
358 359 bool ChartPresenter::isBackgroundVisible() const
359 360 {
360 361 if (!m_background)
361 362 return false;
362 363 return m_background->isVisible();
363 364 }
364 365
365 366 void ChartPresenter::setPlotAreaBackgroundVisible(bool visible)
366 367 {
367 368 createPlotAreaBackgroundItem();
368 369 m_plotAreaBackground->setVisible(visible);
369 370 }
370 371
371 372 bool ChartPresenter::isPlotAreaBackgroundVisible() const
372 373 {
373 374 if (!m_plotAreaBackground)
374 375 return false;
375 376 return m_plotAreaBackground->isVisible();
376 377 }
377 378
378 379 void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled)
379 380 {
380 381 createBackgroundItem();
381 382 m_background->setDropShadowEnabled(enabled);
382 383 }
383 384
384 385 bool ChartPresenter::isBackgroundDropShadowEnabled() const
385 386 {
386 387 if (!m_background)
387 388 return false;
388 389 return m_background->isDropShadowEnabled();
389 390 }
390 391
391 392 void ChartPresenter::setLocalizeNumbers(bool localize)
392 393 {
393 394 m_localizeNumbers = localize;
394 395 m_layout->invalidate();
395 396 }
396 397
397 398 void ChartPresenter::setLocale(const QLocale &locale)
398 399 {
399 400 m_locale = locale;
400 401 m_layout->invalidate();
401 402 }
402 403
403 404 AbstractChartLayout *ChartPresenter::layout()
404 405 {
405 406 return m_layout;
406 407 }
407 408
408 409 QLegend *ChartPresenter::legend()
409 410 {
410 411 return m_chart->legend();
411 412 }
412 413
413 414 void ChartPresenter::setVisible(bool visible)
414 415 {
415 416 m_chart->setVisible(visible);
416 417 }
417 418
418 419 ChartBackground *ChartPresenter::backgroundElement()
419 420 {
420 421 return m_background;
421 422 }
422 423
423 424 QAbstractGraphicsShapeItem *ChartPresenter::plotAreaElement()
424 425 {
425 426 return m_plotAreaBackground;
426 427 }
427 428
428 429 QList<ChartAxisElement *> ChartPresenter::axisItems() const
429 430 {
430 431 return m_axisItems;
431 432 }
432 433
433 434 QList<ChartItem *> ChartPresenter::chartItems() const
434 435 {
435 436 return m_chartItems;
436 437 }
437 438
438 439 ChartTitle *ChartPresenter::titleElement()
439 440 {
440 441 return m_title;
441 442 }
442 443
443 444 QRectF ChartPresenter::textBoundingRect(const QFont &font, const QString &text, qreal angle)
444 445 {
445 446 static QGraphicsTextItem dummyTextItem;
446 447 static bool initMargin = true;
447 448 if (initMargin) {
448 449 dummyTextItem.document()->setDocumentMargin(textMargin());
449 450 initMargin = false;
450 451 }
451 452
452 453 dummyTextItem.setFont(font);
453 454 dummyTextItem.setHtml(text);
454 455 QRectF boundingRect = dummyTextItem.boundingRect();
455 456
456 457 // Take rotation into account
457 458 if (angle) {
458 459 QTransform transform;
459 460 transform.rotate(angle);
460 461 boundingRect = transform.mapRect(boundingRect);
461 462 }
462 463
463 464 return boundingRect;
464 465 }
465 466
466 467 // boundingRect parameter returns the rotated bounding rect of the text
467 468 QString ChartPresenter::truncatedText(const QFont &font, const QString &text, qreal angle,
468 469 qreal maxWidth, qreal maxHeight, QRectF &boundingRect)
469 470 {
470 471 QString truncatedString(text);
471 472 boundingRect = textBoundingRect(font, truncatedString, angle);
472 473 if (boundingRect.width() > maxWidth || boundingRect.height() > maxHeight) {
473 474 // It can be assumed that almost any amount of string manipulation is faster
474 475 // than calculating one bounding rectangle, so first prepare a list of truncated strings
475 476 // to try.
476 477 static QRegExp truncateMatcher(QStringLiteral("&#?[0-9a-zA-Z]*;$"));
477 478
478 479 QVector<QString> testStrings(text.length());
479 480 int count(0);
480 481 static QLatin1Char closeTag('>');
481 482 static QLatin1Char openTag('<');
482 483 static QLatin1Char semiColon(';');
483 484 static QLatin1String ellipsis("...");
484 485 while (truncatedString.length() > 1) {
485 486 int chopIndex(-1);
486 487 int chopCount(1);
487 488 QChar lastChar(truncatedString.at(truncatedString.length() - 1));
488 489
489 490 if (lastChar == closeTag)
490 491 chopIndex = truncatedString.lastIndexOf(openTag);
491 492 else if (lastChar == semiColon)
492 493 chopIndex = truncateMatcher.indexIn(truncatedString, 0);
493 494
494 495 if (chopIndex != -1)
495 496 chopCount = truncatedString.length() - chopIndex;
496 497 truncatedString.chop(chopCount);
497 498 testStrings[count] = truncatedString + ellipsis;
498 499 count++;
499 500 }
500 501
501 502 // Binary search for best fit
502 503 int minIndex(0);
503 504 int maxIndex(count - 1);
504 505 int bestIndex(count);
505 506 QRectF checkRect;
506 507
507 508 while (maxIndex >= minIndex) {
508 509 int mid = (maxIndex + minIndex) / 2;
509 510 checkRect = textBoundingRect(font, testStrings.at(mid), angle);
510 511 if (checkRect.width() > maxWidth || checkRect.height() > maxHeight) {
511 512 // Checked index too large, all under this are also too large
512 513 minIndex = mid + 1;
513 514 } else {
514 515 // Checked index fits, all over this also fit
515 516 maxIndex = mid - 1;
516 517 bestIndex = mid;
517 518 boundingRect = checkRect;
518 519 }
519 520 }
520 521 // Default to "..." if nothing fits
521 522 if (bestIndex == count) {
522 523 boundingRect = textBoundingRect(font, ellipsis, angle);
523 524 truncatedString = ellipsis;
524 525 } else {
525 526 truncatedString = testStrings.at(bestIndex);
526 527 }
527 528 }
528 529
529 530 return truncatedString;
530 531 }
531 532
532 533 QString ChartPresenter::numberToString(double value, char f, int prec)
533 534 {
534 535 if (m_localizeNumbers)
535 536 return m_locale.toString(value, f, prec);
536 537 else
537 538 return QString::number(value, f, prec);
538 539 }
539 540
540 541 QString ChartPresenter::numberToString(int value)
541 542 {
542 543 if (m_localizeNumbers)
543 544 return m_locale.toString(value);
544 545 else
545 546 return QString::number(value);
546 547 }
547 548
548 549 void ChartPresenter::ensureGLWidget()
549 550 {
550 551 #ifndef QT_NO_OPENGL
551 552 // GLWidget pointer is wrapped in QPointer as its parent is not in our control, and therefore
552 553 // can potentially get deleted unexpectedly.
553 554 if (m_glWidget.isNull() && m_glUseWidget && m_chart->scene()) {
554 555 // Find the view of the scene. If the scene has multiple views, only the first view is
555 556 // chosen.
556 557 QList<QGraphicsView *> views = m_chart->scene()->views();
557 558 if (views.size()) {
558 559 QGraphicsView *firstView = views.at(0);
559 560 m_glWidget = new GLWidget(m_chart->d_ptr->m_dataset->glXYSeriesDataManager(),
560 561 firstView);
561 562 m_glWidget->setGeometry(m_rect.toRect());
562 563 m_glWidget->show();
563 564 }
564 565 }
565 566 #endif
566 567 }
567 568
568 569 #include "moc_chartpresenter_p.cpp"
569 570
570 571 QT_CHARTS_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now