// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "qitemmodelsurfacedataproxy_p.h" #include "surfaceitemmodelhandler_p.h" #include "qgraphs3dlogging_p.h" QT_BEGIN_NAMESPACE /*! * \class QItemModelSurfaceDataProxy * \inmodule QtGraphs * \ingroup graphs_3D * \brief Proxy class for presenting data in item models with Q3DSurfaceWidgetItem. * * QItemModelSurfaceDataProxy allows you to use QAbstractItemModel derived * models as a data source for Q3DSurfaceWidgetItem. It uses the defined mappings to map * data from the model to rows, columns, and surface points of Q3DSurfaceWidgetItem 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 Q3DSurfaceWidgetItem, 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 the * 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_qtgraphs.cpp surfacemodelproxy * * 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 on how * the replacement 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}. * * \sa {Qt Graphs Data Handling with 3D} */ /*! * \qmltype ItemModelSurfaceDataProxy * \inqmlmodule QtGraphs * \ingroup graphs_qml_3D * \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_qmlgraphs.cpp 9 * * \sa SurfaceDataProxy, {Qt Graphs Data Handling with 3D} */ /*! * \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 the * 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 the 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 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 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 replacement 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 replacement 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 replacement 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 replacement 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 replacement 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 enumeration ItemModelSurfaceDataProxy::multiMatchBehavior * Defines how multiple matches for each row/column combination are handled. * Defaults to * \l{QItemModelSurfaceDataProxy::MultiMatchBehavior::Last} * {ItemModelSurfaceDataProxy.MultiMatchBehavior.Last}. * * 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::MultiMatchBehavior::Average} * {ItemModelSurfaceDataProxy.MultiMatchBehavior.Average}. */ /*! \qmlsignal ItemModelSurfaceDataProxy::itemModelChanged(model itemModel) This signal is emitted when itemModel changes to \a itemModel. */ /*! \qmlsignal ItemModelSurfaceDataProxy::rowRoleChanged(string role) This signal is emitted when rowRole changes to \a role. */ /*! \qmlsignal ItemModelSurfaceDataProxy::columnRoleChanged(string role) This signal is emitted when columnRole changes to \a role. */ /*! \qmlsignal ItemModelSurfaceDataProxy::xPosRoleChanged(string role) This signal is emitted when xPosRole changes to \a role. */ /*! \qmlsignal ItemModelSurfaceDataProxy::yPosRoleChanged(string role) This signal is emitted when yPosRole changes to \a role. */ /*! \qmlsignal ItemModelSurfaceDataProxy::zPosRoleChanged(string role) This signal is emitted when zPosRole changes to \a role. */ /*! \qmlsignal ItemModelSurfaceDataProxy::rowCategoriesChanged() This signal is emitted when rowCategories changes. */ /*! \qmlsignal ItemModelSurfaceDataProxy::columnCategoriesChanged() This signal is emitted when columnCategories changes. */ /*! \qmlsignal ItemModelSurfaceDataProxy::useModelCategoriesChanged(bool enable) This signal is emitted when useModelCategories changes to \a enable. */ /*! \qmlsignal ItemModelSurfaceDataProxy::autoRowCategoriesChanged(bool enable) This signal is emitted when autoRowCategories changes to \a enable. */ /*! \qmlsignal ItemModelSurfaceDataProxy::autoColumnCategoriesChanged(bool enable) This signal is emitted when autoColumnCategories changes to \a enable. */ /*! \qmlsignal ItemModelSurfaceDataProxy::rowRolePatternChanged(regExp pattern) This signal is emitted when rowRolePattern changes to \a pattern. */ /*! \qmlsignal ItemModelSurfaceDataProxy::columnRolePatternChanged(regExp pattern) This signal is emitted when columnRolePattern changes to \a pattern. */ /*! \qmlsignal ItemModelSurfaceDataProxy::xPosRolePatternChanged(regExp pattern) This signal is emitted when xPosRolePattern changes to \a pattern. */ /*! \qmlsignal ItemModelSurfaceDataProxy::yPosRolePatternChanged(regExp pattern) This signal is emitted when yPosRolePattern changes to \a pattern. */ /*! \qmlsignal ItemModelSurfaceDataProxy::zPosRolePatternChanged(regExp pattern) This signal is emitted when zPosRolePattern changes to \a pattern. */ /*! \qmlsignal ItemModelSurfaceDataProxy::rowRoleReplaceChanged(string replace) This signal is emitted when rowRoleReplace changes to \a replace. */ /*! \qmlsignal ItemModelSurfaceDataProxy::columnRoleReplaceChanged(string replace) This signal is emitted when columnRoleReplace changes to \a replace. */ /*! \qmlsignal ItemModelSurfaceDataProxy::xPosRoleReplaceChanged(string replace) This signal is emitted when xPosRoleReplace changes to \a replace. */ /*! \qmlsignal ItemModelSurfaceDataProxy::yPosRoleReplaceChanged(string replace) This signal is emitted when yPosRoleReplace changes to \a replace. */ /*! \qmlsignal ItemModelSurfaceDataProxy::zPosRoleReplaceChanged(string replace) This signal is emitted when zPosRoleReplace changes to \a replace. */ /*! \qmlsignal ItemModelSurfaceDataProxy::multiMatchBehaviorChanged(enumeration behavior) This signal is emitted when multiMatchBehavior changes to \a behavior. */ /*! * \enum QItemModelSurfaceDataProxy::MultiMatchBehavior * * Behavior types for QItemModelSurfaceDataProxy::multiMatchBehavior property. * * \value First * The position values are taken from the first item in the item model that matches * each row/column combination. * \value Last * The position values are taken from the last item in the item model that matches * each row/column combination. * \value Average * 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 CumulativeY * For X and Z values this acts just like \c{Average}, but Y values are added together * instead of averaged and the total is used as the surface point Y position. */ /*! * Constructs QItemModelSurfaceDataProxy with an optional \a parent. */ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QObject *parent) : QSurfaceDataProxy(*(new QItemModelSurfaceDataProxyPrivate(this)), parent) { Q_D(QItemModelSurfaceDataProxy); d->connectItemModelHandler(); } /*! * Constructs QItemModelSurfaceDataProxy with \a itemModel and an optional \a parent. * The 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) { Q_D(QItemModelSurfaceDataProxy); d->m_itemModelHandler->setItemModel(itemModel); d->connectItemModelHandler(); } /*! * Constructs QItemModelSurfaceDataProxy with \a itemModel and an optional \a parent. * The 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) { Q_D(QItemModelSurfaceDataProxy); d->m_itemModelHandler->setItemModel(itemModel); d->m_yPosRole = yPosRole; d->m_useModelCategories = true; d->connectItemModelHandler(); } /*! * Constructs QItemModelSurfaceDataProxy with \a itemModel and an optional \a parent. * The 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) { Q_D(QItemModelSurfaceDataProxy); d->m_itemModelHandler->setItemModel(itemModel); d->m_rowRole = rowRole; d->m_columnRole = columnRole; d->m_xPosRole = columnRole; d->m_yPosRole = yPosRole; d->m_zPosRole = rowRole; d->connectItemModelHandler(); } /*! * Constructs QItemModelSurfaceDataProxy with \a itemModel and an optional \a parent. * The 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) { Q_D(QItemModelSurfaceDataProxy); d->m_itemModelHandler->setItemModel(itemModel); d->m_rowRole = rowRole; d->m_columnRole = columnRole; d->m_xPosRole = xPosRole; d->m_yPosRole = yPosRole; d->m_zPosRole = zPosRole; d->connectItemModelHandler(); } /*! * Constructs QItemModelSurfaceDataProxy with \a itemModel and an optional \a parent. * The 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) { Q_D(QItemModelSurfaceDataProxy); d->m_itemModelHandler->setItemModel(itemModel); d->m_rowRole = rowRole; d->m_columnRole = columnRole; d->m_xPosRole = columnRole; d->m_yPosRole = yPosRole; d->m_zPosRole = rowRole; d->m_rowCategories = rowCategories; d->m_columnCategories = columnCategories; d->m_autoRowCategories = false; d->m_autoColumnCategories = false; d->connectItemModelHandler(); } /*! * Constructs QItemModelSurfaceDataProxy with \a itemModel and an optional \a parent. * The 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) { Q_D(QItemModelSurfaceDataProxy); d->m_itemModelHandler->setItemModel(itemModel); d->m_rowRole = rowRole; d->m_columnRole = columnRole; d->m_xPosRole = xPosRole; d->m_yPosRole = yPosRole; d->m_zPosRole = zPosRole; d->m_rowCategories = rowCategories; d->m_columnCategories = columnCategories; d->m_autoRowCategories = false; d->m_autoColumnCategories = false; d->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) { Q_D(QItemModelSurfaceDataProxy); d->m_itemModelHandler->setItemModel(itemModel); } QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_rowRole == role) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(role)); return; } d->m_rowRole = role; emit rowRoleChanged(role); } QString QItemModelSurfaceDataProxy::rowRole() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_columnRole == role) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(role)); return; } d->m_columnRole = role; emit columnRoleChanged(role); } QString QItemModelSurfaceDataProxy::columnRole() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_xPosRole == role) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(role)); return; } d->m_xPosRole = role; emit xPosRoleChanged(role); } QString QItemModelSurfaceDataProxy::xPosRole() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_xPosRole; } /*! * \property QItemModelSurfaceDataProxy::yPosRole * * \brief The item model role to map to the Y position. */ void QItemModelSurfaceDataProxy::setYPosRole(const QString &role) { Q_D(QItemModelSurfaceDataProxy); if (d->m_yPosRole == role) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(role)); return; } d->m_yPosRole = role; emit yPosRoleChanged(role); } QString QItemModelSurfaceDataProxy::yPosRole() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_zPosRole == role) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(role)); return; } d->m_zPosRole = role; emit zPosRoleChanged(role); } QString QItemModelSurfaceDataProxy::zPosRole() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_zPosRole; } /*! * \property QItemModelSurfaceDataProxy::rowCategories * * \brief The row categories for the mapping. */ void QItemModelSurfaceDataProxy::setRowCategories(const QStringList &categories) { Q_D(QItemModelSurfaceDataProxy); if (d->m_rowCategories == categories) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << categories; return; } d->m_rowCategories = categories; emit rowCategoriesChanged(); } QStringList QItemModelSurfaceDataProxy::rowCategories() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_rowCategories; } /*! * \property QItemModelSurfaceDataProxy::columnCategories * * \brief The column categories for the mapping. */ void QItemModelSurfaceDataProxy::setColumnCategories(const QStringList &categories) { Q_D(QItemModelSurfaceDataProxy); if (d->m_columnCategories == categories) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << categories; return; } d->m_columnCategories = categories; emit columnCategoriesChanged(); } QStringList QItemModelSurfaceDataProxy::columnCategories() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_useModelCategories == enable) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << enable; return; } d->m_useModelCategories = enable; emit useModelCategoriesChanged(enable); } bool QItemModelSurfaceDataProxy::useModelCategories() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_autoRowCategories == enable) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << enable; return; } d->m_autoRowCategories = enable; emit autoRowCategoriesChanged(enable); } bool QItemModelSurfaceDataProxy::autoRowCategories() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_autoColumnCategories == enable) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << enable; return; } d->m_autoColumnCategories = enable; emit autoColumnCategoriesChanged(enable); } bool QItemModelSurfaceDataProxy::autoColumnCategories() const { Q_D(const QItemModelSurfaceDataProxy); return d->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. */ qsizetype QItemModelSurfaceDataProxy::rowCategoryIndex(const QString &category) { Q_D(QItemModelSurfaceDataProxy); return d->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. */ qsizetype QItemModelSurfaceDataProxy::columnCategoryIndex(const QString &category) { Q_D(QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_rowRolePattern == pattern) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << pattern; return; } d->m_rowRolePattern = pattern; emit rowRolePatternChanged(pattern); } QRegularExpression QItemModelSurfaceDataProxy::rowRolePattern() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_columnRolePattern == pattern) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << pattern; return; } d->m_columnRolePattern = pattern; emit columnRolePatternChanged(pattern); } QRegularExpression QItemModelSurfaceDataProxy::columnRolePattern() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_xPosRolePattern == pattern) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << pattern; return; } d->m_xPosRolePattern = pattern; emit xPosRolePatternChanged(pattern); } QRegularExpression QItemModelSurfaceDataProxy::xPosRolePattern() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_yPosRolePattern == pattern) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << pattern; return; } d->m_yPosRolePattern = pattern; emit yPosRolePatternChanged(pattern); } QRegularExpression QItemModelSurfaceDataProxy::yPosRolePattern() const { Q_D(const QItemModelSurfaceDataProxy); return d->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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_zPosRolePattern == pattern) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << pattern; return; } d->m_zPosRolePattern = pattern; emit zPosRolePatternChanged(pattern); } QRegularExpression QItemModelSurfaceDataProxy::zPosRolePattern() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_zPosRolePattern; } /*! * \property QItemModelSurfaceDataProxy::rowRoleReplace * * \brief The replacement 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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_rowRoleReplace == replace) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(replace)); return; } d->m_rowRoleReplace = replace; emit rowRoleReplaceChanged(replace); } QString QItemModelSurfaceDataProxy::rowRoleReplace() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_rowRoleReplace; } /*! * \property QItemModelSurfaceDataProxy::columnRoleReplace * * \brief The replacement 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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_columnRoleReplace == replace) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(replace)); return; } d->m_columnRoleReplace = replace; emit columnRoleReplaceChanged(replace); } QString QItemModelSurfaceDataProxy::columnRoleReplace() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_columnRoleReplace; } /*! * \property QItemModelSurfaceDataProxy::xPosRoleReplace * * \brief The replacement 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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_xPosRoleReplace == replace) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(replace)); return; } d->m_xPosRoleReplace = replace; emit xPosRoleReplaceChanged(replace); } QString QItemModelSurfaceDataProxy::xPosRoleReplace() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_xPosRoleReplace; } /*! * \property QItemModelSurfaceDataProxy::yPosRoleReplace * * \brief The replacement 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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_yPosRoleReplace == replace) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(replace)); return; } d->m_yPosRoleReplace = replace; emit yPosRoleReplaceChanged(replace); } QString QItemModelSurfaceDataProxy::yPosRoleReplace() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_yPosRoleReplace; } /*! * \property QItemModelSurfaceDataProxy::zPosRoleReplace * * \brief The replacement 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) { Q_D(QItemModelSurfaceDataProxy); if (d->m_zPosRoleReplace == replace) { qCDebug(lcProperties3D, "%s value is already set to: %s", qUtf8Printable(QLatin1String(__FUNCTION__)), qUtf8Printable(replace)); return; } d->m_zPosRoleReplace = replace; emit zPosRoleReplaceChanged(replace); } QString QItemModelSurfaceDataProxy::zPosRoleReplace() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_zPosRoleReplace; } /*! * \property QItemModelSurfaceDataProxy::multiMatchBehavior * * \brief How multiple matches for each row/column combination are handled. * * Defaults to Last. * * 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 Average. */ void QItemModelSurfaceDataProxy::setMultiMatchBehavior( QItemModelSurfaceDataProxy::MultiMatchBehavior behavior) { Q_D(QItemModelSurfaceDataProxy); if (d->m_multiMatchBehavior == behavior) { qCDebug(lcProperties3D) << __FUNCTION__ << "value is already set to:" << behavior; } d->m_multiMatchBehavior = behavior; emit multiMatchBehaviorChanged(behavior); } QItemModelSurfaceDataProxy::MultiMatchBehavior QItemModelSurfaceDataProxy::multiMatchBehavior() const { Q_D(const QItemModelSurfaceDataProxy); return d->m_multiMatchBehavior; } // QItemModelSurfaceDataProxyPrivate QItemModelSurfaceDataProxyPrivate::QItemModelSurfaceDataProxyPrivate(QItemModelSurfaceDataProxy *q) : m_itemModelHandler(new SurfaceItemModelHandler(q)) , m_useModelCategories(false) , m_autoRowCategories(true) , m_autoColumnCategories(true) , m_multiMatchBehavior(QItemModelSurfaceDataProxy::MultiMatchBehavior::Last) {} QItemModelSurfaceDataProxyPrivate::~QItemModelSurfaceDataProxyPrivate() { delete m_itemModelHandler; } void QItemModelSurfaceDataProxyPrivate::connectItemModelHandler() { Q_Q(QItemModelSurfaceDataProxy); QObject::connect(m_itemModelHandler, &SurfaceItemModelHandler::itemModelChanged, q, &QItemModelSurfaceDataProxy::itemModelChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::rowRoleChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::columnRoleChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::xPosRoleChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::yPosRoleChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::zPosRoleChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::rowCategoriesChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::columnCategoriesChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::useModelCategoriesChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::autoRowCategoriesChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::autoColumnCategoriesChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::rowRolePatternChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::columnRolePatternChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::xPosRolePatternChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::yPosRolePatternChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::zPosRolePatternChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::rowRoleReplaceChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::columnRoleReplaceChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::xPosRoleReplaceChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::yPosRoleReplaceChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::zPosRoleReplaceChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(q, &QItemModelSurfaceDataProxy::multiMatchBehaviorChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); } QT_END_NAMESPACE