diff options
author | Sami Varanka <sami.varanka@qt.io> | 2024-05-06 10:06:53 +0300 |
---|---|---|
committer | Sami Varanka <sami.varanka@qt.io> | 2024-05-10 08:59:44 +0300 |
commit | 9aa8d47557f4e89b95622f3f1b03410458140b3d (patch) | |
tree | c3bae96d4cdd971985e55d6f828f7d1187f98b34 | |
parent | be53d4ba6f4437ad9552da268f755f5e51f60ba4 (diff) |
Add PieModelMapper
Task-number: QTBUG-124545
Change-Id: Ia615a85725af1f2ace8c87d2d28bac7b6f8de4e4
Reviewed-by: Kaj Grönholm <kaj.gronholm@qt.io>
-rw-r--r-- | src/graphs2d/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/graphs2d/piechart/qpiemodelmapper.cpp | 628 | ||||
-rw-r--r-- | src/graphs2d/piechart/qpiemodelmapper.h | 72 | ||||
-rw-r--r-- | src/graphs2d/piechart/qpiemodelmapper_p.h | 74 | ||||
-rw-r--r-- | tests/auto/cpp2dtest/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/cpp2dtest/qgpiemodelmapper/CMakeLists.txt | 10 | ||||
-rw-r--r-- | tests/auto/cpp2dtest/qgpiemodelmapper/tst_piemodelmapper.cpp | 565 |
7 files changed, 1351 insertions, 0 deletions
diff --git a/src/graphs2d/CMakeLists.txt b/src/graphs2d/CMakeLists.txt index 3005db6..318cd74 100644 --- a/src/graphs2d/CMakeLists.txt +++ b/src/graphs2d/CMakeLists.txt @@ -12,6 +12,7 @@ qt_internal_extend_target(Graphs linechart/qlineseries.cpp linechart/qlineseries.h linechart/qlineseries_p.h piechart/qpieseries.cpp piechart/qpieseries.h piechart/qpieseries_p.h piechart/qpieslice.cpp piechart/qpieslice.h piechart/qpieslice_p.h + piechart/qpiemodelmapper.cpp piechart/qpiemodelmapper.h piechart/qpiemodelmapper_p.h scatterchart/qscatterseries.cpp scatterchart/qscatterseries.h scatterchart/qscatterseries_p.h xychart/qxyseries.cpp xychart/qxyseries.h xychart/qxyseries_p.h xychart/qxypoint.cpp xychart/qxypoint_p.h diff --git a/src/graphs2d/piechart/qpiemodelmapper.cpp b/src/graphs2d/piechart/qpiemodelmapper.cpp new file mode 100644 index 0000000..4280522 --- /dev/null +++ b/src/graphs2d/piechart/qpiemodelmapper.cpp @@ -0,0 +1,628 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include <QtCore/qabstractitemmodel.h> +#include <QtGraphs/qpiemodelmapper.h> +#include <QtGraphs/qpieseries.h> +#include <private/qpiemodelmapper_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QPieModelMapper + \inmodule QtGraphs + \ingroup graphs_2D + \brief The QPieModelMapper is a model mapper for pie series. + + Model mappers enable using a data model derived from the QAbstractItemModel + class as a data source for a chart. A vertical model mapper is used to create + a connection between a data model and QPieSeries, so that each row in the + data model defines a pie slice and each column maps to the label or the value + of the pie slice. + + Both model and pie series properties can be used to manipulate the data. The + model mapper keeps the pie series and the data model in sync. +*/ +/*! + \qmltype PieModelMapper + \instantiates QPieModelMapper + \inqmlmodule QtGraphs + \ingroup graphs_qml_2D + + \brief Model mapper for pie series. + + Model mappers enable using a data model derived from the QAbstractItemModel + class as a data source for a chart. A vertical model mapper is used to create + a connection between a data model and PieSeries, so that each row in the data + model defines a pie slice and each column maps to the label or the value of + the pie slice. + + Both model and pie series properties can be used to manipulate the data. The + model mapper keeps the pie series and the data model in sync. + + The following QML example creates a pie series with four slices (assuming + the model has at least five rows). Each slice gets a label from column 1 and + a value from column 2. + \code + PieModelMapper { + series: pieSeries + model: customModel + labelsSection: 1 + valuesSection: 2 + firstRow: 1 + rowCount: 4 + } + \endcode +*/ + +QPieModelMapper::~QPieModelMapper() {} + +QPieModelMapper::QPieModelMapper(QObject *parent) + : QObject{*(new QPieModelMapperPrivate), parent} {} + +QPieModelMapper::QPieModelMapper(QPieModelMapperPrivate &dd, QObject *parent) + : QObject(dd, parent) {} + +void QPieModelMapper::onSliceLabelChanged() { + Q_D(QPieModelMapper); + d->onSliceLabelChanged(qobject_cast<QPieSlice *>(sender())); +} + +void QPieModelMapper::onSliceValueChanged() { + Q_D(QPieModelMapper); + d->onSliceValueChanged(qobject_cast<QPieSlice *>(sender())); +} + +QAbstractItemModel *QPieModelMapper::model() const { + const Q_D(QPieModelMapper); + return d->m_model; +} + +void QPieModelMapper::setModel(QAbstractItemModel *model) { + if (model == nullptr) + return; + Q_D(QPieModelMapper); + if (d->m_model) { + QObjectPrivate::disconnect(d->m_model, + &QAbstractItemModel::modelReset, + d, + &QPieModelMapperPrivate::initializePieFromModel); + QObjectPrivate::disconnect(d->m_model, + &QAbstractItemModel::dataChanged, + d, + &QPieModelMapperPrivate::onModelUpdated); + QObjectPrivate::disconnect(d->m_model, + &QAbstractItemModel::rowsInserted, + d, + &QPieModelMapperPrivate::onModelRowsAdded); + QObjectPrivate::disconnect(d->m_model, + &QAbstractItemModel::rowsRemoved, + d, + &QPieModelMapperPrivate::onModelRowsRemoved); + QObjectPrivate::disconnect(d->m_model, + &QAbstractItemModel::columnsInserted, + d, + &QPieModelMapperPrivate::onModelColumnsAdded); + QObjectPrivate::disconnect(d->m_model, + &QAbstractItemModel::columnsRemoved, + d, + &QPieModelMapperPrivate::onModelColumnsRemoved); + QObjectPrivate::disconnect(d->m_model, + &QAbstractItemModel::destroyed, + d, + &QPieModelMapperPrivate::handleModelDestroyed); + } + d->m_model = model; + d->initializePieFromModel(); + + QObjectPrivate::connect(d->m_model, + &QAbstractItemModel::modelReset, + d, + &QPieModelMapperPrivate::initializePieFromModel); + QObjectPrivate::connect(d->m_model, + &QAbstractItemModel::dataChanged, + d, + &QPieModelMapperPrivate::onModelUpdated); + QObjectPrivate::connect(d->m_model, + &QAbstractItemModel::rowsInserted, + d, + &QPieModelMapperPrivate::onModelRowsAdded); + QObjectPrivate::connect(d->m_model, + &QAbstractItemModel::rowsRemoved, + d, + &QPieModelMapperPrivate::onModelRowsRemoved); + QObjectPrivate::connect(d->m_model, + &QAbstractItemModel::columnsInserted, + d, + &QPieModelMapperPrivate::onModelColumnsAdded); + QObjectPrivate::connect(d->m_model, + &QAbstractItemModel::columnsRemoved, + d, + &QPieModelMapperPrivate::onModelColumnsRemoved); + QObjectPrivate::connect(d->m_model, + &QAbstractItemModel::destroyed, + d, + &QPieModelMapperPrivate::handleModelDestroyed); + Q_EMIT modelChanged(); +} + +QPieSeries *QPieModelMapper::series() const { + const Q_D(QPieModelMapper); + return d->m_series; +} + +void QPieModelMapper::setSeries(QPieSeries *series) { + Q_D(QPieModelMapper); + if (d->m_series) { + QObjectPrivate::disconnect(d->m_series, + &QPieSeries::added, + d, + &QPieModelMapperPrivate::onSlicesAdded); + QObjectPrivate::disconnect(d->m_series, + &QPieSeries::removed, + d, + &QPieModelMapperPrivate::onSlicesRemoved); + QObjectPrivate::disconnect(d->m_series, + &QPieSeries::destroyed, + d, + &QPieModelMapperPrivate::handleSeriesDestroyed); + } + + if (series == 0) + return; + + d->m_series = series; + d->initializePieFromModel(); + // connect the signals from the series + QObjectPrivate::connect(d->m_series, + &QPieSeries::added, + d, + &QPieModelMapperPrivate::onSlicesAdded); + QObjectPrivate::connect(d->m_series, + &QPieSeries::removed, + d, + &QPieModelMapperPrivate::onSlicesRemoved); + QObjectPrivate::connect(d->m_series, + &QPieSeries::destroyed, + d, + &QPieModelMapperPrivate::handleSeriesDestroyed); + Q_EMIT seriesChanged(); +} + +int QPieModelMapper::first() const { + Q_D(const QPieModelMapper); + return d->m_first; +} + +void QPieModelMapper::setFirst(int first) { + Q_D(QPieModelMapper); + d->m_first = qMax(first, 0); + d->initializePieFromModel(); + Q_EMIT firstChanged(); +} + +int QPieModelMapper::count() const { + Q_D(const QPieModelMapper); + return d->m_count; +} + +void QPieModelMapper::setCount(int count) { + Q_D(QPieModelMapper); + d->m_count = qMax(count, -1); + d->initializePieFromModel(); + Q_EMIT countChanged(); +} + +Qt::Orientation QPieModelMapper::orientation() const { + Q_D(const QPieModelMapper); + return d->m_orientation; +} + +void QPieModelMapper::setOrientation(Qt::Orientation orientation) { + Q_D(QPieModelMapper); + d->m_orientation = orientation; + d->initializePieFromModel(); + Q_EMIT orientationChanged(); +} + +int QPieModelMapper::valuesSection() const { + Q_D(const QPieModelMapper); + return d->m_valuesSection; +} + +void QPieModelMapper::setValuesSection(int valuesSection) { + Q_D(QPieModelMapper); + d->m_valuesSection = qMax(-1, valuesSection); + d->initializePieFromModel(); + Q_EMIT valuesSectionChanged(); +} + +int QPieModelMapper::labelsSection() const { + Q_D(const QPieModelMapper); + return d->m_labelsSection; +} + +void QPieModelMapper::setLabelsSection(int labelsSection) { + Q_D(QPieModelMapper); + d->m_labelsSection = qMax(-1, labelsSection); + d->initializePieFromModel(); + Q_EMIT labelsSectionChanged(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QPieModelMapperPrivate::QPieModelMapperPrivate() {} + +QPieModelMapperPrivate::~QPieModelMapperPrivate() {} + +void QPieModelMapperPrivate::blockModelSignals(bool block) { + m_modelSignalsBlock = block; +} + +void QPieModelMapperPrivate::blockSeriesSignals(bool block) { + m_seriesSignalsBlock = block; +} + +QPieSlice *QPieModelMapperPrivate::pieSlice(QModelIndex index) const { + if (!index.isValid()) + return 0; // index is invalid + + if (m_orientation == Qt::Vertical + && (index.column() == m_valuesSection || index.column() == m_labelsSection)) { + if (index.row() >= m_first && (m_count == -1 || index.row() < m_first + m_count)) { + if (m_model->index(index.row(), m_valuesSection).isValid() + && m_model->index(index.row(), m_labelsSection).isValid()) + return m_series->slices().at(index.row() - m_first); + else + return 0; + } + } else if (m_orientation == Qt::Horizontal + && (index.row() == m_valuesSection || index.row() == m_labelsSection)) { + if (index.column() >= m_first && (m_count == -1 || index.column() < m_first + m_count)) { + if (m_model->index(m_valuesSection, index.column()).isValid() + && m_model->index(m_labelsSection, index.column()).isValid()) + return m_series->slices().at(index.column() - m_first); + else + return 0; + } + } + return 0; // This part of model has not been mapped to any slice +} + +QModelIndex QPieModelMapperPrivate::valueModelIndex(int slicePos) { + if (m_count != -1 && slicePos >= m_count) + return QModelIndex(); // invalid + + if (m_orientation == Qt::Vertical) + return m_model->index(slicePos + m_first, m_valuesSection); + else + return m_model->index(m_valuesSection, slicePos + m_first); +} + +QModelIndex QPieModelMapperPrivate::labelModelIndex(int slicePos) { + if (m_count != -1 && slicePos >= m_count) + return QModelIndex(); // invalid + + if (m_orientation == Qt::Vertical) + return m_model->index(slicePos + m_first, m_labelsSection); + else + return m_model->index(m_labelsSection, slicePos + m_first); +} + +bool QPieModelMapperPrivate::isLabelIndex(QModelIndex index) const { + if (m_orientation == Qt::Vertical && index.column() == m_labelsSection) + return true; + else if (m_orientation == Qt::Horizontal && index.row() == m_labelsSection) + return true; + + return false; +} + +bool QPieModelMapperPrivate::isValueIndex(QModelIndex index) const { + if (m_orientation == Qt::Vertical && index.column() == m_valuesSection) + return true; + else if (m_orientation == Qt::Horizontal && index.row() == m_valuesSection) + return true; + + return false; +} + +void QPieModelMapperPrivate::onSlicesAdded(const QList<QPieSlice *> &slices) { + if (m_seriesSignalsBlock) + return; + + if (slices.size() == 0) + return; + + int firstIndex = m_series->slices().indexOf(slices.at(0)); + if (firstIndex == -1) + return; + + if (m_count != -1) + m_count += slices.size(); + Q_Q(QPieModelMapper); + for (int i = firstIndex; i < firstIndex + slices.size(); i++) { + m_slices.insert(i, slices.at(i - firstIndex)); + QObject::connect(slices.at(i - firstIndex), + &QPieSlice::labelChanged, + q, + &QPieModelMapper::onSliceLabelChanged); + QObject::connect(slices.at(i - firstIndex), + &QPieSlice::valueChanged, + q, + &QPieModelMapper::onSliceValueChanged); + } + + blockModelSignals(); + if (m_orientation == Qt::Vertical) + m_model->insertRows(firstIndex + m_first, slices.size()); + else + m_model->insertColumns(firstIndex + m_first, slices.size()); + + for (int i = firstIndex; i < firstIndex + slices.size(); i++) { + m_model->setData(valueModelIndex(i), slices.at(i - firstIndex)->value()); + m_model->setData(labelModelIndex(i), slices.at(i - firstIndex)->label()); + } + blockModelSignals(false); +} + +void QPieModelMapperPrivate::onSlicesRemoved(const QList<QPieSlice *> &slices) { + if (m_seriesSignalsBlock) + return; + + if (slices.size() == 0) + return; + + int firstIndex = m_slices.indexOf(slices.at(0)); + if (firstIndex == -1) + return; + + if (m_count != -1) + m_count -= slices.size(); + + for (int i = firstIndex + slices.size() - 1; i >= firstIndex; i--) + m_slices.removeAt(i); + + blockModelSignals(); + if (m_orientation == Qt::Vertical) + m_model->removeRows(firstIndex + m_first, slices.size()); + else + m_model->removeColumns(firstIndex + m_first, slices.size()); + blockModelSignals(false); +} + +void QPieModelMapperPrivate::onSliceLabelChanged(const QPieSlice *slice) { + if (m_seriesSignalsBlock) + return; + + blockModelSignals(); + m_model->setData(labelModelIndex(m_series->slices().indexOf(slice)), slice->label()); + blockModelSignals(false); +} + +void QPieModelMapperPrivate::onSliceValueChanged(const QPieSlice *slice) { + if (m_seriesSignalsBlock) + return; + + blockModelSignals(); + m_model->setData(valueModelIndex(m_series->slices().indexOf(slice)), slice->value()); + blockModelSignals(false); +} + +void QPieModelMapperPrivate::handleSeriesDestroyed() { m_series = nullptr; } + +void QPieModelMapperPrivate::onModelUpdated(QModelIndex topLeft, QModelIndex bottomRight) +{ + if (m_model == nullptr || m_series == nullptr) + return; + + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + QModelIndex index; + QPieSlice *slice; + for (int row = topLeft.row(); row <= bottomRight.row(); row++) { + for (int column = topLeft.column(); column <= bottomRight.column(); column++) { + index = topLeft.sibling(row, column); + slice = pieSlice(index); + if (slice) { + if (isValueIndex(index)) + slice->setValue(m_model->data(index, Qt::DisplayRole).toReal()); + if (isLabelIndex(index)) + slice->setLabel(m_model->data(index, Qt::DisplayRole).toString()); + } + } + } + blockSeriesSignals(false); +} + +void QPieModelMapperPrivate::onModelRowsAdded(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent); + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + if (m_orientation == Qt::Vertical) { + insertData(start, end); + } else if (start <= m_valuesSection + || start <= m_labelsSection) { // if the changes affect the map - reinitialize the pie + initializePieFromModel(); + } + blockSeriesSignals(false); +} + +void QPieModelMapperPrivate::onModelRowsRemoved(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent); + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + if (m_orientation == Qt::Vertical) { + removeData(start, end); + } else if (start <= m_valuesSection || start <= m_labelsSection) { + // if the changes affect the map - reinitialize the pie + initializePieFromModel(); + } + blockSeriesSignals(false); +} + +void QPieModelMapperPrivate::onModelColumnsAdded(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent); + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + if (m_orientation == Qt::Horizontal) { + insertData(start, end); + } else if (start <= m_valuesSection || start <= m_labelsSection) { + // if the changes affect the map - reinitialize the pie + initializePieFromModel(); + } + blockSeriesSignals(false); +} + +void QPieModelMapperPrivate::onModelColumnsRemoved(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent); + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + if (m_orientation == Qt::Horizontal) { + removeData(start, end); + } else if (start <= m_valuesSection || start <= m_labelsSection) { + // if the changes affect the map - reinitialize the pie + initializePieFromModel(); + } + blockSeriesSignals(false); +} + +void QPieModelMapperPrivate::handleModelDestroyed() { m_model = nullptr; } + +void QPieModelMapperPrivate::insertData(int start, int end) { + if (m_model == nullptr || m_series == nullptr) + return; + + if (m_count != -1 && start >= m_first + m_count) { + return; + } else { + int addedCount = end - start + 1; + if (m_count != -1 && addedCount > m_count) + addedCount = m_count; + int first = qMax(start, m_first); + int last = qMin(first + addedCount - 1, + m_orientation == Qt::Vertical ? m_model->rowCount() - 1 + : m_model->columnCount() - 1); + Q_Q(QPieModelMapper); + + for (int i = first; i <= last; i++) { + QModelIndex valueIndex = valueModelIndex(i - m_first); + QModelIndex labelIndex = labelModelIndex(i - m_first); + if (valueIndex.isValid() && labelIndex.isValid()) { + QPieSlice *slice = new QPieSlice; + slice->setValue(m_model->data(valueIndex, Qt::DisplayRole).toDouble()); + slice->setLabel(m_model->data(labelIndex, Qt::DisplayRole).toString()); + QObject::connect(slice, + &QPieSlice::labelChanged, + q, + &QPieModelMapper::onSliceLabelChanged); + QObject::connect(slice, + &QPieSlice::valueChanged, + q, + &QPieModelMapper::onSliceValueChanged); + m_series->insert(i - m_first, slice); + m_slices.insert(i - m_first, slice); + } + } + + // remove excess of slices (abouve m_count) + if (m_count != -1 && m_series->slices().size() > m_count) { + for (int i = m_series->slices().size() - 1; i >= m_count; i--) { + m_series->remove(m_series->slices().at(i)); + m_slices.removeAt(i); + } + } + } +} + +void QPieModelMapperPrivate::removeData(int start, int end) { + if (m_model == 0 || m_series == 0) + return; + + int removedCount = end - start + 1; + if (m_count != -1 && start >= m_first + m_count) { + return; + } else { + int toRemove = qMin(m_series->slices().size(), + removedCount); // first find how many items can actually be removed + int first = qMax(start, + m_first); // get the index of the first item that will be removed. + int last = qMin(first + toRemove - 1, + m_series->slices().size() + m_first + - 1); // get the index of the last item that will be removed. + for (int i = last; i >= first; i--) { + m_series->remove(m_series->slices().at(i - m_first)); + m_slices.removeAt(i - m_first); + } + + if (m_count != -1) { + int itemsAvailable; // check how many are available to be added + if (m_orientation == Qt::Vertical) + itemsAvailable = m_model->rowCount() - m_first - m_series->slices().size(); + else + itemsAvailable = m_model->columnCount() - m_first - m_series->slices().size(); + int toBeAdded = qMin(itemsAvailable, + m_count + - m_series->slices().size()); // add not more items than there + // is space left to be filled. + int currentSize = m_series->slices().size(); + if (toBeAdded > 0) { + for (int i = m_series->slices().size(); i < currentSize + toBeAdded; i++) { + QModelIndex valueIndex = valueModelIndex(i - m_first); + QModelIndex labelIndex = labelModelIndex(i - m_first); + if (valueIndex.isValid() && labelIndex.isValid()) { + QPieSlice *slice = new QPieSlice; + slice->setValue(m_model->data(valueIndex, Qt::DisplayRole).toDouble()); + slice->setLabel(m_model->data(labelIndex, Qt::DisplayRole).toString()); + m_series->insert(i, slice); + m_slices.insert(i, slice); + } + } + } + } + } +} + +void QPieModelMapperPrivate::initializePieFromModel() { + if (m_model == nullptr || m_series == nullptr) + return; + + blockSeriesSignals(); + // clear current content + m_series->clear(); + m_slices.clear(); + + // create the initial slices set + int slicePos = 0; + QModelIndex valueIndex = valueModelIndex(slicePos); + QModelIndex labelIndex = labelModelIndex(slicePos); + Q_Q(QPieModelMapper); + while (valueIndex.isValid() && labelIndex.isValid()) { + QPieSlice *slice = new QPieSlice; + slice->setLabel(m_model->data(labelIndex, Qt::DisplayRole).toString()); + slice->setValue(m_model->data(valueIndex, Qt::DisplayRole).toDouble()); + QObject::connect(slice, &QPieSlice::labelChanged, q, &QPieModelMapper::onSliceLabelChanged); + QObject::connect(slice, &QPieSlice::valueChanged, q, &QPieModelMapper::onSliceValueChanged); + m_series->append(slice); + m_slices.append(slice); + slicePos++; + valueIndex = valueModelIndex(slicePos); + labelIndex = labelModelIndex(slicePos); + } + blockSeriesSignals(false); +} + +QT_END_NAMESPACE diff --git a/src/graphs2d/piechart/qpiemodelmapper.h b/src/graphs2d/piechart/qpiemodelmapper.h new file mode 100644 index 0000000..f66b7aa --- /dev/null +++ b/src/graphs2d/piechart/qpiemodelmapper.h @@ -0,0 +1,72 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#ifndef QPIEMODELMAPPER_H +#define QPIEMODELMAPPER_H + +#include <QtCore/qobject.h> +#include <QtGraphs/qgraphsglobal.h> +#include <QtQmlIntegration/qqmlintegration.h> +Q_MOC_INCLUDE(<QtGraphs / qpieseries.h>) +Q_MOC_INCLUDE(<QtCore / qabstractitemmodel.h>) +QT_BEGIN_NAMESPACE +class QAbstractItemModel; +class QPieModelMapperPrivate; +class QPieSeries; +class Q_GRAPHS_EXPORT QPieModelMapper : public QObject +{ + Q_OBJECT + Q_PROPERTY(QPieSeries *series READ series WRITE setSeries NOTIFY seriesChanged) + Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged) + Q_PROPERTY( + int valuesSection READ valuesSection WRITE setValuesSection NOTIFY valuesSectionChanged) + Q_PROPERTY( + int labelsSection READ labelsSection WRITE setLabelsSection NOTIFY labelsSectionChanged) + Q_PROPERTY(int first READ first WRITE setFirst NOTIFY first) + Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged) + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY + orientationChanged FINAL) + QML_NAMED_ELEMENT(PieModelMapper) + + Q_DECLARE_PRIVATE(QPieModelMapper) +public: + explicit QPieModelMapper(QObject *parent = nullptr); + ~QPieModelMapper() override; + + QPieSeries *series() const; + void setSeries(QPieSeries *series); + + int first() const; + void setFirst(int first); + + int count() const; + void setCount(int count); + + int valuesSection() const; + void setValuesSection(int valuesSection); + + int labelsSection() const; + void setLabelsSection(int labelsSection); + + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation orientation); + + QAbstractItemModel *model() const; + void setModel(QAbstractItemModel *model); +Q_SIGNALS: + void seriesChanged(); + void modelChanged(); + void valuesSectionChanged(); + void labelsSectionChanged(); + void firstChanged(); + void countChanged(); + void orientationChanged(); + +public Q_SLOTS: + void onSliceLabelChanged(); + void onSliceValueChanged(); + +protected: + QPieModelMapper(QPieModelMapperPrivate &dd, QObject *parent = nullptr); +}; +QT_END_NAMESPACE +#endif // QPIEMODELMAPPER_H diff --git a/src/graphs2d/piechart/qpiemodelmapper_p.h b/src/graphs2d/piechart/qpiemodelmapper_p.h new file mode 100644 index 0000000..c9a5603 --- /dev/null +++ b/src/graphs2d/piechart/qpiemodelmapper_p.h @@ -0,0 +1,74 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +// W A R N I N G +// ------------- +// +// This file is not part of the QtGraphs API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +#ifndef QPIEMODELMAPPER_P_H +#define QPIEMODELMAPPER_P_H +#include <QtGraphs/qpiemodelmapper.h> +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE +class QPieSlice; +class QPieSeries; +class QAbstractItemModel; + +class QPieModelMapperPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QPieModelMapper) + +public: + explicit QPieModelMapperPrivate(); + ~QPieModelMapperPrivate() override; + + void onSliceLabelChanged(const QPieSlice *slice); + void onSliceValueChanged(const QPieSlice *slice); +public Q_SLOTS: + // for the model + void onModelUpdated(QModelIndex topLeft, QModelIndex bottomRight); + void onModelRowsAdded(QModelIndex parent, int start, int end); + void onModelRowsRemoved(QModelIndex parent, int start, int end); + void onModelColumnsAdded(QModelIndex parent, int start, int end); + void onModelColumnsRemoved(QModelIndex parent, int start, int end); + void handleModelDestroyed(); + + // for the series + void onSlicesAdded(const QList<QPieSlice *> &slices); + void onSlicesRemoved(const QList<QPieSlice *> &slices); + void handleSeriesDestroyed(); + + void initializePieFromModel(); + +private: + QPieSlice *pieSlice(QModelIndex index) const; + bool isLabelIndex(QModelIndex index) const; + bool isValueIndex(QModelIndex index) const; + QModelIndex valueModelIndex(int slicePos); + QModelIndex labelModelIndex(int slicePos); + void insertData(int start, int end); + void removeData(int start, int end); + + void blockModelSignals(bool block = true); + void blockSeriesSignals(bool block = true); + +private: + QPieSeries *m_series = nullptr; + QList<QPieSlice *> m_slices; + QAbstractItemModel *m_model = nullptr; + int m_first = 0; + int m_count = -1; + Qt::Orientation m_orientation = Qt::Vertical; + int m_valuesSection = -1; + int m_labelsSection = -1; + bool m_seriesSignalsBlock = false; + bool m_modelSignalsBlock = false; +}; + +QT_END_NAMESPACE +#endif // QPIEMODELMAPPER_P_H diff --git a/tests/auto/cpp2dtest/CMakeLists.txt b/tests/auto/cpp2dtest/CMakeLists.txt index 4237c4e..7b74dd1 100644 --- a/tests/auto/cpp2dtest/CMakeLists.txt +++ b/tests/auto/cpp2dtest/CMakeLists.txt @@ -15,3 +15,4 @@ add_subdirectory(qgxychart) add_subdirectory(qgsplines) add_subdirectory(qgarea) add_subdirectory(qgbarmodelmapper) +add_subdirectory(qgpiemodelmapper) diff --git a/tests/auto/cpp2dtest/qgpiemodelmapper/CMakeLists.txt b/tests/auto/cpp2dtest/qgpiemodelmapper/CMakeLists.txt new file mode 100644 index 0000000..1797808 --- /dev/null +++ b/tests/auto/cpp2dtest/qgpiemodelmapper/CMakeLists.txt @@ -0,0 +1,10 @@ +qt_internal_add_test(tst_qgpiemodelmapper + SOURCES + tst_piemodelmapper.cpp + INCLUDE_DIRECTORIES + ../common + LIBRARIES + Qt::Gui + Qt::GuiPrivate + Qt::Graphs +) diff --git a/tests/auto/cpp2dtest/qgpiemodelmapper/tst_piemodelmapper.cpp b/tests/auto/cpp2dtest/qgpiemodelmapper/tst_piemodelmapper.cpp new file mode 100644 index 0000000..0e5110d --- /dev/null +++ b/tests/auto/cpp2dtest/qgpiemodelmapper/tst_piemodelmapper.cpp @@ -0,0 +1,565 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QStandardItemModel> +#include <QtGraphs/QPieModelMapper> +#include <QtGraphs/QPieSeries> +#include <QtGraphs/QPieSlice> +#include <QtTest/QtTest> + +class tst_piemodelmapper : public QObject +{ + Q_OBJECT + +public: + tst_piemodelmapper(); + void createVerticalMapper(); + void createHorizontalMapper(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + void verticalMapper_data(); + void verticalMapper(); + void verticalMapperCustomMapping_data(); + void verticalMapperCustomMapping(); + void horizontalMapper_data(); + void horizontalMapper(); + void horizontalMapperCustomMapping_data(); + void horizontalMapperCustomMapping(); + void seriesUpdated(); + void verticalModelInsertRows(); + void verticalModelRemoveRows(); + void verticalModelInsertColumns(); + void verticalModelRemoveColumns(); + void horizontalModelInsertRows(); + void horizontalModelRemoveRows(); + void horizontalModelInsertColumns(); + void horizontalModelRemoveColumns(); + void modelUpdateCell(); + void verticalMapperSignals(); + void horizontalMapperSignals(); + +private: + QStandardItemModel *m_model = nullptr; + int m_modelRowCount = 10; + int m_modelColumnCount = 8; + QPieModelMapper *m_vMapper = nullptr; + QPieModelMapper *m_hMapper = nullptr; + + QPieSeries *m_series = nullptr; +}; + +tst_piemodelmapper::tst_piemodelmapper() {} + +void tst_piemodelmapper::createVerticalMapper() +{ + m_vMapper = new QPieModelMapper; + QVERIFY(m_vMapper->model() == 0); + m_vMapper->setValuesSection(0); + m_vMapper->setLabelsSection(1); + m_vMapper->setModel(m_model); + m_vMapper->setSeries(m_series); +} + +void tst_piemodelmapper::createHorizontalMapper() +{ + m_hMapper = new QPieModelMapper; + QVERIFY(m_hMapper->model() == 0); + m_hMapper->setOrientation(Qt::Horizontal); + m_hMapper->setValuesSection(0); + m_hMapper->setLabelsSection(1); + m_hMapper->setModel(m_model); + m_hMapper->setSeries(m_series); +} + +void tst_piemodelmapper::init() +{ + m_series = new QPieSeries; + + m_model = new QStandardItemModel(m_modelRowCount, m_modelColumnCount, this); + for (int row = 0; row < m_modelRowCount; ++row) { + for (int column = 0; column < m_modelColumnCount; column++) { + m_model->setData(m_model->index(row, column), row * column); + } + } +} + +void tst_piemodelmapper::cleanup() +{ + m_series->deleteLater(); + m_series = 0; + + m_model->clear(); + m_model->deleteLater(); + m_model = 0; + + if (m_vMapper) { + m_vMapper->deleteLater(); + m_vMapper = 0; + } + + if (m_hMapper) { + m_hMapper->deleteLater(); + m_hMapper = 0; + } +} + +void tst_piemodelmapper::initTestCase() {} + +void tst_piemodelmapper::cleanupTestCase() {} + +void tst_piemodelmapper::verticalMapper_data() +{ + QTest::addColumn<int>("valuesColumn"); + QTest::addColumn<int>("labelsColumn"); + QTest::addColumn<int>("expectedCount"); + QTest::newRow("different values and labels columns") << 0 << 1 << m_modelRowCount; + QTest::newRow("same values and labels columns") << 1 << 1 << m_modelRowCount; + QTest::newRow("invalid values column and correct labels column") << -3 << 1 << 0; + QTest::newRow("values column beyond the size of model and correct labels column") + << m_modelColumnCount << 1 << 0; + QTest::newRow("values column beyond the size of model and invalid labels column") + << m_modelColumnCount << -1 << 0; +} + +void tst_piemodelmapper::verticalMapper() +{ + QFETCH(int, valuesColumn); + QFETCH(int, labelsColumn); + QFETCH(int, expectedCount); + + auto mapper = new QPieModelMapper; + mapper->setValuesSection(valuesColumn); + mapper->setLabelsSection(labelsColumn); + mapper->setModel(m_model); + mapper->setSeries(m_series); + + QCOMPARE(m_series->count(), expectedCount); + QCOMPARE(mapper->valuesSection(), qMax(-1, valuesColumn)); + QCOMPARE(mapper->labelsSection(), qMax(-1, labelsColumn)); + + delete mapper; + mapper = 0; +} + +void tst_piemodelmapper::verticalMapperCustomMapping_data() +{ + QTest::addColumn<int>("first"); + QTest::addColumn<int>("countLimit"); + QTest::addColumn<int>("expectedCount"); + QTest::newRow("first: 0, unlimited count") << 0 << -1 << m_modelRowCount; + QTest::newRow("first: 3, unlimited count") << 3 << -1 << m_modelRowCount - 3; + QTest::newRow("first: 0, count: 5") << 0 << 5 << qMin(5, m_modelRowCount); + QTest::newRow("first: 3, count: 5") << 3 << 5 << qMin(5, m_modelRowCount - 3); + QTest::newRow("first: +1 greater then the number of rows in the model, unlimited count") + << m_modelRowCount + 1 << -1 << 0; + QTest::newRow("first: +1 greater then the number of rows in the model, count: 5") + << m_modelRowCount + 1 << 5 << 0; + QTest::newRow("first: 0, count: +3 greater than the number of rows in the model (should limit " + "to the size of model)") + << 0 << m_modelRowCount + 3 << m_modelRowCount; + QTest::newRow("first: -3(invalid - should default to 0), unlimited count") + << -3 << -1 << m_modelRowCount; + QTest::newRow("first: 0, count: -3 (invalid - shlould default to -1)") + << 0 << -3 << m_modelRowCount; + QTest::newRow( + "first: -3(invalid - should default to 0), count: -3 (invalid - shlould default to -1)") + << -3 << -3 << m_modelRowCount; +} + +void tst_piemodelmapper::verticalMapperCustomMapping() +{ + QFETCH(int, first); + QFETCH(int, countLimit); + QFETCH(int, expectedCount); + + QCOMPARE(m_series->count(), 0); + + auto mapper = new QPieModelMapper; + mapper->setValuesSection(0); + mapper->setLabelsSection(1); + mapper->setModel(m_model); + mapper->setSeries(m_series); + mapper->setFirst(first); + mapper->setCount(countLimit); + + QCOMPARE(m_series->count(), expectedCount); + + // change values column mapping to invalid + mapper->setValuesSection(-1); + mapper->setLabelsSection(1); + + QCOMPARE(m_series->count(), 0); + + delete mapper; + mapper = 0; +} + +void tst_piemodelmapper::horizontalMapper_data() +{ + QTest::addColumn<int>("valuesRow"); + QTest::addColumn<int>("labelsRow"); + QTest::addColumn<int>("expectedCount"); + QTest::newRow("different values and labels rows") << 0 << 1 << m_modelColumnCount; + QTest::newRow("same values and labels rows") << 1 << 1 << m_modelColumnCount; + QTest::newRow("invalid values row and correct labels row") << -3 << 1 << 0; + QTest::newRow("values row beyond the size of model and correct labels row") + << m_modelRowCount << 1 << 0; + QTest::newRow("values row beyond the size of model and invalid labels row") + << m_modelRowCount << -1 << 0; +} + +void tst_piemodelmapper::horizontalMapper() +{ + QFETCH(int, valuesRow); + QFETCH(int, labelsRow); + QFETCH(int, expectedCount); + + auto mapper = new QPieModelMapper; + mapper->setOrientation(Qt::Horizontal); + mapper->setValuesSection(valuesRow); + mapper->setLabelsSection(labelsRow); + mapper->setModel(m_model); + mapper->setSeries(m_series); + + QCOMPARE(m_series->count(), expectedCount); + QCOMPARE(mapper->valuesSection(), qMax(-1, valuesRow)); + QCOMPARE(mapper->labelsSection(), qMax(-1, labelsRow)); + + delete mapper; + mapper = 0; +} + +void tst_piemodelmapper::horizontalMapperCustomMapping_data() +{ + QTest::addColumn<int>("first"); + QTest::addColumn<int>("countLimit"); + QTest::addColumn<int>("expectedCount"); + QTest::newRow("first: 0, unlimited count") << 0 << -1 << m_modelColumnCount; + QTest::newRow("first: 3, unlimited count") << 3 << -1 << m_modelColumnCount - 3; + QTest::newRow("first: 0, count: 5") << 0 << 5 << qMin(5, m_modelColumnCount); + QTest::newRow("first: 3, count: 5") << 3 << 5 << qMin(5, m_modelColumnCount - 3); + QTest::newRow("first: +1 greater then the number of columns in the model, unlimited count") + << m_modelColumnCount + 1 << -1 << 0; + QTest::newRow("first: +1 greater then the number of columns in the model, count: 5") + << m_modelColumnCount + 1 << 5 << 0; + QTest::newRow("first: 0, count: +3 greater than the number of columns in the model (should " + "limit to the size of model)") + << 0 << m_modelColumnCount + 3 << m_modelColumnCount; + QTest::newRow("first: -3(invalid - should default to 0), unlimited count") + << -3 << -1 << m_modelColumnCount; + QTest::newRow("first: 0, count: -3 (invalid - shlould default to -1)") + << 0 << -3 << m_modelColumnCount; + QTest::newRow( + "first: -3(invalid - should default to 0), count: -3 (invalid - shlould default to -1)") + << -3 << -3 << m_modelColumnCount; +} + +void tst_piemodelmapper::horizontalMapperCustomMapping() +{ + QFETCH(int, first); + QFETCH(int, countLimit); + QFETCH(int, expectedCount); + + QCOMPARE(m_series->count(), 0); + + auto mapper = new QPieModelMapper; + mapper->setOrientation(Qt::Horizontal); + mapper->setValuesSection(0); + mapper->setLabelsSection(1); + mapper->setModel(m_model); + mapper->setSeries(m_series); + mapper->setFirst(first); + mapper->setCount(countLimit); + + QCOMPARE(m_series->count(), expectedCount); + + // change values row mapping to invalid + mapper->setValuesSection(-1); + mapper->setLabelsSection(1); + + QCOMPARE(m_series->count(), 0); + + delete mapper; + mapper = 0; +} + +void tst_piemodelmapper::seriesUpdated() +{ + // setup the mapper + createVerticalMapper(); + QCOMPARE(m_series->count(), m_modelRowCount); + QCOMPARE(m_vMapper->count(), -1); + + m_series->append("1000", 1000); + QCOMPARE(m_series->count(), m_modelRowCount + 1); + QCOMPARE(m_vMapper->count(), + -1); // the value should not change as it indicates 'all' items there are in the model + + m_series->remove(m_series->slices().last()); + QCOMPARE(m_series->count(), m_modelRowCount); + QCOMPARE(m_vMapper->count(), + -1); // the value should not change as it indicates 'all' items there are in the model + + QPieSlice *slice = m_series->slices().first(); + slice->setValue(25.0); + slice->setLabel(QString("25.0")); + QCOMPARE(m_model->data(m_model->index(0, 0)).toReal(), 25.0); + QCOMPARE(m_model->data(m_model->index(0, 1)).toString(), QString("25.0")); +} + +void tst_piemodelmapper::verticalModelInsertRows() +{ + // setup the mapper + createVerticalMapper(); + QCOMPARE(m_series->count(), m_modelRowCount); + QVERIFY(m_vMapper->model() != 0); + + int insertCount = 4; + m_model->insertRows(3, insertCount); + QCOMPARE(m_series->count(), m_modelRowCount + insertCount); + + int first = 3; + m_vMapper->setFirst(3); + QCOMPARE(m_series->count(), m_modelRowCount + insertCount - first); + + m_model->insertRows(3, insertCount); + QCOMPARE(m_series->count(), m_modelRowCount + 2 * insertCount - first); + + int countLimit = 6; + m_vMapper->setCount(countLimit); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelRowCount + 2 * insertCount - first)); + + m_model->insertRows(3, insertCount); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelRowCount + 3 * insertCount - first)); + + m_vMapper->setFirst(0); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelRowCount + 3 * insertCount)); + + m_vMapper->setCount(-1); + QCOMPARE(m_series->count(), m_modelRowCount + 3 * insertCount); +} + +void tst_piemodelmapper::verticalModelRemoveRows() +{ + // setup the mapper + createVerticalMapper(); + QCOMPARE(m_series->count(), m_modelRowCount); + QVERIFY(m_vMapper->model() != 0); + + int removeCount = 2; + m_model->removeRows(1, removeCount); + QCOMPARE(m_series->count(), m_modelRowCount - removeCount); + + int first = 1; + m_vMapper->setFirst(first); + QCOMPARE(m_series->count(), m_modelRowCount - removeCount - first); + + m_model->removeRows(1, removeCount); + QCOMPARE(m_series->count(), m_modelRowCount - 2 * removeCount - first); + + int countLimit = 3; + m_vMapper->setCount(countLimit); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelRowCount - 2 * removeCount - first)); + + m_model->removeRows(1, removeCount); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelRowCount - 3 * removeCount - first)); + + m_vMapper->setFirst(0); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelRowCount - 3 * removeCount)); + + m_vMapper->setCount(-1); + QCOMPARE(m_series->count(), m_modelRowCount - 3 * removeCount); +} + +void tst_piemodelmapper::verticalModelInsertColumns() +{ + // setup the mapper + createVerticalMapper(); + QCOMPARE(m_series->count(), m_modelRowCount); + QVERIFY(m_vMapper->model() != 0); + + int insertCount = 4; + m_model->insertColumns(3, insertCount); + QCOMPARE(m_series->count(), m_modelRowCount); +} + +void tst_piemodelmapper::verticalModelRemoveColumns() +{ + // setup the mapper + createVerticalMapper(); + QCOMPARE(m_series->count(), m_modelRowCount); + QVERIFY(m_vMapper->model() != 0); + + int removeCount = m_modelColumnCount - 2; + m_model->removeColumns(0, removeCount); + QCOMPARE(m_series->count(), m_modelRowCount); + + // leave only one column + m_model->removeColumns(0, m_modelColumnCount - removeCount - 1); + QCOMPARE(m_series->count(), 0); +} + +void tst_piemodelmapper::horizontalModelInsertRows() +{ + // setup the mapper + createHorizontalMapper(); + QCOMPARE(m_series->count(), m_modelColumnCount); + QVERIFY(m_hMapper->model() != 0); + + int insertCount = 4; + m_model->insertRows(3, insertCount); + QCOMPARE(m_series->count(), m_modelColumnCount); +} + +void tst_piemodelmapper::horizontalModelRemoveRows() +{ + // setup the mapper + createHorizontalMapper(); + QCOMPARE(m_series->count(), m_modelColumnCount); + QVERIFY(m_hMapper->model() != 0); + + int removeCount = m_modelRowCount - 2; + m_model->removeRows(0, removeCount); + QCOMPARE(m_series->count(), m_modelColumnCount); + + // leave only one column + m_model->removeRows(0, m_modelRowCount - removeCount - 1); + QCOMPARE(m_series->count(), 0); +} + +void tst_piemodelmapper::horizontalModelInsertColumns() +{ + // setup the mapper + createHorizontalMapper(); + QCOMPARE(m_series->count(), m_modelColumnCount); + QVERIFY(m_hMapper->model() != 0); + + int insertCount = 4; + m_model->insertColumns(3, insertCount); + QCOMPARE(m_series->count(), m_modelColumnCount + insertCount); + + int first = 3; + m_hMapper->setFirst(3); + QCOMPARE(m_series->count(), m_modelColumnCount + insertCount - first); + + m_model->insertColumns(3, insertCount); + QCOMPARE(m_series->count(), m_modelColumnCount + 2 * insertCount - first); + + int countLimit = 6; + m_hMapper->setCount(countLimit); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelColumnCount + 2 * insertCount - first)); + + m_model->insertColumns(3, insertCount); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelColumnCount + 3 * insertCount - first)); + + m_hMapper->setFirst(0); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelColumnCount + 3 * insertCount)); + + m_hMapper->setCount(-1); + QCOMPARE(m_series->count(), m_modelColumnCount + 3 * insertCount); +} + +void tst_piemodelmapper::horizontalModelRemoveColumns() +{ + // setup the mapper + createHorizontalMapper(); + QCOMPARE(m_series->count(), m_modelColumnCount); + QVERIFY(m_hMapper->model() != 0); + + int removeCount = 2; + m_model->removeColumns(1, removeCount); + QCOMPARE(m_series->count(), m_modelColumnCount - removeCount); + + int first = 1; + m_hMapper->setFirst(first); + QCOMPARE(m_series->count(), m_modelColumnCount - removeCount - first); + + m_model->removeColumns(1, removeCount); + QCOMPARE(m_series->count(), m_modelColumnCount - 2 * removeCount - first); + + int countLimit = 3; + m_hMapper->setCount(countLimit); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelColumnCount - 2 * removeCount - first)); + + m_model->removeColumns(1, removeCount); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelColumnCount - 3 * removeCount - first)); + + m_hMapper->setFirst(0); + QCOMPARE(m_series->count(), qMin(countLimit, m_modelColumnCount - 3 * removeCount)); + + m_hMapper->setCount(-1); + QCOMPARE(m_series->count(), m_modelColumnCount - 3 * removeCount); +} + +void tst_piemodelmapper::modelUpdateCell() +{ + // setup the mapper + createVerticalMapper(); + + QVERIFY(m_model->setData(m_model->index(1, 0), 44)); + QCOMPARE(m_series->slices().at(1)->value(), 44.0); + QCOMPARE(m_model->data(m_model->index(1, 0)).toReal(), 44.0); +} + +void tst_piemodelmapper::verticalMapperSignals() +{ + auto mapper = new QPieModelMapper; + + QSignalSpy spy0(mapper, SIGNAL(firstChanged())); + QSignalSpy spy1(mapper, SIGNAL(countChanged())); + QSignalSpy spy2(mapper, SIGNAL(valuesSectionChanged())); + QSignalSpy spy3(mapper, SIGNAL(labelsSectionChanged())); + QSignalSpy spy4(mapper, SIGNAL(modelChanged())); + QSignalSpy spy5(mapper, SIGNAL(seriesChanged())); + + mapper->setValuesSection(0); + mapper->setLabelsSection(1); + mapper->setModel(m_model); + mapper->setSeries(m_series); + mapper->setFirst(1); + mapper->setCount(5); + + QCOMPARE(spy0.size(), 1); + QCOMPARE(spy1.size(), 1); + QCOMPARE(spy2.size(), 1); + QCOMPARE(spy3.size(), 1); + QCOMPARE(spy4.size(), 1); + QCOMPARE(spy5.size(), 1); + + delete mapper; +} + +void tst_piemodelmapper::horizontalMapperSignals() +{ + auto mapper = new QPieModelMapper; + + QSignalSpy spy0(mapper, SIGNAL(firstChanged())); + QSignalSpy spy1(mapper, SIGNAL(countChanged())); + QSignalSpy spy2(mapper, SIGNAL(valuesSectionChanged())); + QSignalSpy spy3(mapper, SIGNAL(labelsSectionChanged())); + QSignalSpy spy4(mapper, SIGNAL(modelChanged())); + QSignalSpy spy5(mapper, SIGNAL(seriesChanged())); + + mapper->setOrientation(Qt::Horizontal); + mapper->setValuesSection(0); + mapper->setLabelsSection(1); + mapper->setModel(m_model); + mapper->setSeries(m_series); + mapper->setFirst(1); + mapper->setCount(5); + + QCOMPARE(spy0.size(), 1); + QCOMPARE(spy1.size(), 1); + QCOMPARE(spy2.size(), 1); + QCOMPARE(spy3.size(), 1); + QCOMPARE(spy4.size(), 1); + QCOMPARE(spy5.size(), 1); +} + +QTEST_MAIN(tst_piemodelmapper) + +#include "tst_piemodelmapper.moc" |