1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Charts module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 or (at your option) any later version |
20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by |
21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include <QtCharts/QBoxPlotSeries> |
31 | #include <private/qboxplotseries_p.h> |
32 | #include <QtCharts/QBoxPlotLegendMarker> |
33 | #include <QtCharts/QBarCategoryAxis> |
34 | #include <private/boxplotchartitem_p.h> |
35 | #include <private/chartdataset_p.h> |
36 | #include <private/charttheme_p.h> |
37 | #include <QtCharts/QValueAxis> |
38 | #include <private/charttheme_p.h> |
39 | #include <private/boxplotanimation_p.h> |
40 | #include <private/qchart_p.h> |
41 | #include <QtCharts/QBoxSet> |
42 | #include <private/qboxset_p.h> |
43 | |
44 | QT_CHARTS_BEGIN_NAMESPACE |
45 | |
46 | /*! |
47 | \class QBoxPlotSeries |
48 | \inmodule QtCharts |
49 | \brief The QBoxPlotSeries class presents data in box-and-whiskers charts. |
50 | |
51 | A box plot series acts as a container for box-and-whiskers items. Items from multiple series |
52 | are grouped into categories according to their index value. |
53 | |
54 | The QBarCategoryAxis class is used to add the categories to the chart's axis. Category labels |
55 | have to be unique. If the same category label is defined for several box-and-whiskers items, |
56 | only the first one is drawn. |
57 | |
58 | See the \l {Box and Whiskers Example} {box-and-whiskers chart example} to learn how to create a |
59 | box-and-whiskers chart. |
60 | \image examples_boxplotchart.png |
61 | |
62 | \sa QBoxSet, QBarCategoryAxis |
63 | */ |
64 | /*! |
65 | \fn QBoxPlotSeries::boxsetsAdded(QList<QBoxSet *> sets) |
66 | This signal is emitted when the list of box-and-whiskers items specified by \a sets |
67 | is added to the series. |
68 | */ |
69 | /*! |
70 | \fn QBoxPlotSeries::boxsetsRemoved(QList<QBoxSet *> sets) |
71 | This signal is emitted when the list of box-and-whiskers items specified by \a sets |
72 | is removed from the series. |
73 | */ |
74 | /*! |
75 | \fn QBoxPlotSeries::clicked(QBoxSet *boxset) |
76 | This signal is emitted when the user clicks the box-and-whiskers item specified by |
77 | \a boxset in the chart. |
78 | */ |
79 | /*! |
80 | \fn QBoxPlotSeries::pressed(QBoxSet *boxset) |
81 | This signal is emitted when the user clicks the box-and-whiskers item specified by |
82 | \a boxset in the chart and holds down the mouse button. |
83 | */ |
84 | /*! |
85 | \fn QBoxPlotSeries::released(QBoxSet *boxset) |
86 | This signal is emitted when the user releases the mouse press on the box-and-whiskers |
87 | item specified by \a boxset in the chart. |
88 | */ |
89 | /*! |
90 | \fn QBoxPlotSeries::doubleClicked(QBoxSet *boxset) |
91 | This signal is emitted when the user double-clicks the box-and-whiskers item specified by |
92 | \a boxset in the chart. |
93 | */ |
94 | /*! |
95 | \fn QBoxPlotSeries::hovered(bool status, QBoxSet *boxset) |
96 | This signal is emitted when a mouse is hovered over the box-and-whiskers item specified by |
97 | \a boxset in the chart. When the mouse moves over the item, \a status turns \c true, and |
98 | when the mouse moves away again, it turns \c false. |
99 | */ |
100 | /*! |
101 | \fn QBoxPlotSeries::countChanged() |
102 | This signal is emitted when the number of box-and-whiskers items in the series changes. |
103 | */ |
104 | /*! |
105 | \property QBoxPlotSeries::boxOutlineVisible |
106 | \brief The visibility of the box outline. |
107 | */ |
108 | /*! |
109 | \property QBoxPlotSeries::boxWidth |
110 | \brief The width of the box-and-whiskers item. The value indicates the relative |
111 | width of the item within its category. The value can be between 0.0 and 1.0. Negative values |
112 | are replaced with 0.0 and values greater than 1.0 are replaced with 1.0. |
113 | */ |
114 | /*! |
115 | \property QBoxPlotSeries::pen |
116 | \brief The pen used to draw the lines of the box-and-whiskers items. |
117 | */ |
118 | /*! |
119 | \property QBoxPlotSeries::brush |
120 | \brief The brush used to fill the boxes of the box-and-whiskers items. |
121 | */ |
122 | /*! |
123 | \property QBoxPlotSeries::count |
124 | \brief The number of box-and-whiskers items in a box plot series. |
125 | */ |
126 | |
127 | /*! |
128 | \fn void QBoxPlotSeries::boxOutlineVisibilityChanged() |
129 | This signal is emitted when the box outline visibility changes. |
130 | */ |
131 | |
132 | /*! |
133 | \fn void QBoxPlotSeries::boxWidthChanged() |
134 | This signal is emitted when the width of the box-and-whiskers item changes. |
135 | */ |
136 | /*! |
137 | \fn void QBoxPlotSeries::penChanged() |
138 | This signal is emitted when the pen used to draw the lines of the box-and-whiskers |
139 | items changes. |
140 | */ |
141 | /*! |
142 | \fn void QBoxPlotSeries::brushChanged() |
143 | This signal is emitted when the brush used to fill the boxes of the box-and-whiskers |
144 | items changes. |
145 | */ |
146 | /*! |
147 | \fn virtual SeriesType QBoxPlotSeries::type() const |
148 | Returns the type of the series. |
149 | \sa QAbstractSeries, SeriesType |
150 | */ |
151 | |
152 | /*! |
153 | Constructs an empty box plot series that is a QObject and a child of \a parent. |
154 | */ |
155 | QBoxPlotSeries::QBoxPlotSeries(QObject *parent) |
156 | : QAbstractSeries(*new QBoxPlotSeriesPrivate(this), parent) |
157 | { |
158 | } |
159 | |
160 | /*! |
161 | Removes the series from the chart. |
162 | */ |
163 | QBoxPlotSeries::~QBoxPlotSeries() |
164 | { |
165 | Q_D(QBoxPlotSeries); |
166 | if (d->m_chart) |
167 | d->m_chart->removeSeries(series: this); |
168 | } |
169 | |
170 | /*! |
171 | Adds a single box-and-whiskers item specified by \a set to the series and takes ownership of |
172 | it. If the item is null or it already belongs to the series, it will not be appended. |
173 | Returns \c true if appending succeeded. |
174 | */ |
175 | bool QBoxPlotSeries::append(QBoxSet *set) |
176 | { |
177 | Q_D(QBoxPlotSeries); |
178 | |
179 | bool success = d->append(set); |
180 | if (success) { |
181 | QList<QBoxSet *> sets; |
182 | sets.append(t: set); |
183 | set->setParent(this); |
184 | emit boxsetsAdded(sets); |
185 | emit countChanged(); |
186 | } |
187 | return success; |
188 | } |
189 | |
190 | /*! |
191 | Removes the box-and-whiskers item specified by \a set from the series and permanently |
192 | deletes it if the removal succeeds. Returns \c true if the item was removed. |
193 | */ |
194 | bool QBoxPlotSeries::remove(QBoxSet *set) |
195 | { |
196 | Q_D(QBoxPlotSeries); |
197 | bool success = d->remove(set); |
198 | if (success) { |
199 | QList<QBoxSet *> sets; |
200 | sets.append(t: set); |
201 | set->setParent(0); |
202 | emit boxsetsRemoved(sets); |
203 | emit countChanged(); |
204 | delete set; |
205 | set = 0; |
206 | } |
207 | return success; |
208 | } |
209 | |
210 | /*! |
211 | Takes the box-and-whiskers item specified by \a set from the series. Does not delete the |
212 | item. |
213 | |
214 | \note The series remains the item's parent object. You must set the parent object to take |
215 | full ownership. |
216 | |
217 | Returns \c true if the take operation succeeds. |
218 | |
219 | */ |
220 | bool QBoxPlotSeries::take(QBoxSet *set) |
221 | { |
222 | Q_D(QBoxPlotSeries); |
223 | |
224 | bool success = d->remove(set); |
225 | if (success) { |
226 | QList<QBoxSet *> sets; |
227 | sets.append(t: set); |
228 | emit boxsetsRemoved(sets); |
229 | emit countChanged(); |
230 | } |
231 | return success; |
232 | } |
233 | |
234 | /*! |
235 | Adds a list of box-and-whiskers items specified by \a sets to the series and takes ownership of |
236 | them. If the list is null or the items already belong to the series, it will not be appended. |
237 | Returns \c true if appending succeeded. |
238 | */ |
239 | bool QBoxPlotSeries::append(QList<QBoxSet *> sets) |
240 | { |
241 | Q_D(QBoxPlotSeries); |
242 | bool success = d->append(sets); |
243 | if (success) { |
244 | emit boxsetsAdded(sets); |
245 | emit countChanged(); |
246 | } |
247 | return success; |
248 | } |
249 | |
250 | /*! |
251 | Inserts a box-and-whiskers item specified by \a set to a series at the position specified by |
252 | \a index and takes ownership of the item. If the item is null or already belongs to the series, |
253 | it will not be appended. Returns \c true if inserting succeeds. |
254 | */ |
255 | bool QBoxPlotSeries::insert(int index, QBoxSet *set) |
256 | { |
257 | Q_D(QBoxPlotSeries); |
258 | bool success = d->insert(index, set); |
259 | if (success) { |
260 | QList<QBoxSet *> sets; |
261 | sets.append(t: set); |
262 | emit boxsetsAdded(sets); |
263 | emit countChanged(); |
264 | } |
265 | return success; |
266 | } |
267 | |
268 | /*! |
269 | Removes all box-and-whiskers items from the series and permanently deletes them. |
270 | */ |
271 | void QBoxPlotSeries::clear() |
272 | { |
273 | Q_D(QBoxPlotSeries); |
274 | QList<QBoxSet *> sets = boxSets(); |
275 | bool success = d->remove(sets); |
276 | if (success) { |
277 | emit boxsetsRemoved(sets); |
278 | emit countChanged(); |
279 | foreach (QBoxSet *set, sets) |
280 | delete set; |
281 | } |
282 | } |
283 | |
284 | /*! |
285 | Returns the number of box-and-whiskers items in a box plot series. |
286 | */ |
287 | int QBoxPlotSeries::count() const |
288 | { |
289 | Q_D(const QBoxPlotSeries); |
290 | return d->m_boxSets.count(); |
291 | } |
292 | |
293 | /*! |
294 | Returns a list of box-and-whiskers items in a box plot series. Keeps the ownership of the items. |
295 | */ |
296 | QList<QBoxSet *> QBoxPlotSeries::boxSets() const |
297 | { |
298 | Q_D(const QBoxPlotSeries); |
299 | return d->m_boxSets; |
300 | } |
301 | |
302 | /* |
303 | Returns QAbstractSeries::SeriesTypeBoxPlot. |
304 | */ |
305 | QAbstractSeries::SeriesType QBoxPlotSeries::type() const |
306 | { |
307 | return QAbstractSeries::SeriesTypeBoxPlot; |
308 | } |
309 | |
310 | void QBoxPlotSeries::setBoxOutlineVisible(bool visible) |
311 | { |
312 | Q_D(QBoxPlotSeries); |
313 | |
314 | if (d->m_boxOutlineVisible != visible) { |
315 | d->m_boxOutlineVisible = visible; |
316 | emit d->updated(); |
317 | emit boxOutlineVisibilityChanged(); |
318 | } |
319 | } |
320 | |
321 | bool QBoxPlotSeries::boxOutlineVisible() |
322 | { |
323 | Q_D(QBoxPlotSeries); |
324 | |
325 | return d->m_boxOutlineVisible; |
326 | } |
327 | |
328 | void QBoxPlotSeries::setBoxWidth(qreal width) |
329 | { |
330 | Q_D(QBoxPlotSeries); |
331 | |
332 | if (width != d->m_boxWidth) { |
333 | if (width < 0.0) |
334 | width = 0.0; |
335 | if (width > 1.0) |
336 | width = 1.0; |
337 | d->m_boxWidth = width; |
338 | emit d->updatedLayout(); |
339 | emit boxWidthChanged(); |
340 | } |
341 | } |
342 | |
343 | qreal QBoxPlotSeries::boxWidth() |
344 | { |
345 | Q_D(QBoxPlotSeries); |
346 | |
347 | return d->m_boxWidth; |
348 | } |
349 | |
350 | void QBoxPlotSeries::setBrush(const QBrush &brush) |
351 | { |
352 | Q_D(QBoxPlotSeries); |
353 | |
354 | if (d->m_brush != brush) { |
355 | d->m_brush = brush; |
356 | emit d->updated(); |
357 | emit brushChanged(); |
358 | } |
359 | } |
360 | |
361 | QBrush QBoxPlotSeries::brush() const |
362 | { |
363 | Q_D(const QBoxPlotSeries); |
364 | |
365 | return d->m_brush; |
366 | } |
367 | |
368 | void QBoxPlotSeries::setPen(const QPen &pen) |
369 | { |
370 | Q_D(QBoxPlotSeries); |
371 | |
372 | if (d->m_pen != pen) { |
373 | d->m_pen = pen; |
374 | emit d->updated(); |
375 | emit penChanged(); |
376 | } |
377 | } |
378 | |
379 | QPen QBoxPlotSeries::pen() const |
380 | { |
381 | Q_D(const QBoxPlotSeries); |
382 | |
383 | return d->m_pen; |
384 | } |
385 | |
386 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
387 | |
388 | QBoxPlotSeriesPrivate::QBoxPlotSeriesPrivate(QBoxPlotSeries *q) |
389 | : QAbstractSeriesPrivate(q), |
390 | m_pen(QChartPrivate::defaultPen()), |
391 | m_brush(QChartPrivate::defaultBrush()), |
392 | m_boxOutlineVisible(true), |
393 | m_boxWidth(0.5) |
394 | { |
395 | } |
396 | |
397 | QBoxPlotSeriesPrivate::~QBoxPlotSeriesPrivate() |
398 | { |
399 | disconnect(sender: this, signal: 0, receiver: 0, member: 0); |
400 | } |
401 | |
402 | void QBoxPlotSeriesPrivate::initializeDomain() |
403 | { |
404 | qreal minX(domain()->minX()); |
405 | qreal minY(domain()->minY()); |
406 | qreal maxX(domain()->maxX()); |
407 | qreal maxY(domain()->maxY()); |
408 | |
409 | qreal x = m_boxSets.count(); |
410 | minX = qMin(a: minX, b: qreal(-0.5)); |
411 | minY = qMin(a: minY, b: min()); |
412 | maxX = qMax(a: maxX, b: x - qreal(0.5)); |
413 | maxY = qMax(a: maxY, b: max()); |
414 | |
415 | domain()->setRange(minX, maxX, minY, maxY); |
416 | } |
417 | |
418 | void QBoxPlotSeriesPrivate::initializeAxes() |
419 | { |
420 | foreach (QAbstractAxis* axis, m_axes) { |
421 | if (axis->type() == QAbstractAxis::AxisTypeBarCategory) { |
422 | if (axis->orientation() == Qt::Horizontal) |
423 | populateCategories(axis: qobject_cast<QBarCategoryAxis *>(object: axis)); |
424 | } |
425 | } |
426 | } |
427 | |
428 | QAbstractAxis::AxisType QBoxPlotSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const |
429 | { |
430 | if (orientation == Qt::Horizontal) |
431 | return QAbstractAxis::AxisTypeBarCategory; |
432 | |
433 | return QAbstractAxis::AxisTypeValue; |
434 | } |
435 | |
436 | QAbstractAxis* QBoxPlotSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const |
437 | { |
438 | if (defaultAxisType(orientation) == QAbstractAxis::AxisTypeBarCategory) |
439 | return new QBarCategoryAxis; |
440 | else |
441 | return new QValueAxis; |
442 | } |
443 | |
444 | void QBoxPlotSeriesPrivate::populateCategories(QBarCategoryAxis *axis) |
445 | { |
446 | QStringList categories; |
447 | if (axis->categories().isEmpty()) { |
448 | for (int i(1); i < m_boxSets.count() + 1; i++) { |
449 | QBoxSet *set = m_boxSets.at(i: i - 1); |
450 | if (set->label().isEmpty()) |
451 | categories << presenter()->numberToString(value: i); |
452 | else |
453 | categories << set->label(); |
454 | } |
455 | axis->append(categories); |
456 | } |
457 | } |
458 | |
459 | void QBoxPlotSeriesPrivate::initializeGraphics(QGraphicsItem *parent) |
460 | { |
461 | Q_Q(QBoxPlotSeries); |
462 | |
463 | BoxPlotChartItem *boxPlot = new BoxPlotChartItem(q, parent); |
464 | m_item.reset(other: boxPlot); |
465 | QAbstractSeriesPrivate::initializeGraphics(parent); |
466 | |
467 | if (m_chart) { |
468 | connect(sender: m_chart->d_ptr->m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), receiver: this, SLOT(handleSeriesChange(QAbstractSeries*)) ); |
469 | connect(sender: m_chart->d_ptr->m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)), receiver: this, SLOT(handleSeriesRemove(QAbstractSeries*)) ); |
470 | |
471 | QList<QAbstractSeries *> serieses = m_chart->series(); |
472 | |
473 | // Tries to find this series from the Chart's list of series and deduce the index |
474 | int index = 0; |
475 | foreach (QAbstractSeries *s, serieses) { |
476 | if (s->type() == QAbstractSeries::SeriesTypeBoxPlot) { |
477 | if (q == static_cast<QBoxPlotSeries *>(s)) { |
478 | boxPlot->m_seriesIndex = index; |
479 | m_index = index; |
480 | } |
481 | index++; |
482 | } |
483 | } |
484 | boxPlot->m_seriesCount = index; |
485 | } |
486 | |
487 | // Make BoxPlotChartItem to instantiate box & whisker items |
488 | boxPlot->handleDataStructureChanged(); |
489 | } |
490 | |
491 | void QBoxPlotSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced) |
492 | { |
493 | Q_Q(QBoxPlotSeries); |
494 | |
495 | const QList<QGradient> gradients = theme->seriesGradients(); |
496 | |
497 | if (forced || QChartPrivate::defaultBrush() == m_brush) { |
498 | QColor brushColor = ChartThemeManager::colorAt(gradient: gradients.at(i: index % gradients.size()), pos: 0.5); |
499 | q->setBrush(brushColor); |
500 | } |
501 | |
502 | if (forced || QChartPrivate::defaultPen() == m_pen) { |
503 | QPen pen = theme->outlinePen(); |
504 | pen.setCosmetic(true); |
505 | q->setPen(pen); |
506 | } |
507 | } |
508 | |
509 | void QBoxPlotSeriesPrivate::initializeAnimations(QChart::AnimationOptions options, int duration, |
510 | QEasingCurve &curve) |
511 | { |
512 | BoxPlotChartItem *item = static_cast<BoxPlotChartItem *>(m_item.data()); |
513 | Q_ASSERT(item); |
514 | if (item->animation()) |
515 | item->animation()->stopAndDestroyLater(); |
516 | |
517 | if (options.testFlag(flag: QChart::SeriesAnimations)) |
518 | m_animation = new BoxPlotAnimation(item, duration, curve); |
519 | else |
520 | m_animation = 0; |
521 | item->setAnimation(m_animation); |
522 | |
523 | QAbstractSeriesPrivate::initializeAnimations(options, duration, curve); |
524 | |
525 | // Make BoxPlotChartItem to instantiate box & whisker items |
526 | item->handleDataStructureChanged(); |
527 | } |
528 | |
529 | QList<QLegendMarker*> QBoxPlotSeriesPrivate::createLegendMarkers(QLegend *legend) |
530 | { |
531 | Q_Q(QBoxPlotSeries); |
532 | QList<QLegendMarker *> list; |
533 | return list << new QBoxPlotLegendMarker(q, legend); |
534 | } |
535 | |
536 | void QBoxPlotSeriesPrivate::handleSeriesRemove(QAbstractSeries *series) |
537 | { |
538 | Q_Q(QBoxPlotSeries); |
539 | |
540 | QBoxPlotSeries *removedSeries = static_cast<QBoxPlotSeries *>(series); |
541 | |
542 | if (q == removedSeries) { |
543 | if (m_animation) |
544 | m_animation->stopAll(); |
545 | QObject::disconnect(sender: m_chart->d_ptr->m_dataset, signal: 0, receiver: this, member: 0); |
546 | } |
547 | |
548 | // Test if series removed is me, then don't do anything |
549 | if (q != removedSeries) { |
550 | BoxPlotChartItem *item = static_cast<BoxPlotChartItem *>(m_item.data()); |
551 | if (item) { |
552 | item->m_seriesCount = item->m_seriesCount - 1; |
553 | if (removedSeries->d_func()->m_index < m_index) { |
554 | m_index--; |
555 | item->m_seriesIndex = m_index; |
556 | } |
557 | |
558 | item->handleDataStructureChanged(); |
559 | } |
560 | } |
561 | } |
562 | |
563 | void QBoxPlotSeriesPrivate::handleSeriesChange(QAbstractSeries *series) |
564 | { |
565 | Q_UNUSED(series); |
566 | |
567 | Q_Q(QBoxPlotSeries); |
568 | |
569 | BoxPlotChartItem *boxPlot = static_cast<BoxPlotChartItem *>(m_item.data()); |
570 | |
571 | if (m_chart) { |
572 | QList<QAbstractSeries *> serieses = m_chart->series(); |
573 | |
574 | // Tries to find this series from the Chart's list of series and deduce the index |
575 | int index = 0; |
576 | foreach (QAbstractSeries *s, serieses) { |
577 | if (s->type() == QAbstractSeries::SeriesTypeBoxPlot) { |
578 | if (q == static_cast<QBoxPlotSeries *>(s)) { |
579 | boxPlot->m_seriesIndex = index; |
580 | m_index = index; |
581 | } |
582 | index++; |
583 | } |
584 | } |
585 | boxPlot->m_seriesCount = index; |
586 | } |
587 | |
588 | boxPlot->handleDataStructureChanged(); |
589 | } |
590 | |
591 | bool QBoxPlotSeriesPrivate::append(QBoxSet *set) |
592 | { |
593 | if (m_boxSets.contains(t: set) || (set == 0) || set->d_ptr->m_series) |
594 | return false; // Fail if set is already in list or set is null. |
595 | |
596 | m_boxSets.append(t: set); |
597 | QObject::connect(sender: set->d_ptr.data(), SIGNAL(updatedLayout()), receiver: this, SIGNAL(updatedLayout())); |
598 | QObject::connect(sender: set->d_ptr.data(), SIGNAL(updatedBox()), receiver: this, SIGNAL(updatedBoxes())); |
599 | QObject::connect(sender: set->d_ptr.data(), SIGNAL(restructuredBox()), receiver: this, SIGNAL(restructuredBoxes())); |
600 | set->d_ptr->m_series = this; |
601 | |
602 | emit restructuredBoxes(); // this notifies boxplotchartitem |
603 | return true; |
604 | } |
605 | |
606 | bool QBoxPlotSeriesPrivate::remove(QBoxSet *set) |
607 | { |
608 | if (!m_boxSets.contains(t: set)) |
609 | return false; // Fail if set is not in list |
610 | |
611 | set->d_ptr->m_series = 0; |
612 | m_boxSets.removeOne(t: set); |
613 | QObject::disconnect(sender: set->d_ptr.data(), SIGNAL(updatedLayout()), receiver: this, SIGNAL(updatedLayout())); |
614 | QObject::disconnect(sender: set->d_ptr.data(), SIGNAL(updatedBox()), receiver: this, SIGNAL(updatedBoxes())); |
615 | QObject::disconnect(sender: set->d_ptr.data(), SIGNAL(restructuredBox()), receiver: this, SIGNAL(restructuredBoxes())); |
616 | |
617 | emit restructuredBoxes(); // this notifies boxplotchartitem |
618 | return true; |
619 | } |
620 | |
621 | bool QBoxPlotSeriesPrivate::append(QList<QBoxSet *> sets) |
622 | { |
623 | foreach (QBoxSet *set, sets) { |
624 | if ((set == 0) || m_boxSets.contains(t: set) || set->d_ptr->m_series) |
625 | return false; // Fail if any of the sets is null or is already appended. |
626 | if (sets.count(t: set) != 1) |
627 | return false; // Also fail if same set is more than once in given list. |
628 | } |
629 | |
630 | foreach (QBoxSet *set, sets) { |
631 | m_boxSets.append(t: set); |
632 | QObject::connect(sender: set->d_ptr.data(), SIGNAL(updatedLayout()), receiver: this, SIGNAL(updatedLayout())); |
633 | QObject::connect(sender: set->d_ptr.data(), SIGNAL(updatedBox()), receiver: this, SIGNAL(updatedBoxes())); |
634 | QObject::connect(sender: set->d_ptr.data(), SIGNAL(restructuredBox()), receiver: this, SIGNAL(restructuredBoxes())); |
635 | set->d_ptr->m_series = this; |
636 | } |
637 | |
638 | emit restructuredBoxes(); // this notifies boxplotchartitem |
639 | return true; |
640 | } |
641 | |
642 | bool QBoxPlotSeriesPrivate::remove(QList<QBoxSet *> sets) |
643 | { |
644 | if (sets.count() == 0) |
645 | return false; |
646 | |
647 | foreach (QBoxSet *set, sets) { |
648 | if ((set == 0) || (!m_boxSets.contains(t: set))) |
649 | return false; // Fail if any of the sets is null or is not in series |
650 | if (sets.count(t: set) != 1) |
651 | return false; // Also fail if same set is more than once in given list. |
652 | } |
653 | |
654 | foreach (QBoxSet *set, sets) { |
655 | set->d_ptr->m_series = 0; |
656 | m_boxSets.removeOne(t: set); |
657 | QObject::disconnect(sender: set->d_ptr.data(), SIGNAL(updatedLayout()), receiver: this, SIGNAL(updatedLayout())); |
658 | QObject::disconnect(sender: set->d_ptr.data(), SIGNAL(updatedBox()), receiver: this, SIGNAL(updatedBoxes())); |
659 | QObject::disconnect(sender: set->d_ptr.data(), SIGNAL(restructuredBox()), receiver: this, SIGNAL(restructuredBoxes())); |
660 | } |
661 | |
662 | emit restructuredBoxes(); // this notifies boxplotchartitem |
663 | |
664 | return true; |
665 | } |
666 | |
667 | bool QBoxPlotSeriesPrivate::insert(int index, QBoxSet *set) |
668 | { |
669 | if ((m_boxSets.contains(t: set)) || (set == 0) || set->d_ptr->m_series) |
670 | return false; // Fail if set is already in list or set is null. |
671 | |
672 | m_boxSets.insert(i: index, t: set); |
673 | set->d_ptr->m_series = this; |
674 | QObject::connect(sender: set->d_ptr.data(), SIGNAL(updatedLayout()), receiver: this, SIGNAL(updatedLayout())); |
675 | QObject::connect(sender: set->d_ptr.data(), SIGNAL(updatedBox()), receiver: this, SIGNAL(updatedBoxes())); |
676 | QObject::connect(sender: set->d_ptr.data(), SIGNAL(restructuredBox()), receiver: this, SIGNAL(restructuredBoxes())); |
677 | |
678 | emit restructuredBoxes(); // this notifies boxplotchartitem |
679 | return true; |
680 | } |
681 | |
682 | QBoxSet *QBoxPlotSeriesPrivate::boxSetAt(int index) |
683 | { |
684 | return m_boxSets.at(i: index); |
685 | } |
686 | |
687 | qreal QBoxPlotSeriesPrivate::min() |
688 | { |
689 | if (m_boxSets.count() <= 0) |
690 | return 0; |
691 | |
692 | qreal min = m_boxSets.at(i: 0)->at(index: 0); |
693 | |
694 | foreach (QBoxSet *set, m_boxSets) { |
695 | for (int i = 0; i < 5; i++) { |
696 | if (set->at(index: i) < min) |
697 | min = set->at(index: i); |
698 | } |
699 | } |
700 | |
701 | return min; |
702 | } |
703 | |
704 | qreal QBoxPlotSeriesPrivate::max() |
705 | { |
706 | if (m_boxSets.count() <= 0) |
707 | return 0; |
708 | |
709 | qreal max = m_boxSets.at(i: 0)->at(index: 0); |
710 | |
711 | foreach (QBoxSet *set, m_boxSets) { |
712 | for (int i = 0; i < 5; i++) { |
713 | if (set->at(index: i) > max) |
714 | max = set->at(index: i); |
715 | } |
716 | } |
717 | |
718 | return max; |
719 | } |
720 | |
721 | QT_CHARTS_END_NAMESPACE |
722 | |
723 | #include "moc_qboxplotseries.cpp" |
724 | #include "moc_qboxplotseries_p.cpp" |
725 | |