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/QAbstractBarSeries>
31#include <private/qabstractbarseries_p.h>
32#include <QtCharts/QBarSet>
33#include <private/qbarset_p.h>
34#include <private/abstractdomain_p.h>
35#include <private/chartdataset_p.h>
36#include <private/charttheme_p.h>
37#include <QtCharts/QValueAxis>
38#include <QtCharts/QBarCategoryAxis>
39#include <QtCharts/QBarLegendMarker>
40#include <private/baranimation_p.h>
41#include <private/abstractbarchartitem_p.h>
42#include <private/qchart_p.h>
43
44QT_CHARTS_BEGIN_NAMESPACE
45
46/*!
47 \class QAbstractBarSeries
48 \inmodule QtCharts
49 \brief The QAbstractBarSeries class is an abstract parent class for all bar series classes.
50
51 In bar charts, bars are defined as bar sets that contain one data value for each category.
52 The position of a bar is specified by the category and its height by the data value. Bar
53 series that contain multiple bar sets group together bars that belong to the same category.
54 The way the bars are displayed is determined by the subclass of this class chosen to create
55 the bar chart.
56
57 If a QValueAxis is used instead of QBarCategoryAxis for the main bar axis, the bars are
58 grouped around the index value of the category.
59
60 See the \l {BarChart Example} {bar chart example} to learn how to use the QBarSeries class
61 to create a simple bar chart.
62 \image examples_barchart.png
63
64 \sa QBarSet, QBarSeries, QStackedBarSeries, QPercentBarSeries
65 \sa QHorizontalBarSeries, QHorizontalStackedBarSeries, QHorizontalPercentBarSeries
66*/
67/*!
68 \qmltype AbstractBarSeries
69 \instantiates QAbstractBarSeries
70 \inqmlmodule QtCharts
71
72 \inherits AbstractSeries
73
74 \brief An abstract parent type for all bar series types.
75
76 In bar charts, bars are defined as bar sets that contain one data value for each category.
77 The position of a bar is specified by the category and its height by the data value. Bar
78 series that contain multiple bar sets group together bars that belong to the same category.
79 The way the bars are displayed is determined by the type chosen to create the bar chart:
80 BarSeries, StackedBarSeries, PercentBarSeries, HorizontalBarSeries, HorizontalStackedBarSeries,
81 or HorizontalPercentBarSeries.
82
83 If a ValueAxis type is used instead of a BarCategoryAxis type for the main bar axis, the
84 bars are grouped around the index value of the category.
85
86 The following QML code snippet shows how to use the BarSeries and BarCategoryAxis type
87 to create a simple bar chart:
88 \snippet qmlchart/qml/qmlchart/View6.qml 1
89
90 \beginfloatleft
91 \image examples_qmlchart6.png
92 \endfloat
93 \clearfloat
94*/
95
96/*!
97 \qmlproperty AbstractAxis AbstractBarSeries::axisX
98 The x-axis used for the series. If you leave both axisX and axisXTop undefined, a
99 BarCategoryAxis is created for the series.
100 \sa axisXTop
101*/
102
103/*!
104 \qmlproperty AbstractAxis AbstractBarSeries::axisY
105 The y-axis used for the series. If you leave both axisY and axisYRight undefined, a
106 ValueAxis is created for the series.
107 \sa axisYRight
108*/
109
110/*!
111 \qmlproperty AbstractAxis AbstractBarSeries::axisXTop
112 The x-axis used for the series, drawn on top of the chart view.
113
114 \note You can only provide either axisX or axisXTop, but not both.
115 \sa axisX
116*/
117
118/*!
119 \qmlproperty AbstractAxis AbstractBarSeries::axisYRight
120 The y-axis used for the series, drawn to the right of the chart view.
121
122 \note You can only provide either axisY or axisYRight, but not both.
123 \sa axisY
124*/
125
126/*!
127 \property QAbstractBarSeries::barWidth
128 \brief The width of the bars of the series.
129
130 The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative
131 values are treated as zero. Setting the width to zero means that the width of the bar on the
132 screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled
133 using the x-axis scale.
134
135 \note When used with QBarSeries, this value specifies the width of a group of bars instead of
136 that of a single bar.
137 \sa QBarSeries
138*/
139/*!
140 \qmlproperty real AbstractBarSeries::barWidth
141 The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative
142 values are treated as zero. Setting the width to zero means that the width of the bar on the
143 screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled
144 using the x-axis scale.
145
146 \note When used with the BarSeries type, this value specifies the width of a group of bars
147 instead of that of a single bar.
148*/
149
150/*!
151 \property QAbstractBarSeries::count
152 \brief The number of bar sets in a bar series.
153*/
154/*!
155 \qmlproperty int AbstractBarSeries::count
156 The number of bar sets in a bar series.
157*/
158
159/*!
160 \property QAbstractBarSeries::labelsVisible
161 \brief The visibility of the labels in a bar series.
162*/
163/*!
164 \qmlproperty bool AbstractBarSeries::labelsVisible
165 The visibility of the labels in a bar series.
166*/
167
168/*!
169 \property QAbstractBarSeries::labelsFormat
170 \brief The format used for showing labels in a bar series.
171
172 QAbstractBarSeries supports the following format tag:
173 \table
174 \row
175 \li @value \li The value of the bar
176 \endtable
177
178 For example, the following usage of the format tags would produce labels that show the value
179 followed by the unit (u):
180 \code
181 series->setLabelsFormat("@value u");
182 \endcode
183
184 By default, the labels show the value of the bar. For the percent bar series, \e % is added
185 after the value. The labels are shown on the plot area, if the bars are close to each other,
186 the labels may overlap.
187
188 \sa labelsVisible, labelsPosition, labelsPrecision
189*/
190/*!
191 \qmlproperty string AbstractBarSeries::labelsFormat
192 The format used for showing labels in a bar series.
193
194 \sa QAbstractBarSeries::labelsFormat, labelsVisible, labelsPosition
195*/
196/*!
197 \fn void QAbstractBarSeries::labelsFormatChanged(const QString &format)
198 This signal is emitted when the \a format of data value labels changes.
199*/
200
201/*!
202 \enum QAbstractBarSeries::LabelsPosition
203
204 This enum value describes the position of the data value labels:
205
206 \value LabelsCenter Label is located in the center of the bar.
207 \value LabelsInsideEnd Label is located inside the bar at the top.
208 \value LabelsInsideBase Label is located inside the bar at the bottom.
209 \value LabelsOutsideEnd Label is located outside the bar at the top.
210 */
211
212/*!
213 \property QAbstractBarSeries::labelsPosition
214 \brief The position of value labels.
215
216 \sa labelsVisible, labelsFormat
217*/
218/*!
219 \qmlproperty enumeration AbstractBarSeries::labelsPosition
220
221 The position of the data value labels:
222
223 \value AbstractBarSeries.LabelsCenter
224 Label is located in the center of the bar.
225 \value AbstractBarSeries.LabelsInsideEnd
226 Label is located inside the bar at the top.
227 \value AbstractBarSeries.LabelsInsideBase
228 Label is located inside the bar at the bottom.
229 \value AbstractBarSeries.LabelsOutsideEnd
230 Label is located outside the bar at the top.
231
232 \sa labelsVisible, labelsFormat
233*/
234/*!
235 \fn void QAbstractBarSeries::labelsPositionChanged(QAbstractBarSeries::LabelsPosition position)
236 This signal is emitted when the \a position of value labels changes.
237*/
238
239/*!
240 \property QAbstractBarSeries::labelsAngle
241 \brief The angle of the value labels in degrees.
242*/
243/*!
244 \qmlproperty real AbstractBarSeries::labelsAngle
245 The angle of the value labels in degrees.
246*/
247/*!
248 \fn void QAbstractBarSeries::labelsAngleChanged(qreal angle)
249 This signal is emitted when the \a angle of the value labels changes.
250*/
251
252/*!
253 \property QAbstractBarSeries::labelsPrecision
254 \brief The maximum amount of significant digits shown in value labels.
255
256 Default value is 6.
257*/
258/*!
259 \qmlproperty real AbstractBarSeries::labelsPrecision
260 The maximum amount of significant digits shown in value labels.
261
262 Default value is 6.
263*/
264/*!
265 \fn void QAbstractBarSeries::labelsPrecisionChanged(int precision)
266 This signal is emitted when the \a precision of the value labels changes.
267*/
268
269/*!
270 \fn void QAbstractBarSeries::clicked(int index, QBarSet *barset)
271 This signal is emitted when the user clicks the bar specified by \a index
272 in the bar set specified by \a barset.
273*/
274/*!
275 \qmlsignal AbstractBarSeries::clicked(int index, BarSet barset)
276 This signal is emitted when the user clicks the bar specified by \a index
277 in the bar set specified by \a barset.
278
279 The corresponding signal handler is \c onClicked.
280*/
281
282/*!
283 \fn void QAbstractBarSeries::pressed(int index, QBarSet *barset)
284 This signal is emitted when the user clicks the bar specified by \a index
285 in the bar set specified by \a barset and holds down the mouse button.
286*/
287/*!
288 \qmlsignal AbstractBarSeries::pressed(int index, BarSet barset)
289 This signal is emitted when the user clicks the bar specified by \a index
290 in the bar set specified by \a barset and holds down the mouse button.
291
292 The corresponding signal handler is \c onPressed.
293*/
294
295/*!
296 \fn void QAbstractBarSeries::released(int index, QBarSet *barset)
297 This signal is emitted when the user releases the mouse press on the bar
298 specified by \a index in the bar set specified by \a barset.
299*/
300/*!
301 \qmlsignal AbstractBarSeries::released(int index, BarSet barset)
302 This signal is emitted when the user releases the mouse press on the bar
303 specified by \a index in the bar set specified by \a barset.
304
305 The corresponding signal handler is \c onReleased.
306*/
307
308/*!
309 \fn void QAbstractBarSeries::doubleClicked(int index, QBarSet *barset)
310 This signal is emitted when the user double-clicks the bar specified by \a index
311 in the bar set specified by \a barset.
312*/
313/*!
314 \qmlsignal AbstractBarSeries::doubleClicked(int index, BarSet barset)
315 This signal is emitted when the user double-clicks the bar specified by \a index
316 in the bar set specified by \a barset.
317
318 The corresponding signal handler is \c onDoubleClicked.
319*/
320
321/*!
322 \fn void QAbstractBarSeries::hovered(bool status, int index, QBarSet* barset)
323
324 This signal is emitted when a mouse is hovered over the bar specified by \a index in the
325 bar set specified by \a barset. When the mouse moves over the bar, \a status turns \c true,
326 and when the mouse moves away again, it turns \c false.
327*/
328/*!
329 \qmlsignal AbstractBarSeries::hovered(bool status, int index, BarSet barset)
330
331 This signal is emitted when a mouse is hovered over the bar specified by \a index in the
332 bar set specified by \a barset. When the mouse moves over the bar, \a status turns \c true,
333 and when the mouse moves away again, it turns \c false.
334
335 The corresponding signal handler is \c onHovered.
336*/
337
338/*!
339 \fn void QAbstractBarSeries::countChanged()
340 This signal is emitted when the number of bar sets is changed, for example by append() or
341 remove().
342*/
343
344/*!
345 \fn void QAbstractBarSeries::labelsVisibleChanged()
346 This signal is emitted when the labels' visibility changes.
347 \sa isLabelsVisible(), setLabelsVisible()
348*/
349
350/*!
351 \fn void QAbstractBarSeries::barsetsAdded(QList<QBarSet*> sets)
352 This signal is emitted when the bar sets specified by \a sets are added to the series.
353 \sa append(), insert()
354*/
355/*!
356 \qmlsignal AbstractBarSeries::barsetsAdded()
357 This signal is emitted when bar sets are added to the series.
358
359 The corresponding signal handler is \c onBarsetsAdded.
360*/
361
362/*!
363 \fn void QAbstractBarSeries::barsetsRemoved(QList<QBarSet*> sets)
364 This signal is emitted when the bar sets specified by \a sets are removed from the series.
365 \sa remove()
366*/
367/*!
368 \qmlsignal AbstractBarSeries::barsetsRemoved()
369 This signal is emitted when bar sets are removed from the series.
370
371 The corresponding signal handler is \c onBarsetsRemoved.
372*/
373
374/*!
375 \qmlmethod BarSet AbstractBarSeries::at(int index)
376 Returns the bar set at \a index. Returns null if the index is not valid.
377*/
378
379/*!
380 \qmlmethod BarSet AbstractBarSeries::append(string label, VariantList values)
381 Adds a new bar set with \a label and \a values to the index. \a values is
382 a list of real values.
383
384 For example:
385 \code
386 myBarSeries.append("set 1", [0, 0.2, 0.2, 0.5, 0.4, 1.5, 0.9]);
387 \endcode
388*/
389
390/*!
391 \qmlmethod BarSet AbstractBarSeries::insert(int index, string label, VariantList values)
392 Adds a new bar set with \a label and \a values to \a index. \a values can be a list
393 of real values or a list of XYPoint types.
394
395 If the index value is equal to or less than zero, the new bar set is prepended to the bar
396 series. If the index value is equal to or greater than the number of bar sets in the bar
397 series, the new bar set is appended to the bar series.
398
399 \sa append()
400*/
401
402/*!
403 \qmlmethod bool AbstractBarSeries::remove(BarSet barset)
404 Removes the bar set specified by \a barset from the series. Returns \c true if successful,
405 \c false otherwise.
406*/
407
408/*!
409 \qmlmethod AbstractBarSeries::clear()
410 Removes all bar sets from the series.
411*/
412
413/*!
414 Removes the abstract bar series and the bar sets owned by it.
415*/
416QAbstractBarSeries::~QAbstractBarSeries()
417{
418
419}
420
421/*!
422 \internal
423*/
424QAbstractBarSeries::QAbstractBarSeries(QAbstractBarSeriesPrivate &o, QObject *parent)
425 : QAbstractSeries(o, parent)
426{
427 Q_D(QAbstractSeries);
428 QObject::connect(sender: this, SIGNAL(countChanged()), receiver: d, SIGNAL(countChanged()));
429}
430
431/*!
432 Sets the width of the bars of the series to \a width.
433*/
434void QAbstractBarSeries::setBarWidth(qreal width)
435{
436 Q_D(QAbstractBarSeries);
437 d->setBarWidth(width);
438}
439
440/*!
441 Returns the width of the bars of the series.
442 \sa setBarWidth()
443*/
444qreal QAbstractBarSeries::barWidth() const
445{
446 Q_D(const QAbstractBarSeries);
447 return d->barWidth();
448}
449
450/*!
451 Adds a set of bars specified by \a set to the bar series and takes ownership of it. If the set
452 is null or it already belongs to the series, it will not be appended.
453 Returns \c true if appending succeeded.
454*/
455bool QAbstractBarSeries::append(QBarSet *set)
456{
457 Q_D(QAbstractBarSeries);
458 bool success = d->append(set);
459 if (success) {
460 QList<QBarSet *> sets;
461 sets.append(t: set);
462 set->setParent(this);
463 emit barsetsAdded(sets);
464 emit countChanged();
465 }
466 return success;
467}
468
469/*!
470 Removes the bar set specified by \a set from the series and permanently deletes it if
471 the removal succeeds. Returns \c true if the set was removed.
472*/
473bool QAbstractBarSeries::remove(QBarSet *set)
474{
475 Q_D(QAbstractBarSeries);
476 bool success = d->remove(set);
477 if (success) {
478 QList<QBarSet *> sets;
479 sets.append(t: set);
480 set->setParent(0);
481 emit barsetsRemoved(sets);
482 emit countChanged();
483 delete set;
484 set = 0;
485 }
486 return success;
487}
488
489/*!
490 Takes a single \a set from the series. Does not delete the bar set object.
491 \note The series remains the barset's parent object. You must set the
492 parent object to take full ownership.
493
494 Returns \c true if the take operation succeeds.
495*/
496bool QAbstractBarSeries::take(QBarSet *set)
497{
498 Q_D(QAbstractBarSeries);
499 bool success = d->remove(set);
500 if (success) {
501 QList<QBarSet *> sets;
502 sets.append(t: set);
503 emit barsetsRemoved(sets);
504 emit countChanged();
505 }
506 return success;
507}
508
509/*!
510 Adds a list of bar sets specified by \a sets to a bar series and takes ownership of the sets.
511 Returns \c true if all sets were appended successfully. If any of the sets is null or was
512 previously appended to the series, nothing is appended and this function returns \c false.
513 If any of the sets appears in the list more than once, nothing is appended and this function
514 returns \c false.
515*/
516bool QAbstractBarSeries::append(QList<QBarSet *> sets)
517{
518 Q_D(QAbstractBarSeries);
519 bool success = d->append(sets);
520 if (success) {
521 foreach (QBarSet *set, sets)
522 set->setParent(this);
523 emit barsetsAdded(sets);
524 emit countChanged();
525 }
526 return success;
527}
528
529/*!
530 Inserts a bar set specified by \a set to a series at the position specified by \a index
531 and takes ownership of the set. If the set is null or already belongs to the series, it will
532 not be appended. Returns \c true if inserting succeeds.
533*/
534bool QAbstractBarSeries::insert(int index, QBarSet *set)
535{
536 Q_D(QAbstractBarSeries);
537 bool success = d->insert(index, set);
538 if (success) {
539 QList<QBarSet *> sets;
540 sets.append(t: set);
541 emit barsetsAdded(sets);
542 emit countChanged();
543 }
544 return success;
545}
546
547/*!
548 Removes all bar sets from the series and permanently deletes them.
549*/
550void QAbstractBarSeries::clear()
551{
552 Q_D(QAbstractBarSeries);
553 QList<QBarSet *> sets = barSets();
554 bool success = d->remove(sets);
555 if (success) {
556 emit barsetsRemoved(sets);
557 emit countChanged();
558 foreach (QBarSet *set, sets)
559 delete set;
560 }
561}
562
563/*!
564 Returns the number of bar sets in a bar series.
565*/
566int QAbstractBarSeries::count() const
567{
568 Q_D(const QAbstractBarSeries);
569 return d->m_barSets.count();
570}
571
572/*!
573 Returns a list of bar sets in a bar series. Keeps the ownership of the bar sets.
574 */
575QList<QBarSet *> QAbstractBarSeries::barSets() const
576{
577 Q_D(const QAbstractBarSeries);
578 return d->m_barSets;
579}
580
581/*!
582 Sets the visibility of labels in a bar series to \a visible.
583*/
584void QAbstractBarSeries::setLabelsVisible(bool visible)
585{
586 Q_D(QAbstractBarSeries);
587 if (d->m_labelsVisible != visible) {
588 d->setLabelsVisible(visible);
589 emit labelsVisibleChanged();
590 }
591}
592
593/*!
594 Returns the visibility of labels.
595*/
596bool QAbstractBarSeries::isLabelsVisible() const
597{
598 Q_D(const QAbstractBarSeries);
599 return d->m_labelsVisible;
600}
601
602void QAbstractBarSeries::setLabelsFormat(const QString &format)
603{
604 Q_D(QAbstractBarSeries);
605 if (d->m_labelsFormat != format) {
606 d->m_labelsFormat = format;
607 d->setLabelsDirty(true);
608 emit labelsFormatChanged(format);
609 }
610}
611
612QString QAbstractBarSeries::labelsFormat() const
613{
614 Q_D(const QAbstractBarSeries);
615 return d->m_labelsFormat;
616}
617
618void QAbstractBarSeries::setLabelsAngle(qreal angle)
619{
620 Q_D(QAbstractBarSeries);
621 if (d->m_labelsAngle != angle) {
622 d->m_labelsAngle = angle;
623 d->setLabelsDirty(true);
624 emit labelsAngleChanged(angle);
625 }
626}
627
628qreal QAbstractBarSeries::labelsAngle() const
629{
630 Q_D(const QAbstractBarSeries);
631 return d->m_labelsAngle;
632}
633
634void QAbstractBarSeries::setLabelsPosition(QAbstractBarSeries::LabelsPosition position)
635{
636 Q_D(QAbstractBarSeries);
637 if (d->m_labelsPosition != position) {
638 d->m_labelsPosition = position;
639 emit labelsPositionChanged(position);
640 }
641}
642
643QAbstractBarSeries::LabelsPosition QAbstractBarSeries::labelsPosition() const
644{
645 Q_D(const QAbstractBarSeries);
646 return d->m_labelsPosition;
647}
648
649void QAbstractBarSeries::setLabelsPrecision(int precision)
650{
651 Q_D(QAbstractBarSeries);
652 if (d->m_labelsPrecision != precision) {
653 d->m_labelsPrecision = precision;
654 d->setLabelsDirty(true);
655 emit labelsPrecisionChanged(precision);
656 }
657}
658
659int QAbstractBarSeries::labelsPrecision() const
660{
661 Q_D(const QAbstractBarSeries);
662 return d->m_labelsPrecision;
663}
664
665///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
666
667QAbstractBarSeriesPrivate::QAbstractBarSeriesPrivate(QAbstractBarSeries *q) :
668 QAbstractSeriesPrivate(q),
669 m_barWidth(0.5), // Default value is 50% of category width
670 m_labelsVisible(false),
671 m_visible(true),
672 m_blockBarUpdate(false),
673 m_labelsFormat(),
674 m_labelsPosition(QAbstractBarSeries::LabelsCenter),
675 m_labelsAngle(0),
676 m_labelsPrecision(6),
677 m_visualsDirty(true),
678 m_labelsDirty(true)
679{
680}
681
682int QAbstractBarSeriesPrivate::categoryCount() const
683{
684 // No categories defined. return count of longest set.
685 int count = 0;
686 for (int i = 0; i < m_barSets.count(); i++) {
687 if (m_barSets.at(i)->count() > count)
688 count = m_barSets.at(i)->count();
689 }
690
691 return count;
692}
693
694void QAbstractBarSeriesPrivate::setBarWidth(qreal width)
695{
696 if (width < 0.0)
697 width = 0.0;
698 m_barWidth = width;
699 emit updatedLayout();
700}
701
702qreal QAbstractBarSeriesPrivate::barWidth() const
703{
704 return m_barWidth;
705}
706
707QBarSet *QAbstractBarSeriesPrivate::barsetAt(int index)
708{
709 return m_barSets.at(i: index);
710}
711
712void QAbstractBarSeriesPrivate::setVisible(bool visible)
713{
714 m_visible = visible;
715 emit visibleChanged();
716}
717
718void QAbstractBarSeriesPrivate::setLabelsVisible(bool visible)
719{
720 m_labelsVisible = visible;
721 emit labelsVisibleChanged(visible);
722}
723
724qreal QAbstractBarSeriesPrivate::min()
725{
726 if (m_barSets.count() <= 0)
727 return 0;
728
729 qreal min = INT_MAX;
730
731 for (int i = 0; i < m_barSets.count(); i++) {
732 int categoryCount = m_barSets.at(i)->count();
733 for (int j = 0; j < categoryCount; j++) {
734 qreal temp = m_barSets.at(i)->at(index: j);
735 if (temp < min)
736 min = temp;
737 }
738 }
739 return min;
740}
741
742qreal QAbstractBarSeriesPrivate::max()
743{
744 if (m_barSets.count() <= 0)
745 return 0;
746
747 qreal max = INT_MIN;
748
749 for (int i = 0; i < m_barSets.count(); i++) {
750 int categoryCount = m_barSets.at(i)->count();
751 for (int j = 0; j < categoryCount; j++) {
752 qreal temp = m_barSets.at(i)->at(index: j);
753 if (temp > max)
754 max = temp;
755 }
756 }
757
758 return max;
759}
760
761qreal QAbstractBarSeriesPrivate::valueAt(int set, int category)
762{
763 if ((set < 0) || (set >= m_barSets.count()))
764 return 0; // No set, no value.
765 else if ((category < 0) || (category >= m_barSets.at(i: set)->count()))
766 return 0; // No category, no value.
767
768 return m_barSets.at(i: set)->at(index: category);
769}
770
771qreal QAbstractBarSeriesPrivate::percentageAt(int set, int category)
772{
773 if ((set < 0) || (set >= m_barSets.count()))
774 return 0; // No set, no value.
775 else if ((category < 0) || (category >= m_barSets.at(i: set)->count()))
776 return 0; // No category, no value.
777
778 qreal value = m_barSets.at(i: set)->at(index: category);
779 qreal sum = categorySum(category);
780 if (qFuzzyCompare(p1: sum, p2: 0))
781 return 0;
782
783 return value / sum;
784}
785
786qreal QAbstractBarSeriesPrivate::categorySum(int category)
787{
788 qreal sum(0);
789 int count = m_barSets.count(); // Count sets
790 for (int set = 0; set < count; set++) {
791 if (category < m_barSets.at(i: set)->count())
792 sum += m_barSets.at(i: set)->at(index: category);
793 }
794 return sum;
795}
796
797qreal QAbstractBarSeriesPrivate::absoluteCategorySum(int category)
798{
799 qreal sum(0);
800 int count = m_barSets.count(); // Count sets
801 for (int set = 0; set < count; set++) {
802 if (category < m_barSets.at(i: set)->count())
803 sum += qAbs(t: m_barSets.at(i: set)->at(index: category));
804 }
805 return sum;
806}
807
808qreal QAbstractBarSeriesPrivate::maxCategorySum()
809{
810 qreal max = INT_MIN;
811 int count = categoryCount();
812 for (int i = 0; i < count; i++) {
813 qreal sum = categorySum(category: i);
814 if (sum > max)
815 max = sum;
816 }
817 return max;
818}
819
820qreal QAbstractBarSeriesPrivate::minX()
821{
822 if (m_barSets.count() <= 0)
823 return 0;
824
825 qreal min = INT_MAX;
826
827 for (int i = 0; i < m_barSets.count(); i++) {
828 int categoryCount = m_barSets.at(i)->count();
829 for (int j = 0; j < categoryCount; j++) {
830 qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(i: j).x();
831 if (temp < min)
832 min = temp;
833 }
834 }
835 return min;
836}
837
838qreal QAbstractBarSeriesPrivate::maxX()
839{
840 if (m_barSets.count() <= 0)
841 return 0;
842
843 qreal max = INT_MIN;
844
845 for (int i = 0; i < m_barSets.count(); i++) {
846 int categoryCount = m_barSets.at(i)->count();
847 for (int j = 0; j < categoryCount; j++) {
848 qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(i: j).x();
849 if (temp > max)
850 max = temp;
851 }
852 }
853
854 return max;
855}
856
857qreal QAbstractBarSeriesPrivate::categoryTop(int category)
858{
859 // Returns top (sum of all positive values) of category.
860 // Returns 0, if all values are negative
861 qreal top(0);
862 int count = m_barSets.count();
863 for (int set = 0; set < count; set++) {
864 if (category < m_barSets.at(i: set)->count()) {
865 qreal temp = m_barSets.at(i: set)->at(index: category);
866 if (temp > 0) {
867 top += temp;
868 }
869 }
870 }
871 return top;
872}
873
874qreal QAbstractBarSeriesPrivate::categoryBottom(int category)
875{
876 // Returns bottom (sum of all negative values) of category
877 // Returns 0, if all values are positive
878 qreal bottom(0);
879 int count = m_barSets.count();
880 for (int set = 0; set < count; set++) {
881 if (category < m_barSets.at(i: set)->count()) {
882 qreal temp = m_barSets.at(i: set)->at(index: category);
883 if (temp < 0) {
884 bottom += temp;
885 }
886 }
887 }
888 return bottom;
889}
890
891qreal QAbstractBarSeriesPrivate::top()
892{
893 // Returns top of all categories
894 qreal top(0);
895 int count = categoryCount();
896 for (int i = 0; i < count; i++) {
897 qreal temp = categoryTop(category: i);
898 if (temp > top)
899 top = temp;
900 }
901 return top;
902}
903
904qreal QAbstractBarSeriesPrivate::bottom()
905{
906 // Returns bottom of all categories
907 qreal bottom(0);
908 int count = categoryCount();
909 for (int i = 0; i < count; i++) {
910 qreal temp = categoryBottom(category: i);
911 if (temp < bottom)
912 bottom = temp;
913 }
914 return bottom;
915}
916
917bool QAbstractBarSeriesPrivate::blockBarUpdate()
918{
919 return m_blockBarUpdate;
920}
921
922qreal QAbstractBarSeriesPrivate::labelsAngle() const
923{
924 return m_labelsAngle;
925}
926
927void QAbstractBarSeriesPrivate::initializeDomain()
928{
929 qreal minX(domain()->minX());
930 qreal minY(domain()->minY());
931 qreal maxX(domain()->maxX());
932 qreal maxY(domain()->maxY());
933
934 qreal seriesMinX = this->minX();
935 qreal seriesMaxX = this->maxX();
936 qreal y = max();
937 minX = qMin(a: minX, b: seriesMinX - (qreal)0.5);
938 minY = qMin(a: minY, b: y);
939 maxX = qMax(a: maxX, b: seriesMaxX + (qreal)0.5);
940 maxY = qMax(a: maxY, b: y);
941
942 domain()->setRange(minX, maxX, minY, maxY);
943}
944
945QList<QLegendMarker*> QAbstractBarSeriesPrivate::createLegendMarkers(QLegend* legend)
946{
947 Q_Q(QAbstractBarSeries);
948 QList<QLegendMarker*> markers;
949
950 foreach(QBarSet* set, q->barSets()) {
951 QBarLegendMarker* marker = new QBarLegendMarker(q,set,legend);
952 markers << marker;
953 }
954 return markers;
955}
956
957
958bool QAbstractBarSeriesPrivate::append(QBarSet *set)
959{
960 if ((m_barSets.contains(t: set)) || (set == 0))
961 return false; // Fail if set is already in list or set is null.
962
963 m_barSets.append(t: set);
964 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
965 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
966 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
967 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
968 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
969 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
970 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
971 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
972
973 emit restructuredBars(); // this notifies barchartitem
974 return true;
975}
976
977bool QAbstractBarSeriesPrivate::remove(QBarSet *set)
978{
979 if (!m_barSets.contains(t: set))
980 return false; // Fail if set is not in list
981
982 m_barSets.removeOne(t: set);
983 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
984 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
985 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
986 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
987 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
988 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
989 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
990 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
991
992 emit restructuredBars(); // this notifies barchartitem
993 return true;
994}
995
996bool QAbstractBarSeriesPrivate::append(QList<QBarSet * > sets)
997{
998 foreach (QBarSet *set, sets) {
999 if ((set == 0) || (m_barSets.contains(t: set)))
1000 return false; // Fail if any of the sets is null or is already appended.
1001 if (sets.count(t: set) != 1)
1002 return false; // Also fail if same set is more than once in given list.
1003 }
1004
1005 foreach (QBarSet *set, sets) {
1006 m_barSets.append(t: set);
1007 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
1008 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
1009 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
1010 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
1011 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
1012 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
1013 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
1014 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
1015 }
1016
1017 emit restructuredBars(); // this notifies barchartitem
1018 return true;
1019}
1020
1021bool QAbstractBarSeriesPrivate::remove(QList<QBarSet * > sets)
1022{
1023 if (sets.count() == 0)
1024 return false;
1025
1026 foreach (QBarSet *set, sets) {
1027 if ((set == 0) || (!m_barSets.contains(t: set)))
1028 return false; // Fail if any of the sets is null or is not in series
1029 if (sets.count(t: set) != 1)
1030 return false; // Also fail if same set is more than once in given list.
1031 }
1032
1033 foreach (QBarSet *set, sets) {
1034 m_barSets.removeOne(t: set);
1035 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
1036 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
1037 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
1038 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
1039 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
1040 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
1041 QObject::disconnect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
1042 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
1043 }
1044
1045 emit restructuredBars(); // this notifies barchartitem
1046
1047 return true;
1048}
1049
1050bool QAbstractBarSeriesPrivate::insert(int index, QBarSet *set)
1051{
1052 if ((m_barSets.contains(t: set)) || (set == 0))
1053 return false; // Fail if set is already in list or set is null.
1054
1055 m_barSets.insert(i: index, t: set);
1056 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::updatedBars,
1057 receiver: this, slot: &QAbstractBarSeriesPrivate::updatedBars);
1058 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueChanged,
1059 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueChange);
1060 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueAdded,
1061 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueAdd);
1062 QObject::connect(sender: set->d_ptr.data(), signal: &QBarSetPrivate::valueRemoved,
1063 receiver: this, slot: &QAbstractBarSeriesPrivate::handleSetValueRemove);
1064
1065 emit restructuredBars(); // this notifies barchartitem
1066 return true;
1067}
1068
1069void QAbstractBarSeriesPrivate::initializeAxes()
1070{
1071 Q_Q(QAbstractBarSeries);
1072
1073 foreach(QAbstractAxis* axis, m_axes) {
1074 if (axis->type() == QAbstractAxis::AxisTypeBarCategory) {
1075 switch (q->type()) {
1076 case QAbstractSeries::SeriesTypeHorizontalBar:
1077 case QAbstractSeries::SeriesTypeHorizontalPercentBar:
1078 case QAbstractSeries::SeriesTypeHorizontalStackedBar:
1079 if (axis->orientation() == Qt::Vertical)
1080 populateCategories(axis: qobject_cast<QBarCategoryAxis *>(object: axis));
1081 break;
1082 case QAbstractSeries::SeriesTypeBar:
1083 case QAbstractSeries::SeriesTypePercentBar:
1084 case QAbstractSeries::SeriesTypeStackedBar:
1085 case QAbstractSeries::SeriesTypeBoxPlot:
1086 case QAbstractSeries::SeriesTypeCandlestick:
1087 if (axis->orientation() == Qt::Horizontal)
1088 populateCategories(axis: qobject_cast<QBarCategoryAxis *>(object: axis));
1089 break;
1090 default:
1091 qWarning() << "Unexpected series type";
1092 break;
1093 }
1094 }
1095 }
1096
1097 // Make sure series animations are reset when axes change
1098 AbstractBarChartItem *item = qobject_cast<AbstractBarChartItem *>(object: m_item.data());
1099 if (item)
1100 item->resetAnimation();
1101}
1102
1103QAbstractAxis::AxisType QAbstractBarSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
1104{
1105 Q_Q(const QAbstractBarSeries);
1106
1107 switch (q->type()) {
1108 case QAbstractSeries::SeriesTypeHorizontalBar:
1109 case QAbstractSeries::SeriesTypeHorizontalPercentBar:
1110 case QAbstractSeries::SeriesTypeHorizontalStackedBar:
1111 if (orientation == Qt::Vertical)
1112 return QAbstractAxis::AxisTypeBarCategory;
1113 break;
1114 case QAbstractSeries::SeriesTypeBar:
1115 case QAbstractSeries::SeriesTypePercentBar:
1116 case QAbstractSeries::SeriesTypeStackedBar:
1117 case QAbstractSeries::SeriesTypeBoxPlot:
1118 case QAbstractSeries::SeriesTypeCandlestick:
1119 if (orientation == Qt::Horizontal)
1120 return QAbstractAxis::AxisTypeBarCategory;
1121 break;
1122 default:
1123 qWarning() << "Unexpected series type";
1124 break;
1125 }
1126 return QAbstractAxis::AxisTypeValue;
1127
1128}
1129
1130void QAbstractBarSeriesPrivate::handleSetValueChange(int index)
1131{
1132 QBarSetPrivate *priv = qobject_cast<QBarSetPrivate *>(object: sender());
1133 if (priv)
1134 emit setValueChanged(index, barset: priv->q_ptr);
1135}
1136
1137void QAbstractBarSeriesPrivate::handleSetValueAdd(int index, int count)
1138{
1139 QBarSetPrivate *priv = qobject_cast<QBarSetPrivate *>(object: sender());
1140 if (priv)
1141 emit setValueAdded(index, count, barset: priv->q_ptr);
1142}
1143
1144void QAbstractBarSeriesPrivate::handleSetValueRemove(int index, int count)
1145{
1146 QBarSetPrivate *priv = qobject_cast<QBarSetPrivate *>(object: sender());
1147 if (priv)
1148 emit setValueRemoved(index, count, barset: priv->q_ptr);
1149}
1150
1151void QAbstractBarSeriesPrivate::populateCategories(QBarCategoryAxis *axis)
1152{
1153 QStringList categories;
1154 if (axis->categories().isEmpty()) {
1155 for (int i(1); i < categoryCount() + 1; i++)
1156 categories << presenter()->numberToString(value: i);
1157 axis->append(categories);
1158 }
1159}
1160
1161QAbstractAxis* QAbstractBarSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
1162{
1163 if (defaultAxisType(orientation) == QAbstractAxis::AxisTypeBarCategory)
1164 return new QBarCategoryAxis;
1165 else
1166 return new QValueAxis;
1167}
1168
1169void QAbstractBarSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
1170{
1171 m_blockBarUpdate = true; // Ensures that the bars are not updated before the theme is ready
1172
1173 const QList<QGradient> gradients = theme->seriesGradients();
1174
1175 // Since each bar series uses different number of colors, we need to account for other
1176 // bar series in the chart that are also themed when choosing colors.
1177 // First series count is used to determine the color stepping to keep old applications
1178 // with single bar series with a lot of sets colored as they always have been.
1179 int actualIndex = 0;
1180 int firstSeriesSetCount = m_barSets.count();
1181 if (!m_item.isNull()) {
1182 auto seriesMap = m_item->themeManager()->seriesMap();
1183 int lowestSeries = index;
1184 for (auto it = seriesMap.cbegin(), end = seriesMap.cend(); it != end; ++it) {
1185 if (it.value() != index) {
1186 auto barSeries = qobject_cast<QAbstractBarSeries *>(object: it.key());
1187 if (barSeries) {
1188 actualIndex += barSeries->count();
1189 if (it.value() < lowestSeries) {
1190 firstSeriesSetCount = qMax(a: barSeries->count(), b: gradients.count());
1191 lowestSeries = it.value();
1192 }
1193 }
1194 }
1195 }
1196 }
1197
1198 qreal takeAtPos = 0.5;
1199 qreal step = 0.2;
1200 if (firstSeriesSetCount > 1) {
1201 step = 1.0 / qreal(firstSeriesSetCount);
1202 if (firstSeriesSetCount % gradients.count())
1203 step *= gradients.count();
1204 else
1205 step *= (gradients.count() - 1);
1206 if (index > 0) {
1207 // Take necessary amount of initial steps
1208 int initialStepper = actualIndex;
1209 while (initialStepper > gradients.count()) {
1210 initialStepper -= gradients.count();
1211 takeAtPos += step;
1212 if (takeAtPos == 1.0)
1213 takeAtPos += step;
1214 takeAtPos -= int(takeAtPos);
1215 }
1216 }
1217 }
1218
1219 for (int i(0); i < m_barSets.count(); i++) {
1220 int colorIndex = (actualIndex + i) % gradients.count();
1221 if ((actualIndex + i) > 0 && (actualIndex + i) % gradients.count() == 0) {
1222 // There is no dedicated base color for each sets, generate more colors
1223 takeAtPos += step;
1224 if (takeAtPos == 1.0)
1225 takeAtPos += step;
1226 takeAtPos -= (int) takeAtPos;
1227 }
1228 if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_brush)
1229 m_barSets.at(i)->setBrush(ChartThemeManager::colorAt(gradient: gradients.at(i: colorIndex), pos: takeAtPos));
1230
1231 // Pick label color from the opposite end of the gradient.
1232 // 0.3 as a boundary seems to work well.
1233 if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_labelBrush) {
1234 if (takeAtPos < 0.3)
1235 m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradient: gradients.at(i: actualIndex % gradients.size()), pos: 1));
1236 else
1237 m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradient: gradients.at(i: actualIndex % gradients.size()), pos: 0));
1238 }
1239 if (forced || QChartPrivate::defaultPen() == m_barSets.at(i)->d_ptr->m_pen) {
1240 QColor c = ChartThemeManager::colorAt(gradient: gradients.at(i: actualIndex % gradients.size()), pos: 0.0);
1241 m_barSets.at(i)->setPen(c);
1242 }
1243 }
1244 m_blockBarUpdate = false;
1245 emit updatedBars();
1246}
1247
1248void QAbstractBarSeriesPrivate::initializeAnimations(QChart::AnimationOptions options, int duration,
1249 QEasingCurve &curve)
1250{
1251 AbstractBarChartItem *bar = static_cast<AbstractBarChartItem *>(m_item.data());
1252 Q_ASSERT(bar);
1253 if (bar->animation())
1254 bar->animation()->stopAndDestroyLater();
1255
1256 if (options.testFlag(flag: QChart::SeriesAnimations))
1257 bar->setAnimation(new BarAnimation(bar, duration, curve));
1258 else
1259 bar->setAnimation(0);
1260 QAbstractSeriesPrivate::initializeAnimations(options, duration, curve);
1261}
1262
1263QT_CHARTS_END_NAMESPACE
1264
1265#include "moc_qabstractbarseries.cpp"
1266#include "moc_qabstractbarseries_p.cpp"
1267

source code of qtcharts/src/charts/barchart/qabstractbarseries.cpp