1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtGraphs/qabstractseries.h>
5#include <QtGraphs/qbarseries.h>
6#include <QtGraphs/qbarset.h>
7#include <private/qabstractseries_p.h>
8#include <private/qbarseries_p.h>
9#include <private/qbarset_p.h>
10#include <private/qgraphsview_p.h>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \class QBarSeries
16 \inmodule QtGraphs
17 \ingroup graphs_2D
18 \brief The QBarSeries class presents data in bar graphs.
19
20 This class draws data by default as a series of bars grouped by category,
21 with one bar per category from each bar set added to the series.
22 It also supports horizontal bars and grouping bars as stacked.
23
24 A bar series needs the GraphsView x-axis to be set to a BarCategoryAxis and
25 the y-axis set to ValueAxis.
26
27 \sa QBarSet, QAbstractSeries
28*/
29/*!
30 \qmltype BarSeries
31 \nativetype QBarSeries
32 \inqmlmodule QtGraphs
33 \ingroup graphs_qml_2D
34 \inherits AbstractSeries
35
36 \brief Presents data in bar graphs.
37
38 Draws data by default as a series of bars grouped by category,
39 with one bar per category from each bar set added to the series.
40 It also supports horizontal bars and grouping bars as stacked.
41*/
42
43/*!
44 \property QBarSeries::barWidth
45 \brief The width of the bars of the series.
46
47 The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative
48 values are treated as zero. Setting the width to zero means that the width of the bar on the
49 screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled
50 using the x-axis scale.
51
52 By default, the barWidth is 0.5 (bars will take 50% of the available width).
53 The valid values range from 0.0 (0%) to 1.0 (100%).
54
55 \note When used with QBarSeries, this value specifies the width of a group of bars instead of
56 that of a single bar.
57 \sa QBarSeries
58*/
59
60/*!
61 \enum QBarSeries::BarsType
62
63 This enum value describes the type of the bar series:
64
65 \value Groups Bar sets are grouped by category.
66 \value Stacked Bar sets are stacked after each other by category.
67 \value StackedPercent Bar sets are stacked after each other by category.
68 The segment size corresponds to the percentage of the segment value
69 compared with the total value of all segments in the stack.
70*/
71/*!
72 \property QBarSeries::barsType
73 \brief The type of the bar series.
74*/
75/*!
76 \qmlproperty enumeration BarSeries::barsType
77
78 The type of the bar series:
79
80 \value BarSeries.BarsType.Groups
81 Bar sets are grouped by category. This is the default value.
82 \value BarSeries.BarsType.Stacked
83 Bar sets are stacked after each other by category.
84 \value BarSeries.BarsType.StackedPercent
85 Bar sets are stacked after each other by category. The segment size corresponds
86 to the percentage of the segment value compared with the total value of all
87 segments in the stack.
88*/
89
90/*!
91 \qmlproperty real BarSeries::barWidth
92 The unit of width is the unit of the x-axis. The minimum width for bars is zero, and negative
93 values are treated as zero. Setting the width to zero means that the width of the bar on the
94 screen is one pixel regardless of the scale of the x-axis. Bars wider than zero are scaled
95 using the x-axis scale.
96
97 By default, the barWidth is 0.5 (bars will take 50% of the available width).
98 The valid values range from 0.0 (0%) to 1.0 (100%).
99
100 \note When used with the BarSeries type, this value specifies the width of a group of bars
101 instead of that of a single bar.
102*/
103
104/*!
105 \property QBarSeries::count
106 \brief The number of bar sets in a bar series.
107*/
108/*!
109 \qmlproperty int BarSeries::count
110 The number of bar sets in a bar series.
111*/
112
113/*!
114 \property QBarSeries::labelsVisible
115 \brief The visibility of the labels in a bar series.
116 The default label visibility is \c false.
117*/
118/*!
119 \qmlproperty bool BarSeries::labelsVisible
120 The visibility of the labels in a bar series.
121 The default label visibility is \c false.
122*/
123
124/*!
125 \property QBarSeries::labelsFormat
126 \brief The format used for showing labels in a bar series.
127
128 QBarSeries supports the following format tag:
129 \table
130 \row
131 \li @value \li The value of the bar
132 \endtable
133
134 For example, the following usage of the format tags would produce labels that show the value
135 followed by the unit (u):
136 \code
137 series->setLabelsFormat("@value u");
138 \endcode
139
140 By default, the labels show the value of the bar. For the percent bar series, \e % is added
141 after the value. The labels are shown on the plot area, if the bars are close to each other,
142 the labels may overlap.
143
144 \sa labelsVisible, labelsPosition, labelsPrecision
145*/
146/*!
147 \qmlproperty string BarSeries::labelsFormat
148 The format used for showing labels in a bar series.
149
150 \sa QBarSeries::labelsFormat, labelsVisible, labelsPosition
151*/
152
153/*!
154 \enum QBarSeries::LabelsPosition
155
156 This enum value describes the position of the data value labels:
157
158 \value Center Label is located in the center of the bar.
159 \value InsideEnd Label is located inside the bar at the top.
160 \value InsideBase Label is located inside the bar at the bottom.
161 \value OutsideEnd Label is located outside the bar at the top.
162*/
163
164/*!
165 \property QBarSeries::labelsPosition
166 \brief The position of value labels.
167
168 \sa labelsVisible, labelsFormat
169*/
170/*!
171 \qmlproperty enumeration BarSeries::labelsPosition
172
173 The position of the data value labels:
174
175 \value BarSeries.LabelsPosition.Center
176 Label is located in the center of the bar.
177 \value BarSeries.LabelsPosition.InsideEnd
178 Label is located inside the bar at the top.
179 \value BarSeries.LabelsPosition.InsideBase
180 Label is located inside the bar at the bottom.
181 \value BarSeries.LabelsPosition.OutsideEnd
182 Label is located outside the bar at the top.
183
184 \sa labelsVisible, labelsFormat
185*/
186
187/*!
188 \property QBarSeries::labelsMargin
189 \brief The margin of the value labels in pixels.
190
191 This margin from side is used when \l labelsPosition is set to something else
192 than \c LabelsPosition.Center. The default value is \c 0.
193*/
194/*!
195 \qmlproperty real BarSeries::labelsMargin
196 The margin of the value labels in pixels.
197
198 This margin from side is used when \l labelsPosition is set to something else
199 than \c LabelsPosition.Center. The default value is \c 0.
200*/
201
202/*!
203 \property QBarSeries::labelsAngle
204 \brief The angle of the value labels in degrees.
205*/
206/*!
207 \qmlproperty real BarSeries::labelsAngle
208 The angle of the value labels in degrees.
209*/
210
211/*!
212 \property QBarSeries::labelsPrecision
213 \brief The maximum amount of significant digits shown in value labels.
214
215 Default value is 6.
216*/
217/*!
218 \qmlproperty real BarSeries::labelsPrecision
219 The maximum amount of significant digits shown in value labels.
220
221 Default value is 6.
222*/
223
224/*!
225 \property QBarSeries::barDelegate
226 \brief A custom QML component used for visualizing each of the bars.
227 Instance of this component is created for each of the bar.
228 When this is not defined, a default rectangle visualization for bars is used.
229
230 The dynamic properties available for this component are:
231
232 \table
233 \header
234 \li Type
235 \li Name
236 \li Description
237 \row
238 \li QColor
239 \li barColor
240 \li The fill color of the bar. This value comes either from the \l QGraphsTheme
241 or from \l{QBarSet::color} if the \l QBarSet overrides the color.
242 \row
243 \li QColor
244 \li barBorderColor
245 \li The border color of the bar. This value comes either from the \l QGraphsTheme
246 or from \l{QBarSet::borderColor} if the \l QBarSet overrides the color.
247 \row
248 \li qreal
249 \li barBorderWidth
250 \li The width of the bar border. This value comes either from the \l QGraphsTheme
251 or from \l{QBarSet::borderWidth} if the \l QBarSet overrides the width.
252 \row
253 \li qreal
254 \li barValue
255 \li The value of the bar. This value comes from the \l{QBarSet::values}.
256 \row
257 \li QString
258 \li barLabel
259 \li The label of the bar. This value comes from the \l{QBarSet::label}.
260 \row
261 \li bool
262 \li barSelected
263 \li This value is true when the bar is selected, meaning that the bar index
264 is in \l{QBarSet::selectedBars}.
265 \endtable
266
267 To use any of these, add property with the defined name into your custom component.
268 For example \c{"property color barColor"} and \c{"property real barValue"}.
269*/
270/*!
271 \qmlproperty Component BarSeries::barDelegate
272 A custom QML component used for visualizing each of the bars.
273 Instance of this component is created for each of the bar.
274 When this is not defined, a default rectangle visualization for bars is used.
275
276 The dynamic properties available for this component are:
277
278 \table
279 \header
280 \li Type
281 \li Name
282 \li Description
283 \row
284 \li color
285 \li barColor
286 \li The fill color of the bar. This value comes either from the \l GraphsTheme
287 or from \l{BarSet::color} if the \l BarSet overrides the color.
288 \row
289 \li color
290 \li barBorderColor
291 \li The border color of the bar. This value comes either from the \l GraphsTheme
292 or from \l{BarSet::borderColor} if the \l BarSet overrides the color.
293 \row
294 \li real
295 \li barBorderWidth
296 \li The width of the bar border. This value comes either from the \l GraphsTheme
297 or from \l{BarSet::borderWidth} if the \l BarSet overrides the width.
298 \row
299 \li real
300 \li barValue
301 \li The value of the bar. This value comes from the \l{BarSet::values}.
302 \row
303 \li string
304 \li barLabel
305 \li The label of the bar. This value comes from the \l{BarSet::label}.
306 \row
307 \li bool
308 \li barSelected
309 \li This value is true when the bar is selected, meaning that the bar index
310 is in \l{BarSet::selectedBars}.
311 \endtable
312
313 To use any of these, add property with the defined name into your custom component.
314 For example \c{"property color barColor"} and \c{"property real barValue"}.
315*/
316
317/*!
318 \property QBarSeries::barSets
319 \brief A list of sets added to the series.
320 */
321/*!
322 \qmlproperty list<BarSet> BarSeries::barSets
323 A list of sets added to the series.
324*/
325
326/*!
327 \fn void QBarSeries::updatedBars()
328 This signal is emitted when bars are updated.
329*/
330
331/*!
332 \fn void QBarSeries::labelsVisibleChanged(bool visible)
333 This signal is emitted when the labels' visibility changes to \a visible.
334 \sa labelsVisible(), setLabelsVisible()
335*/
336
337/*!
338 \fn void QBarSeries::barsetsAdded(const QList<QBarSet *> &sets)
339 This signal is emitted when the bar sets specified by \a sets are added to the series.
340 \sa append(), insert()
341*/
342/*!
343 \qmlsignal BarSeries::barsetsAdded()
344 This signal is emitted when bar sets are added to the series.
345*/
346
347/*!
348 \fn void QBarSeries::barsetsRemoved(const QList<QBarSet *> &sets)
349 This signal is emitted when the bar sets specified by \a sets are removed from the series.
350 \sa remove()
351*/
352/*!
353 \qmlsignal BarSeries::barsetsRemoved()
354 This signal is emitted when bar sets are removed from the series.
355*/
356
357/*!
358 \fn void QBarSeries::setValueChanged(qsizetype index, QBarSet *barset)
359 This signal is emitted when a barset's value is changed. \a index is the index of
360 the barset in the series. The \a barset is a pointer to the changed set.
361*/
362/*!
363 \fn void QBarSeries::setValueAdded(qsizetype index, qsizetype count, QBarSet *barset)
364 This signal is emitted when a barset's value is changed. \a index is the index of
365 the barset in the series. The number of the added values is indicated \a count.
366 The \a barset is a pointer to the changed set.
367*/
368/*!
369 \fn void QBarSeries::setValueRemoved(qsizetype index, qsizetype count, QBarSet *barset)
370 This signal is emitted when a barset's value is changed. \a index is the index of
371 the barset in the series. The number of the removed values is indicated \a count.
372 The \a barset is a pointer to the changed set.
373*/
374
375/*!
376 \qmlmethod BarSet BarSeries::at(int index)
377 Returns the bar set at \a index. Returns null if the index is not valid.
378*/
379
380/*!
381 \qmlmethod BarSet BarSeries::insert(int index, string label, VariantList values)
382 Adds a new bar set with \a label and \a values to \a index. \a values can be a list
383 of real values or a list of XYPoint types.
384
385 If the index value is equal to or less than zero, the new bar set is prepended to the bar
386 series. If the index value is equal to or greater than the number of bar sets in the bar
387 series, the new bar set is appended to the bar series.
388
389 \sa append()
390*/
391
392/*!
393 \qmlmethod bool BarSeries::remove(BarSet barset)
394 Removes the bar set specified by \a barset from the series. Returns \c true if successful,
395 \c false otherwise.
396*/
397
398/*!
399 \qmlmethod BarSeries::clear()
400 Removes all bar sets from the series.
401*/
402
403/*!
404 \qmlmethod bool BarSeries::replace(int index, BarSet barset)
405 Replaces the bar set at the position specified by \a index from the series and replaces it
406 with \a barset. Returns \c true if successful, \c false otherwise.
407*/
408
409/*!
410 \qmlmethod Barset BarSeries::at(int index)
411 Returns the bar set specified by \a index from the series. Returns \c null otherwise.
412*/
413
414/*!
415 \qmlmethod int BarSeries::find(BarSet barset)
416 Returns the index of the bar set specified by \a barset from the series. Returns \c -1 if
417 not found.
418*/
419
420/*!
421 \qmlmethod BarSeries::removeMultiple(int index, int count)
422 Removes a range of bar sets as specified by the \a index and \a count. The call
423 traverses over all sets even if removal of one fails.
424*/
425
426/*!
427 \qmlmethod bool BarSeries::remove(int index)
428 Removes the bar set specified by \a index from the series. Returns \c true if the
429 removal was successful, \c false otherwise.
430*/
431
432/*!
433 \qmlmethod bool BarSeries::replace(BarSet oldSet, BarSet newSet)
434 Replaces the bar set specified by \a oldSet with newSet. Returns \c true if the
435 removal was successful, \c false otherwise. \a oldSet is destroyed if this
436 is successful.
437*/
438
439/*!
440 \qmlmethod bool BarSeries::replace(list<BarSet> sets)
441 Completely replaces all current bar set with \a sets. The size does not need
442 to match. Returns false if any of the bar set in \a sets are invalid.
443*/
444
445/*!
446 \internal
447*/
448
449/*!
450 Constructs an empty bar series that is a QObject and a child of \a parent.
451*/
452QBarSeries::QBarSeries(QObject *parent)
453 : QAbstractSeries(*(new QBarSeriesPrivate()), parent)
454{}
455
456QBarSeries::~QBarSeries() {}
457
458QBarSeries::QBarSeries(QBarSeriesPrivate &dd, QObject *parent)
459 : QAbstractSeries(dd, parent)
460{}
461
462/*!
463 Returns the bar series.
464*/
465QAbstractSeries::SeriesType QBarSeries::type() const
466{
467 return QAbstractSeries::SeriesType::Bar;
468}
469
470/*!
471 \property QBarSeries::seriesColors
472 \brief The list of base colors to be used for all the objects in the series.
473
474 If there are more series than colors, the color list wraps and starts again
475 with the first color in the list. If this is not set (default), colors
476 from the \l{QGraphsTheme::seriesColors} will be used.
477*/
478/*!
479 \qmlproperty list<color> BarSeries::seriesColors
480 The list of base colors to be used for all the objects in the series.
481
482 If there are more series than colors, the color list wraps and starts again
483 with the first color in the list. If this is not set (default), colors
484 from the \l{GraphsTheme::seriesColors} will be used.
485*/
486QList<QColor> QBarSeries::seriesColors() const
487{
488 Q_D(const QBarSeries);
489 return d->m_seriesColors;
490}
491
492void QBarSeries::setSeriesColors(const QList<QColor> &newSeriesColors)
493{
494 Q_D(QBarSeries);
495 if (d->m_seriesColors == newSeriesColors)
496 return;
497 d->m_seriesColors = newSeriesColors;
498 emit seriesColorsChanged();
499 emit update();
500}
501
502/*!
503 \property QBarSeries::borderColors
504 \brief The list of border colors to be used for all the objects in the series.
505
506 If there are more series than colors, the color list wraps and starts again
507 with the first color in the list. If this is not set (default), colors
508 from the \l{QGraphsTheme::borderColors} will be used.
509*/
510/*!
511 \qmlproperty list<color> BarSeries::borderColors
512 The list of border colors to be used for all the objects in the series.
513
514 If there are more series than colors, the color list wraps and starts again
515 with the first color in the list. If this is not set (default), colors
516 from the \l{GraphsTheme::borderColors} will be used.
517*/
518QList<QColor> QBarSeries::borderColors() const
519{
520 Q_D(const QBarSeries);
521 return d->m_borderColors;
522}
523
524void QBarSeries::setBorderColors(const QList<QColor> &newBorderColors)
525{
526 Q_D(QBarSeries);
527 if (d->m_borderColors == newBorderColors)
528 return;
529 d->m_borderColors = newBorderColors;
530 emit borderColorsChanged();
531 emit update();
532}
533
534void QBarSeries::setBarsType(QBarSeries::BarsType type)
535{
536 Q_D(QBarSeries);
537 if (d->m_barsType != type) {
538 d->m_barsType = type;
539 emit barsTypeChanged(type);
540 emit update();
541 }
542}
543
544QBarSeries::BarsType QBarSeries::barsType() const
545{
546 Q_D(const QBarSeries);
547 return d->m_barsType;
548}
549
550/*!
551 Sets the width of the bars of the series to \a width.
552*/
553void QBarSeries::setBarWidth(qreal width)
554{
555 Q_D(QBarSeries);
556 if (d->barWidth() != width) {
557 d->setBarWidth(width);
558 emit barWidthChanged();
559 }
560}
561
562/*!
563 Returns the width of the bars of the series.
564 \sa setBarWidth()
565*/
566qreal QBarSeries::barWidth() const
567{
568 Q_D(const QBarSeries);
569 return d->barWidth();
570}
571
572/*!
573 Adds a set of bars specified by \a set to the bar series and takes ownership of it. If the set
574 is null or it already belongs to the series, it will not be appended.
575 Returns \c true if appending succeeded.
576*/
577bool QBarSeries::append(QBarSet *set)
578{
579 Q_D(QBarSeries);
580 bool success = d->append(set);
581 if (success) {
582 QList<QBarSet *> sets;
583 sets.append(t: set);
584 set->setParent(this);
585 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
586 emit barsetsAdded(sets);
587 emit countChanged();
588 emit update();
589 }
590 return success;
591}
592
593/*!
594 Removes the bar set specified by \a set from the series and permanently deletes it if
595 the removal succeeds. Returns \c true if the set was removed.
596*/
597bool QBarSeries::remove(QBarSet *set)
598{
599 Q_D(QBarSeries);
600 bool success = d->remove(set);
601 if (success) {
602 QList<QBarSet *> sets;
603 sets.append(t: set);
604 set->setParent(0);
605 QObject::disconnect(sender: set, signal: &QBarSet::update, receiver: this, slot: &QBarSeries::update);
606 emit barsetsRemoved(sets);
607 emit countChanged();
608 emit update();
609 delete set;
610 set = 0;
611 }
612 return success;
613}
614
615/*!
616 Takes a single \a set from the series. Does not delete the bar set object.
617 \note The series remains the barset's parent object. You must set the
618 parent object to take full ownership.
619
620 Returns \c true if the take operation succeeds.
621*/
622bool QBarSeries::take(QBarSet *set)
623{
624 Q_D(QBarSeries);
625 bool success = d->remove(set);
626 if (success) {
627 QList<QBarSet *> sets;
628 sets.append(t: set);
629 QObject::disconnect(sender: set, signal: &QBarSet::update, receiver: this, slot: &QBarSeries::update);
630 emit barsetsRemoved(sets);
631 emit countChanged();
632 emit update();
633 }
634 return success;
635}
636
637/*!
638 Adds a list of bar sets specified by \a sets to a bar series and takes ownership of the sets.
639 Returns \c true if all sets were appended successfully. If any of the sets is null or was
640 previously appended to the series, nothing is appended and this function returns \c false.
641 If any of the sets appears in the list more than once, nothing is appended and this function
642 returns \c false.
643*/
644bool QBarSeries::append(const QList<QBarSet *> &sets)
645{
646 Q_D(QBarSeries);
647 if (!d->append(sets))
648 return false;
649
650 for (auto *set : sets) {
651 set->setParent(this);
652 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
653 }
654
655 emit barsetsAdded(sets);
656 emit countChanged();
657 emit update();
658 return true;
659}
660
661/*!
662 Inserts a bar set specified by \a set to a series at the position specified by \a index
663 and takes ownership of the set. If the set is null or already belongs to the series, it will
664 not be appended. Returns \c true if inserting succeeds.
665*/
666bool QBarSeries::insert(qsizetype index, QBarSet *set)
667{
668 Q_D(QBarSeries);
669 bool success = d->insert(index, set);
670 if (success) {
671 QList<QBarSet *> sets;
672 sets.append(t: set);
673 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
674 emit barsetsAdded(sets);
675 emit countChanged();
676 emit update();
677 }
678 return success;
679}
680
681/*!
682 Removes all bar sets from the series and permanently deletes them.
683*/
684void QBarSeries::clear()
685{
686 Q_D(QBarSeries);
687 const QList<QBarSet *> sets = barSets();
688 bool success = d->remove(sets);
689 if (success) {
690 emit barsetsRemoved(sets);
691 emit countChanged();
692 for (QBarSet *set : sets) {
693 QObject::disconnect(sender: set, signal: &QBarSet::update, receiver: this, slot: &QBarSeries::update);
694 set->deleteLater();
695 }
696 emit update();
697 }
698}
699
700/*!
701 Replaces the BarSet which is present at \a index with \a set.
702 The original BarSet will be permanently deleted.
703*/
704void QBarSeries::replace(qsizetype index, QBarSet *set)
705{
706 Q_D(QBarSeries);
707
708 if (d->m_barSets.size() <= index)
709 return;
710 if (!set)
711 return;
712 if (index < 0)
713 index = 0;
714
715 remove(set: d->m_barSets[index]);
716 d->insert(index, set);
717
718 QList<QBarSet *> sets;
719 sets.append(t: set);
720 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
721 emit barsetsReplaced(sets);
722}
723
724/*!
725 Retrieves the BarSet specified at the location \a index.
726 Returns null if no BarSet was found.
727*/
728QBarSet *QBarSeries::at(qsizetype index)
729{
730 Q_D(QBarSeries);
731
732 if (d->m_barSets.size() <= index)
733 return nullptr;
734 if (index < 0)
735 return nullptr;
736
737 return d->m_barSets[index];
738}
739
740/*!
741 Returns the index of the first BarSet found as defined by \a set. Returns -1 if no BarSet was found.
742*/
743qsizetype QBarSeries::find(QBarSet *set) const
744{
745 Q_D(const QBarSeries);
746
747 for (qsizetype i = 0; i < d->m_barSets.size(); ++i) {
748 if (set == d->m_barSets[i])
749 return i;
750 }
751
752 return -1;
753}
754
755/*!
756 Removes multiple BarSets from the series starting from \a index to a number of \a count.
757 The BarSets will be permanently deleted.
758*/
759void QBarSeries::removeMultiple(qsizetype index, qsizetype count)
760{
761 Q_D(QBarSeries);
762
763 if (index + count >= d->m_barSets.size())
764 return;
765 if (index < 0 || count < 0)
766 return;
767
768 for (qsizetype i = index; i < index + count; ++i)
769 remove(set: d->m_barSets[index]);
770}
771
772/*!
773 Removes the BarSet at the location \a index. The BarSet will be permanently deleted.
774*/
775bool QBarSeries::remove(qsizetype index)
776{
777 Q_D(QBarSeries);
778
779 if (index >= d->m_barSets.size())
780 return false;
781 if (index < 0)
782 return false;
783
784 return remove(set: d->m_barSets[index]);
785}
786
787/*!
788 Replaces the BarSet specified by \a oldValue with the one in \a newValue. The BarSet
789 in \a oldValue will be permanently deleted if found inside the series. Returns \c true if
790 the replace is successful.
791*/
792bool QBarSeries::replace(QBarSet *oldValue, QBarSet *newValue)
793{
794 Q_D(QBarSeries);
795
796 if (!oldValue || !newValue)
797 return false;
798 if (oldValue == newValue)
799 return false;
800
801 for (qsizetype i = 0; i < d->m_barSets.size(); ++i) {
802 if (d->m_barSets[i] == oldValue) {
803 remove(set: d->m_barSets[i]);
804 d->insert(index: i, set: newValue);
805
806 QList<QBarSet *> sets;
807 sets.append(t: newValue);
808 QObject::connect(sender: newValue, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
809 emit barsetsReplaced(sets);
810 return true;
811 }
812 }
813
814 return false;
815}
816
817/*!
818 Replaces the entire BarSet list inside of this BarSeries with the BarSets specified by \a sets.
819 All of the original BarSets will be permanently deleted. Returns \c true if all BarSets are replaced.
820*/
821bool QBarSeries::replace(const QList<QBarSet *> &sets)
822{
823 Q_D(QBarSeries);
824
825 for (const auto set : sets) {
826 if (!set)
827 return false;
828 }
829
830 for (const auto set : d->m_barSets) {
831 remove(set);
832 }
833
834 for (const auto set : sets) {
835 QObject::connect(sender: set, signal: &QBarSet::update, context: this, slot: &QBarSeries::update);
836 }
837
838 d->append(sets);
839 emit barsetsReplaced(sets);
840
841 return true;
842}
843
844/*!
845 Returns the number of bar sets in a bar series.
846*/
847qsizetype QBarSeries::count() const
848{
849 Q_D(const QBarSeries);
850 return d->m_barSets.size();
851}
852
853/*!
854 Returns a list of bar sets in a bar series. Keeps the ownership of the bar sets.
855 */
856QList<QBarSet *> QBarSeries::barSets() const
857{
858 Q_D(const QBarSeries);
859 return d->m_barSets;
860}
861
862/*!
863 Sets the visibility of labels in a bar series to \a visible.
864*/
865void QBarSeries::setLabelsVisible(bool visible)
866{
867 Q_D(QBarSeries);
868 if (d->m_labelsVisible != visible) {
869 d->setLabelsVisible(visible);
870 emit labelsVisibleChanged(visible);
871 emit update();
872 }
873}
874
875/*!
876 Returns the visibility of labels.
877*/
878bool QBarSeries::labelsVisible() const
879{
880 Q_D(const QBarSeries);
881 return d->m_labelsVisible;
882}
883
884void QBarSeries::setLabelsFormat(const QString &format)
885{
886 Q_D(QBarSeries);
887 if (d->m_labelsFormat != format) {
888 d->m_labelsFormat = format;
889 d->setLabelsDirty(true);
890 emit labelsFormatChanged(format);
891 emit update();
892 }
893}
894
895QString QBarSeries::labelsFormat() const
896{
897 Q_D(const QBarSeries);
898 return d->m_labelsFormat;
899}
900
901void QBarSeries::setLabelsMargin(qreal margin)
902{
903 Q_D(QBarSeries);
904 if (d->m_labelsMargin != margin) {
905 d->m_labelsMargin = margin;
906 d->setLabelsDirty(true);
907 emit labelsMarginChanged(margin);
908 emit update();
909 }
910}
911
912qreal QBarSeries::labelsMargin() const
913{
914 Q_D(const QBarSeries);
915 return d->m_labelsMargin;
916}
917
918void QBarSeries::setLabelsAngle(qreal angle)
919{
920 Q_D(QBarSeries);
921 if (d->m_labelsAngle != angle) {
922 d->m_labelsAngle = angle;
923 d->setLabelsDirty(true);
924 emit labelsAngleChanged(angle);
925 emit update();
926 }
927}
928
929qreal QBarSeries::labelsAngle() const
930{
931 Q_D(const QBarSeries);
932 return d->m_labelsAngle;
933}
934
935void QBarSeries::setLabelsPosition(QBarSeries::LabelsPosition position)
936{
937 Q_D(QBarSeries);
938 if (d->m_labelsPosition != position) {
939 d->m_labelsPosition = position;
940 emit labelsPositionChanged(position);
941 emit update();
942 }
943}
944
945QBarSeries::LabelsPosition QBarSeries::labelsPosition() const
946{
947 Q_D(const QBarSeries);
948 return d->m_labelsPosition;
949}
950
951void QBarSeries::setLabelsPrecision(int precision)
952{
953 Q_D(QBarSeries);
954 if (d->m_labelsPrecision != precision) {
955 d->m_labelsPrecision = precision;
956 d->setLabelsDirty(true);
957 emit labelsPrecisionChanged(precision);
958 emit update();
959 }
960}
961
962int QBarSeries::labelsPrecision() const
963{
964 Q_D(const QBarSeries);
965 return d->m_labelsPrecision;
966}
967
968QQmlComponent *QBarSeries::barDelegate() const
969{
970 Q_D(const QBarSeries);
971 return d->m_barDelegate;
972}
973
974void QBarSeries::setBarDelegate(QQmlComponent *newBarDelegate)
975{
976 Q_D(QBarSeries);
977 if (d->m_barDelegate == newBarDelegate)
978 return;
979 d->m_barDelegate = newBarDelegate;
980 d->m_barDelegateDirty = true;
981 emit barDelegateChanged();
982 emit update();
983}
984
985// Select all the elements in the series
986void QBarSeries::selectAll()
987{
988 Q_D(QBarSeries);
989 for (auto s : d->m_barSets) {
990 s->selectAllBars();
991 }
992}
993
994// Deselect all the elements in the series
995void QBarSeries::deselectAll()
996{
997 Q_D(QBarSeries);
998 for (auto s : d->m_barSets) {
999 s->deselectAllBars();
1000 }
1001}
1002
1003void QBarSeries::componentComplete()
1004{
1005 for (auto *child : children()) {
1006 if (auto bs = qobject_cast<QBarSet *>(object: child))
1007 append(set: bs);
1008 }
1009 QAbstractSeries::componentComplete();
1010}
1011
1012void QBarSeries::handleSetValueChange(qsizetype index)
1013{
1014 QBarSet *set = qobject_cast<QBarSet *>(object: sender());
1015 if (set)
1016 emit setValueChanged(index, barset: set);
1017 emit update();
1018}
1019
1020void QBarSeries::handleSetValueAdd(qsizetype index, qsizetype count)
1021{
1022 QBarSet *set = qobject_cast<QBarSet *>(object: sender());
1023 if (set)
1024 emit setValueAdded(index, count, barset: set);
1025 emit update();
1026}
1027
1028void QBarSeries::handleSetValueRemove(qsizetype index, qsizetype count)
1029{
1030 QBarSet *set = qobject_cast<QBarSet *>(object: sender());
1031 if (set)
1032 emit setValueRemoved(index, count, barset: set);
1033 emit update();
1034}
1035
1036bool QBarSeries::barDelegateDirty() const
1037{
1038 Q_D(const QBarSeries);
1039 return d->m_barDelegateDirty;
1040}
1041
1042void QBarSeries::setBarDelegateDirty(bool dirty)
1043{
1044 Q_D(QBarSeries);
1045 d->m_barDelegateDirty = dirty;
1046}
1047
1048QBarSeriesPrivate::QBarSeriesPrivate()
1049 : m_barWidth(0.5) // Default value is 50% of category width
1050 , m_labelsVisible(false)
1051 , m_visible(true)
1052 , m_blockBarUpdate(false)
1053 , m_labelsFormat()
1054 , m_labelsMargin(0)
1055 , m_labelsAngle(0)
1056 , m_labelsPrecision(6)
1057 , m_labelsDirty(true)
1058 , m_barDelegateDirty(false)
1059{
1060}
1061
1062qsizetype QBarSeriesPrivate::categoryCount() const
1063{
1064 // No categories defined. return count of longest set.
1065 qsizetype count = 0;
1066 for (qsizetype i = 0; i < m_barSets.size(); i++) {
1067 if (m_barSets.at(i)->count() > count)
1068 count = m_barSets.at(i)->count();
1069 }
1070
1071 return count;
1072}
1073
1074void QBarSeriesPrivate::setBarWidth(qreal width)
1075{
1076 Q_Q(QBarSeries);
1077 width = std::clamp<qreal>(val: width, lo: 0.0, hi: 1.0);
1078 if (!qFuzzyCompare(p1: width, p2: m_barWidth)) {
1079 m_barWidth = width;
1080 q->update();
1081 }
1082}
1083
1084qreal QBarSeriesPrivate::barWidth() const
1085{
1086 return m_barWidth;
1087}
1088
1089QBarSet *QBarSeriesPrivate::barsetAt(qsizetype index)
1090{
1091 return m_barSets.at(i: index);
1092}
1093
1094void QBarSeriesPrivate::setVisible(bool visible)
1095{
1096 Q_Q(QBarSeries);
1097 m_visible = visible;
1098 emit q->visibleChanged();
1099}
1100
1101void QBarSeriesPrivate::setLabelsVisible(bool visible)
1102{
1103 m_labelsVisible = visible;
1104}
1105
1106qreal QBarSeriesPrivate::min()
1107{
1108 if (m_barSets.size() <= 0)
1109 return 0;
1110
1111 qreal min = INT_MAX;
1112
1113 for (int i = 0; i < m_barSets.size(); i++) {
1114 qsizetype categoryCount = m_barSets.at(i)->count();
1115 for (qsizetype j = 0; j < categoryCount; j++) {
1116 qreal temp = m_barSets.at(i)->at(index: j);
1117 if (temp < min)
1118 min = temp;
1119 }
1120 }
1121 return min;
1122}
1123
1124qreal QBarSeriesPrivate::max()
1125{
1126 if (m_barSets.size() <= 0)
1127 return 0;
1128
1129 qreal max = INT_MIN;
1130
1131 for (int i = 0; i < m_barSets.size(); i++) {
1132 qsizetype categoryCount = m_barSets.at(i)->count();
1133 for (qsizetype j = 0; j < categoryCount; j++) {
1134 qreal temp = m_barSets.at(i)->at(index: j);
1135 if (temp > max)
1136 max = temp;
1137 }
1138 }
1139
1140 return max;
1141}
1142
1143qreal QBarSeriesPrivate::valueAt(int set, int category)
1144{
1145 if ((set < 0) || (set >= m_barSets.size()))
1146 return 0; // No set, no value.
1147 else if ((category < 0) || (category >= m_barSets.at(i: set)->count()))
1148 return 0; // No category, no value.
1149
1150 return m_barSets.at(i: set)->at(index: category);
1151}
1152
1153qreal QBarSeriesPrivate::percentageAt(int set, int category)
1154{
1155 if ((set < 0) || (set >= m_barSets.size()))
1156 return 0; // No set, no value.
1157 else if ((category < 0) || (category >= m_barSets.at(i: set)->count()))
1158 return 0; // No category, no value.
1159
1160 qreal value = m_barSets.at(i: set)->at(index: category);
1161 qreal sum = categorySum(category);
1162 if (qFuzzyCompare(p1: sum, p2: 0))
1163 return 0;
1164
1165 return value / sum;
1166}
1167
1168qreal QBarSeriesPrivate::categorySum(qsizetype category)
1169{
1170 qreal sum(0);
1171 qsizetype count = m_barSets.size(); // Count sets
1172 for (qsizetype set = 0; set < count; set++) {
1173 if (category < m_barSets.at(i: set)->count())
1174 sum += m_barSets.at(i: set)->at(index: category);
1175 }
1176 return sum;
1177}
1178
1179qreal QBarSeriesPrivate::absoluteCategorySum(int category)
1180{
1181 qreal sum(0);
1182 qsizetype count = m_barSets.size(); // Count sets
1183 for (qsizetype set = 0; set < count; set++) {
1184 if (category < m_barSets.at(i: set)->count())
1185 sum += qAbs(t: m_barSets.at(i: set)->at(index: category));
1186 }
1187 return sum;
1188}
1189
1190qreal QBarSeriesPrivate::maxCategorySum()
1191{
1192 qreal max = INT_MIN;
1193 qsizetype count = categoryCount();
1194 for (qsizetype i = 0; i < count; i++) {
1195 qreal sum = categorySum(category: i);
1196 if (sum > max)
1197 max = sum;
1198 }
1199 return max;
1200}
1201
1202qreal QBarSeriesPrivate::minX()
1203{
1204 if (m_barSets.size() <= 0)
1205 return 0;
1206
1207 qreal min = INT_MAX;
1208
1209 for (int i = 0; i < m_barSets.size(); i++) {
1210 qsizetype categoryCount = m_barSets.at(i)->count();
1211 for (qsizetype j = 0; j < categoryCount; j++) {
1212 qreal temp = m_barSets.at(i)->d_func()->m_values.at(i: j).x();
1213 if (temp < min)
1214 min = temp;
1215 }
1216 }
1217 return min;
1218}
1219
1220qreal QBarSeriesPrivate::maxX()
1221{
1222 if (m_barSets.size() <= 0)
1223 return 0;
1224
1225 qreal max = INT_MIN;
1226
1227 for (int i = 0; i < m_barSets.size(); i++) {
1228 qsizetype categoryCount = m_barSets.at(i)->count();
1229 for (qsizetype j = 0; j < categoryCount; j++) {
1230 qreal temp = m_barSets.at(i)->d_func()->m_values.at(i: j).x();
1231 if (temp > max)
1232 max = temp;
1233 }
1234 }
1235
1236 return max;
1237}
1238
1239qreal QBarSeriesPrivate::categoryTop(qsizetype category)
1240{
1241 // Returns top (sum of all positive values) of category.
1242 // Returns 0, if all values are negative
1243 qreal top(0);
1244 qsizetype count = m_barSets.size();
1245 for (qsizetype set = 0; set < count; set++) {
1246 if (category < m_barSets.at(i: set)->count()) {
1247 qreal temp = m_barSets.at(i: set)->at(index: category);
1248 if (temp > 0) {
1249 top += temp;
1250 }
1251 }
1252 }
1253 return top;
1254}
1255
1256qreal QBarSeriesPrivate::categoryBottom(qsizetype category)
1257{
1258 // Returns bottom (sum of all negative values) of category
1259 // Returns 0, if all values are positive
1260 qreal bottom(0);
1261 qsizetype count = m_barSets.size();
1262 for (qsizetype set = 0; set < count; set++) {
1263 if (category < m_barSets.at(i: set)->count()) {
1264 qreal temp = m_barSets.at(i: set)->at(index: category);
1265 if (temp < 0) {
1266 bottom += temp;
1267 }
1268 }
1269 }
1270 return bottom;
1271}
1272qreal QBarSeriesPrivate::top()
1273{
1274 // Returns top of all categories
1275 qreal top(0);
1276 qsizetype count = categoryCount();
1277 for (qsizetype i = 0; i < count; i++) {
1278 qreal temp = categoryTop(category: i);
1279 if (temp > top)
1280 top = temp;
1281 }
1282 return top;
1283}
1284
1285qreal QBarSeriesPrivate::bottom()
1286{
1287 // Returns bottom of all categories
1288 qreal bottom(0);
1289 qsizetype count = categoryCount();
1290 for (qsizetype i = 0; i < count; i++) {
1291 qreal temp = categoryBottom(category: i);
1292 if (temp < bottom)
1293 bottom = temp;
1294 }
1295 return bottom;
1296}
1297
1298bool QBarSeriesPrivate::blockBarUpdate()
1299{
1300 return m_blockBarUpdate;
1301}
1302
1303bool QBarSeriesPrivate::append(QBarSet *set)
1304{
1305 if ((m_barSets.contains(t: set)) || (set == 0))
1306 return false; // Fail if set is already in list or set is null.
1307
1308 m_barSets.append(t: set);
1309 Q_Q(QBarSeries);
1310 QObject::connect(sender: set, signal: &QBarSet::updatedBars, context: q, slot: &QBarSeries::updatedBars);
1311 QObject::connect(sender: set, signal: &QBarSet::valueChanged, context: q, slot: &QBarSeries::handleSetValueChange);
1312 QObject::connect(sender: set, signal: &QBarSet::valueAdded, context: q, slot: &QBarSeries::handleSetValueAdd);
1313 QObject::connect(sender: set, signal: &QBarSet::valueRemoved, context: q, slot: &QBarSeries::handleSetValueRemove);
1314 QObject::connect(sender: set, signal: &QBarSet::selectedBarsChanged, context: q, slot: &QBarSeries::updatedBars);
1315
1316 return true;
1317}
1318
1319bool QBarSeriesPrivate::remove(QBarSet *set)
1320{
1321 if (!m_barSets.contains(t: set))
1322 return false; // Fail if set is not in list
1323
1324 m_barSets.removeOne(t: set);
1325 Q_Q(QBarSeries);
1326 QObject::disconnect(sender: set, signal: &QBarSet::updatedBars, receiver: q, slot: &QBarSeries::updatedBars);
1327 QObject::disconnect(sender: set, signal: &QBarSet::valueChanged, receiver: q, slot: &QBarSeries::handleSetValueChange);
1328 QObject::disconnect(sender: set, signal: &QBarSet::valueAdded, receiver: q, slot: &QBarSeries::handleSetValueAdd);
1329 QObject::disconnect(sender: set, signal: &QBarSet::valueRemoved, receiver: q, slot: &QBarSeries::handleSetValueRemove);
1330 QObject::disconnect(sender: set, signal: &QBarSet::selectedBarsChanged, receiver: q, slot: &QBarSeries::updatedBars);
1331
1332 return true;
1333}
1334
1335bool QBarSeriesPrivate::append(const QList<QBarSet *> &sets)
1336{
1337 for (auto *set : sets) {
1338 if ((set == 0) || (m_barSets.contains(t: set)))
1339 return false; // Fail if any of the sets is null or is already appended.
1340 if (sets.count(t: set) != 1)
1341 return false; // Also fail if same set is more than once in given list.
1342 }
1343
1344 Q_Q(QBarSeries);
1345 for (auto *set : sets) {
1346 m_barSets.append(t: set);
1347 QObject::connect(sender: set, signal: &QBarSet::updatedBars, context: q, slot: &QBarSeries::updatedBars);
1348 QObject::connect(sender: set, signal: &QBarSet::valueChanged, context: q, slot: &QBarSeries::handleSetValueChange);
1349 QObject::connect(sender: set, signal: &QBarSet::valueAdded, context: q, slot: &QBarSeries::handleSetValueAdd);
1350 QObject::connect(sender: set, signal: &QBarSet::valueRemoved, context: q, slot: &QBarSeries::handleSetValueRemove);
1351 QObject::connect(sender: set, signal: &QBarSet::selectedBarsChanged, context: q, slot: &QBarSeries::updatedBars);
1352 }
1353
1354 return true;
1355}
1356
1357bool QBarSeriesPrivate::remove(const QList<QBarSet *> &sets)
1358{
1359 if (sets.size() == 0)
1360 return false;
1361
1362 for (QBarSet *set : sets) {
1363 if ((set == 0) || (!m_barSets.contains(t: set)))
1364 return false; // Fail if any of the sets is null or is not in series
1365 if (sets.count(t: set) != 1)
1366 return false; // Also fail if same set is more than once in given list.
1367 }
1368
1369 Q_Q(QBarSeries);
1370 for (QBarSet *set : sets) {
1371 m_barSets.removeOne(t: set);
1372 QObject::disconnect(sender: set, signal: &QBarSet::updatedBars, receiver: q, slot: &QBarSeries::updatedBars);
1373 QObject::disconnect(sender: set,
1374 signal: &QBarSet::valueChanged,
1375 receiver: q,
1376 slot: &QBarSeries::handleSetValueChange);
1377 QObject::disconnect(sender: set, signal: &QBarSet::valueAdded, receiver: q, slot: &QBarSeries::handleSetValueAdd);
1378 QObject::disconnect(sender: set,
1379 signal: &QBarSet::valueRemoved,
1380 receiver: q,
1381 slot: &QBarSeries::handleSetValueRemove);
1382 QObject::disconnect(sender: set, signal: &QBarSet::selectedBarsChanged, receiver: q, slot: &QBarSeries::updatedBars);
1383 }
1384
1385 return true;
1386}
1387
1388bool QBarSeriesPrivate::insert(qsizetype index, QBarSet *set)
1389{
1390 if ((m_barSets.contains(t: set)) || (set == 0))
1391 return false; // Fail if set is already in list or set is null.
1392
1393 m_barSets.insert(i: index, t: set);
1394 Q_Q(QBarSeries);
1395 QObject::connect(sender: set, signal: &QBarSet::updatedBars, context: q, slot: &QBarSeries::updatedBars);
1396 QObject::connect(sender: set, signal: &QBarSet::valueChanged, context: q, slot: &QBarSeries::handleSetValueChange);
1397 QObject::connect(sender: set, signal: &QBarSet::valueAdded, context: q, slot: &QBarSeries::handleSetValueAdd);
1398 QObject::connect(sender: set, signal: &QBarSet::valueRemoved, context: q, slot: &QBarSeries::handleSetValueRemove);
1399 QObject::disconnect(sender: set, signal: &QBarSet::selectedBarsChanged, receiver: q, slot: &QBarSeries::updatedBars);
1400
1401 return true;
1402}
1403
1404QT_END_NAMESPACE
1405
1406#include "moc_qbarseries.cpp"
1407

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtgraphs/src/graphs2d/barchart/qbarseries.cpp