From 7c942cc0f497fe7e61ce6a10fce45771c0858e09 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 26 Nov 2013 14:53:50 +0200 Subject: Integrated item model mappings to item model proxies Separate mapping object was redundant. Task-number: QTRD-2564 Change-Id: I6b1a23ba52dbb184f46df0fdd64184eeb145c0c3 Reviewed-by: Mika Salmela --- .../data/qitemmodelsurfacedataproxy.cpp | 376 +++++++++++++++++++-- 1 file changed, 340 insertions(+), 36 deletions(-) (limited to 'src/datavisualization/data/qitemmodelsurfacedataproxy.cpp') diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp b/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp index 75032930..920878d5 100644 --- a/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp +++ b/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp @@ -31,11 +31,36 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE * \since Qt Data Visualization 1.0 * * QItemModelSurfaceDataProxy allows you to use QAbstractItemModel derived models as a data source - * for Q3DSurface. It maps roles defined in QItemModelSurfaceDataMapping to roles in the model. + * for Q3DSurface. It uses the defined mappings to map data from the model to rows, columns, and + * values of Q3DSurface graph. * * Data is resolved asynchronously whenever the mapping or the model changes. * QSurfaceDataProxy::arrayReset() is emitted when the data has been resolved. * + * There are three ways to use mappings: + * + * 1) If useModelCategories property is set to 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 bar value by default. + * The value role to be used can be redefined if Qt::DisplayRole is not suitable. + * + * 2) 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 value. + * + * 3) 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. + * + * 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 + * * \sa {Qt Data Visualization Data Handling} */ @@ -53,11 +78,13 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE * Data is resolved asynchronously whenever the mapping or the model changes. * QSurfaceDataProxy::arrayReset() is emitted when the data has been resolved. * + * For more details, see QItemModelSurfaceDataProxy documentation. + * * Usage example: * * \snippet doc_src_qmldatavisualization.cpp 9 * - * \sa SurfaceDataProxy, SurfaceDataMapping, {Qt Data Visualization Data Handling} + * \sa SurfaceDataProxy, {Qt Data Visualization Data Handling} */ /*! @@ -66,29 +93,140 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE */ /*! - * \qmlproperty list ItemModelSurfaceDataProxy::activeMapping - * The active mapping. Modifying a mapping that is set to the proxy will trigger data set - * re-resolving. + * \qmlproperty string ItemModelSurfaceDataProxy::rowRole + * The row role of the mapping. + * In addition to defining which row the data belongs to, the value indicated by row role + * is also set as the Z-coordinate value of the QSurfaceDataItem when model data is resolved. */ /*! - * Constructs QItemModelSurfaceDataProxy. + * \qmlproperty string ItemModelSurfaceDataProxy::columnRole + * The column role of the mapping. + * In addition to defining which column the data belongs to, the value indicated by column role + * is also set as the X-coordinate value of the QSurfaceDataItem when model data is resolved. */ -QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy() : - QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this)) + +/*! + * \qmlproperty string ItemModelSurfaceDataProxy::valueRole + * The value role of the mapping. + * The value indicated by value role is set as Y-coodrinate value of the + * QSurfaceDataItem when model data is resolved. + */ + +/*! + * \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 list ItemModelSurfaceDataProxy::useModelCategories + * When set to true, the mapping ignores row and column roles and categories, and uses + * the rows and columns from the model instead. Defaults to false. + */ + +/*! + * \qmlproperty list ItemModelSurfaceDataProxy::autoRowCategories + * When set to true, the mapping ignores any explicitly set row categories + * and overwrites them with automatically generated ones whenever the + * data from model is resolved. Proxy minimum and maximum row values are also + * autogenerated from data when this is set to true. Defaults to true. + */ + +/*! + * \qmlproperty list ItemModelSurfaceDataProxy::autoColumnCategories + * When set to true, the mapping ignores any explicitly set column categories + * and overwrites them with automatically generated ones whenever the + * data from model is resolved. Proxy minimum and maximum column values are also + * autogenerated from data when this is set to true. Defaults to true. + */ + +/*! + * Constructs QItemModelSurfaceDataProxy with optional \a parent. + */ +QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QObject *parent) + : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent) { + connectItemModelHandler(); } /*! - * Constructs QItemModelSurfaceDataProxy with \a itemModel and \a mapping. Does not take ownership - * of the model or the mapping, but does connect to them to listen for changes. + * 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(const QAbstractItemModel *itemModel, QObject *parent) + : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent) +{ + dptr()->m_itemModelHandler->setItemModel(itemModel); + 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 value role is set to \a valueRole. + * 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 true. + */ +QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, + const QString &valueRole, QObject *parent) + : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent) +{ + dptr()->m_itemModelHandler->setItemModel(itemModel); + dptr()->m_valueRole = valueRole; + dptr()->m_useModelCategories = true; + 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 valueRole. + */ +QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, + const QString &rowRole, + const QString &columnRole, + const QString &valueRole, QObject *parent) + : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent) +{ + dptr()->m_itemModelHandler->setItemModel(itemModel); + dptr()->m_rowRole = rowRole; + dptr()->m_columnRole = columnRole; + dptr()->m_valueRole = valueRole; + 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 valueRole. + * Row and column categories are set with \a rowCategories and \a columnCategories. + * This constructor also sets autoRowCategories and autoColumnCategories to false. */ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, - QItemModelSurfaceDataMapping *mapping) : - QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this)) + const QString &rowRole, + const QString &columnRole, + const QString &valueRole, + const QStringList &rowCategories, + const QStringList &columnCategories, + QObject *parent) + : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent) { dptr()->m_itemModelHandler->setItemModel(itemModel); - dptr()->m_itemModelHandler->setActiveMapping(mapping); + dptr()->m_rowRole = rowRole; + dptr()->m_columnRole = columnRole; + dptr()->m_valueRole = valueRole; + dptr()->m_rowCategories = rowCategories; + dptr()->m_columnCategories = columnCategories; + dptr()->m_autoRowCategories = false; + dptr()->m_autoColumnCategories = false; + connectItemModelHandler(); } /*! @@ -115,50 +253,191 @@ const QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const } /*! - * \property QItemModelSurfaceDataProxy::activeMapping + * \property QItemModelSurfaceDataProxy::rowRole * - * Defines data mapping. Proxy takes ownership of the \a mapping. - * Modifying a mapping that is set to the proxy will trigger data set re-resolving. + * Defines the row role for the mapping. */ -void QItemModelSurfaceDataProxy::setActiveMapping(QItemModelSurfaceDataMapping *mapping) +void QItemModelSurfaceDataProxy::setRowRole(const QString &role) { - dptr()->m_itemModelHandler->setActiveMapping(mapping); + if (dptr()->m_rowRole != role) { + dptr()->m_rowRole = role; + emit rowRoleChanged(role); + } } -QItemModelSurfaceDataMapping *QItemModelSurfaceDataProxy::activeMapping() const +QString QItemModelSurfaceDataProxy::rowRole() const { - return static_cast(dptrc()->m_itemModelHandler->activeMapping()); + return dptrc()->m_rowRole; } /*! - * Transfers the ownership of the \a mapping to this proxy. The mapping is not taken to use yet. - * \sa setActiveMapping(), releaseMapping() + * \property QItemModelSurfaceDataProxy::columnRole + * + * Defines the column role for the mapping. */ -void QItemModelSurfaceDataProxy::addMapping(QItemModelSurfaceDataMapping *mapping) +void QItemModelSurfaceDataProxy::setColumnRole(const QString &role) +{ + if (dptr()->m_columnRole != role) { + dptr()->m_columnRole = role; + emit columnRoleChanged(role); + } +} + +QString QItemModelSurfaceDataProxy::columnRole() const { - dptr()->m_itemModelHandler->addMapping(mapping); + return dptrc()->m_columnRole; } /*! - * Releases the ownership of the \a mapping back to the caller. If the mapping was the currently - * active one, no mapping remains active after this call. + * \property QItemModelSurfaceDataProxy::valueRole + * + * Defines the value role for the mapping. */ -void QItemModelSurfaceDataProxy::releaseMapping(QItemModelSurfaceDataMapping *mapping) +void QItemModelSurfaceDataProxy::setValueRole(const QString &role) { - dptr()->m_itemModelHandler->releaseMapping(mapping); + if (dptr()->m_valueRole != role) { + dptr()->m_valueRole = role; + emit valueRoleChanged(role); + } +} + +QString QItemModelSurfaceDataProxy::valueRole() const +{ + return dptrc()->m_valueRole; } /*! - * \return list of mappings owned by the proxy. + * \property QItemModelSurfaceDataProxy::rowCategories + * + * Defines the row categories for the mapping. */ -QList QItemModelSurfaceDataProxy::mappings() const +void QItemModelSurfaceDataProxy::setRowCategories(const QStringList &categories) { - QList retList; - QList abstractList = dptrc()->m_itemModelHandler->mappings(); - foreach (QAbstractDataMapping *mapping, abstractList) - retList.append(static_cast(mapping)); + if (dptr()->m_rowCategories != categories) { + dptr()->m_rowCategories = categories; + emit rowCategoriesChanged(categories); + } +} + +QStringList QItemModelSurfaceDataProxy::rowCategories() const +{ + return dptrc()->m_rowCategories; +} + +/*! + * \property QItemModelSurfaceDataProxy::columnCategories + * + * Defines the column categories for the mapping. + */ +void QItemModelSurfaceDataProxy::setColumnCategories(const QStringList &categories) +{ + if (dptr()->m_columnCategories != categories) { + dptr()->m_columnCategories = categories; + emit columnCategoriesChanged(categories); + } +} + +QStringList QItemModelSurfaceDataProxy::columnCategories() const +{ + return dptrc()->m_columnCategories; +} + +/*! + * \property QItemModelSurfaceDataProxy::useModelCategories + * + * When set to true, the mapping ignores row and column roles and categories, and uses + * the rows and columns from the model instead. Defaults to 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 + * + * When set to true, the mapping ignores any explicitly set row categories + * and overwrites them with automatically generated ones whenever the + * data from model is resolved. Defaults to true. + */ +void QItemModelSurfaceDataProxy::setAutoRowCategories(bool enable) +{ + if (dptr()->m_autoRowCategories != enable) { + dptr()->m_autoRowCategories = enable; + emit autoRowCategoriesChanged(enable); + } +} - return retList; +bool QItemModelSurfaceDataProxy::autoRowCategories() const +{ + return dptrc()->m_autoRowCategories; +} + +/*! + * \property QItemModelSurfaceDataProxy::autoColumnCategories + * + * When set to true, the mapping ignores any explicitly set column categories + * and overwrites them with automatically generated ones whenever the + * data from model is resolved. Defaults to 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 valueRole, \a rowCategories and \a columnCategories to the + * mapping. + */ +void QItemModelSurfaceDataProxy::remap(const QString &rowRole, + const QString &columnRole, + const QString &valueRole, + const QStringList &rowCategories, + const QStringList &columnCategories) +{ + setRowRole(rowRole); + setColumnRole(columnRole); + setValueRole(valueRole); + setRowCategories(rowCategories); + setColumnCategories(columnCategories); +} + +/*! + * /return index of the specified \a category in 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); +} + +/*! + * /return index of the specified \a category in 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); } /*! @@ -177,11 +456,36 @@ const QItemModelSurfaceDataProxyPrivate *QItemModelSurfaceDataProxy::dptrc() con return static_cast(d_ptr.data()); } +void QItemModelSurfaceDataProxy::connectItemModelHandler() +{ + QObject::connect(dptr()->m_itemModelHandler, &SurfaceItemModelHandler::itemModelChanged, + this, &QItemModelSurfaceDataProxy::itemModelChanged); + QObject::connect(this, &QItemModelSurfaceDataProxy::rowRoleChanged, + dptr()->m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(this, &QItemModelSurfaceDataProxy::columnRoleChanged, + dptr()->m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(this, &QItemModelSurfaceDataProxy::valueRoleChanged, + dptr()->m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(this, &QItemModelSurfaceDataProxy::rowCategoriesChanged, + dptr()->m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(this, &QItemModelSurfaceDataProxy::columnCategoriesChanged, + dptr()->m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(this, &QItemModelSurfaceDataProxy::useModelCategoriesChanged, + dptr()->m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(this, &QItemModelSurfaceDataProxy::autoRowCategoriesChanged, + dptr()->m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(this, &QItemModelSurfaceDataProxy::autoColumnCategoriesChanged, + dptr()->m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); +} + // QItemModelSurfaceDataProxyPrivate QItemModelSurfaceDataProxyPrivate::QItemModelSurfaceDataProxyPrivate(QItemModelSurfaceDataProxy *q) : QSurfaceDataProxyPrivate(q), - m_itemModelHandler(new SurfaceItemModelHandler(q)) + m_itemModelHandler(new SurfaceItemModelHandler(q)), + m_useModelCategories(false), + m_autoRowCategories(true), + m_autoColumnCategories(true) { } -- cgit v1.2.3