Revision control

++ // Copyright (C) 2017 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "qitemmodelsurfacedataproxy_p.h"
++ #include "surfaceitemmodelhandler_p.h"
++
++ QT_BEGIN_NAMESPACE
++
++ /*!
++ * \class QItemModelSurfaceDataProxy
++ * \inmodule QtDataVisualization
++ * \brief Proxy class for presenting data in item models with Q3DSurface.
++ * \since QtDataVisualization 1.0
++ *
++ * QItemModelSurfaceDataProxy allows you to use QAbstractItemModel derived models as a data source
++ * for Q3DSurface. It uses the defined mappings to map data from the model to rows, columns, and
++ * surface points of Q3DSurface graph.
++ *
++ * Data is resolved asynchronously whenever the mapping or the model changes.
++ * QSurfaceDataProxy::arrayReset() is emitted when the data has been resolved.
++ * However, when useModelCategories property is set to \c true, single item changes are resolved
++ * synchronously, unless the same frame also contains a change that causes the whole model to be
++ * resolved.
++ *
++ * Mappings can be used in the following ways:
++ *
++ * \list
++ * \li If useModelCategories property is set to \c true, this proxy will map rows and
++ * columns of QAbstractItemModel to rows and columns of Q3DSurface, and uses the value returned for
++ * Qt::DisplayRole as Y-position by default. Row and column headers are used for Z-position and
++ * X-position by default, if they can be converted to floats. Otherwise row and column indices
++ * are used.
++ * The Y-position role to be used can be redefined if Qt::DisplayRole is not suitable.
++ * The Z-position and X-position roles to be used can be redefined if the headers or indices
++ * are not suitable.
++ *
++ * \li For models that do not have data already neatly sorted into rows and columns, such as
++ * QAbstractListModel based models, you can define a role from the model to map for each of row,
++ * column and Y-position.
++ *
++ * \li If you do not want to include all data contained in the model, or the autogenerated rows and
++ * columns are not ordered as you wish, you can specify which rows and columns should be included
++ * and in which order by defining an explicit list of categories for either or both of rows and
++ * columns.
++ * \endlist
++ *
++ * For example, assume that you have a custom QAbstractItemModel storing surface topography data.
++ * Each item in the model has the roles "longitude", "latitude", and "height".
++ * The item model already contains the data properly sorted so that longitudes and latitudes are
++ * first encountered in correct order, which enables us to utilize the row and column category
++ * autogeneration.
++ * You could do the following to display the data in a surface graph:
++ *
++ * \snippet doc_src_qtdatavisualization.cpp 5
++ *
++ * If the fields of the model do not contain the data in the exact format you need, you can specify
++ * a search pattern regular expression and a replace rule for each role to get the value in a
++ * format you need. For more information how the replace using regular expressions works, see
++ * QString::replace(const QRegularExpression &rx, const QString &after) function documentation. Note that
++ * using regular expressions has an impact on the performance, so it's more efficient to utilize
++ * item models where doing search and replace is not necessary to get the desired values.
++ *
++ * For example about using the search patterns in conjunction with the roles, see
++ * ItemModelBarDataProxy usage in \l{Simple Bar Graph} example.
++ *
++ * \sa {Qt Data Visualization Data Handling}
++ */
++
++ /*!
++ * \qmltype ItemModelSurfaceDataProxy
++ * \inqmlmodule QtDataVisualization
++ * \since QtDataVisualization 1.0
++ * \ingroup datavisualization_qml
++ * \nativetype QItemModelSurfaceDataProxy
++ * \inherits SurfaceDataProxy
++ * \brief Proxy class for presenting data in item models with Surface3D.
++ *
++ * This type allows you to use \c AbstractItemModel derived models as a data
++ * source for Surface3D.
++ *
++ * Data is resolved asynchronously whenever the mapping or the model changes.
++ *
++ * For ItemModelSurfaceDataProxy enums, see \l{QItemModelSurfaceDataProxy::MultiMatchBehavior}.
++ *
++ * For more details, see QItemModelSurfaceDataProxy documentation.
++ *
++ * Usage example:
++ *
++ * \snippet doc_src_qmldatavisualization.cpp 9
++ *
++ * \sa SurfaceDataProxy, {Qt Data Visualization Data Handling}
++ */
++
++ /*!
++ * \qmlproperty model ItemModelSurfaceDataProxy::itemModel
++ * The item model used as a data source for Surface3D.
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::rowRole
++ * The item model role to map to the row category.
++ * In addition to defining which row the data belongs to, the value indicated by the row role
++ * is also set as the Z-coordinate value of QSurfaceDataItem when model data is resolved,
++ * unless a separate z position role is also defined.
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::columnRole
++ * The item model role to map to the column category.
++ * In addition to defining which column the data belongs to, the value indicated by the column role
++ * is also set as the X-coordinate value of QSurfaceDataItem when model data is resolved,
++ * unless a separate x position role is also defined.
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::xPosRole
++ * The item model role to map to the X position. If this role is not defined, columnRole is
++ * used to determine the X-coordinate value of the resolved \c QSurfaceDataItem
++ * items.
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::yPosRole
++ * The item model role to map to the Y position.
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::zPosRole
++ * The item model role to map to the Z position. If this role is not defined, rowRole is
++ * used to determine the Z-coordinate value of the resolved \c QSurfaceDataItem
++ * items.
++ */
++
++ /*!
++ * \qmlproperty list<String> ItemModelSurfaceDataProxy::rowCategories
++ * The row categories of the mapping. Only items with row roles that are found in this list are
++ * included when data is resolved. The rows are ordered in the same order as they are in this list.
++ */
++
++ /*!
++ * \qmlproperty list<String> ItemModelSurfaceDataProxy::columnCategories
++ * The column categories of the mapping. Only items with column roles that are found in this
++ * list are included when data is resolved. The columns are ordered in the same order as they are
++ * in this list.
++ */
++
++ /*!
++ * \qmlproperty bool ItemModelSurfaceDataProxy::useModelCategories
++ * When set to \c true, the mapping ignores row and column roles and categories, and uses
++ * the rows and columns from the model instead. Defaults to \c{false}.
++ */
++
++ /*!
++ * \qmlproperty bool ItemModelSurfaceDataProxy::autoRowCategories
++ * When set to \c true, the mapping ignores any explicitly set row categories
++ * and overwrites them with automatically generated ones whenever the
++ * data from the model is resolved. Proxy minimum and maximum row values are also
++ * autogenerated from the data when this is set to \c true. Defaults to \c{true}.
++ */
++
++ /*!
++ * \qmlproperty bool ItemModelSurfaceDataProxy::autoColumnCategories
++ * When set to \c true, the mapping ignores any explicitly set column categories
++ * and overwrites them with automatically generated ones whenever the
++ * data from the model is resolved. Proxy minimum and maximum column values are also
++ * autogenerated from the data when this is set to \c true. Defaults to \c{true}.
++ */
++
++ /*!
++ * \qmlproperty regExp ItemModelSurfaceDataProxy::rowRolePattern
++ *
++ * When set, a search and replace is done on the value mapped by the row role before it is used as
++ * a row category. This property specifies the regular expression to find the portion of the
++ * mapped value to replace and the rowRoleReplace property contains the replacement string.
++ *
++ * \sa rowRole, rowRoleReplace
++ */
++
++ /*!
++ * \qmlproperty regExp ItemModelSurfaceDataProxy::columnRolePattern
++ *
++ * When set, a search and replace is done on the value mapped by the column role before it is used
++ * as a column category. This property specifies the regular expression to find the portion of the
++ * mapped value to replace and the columnRoleReplace property contains the replacement string.
++ *
++ * \sa columnRole, columnRoleReplace
++ */
++
++ /*!
++ * \qmlproperty regExp ItemModelSurfaceDataProxy::xPosRolePattern
++ *
++ * When set, a search and replace is done on the value mapped by the x position
++ * role before it is used as an item position value. This property specifies
++ * the regular expression to find the portion of the mapped value to replace and
++ * the xPosRoleReplace property contains the replacement string.
++ *
++ * \sa xPosRole, xPosRoleReplace
++ */
++
++ /*!
++ * \qmlproperty regExp ItemModelSurfaceDataProxy::yPosRolePattern
++ *
++ * When set, a search and replace is done on the value mapped by the y position
++ * role before it is used as an item position value. This property specifies
++ * the regular expression to find the portion of the mapped value to replace and
++ * the yPosRoleReplace property contains the replacement string.
++ *
++ * \sa yPosRole, yPosRoleReplace
++ */
++
++ /*!
++ * \qmlproperty regExp ItemModelSurfaceDataProxy::zPosRolePattern
++ *
++ * When set, a search and replace is done on the value mapped by the z position
++ * role before it is used as an item position value. This property specifies
++ * the regular expression to find the portion of the mapped value to replace and
++ * the zPosRoleReplace property contains the replacement string.
++ *
++ * \sa zPosRole, zPosRoleReplace
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::rowRoleReplace
++ *
++ * The replace content to be used in conjunction with rowRolePattern.
++ * Defaults to an empty string. For more information on how the search and
++ * replace using regular expressions works, see the
++ * QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa rowRole, rowRolePattern
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::columnRoleReplace
++ *
++ * The replace content to be used in conjunction with columnRolePattern.
++ * Defaults to an empty string. For more information on how the search and
++ * replace using regular expressions works, see the
++ * QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa columnRole, columnRolePattern
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::xPosRoleReplace
++ *
++ * The replace content to be used in conjunction with xPosRolePattern.
++ * Defaults to an empty string. For more information on how the search and
++ * replace using regular expressions works, see the
++ * QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa xPosRole, xPosRolePattern
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::yPosRoleReplace
++ *
++ * The replace content to be used in conjunction with yPosRolePattern.
++ * Defaults to an empty string. For more information on how the search and
++ * replace using regular expressions works, see the
++ * QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa yPosRole, yPosRolePattern
++ */
++
++ /*!
++ * \qmlproperty string ItemModelSurfaceDataProxy::zPosRoleReplace
++ *
++ * The replace content to be used in conjunction with zPosRolePattern.
++ * Defaults to an empty string. For more information on how the search and
++ * replace using regular expressions works, see the
++ * QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa zPosRole, zPosRolePattern
++ */
++
++ /*!
++ * \qmlproperty ItemModelSurfaceDataProxy.MultiMatchBehavior ItemModelSurfaceDataProxy::multiMatchBehavior
++ * Defines how multiple matches for each row/column combination are handled.
++ * Defaults to \l{QItemModelSurfaceDataProxy::MMBLast}{ItemModelSurfaceDataProxy.MMBLast}.
++ *
++ * For example, you might have an item model with timestamped data taken at irregular intervals
++ * and you want to visualize an average position of data items on each hour with a surface graph.
++ * This can be done by specifying row and column categories so that each surface point represents
++ * an hour, and setting multiMatchBehavior to
++ * \l{QItemModelSurfaceDataProxy::MMBAverage}{ItemModelSurfaceDataProxy.MMBAverage}.
++ */
++
++ /*!
++ * \enum QItemModelSurfaceDataProxy::MultiMatchBehavior
++ *
++ * Behavior types for QItemModelSurfaceDataProxy::multiMatchBehavior property.
++ *
++ * \value MMBFirst
++ * The position values are taken from the first item in the item model that matches
++ * each row/column combination.
++ * \value MMBLast
++ * The position values are taken from the last item in the item model that matches
++ * each row/column combination.
++ * \value MMBAverage
++ * The position values from all items matching each row/column combination are
++ * averaged together and the averages are used as the surface point position.
++ * \value MMBCumulativeY
++ * For X and Z values this acts just like \c{MMBAverage}, but Y values are added together
++ * instead of averaged and the total is used as the surface point Y position.
++ */
++
++ /*!
++ * Constructs QItemModelSurfaceDataProxy with optional \a parent.
++ */
++ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QObject *parent)
++ : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent)
++ {
++ dptr()->connectItemModelHandler();
++ }
++
++ /*!
++ * Constructs QItemModelSurfaceDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
++ * ownership of the \a itemModel, as typically item models are owned by other controls.
++ */
++ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
++ QObject *parent)
++ : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent)
++ {
++ dptr()->m_itemModelHandler->setItemModel(itemModel);
++ dptr()->connectItemModelHandler();
++ }
++
++ /*!
++ * Constructs QItemModelSurfaceDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
++ * ownership of the \a itemModel, as typically item models are owned by other controls.
++ * The yPosRole role is set to \a yPosRole.
++ * This constructor is meant to be used with models that have data properly sorted
++ * in rows and columns already, so it also sets useModelCategories property to \c true.
++ */
++ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
++ const QString &yPosRole,
++ QObject *parent)
++ : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent)
++ {
++ dptr()->m_itemModelHandler->setItemModel(itemModel);
++ dptr()->m_yPosRole = yPosRole;
++ dptr()->m_useModelCategories = true;
++ dptr()->connectItemModelHandler();
++ }
++
++ /*!
++ * Constructs QItemModelSurfaceDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
++ * ownership of the \a itemModel, as typically item models are owned by other controls.
++ * The role mappings are set with \a rowRole, \a columnRole, and \a yPosRole.
++ * The zPosRole and the xPosRole are set to \a rowRole and \a columnRole, respectively.
++ */
++ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
++ const QString &rowRole,
++ const QString &columnRole,
++ const QString &yPosRole,
++ QObject *parent)
++ : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent)
++ {
++ dptr()->m_itemModelHandler->setItemModel(itemModel);
++ dptr()->m_rowRole = rowRole;
++ dptr()->m_columnRole = columnRole;
++ dptr()->m_xPosRole = columnRole;
++ dptr()->m_yPosRole = yPosRole;
++ dptr()->m_zPosRole = rowRole;
++ dptr()->connectItemModelHandler();
++ }
++
++ /*!
++ * Constructs QItemModelSurfaceDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
++ * ownership of the \a itemModel, as typically item models are owned by other controls.
++ * The role mappings are set with \a rowRole, \a columnRole, \a xPosRole, \a yPosRole, and
++ * \a zPosRole.
++ */
++ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
++ const QString &rowRole,
++ const QString &columnRole,
++ const QString &xPosRole,
++ const QString &yPosRole,
++ const QString &zPosRole,
++ QObject *parent)
++ : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent)
++ {
++ dptr()->m_itemModelHandler->setItemModel(itemModel);
++ dptr()->m_rowRole = rowRole;
++ dptr()->m_columnRole = columnRole;
++ dptr()->m_xPosRole = xPosRole;
++ dptr()->m_yPosRole = yPosRole;
++ dptr()->m_zPosRole = zPosRole;
++ dptr()->connectItemModelHandler();
++ }
++
++ /*!
++ * Constructs QItemModelSurfaceDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
++ * ownership of the \a itemModel, as typically item models are owned by other controls.
++ * The role mappings are set with \a rowRole, \a columnRole, and \a yPosRole.
++ * The zPosRole and the xPosRole are set to \a rowRole and \a columnRole, respectively.
++ * Row and column categories are set with \a rowCategories and \a columnCategories.
++ * This constructor also sets autoRowCategories and autoColumnCategories to false.
++ */
++ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
++ const QString &rowRole,
++ const QString &columnRole,
++ const QString &yPosRole,
++ const QStringList &rowCategories,
++ const QStringList &columnCategories,
++ QObject *parent)
++ : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent)
++ {
++ dptr()->m_itemModelHandler->setItemModel(itemModel);
++ dptr()->m_rowRole = rowRole;
++ dptr()->m_columnRole = columnRole;
++ dptr()->m_xPosRole = columnRole;
++ dptr()->m_yPosRole = yPosRole;
++ dptr()->m_zPosRole = rowRole;
++ dptr()->m_rowCategories = rowCategories;
++ dptr()->m_columnCategories = columnCategories;
++ dptr()->m_autoRowCategories = false;
++ dptr()->m_autoColumnCategories = false;
++ dptr()->connectItemModelHandler();
++ }
++
++ /*!
++ * Constructs QItemModelSurfaceDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
++ * ownership of the \a itemModel, as typically item models are owned by other controls.
++ * The role mappings are set with \a rowRole, \a columnRole, \a xPosRole, \a yPosRole,
++ * and \a zPosRole.
++ * Row and column categories are set with \a rowCategories and \a columnCategories.
++ * This constructor also sets autoRowCategories and autoColumnCategories to false.
++ */
++ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
++ const QString &rowRole,
++ const QString &columnRole,
++ const QString &xPosRole,
++ const QString &yPosRole,
++ const QString &zPosRole,
++ const QStringList &rowCategories,
++ const QStringList &columnCategories,
++ QObject *parent)
++ : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent)
++ {
++ dptr()->m_itemModelHandler->setItemModel(itemModel);
++ dptr()->m_rowRole = rowRole;
++ dptr()->m_columnRole = columnRole;
++ dptr()->m_xPosRole = xPosRole;
++ dptr()->m_yPosRole = yPosRole;
++ dptr()->m_zPosRole = zPosRole;
++ dptr()->m_rowCategories = rowCategories;
++ dptr()->m_columnCategories = columnCategories;
++ dptr()->m_autoRowCategories = false;
++ dptr()->m_autoColumnCategories = false;
++ dptr()->connectItemModelHandler();
++ }
++
++ /*!
++ * Destroys QItemModelSurfaceDataProxy.
++ */
++ QItemModelSurfaceDataProxy::~QItemModelSurfaceDataProxy()
++ {
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::itemModel
++ *
++ * \brief The item model used as a data source for the 3D surface.
++ */
++
++ /*!
++ * Sets the item model to \a itemModel. Does not take ownership of the model,
++ * but does connect to it to listen for changes.
++ */
++ void QItemModelSurfaceDataProxy::setItemModel(QAbstractItemModel *itemModel)
++ {
++ dptr()->m_itemModelHandler->setItemModel(itemModel);
++ }
++
++ QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const
++ {
++ return dptrc()->m_itemModelHandler->itemModel();
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::rowRole
++ *
++ * \brief The item model role to map to the row category.
++ *
++ * In addition to defining which row the data belongs to, the value indicated by the row role
++ * is also set as the Z-coordinate value of QSurfaceDataItem when model data is resolved,
++ * unless a separate z position role is also defined.
++ */
++ void QItemModelSurfaceDataProxy::setRowRole(const QString &role)
++ {
++ if (dptr()->m_rowRole != role) {
++ dptr()->m_rowRole = role;
++ emit rowRoleChanged(role);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::rowRole() const
++ {
++ return dptrc()->m_rowRole;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::columnRole
++ *
++ * \brief The item model role to map to the column category.
++ *
++ * In addition to defining which column the data belongs to, the value indicated by the column
++ * role is also set as the X-coordinate value of QSurfaceDataItem when model data is resolved,
++ * unless a separate x position role is also defined.
++ */
++ void QItemModelSurfaceDataProxy::setColumnRole(const QString &role)
++ {
++ if (dptr()->m_columnRole != role) {
++ dptr()->m_columnRole = role;
++ emit columnRoleChanged(role);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::columnRole() const
++ {
++ return dptrc()->m_columnRole;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::xPosRole
++ *
++ * \brief The item model role to map to the X position.
++ *
++ * If this role is not defined, columnRole is used to determine the X-coordinate
++ * value of the resolved \l{QSurfaceDataItem} objects.
++ */
++ void QItemModelSurfaceDataProxy::setXPosRole(const QString &role)
++ {
++ if (dptr()->m_xPosRole != role) {
++ dptr()->m_xPosRole = role;
++ emit xPosRoleChanged(role);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::xPosRole() const
++ {
++ return dptrc()->m_xPosRole;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::yPosRole
++ *
++ * \brief The item model role to map to the Y position.
++ */
++ void QItemModelSurfaceDataProxy::setYPosRole(const QString &role)
++ {
++ if (dptr()->m_yPosRole != role) {
++ dptr()->m_yPosRole = role;
++ emit yPosRoleChanged(role);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::yPosRole() const
++ {
++ return dptrc()->m_yPosRole;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::zPosRole
++ *
++ * \brief The item model role to map to the Z position.
++ *
++ * If this role is not defined, rowRole is used to determine the Z-coordinate
++ * value of resolved \l{QSurfaceDataItem} objects.
++ */
++ void QItemModelSurfaceDataProxy::setZPosRole(const QString &role)
++ {
++ if (dptr()->m_zPosRole != role) {
++ dptr()->m_zPosRole = role;
++ emit zPosRoleChanged(role);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::zPosRole() const
++ {
++ return dptrc()->m_zPosRole;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::rowCategories
++ *
++ * \brief The row categories for the mapping.
++ */
++ void QItemModelSurfaceDataProxy::setRowCategories(const QStringList &categories)
++ {
++ if (dptr()->m_rowCategories != categories) {
++ dptr()->m_rowCategories = categories;
++ emit rowCategoriesChanged();
++ }
++ }
++
++ QStringList QItemModelSurfaceDataProxy::rowCategories() const
++ {
++ return dptrc()->m_rowCategories;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::columnCategories
++ *
++ * \brief The column categories for the mapping.
++ */
++ void QItemModelSurfaceDataProxy::setColumnCategories(const QStringList &categories)
++ {
++ if (dptr()->m_columnCategories != categories) {
++ dptr()->m_columnCategories = categories;
++ emit columnCategoriesChanged();
++ }
++ }
++
++ QStringList QItemModelSurfaceDataProxy::columnCategories() const
++ {
++ return dptrc()->m_columnCategories;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::useModelCategories
++ *
++ * \brief Whether row and column roles and categories are used for mapping.
++ *
++ * When set to \c true, the mapping ignores row and column roles and categories, and uses
++ * the rows and columns from the model instead. Defaults to \c{false}.
++ */
++ void QItemModelSurfaceDataProxy::setUseModelCategories(bool enable)
++ {
++ if (dptr()->m_useModelCategories != enable) {
++ dptr()->m_useModelCategories = enable;
++ emit useModelCategoriesChanged(enable);
++ }
++ }
++
++ bool QItemModelSurfaceDataProxy::useModelCategories() const
++ {
++ return dptrc()->m_useModelCategories;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::autoRowCategories
++ *
++ * \brief Whether row categories are generated automatically.
++ *
++ * When set to \c true, the mapping ignores any explicitly set row categories
++ * and overwrites them with automatically generated ones whenever the
++ * data from the model is resolved. Defaults to \c{true}.
++ */
++ void QItemModelSurfaceDataProxy::setAutoRowCategories(bool enable)
++ {
++ if (dptr()->m_autoRowCategories != enable) {
++ dptr()->m_autoRowCategories = enable;
++ emit autoRowCategoriesChanged(enable);
++ }
++ }
++
++ bool QItemModelSurfaceDataProxy::autoRowCategories() const
++ {
++ return dptrc()->m_autoRowCategories;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::autoColumnCategories
++ *
++ * \brief Whether column categories are generated automatically.
++ *
++ * When set to \c true, the mapping ignores any explicitly set column categories
++ * and overwrites them with automatically generated ones whenever the
++ * data from the model is resolved. Defaults to \c{true}.
++ */
++ void QItemModelSurfaceDataProxy::setAutoColumnCategories(bool enable)
++ {
++ if (dptr()->m_autoColumnCategories != enable) {
++ dptr()->m_autoColumnCategories = enable;
++ emit autoColumnCategoriesChanged(enable);
++ }
++ }
++
++ bool QItemModelSurfaceDataProxy::autoColumnCategories() const
++ {
++ return dptrc()->m_autoColumnCategories;
++ }
++
++ /*!
++ * Changes \a rowRole, \a columnRole, \a xPosRole, \a yPosRole, \a zPosRole,
++ * \a rowCategories and \a columnCategories to the mapping.
++ */
++ void QItemModelSurfaceDataProxy::remap(const QString &rowRole,
++ const QString &columnRole,
++ const QString &xPosRole,
++ const QString &yPosRole,
++ const QString &zPosRole,
++ const QStringList &rowCategories,
++ const QStringList &columnCategories)
++ {
++ setRowRole(rowRole);
++ setColumnRole(columnRole);
++ setXPosRole(xPosRole);
++ setYPosRole(yPosRole);
++ setZPosRole(zPosRole);
++ setRowCategories(rowCategories);
++ setColumnCategories(columnCategories);
++ }
++
++ /*!
++ * Returns the index of the specified \a category in the row categories list.
++ * If the row categories list is empty, -1 is returned.
++ * \note If the automatic row categories generation is in use, this method will
++ * not return a valid index before the data in the model is resolved for the first time.
++ */
++ int QItemModelSurfaceDataProxy::rowCategoryIndex(const QString &category)
++ {
++ return dptr()->m_rowCategories.indexOf(category);
++ }
++
++ /*!
++ * Returns the index of the specified \a category in the column categories list.
++ * If the category is not found, -1 is returned.
++ * \note If the automatic column categories generation is in use, this method will
++ * not return a valid index before the data in the model is resolved for the first time.
++ */
++ int QItemModelSurfaceDataProxy::columnCategoryIndex(const QString &category)
++ {
++ return dptr()->m_columnCategories.indexOf(category);
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::rowRolePattern
++ *
++ * \brief Whether a search and replace is performed on the value mapped by the
++ * row role before it is used as a row category.
++ *
++ * This property specifies the regular expression to find the portion of the
++ * mapped value to replace and the rowRoleReplace property contains the
++ * replacement string.
++ *
++ * \sa rowRole, rowRoleReplace
++ */
++ void QItemModelSurfaceDataProxy::setRowRolePattern(const QRegularExpression &pattern)
++ {
++ if (dptr()->m_rowRolePattern != pattern) {
++ dptr()->m_rowRolePattern = pattern;
++ emit rowRolePatternChanged(pattern);
++ }
++ }
++
++ QRegularExpression QItemModelSurfaceDataProxy::rowRolePattern() const
++ {
++ return dptrc()->m_rowRolePattern;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::columnRolePattern
++ *
++ * \brief Whether a search and replace is done on the value mapped by the column
++ * role before it is used as a column category.
++ *
++ * This property specifies the regular expression to find the portion of the
++ * mapped value to replace and the columnRoleReplace property contains the
++ * replacement string.
++ *
++ * \sa columnRole, columnRoleReplace
++ */
++ void QItemModelSurfaceDataProxy::setColumnRolePattern(const QRegularExpression &pattern)
++ {
++ if (dptr()->m_columnRolePattern != pattern) {
++ dptr()->m_columnRolePattern = pattern;
++ emit columnRolePatternChanged(pattern);
++ }
++ }
++
++ QRegularExpression QItemModelSurfaceDataProxy::columnRolePattern() const
++ {
++ return dptrc()->m_columnRolePattern;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::xPosRolePattern
++ *
++ * \brief Whether a search and replace is done on the value mapped by the x
++ * position role before it is used as an item position value.
++ *
++ * This property specifies the regular expression to find the portion of the
++ * mapped value to replace and the xPosRoleReplace property contains the
++ * replacement string.
++ *
++ * \sa xPosRole, xPosRoleReplace
++ */
++ void QItemModelSurfaceDataProxy::setXPosRolePattern(const QRegularExpression &pattern)
++ {
++ if (dptr()->m_xPosRolePattern != pattern) {
++ dptr()->m_xPosRolePattern = pattern;
++ emit xPosRolePatternChanged(pattern);
++ }
++ }
++
++ QRegularExpression QItemModelSurfaceDataProxy::xPosRolePattern() const
++ {
++ return dptrc()->m_xPosRolePattern;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::yPosRolePattern
++ *
++ * \brief Whether a search and replace is done on the value mapped by the y
++ * position role before it is used as an item position value.
++ *
++ * This property specifies the regular expression to find the portion of the
++ * mapped value to replace and the yPosRoleReplace property contains the
++ * replacement string.
++ *
++ * \sa yPosRole, yPosRoleReplace
++ */
++ void QItemModelSurfaceDataProxy::setYPosRolePattern(const QRegularExpression &pattern)
++ {
++ if (dptr()->m_yPosRolePattern != pattern) {
++ dptr()->m_yPosRolePattern = pattern;
++ emit yPosRolePatternChanged(pattern);
++ }
++ }
++
++ QRegularExpression QItemModelSurfaceDataProxy::yPosRolePattern() const
++ {
++ return dptrc()->m_yPosRolePattern;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::zPosRolePattern
++ *
++ * \brief Whether a search and replace is done on the value mapped by the z
++ * position role before it is used as an item position value.
++ *
++ * This property specifies the regular expression to find the portion of the
++ * mapped value to replace and the zPosRoleReplace property contains the
++ * replacement string.
++ *
++ * \sa zPosRole, zPosRoleReplace
++ */
++ void QItemModelSurfaceDataProxy::setZPosRolePattern(const QRegularExpression &pattern)
++ {
++ if (dptr()->m_zPosRolePattern != pattern) {
++ dptr()->m_zPosRolePattern = pattern;
++ emit zPosRolePatternChanged(pattern);
++ }
++ }
++
++ QRegularExpression QItemModelSurfaceDataProxy::zPosRolePattern() const
++ {
++ return dptrc()->m_zPosRolePattern;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::rowRoleReplace
++ *
++ * \brief The replace content to be used in conjunction with the row role
++ * pattern.
++ *
++ * Defaults to an empty string. For more information on how the search and replace using regular
++ * expressions works, see QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa rowRole, rowRolePattern
++ */
++ void QItemModelSurfaceDataProxy::setRowRoleReplace(const QString &replace)
++ {
++ if (dptr()->m_rowRoleReplace != replace) {
++ dptr()->m_rowRoleReplace = replace;
++ emit rowRoleReplaceChanged(replace);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::rowRoleReplace() const
++ {
++ return dptrc()->m_rowRoleReplace;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::columnRoleReplace
++ *
++ * \brief The replace content to be used in conjunction with a column role
++ * pattern.
++ *
++ * Defaults to an empty string. For more information on how the search and
++ * replace using regular expressions works, see the
++ * QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa columnRole, columnRolePattern
++ */
++ void QItemModelSurfaceDataProxy::setColumnRoleReplace(const QString &replace)
++ {
++ if (dptr()->m_columnRoleReplace != replace) {
++ dptr()->m_columnRoleReplace = replace;
++ emit columnRoleReplaceChanged(replace);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::columnRoleReplace() const
++ {
++ return dptrc()->m_columnRoleReplace;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::xPosRoleReplace
++ *
++ * \brief The replace content to be used in conjunction with an x position role
++ * pattern.
++ *
++ * Defaults to an empty string. For more information on how the search and
++ * replace using regular expressions works, see the
++ * QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa xPosRole, xPosRolePattern
++ */
++ void QItemModelSurfaceDataProxy::setXPosRoleReplace(const QString &replace)
++ {
++ if (dptr()->m_xPosRoleReplace != replace) {
++ dptr()->m_xPosRoleReplace = replace;
++ emit xPosRoleReplaceChanged(replace);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::xPosRoleReplace() const
++ {
++ return dptrc()->m_xPosRoleReplace;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::yPosRoleReplace
++ *
++ * \brief The replace content to be used in conjunction with an y position role
++ * pattern.
++ *
++ * Defaults to an empty string. For more information on how the search and
++ * replace using regular expressions works, see the
++ * QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa yPosRole, yPosRolePattern
++ */
++ void QItemModelSurfaceDataProxy::setYPosRoleReplace(const QString &replace)
++ {
++ if (dptr()->m_yPosRoleReplace != replace) {
++ dptr()->m_yPosRoleReplace = replace;
++ emit yPosRoleReplaceChanged(replace);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::yPosRoleReplace() const
++ {
++ return dptrc()->m_yPosRoleReplace;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::zPosRoleReplace
++ *
++ * \brief The replace content to be used in conjunction with a z position role
++ * pattern.
++ *
++ * Defaults to an empty string. For more information on how the search and
++ * replace using regular expressions works, see the
++ * QString::replace(const QRegularExpression &rx, const QString &after)
++ * function documentation.
++ *
++ * \sa zPosRole, zPosRolePattern
++ */
++ void QItemModelSurfaceDataProxy::setZPosRoleReplace(const QString &replace)
++ {
++ if (dptr()->m_zPosRoleReplace != replace) {
++ dptr()->m_zPosRoleReplace = replace;
++ emit zPosRoleReplaceChanged(replace);
++ }
++ }
++
++ QString QItemModelSurfaceDataProxy::zPosRoleReplace() const
++ {
++ return dptrc()->m_zPosRoleReplace;
++ }
++
++ /*!
++ * \property QItemModelSurfaceDataProxy::multiMatchBehavior
++ *
++ * \brief How multiple matches for each row/column combination are handled.
++ *
++ * Defaults to MMBLast.
++ *
++ * For example, you might have an item model with timestamped data taken at irregular intervals
++ * and you want to visualize an average position of data items on each hour with a surface graph.
++ * This can be done by specifying row and column categories so that each surface point represents
++ * an hour, and setting this property to MMBAverage.
++ */
++
++ void QItemModelSurfaceDataProxy::setMultiMatchBehavior(QItemModelSurfaceDataProxy::MultiMatchBehavior behavior)
++ {
++ if (dptr()->m_multiMatchBehavior != behavior) {
++ dptr()->m_multiMatchBehavior = behavior;
++ emit multiMatchBehaviorChanged(behavior);
++ }
++ }
++
++ QItemModelSurfaceDataProxy::MultiMatchBehavior QItemModelSurfaceDataProxy::multiMatchBehavior() const
++ {
++ return dptrc()->m_multiMatchBehavior;
++ }
++
++ /*!
++ * \internal
++ */
++ QItemModelSurfaceDataProxyPrivate *QItemModelSurfaceDataProxy::dptr()
++ {
++ return static_cast<QItemModelSurfaceDataProxyPrivate *>(d_ptr.data());
++ }
++
++ /*!
++ * \internal
++ */
++ const QItemModelSurfaceDataProxyPrivate *QItemModelSurfaceDataProxy::dptrc() const
++ {
++ return static_cast<const QItemModelSurfaceDataProxyPrivate *>(d_ptr.data());
++ }
++
++ // QItemModelSurfaceDataProxyPrivate
++
++ QItemModelSurfaceDataProxyPrivate::QItemModelSurfaceDataProxyPrivate(QItemModelSurfaceDataProxy *q)
++ : QSurfaceDataProxyPrivate(q),
++ m_itemModelHandler(new SurfaceItemModelHandler(q)),
++ m_useModelCategories(false),
++ m_autoRowCategories(true),
++ m_autoColumnCategories(true),
++ m_multiMatchBehavior(QItemModelSurfaceDataProxy::MMBLast)
++ {
++ }
++
++ QItemModelSurfaceDataProxyPrivate::~QItemModelSurfaceDataProxyPrivate()
++ {
++ delete m_itemModelHandler;
++ }
++
++ QItemModelSurfaceDataProxy *QItemModelSurfaceDataProxyPrivate::qptr()
++ {
++ return static_cast<QItemModelSurfaceDataProxy *>(q_ptr);
++ }
++
++ void QItemModelSurfaceDataProxyPrivate::connectItemModelHandler()
++ {
++ QObject::connect(m_itemModelHandler, &SurfaceItemModelHandler::itemModelChanged,
++ qptr(), &QItemModelSurfaceDataProxy::itemModelChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::rowRoleChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::columnRoleChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::xPosRoleChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::yPosRoleChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::zPosRoleChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::rowCategoriesChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::columnCategoriesChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::useModelCategoriesChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::autoRowCategoriesChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::autoColumnCategoriesChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::rowRolePatternChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::columnRolePatternChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::xPosRolePatternChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::yPosRolePatternChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::zPosRolePatternChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::rowRoleReplaceChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::columnRoleReplaceChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::xPosRoleReplaceChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::yPosRoleReplaceChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::zPosRoleReplaceChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::multiMatchBehaviorChanged,
++ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
++ }
++
++ QT_END_NAMESPACE