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
44QT_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*/
155QBoxPlotSeries::QBoxPlotSeries(QObject *parent)
156 : QAbstractSeries(*new QBoxPlotSeriesPrivate(this), parent)
157{
158}
159
160/*!
161 Removes the series from the chart.
162*/
163QBoxPlotSeries::~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*/
175bool 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*/
194bool 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*/
220bool 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*/
239bool 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*/
255bool 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*/
271void 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*/
287int 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 */
296QList<QBoxSet *> QBoxPlotSeries::boxSets() const
297{
298 Q_D(const QBoxPlotSeries);
299 return d->m_boxSets;
300}
301
302/*
303 Returns QAbstractSeries::SeriesTypeBoxPlot.
304*/
305QAbstractSeries::SeriesType QBoxPlotSeries::type() const
306{
307 return QAbstractSeries::SeriesTypeBoxPlot;
308}
309
310void 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
321bool QBoxPlotSeries::boxOutlineVisible()
322{
323 Q_D(QBoxPlotSeries);
324
325 return d->m_boxOutlineVisible;
326}
327
328void 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
343qreal QBoxPlotSeries::boxWidth()
344{
345 Q_D(QBoxPlotSeries);
346
347 return d->m_boxWidth;
348}
349
350void 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
361QBrush QBoxPlotSeries::brush() const
362{
363 Q_D(const QBoxPlotSeries);
364
365 return d->m_brush;
366}
367
368void 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
379QPen QBoxPlotSeries::pen() const
380{
381 Q_D(const QBoxPlotSeries);
382
383 return d->m_pen;
384}
385
386///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
387
388QBoxPlotSeriesPrivate::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
397QBoxPlotSeriesPrivate::~QBoxPlotSeriesPrivate()
398{
399 disconnect(sender: this, signal: 0, receiver: 0, member: 0);
400}
401
402void 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
418void 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
428QAbstractAxis::AxisType QBoxPlotSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
429{
430 if (orientation == Qt::Horizontal)
431 return QAbstractAxis::AxisTypeBarCategory;
432
433 return QAbstractAxis::AxisTypeValue;
434}
435
436QAbstractAxis* 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
444void 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
459void 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
491void 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
509void 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
529QList<QLegendMarker*> QBoxPlotSeriesPrivate::createLegendMarkers(QLegend *legend)
530{
531 Q_Q(QBoxPlotSeries);
532 QList<QLegendMarker *> list;
533 return list << new QBoxPlotLegendMarker(q, legend);
534}
535
536void 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
563void 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
591bool 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
606bool 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
621bool 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
642bool 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
667bool 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
682QBoxSet *QBoxPlotSeriesPrivate::boxSetAt(int index)
683{
684 return m_boxSets.at(i: index);
685}
686
687qreal 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
704qreal 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
721QT_CHARTS_END_NAMESPACE
722
723#include "moc_qboxplotseries.cpp"
724#include "moc_qboxplotseries_p.cpp"
725

source code of qtcharts/src/charts/boxplotchart/qboxplotseries.cpp