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