##// END OF EJS Templates
Fix missing legend...
Titta Heikkala -
r2602:2e0922f74ba5
parent child
Show More
@@ -1,596 +1,594
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qlegend.h"
22 22 #include "qlegend_p.h"
23 23 #include "qabstractseries.h"
24 24 #include "qabstractseries_p.h"
25 25 #include "qchart_p.h"
26 26 #include "legendlayout_p.h"
27 27 #include "chartpresenter_p.h"
28 28 #include "abstractchartlayout_p.h"
29 29 #include "qlegendmarker.h"
30 30 #include "qlegendmarker_p.h"
31 31 #include "legendmarkeritem_p.h"
32 32 #include "chartdataset_p.h"
33 33 #include <QPainter>
34 34 #include <QPen>
35 35 #include <QGraphicsItemGroup>
36 36
37 37 QTCOMMERCIALCHART_BEGIN_NAMESPACE
38 38
39 39 /*!
40 40 \class QLegend
41 41 \brief Legend object.
42 42 \mainclass
43 43
44 44 QLegend is a graphical object for displaying the legend of the chart. Legend state is updated by QChart, when
45 45 series have been changed. By default, legend is drawn by QChart, but user can set a new parent to legend and
46 46 handle the drawing manually.
47 47 User isn't supposed to create or delete legend objects, but can reference it via QChart class.
48 48
49 49 \image examples_percentbarchart_legend.png
50 50
51 51 \sa QChart
52 52 */
53 53 /*!
54 54 \qmlclass Legend QLegend
55 55 \brief Legend is part of Qt Chart QML API.
56 56
57 57 Legend is a graphical object, whics displays legend of the chart. Legend state is updated by ChartView, when
58 58 series have been changed. Legend is used via ChartView class. For example:
59 59 \code
60 60 ChartView {
61 61 legend.visible: true
62 62 legend.alignment: Qt.AlignBottom
63 63 // Add a few series...
64 64 }
65 65 \endcode
66 66
67 67 \image examples_percentbarchart_legend.png
68 68
69 69 Please note that there is no QML API available for modifying legend markers, unlike in the Qt API of Charts.
70 70 The use case of modifying markers can be implemented for example by creating your own custom legend. For an example
71 71 on how to do this, see \l {demos/qmlcustomlegend}{Qml Custom Demo} application.
72 72 */
73 73
74 74 /*!
75 75 \property QLegend::alignment
76 76 \brief The alignment of the legend.
77 77
78 78 Legend paints on the defined position in the chart. The following alignments are supported:
79 79 Qt::AlignTop, Qt::AlignBottom, Qt::AlignLeft, Qt::AlignRight. If you set more than one flag the result is undefined.
80 80 */
81 81 /*!
82 82 \qmlproperty Qt.Alignment Legend::alignment
83 83 \brief The alignment of the legend.
84 84
85 85 Legend paints on the defined position in the chart. The following alignments are supported:
86 86 Qt.AlignTop, Qt.AlignBottom, Qt.AlignLeft, Qt.AlignRight. If you set more than one flag the result is undefined.
87 87 */
88 88
89 89 /*!
90 90 \property QLegend::backgroundVisible
91 91 Whether the legend background is visible or not.
92 92 */
93 93 /*!
94 94 \qmlproperty bool Legend::backgroundVisible
95 95 Whether the legend background is visible or not.
96 96 */
97 97
98 98 /*!
99 99 \property QLegend::color
100 100 The color of the legend, i.e. the background (brush) color. Note that if you change the color
101 101 of the legend, the style of the legend brush is set to Qt::SolidPattern.
102 102 */
103 103 /*!
104 104 \qmlproperty color Legend::color
105 105 The color of the legend, i.e. the background (brush) color.
106 106 */
107 107
108 108 /*!
109 109 \property QLegend::borderColor
110 110 The border color of the legend, i.e. the line color.
111 111 */
112 112 /*!
113 113 \qmlproperty color Legend::borderColor
114 114 The border color of the legend, i.e. the line color.
115 115 */
116 116
117 117 /*!
118 118 \property QLegend::font
119 119 The font of markers used by legend
120 120 */
121 121 /*!
122 122 \qmlproperty Font Legend::font
123 123 The font of markers used by legend
124 124 */
125 125
126 126 /*!
127 127 \property QLegend::labelColor
128 128 The color of brush used to draw labels.
129 129 */
130 130 /*!
131 131 \qmlproperty color QLegend::labelColor
132 132 The color of brush used to draw labels.
133 133 */
134 134
135 135 /*!
136 136 \fn void QLegend::backgroundVisibleChanged(bool)
137 137 The visibility of the legend background changed to \a visible.
138 138 */
139 139
140 140 /*!
141 141 \fn void QLegend::colorChanged(QColor)
142 142 The color of the legend background changed to \a color.
143 143 */
144 144
145 145 /*!
146 146 \fn void QLegend::borderColorChanged(QColor)
147 147 The border color of the legend background changed to \a color.
148 148 */
149 149
150 150 /*!
151 151 \fn void QLegend::fontChanged(QFont)
152 152 The font of markers of the legend changed to \a font.
153 153 */
154 154
155 155 /*!
156 156 \fn void QLegend::labelColorChanged(QColor color)
157 157 This signal is emitted when the color of brush used to draw labels has changed to \a color.
158 158 */
159 159
160 160 QLegend::QLegend(QChart *chart): QGraphicsWidget(chart),
161 161 d_ptr(new QLegendPrivate(chart->d_ptr->m_presenter, chart, this))
162 162 {
163 163 setZValue(ChartPresenter::LegendZValue);
164 164 setFlags(QGraphicsItem::ItemClipsChildrenToShape);
165 165 QObject::connect(chart->d_ptr->m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), d_ptr.data(), SLOT(handleSeriesAdded(QAbstractSeries*)));
166 166 QObject::connect(chart->d_ptr->m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)), d_ptr.data(), SLOT(handleSeriesRemoved(QAbstractSeries*)));
167 167 setLayout(d_ptr->m_layout);
168 168 }
169 169
170 170 /*!
171 171 Destroys the legend object. Legend is always owned by a QChart, so an application should never call this.
172 172 */
173 173 QLegend::~QLegend()
174 174 {
175 175 }
176 176
177 177 /*!
178 178 \internal
179 179 */
180 180 void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
181 181 {
182 182 Q_UNUSED(option)
183 183 Q_UNUSED(widget)
184 184
185 185 if (!d_ptr->m_backgroundVisible)
186 186 return;
187 187
188 188 painter->setOpacity(opacity());
189 189 painter->setPen(d_ptr->m_pen);
190 190 painter->setBrush(d_ptr->m_brush);
191 191 painter->drawRoundRect(rect(), d_ptr->roundness(rect().width()), d_ptr->roundness(rect().height()));
192 192 }
193 193
194 194
195 195 /*!
196 196 Sets the \a brush of legend. Brush affects the background of legend.
197 197 */
198 198 void QLegend::setBrush(const QBrush &brush)
199 199 {
200 200 if (d_ptr->m_brush != brush) {
201 201 d_ptr->m_brush = brush;
202 202 update();
203 203 emit colorChanged(brush.color());
204 204 }
205 205 }
206 206
207 207 /*!
208 208 Returns the brush used by legend.
209 209 */
210 210 QBrush QLegend::brush() const
211 211 {
212 212 return d_ptr->m_brush;
213 213 }
214 214
215 215 void QLegend::setColor(QColor color)
216 216 {
217 217 QBrush b = d_ptr->m_brush;
218 218 if (b.style() != Qt::SolidPattern || b.color() != color) {
219 219 b.setStyle(Qt::SolidPattern);
220 220 b.setColor(color);
221 221 setBrush(b);
222 222 }
223 223 }
224 224
225 225 QColor QLegend::color()
226 226 {
227 227 return d_ptr->m_brush.color();
228 228 }
229 229
230 230 /*!
231 231 Sets the \a pen of legend. Pen affects the legend borders.
232 232 */
233 233 void QLegend::setPen(const QPen &pen)
234 234 {
235 235 if (d_ptr->m_pen != pen) {
236 236 d_ptr->m_pen = pen;
237 237 update();
238 238 emit borderColorChanged(pen.color());
239 239 }
240 240 }
241 241
242 242 /*!
243 243 Returns the pen used by legend
244 244 */
245 245
246 246 QPen QLegend::pen() const
247 247 {
248 248 return d_ptr->m_pen;
249 249 }
250 250
251 251 void QLegend::setFont(const QFont &font)
252 252 {
253 253 if (d_ptr->m_font != font) {
254 254 d_ptr->m_font = font;
255 255 foreach (QLegendMarker *marker, d_ptr->markers()) {
256 256 marker->setFont(d_ptr->m_font);
257 257 }
258 258 layout()->invalidate();
259 259 emit fontChanged(font);
260 260 }
261 261 }
262 262
263 263 QFont QLegend::font() const
264 264 {
265 265 return d_ptr->m_font;
266 266 }
267 267
268 268 void QLegend::setBorderColor(QColor color)
269 269 {
270 270 QPen p = d_ptr->m_pen;
271 271 if (p.color() != color) {
272 272 p.setColor(color);
273 273 setPen(p);
274 274 }
275 275 }
276 276
277 277 QColor QLegend::borderColor()
278 278 {
279 279 return d_ptr->m_pen.color();
280 280 }
281 281
282 282 /*!
283 283 Set brush used to draw labels to \a brush.
284 284 */
285 285 void QLegend::setLabelBrush(const QBrush &brush)
286 286 {
287 287 if (d_ptr->m_labelBrush != brush) {
288 288 d_ptr->m_labelBrush = brush;
289 289 foreach (QLegendMarker *marker, d_ptr->markers()) {
290 290 marker->setLabelBrush(d_ptr->m_labelBrush);
291 291 // Note: The pen of the marker rectangle could be exposed in the public QLegend API
292 292 // instead of mapping it from label brush color
293 293 marker->setPen(brush.color());
294 294 }
295 295 emit labelColorChanged(brush.color());
296 296 }
297 297 }
298 298
299 299 /*!
300 300 Brush used to draw labels.
301 301 */
302 302 QBrush QLegend::labelBrush() const
303 303 {
304 304 return d_ptr->m_labelBrush;
305 305 }
306 306
307 307 void QLegend::setLabelColor(QColor color)
308 308 {
309 309 QBrush b = d_ptr->m_labelBrush;
310 310 if (b.style() != Qt::SolidPattern || b.color() != color) {
311 311 b.setStyle(Qt::SolidPattern);
312 312 b.setColor(color);
313 313 setLabelBrush(b);
314 314 }
315 315 }
316 316
317 317 QColor QLegend::labelColor() const
318 318 {
319 319 return d_ptr->m_labelBrush.color();
320 320 }
321 321
322 322
323 323 void QLegend::setAlignment(Qt::Alignment alignment)
324 324 {
325 325 if (d_ptr->m_alignment != alignment) {
326 326 d_ptr->m_alignment = alignment;
327 327 layout()->invalidate();
328 328 }
329 329 }
330 330
331 331 Qt::Alignment QLegend::alignment() const
332 332 {
333 333 return d_ptr->m_alignment;
334 334 }
335 335
336 336 /*!
337 337 Detaches the legend from chart. Chart won't change layout of the legend.
338 338 */
339 339 void QLegend::detachFromChart()
340 340 {
341 341 d_ptr->m_attachedToChart = false;
342 342 // layout()->invalidate();
343 343 d_ptr->m_chart->layout()->invalidate();
344 344 setParent(0);
345 345
346 346 }
347 347
348 348 /*!
349 349 Attaches the legend to chart. Chart may change layout of the legend.
350 350 */
351 351 void QLegend::attachToChart()
352 352 {
353 353 d_ptr->m_attachedToChart = true;
354 354 // layout()->invalidate();
355 355 d_ptr->m_chart->layout()->invalidate();
356 356 setParent(d_ptr->m_chart);
357 357 }
358 358
359 359 /*!
360 360 Returns true, if legend is attached to chart.
361 361 */
362 362 bool QLegend::isAttachedToChart()
363 363 {
364 364 return d_ptr->m_attachedToChart;
365 365 }
366 366
367 367 /*!
368 368 Sets the visibility of legend background to \a visible
369 369 */
370 370 void QLegend::setBackgroundVisible(bool visible)
371 371 {
372 372 if (d_ptr->m_backgroundVisible != visible) {
373 373 d_ptr->m_backgroundVisible = visible;
374 374 update();
375 375 emit backgroundVisibleChanged(visible);
376 376 }
377 377 }
378 378
379 379 /*!
380 380 Returns the visibility of legend background
381 381 */
382 382 bool QLegend::isBackgroundVisible() const
383 383 {
384 384 return d_ptr->m_backgroundVisible;
385 385 }
386 386
387 387 /*!
388 388 Returns the list of markers in legend. The list can be filtered with \a series parameter.
389 389 If \a series is given, only markers related to that series are returned.
390 390 */
391 391 QList<QLegendMarker*> QLegend::markers(QAbstractSeries *series) const
392 392 {
393 393 return d_ptr->markers(series);
394 394 }
395 395
396 396 /*!
397 397 \internal \a event see QGraphicsWidget for details
398 398 */
399 399 void QLegend::hideEvent(QHideEvent *event)
400 400 {
401 401 if (isAttachedToChart())
402 402 d_ptr->m_presenter->layout()->invalidate();
403 403 QGraphicsWidget::hideEvent(event);
404 404 }
405 405 /*!
406 406 \internal \a event see QGraphicsWidget for details
407 407 */
408 408 void QLegend::showEvent(QShowEvent *event)
409 409 {
410 if (isAttachedToChart()) {
411 d_ptr->items()->setVisible(false);
410 if (isAttachedToChart())
412 411 layout()->invalidate();
413 }
414 412 QGraphicsWidget::showEvent(event);
415 413 //layout activation will show the items
416 414 }
417 415
418 416 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
419 417
420 418 QLegendPrivate::QLegendPrivate(ChartPresenter *presenter, QChart *chart, QLegend *q)
421 419 : q_ptr(q),
422 420 m_presenter(presenter),
423 421 m_layout(new LegendLayout(q)),
424 422 m_chart(chart),
425 423 m_items(new QGraphicsItemGroup(q)),
426 424 m_alignment(Qt::AlignTop),
427 425 m_brush(QBrush()),
428 426 m_pen(QPen()),
429 427 m_labelBrush(QBrush()),
430 428 m_diameter(5),
431 429 m_attachedToChart(true),
432 430 m_backgroundVisible(false)
433 431 {
434 432 m_items->setHandlesChildEvents(false);
435 433 }
436 434
437 435 QLegendPrivate::~QLegendPrivate()
438 436 {
439 437
440 438 }
441 439
442 440 void QLegendPrivate::setOffset(const QPointF &offset)
443 441 {
444 442 m_layout->setOffset(offset.x(), offset.y());
445 443 }
446 444
447 445 QPointF QLegendPrivate::offset() const
448 446 {
449 447 return m_layout->offset();
450 448 }
451 449
452 450 int QLegendPrivate::roundness(qreal size)
453 451 {
454 452 return 100 * m_diameter / int(size);
455 453 }
456 454
457 455 QList<QLegendMarker*> QLegendPrivate::markers(QAbstractSeries *series)
458 456 {
459 457 // Return all markers
460 458 if (!series) {
461 459 return m_markers;
462 460 }
463 461
464 462 // Create filtered list
465 463 QList<QLegendMarker *> markers;
466 464 foreach (QLegendMarker *marker, m_markers) {
467 465 if (marker->series() == series) {
468 466 markers.append(marker);
469 467 }
470 468 }
471 469 return markers;
472 470 }
473 471
474 472 void QLegendPrivate::handleSeriesAdded(QAbstractSeries *series)
475 473 {
476 474 if (m_series.contains(series)) {
477 475 return;
478 476 }
479 477
480 478 QList<QLegendMarker*> newMarkers = series->d_ptr->createLegendMarkers(q_ptr);
481 479 decorateMarkers(newMarkers);
482 480 addMarkers(newMarkers);
483 481
484 482 QObject::connect(series->d_ptr.data(), SIGNAL(countChanged()), this, SLOT(handleCountChanged()));
485 483 QObject::connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
486 484
487 485 m_series.append(series);
488 486 m_items->setVisible(false);
489 487 m_layout->invalidate();
490 488 }
491 489
492 490 void QLegendPrivate::handleSeriesRemoved(QAbstractSeries *series)
493 491 {
494 492 if (m_series.contains(series)) {
495 493 m_series.removeOne(series);
496 494 }
497 495
498 496 // Find out, which markers to remove
499 497 QList<QLegendMarker *> removed;
500 498 foreach (QLegendMarker *m, m_markers) {
501 499 if (m->series() == series) {
502 500 removed << m;
503 501 }
504 502 }
505 503 removeMarkers(removed);
506 504
507 505 QObject::disconnect(series->d_ptr.data(), SIGNAL(countChanged()), this, SLOT(handleCountChanged()));
508 506 QObject::disconnect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
509 507
510 508 m_layout->invalidate();
511 509 }
512 510
513 511 void QLegendPrivate::handleSeriesVisibleChanged()
514 512 {
515 513 QAbstractSeries *series = qobject_cast<QAbstractSeries *> (sender());
516 514 Q_ASSERT(series);
517 515
518 516 foreach (QLegendMarker *marker, m_markers) {
519 517 if (marker->series() == series) {
520 518 marker->setVisible(series->isVisible());
521 519 }
522 520 }
523 521 m_layout->invalidate();
524 522 }
525 523
526 524 void QLegendPrivate::handleCountChanged()
527 525 {
528 526 // Here we handle the changes in marker count.
529 527 // Can happen for example when pieslice(s) have been added to or removed from pieseries.
530 528
531 529 QAbstractSeriesPrivate *series = qobject_cast<QAbstractSeriesPrivate *> (sender());
532 530 QList<QLegendMarker *> createdMarkers = series->createLegendMarkers(q_ptr);
533 531
534 532 // Find out removed markers and created markers
535 533 QList<QLegendMarker *> removedMarkers;
536 534 foreach (QLegendMarker *oldMarker, m_markers) {
537 535 // we have marker, which is related to sender.
538 536 if (oldMarker->series() == series->q_ptr) {
539 537 bool found = false;
540 538 foreach(QLegendMarker *newMarker, createdMarkers) {
541 539 // New marker considered existing if:
542 540 // - d_ptr->relatedObject() is same for both markers.
543 541 if (newMarker->d_ptr->relatedObject() == oldMarker->d_ptr->relatedObject()) {
544 542 // Delete the new marker, since we already have existing marker, that might be connected on user side.
545 543 found = true;
546 544 createdMarkers.removeOne(newMarker);
547 545 delete newMarker;
548 546 }
549 547 }
550 548 if (!found) {
551 549 // No related object found for marker, add to removedMarkers list
552 550 removedMarkers << oldMarker;
553 551 }
554 552 }
555 553 }
556 554
557 555 removeMarkers(removedMarkers);
558 556 decorateMarkers(createdMarkers);
559 557 addMarkers(createdMarkers);
560 558
561 559 q_ptr->layout()->invalidate();
562 560 }
563 561
564 562 void QLegendPrivate::addMarkers(QList<QLegendMarker *> markers)
565 563 {
566 564 foreach (QLegendMarker *marker, markers) {
567 565 m_items->addToGroup(marker->d_ptr.data()->item());
568 566 m_markers << marker;
569 567 m_markerHash.insert(marker->d_ptr->item(), marker);
570 568 }
571 569 }
572 570
573 571 void QLegendPrivate::removeMarkers(QList<QLegendMarker *> markers)
574 572 {
575 573 foreach (QLegendMarker *marker, markers) {
576 574 marker->d_ptr->item()->setVisible(false);
577 575 m_items->removeFromGroup(marker->d_ptr->item());
578 576 m_markers.removeOne(marker);
579 577 m_markerHash.remove(marker->d_ptr->item());
580 578 delete marker;
581 579 }
582 580 }
583 581
584 582 void QLegendPrivate::decorateMarkers(QList<QLegendMarker *> markers)
585 583 {
586 584 foreach (QLegendMarker *marker, markers) {
587 585 marker->setFont(m_font);
588 586 marker->setLabelBrush(m_labelBrush);
589 587 }
590 588 }
591 589
592 590
593 591 #include "moc_qlegend.cpp"
594 592 #include "moc_qlegend_p.cpp"
595 593
596 594 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now