diff options
Diffstat (limited to 'src/datavisualization/data')
54 files changed, 3420 insertions, 256 deletions
diff --git a/src/datavisualization/data/abstractitemmodelhandler.cpp b/src/datavisualization/data/abstractitemmodelhandler.cpp index 9f2ccd86..f8ddf7b7 100644 --- a/src/datavisualization/data/abstractitemmodelhandler.cpp +++ b/src/datavisualization/data/abstractitemmodelhandler.cpp @@ -34,7 +34,7 @@ AbstractItemModelHandler::~AbstractItemModelHandler() { } -void AbstractItemModelHandler::setItemModel(const QAbstractItemModel *itemModel) +void AbstractItemModelHandler::setItemModel(QAbstractItemModel *itemModel) { if (itemModel != m_itemModel.data()) { if (!m_itemModel.isNull()) @@ -69,7 +69,7 @@ void AbstractItemModelHandler::setItemModel(const QAbstractItemModel *itemModel) } } -const QAbstractItemModel *AbstractItemModelHandler::itemModel() const +QAbstractItemModel *AbstractItemModelHandler::itemModel() const { return m_itemModel.data(); } diff --git a/src/datavisualization/data/abstractitemmodelhandler_p.h b/src/datavisualization/data/abstractitemmodelhandler_p.h index ecbfe61c..e11d229a 100644 --- a/src/datavisualization/data/abstractitemmodelhandler_p.h +++ b/src/datavisualization/data/abstractitemmodelhandler_p.h @@ -43,8 +43,8 @@ public: AbstractItemModelHandler(QObject *parent = 0); virtual ~AbstractItemModelHandler(); - virtual void setItemModel(const QAbstractItemModel *itemModel); - virtual const QAbstractItemModel *itemModel() const; + virtual void setItemModel(QAbstractItemModel *itemModel); + virtual QAbstractItemModel *itemModel() const; public slots: virtual void handleColumnsInserted(const QModelIndex &parent, int start, int end); @@ -71,7 +71,7 @@ signals: protected: virtual void resolveModel() = 0; - QPointer<const QAbstractItemModel> m_itemModel; // Not owned + QPointer<QAbstractItemModel> m_itemModel; // Not owned bool resolvePending; QTimer m_resolveTimer; bool m_fullReset; diff --git a/src/datavisualization/data/abstractrenderitem_p.h b/src/datavisualization/data/abstractrenderitem_p.h index 912a09f3..57977a3c 100644 --- a/src/datavisualization/data/abstractrenderitem_p.h +++ b/src/datavisualization/data/abstractrenderitem_p.h @@ -32,8 +32,6 @@ #include "datavisualizationglobal_p.h" #include "labelitem_p.h" -#include <QtCore/QString> -#include <QtGui/QOpenGLFunctions> #include <QtGui/QVector3D> #include <QtGui/QQuaternion> diff --git a/src/datavisualization/data/baritemmodelhandler.cpp b/src/datavisualization/data/baritemmodelhandler.cpp index 4f44fe1d..62e6390d 100644 --- a/src/datavisualization/data/baritemmodelhandler.cpp +++ b/src/datavisualization/data/baritemmodelhandler.cpp @@ -26,7 +26,11 @@ BarItemModelHandler::BarItemModelHandler(QItemModelBarDataProxy *proxy, QObject : AbstractItemModelHandler(parent), m_proxy(proxy), m_proxyArray(0), - m_columnCount(0) + m_columnCount(0), + m_valueRole(noRoleIndex), + m_rotationRole(noRoleIndex), + m_haveValuePattern(false), + m_haveRotationPattern(false) { } @@ -34,6 +38,50 @@ BarItemModelHandler::~BarItemModelHandler() { } +void BarItemModelHandler::handleDataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight, + const QVector<int> &roles) +{ + // Do nothing if full reset already pending + if (!m_fullReset) { + if (!m_proxy->useModelCategories()) { + // If the data model doesn't directly map rows and columns, we cannot optimize + AbstractItemModelHandler::handleDataChanged(topLeft, bottomRight, roles); + } else { + int startRow = qMin(topLeft.row(), bottomRight.row()); + int endRow = qMax(topLeft.row(), bottomRight.row()); + int startCol = qMin(topLeft.column(), bottomRight.column()); + int endCol = qMax(topLeft.column(), bottomRight.column()); + + for (int i = startRow; i <= endRow; i++) { + for (int j = startCol; j <= endCol; j++) { + QModelIndex index = m_itemModel->index(i, j); + QBarDataItem item; + QVariant valueVar = index.data(m_valueRole); + float value; + if (m_haveValuePattern) + value = valueVar.toString().replace(m_valuePattern, m_valueReplace).toFloat(); + else + value = valueVar.toFloat(); + item.setValue(value); + if (m_rotationRole != noRoleIndex) { + QVariant rotationVar = index.data(m_rotationRole); + float rotation; + if (m_haveRotationPattern) { + rotation = rotationVar.toString().replace(m_rotationPattern, + m_rotationReplace).toFloat(); + } else { + rotation = rotationVar.toFloat(); + } + item.setRotation(rotation); + } + m_proxy->setItem(i, j, item); + } + } + } + } +} + // Resolve entire item model into QBarDataArray. void BarItemModelHandler::resolveModel() { @@ -48,14 +96,29 @@ void BarItemModelHandler::resolveModel() return; } + // Value and rotation patterns can be reused on single item changes, + // so store them to member variables. + QRegExp rowPattern(m_proxy->rowRolePattern()); + QRegExp colPattern(m_proxy->columnRolePattern()); + m_valuePattern = m_proxy->valueRolePattern(); + m_rotationPattern = m_proxy->rotationRolePattern(); + QString rowReplace = m_proxy->rowRoleReplace(); + QString colReplace = m_proxy->columnRoleReplace(); + m_valueReplace = m_proxy->valueRoleReplace(); + m_rotationReplace = m_proxy->rotationRoleReplace(); + bool haveRowPattern = !rowPattern.isEmpty() && rowPattern.isValid(); + bool haveColPattern = !colPattern.isEmpty() && colPattern.isValid(); + m_haveValuePattern = !m_valuePattern.isEmpty() && m_valuePattern.isValid(); + m_haveRotationPattern = !m_rotationPattern.isEmpty() && m_rotationPattern.isValid(); + QStringList rowLabels; QStringList columnLabels; QHash<int, QByteArray> roleHash = m_itemModel->roleNames(); // Default value role to display role if no mapping - int valueRole = roleHash.key(m_proxy->valueRole().toLatin1(), Qt::DisplayRole); - int rotationRole = roleHash.key(m_proxy->rotationRole().toLatin1(), noRoleIndex); + m_valueRole = roleHash.key(m_proxy->valueRole().toLatin1(), Qt::DisplayRole); + m_rotationRole = roleHash.key(m_proxy->rotationRole().toLatin1(), noRoleIndex); int rowCount = m_itemModel->rowCount(); int columnCount = m_itemModel->columnCount(); @@ -71,9 +134,25 @@ void BarItemModelHandler::resolveModel() for (int i = 0; i < rowCount; i++) { QBarDataRow &newProxyRow = *m_proxyArray->at(i); for (int j = 0; j < columnCount; j++) { - newProxyRow[j].setValue(m_itemModel->index(i, j).data(valueRole).toReal()); - if (rotationRole != noRoleIndex) - newProxyRow[j].setRotation(m_itemModel->index(i, j).data(rotationRole).toReal()); + QModelIndex index = m_itemModel->index(i, j); + QVariant valueVar = index.data(m_valueRole); + float value; + if (m_haveValuePattern) + value = valueVar.toString().replace(m_valuePattern, m_valueReplace).toFloat(); + else + value = valueVar.toFloat(); + newProxyRow[j].setValue(value); + if (m_rotationRole != noRoleIndex) { + QVariant rotationVar = index.data(m_rotationRole); + float rotation; + if (m_haveRotationPattern) { + rotation = rotationVar.toString().replace(m_rotationPattern, + m_rotationReplace).toFloat(); + } else { + rotation = rotationVar.toFloat(); + } + newProxyRow[j].setRotation(rotation); + } } } // Generate labels from headers if using model rows/columns @@ -97,16 +176,62 @@ void BarItemModelHandler::resolveModel() // Sort values into rows and columns typedef QHash<QString, float> ColumnValueMap; - QHash <QString, ColumnValueMap> itemValueMap; - QHash <QString, ColumnValueMap> itemRotationMap; + QHash<QString, ColumnValueMap> itemValueMap; + QHash<QString, ColumnValueMap> itemRotationMap; + + bool cumulative = m_proxy->multiMatchBehavior() == QItemModelBarDataProxy::MMBAverage + || m_proxy->multiMatchBehavior() == QItemModelBarDataProxy::MMBCumulative; + bool countMatches = m_proxy->multiMatchBehavior() == QItemModelBarDataProxy::MMBAverage; + bool takeFirst = m_proxy->multiMatchBehavior() == QItemModelBarDataProxy::MMBFirst; + QHash<QString, QHash<QString, int> > *matchCountMap = 0; + if (countMatches) + matchCountMap = new QHash<QString, QHash<QString, int> >; + for (int i = 0; i < rowCount; i++) { for (int j = 0; j < columnCount; j++) { QModelIndex index = m_itemModel->index(i, j); QString rowRoleStr = index.data(rowRole).toString(); + if (haveRowPattern) + rowRoleStr.replace(rowPattern, rowReplace); QString columnRoleStr = index.data(columnRole).toString(); - itemValueMap[rowRoleStr][columnRoleStr] = index.data(valueRole).toReal(); - if (rotationRole != noRoleIndex) - itemRotationMap[rowRoleStr][columnRoleStr] = index.data(rotationRole).toReal(); + if (haveColPattern) + columnRoleStr.replace(colPattern, colReplace); + QVariant valueVar = index.data(m_valueRole); + float value; + if (m_haveValuePattern) + value = valueVar.toString().replace(m_valuePattern, m_valueReplace).toFloat(); + else + value = valueVar.toFloat(); + if (countMatches) + (*matchCountMap)[rowRoleStr][columnRoleStr]++; + + if (cumulative) { + itemValueMap[rowRoleStr][columnRoleStr] += value; + } else { + if (takeFirst && itemValueMap.contains(rowRoleStr)) { + if (itemValueMap.value(rowRoleStr).contains(columnRoleStr)) + continue; // We already have a value for this row/column combo + } + itemValueMap[rowRoleStr][columnRoleStr] = value; + } + + if (m_rotationRole != noRoleIndex) { + QVariant rotationVar = index.data(m_rotationRole); + float rotation; + if (m_haveRotationPattern) { + rotation = rotationVar.toString().replace(m_rotationPattern, + m_rotationReplace).toFloat(); + } else { + rotation = rotationVar.toFloat(); + } + if (cumulative) { + itemRotationMap[rowRoleStr][columnRoleStr] += rotation; + } else { + // We know we are in take last mode if we get here, + // as take first mode skips to next loop already earlier + itemRotationMap[rowRoleStr][columnRoleStr] = rotation; + } + } if (generateRows && !rowListHash.value(rowRoleStr, false)) { rowListHash.insert(rowRoleStr, true); rowList << rowRoleStr; @@ -141,15 +266,24 @@ void BarItemModelHandler::resolveModel() QString rowKey = rowList.at(i); QBarDataRow &newProxyRow = *m_proxyArray->at(i); for (int j = 0; j < columnList.size(); j++) { - newProxyRow[j].setValue(itemValueMap[rowKey][columnList.at(j)]); - if (rotationRole != noRoleIndex) - newProxyRow[j].setRotation(itemRotationMap[rowKey][columnList.at(j)]); + float value = itemValueMap[rowKey][columnList.at(j)]; + if (countMatches) + value /= float((*matchCountMap)[rowKey][columnList.at(j)]); + newProxyRow[j].setValue(value); + if (m_rotationRole != noRoleIndex) { + float angle = itemRotationMap[rowKey][columnList.at(j)]; + if (countMatches) + angle /= float((*matchCountMap)[rowKey][columnList.at(j)]); + newProxyRow[j].setRotation(angle); + } } } rowLabels = rowList; columnLabels = columnList; m_columnCount = columnList.size(); + + delete matchCountMap; } m_proxy->resetArray(m_proxyArray, rowLabels, columnLabels); diff --git a/src/datavisualization/data/baritemmodelhandler_p.h b/src/datavisualization/data/baritemmodelhandler_p.h index 7bf7b0a1..6dea906e 100644 --- a/src/datavisualization/data/baritemmodelhandler_p.h +++ b/src/datavisualization/data/baritemmodelhandler_p.h @@ -41,12 +41,24 @@ public: BarItemModelHandler(QItemModelBarDataProxy *proxy, QObject *parent = 0); virtual ~BarItemModelHandler(); +public slots: + virtual void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, + const QVector<int> &roles = QVector<int> ()); + protected: void virtual resolveModel(); QItemModelBarDataProxy *m_proxy; // Not owned QBarDataArray *m_proxyArray; // Not owned int m_columnCount; + int m_valueRole; + int m_rotationRole; + QRegExp m_valuePattern; + QRegExp m_rotationPattern; + QString m_valueReplace; + QString m_rotationReplace; + bool m_haveValuePattern; + bool m_haveRotationPattern; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/barrenderitem.cpp b/src/datavisualization/data/barrenderitem.cpp index 50d2a4b4..eab5178b 100644 --- a/src/datavisualization/data/barrenderitem.cpp +++ b/src/datavisualization/data/barrenderitem.cpp @@ -17,15 +17,13 @@ ****************************************************************************/ #include "barrenderitem_p.h" -#include "bars3drenderer_p.h" QT_BEGIN_NAMESPACE_DATAVISUALIZATION BarRenderItem::BarRenderItem() : AbstractRenderItem(), m_value(0), - m_height(0.0f), - m_seriesIndex(0) + m_height(0.0f) { } @@ -35,7 +33,6 @@ BarRenderItem::BarRenderItem(const BarRenderItem &other) m_value = other.m_value; m_position = other.m_position; m_height = other.m_height; - m_seriesIndex = other.m_seriesIndex; } BarRenderItem::~BarRenderItem() @@ -67,8 +64,8 @@ void BarRenderSliceItem::setItem(const BarRenderItem &renderItem) m_value = renderItem.value(); m_position = renderItem.position(); m_height = renderItem.height(); - m_seriesIndex = renderItem.seriesIndex(); m_sliceLabel = QString(); + delete m_sliceLabelItem; m_sliceLabelItem = 0; } diff --git a/src/datavisualization/data/barrenderitem_p.h b/src/datavisualization/data/barrenderitem_p.h index 1122053d..72c5abc1 100644 --- a/src/datavisualization/data/barrenderitem_p.h +++ b/src/datavisualization/data/barrenderitem_p.h @@ -33,8 +33,6 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION -class Bars3DRenderer; - class BarRenderItem : public AbstractRenderItem { public: @@ -54,16 +52,10 @@ public: inline void setHeight(GLfloat height) { m_height = height; } inline GLfloat height() const { return m_height; } - // Series index in visual series that this item belongs to. - // This is only utilized by slicing, so it may not be up to date on all items. - inline void setSeriesIndex(int seriesIndex) { m_seriesIndex = seriesIndex; } - inline int seriesIndex() const { return m_seriesIndex; } - protected: float m_value; QPoint m_position; // x = row, y = column GLfloat m_height; - int m_seriesIndex; friend class QBarDataItem; }; diff --git a/src/datavisualization/data/customrenderitem.cpp b/src/datavisualization/data/customrenderitem.cpp new file mode 100644 index 00000000..a1c70057 --- /dev/null +++ b/src/datavisualization/data/customrenderitem.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "customrenderitem_p.h" + +QT_BEGIN_NAMESPACE_DATAVISUALIZATION + +CustomRenderItem::CustomRenderItem() + : AbstractRenderItem(), + m_texture(0), + m_object(0), + m_visible(true), + m_renderer(0) +{ +} + +CustomRenderItem::~CustomRenderItem() +{ + ObjectHelper::releaseObjectHelper(m_renderer, m_object); +} + +void CustomRenderItem::setMesh(const QString &meshFile) +{ + ObjectHelper::resetObjectHelper(m_renderer, m_object, meshFile); +} + +QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h new file mode 100644 index 00000000..4fb94276 --- /dev/null +++ b/src/datavisualization/data/customrenderitem_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef CUSTOMRENDERITEM_P_H +#define CUSTOMRENDERITEM_P_H + +#include "abstractrenderitem_p.h" +#include "objecthelper_p.h" + +QT_BEGIN_NAMESPACE_DATAVISUALIZATION + +class QCustom3DItem; +class Abstract3DRenderer; + +class CustomRenderItem : public AbstractRenderItem +{ +public: + CustomRenderItem(); + virtual ~CustomRenderItem(); + + inline void setTexture(GLuint texture) { m_texture = texture; } + inline GLuint texture() const { return m_texture; } + void setMesh(const QString &meshFile); + inline ObjectHelper *mesh() const { return m_object; } + inline void setScaling(const QVector3D &scaling) { m_scaling = scaling; } + inline QVector3D scaling() const { return m_scaling; } + inline void setPosition(const QVector3D &position) { m_position = position; } + inline QVector3D position() const { return m_position; } + inline void setPositionAbsolute(bool absolute) { m_absolute = absolute; } + inline bool isPositionAbsolute() const { return m_absolute; } + inline void setBlendNeeded(bool blend) { m_needBlend = blend; } + inline bool isBlendNeeded() const { return m_needBlend; } + inline void setVisible(bool visible) { m_visible = visible; } + inline bool isVisible() const { return m_visible; } + inline void setItemPointer(QCustom3DItem *item) { m_item = item; } + inline QCustom3DItem *itemPointer() const { return m_item; } + inline void setValid(bool valid) { m_valid = valid; } + inline bool isValid() const { return m_valid; } + inline void setIndex(int index) { m_index = index; } + inline int index() const { return m_index; } + inline void setShadowCasting(bool shadowCasting) { m_shadowCasting = shadowCasting; } + inline bool isShadowCasting() const { return m_shadowCasting; } + inline void setFacingCamera(bool facing) { m_isFacingCamera = facing; } + inline bool isFacingCamera() const { return m_isFacingCamera; } + inline void setRenderer(Abstract3DRenderer *renderer) { m_renderer = renderer; } + +private: + Q_DISABLE_COPY(CustomRenderItem) + + GLuint m_texture; + QVector3D m_scaling; + QVector3D m_position; + bool m_absolute; + ObjectHelper *m_object; // shared reference + bool m_needBlend; + bool m_visible; + bool m_valid; + int m_index; + bool m_shadowCasting; + bool m_isFacingCamera; + QCustom3DItem *m_item; + Abstract3DRenderer *m_renderer; +}; +typedef QHash<QCustom3DItem *, CustomRenderItem *> CustomRenderItemArray; + +QT_END_NAMESPACE_DATAVISUALIZATION + +#endif diff --git a/src/datavisualization/data/data.pri b/src/datavisualization/data/data.pri index 6ebfed6b..73f398bf 100644 --- a/src/datavisualization/data/data.pri +++ b/src/datavisualization/data/data.pri @@ -36,7 +36,12 @@ HEADERS += \ $$PWD/qscatter3dseries.h \ $$PWD/qscatter3dseries_p.h \ $$PWD/qsurface3dseries.h \ - $$PWD/qsurface3dseries_p.h + $$PWD/qsurface3dseries_p.h \ + $$PWD/customrenderitem_p.h \ + $$PWD/qcustom3ditem.h \ + $$PWD/qcustom3ditem_p.h \ + $$PWD/qcustom3dlabel.h \ + $$PWD/qcustom3dlabel_p.h SOURCES += \ $$PWD/labelitem.cpp \ @@ -61,4 +66,7 @@ SOURCES += \ $$PWD/qabstract3dseries.cpp \ $$PWD/qbar3dseries.cpp \ $$PWD/qscatter3dseries.cpp \ - $$PWD/qsurface3dseries.cpp + $$PWD/qsurface3dseries.cpp \ + $$PWD/customrenderitem.cpp \ + $$PWD/qcustom3ditem.cpp \ + $$PWD/qcustom3dlabel.cpp diff --git a/src/datavisualization/data/labelitem_p.h b/src/datavisualization/data/labelitem_p.h index 3a2c1eb1..89b6cc56 100644 --- a/src/datavisualization/data/labelitem_p.h +++ b/src/datavisualization/data/labelitem_p.h @@ -30,7 +30,6 @@ #define LABELITEM_P_H #include "datavisualizationglobal_p.h" -#include <QtGui/QOpenGLFunctions> #include <QtCore/QSize> QT_BEGIN_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qabstract3dseries.cpp b/src/datavisualization/data/qabstract3dseries.cpp index e593a1d9..f8fe6b4f 100644 --- a/src/datavisualization/data/qabstract3dseries.cpp +++ b/src/datavisualization/data/qabstract3dseries.cpp @@ -16,7 +16,6 @@ ** ****************************************************************************/ -#include "qabstract3dseries.h" #include "qabstract3dseries_p.h" #include "qabstractdataproxy_p.h" #include "abstract3dcontroller_p.h" @@ -27,7 +26,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QAbstract3DSeries * \inmodule QtDataVisualization * \brief Base class for all QtDataVisualization series. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * You use the visualization type specific inherited classes instead of the base class. * \sa QBar3DSeries, QScatter3DSeries, QSurface3DSeries, {Qt Data Visualization Data Handling} @@ -53,7 +52,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * * This type is uncreatable, but contains properties that are exposed via subtypes. * - * For Abstract3DSeries enums, see \l QAbstract3DSeries::SeriesType and \l QAbstract3DSeries::Mesh + * For Abstract3DSeries enums, see \l QAbstract3DSeries::SeriesType and \l{QAbstract3DSeries::Mesh}. * * \sa Bar3DSeries, Scatter3DSeries, Surface3DSeries, {Qt Data Visualization Data Handling} */ @@ -102,7 +101,8 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * Arrow pointing upwards. * \value MeshPoint * 2D point. Usable only with Q3DScatter. - * \b Note: Shadows and color gradients do not affect this style. + * \b Note: Shadows do not affect this style. Color style Q3DTheme::ColorStyleObjectGradient + * is not supported by this style. */ /*! @@ -240,6 +240,27 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION */ /*! + * \qmlproperty string Abstract3DSeries::itemLabel + * \since QtDataVisualization 1.1 + * + * Contains the formatted item label. If there is no selected item or the selected item is not + * visible, returns an empty string. + * + * \sa itemLabelFormat + */ + +/*! + * \qmlproperty bool Abstract3DSeries::itemLabelVisible + * \since QtDataVisualization 1.1 + * + * If \c true, item labels are drawn as floating labels in the graph. Otherwise item labels are not + * drawn. If you prefer to show the item label in an external control, set this property to + * \c false. Defaults to \c true. + * + * \sa itemLabelFormat, itemLabel + */ + +/*! * \qmlmethod void Abstract3DSeries::setMeshAxisAndAngle(vector3d axis, real angle) * * A convenience function to construct mesh rotation quaternion from axis and angle. @@ -586,9 +607,47 @@ QString QAbstract3DSeries::name() const return d_ptr->m_name; } +/*! + * \property QAbstract3DSeries::itemLabel + * \since QtDataVisualization 1.1 + * + * Contains the formatted item label. If there is no selected item or the selected item is not + * visible, returns an empty string. + * + * \sa itemLabelFormat + */ +QString QAbstract3DSeries::itemLabel() const +{ + return d_ptr->itemLabel(); +} + +/*! + * \property QAbstract3DSeries::itemLabelVisible + * \since QtDataVisualization 1.1 + * + * If \c true, item labels are drawn as floating labels in the graph. Otherwise item labels are not + * drawn. If you prefer to show the item label in an external control, set this property to + * \c false. Defaults to \c true. + * + * \sa itemLabelFormat, itemLabel + */ +void QAbstract3DSeries::setItemLabelVisible(bool visible) +{ + if (d_ptr->m_itemLabelVisible != visible) { + d_ptr->setItemLabelVisible(visible); + emit itemLabelVisibilityChanged(visible); + } +} + +bool QAbstract3DSeries::isItemLabelVisible() const +{ + return d_ptr->m_itemLabelVisible; +} + // QAbstract3DSeriesPrivate -QAbstract3DSeriesPrivate::QAbstract3DSeriesPrivate(QAbstract3DSeries *q, QAbstract3DSeries::SeriesType type) +QAbstract3DSeriesPrivate::QAbstract3DSeriesPrivate(QAbstract3DSeries *q, + QAbstract3DSeries::SeriesType type) : QObject(0), q_ptr(q), m_type(type), @@ -597,7 +656,9 @@ QAbstract3DSeriesPrivate::QAbstract3DSeriesPrivate(QAbstract3DSeries *q, QAbstra m_controller(0), m_mesh(QAbstract3DSeries::MeshCube), m_meshSmooth(false), - m_colorStyle(Q3DTheme::ColorStyleUniform) + m_colorStyle(Q3DTheme::ColorStyleUniform), + m_itemLabelDirty(true), + m_itemLabelVisible(true) { } @@ -630,53 +691,67 @@ void QAbstract3DSeriesPrivate::setController(Abstract3DController *controller) connectControllerAndProxy(controller); m_controller = controller; q_ptr->setParent(controller); + markItemLabelDirty(); } void QAbstract3DSeriesPrivate::setItemLabelFormat(const QString &format) { m_itemLabelFormat = format; - m_changeTracker.itemLabelFormatChanged = true; - if (m_controller) - m_controller->markSeriesVisualsDirty(); + markItemLabelDirty(); } void QAbstract3DSeriesPrivate::setVisible(bool visible) { m_visible = visible; - if (m_controller) - m_controller->markSeriesVisualsDirty(); + markItemLabelDirty(); } void QAbstract3DSeriesPrivate::setMesh(QAbstract3DSeries::Mesh mesh) { m_mesh = mesh; m_changeTracker.meshChanged = true; - if (m_controller) + if (m_controller) { m_controller->markSeriesVisualsDirty(); + + if (m_controller->optimizationHints().testFlag(QAbstract3DGraph::OptimizationStatic)) + m_controller->markDataDirty(); + } } void QAbstract3DSeriesPrivate::setMeshSmooth(bool enable) { m_meshSmooth = enable; m_changeTracker.meshSmoothChanged = true; - if (m_controller) + if (m_controller) { m_controller->markSeriesVisualsDirty(); + + if (m_controller->optimizationHints().testFlag(QAbstract3DGraph::OptimizationStatic)) + m_controller->markDataDirty(); + } } void QAbstract3DSeriesPrivate::setMeshRotation(const QQuaternion &rotation) { m_meshRotation = rotation; m_changeTracker.meshRotationChanged = true; - if (m_controller) + if (m_controller) { m_controller->markSeriesVisualsDirty(); + + if (m_controller->optimizationHints().testFlag(QAbstract3DGraph::OptimizationStatic)) + m_controller->markDataDirty(); + } } void QAbstract3DSeriesPrivate::setUserDefinedMesh(const QString &meshFile) { m_userDefinedMesh = meshFile; m_changeTracker.userDefinedMeshChanged = true; - if (m_controller) + if (m_controller) { m_controller->markSeriesVisualsDirty(); + + if (m_controller->optimizationHints().testFlag(QAbstract3DGraph::OptimizationStatic)) + m_controller->markDataDirty(); + } } void QAbstract3DSeriesPrivate::setColorStyle(Q3DTheme::ColorStyle style) @@ -738,9 +813,8 @@ void QAbstract3DSeriesPrivate::setMultiHighlightGradient(const QLinearGradient & void QAbstract3DSeriesPrivate::setName(const QString &name) { m_name = name; + markItemLabelDirty(); m_changeTracker.nameChanged = true; - if (m_controller) - m_controller->markSeriesVisualsDirty(); } void QAbstract3DSeriesPrivate::resetToTheme(const Q3DTheme &theme, int seriesIndex, bool force) @@ -780,4 +854,36 @@ void QAbstract3DSeriesPrivate::resetToTheme(const Q3DTheme &theme, int seriesInd } } +QString QAbstract3DSeriesPrivate::itemLabel() +{ + if (m_itemLabelDirty) { + QString oldLabel = m_itemLabel; + if (m_controller && m_visible) + createItemLabel(); + else + m_itemLabel = QString(); + m_itemLabelDirty = false; + + if (oldLabel != m_itemLabel) + emit q_ptr->itemLabelChanged(m_itemLabel); + } + + return m_itemLabel; +} + +void QAbstract3DSeriesPrivate::markItemLabelDirty() +{ + m_itemLabelDirty = true; + m_changeTracker.itemLabelChanged = true; + if (m_controller) + m_controller->markSeriesVisualsDirty(); +} + +void QAbstract3DSeriesPrivate::setItemLabelVisible(bool visible) +{ + m_itemLabelVisible = visible; + markItemLabelDirty(); + m_changeTracker.itemLabelVisibilityChanged = true; +} + QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qabstract3dseries.h b/src/datavisualization/data/qabstract3dseries.h index bf56422f..87c4f3c1 100644 --- a/src/datavisualization/data/qabstract3dseries.h +++ b/src/datavisualization/data/qabstract3dseries.h @@ -50,6 +50,8 @@ class QT_DATAVISUALIZATION_EXPORT QAbstract3DSeries : public QObject Q_PROPERTY(QColor multiHighlightColor READ multiHighlightColor WRITE setMultiHighlightColor NOTIFY multiHighlightColorChanged) Q_PROPERTY(QLinearGradient multiHighlightGradient READ multiHighlightGradient WRITE setMultiHighlightGradient NOTIFY multiHighlightGradientChanged) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString itemLabel READ itemLabel NOTIFY itemLabelChanged REVISION 1) + Q_PROPERTY(bool itemLabelVisible READ isItemLabelVisible WRITE setItemLabelVisible NOTIFY itemLabelVisibilityChanged REVISION 1) public: enum SeriesType { @@ -119,6 +121,10 @@ public: void setName(const QString &name); QString name() const; + QString itemLabel() const; + void setItemLabelVisible(bool visible); + bool isItemLabelVisible() const; + signals: void itemLabelFormatChanged(const QString &format); void visibilityChanged(bool visible); @@ -134,6 +140,8 @@ signals: void multiHighlightColorChanged(const QColor &color); void multiHighlightGradientChanged(const QLinearGradient &gradient); void nameChanged(const QString &name); + Q_REVISION(1) void itemLabelChanged(const QString &label); + Q_REVISION(1) void itemLabelVisibilityChanged(bool visible); protected: QScopedPointer<QAbstract3DSeriesPrivate> d_ptr; diff --git a/src/datavisualization/data/qabstract3dseries_p.h b/src/datavisualization/data/qabstract3dseries_p.h index a803e99b..dd574e03 100644 --- a/src/datavisualization/data/qabstract3dseries_p.h +++ b/src/datavisualization/data/qabstract3dseries_p.h @@ -26,19 +26,18 @@ // // We mean it. -#include "datavisualizationglobal_p.h" -#include "qabstract3dseries.h" - #ifndef QABSTRACT3DSERIES_P_H #define QABSTRACT3DSERIES_P_H +#include "datavisualizationglobal_p.h" +#include "qabstract3dseries.h" + QT_BEGIN_NAMESPACE_DATAVISUALIZATION class QAbstractDataProxy; class Abstract3DController; struct QAbstract3DSeriesChangeBitField { - bool itemLabelFormatChanged : 1; bool meshChanged : 1; bool meshSmoothChanged : 1; bool meshRotationChanged : 1; @@ -51,10 +50,12 @@ struct QAbstract3DSeriesChangeBitField { bool multiHighlightColorChanged : 1; bool multiHighlightGradientChanged : 1; bool nameChanged : 1; + bool itemLabelChanged : 1; + bool itemLabelVisibilityChanged : 1; + bool visibilityChanged : 1; QAbstract3DSeriesChangeBitField() - : itemLabelFormatChanged(true), - meshChanged(true), + : meshChanged(true), meshSmoothChanged(true), meshRotationChanged(true), userDefinedMeshChanged(true), @@ -65,7 +66,10 @@ struct QAbstract3DSeriesChangeBitField { singleHighlightGradientChanged(true), multiHighlightColorChanged(true), multiHighlightGradientChanged(true), - nameChanged(true) + nameChanged(true), + itemLabelChanged(true), + itemLabelVisibilityChanged(true), + visibilityChanged(true) { } }; @@ -102,6 +106,7 @@ public: virtual void setDataProxy(QAbstractDataProxy *proxy); virtual void setController(Abstract3DController *controller); virtual void connectControllerAndProxy(Abstract3DController *newController) = 0; + virtual void createItemLabel() = 0; void setItemLabelFormat(const QString &format); void setVisible(bool visible); @@ -120,6 +125,10 @@ public: void setName(const QString &name); void resetToTheme(const Q3DTheme &theme, int seriesIndex, bool force); + QString itemLabel(); + void markItemLabelDirty(); + inline bool itemLabelDirty() const { return m_itemLabelDirty; } + void setItemLabelVisible(bool visible); QAbstract3DSeriesChangeBitField m_changeTracker; QAbstract3DSeriesThemeOverrideBitField m_themeTracker; @@ -143,6 +152,9 @@ public: QLinearGradient m_multiHighlightGradient; QString m_name; + QString m_itemLabel; + bool m_itemLabelDirty; + bool m_itemLabelVisible; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qabstractdataproxy.cpp b/src/datavisualization/data/qabstractdataproxy.cpp index 18d88971..eb15cec8 100644 --- a/src/datavisualization/data/qabstractdataproxy.cpp +++ b/src/datavisualization/data/qabstractdataproxy.cpp @@ -16,7 +16,6 @@ ** ****************************************************************************/ -#include "qabstractdataproxy.h" #include "qabstractdataproxy_p.h" #include "qabstract3dseries_p.h" @@ -26,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QAbstractDataProxy * \inmodule QtDataVisualization * \brief Base class for all QtDataVisualization data proxies. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * You use the visualization type specific inherited classes instead of the base class. * \sa QBarDataProxy, QScatterDataProxy, QSurfaceDataProxy, {Qt Data Visualization Data Handling} @@ -42,7 +41,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * * This type is uncreatable, but contains properties that are exposed via subtypes. * - * For AbstractDataProxy enums, see \l QAbstractDataProxy::DataType + * For AbstractDataProxy enums, see \l{QAbstractDataProxy::DataType}. * * \sa BarDataProxy, ScatterDataProxy, SurfaceDataProxy, {Qt Data Visualization Data Handling} */ diff --git a/src/datavisualization/data/qabstractdataproxy_p.h b/src/datavisualization/data/qabstractdataproxy_p.h index eb901f4c..c2f53369 100644 --- a/src/datavisualization/data/qabstractdataproxy_p.h +++ b/src/datavisualization/data/qabstractdataproxy_p.h @@ -26,12 +26,12 @@ // // We mean it. -#include "datavisualizationglobal_p.h" -#include "qabstractdataproxy.h" - #ifndef QABSTRACTDATAPROXY_P_H #define QABSTRACTDATAPROXY_P_H +#include "datavisualizationglobal_p.h" +#include "qabstractdataproxy.h" + QT_BEGIN_NAMESPACE_DATAVISUALIZATION class QAbstract3DSeries; diff --git a/src/datavisualization/data/qbar3dseries.cpp b/src/datavisualization/data/qbar3dseries.cpp index ed4ffaba..3440a3db 100644 --- a/src/datavisualization/data/qbar3dseries.cpp +++ b/src/datavisualization/data/qbar3dseries.cpp @@ -26,7 +26,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QBar3DSeries * \inmodule QtDataVisualization * \brief Base series class for Q3DBars. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * QBar3DSeries manages the series specific visual elements, as well as series data * (via data proxy). @@ -317,6 +317,56 @@ void QBar3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *newCon } } +void QBar3DSeriesPrivate::createItemLabel() +{ + static const QString rowIndexTag(QStringLiteral("@rowIdx")); + static const QString rowLabelTag(QStringLiteral("@rowLabel")); + static const QString rowTitleTag(QStringLiteral("@rowTitle")); + static const QString colIndexTag(QStringLiteral("@colIdx")); + static const QString colLabelTag(QStringLiteral("@colLabel")); + static const QString colTitleTag(QStringLiteral("@colTitle")); + static const QString valueTitleTag(QStringLiteral("@valueTitle")); + static const QString valueLabelTag(QStringLiteral("@valueLabel")); + static const QString seriesNameTag(QStringLiteral("@seriesName")); + + if (m_selectedBar == QBar3DSeries::invalidSelectionPosition()) { + m_itemLabel = QString(); + return; + } + + QCategory3DAxis *categoryAxisZ = static_cast<QCategory3DAxis *>(m_controller->axisZ()); + QCategory3DAxis *categoryAxisX = static_cast<QCategory3DAxis *>(m_controller->axisX()); + QValue3DAxis *valueAxis = static_cast<QValue3DAxis *>(m_controller->axisY()); + qreal selectedBarValue = qreal(qptr()->dataProxy()->itemAt(m_selectedBar)->value()); + + // Custom format expects printf format specifier. There is no tag for it. + m_itemLabel = valueAxis->formatter()->stringForValue(selectedBarValue, m_itemLabelFormat); + + int selBarPosRow = m_selectedBar.x(); + int selBarPosCol = m_selectedBar.y(); + m_itemLabel.replace(rowIndexTag, QString::number(selBarPosRow)); + if (categoryAxisZ->labels().size() > selBarPosRow) + m_itemLabel.replace(rowLabelTag, categoryAxisZ->labels().at(selBarPosRow)); + else + m_itemLabel.replace(rowLabelTag, QString()); + m_itemLabel.replace(rowTitleTag, categoryAxisZ->title()); + m_itemLabel.replace(colIndexTag, QString::number(selBarPosCol)); + if (categoryAxisX->labels().size() > selBarPosCol) + m_itemLabel.replace(colLabelTag, categoryAxisX->labels().at(selBarPosCol)); + else + m_itemLabel.replace(colLabelTag, QString()); + m_itemLabel.replace(colTitleTag, categoryAxisX->title()); + m_itemLabel.replace(valueTitleTag, valueAxis->title()); + + if (m_itemLabel.contains(valueLabelTag)) { + QString valueLabelText = valueAxis->formatter()->stringForValue(selectedBarValue, + valueAxis->labelFormat()); + m_itemLabel.replace(valueLabelTag, valueLabelText); + } + + m_itemLabel.replace(seriesNameTag, m_name); +} + void QBar3DSeriesPrivate::handleMeshRotationChanged(const QQuaternion &rotation) { emit qptr()->meshAngleChanged(quaternionAngle(rotation)); @@ -325,6 +375,7 @@ void QBar3DSeriesPrivate::handleMeshRotationChanged(const QQuaternion &rotation) void QBar3DSeriesPrivate::setSelectedBar(const QPoint &position) { if (position != m_selectedBar) { + markItemLabelDirty(); m_selectedBar = position; emit qptr()->selectedBarChanged(m_selectedBar); } diff --git a/src/datavisualization/data/qbar3dseries_p.h b/src/datavisualization/data/qbar3dseries_p.h index 718f1237..c5b51108 100644 --- a/src/datavisualization/data/qbar3dseries_p.h +++ b/src/datavisualization/data/qbar3dseries_p.h @@ -43,6 +43,7 @@ public: virtual void setDataProxy(QAbstractDataProxy *proxy); virtual void connectControllerAndProxy(Abstract3DController *newController); + virtual void createItemLabel(); void handleMeshRotationChanged(const QQuaternion &rotation); diff --git a/src/datavisualization/data/qbardataitem.cpp b/src/datavisualization/data/qbardataitem.cpp index 37c2033f..8f370e24 100644 --- a/src/datavisualization/data/qbardataitem.cpp +++ b/src/datavisualization/data/qbardataitem.cpp @@ -24,7 +24,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QBarDataItem * \inmodule QtDataVisualization * \brief The QBarDataItem class provides a container for resolved data to be added to bar graphs. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * A QBarDataItem holds data for a single rendered bar in a graph. * Bar data proxies parse data into QBarDataItem instances for visualizing. diff --git a/src/datavisualization/data/qbardataitem_p.h b/src/datavisualization/data/qbardataitem_p.h index c06ddea9..623c4012 100644 --- a/src/datavisualization/data/qbardataitem_p.h +++ b/src/datavisualization/data/qbardataitem_p.h @@ -39,9 +39,6 @@ class QBarDataItemPrivate public: QBarDataItemPrivate(); virtual ~QBarDataItemPrivate(); - -protected: - friend class QBarDataItem; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qbardataproxy.cpp b/src/datavisualization/data/qbardataproxy.cpp index 1c1170ff..8e4f25de 100644 --- a/src/datavisualization/data/qbardataproxy.cpp +++ b/src/datavisualization/data/qbardataproxy.cpp @@ -16,7 +16,6 @@ ** ****************************************************************************/ -#include "qbardataproxy.h" #include "qbardataproxy_p.h" #include "qbar3dseries_p.h" @@ -26,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QBarDataProxy * \inmodule QtDataVisualization * \brief Base proxy class for Q3DBars. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * QBarDataProxy handles adding, inserting, changing and removing rows of data. * @@ -554,7 +553,8 @@ void QBarDataProxyPrivate::setRow(int rowIndex, QBarDataRow *row, const QString } } -void QBarDataProxyPrivate::setRows(int rowIndex, const QBarDataArray &rows, const QStringList *labels) +void QBarDataProxyPrivate::setRows(int rowIndex, const QBarDataArray &rows, + const QStringList *labels) { QBarDataArray &dataArray = *m_dataArray; Q_ASSERT(rowIndex >= 0 && (rowIndex + rows.size()) <= dataArray.size()); @@ -604,7 +604,8 @@ void QBarDataProxyPrivate::insertRow(int rowIndex, QBarDataRow *row, const QStri m_dataArray->insert(rowIndex, row); } -void QBarDataProxyPrivate::insertRows(int rowIndex, const QBarDataArray &rows, const QStringList *labels) +void QBarDataProxyPrivate::insertRows(int rowIndex, const QBarDataArray &rows, + const QStringList *labels) { Q_ASSERT(rowIndex >= 0 && rowIndex <= m_dataArray->size()); if (labels) @@ -656,7 +657,8 @@ void QBarDataProxyPrivate::clearArray() * \internal * Fixes the row label array to include specified labels. */ -void QBarDataProxyPrivate::fixRowLabels(int startIndex, int count, const QStringList &newLabels, bool isInsert) +void QBarDataProxyPrivate::fixRowLabels(int startIndex, int count, const QStringList &newLabels, + bool isInsert) { bool changed = false; int currentSize = m_rowLabels.size(); diff --git a/src/datavisualization/data/qbardataproxy_p.h b/src/datavisualization/data/qbardataproxy_p.h index eb0a0873..4d1489d9 100644 --- a/src/datavisualization/data/qbardataproxy_p.h +++ b/src/datavisualization/data/qbardataproxy_p.h @@ -31,7 +31,6 @@ #include "qbardataproxy.h" #include "qabstractdataproxy_p.h" -#include "qbardataitem.h" QT_BEGIN_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qcustom3ditem.cpp b/src/datavisualization/data/qcustom3ditem.cpp new file mode 100644 index 00000000..f5d8470f --- /dev/null +++ b/src/datavisualization/data/qcustom3ditem.cpp @@ -0,0 +1,422 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "qcustom3ditem_p.h" + +QT_BEGIN_NAMESPACE_DATAVISUALIZATION + +/*! + * \class QCustom3DItem + * \inmodule QtDataVisualization + * \brief The QCustom3DItem class is for creating custom items to be added to a graph. + * \since QtDataVisualization 1.1 + * + * This class is for creating custom items to be added to a graph. The item has a custom mesh, + * position, scaling, rotation, and an optional texture. + * + * \sa QAbstract3DGraph::addCustomItem() + */ + +/*! + * \qmltype Custom3DItem + * \inqmlmodule QtDataVisualization + * \since QtDataVisualization 1.1 + * \ingroup datavisualization_qml + * \instantiates QCustom3DItem + * \brief The Custom3DItem type is for creating custom items to be added to a graph. + * + * This type is for creating custom items to be added to a graph. The item has a custom mesh, + * position, scaling, rotation, and an optional texture. + */ + +/*! \qmlproperty string Custom3DItem::meshFile + * + * Holds item mesh file name. Item in the file must be in Wavefront obj format and include + * vertices, normals, and UVs. It also needs to be in triangles. + */ + +/*! \qmlproperty string Custom3DItem::textureFile + * + * Holds the texture file name for the item. If left unset, a solid gray texture will be + * used. + * + * \note To conserve memory the Image loaded from the file is cleared after a texture is created. + */ + +/*! \qmlproperty vector3d Custom3DItem::position + * + * Holds the item \a position as a vector3d. Defaults to \c {vector3d(0.0, 0.0, 0.0)}. + * + * Item position is either in data coordinates or in absolute coordinates, depending on + * positionAbsolute property. When using absolute coordinates, values between \c{-1.0...1.0} are + * within axis ranges. + * + * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}. + * + * \sa positionAbsolute + */ + +/*! \qmlproperty bool Custom3DItem::positionAbsolute + * + * This property dictates if item position is to be handled in data coordinates or in absolute + * coordinates. Defaults to \c{false}. Items with absolute coordinates will always be rendered, + * whereas items with data coordinates are only rendered if they are within axis ranges. + * + * \sa position + */ + +/*! \qmlproperty vector3d Custom3DItem::scaling + * + * Holds the item \a scaling as a vector3d. Defaults to \c {vector3d(0.1, 0.1, 0.1)}. + * The default value sets the item to 10% of the height of the graph, provided the item size is + * normalized. + */ + +/*! \qmlproperty quaternion Custom3DItem::rotation + * + * Holds the item \a rotation as a quaternion. Defaults to \c {quaternion(0.0, 0.0, 0.0, 0.0)}. + */ + +/*! \qmlproperty bool Custom3DItem::visible + * + * Sets the item \a visible. Defaults to \c{true}. + */ + +/*! \qmlproperty bool Custom3DItem::shadowCasting + * + * Sets shadow casting for the item to \a enabled. Defaults to \c{true}. + * If set \c{false}, the item does not cast shadows regardless of + * \l{QAbstract3DGraph::ShadowQuality}{ShadowQuality}. + */ + +/*! + * \qmlmethod void Custom3DItem::setRotationAxisAndAngle(vector3d axis, real angle) + * + * A convenience function to construct rotation quaternion from \a axis and \a angle. + * + * \sa rotation + */ + +/*! + * Constructs QCustom3DItem with given \a parent. + */ +QCustom3DItem::QCustom3DItem(QObject *parent) : + QObject(parent), + d_ptr(new QCustom3DItemPrivate(this)) +{ + setTextureImage(QImage()); +} + +/*! + * \internal + */ +QCustom3DItem::QCustom3DItem(QCustom3DItemPrivate *d, QObject *parent) : + QObject(parent), + d_ptr(d) +{ + setTextureImage(QImage()); +} + +/*! + * Constructs QCustom3DItem with given \a meshFile, \a position, \a scaling, + * \a rotation, \a texture image, and optional \a parent. + */ +QCustom3DItem::QCustom3DItem(const QString &meshFile, const QVector3D &position, + const QVector3D &scaling, const QQuaternion &rotation, + const QImage &texture, QObject *parent) : + QObject(parent), + d_ptr(new QCustom3DItemPrivate(this, meshFile, position, scaling, rotation)) +{ + setTextureImage(texture); +} + +/*! + * Destroys QCustom3DItem. + */ +QCustom3DItem::~QCustom3DItem() +{ +} + +/*! \property QCustom3DItem::meshFile + * + * Holds item mesh file name. Item in the file must be in Wavefront obj format and include + * vertices, normals, and UVs. It also needs to be in triangles. + */ +void QCustom3DItem::setMeshFile(const QString &meshFile) +{ + if (d_ptr->m_meshFile != meshFile) { + d_ptr->m_meshFile = meshFile; + d_ptr->m_dirtyBits.meshDirty = true; + emit meshFileChanged(meshFile); + emit d_ptr->needUpdate(); + } +} + +QString QCustom3DItem::meshFile() const +{ + return d_ptr->m_meshFile; +} + +/*! \property QCustom3DItem::position + * + * Holds the item \a position as a QVector3D. Defaults to \c {QVector3D(0.0, 0.0, 0.0)}. + * + * Item position is either in data coordinates or in absolute coordinates, depending on + * positionAbsolute property. When using absolute coordinates, values between \c{-1.0...1.0} are + * within axis ranges. + * + * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}. + * + * \sa positionAbsolute + */ +void QCustom3DItem::setPosition(const QVector3D &position) +{ + if (d_ptr->m_position != position) { + d_ptr->m_position = position; + d_ptr->m_dirtyBits.positionDirty = true; + emit positionChanged(position); + emit d_ptr->needUpdate(); + } +} + +QVector3D QCustom3DItem::position() const +{ + return d_ptr->m_position; +} + +/*! \property QCustom3DItem::positionAbsolute + * + * This property dictates if item position is to be handled in data coordinates or in absolute + * coordinates. Defaults to \c{false}. Items with absolute coordinates will always be rendered, + * whereas items with data coordinates are only rendered if they are within axis ranges. + * + * \sa position + */ +void QCustom3DItem::setPositionAbsolute(bool positionAbsolute) +{ + if (d_ptr->m_positionAbsolute != positionAbsolute) { + d_ptr->m_positionAbsolute = positionAbsolute; + d_ptr->m_dirtyBits.positionAbsoluteDirty = true; + emit positionAbsoluteChanged(positionAbsolute); + emit d_ptr->needUpdate(); + } +} + +bool QCustom3DItem::isPositionAbsolute() const +{ + return d_ptr->m_positionAbsolute; +} + +/*! \property QCustom3DItem::scaling + * + * Holds the item \a scaling as a QVector3D. Defaults to \c {QVector3D(0.1, 0.1, 0.1)}. + * The default value sets the item to 10% of the height of the graph, provided the item size is + * normalized. + */ +void QCustom3DItem::setScaling(const QVector3D &scaling) +{ + if (d_ptr->m_scaling != scaling) { + d_ptr->m_scaling = scaling; + d_ptr->m_dirtyBits.scalingDirty = true; + emit scalingChanged(scaling); + emit d_ptr->needUpdate(); + } +} + +QVector3D QCustom3DItem::scaling() const +{ + return d_ptr->m_scaling; +} + +/*! \property QCustom3DItem::rotation + * + * Holds the item \a rotation as a QQuaternion. Defaults to \c {QQuaternion(0.0, 0.0, 0.0, 0.0)}. + */ +void QCustom3DItem::setRotation(const QQuaternion &rotation) +{ + if (d_ptr->m_rotation != rotation) { + d_ptr->m_rotation = rotation; + d_ptr->m_dirtyBits.rotationDirty = true; + emit rotationChanged(rotation); + emit d_ptr->needUpdate(); + } +} + +QQuaternion QCustom3DItem::rotation() +{ + return d_ptr->m_rotation; +} + +/*! \property QCustom3DItem::visible + * + * Sets the item \a visible. Defaults to \c{true}. + */ +void QCustom3DItem::setVisible(bool visible) +{ + if (d_ptr->m_visible != visible) { + d_ptr->m_visible = visible; + d_ptr->m_dirtyBits.visibleDirty = true; + emit visibleChanged(visible); + emit d_ptr->needUpdate(); + } +} + +bool QCustom3DItem::isVisible() const +{ + return d_ptr->m_visible; +} + + +/*! \property QCustom3DItem::shadowCasting + * + * Sets shadow casting for the item to \a enabled. Defaults to \c{true}. + * If set \c{false}, the item does not cast shadows regardless of QAbstract3DGraph::ShadowQuality. + */ +void QCustom3DItem::setShadowCasting(bool enabled) +{ + if (d_ptr->m_shadowCasting != enabled) { + d_ptr->m_shadowCasting = enabled; + d_ptr->m_dirtyBits.shadowCastingDirty = true; + emit shadowCastingChanged(enabled); + emit d_ptr->needUpdate(); + } +} + +bool QCustom3DItem::isShadowCasting() const +{ + return d_ptr->m_shadowCasting; +} + +/*! + * A convenience function to construct rotation quaternion from \a axis and \a angle. + * + * \sa rotation + */ +void QCustom3DItem::setRotationAxisAndAngle(const QVector3D &axis, float angle) +{ + setRotation(QQuaternion::fromAxisAndAngle(axis, angle)); +} + +/*! + * Set the \a textureImage as a QImage for the item. Texture defaults to solid gray. + * + * \note To conserve memory the given QImage is cleared after a texture is created. + */ +void QCustom3DItem::setTextureImage(const QImage &textureImage) +{ + if (textureImage != d_ptr->m_textureImage) { + if (textureImage.isNull()) { + // Make a solid gray texture + d_ptr->m_textureImage = QImage(2, 2, QImage::Format_RGB32); + d_ptr->m_textureImage.fill(Qt::gray); + } else { + d_ptr->m_textureImage = textureImage; + } + + if (!d_ptr->m_textureFile.isEmpty()) { + d_ptr->m_textureFile.clear(); + emit textureFileChanged(d_ptr->m_textureFile); + } + d_ptr->m_dirtyBits.textureDirty = true; + emit d_ptr->needUpdate(); + } +} + +/*! \property QCustom3DItem::textureFile + * + * Holds the texture file name for the item. If both this and texture image are unset, a solid + * gray texture will be used. + * + * \note To conserve memory the QImage loaded from the file is cleared after a texture is created. + */ +void QCustom3DItem::setTextureFile(const QString &textureFile) +{ + if (d_ptr->m_textureFile != textureFile) { + d_ptr->m_textureFile = textureFile; + if (!textureFile.isEmpty()) { + d_ptr->m_textureImage = QImage(textureFile); + } else { + d_ptr->m_textureImage = QImage(2, 2, QImage::Format_RGB32); + d_ptr->m_textureImage.fill(Qt::gray); + } + emit textureFileChanged(textureFile); + d_ptr->m_dirtyBits.textureDirty = true; + emit d_ptr->needUpdate(); + } +} + +QString QCustom3DItem::textureFile() const +{ + return d_ptr->m_textureFile; +} + +QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q) : + q_ptr(q), + m_position(QVector3D(0.0f, 0.0f, 0.0f)), + m_positionAbsolute(false), + m_scaling(QVector3D(0.1f, 0.1f, 0.1f)), + m_rotation(QQuaternion(0.0f, 0.0f, 0.0f, 0.0f)), + m_visible(true), + m_shadowCasting(true), + m_isLabelItem(false) +{ +} + +QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q, const QString &meshFile, + const QVector3D &position, const QVector3D &scaling, + const QQuaternion &rotation) : + q_ptr(q), + m_meshFile(meshFile), + m_position(position), + m_positionAbsolute(false), + m_scaling(scaling), + m_rotation(rotation), + m_visible(true), + m_shadowCasting(true), + m_isLabelItem(false) +{ +} + +QCustom3DItemPrivate::~QCustom3DItemPrivate() +{ +} + +QImage QCustom3DItemPrivate::textureImage() +{ + return m_textureImage; +} + +void QCustom3DItemPrivate::clearTextureImage() +{ + m_textureImage = QImage(); + m_textureFile.clear(); +} + +void QCustom3DItemPrivate::resetDirtyBits() +{ + m_dirtyBits.textureDirty = false; + m_dirtyBits.meshDirty = false; + m_dirtyBits.positionDirty = false; + m_dirtyBits.positionAbsoluteDirty = false; + m_dirtyBits.scalingDirty = false; + m_dirtyBits.rotationDirty = false; + m_dirtyBits.visibleDirty = false; + m_dirtyBits.shadowCastingDirty = false; +} + +QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qcustom3ditem.h b/src/datavisualization/data/qcustom3ditem.h new file mode 100644 index 00000000..2f7f37cf --- /dev/null +++ b/src/datavisualization/data/qcustom3ditem.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef QCUSTOM3DITEM_H +#define QCUSTOM3DITEM_H + +#include <QtDataVisualization/qdatavisualizationglobal.h> +#include <QtGui/QImage> +#include <QtGui/QVector3D> +#include <QtGui/QQuaternion> + +QT_BEGIN_NAMESPACE_DATAVISUALIZATION + +class QCustom3DItemPrivate; + +class QT_DATAVISUALIZATION_EXPORT QCustom3DItem : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString meshFile READ meshFile WRITE setMeshFile NOTIFY meshFileChanged) + Q_PROPERTY(QString textureFile READ textureFile WRITE setTextureFile NOTIFY textureFileChanged) + Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(bool positionAbsolute READ isPositionAbsolute WRITE setPositionAbsolute NOTIFY positionAbsoluteChanged) + Q_PROPERTY(QVector3D scaling READ scaling WRITE setScaling NOTIFY scalingChanged) + Q_PROPERTY(QQuaternion rotation READ rotation WRITE setRotation NOTIFY rotationChanged) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) + Q_PROPERTY(bool shadowCasting READ isShadowCasting WRITE setShadowCasting NOTIFY shadowCastingChanged) + +public: + explicit QCustom3DItem(QObject *parent = 0); + explicit QCustom3DItem(const QString &meshFile, const QVector3D &position, + const QVector3D &scaling, const QQuaternion &rotation, + const QImage &texture, QObject *parent = 0); + virtual ~QCustom3DItem(); + + void setMeshFile(const QString &meshFile); + QString meshFile() const; + + void setTextureFile(const QString &textureFile); + QString textureFile() const; + + void setPosition(const QVector3D &position); + QVector3D position() const; + + void setPositionAbsolute(bool positionAbsolute); + bool isPositionAbsolute() const; + + void setScaling(const QVector3D &scaling); + QVector3D scaling() const; + + void setRotation(const QQuaternion &rotation); + QQuaternion rotation(); + + void setVisible(bool visible); + bool isVisible() const; + + void setShadowCasting(bool enabled); + bool isShadowCasting() const; + + Q_INVOKABLE void setRotationAxisAndAngle(const QVector3D &axis, float angle); + + void setTextureImage(const QImage &textureImage); + +signals: + void meshFileChanged(const QString &meshFile); + void textureFileChanged(const QString &textureFile); + void positionChanged(const QVector3D &position); + void positionAbsoluteChanged(bool positionAbsolute); + void scalingChanged(const QVector3D &scaling); + void rotationChanged(const QQuaternion &rotation); + void visibleChanged(bool visible); + void shadowCastingChanged(bool shadowCasting); + +protected: + QCustom3DItem(QCustom3DItemPrivate *d, QObject *parent = 0); + + QScopedPointer<QCustom3DItemPrivate> d_ptr; + +private: + Q_DISABLE_COPY(QCustom3DItem) + + friend class Abstract3DRenderer; + friend class Abstract3DController; +}; + +QT_END_NAMESPACE_DATAVISUALIZATION + +#endif diff --git a/src/datavisualization/data/qcustom3ditem_p.h b/src/datavisualization/data/qcustom3ditem_p.h new file mode 100644 index 00000000..c1ce5996 --- /dev/null +++ b/src/datavisualization/data/qcustom3ditem_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QCUSTOM3DITEM_P_H +#define QCUSTOM3DITEM_P_H + +#include "qcustom3ditem.h" + +QT_BEGIN_NAMESPACE_DATAVISUALIZATION + +struct QCustomItemDirtyBitField { + bool textureDirty : 1; + bool meshDirty : 1; + bool positionDirty : 1; + bool positionAbsoluteDirty : 1; + bool scalingDirty : 1; + bool rotationDirty : 1; + bool visibleDirty : 1; + bool shadowCastingDirty : 1; + + QCustomItemDirtyBitField() + : textureDirty(false), + meshDirty(false), + positionDirty(false), + positionAbsoluteDirty(false), + scalingDirty(false), + rotationDirty(false), + visibleDirty(false), + shadowCastingDirty(false) + { + } +}; + +class QCustom3DItemPrivate : public QObject +{ + Q_OBJECT +public: + QCustom3DItemPrivate(QCustom3DItem *q); + QCustom3DItemPrivate(QCustom3DItem *q, const QString &meshFile, const QVector3D &position, + const QVector3D &scaling, const QQuaternion &rotation); + virtual ~QCustom3DItemPrivate(); + + QImage textureImage(); + void clearTextureImage(); + void resetDirtyBits(); + +public: + QCustom3DItem *q_ptr; + QImage m_textureImage; + QString m_textureFile; + QString m_meshFile; + QVector3D m_position; + bool m_positionAbsolute; + QVector3D m_scaling; + QQuaternion m_rotation; + bool m_visible; + bool m_shadowCasting; + + bool m_isLabelItem; + + QCustomItemDirtyBitField m_dirtyBits; + +signals: + void needUpdate(); + +private: + QCustom3DItemPrivate(QCustom3DItemPrivate *d); + + friend class QCustom3DItem; +}; + +QT_END_NAMESPACE_DATAVISUALIZATION + +#endif diff --git a/src/datavisualization/data/qcustom3dlabel.cpp b/src/datavisualization/data/qcustom3dlabel.cpp new file mode 100644 index 00000000..85a37e2d --- /dev/null +++ b/src/datavisualization/data/qcustom3dlabel.cpp @@ -0,0 +1,358 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "qcustom3dlabel_p.h" +#include "utils_p.h" + +QT_BEGIN_NAMESPACE_DATAVISUALIZATION + +/*! + * \class QCustom3DLabel + * \inmodule QtDataVisualization + * \brief The QCustom3DLabel class is for creating custom labels to be added to a graph. + * \since QtDataVisualization 1.1 + * + * This class is for creating custom labels to be added to a graph. You can set text, font, + * position, scaling, rotation, and colors. You can also toggle borders and background for the + * label. Colors, borders and background are used from active theme unless any of them is set + * explicitly. + * + * \note In scaling, z has no effect. Setting the same x and y retains the original + * font dimensions. + * + * \sa QAbstract3DGraph::addCustomItem() + */ + +/*! + * \qmltype Custom3DLabel + * \inqmlmodule QtDataVisualization + * \since QtDataVisualization 1.1 + * \ingroup datavisualization_qml + * \instantiates QCustom3DLabel + * \brief The Custom3DLabel type is for creating custom labels to be added to a graph. + * + * This type is for creating custom labels to be added to a graph. You can set text, font, + * position, scaling, rotation, and colors. You can also toggle borders and background for the + * label. Colors, borders and background are used from active theme unless any of them is set + * explicitly. + * + * \note In scaling, z has no effect. Setting the same x and y retains the original + * font dimensions. + */ + +/*! \qmlproperty string Custom3DLabel::text + * + * The text for the label. Rich text is not supported. + */ + +/*! \qmlproperty font Custom3DLabel::font + * + * The font to be used for the label. Defaults to \c{Font {family: "Arial"; pointSize: 20}}. + * Special formatting (for example outlined) is not supported. + */ + +/*! \qmlproperty color Custom3DLabel::textColor + * + * Color for the label text. Also affects label border, if enabled. Defaults to \c{"white"}. + * + * \sa borderEnabled + */ + +/*! \qmlproperty color Custom3DLabel::backgroundColor + * + * Color for the label background, if enabled. Defaults to \c{"gray"}. + * + * \sa backgroundEnabled + */ + +/*! \qmlproperty bool Custom3DLabel::backgroundEnabled + * + * Enable label background. If set to \c{false}, backgroundColor has no effect. Defaults + * to \c{true}. + */ + +/*! \qmlproperty bool Custom3DLabel::borderEnabled + * + * Enable label borders. Defaults to \c{true}. + */ + +/*! \qmlproperty bool Custom3DLabel::facingCamera + * + * Forces the label to face camera always. Defaults to \c{false}. If set to \c{true}, rotation() + * has no effect. + */ + +/*! + * Constructs QCustom3DLabel with given \a parent. + */ +QCustom3DLabel::QCustom3DLabel(QObject *parent) : + QCustom3DItem(new QCustom3DLabelPrivate(this), parent) +{ +} + +/*! + * Constructs QCustom3DLabel with given \a text, \a font, \a position, \a scaling, + * \a rotation, and optional \a parent. + * + * \note Setting the same x and y for \a scaling retains the original font dimensions. + */ +QCustom3DLabel::QCustom3DLabel(const QString &text, const QFont &font, + const QVector3D &position, const QVector3D &scaling, + const QQuaternion &rotation, QObject *parent) : + QCustom3DItem(new QCustom3DLabelPrivate(this, text, font, position, scaling, rotation), + parent) +{ +} + +/*! + * Destroys QCustom3DLabel. + */ +QCustom3DLabel::~QCustom3DLabel() +{ +} + +/*! \property QCustom3DLabel::text + * + * The text for the label. Rich text is not supported. + */ +void QCustom3DLabel::setText(const QString &text) +{ + if (dptr()->m_text != text) { + dptr()->m_text = text; + dptr()->handleTextureChange(); + emit textChanged(text); + emit dptr()->needUpdate(); + } +} + +QString QCustom3DLabel::text() const +{ + return dptrc()->m_text; +} + +/*! \property QCustom3DLabel::font + * + * The font to be used for the label. Defaults to \c{QFont("Arial", 20)}. Special formatting + * (for example outlined) is not supported. + */ +void QCustom3DLabel::setFont(const QFont &font) +{ + if (dptr()->m_font != font) { + dptr()->m_font = font; + dptr()->handleTextureChange(); + emit fontChanged(font); + emit dptr()->needUpdate(); + } +} + +QFont QCustom3DLabel::font() const +{ + return dptrc()->m_font; +} + +/*! \property QCustom3DLabel::textColor + * + * Color for the label text. Also affects label border, if enabled. Defaults to \c{Qt::white}. + * + * \sa borderEnabled + */ +void QCustom3DLabel::setTextColor(const QColor &color) +{ + if (dptr()->m_txtColor != color) { + dptr()->m_txtColor = color; + dptr()->m_customVisuals = true; + dptr()->handleTextureChange(); + emit textColorChanged(color); + emit dptr()->needUpdate(); + } +} + +QColor QCustom3DLabel::textColor() const +{ + return dptrc()->m_txtColor; +} + +/*! \property QCustom3DLabel::backgroundColor + * + * Color for the label background, if enabled. Defaults to \c{Qt::gray}. + * + * \sa backgroundEnabled + */ +void QCustom3DLabel::setBackgroundColor(const QColor &color) +{ + if (dptr()->m_bgrColor != color) { + dptr()->m_bgrColor = color; + dptr()->m_customVisuals = true; + dptr()->handleTextureChange(); + emit backgroundColorChanged(color); + emit dptr()->needUpdate(); + } +} + +QColor QCustom3DLabel::backgroundColor() const +{ + return dptrc()->m_bgrColor; +} + +/*! \property QCustom3DLabel::borderEnabled + * + * Enable label borders. Defaults to \c{true}. + */ +void QCustom3DLabel::setBorderEnabled(bool enabled) +{ + if (dptr()->m_borders != enabled) { + dptr()->m_borders = enabled; + dptr()->m_customVisuals = true; + dptr()->handleTextureChange(); + emit borderEnabledChanged(enabled); + emit dptr()->needUpdate(); + } +} + +bool QCustom3DLabel::isBorderEnabled() const +{ + return dptrc()->m_borders; +} + +/*! \property QCustom3DLabel::backgroundEnabled + * + * Enable label background. If set to \c{false}, backgroundColor() has no effect. Defaults + * to \c{true}. + */ +void QCustom3DLabel::setBackgroundEnabled(bool enabled) +{ + if (dptr()->m_background != enabled) { + dptr()->m_background = enabled; + dptr()->m_customVisuals = true; + dptr()->handleTextureChange(); + emit backgroundEnabledChanged(enabled); + emit dptr()->needUpdate(); + } +} + +bool QCustom3DLabel::isBackgroundEnabled() const +{ + return dptrc()->m_background; +} + +/*! \property QCustom3DLabel::facingCamera + * + * Forces the label to face camera always. Defaults to \c{false}. If set to \c{true}, rotation() + * has no effect. + */ +void QCustom3DLabel::setFacingCamera(bool enabled) +{ + if (dptr()->m_facingCamera != enabled) { + dptr()->m_facingCamera = enabled; + dptr()->m_facingCameraDirty = true; + emit facingCameraChanged(enabled); + emit dptr()->needUpdate(); + } +} + +bool QCustom3DLabel::isFacingCamera() const +{ + return dptrc()->m_facingCamera; +} + +/*! + * \internal + */ +QCustom3DLabelPrivate *QCustom3DLabel::dptr() +{ + return static_cast<QCustom3DLabelPrivate *>(d_ptr.data()); +} + +/*! + * \internal + */ +const QCustom3DLabelPrivate *QCustom3DLabel::dptrc() const +{ + return static_cast<const QCustom3DLabelPrivate *>(d_ptr.data()); +} + +QCustom3DLabelPrivate::QCustom3DLabelPrivate(QCustom3DLabel *q) : + QCustom3DItemPrivate(q), + m_font(QFont(QStringLiteral("Arial"), 20)), + m_bgrColor(Qt::gray), + m_txtColor(Qt::white), + m_background(true), + m_borders(true), + m_facingCamera(false), + m_customVisuals(false), + m_facingCameraDirty(false) +{ + m_isLabelItem = true; + m_shadowCasting = false; + m_meshFile = QStringLiteral(":/defaultMeshes/plane"); + createTextureImage(); +} + +QCustom3DLabelPrivate::QCustom3DLabelPrivate(QCustom3DLabel *q, const QString &text, + const QFont &font, const QVector3D &position, + const QVector3D &scaling, + const QQuaternion &rotation) : + QCustom3DItemPrivate(q, QStringLiteral(":/defaultMeshes/plane"), position, scaling, rotation), + m_text(text), + m_font(font), + m_bgrColor(Qt::gray), + m_txtColor(Qt::white), + m_background(true), + m_borders(true), + m_facingCamera(false), + m_customVisuals(false), + m_facingCameraDirty(false) +{ + m_isLabelItem = true; + m_shadowCasting = false; + createTextureImage(); +} + +QCustom3DLabelPrivate::~QCustom3DLabelPrivate() +{ +} + +void QCustom3DLabelPrivate::resetDirtyBits() +{ + QCustom3DItemPrivate::resetDirtyBits(); + m_facingCameraDirty = false; +} + +void QCustom3DLabelPrivate::createTextureImage() +{ + createTextureImage(m_bgrColor, m_txtColor, m_background, m_borders); +} + +void QCustom3DLabelPrivate::createTextureImage(const QColor &bgrColor, const QColor &txtColor, + bool background, bool borders) +{ + m_textureImage = Utils::printTextToImage(m_font, m_text, bgrColor, txtColor, background, + borders, 0); +} + +void QCustom3DLabelPrivate::handleTextureChange() +{ + createTextureImage(); + m_dirtyBits.textureDirty = true; + if (!m_textureFile.isEmpty()) { + m_textureFile.clear(); + emit q_ptr->textureFileChanged(m_textureFile); + } +} + +QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qcustom3dlabel.h b/src/datavisualization/data/qcustom3dlabel.h new file mode 100644 index 00000000..f42ee378 --- /dev/null +++ b/src/datavisualization/data/qcustom3dlabel.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef QCUSTOMLABELITEM_H +#define QCUSTOMLABELITEM_H + +#include <QtDataVisualization/qdatavisualizationglobal.h> +#include <QtDataVisualization/QCustom3DItem> +#include <QtGui/QVector3D> +#include <QtGui/QQuaternion> +#include <QtGui/QFont> +#include <QtGui/QColor> + +QT_BEGIN_NAMESPACE_DATAVISUALIZATION + +class QCustom3DLabelPrivate; + +class QT_DATAVISUALIZATION_EXPORT QCustom3DLabel : public QCustom3DItem +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) + Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor NOTIFY textColorChanged) + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged) + Q_PROPERTY(bool borderEnabled READ isBorderEnabled WRITE setBorderEnabled NOTIFY borderEnabledChanged) + Q_PROPERTY(bool backgroundEnabled READ isBackgroundEnabled WRITE setBackgroundEnabled NOTIFY backgroundEnabledChanged) + Q_PROPERTY(bool facingCamera READ isFacingCamera WRITE setFacingCamera NOTIFY facingCameraChanged) + +public: + explicit QCustom3DLabel(QObject *parent = 0); + explicit QCustom3DLabel(const QString &text, const QFont &font, const QVector3D &position, + const QVector3D &scaling, const QQuaternion &rotation, + QObject *parent = 0); + virtual ~QCustom3DLabel(); + + void setText(const QString &text); + QString text() const; + + void setFont(const QFont &font); + QFont font() const; + + void setTextColor(const QColor &color); + QColor textColor() const; + + void setBackgroundColor(const QColor &color); + QColor backgroundColor() const; + + void setBorderEnabled(bool enabled); + bool isBorderEnabled() const; + + void setBackgroundEnabled(bool enabled); + bool isBackgroundEnabled() const; + + void setFacingCamera(bool enabled); + bool isFacingCamera() const; + +signals: + void textChanged(const QString &text); + void fontChanged(const QFont &font); + void textColorChanged(const QColor &color); + void backgroundColorChanged(const QColor &color); + void borderEnabledChanged(bool enabled); + void backgroundEnabledChanged(bool enabled); + void facingCameraChanged(bool enabled); + +protected: + QCustom3DLabelPrivate *dptr(); + const QCustom3DLabelPrivate *dptrc() const; + +private: + Q_DISABLE_COPY(QCustom3DLabel) + + friend class Abstract3DRenderer; +}; + +QT_END_NAMESPACE_DATAVISUALIZATION + +#endif diff --git a/src/datavisualization/data/qcustom3dlabel_p.h b/src/datavisualization/data/qcustom3dlabel_p.h new file mode 100644 index 00000000..0bb0e017 --- /dev/null +++ b/src/datavisualization/data/qcustom3dlabel_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QCUSTOMLABELITEM_P_H +#define QCUSTOMLABELITEM_P_H + +#include "qcustom3dlabel.h" +#include "qcustom3ditem_p.h" + +QT_BEGIN_NAMESPACE_DATAVISUALIZATION + +class QCustom3DLabelPrivate : public QCustom3DItemPrivate +{ + Q_OBJECT + +public: + QCustom3DLabelPrivate(QCustom3DLabel *q); + QCustom3DLabelPrivate(QCustom3DLabel *q, const QString &text, const QFont &font, + const QVector3D &position, const QVector3D &scaling, + const QQuaternion &rotation); + virtual ~QCustom3DLabelPrivate(); + + void resetDirtyBits(); + void createTextureImage(); + void createTextureImage(const QColor &bgrColor, const QColor &txtColor, bool background, + bool borders); + void handleTextureChange(); + +public: + QString m_text; + QFont m_font; + QColor m_bgrColor; + QColor m_txtColor; + bool m_background; + bool m_borders; + bool m_facingCamera; + + bool m_customVisuals; + + bool m_facingCameraDirty; + +private: + friend class QCustom3DLabel; +}; + +QT_END_NAMESPACE_DATAVISUALIZATION + +#endif diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp index 56fcf5d1..d64046be 100644 --- a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp +++ b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp @@ -28,7 +28,7 @@ const float defaultMaxValue = 10.0f; * \class QHeightMapSurfaceDataProxy * \inmodule QtDataVisualization * \brief Base proxy class for Q3DSurface. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * QHeightMapSurfaceDataProxy takes care of surface related height map data handling. It provides a * way to give a height map to be visualized as a surface plot. diff --git a/src/datavisualization/data/qitemmodelbardataproxy.cpp b/src/datavisualization/data/qitemmodelbardataproxy.cpp index 2281e33f..3d4a980a 100644 --- a/src/datavisualization/data/qitemmodelbardataproxy.cpp +++ b/src/datavisualization/data/qitemmodelbardataproxy.cpp @@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QItemModelBarDataProxy * \inmodule QtDataVisualization * \brief Proxy class for presenting data in item models with Q3DBars. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * QItemModelBarDataProxy allows you to use QAbstractItemModel derived models as a data source * for Q3DBars. It uses the defined mappings to map data from the model to rows, columns, and @@ -33,6 +33,9 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * * The data is resolved asynchronously whenever mappings or the model changes. * QBarDataProxy::arrayReset() is emitted when the data has been resolved. + * However, when useModelCategories property is set to true, single item changes are resolved + * synchronously, unless the same frame also contains a change that causes the whole model to be + * resolved. * * There are three ways to use mappings: * @@ -50,12 +53,22 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * 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 for storing various monthly values - * related to a business. - * Each item in the model has the roles "year", "month", "income", and "expenses". - * You could do the following to display the data in a bar graph: + * For example, assume that you have a custom QAbstractItemModel for storing various monthly values + * related to a business. + * Each item in the model has the roles "year", "month", "income", and "expenses". + * You could do the following to display the data in a bar graph: + * + * \snippet doc_src_qtdatavisualization.cpp 3 + * + * 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 QRegExp &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. * - * \snippet doc_src_qtdatavisualization.cpp 3 + * For example about using the search patterns in conjunction with the roles, see + * \l{Qt Quick 2 Bars Example}. * * \sa {Qt Data Visualization Data Handling} */ @@ -74,6 +87,8 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * Data is resolved asynchronously whenever the mapping or the model changes. * QBarDataProxy::arrayReset() is emitted when the data has been resolved. * + * For ItemModelBarDataProxy enums, see \l{QItemModelBarDataProxy::MultiMatchBehavior}. + * * For more details, see QItemModelBarDataProxy documentation. * * Usage example: @@ -90,35 +105,36 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION /*! * \qmlproperty string ItemModelBarDataProxy::rowRole - * The row role of the mapping. + * Defines the item model role to map into row category. */ /*! * \qmlproperty string ItemModelBarDataProxy::columnRole - * The column role of the mapping. + * Defines the item model role to map into column category. */ /*! * \qmlproperty string ItemModelBarDataProxy::valueRole - * The value role of the mapping. + * Defines the item model role to map into bar value. */ /*! * \qmlproperty string ItemModelBarDataProxy::rotationRole - * - * Defines the rotation role for the mapping. + * Defines the item model role to map into bar rotation angle. */ /*! * \qmlproperty list<String> ItemModelBarDataProxy::rowCategories - * The row categories of the mapping. Only items with row roles that are found in this list are - * included when the data is resolved. The rows are ordered in the same order as they are in this list. + * The row categories of the mapping. Only items with row role values that are found in this list + * are included when the data is resolved. The rows are ordered in the same order as they are in + * this list. */ /*! * \qmlproperty list<String> ItemModelBarDataProxy::columnCategories - * The column categories of the mapping. Only items with column roles that are found in this list are - * included when the data is resolved. The columns are ordered in the same order as they are in this list. + * The column categories of the mapping. Only items with column role values that are found in this + * list are included when the data is resolved. The columns are ordered in the same order as they + * are in this list. */ /*! @@ -143,6 +159,117 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION */ /*! + * \qmlproperty regExp ItemModelBarDataProxy::rowRolePattern + * When set, a search and replace is done on the value mapped by 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 rowRoleReplace property contains the replacement string. + * This is useful for example in parsing row and column categories from a single + * timestamp field in the item model. + * + * \sa rowRole, rowRoleReplace + */ + +/*! + * \qmlproperty regExp ItemModelBarDataProxy::columnRolePattern + * When set, a search and replace is done on the value mapped by 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 columnRoleReplace property contains the replacement string. + * This is useful for example in parsing row and column categories from + * a single timestamp field in the item model. + * + * \sa columnRole, columnRoleReplace + */ + +/*! + * \qmlproperty regExp ItemModelBarDataProxy::valueRolePattern + * When set, a search and replace is done on the value mapped by value role before it is used as + * a bar value. This property specifies the regular expression to find the portion of the + * mapped value to replace and valueRoleReplace property contains the replacement string. + * + * \sa valueRole, valueRoleReplace + */ + +/*! + * \qmlproperty regExp ItemModelBarDataProxy::rotationRolePattern + * When set, a search and replace is done on the value mapped by rotation role before it is used + * as a bar rotation angle. This property specifies the regular expression to find the portion + * of the mapped value to replace and rotationRoleReplace property contains the replacement string. + * + * \sa rotationRole, rotationRoleReplace + */ + +/*! + * \qmlproperty string ItemModelBarDataProxy::rowRoleReplace + * This property defines the replace content to be used in conjunction with rowRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa rowRole, rowRolePattern + */ + +/*! + * \qmlproperty string ItemModelBarDataProxy::columnRoleReplace + * This property defines the replace content to be used in conjunction with columnRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa columnRole, columnRolePattern + */ + +/*! + * \qmlproperty string ItemModelBarDataProxy::valueRoleReplace + * This property defines the replace content to be used in conjunction with valueRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa valueRole, valueRolePattern + */ + +/*! + * \qmlproperty string ItemModelBarDataProxy::rotationRoleReplace + * This property defines the replace content to be used in conjunction with rotationRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa rotationRole, rotationRolePattern + */ + +/*! + * \qmlproperty ItemModelBarDataProxy.MultiMatchBehavior ItemModelBarDataProxy::multiMatchBehavior + * This property defines how multiple matches for each row/column combination are handled. + * Defaults to ItemModelBarDataProxy.MMBLast. The chosen behavior affects both bar value + * and rotation. + * + * For example, you might have an item model with timestamped data taken at irregular intervals + * and you want to visualize total value of data items on each day with a bar graph. + * This can be done by specifying row and column categories so that each bar represents a day, + * and setting multiMatchBehavior to ItemModelBarDataProxy.MMBCumulative. + */ + +/*! + * \enum QItemModelBarDataProxy::MultiMatchBehavior + * + * Behavior types for QItemModelBarDataProxy::multiMatchBehavior property. + * + * \value MMBFirst + * The value is taken from the first item in the item model that matches + * each row/column combination. + * \value MMBLast + * The value is taken from the last item in the item model that matches + * each row/column combination. + * \value MMBAverage + * The values from all items matching each row/column combination are + * averaged together and the average is used as the bar value. + * \value MMBCumulative + * The values from all items matching each row/column combination are + * added together and the total is used as the bar value. + */ + +/*! * Constructs QItemModelBarDataProxy with optional \a parent. */ QItemModelBarDataProxy::QItemModelBarDataProxy(QObject *parent) @@ -155,7 +282,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(QObject *parent) * Constructs QItemModelBarDataProxy 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. */ -QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel, QObject *parent) +QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel, QObject *parent) : QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent) { setItemModel(itemModel); @@ -169,7 +296,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod * 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. */ -QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel, +QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &valueRole, QObject *parent) : QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent) { @@ -184,7 +311,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod * 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. */ -QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel, +QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &valueRole, QObject *parent) @@ -202,7 +329,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod * 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 valueRole, and \a rotationRole. */ -QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel, +QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &valueRole, @@ -225,7 +352,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod * Row and column categories are set with \a rowCategories and \a columnCategories. * This constructor also sets autoRowCategories and autoColumnCategories to false. */ -QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel, +QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &valueRole, @@ -252,7 +379,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod * Row and column categories are set with \a rowCategories and \a columnCategories. * This constructor also sets autoRowCategories and autoColumnCategories to false. */ -QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel, +QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &valueRole, @@ -287,12 +414,12 @@ QItemModelBarDataProxy::~QItemModelBarDataProxy() * Defines item model. Does not take ownership of the model, but does connect to it to listen for * changes. */ -void QItemModelBarDataProxy::setItemModel(const QAbstractItemModel *itemModel) +void QItemModelBarDataProxy::setItemModel(QAbstractItemModel *itemModel) { dptr()->m_itemModelHandler->setItemModel(itemModel); } -const QAbstractItemModel *QItemModelBarDataProxy::itemModel() const +QAbstractItemModel *QItemModelBarDataProxy::itemModel() const { return dptrc()->m_itemModelHandler->itemModel(); } @@ -506,6 +633,215 @@ int QItemModelBarDataProxy::columnCategoryIndex(const QString &category) } /*! + * \property QItemModelBarDataProxy::rowRolePattern + * + * When set, a search and replace is done on the value mapped by 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 rowRoleReplace property contains the replacement string. + * This is useful for example in parsing row and column categories from a single + * timestamp field in the item model. + * + * \sa rowRole, rowRoleReplace + */ +void QItemModelBarDataProxy::setRowRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_rowRolePattern != pattern) { + dptr()->m_rowRolePattern = pattern; + emit rowRolePatternChanged(pattern); + } +} + +QRegExp QItemModelBarDataProxy::rowRolePattern() const +{ + return dptrc()->m_rowRolePattern; +} + +/*! + * \property QItemModelBarDataProxy::columnRolePattern + * + * When set, a search and replace is done on the value mapped by 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 columnRoleReplace property contains the replacement string. + * This is useful for example in parsing row and column categories from + * a single timestamp field in the item model. + * + * \sa columnRole, columnRoleReplace + */ +void QItemModelBarDataProxy::setColumnRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_columnRolePattern != pattern) { + dptr()->m_columnRolePattern = pattern; + emit columnRolePatternChanged(pattern); + } +} + +QRegExp QItemModelBarDataProxy::columnRolePattern() const +{ + return dptrc()->m_columnRolePattern; +} + +/*! + * \property QItemModelBarDataProxy::valueRolePattern + * + * When set, a search and replace is done on the value mapped by value role before it is used as + * a bar value. This property specifies the regular expression to find the portion of the + * mapped value to replace and valueRoleReplace property contains the replacement string. + * + * \sa valueRole, valueRoleReplace + */ +void QItemModelBarDataProxy::setValueRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_valueRolePattern != pattern) { + dptr()->m_valueRolePattern = pattern; + emit valueRolePatternChanged(pattern); + } +} + +QRegExp QItemModelBarDataProxy::valueRolePattern() const +{ + return dptrc()->m_valueRolePattern; +} + +/*! + * \property QItemModelBarDataProxy::rotationRolePattern + * + * When set, a search and replace is done on the value mapped by rotation role before it is used + * as a bar rotation angle. This property specifies the regular expression to find the portion + * of the mapped value to replace and rotationRoleReplace property contains the replacement string. + * + * \sa rotationRole, rotationRoleReplace + */ +void QItemModelBarDataProxy::setRotationRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_rotationRolePattern != pattern) { + dptr()->m_rotationRolePattern = pattern; + emit rotationRolePatternChanged(pattern); + } +} + +QRegExp QItemModelBarDataProxy::rotationRolePattern() const +{ + return dptrc()->m_rotationRolePattern; +} + +/*! + * \property QItemModelBarDataProxy::rowRoleReplace + * + * This property defines the replace content to be used in conjunction with rowRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa rowRole, rowRolePattern + */ +void QItemModelBarDataProxy::setRowRoleReplace(const QString &replace) +{ + if (dptr()->m_rowRoleReplace != replace) { + dptr()->m_rowRoleReplace = replace; + emit rowRoleReplaceChanged(replace); + } +} + +QString QItemModelBarDataProxy::rowRoleReplace() const +{ + return dptrc()->m_rowRoleReplace; +} + +/*! + * \property QItemModelBarDataProxy::columnRoleReplace + * + * This property defines the replace content to be used in conjunction with columnRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa columnRole, columnRolePattern + */ +void QItemModelBarDataProxy::setColumnRoleReplace(const QString &replace) +{ + if (dptr()->m_columnRoleReplace != replace) { + dptr()->m_columnRoleReplace = replace; + emit columnRoleReplaceChanged(replace); + } +} + +QString QItemModelBarDataProxy::columnRoleReplace() const +{ + return dptrc()->m_columnRoleReplace; +} + +/*! + * \property QItemModelBarDataProxy::valueRoleReplace + * + * This property defines the replace content to be used in conjunction with valueRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa valueRole, valueRolePattern + */ +void QItemModelBarDataProxy::setValueRoleReplace(const QString &replace) +{ + if (dptr()->m_valueRoleReplace != replace) { + dptr()->m_valueRoleReplace = replace; + emit valueRoleReplaceChanged(replace); + } +} + +QString QItemModelBarDataProxy::valueRoleReplace() const +{ + return dptrc()->m_valueRoleReplace; +} + +/*! + * \property QItemModelBarDataProxy::rotationRoleReplace + * + * This property defines the replace content to be used in conjunction with rotationRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa rotationRole, rotationRolePattern + */ +void QItemModelBarDataProxy::setRotationRoleReplace(const QString &replace) +{ + if (dptr()->m_rotationRoleReplace != replace) { + dptr()->m_rotationRoleReplace = replace; + emit rotationRoleReplaceChanged(replace); + } +} + +QString QItemModelBarDataProxy::rotationRoleReplace() const +{ + return dptrc()->m_rotationRoleReplace; +} + +/*! + * \property QItemModelBarDataProxy::multiMatchBehavior + * + * This property defines how multiple matches for each row/column combination are handled. + * Defaults to QItemModelBarDataProxy::MMBLast. The chosen behavior affects both bar value + * and rotation. + * + * For example, you might have an item model with timestamped data taken at irregular intervals + * and you want to visualize total value of data items on each day with a bar graph. + * This can be done by specifying row and column categories so that each bar represents a day, + * and setting multiMatchBehavior to QItemModelBarDataProxy::MMBCumulative. + */ +void QItemModelBarDataProxy::setMultiMatchBehavior(QItemModelBarDataProxy::MultiMatchBehavior behavior) +{ + if (dptr()->m_multiMatchBehavior != behavior) { + dptr()->m_multiMatchBehavior = behavior; + emit multiMatchBehaviorChanged(behavior); + } +} + +QItemModelBarDataProxy::MultiMatchBehavior QItemModelBarDataProxy::multiMatchBehavior() const +{ + return dptrc()->m_multiMatchBehavior; +} + +/*! * \internal */ QItemModelBarDataProxyPrivate *QItemModelBarDataProxy::dptr() @@ -528,7 +864,8 @@ QItemModelBarDataProxyPrivate::QItemModelBarDataProxyPrivate(QItemModelBarDataPr m_itemModelHandler(new BarItemModelHandler(q)), m_useModelCategories(false), m_autoRowCategories(true), - m_autoColumnCategories(true) + m_autoColumnCategories(true), + m_multiMatchBehavior(QItemModelBarDataProxy::MMBLast) { } @@ -564,6 +901,24 @@ void QItemModelBarDataProxyPrivate::connectItemModelHandler() m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(qptr(), &QItemModelBarDataProxy::autoColumnCategoriesChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelBarDataProxy::rowRolePatternChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelBarDataProxy::columnRolePatternChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelBarDataProxy::valueRolePatternChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelBarDataProxy::rotationRolePatternChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelBarDataProxy::rowRoleReplaceChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelBarDataProxy::columnRoleReplaceChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelBarDataProxy::valueRoleReplaceChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelBarDataProxy::rotationRoleReplaceChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelBarDataProxy::multiMatchBehaviorChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); } QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qitemmodelbardataproxy.h b/src/datavisualization/data/qitemmodelbardataproxy.h index f19b4445..d7394dcf 100644 --- a/src/datavisualization/data/qitemmodelbardataproxy.h +++ b/src/datavisualization/data/qitemmodelbardataproxy.h @@ -21,6 +21,7 @@ #include <QtDataVisualization/qbardataproxy.h> #include <QtCore/QAbstractItemModel> +#include <QtCore/QRegExp> QT_BEGIN_NAMESPACE_DATAVISUALIZATION @@ -29,7 +30,8 @@ class QItemModelBarDataProxyPrivate; class QT_DATAVISUALIZATION_EXPORT QItemModelBarDataProxy : public QBarDataProxy { Q_OBJECT - Q_PROPERTY(const QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged) + Q_ENUMS(MultiMatchBehavior) + Q_PROPERTY(QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged) Q_PROPERTY(QString rowRole READ rowRole WRITE setRowRole NOTIFY rowRoleChanged) Q_PROPERTY(QString columnRole READ columnRole WRITE setColumnRole NOTIFY columnRoleChanged) Q_PROPERTY(QString valueRole READ valueRole WRITE setValueRole NOTIFY valueRoleChanged) @@ -39,30 +41,46 @@ class QT_DATAVISUALIZATION_EXPORT QItemModelBarDataProxy : public QBarDataProxy Q_PROPERTY(bool useModelCategories READ useModelCategories WRITE setUseModelCategories NOTIFY useModelCategoriesChanged) Q_PROPERTY(bool autoRowCategories READ autoRowCategories WRITE setAutoRowCategories NOTIFY autoRowCategoriesChanged) Q_PROPERTY(bool autoColumnCategories READ autoColumnCategories WRITE setAutoColumnCategories NOTIFY autoColumnCategoriesChanged) + Q_PROPERTY(QRegExp rowRolePattern READ rowRolePattern WRITE setRowRolePattern NOTIFY rowRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp columnRolePattern READ columnRolePattern WRITE setColumnRolePattern NOTIFY columnRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp valueRolePattern READ valueRolePattern WRITE setValueRolePattern NOTIFY valueRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp rotationRolePattern READ rotationRolePattern WRITE setRotationRolePattern NOTIFY rotationRolePatternChanged REVISION 1) + Q_PROPERTY(QString rowRoleReplace READ rowRoleReplace WRITE setRowRoleReplace NOTIFY rowRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString columnRoleReplace READ columnRoleReplace WRITE setColumnRoleReplace NOTIFY columnRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString valueRoleReplace READ valueRoleReplace WRITE setValueRoleReplace NOTIFY valueRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString rotationRoleReplace READ rotationRoleReplace WRITE setRotationRoleReplace NOTIFY rotationRoleReplaceChanged REVISION 1) + Q_PROPERTY(MultiMatchBehavior multiMatchBehavior READ multiMatchBehavior WRITE setMultiMatchBehavior NOTIFY multiMatchBehaviorChanged REVISION 1) public: + enum MultiMatchBehavior { + MMBFirst = 0, + MMBLast = 1, + MMBAverage = 2, + MMBCumulative = 3 + }; + explicit QItemModelBarDataProxy(QObject *parent = 0); - QItemModelBarDataProxy(const QAbstractItemModel *itemModel, QObject *parent = 0); - QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &valueRole, + QItemModelBarDataProxy(QAbstractItemModel *itemModel, QObject *parent = 0); + QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &valueRole, QObject *parent = 0); - QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole, + QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &valueRole, QObject *parent = 0); - QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole, + QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &valueRole, const QString &rotationRole, QObject *parent = 0); - QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole, + QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &valueRole, const QStringList &rowCategories, const QStringList &columnCategories, QObject *parent = 0); - QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole, + QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &valueRole, const QString &rotationRole, const QStringList &rowCategories, const QStringList &columnCategories, QObject *parent = 0); virtual ~QItemModelBarDataProxy(); - void setItemModel(const QAbstractItemModel *itemModel); - const QAbstractItemModel *itemModel() const; + void setItemModel(QAbstractItemModel *itemModel); + QAbstractItemModel *itemModel() const; void setRowRole(const QString &role); QString rowRole() const; @@ -93,6 +111,27 @@ public: Q_INVOKABLE int rowCategoryIndex(const QString& category); Q_INVOKABLE int columnCategoryIndex(const QString& category); + void setRowRolePattern(const QRegExp &pattern); + QRegExp rowRolePattern() const; + void setColumnRolePattern(const QRegExp &pattern); + QRegExp columnRolePattern() const; + void setValueRolePattern(const QRegExp &pattern); + QRegExp valueRolePattern() const; + void setRotationRolePattern(const QRegExp &pattern); + QRegExp rotationRolePattern() const; + + void setRowRoleReplace(const QString &replace); + QString rowRoleReplace() const; + void setColumnRoleReplace(const QString &replace); + QString columnRoleReplace() const; + void setValueRoleReplace(const QString &replace); + QString valueRoleReplace() const; + void setRotationRoleReplace(const QString &replace); + QString rotationRoleReplace() const; + + void setMultiMatchBehavior(MultiMatchBehavior behavior); + MultiMatchBehavior multiMatchBehavior() const; + signals: void itemModelChanged(const QAbstractItemModel* itemModel); void rowRoleChanged(const QString &role); @@ -104,6 +143,15 @@ signals: void useModelCategoriesChanged(bool enable); void autoRowCategoriesChanged(bool enable); void autoColumnCategoriesChanged(bool enable); + Q_REVISION(1) void rowRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void columnRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void valueRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void rotationRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void rowRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void columnRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void valueRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void rotationRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void multiMatchBehaviorChanged(MultiMatchBehavior behavior); protected: QItemModelBarDataProxyPrivate *dptr(); diff --git a/src/datavisualization/data/qitemmodelbardataproxy_p.h b/src/datavisualization/data/qitemmodelbardataproxy_p.h index 2fd74bb2..84564d02 100644 --- a/src/datavisualization/data/qitemmodelbardataproxy_p.h +++ b/src/datavisualization/data/qitemmodelbardataproxy_p.h @@ -63,6 +63,18 @@ private: bool m_autoRowCategories; bool m_autoColumnCategories; + QRegExp m_rowRolePattern; + QRegExp m_columnRolePattern; + QRegExp m_valueRolePattern; + QRegExp m_rotationRolePattern; + + QString m_rowRoleReplace; + QString m_columnRoleReplace; + QString m_valueRoleReplace; + QString m_rotationRoleReplace; + + QItemModelBarDataProxy::MultiMatchBehavior m_multiMatchBehavior; + friend class BarItemModelHandler; friend class QItemModelBarDataProxy; }; diff --git a/src/datavisualization/data/qitemmodelscatterdataproxy.cpp b/src/datavisualization/data/qitemmodelscatterdataproxy.cpp index 16a7b8b5..4e6464ea 100644 --- a/src/datavisualization/data/qitemmodelscatterdataproxy.cpp +++ b/src/datavisualization/data/qitemmodelscatterdataproxy.cpp @@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QItemModelScatterDataProxy * \inmodule QtDataVisualization * \brief Proxy class for presenting data in item models with Q3DScatter. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * QItemModelScatterDataProxy allows you to use QAbstractItemModel derived models as a data source * for Q3DScatter. It maps roles of QAbstractItemModel to the XYZ-values of Q3DScatter points. @@ -36,7 +36,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * unless the same frame also contains a change that causes the whole model to be resolved. * * Mapping ignores rows and columns of the QAbstractItemModel and treats - * all items equally. It requires the model to provide at least three roles for the data items + * all items equally. It requires the model to provide roles for the data items * that can be mapped to X, Y, and Z-values for the scatter points. * * For example, assume that you have a custom QAbstractItemModel for storing various measurements @@ -45,6 +45,16 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * * \snippet doc_src_qtdatavisualization.cpp 4 * + * 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 QRegExp &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{Qt Quick 2 Bars Example}. + * * \sa {Qt Data Visualization Data Handling} */ @@ -78,27 +88,109 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION /*! * \qmlproperty string ItemModelScatterDataProxy::xPosRole - * The X position role of the mapping. + * Defines the item model role to map into X position. */ /*! * \qmlproperty string ItemModelScatterDataProxy::yPosRole - * The Y position role of the mapping. + * Defines the item model role to map into Y position. */ /*! * \qmlproperty string ItemModelScatterDataProxy::zPosRole - * The Z position role of the mapping. + * Defines the item model role to map into Z position. */ /*! * \qmlproperty string ItemModelScatterDataProxy::rotationRole * - * Defines the rotation role for the mapping. + * Defines the item model role to map into item rotation. * The model may supply the value for rotation as either variant that is directly convertible - * to QQuaternion, or as one of the string representations: \c{"scalar,x,y,z"} or \c{"@angle,x,y,z"}. The first - * will construct the quaternion directly with given values, and the second one will construct - * the quaternion using QQuaternion::fromAxisAndAngle() method. + * to QQuaternion, or as one of the string representations: \c{"scalar,x,y,z"} or + * \c{"@angle,x,y,z"}. The first format will construct the quaternion directly with given values, + * and the second one will construct the quaternion using QQuaternion::fromAxisAndAngle() method. + */ + +/*! + * \qmlproperty regExp ItemModelScatterDataProxy::xPosRolePattern + * + * When set, a search and replace is done on the value mapped by xPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and xPosRoleReplace property contains the replacement string. + * + * \sa xPosRole, xPosRoleReplace + */ + +/*! + * \qmlproperty regExp ItemModelScatterDataProxy::yPosRolePattern + * + * When set, a search and replace is done on the value mapped by yPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and yPosRoleReplace property contains the replacement string. + * + * \sa yPosRole, yPosRoleReplace + */ + +/*! + * \qmlproperty regExp ItemModelScatterDataProxy::zPosRolePattern + * + * When set, a search and replace is done on the value mapped by zPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and zPosRoleReplace property contains the replacement string. + * + * \sa zPosRole, zPosRoleReplace + */ + +/*! + * \qmlproperty regExp ItemModelScatterDataProxy::rotationRolePattern + * When set, a search and replace is done on the value mapped by rotation role before it is used + * as a item rotation. This property specifies the regular expression to find the portion + * of the mapped value to replace and rotationRoleReplace property contains the replacement string. + * + * \sa rotationRole, rotationRoleReplace + */ + +/*! + * \qmlproperty string ItemModelScatterDataProxy::xPosRoleReplace + * + * This property defines the replace content to be used in conjunction with xPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa xPosRole, xPosRolePattern + */ + +/*! + * \qmlproperty string ItemModelScatterDataProxy::yPosRoleReplace + * + * This property defines the replace content to be used in conjunction with yPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa yPosRole, yPosRolePattern + */ + +/*! + * \qmlproperty string ItemModelScatterDataProxy::zPosRoleReplace + * + * This property defines the replace content to be used in conjunction with zPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa zPosRole, zPosRolePattern + */ + +/*! + * \qmlproperty string ItemModelScatterDataProxy::rotationRoleReplace + * This property defines the replace content to be used in conjunction with rotationRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa rotationRole, rotationRolePattern */ /*! @@ -114,7 +206,7 @@ QItemModelScatterDataProxy::QItemModelScatterDataProxy(QObject *parent) * Constructs QItemModelScatterDataProxy 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. */ -QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel *itemModel, +QItemModelScatterDataProxy::QItemModelScatterDataProxy(QAbstractItemModel *itemModel, QObject *parent) : QScatterDataProxy(new QItemModelScatterDataProxyPrivate(this), parent) { @@ -128,7 +220,7 @@ QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel * The xPosRole property is set to \a xPosRole, yPosRole property to \a yPosRole, and zPosRole property * to \a zPosRole. */ -QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel *itemModel, +QItemModelScatterDataProxy::QItemModelScatterDataProxy(QAbstractItemModel *itemModel, const QString &xPosRole, const QString &yPosRole, const QString &zPosRole, @@ -148,7 +240,7 @@ QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel * The xPosRole property is set to \a xPosRole, yPosRole property to \a yPosRole, zPosRole property * to \a zPosRole, and rotationRole property to \a rotationRole. */ -QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel *itemModel, +QItemModelScatterDataProxy::QItemModelScatterDataProxy(QAbstractItemModel *itemModel, const QString &xPosRole, const QString &yPosRole, const QString &zPosRole, @@ -177,12 +269,12 @@ QItemModelScatterDataProxy::~QItemModelScatterDataProxy() * Defines the item model. Does not take ownership of the model, but does connect to it to listen for * changes. */ -void QItemModelScatterDataProxy::setItemModel(const QAbstractItemModel *itemModel) +void QItemModelScatterDataProxy::setItemModel(QAbstractItemModel *itemModel) { dptr()->m_itemModelHandler->setItemModel(itemModel); } -const QAbstractItemModel *QItemModelScatterDataProxy::itemModel() const +QAbstractItemModel *QItemModelScatterDataProxy::itemModel() const { return dptrc()->m_itemModelHandler->itemModel(); } @@ -190,7 +282,7 @@ const QAbstractItemModel *QItemModelScatterDataProxy::itemModel() const /*! * \property QItemModelScatterDataProxy::xPosRole * - * Defines the X position \a role for the mapping. + * Defines the item model role to map into X position. */ void QItemModelScatterDataProxy::setXPosRole(const QString &role) { @@ -208,7 +300,7 @@ QString QItemModelScatterDataProxy::xPosRole() const /*! * \property QItemModelScatterDataProxy::yPosRole * - * Defines the Y position \a role for the mapping. + * Defines the item model role to map into Y position. */ void QItemModelScatterDataProxy::setYPosRole(const QString &role) { @@ -226,7 +318,7 @@ QString QItemModelScatterDataProxy::yPosRole() const /*! * \property QItemModelScatterDataProxy::zPosRole * - * Defines the Z position \a role for the mapping. + * Defines the item model role to map into Z position. */ void QItemModelScatterDataProxy::setZPosRole(const QString &role) { @@ -244,7 +336,7 @@ QString QItemModelScatterDataProxy::zPosRole() const /*! * \property QItemModelScatterDataProxy::rotationRole * - * Defines the rotation \a role for the mapping. + * Defines the item model role to map into item rotation. * * The model may supply the value for rotation as either variant that is directly convertible * to QQuaternion, or as one of the string representations: \c{"scalar,x,y,z"} or \c{"@angle,x,y,z"}. @@ -265,6 +357,186 @@ QString QItemModelScatterDataProxy::rotationRole() const } /*! + * \property QItemModelScatterDataProxy::xPosRolePattern + * + * When set, a search and replace is done on the value mapped by xPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and xPosRoleReplace property contains the replacement string. + * + * \sa xPosRole, xPosRoleReplace + */ +void QItemModelScatterDataProxy::setXPosRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_xPosRolePattern != pattern) { + dptr()->m_xPosRolePattern = pattern; + emit xPosRolePatternChanged(pattern); + } +} + +QRegExp QItemModelScatterDataProxy::xPosRolePattern() const +{ + return dptrc()->m_xPosRolePattern; +} + +/*! + * \property QItemModelScatterDataProxy::yPosRolePattern + * + * When set, a search and replace is done on the value mapped by yPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and yPosRoleReplace property contains the replacement string. + * + * \sa yPosRole, yPosRoleReplace + */ +void QItemModelScatterDataProxy::setYPosRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_yPosRolePattern != pattern) { + dptr()->m_yPosRolePattern = pattern; + emit yPosRolePatternChanged(pattern); + } +} + +QRegExp QItemModelScatterDataProxy::yPosRolePattern() const +{ + return dptrc()->m_yPosRolePattern; +} + +/*! + * \property QItemModelScatterDataProxy::zPosRolePattern + * + * When set, a search and replace is done on the value mapped by zPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and zPosRoleReplace property contains the replacement string. + * + * \sa zPosRole, zPosRoleReplace + */ +void QItemModelScatterDataProxy::setZPosRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_zPosRolePattern != pattern) { + dptr()->m_zPosRolePattern = pattern; + emit zPosRolePatternChanged(pattern); + } +} + +QRegExp QItemModelScatterDataProxy::zPosRolePattern() const +{ + return dptrc()->m_zPosRolePattern; +} + +/*! + * \property QItemModelScatterDataProxy::rotationRolePattern + * + * When set, a search and replace is done on the value mapped by rotation role before it is used + * as a item rotation. This property specifies the regular expression to find the portion + * of the mapped value to replace and rotationRoleReplace property contains the replacement string. + * + * \sa rotationRole, rotationRoleReplace + */ +void QItemModelScatterDataProxy::setRotationRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_rotationRolePattern != pattern) { + dptr()->m_rotationRolePattern = pattern; + emit rotationRolePatternChanged(pattern); + } +} + +QRegExp QItemModelScatterDataProxy::rotationRolePattern() const +{ + return dptrc()->m_rotationRolePattern; +} + +/*! + * \property QItemModelScatterDataProxy::xPosRoleReplace + * + * This property defines the replace content to be used in conjunction with xPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa xPosRole, xPosRolePattern + */ +void QItemModelScatterDataProxy::setXPosRoleReplace(const QString &replace) +{ + if (dptr()->m_xPosRoleReplace != replace) { + dptr()->m_xPosRoleReplace = replace; + emit xPosRoleReplaceChanged(replace); + } +} + +QString QItemModelScatterDataProxy::xPosRoleReplace() const +{ + return dptrc()->m_xPosRoleReplace; +} + +/*! + * \property QItemModelScatterDataProxy::yPosRoleReplace + * + * This property defines the replace content to be used in conjunction with yPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa yPosRole, yPosRolePattern + */ +void QItemModelScatterDataProxy::setYPosRoleReplace(const QString &replace) +{ + if (dptr()->m_yPosRoleReplace != replace) { + dptr()->m_yPosRoleReplace = replace; + emit yPosRoleReplaceChanged(replace); + } +} + +QString QItemModelScatterDataProxy::yPosRoleReplace() const +{ + return dptrc()->m_yPosRoleReplace; +} + +/*! + * \property QItemModelScatterDataProxy::zPosRoleReplace + * + * This property defines the replace content to be used in conjunction with zPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa zPosRole, zPosRolePattern + */ +void QItemModelScatterDataProxy::setZPosRoleReplace(const QString &replace) +{ + if (dptr()->m_zPosRoleReplace != replace) { + dptr()->m_zPosRoleReplace = replace; + emit zPosRoleReplaceChanged(replace); + } +} + +QString QItemModelScatterDataProxy::zPosRoleReplace() const +{ + return dptrc()->m_zPosRoleReplace; +} + +/*! + * \property QItemModelScatterDataProxy::rotationRoleReplace + * + * This property defines the replace content to be used in conjunction with rotationRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa rotationRole, rotationRolePattern + */ +void QItemModelScatterDataProxy::setRotationRoleReplace(const QString &replace) +{ + if (dptr()->m_rotationRoleReplace != replace) { + dptr()->m_rotationRoleReplace = replace; + emit rotationRoleReplaceChanged(replace); + } +} + +QString QItemModelScatterDataProxy::rotationRoleReplace() const +{ + return dptrc()->m_rotationRoleReplace; +} + +/*! * Changes \a xPosRole, \a yPosRole, \a zPosRole, and \a rotationRole mapping. */ void QItemModelScatterDataProxy::remap(const QString &xPosRole, const QString &yPosRole, @@ -320,6 +592,24 @@ void QItemModelScatterDataProxyPrivate::connectItemModelHandler() m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); QObject::connect(qptr(), &QItemModelScatterDataProxy::zPosRoleChanged, m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelScatterDataProxy::rotationRoleChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelScatterDataProxy::xPosRolePatternChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelScatterDataProxy::yPosRolePatternChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelScatterDataProxy::zPosRolePatternChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelScatterDataProxy::rotationRolePatternChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelScatterDataProxy::xPosRoleReplaceChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelScatterDataProxy::yPosRoleReplaceChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelScatterDataProxy::zPosRoleReplaceChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); + QObject::connect(qptr(), &QItemModelScatterDataProxy::rotationRoleReplaceChanged, + m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged); } QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qitemmodelscatterdataproxy.h b/src/datavisualization/data/qitemmodelscatterdataproxy.h index c6d2245d..3215c688 100644 --- a/src/datavisualization/data/qitemmodelscatterdataproxy.h +++ b/src/datavisualization/data/qitemmodelscatterdataproxy.h @@ -22,6 +22,7 @@ #include <QtDataVisualization/qscatterdataproxy.h> #include <QtCore/QAbstractItemModel> #include <QtCore/QString> +#include <QtCore/QRegExp> QT_BEGIN_NAMESPACE_DATAVISUALIZATION @@ -30,26 +31,34 @@ class QItemModelScatterDataProxyPrivate; class QT_DATAVISUALIZATION_EXPORT QItemModelScatterDataProxy : public QScatterDataProxy { Q_OBJECT - Q_PROPERTY(const QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged) + Q_PROPERTY(QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged) Q_PROPERTY(QString xPosRole READ xPosRole WRITE setXPosRole NOTIFY xPosRoleChanged) Q_PROPERTY(QString yPosRole READ yPosRole WRITE setYPosRole NOTIFY yPosRoleChanged) Q_PROPERTY(QString zPosRole READ zPosRole WRITE setZPosRole NOTIFY zPosRoleChanged) Q_PROPERTY(QString rotationRole READ rotationRole WRITE setRotationRole NOTIFY rotationRoleChanged) + Q_PROPERTY(QRegExp xPosRolePattern READ xPosRolePattern WRITE setXPosRolePattern NOTIFY xPosRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp yPosRolePattern READ yPosRolePattern WRITE setYPosRolePattern NOTIFY yPosRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp zPosRolePattern READ zPosRolePattern WRITE setZPosRolePattern NOTIFY zPosRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp rotationRolePattern READ rotationRolePattern WRITE setRotationRolePattern NOTIFY rotationRolePatternChanged REVISION 1) + Q_PROPERTY(QString xPosRoleReplace READ xPosRoleReplace WRITE setXPosRoleReplace NOTIFY xPosRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString yPosRoleReplace READ yPosRoleReplace WRITE setYPosRoleReplace NOTIFY yPosRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString zPosRoleReplace READ zPosRoleReplace WRITE setZPosRoleReplace NOTIFY zPosRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString rotationRoleReplace READ rotationRoleReplace WRITE setRotationRoleReplace NOTIFY rotationRoleReplaceChanged REVISION 1) public: explicit QItemModelScatterDataProxy(QObject *parent = 0); - QItemModelScatterDataProxy(const QAbstractItemModel *itemModel, QObject *parent = 0); - QItemModelScatterDataProxy(const QAbstractItemModel *itemModel, + QItemModelScatterDataProxy(QAbstractItemModel *itemModel, QObject *parent = 0); + QItemModelScatterDataProxy(QAbstractItemModel *itemModel, const QString &xPosRole, const QString &yPosRole, const QString &zPosRole, QObject *parent = 0); - QItemModelScatterDataProxy(const QAbstractItemModel *itemModel, + QItemModelScatterDataProxy(QAbstractItemModel *itemModel, const QString &xPosRole, const QString &yPosRole, const QString &zPosRole, const QString &rotationRole, QObject *parent = 0); virtual ~QItemModelScatterDataProxy(); - void setItemModel(const QAbstractItemModel *itemModel); - const QAbstractItemModel *itemModel() const; + void setItemModel(QAbstractItemModel *itemModel); + QAbstractItemModel *itemModel() const; void setXPosRole(const QString &role); QString xPosRole() const; @@ -63,12 +72,38 @@ public: void remap(const QString &xPosRole, const QString &yPosRole, const QString &zPosRole, const QString &rotationRole); + void setXPosRolePattern(const QRegExp &pattern); + QRegExp xPosRolePattern() const; + void setYPosRolePattern(const QRegExp &pattern); + QRegExp yPosRolePattern() const; + void setZPosRolePattern(const QRegExp &pattern); + QRegExp zPosRolePattern() const; + void setRotationRolePattern(const QRegExp &pattern); + QRegExp rotationRolePattern() const; + + void setXPosRoleReplace(const QString &replace); + QString xPosRoleReplace() const; + void setYPosRoleReplace(const QString &replace); + QString yPosRoleReplace() const; + void setZPosRoleReplace(const QString &replace); + QString zPosRoleReplace() const; + void setRotationRoleReplace(const QString &replace); + QString rotationRoleReplace() const; + signals: void itemModelChanged(const QAbstractItemModel* itemModel); void xPosRoleChanged(const QString &role); void yPosRoleChanged(const QString &role); void zPosRoleChanged(const QString &role); void rotationRoleChanged(const QString &role); + Q_REVISION(1) void xPosRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void yPosRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void zPosRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void rotationRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void rotationRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void xPosRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void yPosRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void zPosRoleReplaceChanged(const QString &replace); protected: QItemModelScatterDataProxyPrivate *dptr(); diff --git a/src/datavisualization/data/qitemmodelscatterdataproxy_p.h b/src/datavisualization/data/qitemmodelscatterdataproxy_p.h index 4e1f321f..733cbb1e 100644 --- a/src/datavisualization/data/qitemmodelscatterdataproxy_p.h +++ b/src/datavisualization/data/qitemmodelscatterdataproxy_p.h @@ -54,6 +54,16 @@ private: QString m_zPosRole; QString m_rotationRole; + QRegExp m_xPosRolePattern; + QRegExp m_yPosRolePattern; + QRegExp m_zPosRolePattern; + QRegExp m_rotationRolePattern; + + QString m_xPosRoleReplace; + QString m_yPosRoleReplace; + QString m_zPosRoleReplace; + QString m_rotationRoleReplace; + friend class ScatterItemModelHandler; friend class QItemModelScatterDataProxy; }; diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp b/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp index 440ce2d6..5117d386 100644 --- a/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp +++ b/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp @@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QItemModelSurfaceDataProxy * \inmodule QtDataVisualization * \brief Proxy class for presenting data in item models with Q3DSurface. - * \since Qt Data Visualization 1.0 + * \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 @@ -33,6 +33,9 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * * 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 true, single item changes are resolved + * synchronously, unless the same frame also contains a change that causes the whole model to be + * resolved. * * There are three ways to use mappings: * @@ -54,13 +57,24 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * 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: + * 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 * - * \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 QRegExp &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{Qt Quick 2 Bars Example}. * * \sa {Qt Data Visualization Data Handling} */ @@ -79,6 +93,8 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * Data is resolved asynchronously whenever the mapping or the model changes. * QSurfaceDataProxy::arrayReset() is emitted when the data has been resolved. * + * For ItemModelSurfaceDataProxy enums, see \l{QItemModelSurfaceDataProxy::MultiMatchBehavior}. + * * For more details, see QItemModelSurfaceDataProxy documentation. * * Usage example: @@ -95,33 +111,35 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION /*! * \qmlproperty string ItemModelSurfaceDataProxy::rowRole - * The row role of the mapping. + * Defines the item model role to map into row category. * 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. + * is also set as the Z-coordinate value of the QSurfaceDataItem when model data is resolved, + * unless a separate zPos role is also defined. */ /*! * \qmlproperty string ItemModelSurfaceDataProxy::columnRole - * The column role of the mapping. + * Defines the item model role to map into column category. * 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. + * is also set as the X-coordinate value of the QSurfaceDataItem when model data is resolved, + * unless a separate xPos role is also defined. */ /*! * \qmlproperty string ItemModelSurfaceDataProxy::xPosRole - * The X position role of the mapping. If this role is not defined, columnRole is used to - * determine the X-coordinate value of resolved QSurfaceDataItems. + * Defines the item model role to map into X position. If this role is not defined, columnRole is + * used to determine the X-coordinate value of resolved QSurfaceDataItems. */ /*! * \qmlproperty string ItemModelSurfaceDataProxy::yPosRole - * The Y position role of the mapping. + * Defines the item model role to map into Y position. */ /*! * \qmlproperty string ItemModelSurfaceDataProxy::zPosRole - * The Z position role of the mapping. If this role is not defined, rowRole is used to - * determine the Z-coordinate value of resolved QSurfaceDataItems. + * Defines the item model role to map into Z position. If this role is not defined, rowRole is + * used to determine the Z-coordinate value of resolved QSurfaceDataItems. */ /*! @@ -132,8 +150,9 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION /*! * \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. + * 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. */ /*! @@ -159,6 +178,141 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION */ /*! + * \qmlproperty regExp ItemModelSurfaceDataProxy::rowRolePattern + * + * When set, a search and replace is done on the value mapped by 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 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 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 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 xPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and 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 yPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and 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 zPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and zPosRoleReplace property contains the replacement string. + * + * \sa zPosRole, zPosRoleReplace + */ + +/*! + * \qmlproperty string ItemModelSurfaceDataProxy::rowRoleReplace + * + * This property defines the replace content to be used in conjunction with rowRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa rowRole, rowRolePattern + */ + +/*! + * \qmlproperty string ItemModelSurfaceDataProxy::columnRoleReplace + * + * This property defines the replace content to be used in conjunction with columnRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa columnRole, columnRolePattern + */ + +/*! + * \qmlproperty string ItemModelSurfaceDataProxy::xPosRoleReplace + * + * This property defines the replace content to be used in conjunction with xPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa xPosRole, xPosRolePattern + */ + +/*! + * \qmlproperty string ItemModelSurfaceDataProxy::yPosRoleReplace + * + * This property defines the replace content to be used in conjunction with yPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa yPosRole, yPosRolePattern + */ + +/*! + * \qmlproperty string ItemModelSurfaceDataProxy::zPosRoleReplace + * + * This property defines the replace content to be used in conjunction with zPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &rx, const QString &after) + * function documentation. + * + * \sa zPosRole, zPosRolePattern + */ + +/*! + * \qmlproperty ItemModelSurfaceDataProxy.MultiMatchBehavior ItemModelSurfaceDataProxy::multiMatchBehavior + * This property defines how multiple matches for each row/column combination are handled. + * Defaults to 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 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) @@ -171,7 +325,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QObject *parent) * 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, +QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, QObject *parent) : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent) { @@ -186,7 +340,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel * 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, +QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &yPosRole, QObject *parent) : QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent) @@ -203,7 +357,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel * 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(const QAbstractItemModel *itemModel, +QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &yPosRole, @@ -225,7 +379,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel * The role mappings are set with \a rowRole, \a columnRole, \a xPosRole, \a yPosRole, and * \a zPosRole. */ -QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, +QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &xPosRole, @@ -251,7 +405,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel * 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, +QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &yPosRole, @@ -281,7 +435,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel * 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, +QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &xPosRole, @@ -318,12 +472,12 @@ QItemModelSurfaceDataProxy::~QItemModelSurfaceDataProxy() * Defines item model. Does not take ownership of the model, but does connect to it to listen for * changes. */ -void QItemModelSurfaceDataProxy::setItemModel(const QAbstractItemModel *itemModel) +void QItemModelSurfaceDataProxy::setItemModel(QAbstractItemModel *itemModel) { dptr()->m_itemModelHandler->setItemModel(itemModel); } -const QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const +QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const { return dptrc()->m_itemModelHandler->itemModel(); } @@ -331,7 +485,10 @@ const QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const /*! * \property QItemModelSurfaceDataProxy::rowRole * - * Defines the row \a role for the mapping. + * Defines the item model role to map into row category. + * 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, + * unless a separate zPos role is also defined. */ void QItemModelSurfaceDataProxy::setRowRole(const QString &role) { @@ -349,7 +506,10 @@ QString QItemModelSurfaceDataProxy::rowRole() const /*! * \property QItemModelSurfaceDataProxy::columnRole * - * Defines the column \a role for the mapping. + * Defines the item model role to map into column category. + * 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, + * unless a separate xPos role is also defined. */ void QItemModelSurfaceDataProxy::setColumnRole(const QString &role) { @@ -367,9 +527,8 @@ QString QItemModelSurfaceDataProxy::columnRole() const /*! * \property QItemModelSurfaceDataProxy::xPosRole * - * Defines the X position \a role for the mapping. - * If this role is not defined, columnRole is used to determine the X-coordinate - * value of resolved QSurfaceDataItems. + * Defines the item model role to map into X position. If this role is not defined, columnRole is + * used to determine the X-coordinate value of resolved QSurfaceDataItems. */ void QItemModelSurfaceDataProxy::setXPosRole(const QString &role) { @@ -387,7 +546,7 @@ QString QItemModelSurfaceDataProxy::xPosRole() const /*! * \property QItemModelSurfaceDataProxy::yPosRole * - * Defines the Y position \a role for the mapping. + * Defines the item model role to map into Y position. */ void QItemModelSurfaceDataProxy::setYPosRole(const QString &role) { @@ -405,9 +564,8 @@ QString QItemModelSurfaceDataProxy::yPosRole() const /*! * \property QItemModelSurfaceDataProxy::zPosRole * - * Defines the Z position \a role for the mapping. - * If this role is not defined, rowRole is used to determine the Z-coordinate - * value of resolved QSurfaceDataItems. + * Defines the item model role to map into Z position. If this role is not defined, rowRole is + * used to determine the Z-coordinate value of resolved QSurfaceDataItems. */ void QItemModelSurfaceDataProxy::setZPosRole(const QString &role) { @@ -561,6 +719,256 @@ int QItemModelSurfaceDataProxy::columnCategoryIndex(const QString &category) } /*! + * \property QItemModelSurfaceDataProxy::rowRolePattern + * + * When set, a search and replace is done on the value mapped by 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 rowRoleReplace property contains the replacement string. + * + * \sa rowRole, rowRoleReplace + */ +void QItemModelSurfaceDataProxy::setRowRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_rowRolePattern != pattern) { + dptr()->m_rowRolePattern = pattern; + emit rowRolePatternChanged(pattern); + } +} + +QRegExp QItemModelSurfaceDataProxy::rowRolePattern() const +{ + return dptrc()->m_rowRolePattern; +} + +/*! + * \property QItemModelSurfaceDataProxy::columnRolePattern + * + * When set, a search and replace is done on the value mapped by 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 columnRoleReplace property contains the replacement string. + * + * \sa columnRole, columnRoleReplace + */ +void QItemModelSurfaceDataProxy::setColumnRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_columnRolePattern != pattern) { + dptr()->m_columnRolePattern = pattern; + emit columnRolePatternChanged(pattern); + } +} + +QRegExp QItemModelSurfaceDataProxy::columnRolePattern() const +{ + return dptrc()->m_columnRolePattern; +} + +/*! + * \property QItemModelSurfaceDataProxy::xPosRolePattern + * + * When set, a search and replace is done on the value mapped by xPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and xPosRoleReplace property contains the replacement string. + * + * \sa xPosRole, xPosRoleReplace + */ +void QItemModelSurfaceDataProxy::setXPosRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_xPosRolePattern != pattern) { + dptr()->m_xPosRolePattern = pattern; + emit xPosRolePatternChanged(pattern); + } +} + +QRegExp QItemModelSurfaceDataProxy::xPosRolePattern() const +{ + return dptrc()->m_xPosRolePattern; +} + +/*! + * \property QItemModelSurfaceDataProxy::yPosRolePattern + * + * When set, a search and replace is done on the value mapped by yPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and yPosRoleReplace property contains the replacement string. + * + * \sa yPosRole, yPosRoleReplace + */ +void QItemModelSurfaceDataProxy::setYPosRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_yPosRolePattern != pattern) { + dptr()->m_yPosRolePattern = pattern; + emit yPosRolePatternChanged(pattern); + } +} + +QRegExp QItemModelSurfaceDataProxy::yPosRolePattern() const +{ + return dptrc()->m_yPosRolePattern; +} + +/*! + * \property QItemModelSurfaceDataProxy::zPosRolePattern + * + * When set, a search and replace is done on the value mapped by zPos role before it is used as + * a item position value. This property specifies the regular expression to find the portion of the + * mapped value to replace and zPosRoleReplace property contains the replacement string. + * + * \sa zPosRole, zPosRoleReplace + */ +void QItemModelSurfaceDataProxy::setZPosRolePattern(const QRegExp &pattern) +{ + if (dptr()->m_zPosRolePattern != pattern) { + dptr()->m_zPosRolePattern = pattern; + emit zPosRolePatternChanged(pattern); + } +} + +QRegExp QItemModelSurfaceDataProxy::zPosRolePattern() const +{ + return dptrc()->m_zPosRolePattern; +} + +/*! + * \property QItemModelSurfaceDataProxy::rowRoleReplace + * + * This property defines the replace content to be used in conjunction with rowRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &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 + * + * This property defines the replace content to be used in conjunction with columnRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &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 + * + * This property defines the replace content to be used in conjunction with xPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &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 + * + * This property defines the replace content to be used in conjunction with yPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &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 + * + * This property defines the replace content to be used in conjunction with zPosRolePattern. + * Defaults to empty string. For more information on how the search and replace using regular + * expressions works, see QString::replace(const QRegExp &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 + * + * This property defines how multiple matches for each row/column combination are handled. + * Defaults to QItemModelSurfaceDataProxy::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 QItemModelSurfaceDataProxy::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() @@ -583,7 +991,8 @@ QItemModelSurfaceDataProxyPrivate::QItemModelSurfaceDataProxyPrivate(QItemModelS m_itemModelHandler(new SurfaceItemModelHandler(q)), m_useModelCategories(false), m_autoRowCategories(true), - m_autoColumnCategories(true) + m_autoColumnCategories(true), + m_multiMatchBehavior(QItemModelSurfaceDataProxy::MMBLast) { } @@ -621,6 +1030,28 @@ void QItemModelSurfaceDataProxyPrivate::connectItemModelHandler() 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_DATAVISUALIZATION diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy.h b/src/datavisualization/data/qitemmodelsurfacedataproxy.h index b1ebbeed..1b95ed90 100644 --- a/src/datavisualization/data/qitemmodelsurfacedataproxy.h +++ b/src/datavisualization/data/qitemmodelsurfacedataproxy.h @@ -22,6 +22,7 @@ #include <QtDataVisualization/qsurfacedataproxy.h> #include <QtCore/QAbstractItemModel> #include <QtCore/QStringList> +#include <QtCore/QRegExp> QT_BEGIN_NAMESPACE_DATAVISUALIZATION @@ -30,7 +31,8 @@ class QItemModelSurfaceDataProxyPrivate; class QT_DATAVISUALIZATION_EXPORT QItemModelSurfaceDataProxy : public QSurfaceDataProxy { Q_OBJECT - Q_PROPERTY(const QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged) + Q_ENUMS(MultiMatchBehavior) + Q_PROPERTY(QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged) Q_PROPERTY(QString rowRole READ rowRole WRITE setRowRole NOTIFY rowRoleChanged) Q_PROPERTY(QString columnRole READ columnRole WRITE setColumnRole NOTIFY columnRoleChanged) Q_PROPERTY(QString xPosRole READ xPosRole WRITE setXPosRole NOTIFY xPosRoleChanged) @@ -41,32 +43,52 @@ class QT_DATAVISUALIZATION_EXPORT QItemModelSurfaceDataProxy : public QSurfaceDa Q_PROPERTY(bool useModelCategories READ useModelCategories WRITE setUseModelCategories NOTIFY useModelCategoriesChanged) Q_PROPERTY(bool autoRowCategories READ autoRowCategories WRITE setAutoRowCategories NOTIFY autoRowCategoriesChanged) Q_PROPERTY(bool autoColumnCategories READ autoColumnCategories WRITE setAutoColumnCategories NOTIFY autoColumnCategoriesChanged) + Q_PROPERTY(QRegExp rowRolePattern READ rowRolePattern WRITE setRowRolePattern NOTIFY rowRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp columnRolePattern READ columnRolePattern WRITE setColumnRolePattern NOTIFY columnRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp xPosRolePattern READ xPosRolePattern WRITE setXPosRolePattern NOTIFY xPosRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp yPosRolePattern READ yPosRolePattern WRITE setYPosRolePattern NOTIFY yPosRolePatternChanged REVISION 1) + Q_PROPERTY(QRegExp zPosRolePattern READ zPosRolePattern WRITE setZPosRolePattern NOTIFY zPosRolePatternChanged REVISION 1) + Q_PROPERTY(QString rowRoleReplace READ rowRoleReplace WRITE setRowRoleReplace NOTIFY rowRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString columnRoleReplace READ columnRoleReplace WRITE setColumnRoleReplace NOTIFY columnRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString xPosRoleReplace READ xPosRoleReplace WRITE setXPosRoleReplace NOTIFY xPosRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString yPosRoleReplace READ yPosRoleReplace WRITE setYPosRoleReplace NOTIFY yPosRoleReplaceChanged REVISION 1) + Q_PROPERTY(QString zPosRoleReplace READ zPosRoleReplace WRITE setZPosRoleReplace NOTIFY zPosRoleReplaceChanged REVISION 1) + Q_PROPERTY(MultiMatchBehavior multiMatchBehavior READ multiMatchBehavior WRITE setMultiMatchBehavior NOTIFY multiMatchBehaviorChanged REVISION 1) public: + enum MultiMatchBehavior { + MMBFirst = 0, + MMBLast = 1, + MMBAverage = 2, + MMBCumulativeY = 3 + }; + explicit QItemModelSurfaceDataProxy(QObject *parent = 0); - QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, QObject *parent = 0); - QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &yPosRole, + QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, QObject *parent = 0); + QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &yPosRole, QObject *parent = 0); - QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole, + QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &yPosRole, QObject *parent = 0); - QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole, + QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &xPosRole, const QString &yPosRole, const QString &zPosRole, QObject *parent = 0); - QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole, + QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &yPosRole, - const QStringList &rowCategories, const QStringList &columnCategories, + const QStringList &rowCategories, + const QStringList &columnCategories, QObject *parent = 0); - QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole, + QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole, const QString &columnRole, const QString &xPosRole, const QString &yPosRole, const QString &zPosRole, - const QStringList &rowCategories, const QStringList &columnCategories, + const QStringList &rowCategories, + const QStringList &columnCategories, QObject *parent = 0); virtual ~QItemModelSurfaceDataProxy(); - void setItemModel(const QAbstractItemModel *itemModel); - const QAbstractItemModel *itemModel() const; + void setItemModel(QAbstractItemModel *itemModel); + QAbstractItemModel *itemModel() const; void setRowRole(const QString &role); QString rowRole() const; @@ -99,6 +121,31 @@ public: Q_INVOKABLE int rowCategoryIndex(const QString& category); Q_INVOKABLE int columnCategoryIndex(const QString& category); + void setRowRolePattern(const QRegExp &pattern); + QRegExp rowRolePattern() const; + void setColumnRolePattern(const QRegExp &pattern); + QRegExp columnRolePattern() const; + void setXPosRolePattern(const QRegExp &pattern); + QRegExp xPosRolePattern() const; + void setYPosRolePattern(const QRegExp &pattern); + QRegExp yPosRolePattern() const; + void setZPosRolePattern(const QRegExp &pattern); + QRegExp zPosRolePattern() const; + + void setRowRoleReplace(const QString &replace); + QString rowRoleReplace() const; + void setColumnRoleReplace(const QString &replace); + QString columnRoleReplace() const; + void setXPosRoleReplace(const QString &replace); + QString xPosRoleReplace() const; + void setYPosRoleReplace(const QString &replace); + QString yPosRoleReplace() const; + void setZPosRoleReplace(const QString &replace); + QString zPosRoleReplace() const; + + void setMultiMatchBehavior(MultiMatchBehavior behavior); + MultiMatchBehavior multiMatchBehavior() const; + signals: void itemModelChanged(const QAbstractItemModel* itemModel); void rowRoleChanged(const QString &role); @@ -111,6 +158,17 @@ signals: void useModelCategoriesChanged(bool enable); void autoRowCategoriesChanged(bool enable); void autoColumnCategoriesChanged(bool enable); + Q_REVISION(1) void rowRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void columnRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void xPosRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void yPosRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void zPosRolePatternChanged(const QRegExp &pattern); + Q_REVISION(1) void rowRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void columnRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void xPosRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void yPosRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void zPosRoleReplaceChanged(const QString &replace); + Q_REVISION(1) void multiMatchBehaviorChanged(MultiMatchBehavior behavior); protected: QItemModelSurfaceDataProxyPrivate *dptr(); diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h b/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h index 0aaea8fd..9a79dca2 100644 --- a/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h +++ b/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h @@ -64,6 +64,20 @@ private: bool m_autoRowCategories; bool m_autoColumnCategories; + QRegExp m_rowRolePattern; + QRegExp m_columnRolePattern; + QRegExp m_xPosRolePattern; + QRegExp m_yPosRolePattern; + QRegExp m_zPosRolePattern; + + QString m_rowRoleReplace; + QString m_columnRoleReplace; + QString m_xPosRoleReplace; + QString m_yPosRoleReplace; + QString m_zPosRoleReplace; + + QItemModelSurfaceDataProxy::MultiMatchBehavior m_multiMatchBehavior; + friend class SurfaceItemModelHandler; friend class QItemModelSurfaceDataProxy; }; diff --git a/src/datavisualization/data/qscatter3dseries.cpp b/src/datavisualization/data/qscatter3dseries.cpp index 43bde4dd..e81933ed 100644 --- a/src/datavisualization/data/qscatter3dseries.cpp +++ b/src/datavisualization/data/qscatter3dseries.cpp @@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QScatter3DSeries * \inmodule QtDataVisualization * \brief Base series class for Q3DScatter. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * QScatter3DSeries manages the series specific visual elements, as well as series data * (via data proxy). @@ -298,9 +298,54 @@ void QScatter3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *ne } } +void QScatter3DSeriesPrivate::createItemLabel() +{ + static const QString xTitleTag(QStringLiteral("@xTitle")); + static const QString yTitleTag(QStringLiteral("@yTitle")); + static const QString zTitleTag(QStringLiteral("@zTitle")); + static const QString xLabelTag(QStringLiteral("@xLabel")); + static const QString yLabelTag(QStringLiteral("@yLabel")); + static const QString zLabelTag(QStringLiteral("@zLabel")); + static const QString seriesNameTag(QStringLiteral("@seriesName")); + + if (m_selectedItem == QScatter3DSeries::invalidSelectionIndex()) { + m_itemLabel = QString(); + return; + } + + QValue3DAxis *axisX = static_cast<QValue3DAxis *>(m_controller->axisX()); + QValue3DAxis *axisY = static_cast<QValue3DAxis *>(m_controller->axisY()); + QValue3DAxis *axisZ = static_cast<QValue3DAxis *>(m_controller->axisZ()); + QVector3D selectedPosition = qptr()->dataProxy()->itemAt(m_selectedItem)->position(); + + m_itemLabel = m_itemLabelFormat; + + m_itemLabel.replace(xTitleTag, axisX->title()); + m_itemLabel.replace(yTitleTag, axisY->title()); + m_itemLabel.replace(zTitleTag, axisZ->title()); + + if (m_itemLabel.contains(xLabelTag)) { + QString valueLabelText = axisX->formatter()->stringForValue( + qreal(selectedPosition.x()), axisX->labelFormat()); + m_itemLabel.replace(xLabelTag, valueLabelText); + } + if (m_itemLabel.contains(yLabelTag)) { + QString valueLabelText = axisY->formatter()->stringForValue( + qreal(selectedPosition.y()), axisY->labelFormat()); + m_itemLabel.replace(yLabelTag, valueLabelText); + } + if (m_itemLabel.contains(zLabelTag)) { + QString valueLabelText = axisZ->formatter()->stringForValue( + qreal(selectedPosition.z()), axisZ->labelFormat()); + m_itemLabel.replace(zLabelTag, valueLabelText); + } + m_itemLabel.replace(seriesNameTag, m_name); +} + void QScatter3DSeriesPrivate::setSelectedItem(int index) { if (index != m_selectedItem) { + markItemLabelDirty(); m_selectedItem = index; emit qptr()->selectedItemChanged(m_selectedItem); } diff --git a/src/datavisualization/data/qscatter3dseries_p.h b/src/datavisualization/data/qscatter3dseries_p.h index 1abbd406..8717a616 100644 --- a/src/datavisualization/data/qscatter3dseries_p.h +++ b/src/datavisualization/data/qscatter3dseries_p.h @@ -43,6 +43,7 @@ public: virtual void setDataProxy(QAbstractDataProxy *proxy); virtual void connectControllerAndProxy(Abstract3DController *newController); + virtual void createItemLabel(); void setSelectedItem(int index); void setItemSize(float size); diff --git a/src/datavisualization/data/qscatterdataitem.cpp b/src/datavisualization/data/qscatterdataitem.cpp index 9751dfeb..e45b22f3 100644 --- a/src/datavisualization/data/qscatterdataitem.cpp +++ b/src/datavisualization/data/qscatterdataitem.cpp @@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \inmodule QtDataVisualization * \brief The QScatterDataItem class provides a container for resolved data to be added to scatter * graphs. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * A QScatterDataItem holds data for a single rendered item in a scatter graph. * Scatter data proxies parse data into QScatterDataItem instances for visualizing. diff --git a/src/datavisualization/data/qscatterdataitem_p.h b/src/datavisualization/data/qscatterdataitem_p.h index efb1cc5c..2884c2e3 100644 --- a/src/datavisualization/data/qscatterdataitem_p.h +++ b/src/datavisualization/data/qscatterdataitem_p.h @@ -39,9 +39,6 @@ class QScatterDataItemPrivate public: QScatterDataItemPrivate(); virtual ~QScatterDataItemPrivate(); - -protected: - friend class QScatterDataItem; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qscatterdataproxy.cpp b/src/datavisualization/data/qscatterdataproxy.cpp index 84bb57e7..cc2e3bd8 100644 --- a/src/datavisualization/data/qscatterdataproxy.cpp +++ b/src/datavisualization/data/qscatterdataproxy.cpp @@ -16,7 +16,6 @@ ** ****************************************************************************/ -#include "qscatterdataproxy.h" #include "qscatterdataproxy_p.h" #include "qscatter3dseries_p.h" @@ -26,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QScatterDataProxy * \inmodule QtDataVisualization * \brief Base proxy class for Q3DScatter. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * QScatterDataProxy handles adding, inserting, changing, and removing data items. * diff --git a/src/datavisualization/data/qsurface3dseries.cpp b/src/datavisualization/data/qsurface3dseries.cpp index 72967bae..1107d721 100644 --- a/src/datavisualization/data/qsurface3dseries.cpp +++ b/src/datavisualization/data/qsurface3dseries.cpp @@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QSurface3DSeries * \inmodule QtDataVisualization * \brief Base series class for Q3DSurface. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * QSurface3DSeries manages the series specific visual elements, as well as series data * (via data proxy). @@ -75,7 +75,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * This type manages the series specific visual elements, as well as series data * (via data proxy). * - * For Surface3DSeries enums, see \l QSurface3DSeries::DrawFlag + * For Surface3DSeries enums, see \l{QSurface3DSeries::DrawFlag}. * * For more complete description, see QSurface3DSeries. * @@ -373,9 +373,54 @@ void QSurface3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *ne } } +void QSurface3DSeriesPrivate::createItemLabel() +{ + static const QString xTitleTag(QStringLiteral("@xTitle")); + static const QString yTitleTag(QStringLiteral("@yTitle")); + static const QString zTitleTag(QStringLiteral("@zTitle")); + static const QString xLabelTag(QStringLiteral("@xLabel")); + static const QString yLabelTag(QStringLiteral("@yLabel")); + static const QString zLabelTag(QStringLiteral("@zLabel")); + static const QString seriesNameTag(QStringLiteral("@seriesName")); + + if (m_selectedPoint == QSurface3DSeries::invalidSelectionPosition()) { + m_itemLabel = QString(); + return; + } + + QValue3DAxis *axisX = static_cast<QValue3DAxis *>(m_controller->axisX()); + QValue3DAxis *axisY = static_cast<QValue3DAxis *>(m_controller->axisY()); + QValue3DAxis *axisZ = static_cast<QValue3DAxis *>(m_controller->axisZ()); + QVector3D selectedPosition = qptr()->dataProxy()->itemAt(m_selectedPoint)->position(); + + m_itemLabel = m_itemLabelFormat; + + m_itemLabel.replace(xTitleTag, axisX->title()); + m_itemLabel.replace(yTitleTag, axisY->title()); + m_itemLabel.replace(zTitleTag, axisZ->title()); + + if (m_itemLabel.contains(xLabelTag)) { + QString valueLabelText = axisX->formatter()->stringForValue( + qreal(selectedPosition.x()), axisX->labelFormat()); + m_itemLabel.replace(xLabelTag, valueLabelText); + } + if (m_itemLabel.contains(yLabelTag)) { + QString valueLabelText = axisY->formatter()->stringForValue( + qreal(selectedPosition.y()), axisY->labelFormat()); + m_itemLabel.replace(yLabelTag, valueLabelText); + } + if (m_itemLabel.contains(zLabelTag)) { + QString valueLabelText = axisZ->formatter()->stringForValue( + qreal(selectedPosition.z()), axisZ->labelFormat()); + m_itemLabel.replace(zLabelTag, valueLabelText); + } + m_itemLabel.replace(seriesNameTag, m_name); +} + void QSurface3DSeriesPrivate::setSelectedPoint(const QPoint &position) { if (position != m_selectedPoint) { + markItemLabelDirty(); m_selectedPoint = position; emit qptr()->selectedPointChanged(m_selectedPoint); } diff --git a/src/datavisualization/data/qsurface3dseries_p.h b/src/datavisualization/data/qsurface3dseries_p.h index bc8157bd..d4cc2820 100644 --- a/src/datavisualization/data/qsurface3dseries_p.h +++ b/src/datavisualization/data/qsurface3dseries_p.h @@ -43,6 +43,7 @@ public: virtual void setDataProxy(QAbstractDataProxy *proxy); virtual void connectControllerAndProxy(Abstract3DController *newController); + virtual void createItemLabel(); void setSelectedPoint(const QPoint &position); void setFlatShadingEnabled(bool enabled); diff --git a/src/datavisualization/data/qsurfacedataitem.cpp b/src/datavisualization/data/qsurfacedataitem.cpp index c8a76a67..cd3819c7 100644 --- a/src/datavisualization/data/qsurfacedataitem.cpp +++ b/src/datavisualization/data/qsurfacedataitem.cpp @@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \inmodule QtDataVisualization * \brief The QSurfaceDataItem class provides a container for resolved data to be added to surface * graphs. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * * A QSurfaceDataItem holds data for a single vertex in surface graph. * Surface data proxies parse data into QSurfaceDataItem instances for visualizing. diff --git a/src/datavisualization/data/qsurfacedataitem_p.h b/src/datavisualization/data/qsurfacedataitem_p.h index 0cec7eab..e00134e3 100644 --- a/src/datavisualization/data/qsurfacedataitem_p.h +++ b/src/datavisualization/data/qsurfacedataitem_p.h @@ -39,9 +39,6 @@ class QSurfaceDataItemPrivate public: QSurfaceDataItemPrivate(); virtual ~QSurfaceDataItemPrivate(); - -protected: - friend class QSurfaceDataItem; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qsurfacedataproxy.cpp b/src/datavisualization/data/qsurfacedataproxy.cpp index 2e66bb5b..dbe7cc49 100644 --- a/src/datavisualization/data/qsurfacedataproxy.cpp +++ b/src/datavisualization/data/qsurfacedataproxy.cpp @@ -16,7 +16,6 @@ ** ****************************************************************************/ -#include "qsurfacedataproxy.h" #include "qsurfacedataproxy_p.h" #include "qsurface3dseries_p.h" @@ -26,10 +25,10 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * \class QSurfaceDataProxy * \inmodule QtDataVisualization * \brief Base proxy class for Q3DSurface. - * \since Qt Data Visualization 1.0 + * \since QtDataVisualization 1.0 * - * QSurfaceDataProxy takes care of surface related data handling. The QSurfaceDataProxy handles the data - * in rows and for this it provides two auxiliary typedefs. QSurfaceDataArray is a QList for + * QSurfaceDataProxy takes care of surface related data handling. The QSurfaceDataProxy handles the + * data in rows and for this it provides two auxiliary typedefs. QSurfaceDataArray is a QList for * controlling the rows. For rows there is a QVector QSurfaceDataRow which contains QSurfaceDataItem * objects. See Q3DSurface documentation and basic sample code there how to feed the data for the * QSurfaceDataProxy. @@ -41,17 +40,18 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * If you use QSurfaceDataRow pointers to directly modify data after adding the array to the proxy, * you must also emit proper signal to make the graph update. * - * To make a sensible surface, the X-value of each successive item in the same row must be greater than the - * previous item in that row, and the the Z-value of each successive item in a column must be greater than - * the previous item in that column. + * To make a sensible surface, the X-value of each successive item in all rows must be + * either ascending or descending throughout the row. + * Similarly, the Z-value of each successive item in all columns must be either ascending or + * descending throughout the column. * - * \note In the initial release, only surfaces with straight rows and columns are fully supported. Any row - * with items that do not have the exact same Z-value or any columns with items that do not have the exact - * same X-value may get clipped incorrectly if the whole surface doesn't fit to the visible X or Z axis - * ranges. + * \note Currently only surfaces with straight rows and columns are fully supported. Any row + * with items that do not have the exact same Z-value or any column with items that do not have + * the exact same X-value may get clipped incorrectly if the whole surface doesn't completely fit + * in the visible X or Z axis ranges. * * \note Surfaces with less than two rows or columns are not considered valid surfaces and will - * not get rendered. + * not be rendered. * * \sa {Qt Data Visualization Data Handling} */ @@ -520,10 +520,14 @@ void QSurfaceDataProxyPrivate::limitValues(QVector3D &minValues, QVector3D &maxV minValues.setY(min); maxValues.setY(max); if (columns) { - minValues.setX(m_dataArray->at(0)->at(0).x()); - minValues.setZ(m_dataArray->at(0)->at(0).z()); - maxValues.setX(m_dataArray->at(0)->last().x()); - maxValues.setZ(m_dataArray->last()->at(0).z()); + float xLow = m_dataArray->at(0)->at(0).x(); + float xHigh = m_dataArray->at(0)->last().x(); + float zLow = m_dataArray->at(0)->at(0).z(); + float zHigh = m_dataArray->last()->at(0).z(); + minValues.setX(qMin(xLow, xHigh)); + minValues.setZ(qMin(zLow, zHigh)); + maxValues.setX(qMax(xLow, xHigh)); + maxValues.setZ(qMax(zLow, zHigh)); } else { minValues.setX(0.0f); minValues.setZ(0.0f); diff --git a/src/datavisualization/data/scatteritemmodelhandler.cpp b/src/datavisualization/data/scatteritemmodelhandler.cpp index 08ed12f3..8b4a6f89 100644 --- a/src/datavisualization/data/scatteritemmodelhandler.cpp +++ b/src/datavisualization/data/scatteritemmodelhandler.cpp @@ -25,7 +25,15 @@ static const int noRoleIndex = -1; ScatterItemModelHandler::ScatterItemModelHandler(QItemModelScatterDataProxy *proxy, QObject *parent) : AbstractItemModelHandler(parent), m_proxy(proxy), - m_proxyArray(0) + m_proxyArray(0), + m_xPosRole(noRoleIndex), + m_yPosRole(noRoleIndex), + m_zPosRole(noRoleIndex), + m_rotationRole(noRoleIndex), + m_haveXPosPattern(false), + m_haveYPosPattern(false), + m_haveZPosPattern(false), + m_haveRotationPattern(false) { } @@ -130,17 +138,48 @@ void ScatterItemModelHandler::modelPosToScatterItem(int modelRow, int modelColum QScatterDataItem &item) { QModelIndex index = m_itemModel->index(modelRow, modelColumn); - float xPos(0.0f); - float yPos(0.0f); - float zPos(0.0f); - if (m_xPosRole != noRoleIndex) - xPos = index.data(m_xPosRole).toFloat(); - if (m_yPosRole != noRoleIndex) - yPos = index.data(m_yPosRole).toFloat(); - if (m_zPosRole != noRoleIndex) - zPos = index.data(m_zPosRole).toFloat(); - if (m_rotationRole != noRoleIndex) - item.setRotation(toQuaternion(index.data(m_rotationRole))); + float xPos; + float yPos; + float zPos; + if (m_xPosRole != noRoleIndex) { + QVariant xValueVar = index.data(m_xPosRole); + if (m_haveXPosPattern) + xPos = xValueVar.toString().replace(m_xPosPattern, m_xPosReplace).toFloat(); + else + xPos = xValueVar.toFloat(); + } else { + xPos = 0.0f; + } + if (m_yPosRole != noRoleIndex) { + QVariant yValueVar = index.data(m_yPosRole); + if (m_haveYPosPattern) + yPos = yValueVar.toString().replace(m_yPosPattern, m_yPosReplace).toFloat(); + else + yPos = yValueVar.toFloat(); + } else { + yPos = 0.0f; + } + if (m_zPosRole != noRoleIndex) { + QVariant zValueVar = index.data(m_zPosRole); + if (m_haveZPosPattern) + zPos = zValueVar.toString().replace(m_zPosPattern, m_zPosReplace).toFloat(); + else + zPos = zValueVar.toFloat(); + } else { + zPos = 0.0f; + } + if (m_rotationRole != noRoleIndex) { + QVariant rotationVar = index.data(m_rotationRole); + if (m_haveRotationPattern) { + item.setRotation( + toQuaternion( + QVariant(rotationVar.toString().replace(m_rotationPattern, + m_rotationReplace)))); + } else { + item.setRotation(toQuaternion(rotationVar)); + } + } + item.setPosition(QVector3D(xPos, yPos, zPos)); } @@ -153,6 +192,19 @@ void ScatterItemModelHandler::resolveModel() return; } + m_xPosPattern = m_proxy->xPosRolePattern(); + m_yPosPattern = m_proxy->yPosRolePattern(); + m_zPosPattern = m_proxy->zPosRolePattern(); + m_rotationPattern = m_proxy->rotationRolePattern(); + m_xPosReplace = m_proxy->xPosRoleReplace(); + m_yPosReplace = m_proxy->yPosRoleReplace(); + m_zPosReplace = m_proxy->zPosRoleReplace(); + m_rotationReplace = m_proxy->rotationRoleReplace(); + m_haveXPosPattern = !m_xPosPattern.isEmpty() && m_xPosPattern.isValid(); + m_haveYPosPattern = !m_yPosPattern.isEmpty() && m_yPosPattern.isValid(); + m_haveZPosPattern = !m_zPosPattern.isEmpty() && m_zPosPattern.isValid(); + m_haveRotationPattern = !m_rotationPattern.isEmpty() && m_rotationPattern.isValid(); + QHash<int, QByteArray> roleHash = m_itemModel->roleNames(); m_xPosRole = roleHash.key(m_proxy->xPosRole().toLatin1(), noRoleIndex); m_yPosRole = roleHash.key(m_proxy->yPosRole().toLatin1(), noRoleIndex); diff --git a/src/datavisualization/data/scatteritemmodelhandler_p.h b/src/datavisualization/data/scatteritemmodelhandler_p.h index 0661d734..817b245d 100644 --- a/src/datavisualization/data/scatteritemmodelhandler_p.h +++ b/src/datavisualization/data/scatteritemmodelhandler_p.h @@ -59,6 +59,18 @@ private: int m_yPosRole; int m_zPosRole; int m_rotationRole; + QRegExp m_xPosPattern; + QRegExp m_yPosPattern; + QRegExp m_zPosPattern; + QRegExp m_rotationPattern; + QString m_xPosReplace; + QString m_yPosReplace; + QString m_zPosReplace; + QString m_rotationReplace; + bool m_haveXPosPattern; + bool m_haveYPosPattern; + bool m_haveZPosPattern; + bool m_haveRotationPattern; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/scatterrenderitem.cpp b/src/datavisualization/data/scatterrenderitem.cpp index 3b2e64c5..0b5398f1 100644 --- a/src/datavisualization/data/scatterrenderitem.cpp +++ b/src/datavisualization/data/scatterrenderitem.cpp @@ -17,8 +17,6 @@ ****************************************************************************/ #include "scatterrenderitem_p.h" -#include "scatter3drenderer_p.h" -#include "qscatterdataproxy.h" QT_BEGIN_NAMESPACE_DATAVISUALIZATION @@ -29,10 +27,10 @@ ScatterRenderItem::ScatterRenderItem() } ScatterRenderItem::ScatterRenderItem(const ScatterRenderItem &other) - : AbstractRenderItem(other), - m_visible(false) + : AbstractRenderItem(other) { m_position = other.m_position; + m_visible = other.m_visible; } ScatterRenderItem::~ScatterRenderItem() diff --git a/src/datavisualization/data/scatterrenderitem_p.h b/src/datavisualization/data/scatterrenderitem_p.h index eb070682..d754a8ca 100644 --- a/src/datavisualization/data/scatterrenderitem_p.h +++ b/src/datavisualization/data/scatterrenderitem_p.h @@ -33,8 +33,6 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION -class Scatter3DRenderer; - class ScatterRenderItem : public AbstractRenderItem { public: @@ -55,8 +53,6 @@ public: protected: QVector3D m_position; bool m_visible; - - friend class QScatterDataItem; }; typedef QVector<ScatterRenderItem> ScatterRenderItemArray; diff --git a/src/datavisualization/data/surfaceitemmodelhandler.cpp b/src/datavisualization/data/surfaceitemmodelhandler.cpp index f4383dbf..e6d1e70d 100644 --- a/src/datavisualization/data/surfaceitemmodelhandler.cpp +++ b/src/datavisualization/data/surfaceitemmodelhandler.cpp @@ -25,7 +25,13 @@ static const int noRoleIndex = -1; SurfaceItemModelHandler::SurfaceItemModelHandler(QItemModelSurfaceDataProxy *proxy, QObject *parent) : AbstractItemModelHandler(parent), m_proxy(proxy), - m_proxyArray(0) + m_proxyArray(0), + m_xPosRole(noRoleIndex), + m_yPosRole(noRoleIndex), + m_zPosRole(noRoleIndex), + m_haveXPosPattern(false), + m_haveYPosPattern(false), + m_haveZPosPattern(false) { } @@ -33,6 +39,62 @@ SurfaceItemModelHandler::~SurfaceItemModelHandler() { } +void SurfaceItemModelHandler::handleDataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight, + const QVector<int> &roles) +{ + // Do nothing if full reset already pending + if (!m_fullReset) { + if (!m_proxy->useModelCategories()) { + // If the data model doesn't directly map rows and columns, we cannot optimize + AbstractItemModelHandler::handleDataChanged(topLeft, bottomRight, roles); + } else { + int startRow = qMin(topLeft.row(), bottomRight.row()); + int endRow = qMax(topLeft.row(), bottomRight.row()); + int startCol = qMin(topLeft.column(), bottomRight.column()); + int endCol = qMax(topLeft.column(), bottomRight.column()); + + for (int i = startRow; i <= endRow; i++) { + for (int j = startCol; j <= endCol; j++) { + QModelIndex index = m_itemModel->index(i, j); + QSurfaceDataItem item; + QVariant xValueVar = index.data(m_xPosRole); + QVariant yValueVar = index.data(m_yPosRole); + QVariant zValueVar = index.data(m_zPosRole); + const QSurfaceDataItem *oldItem = m_proxy->itemAt(i, j); + float xPos; + float yPos; + float zPos; + if (m_xPosRole != noRoleIndex) { + if (m_haveXPosPattern) + xPos = xValueVar.toString().replace(m_xPosPattern, m_xPosReplace).toFloat(); + else + xPos = xValueVar.toFloat(); + } else { + xPos = oldItem->x(); + } + + if (m_haveYPosPattern) + yPos = yValueVar.toString().replace(m_yPosPattern, m_yPosReplace).toFloat(); + else + yPos = yValueVar.toFloat(); + + if (m_zPosRole != noRoleIndex) { + if (m_haveZPosPattern) + zPos = zValueVar.toString().replace(m_zPosPattern, m_zPosReplace).toFloat(); + else + zPos = zValueVar.toFloat(); + } else { + zPos = oldItem->z(); + } + item.setPosition(QVector3D(xPos, yPos, zPos)); + m_proxy->setItem(i, j, item); + } + } + } + } +} + // Resolve entire item model into QSurfaceDataArray. void SurfaceItemModelHandler::resolveModel() { @@ -49,12 +111,29 @@ void SurfaceItemModelHandler::resolveModel() return; } + // Position patterns can be reused on single item changes, so store them to member variables. + QRegExp rowPattern(m_proxy->rowRolePattern()); + QRegExp colPattern(m_proxy->columnRolePattern()); + m_xPosPattern = m_proxy->xPosRolePattern(); + m_yPosPattern = m_proxy->yPosRolePattern(); + m_zPosPattern = m_proxy->zPosRolePattern(); + QString rowReplace = m_proxy->rowRoleReplace(); + QString colReplace = m_proxy->columnRoleReplace(); + m_xPosReplace = m_proxy->xPosRoleReplace(); + m_yPosReplace = m_proxy->yPosRoleReplace(); + m_zPosReplace = m_proxy->zPosRoleReplace(); + bool haveRowPattern = !rowPattern.isEmpty() && rowPattern.isValid(); + bool haveColPattern = !colPattern.isEmpty() && colPattern.isValid(); + m_haveXPosPattern = !m_xPosPattern.isEmpty() && m_xPosPattern.isValid(); + m_haveYPosPattern = !m_yPosPattern.isEmpty() && m_yPosPattern.isValid(); + m_haveZPosPattern = !m_zPosPattern.isEmpty() && m_zPosPattern.isValid(); + QHash<int, QByteArray> roleHash = m_itemModel->roleNames(); // Default to display role if no mapping - int xPosRole = roleHash.key(m_proxy->xPosRole().toLatin1(), noRoleIndex); - int yPosRole = roleHash.key(m_proxy->yPosRole().toLatin1(), Qt::DisplayRole); - int zPosRole = roleHash.key(m_proxy->zPosRole().toLatin1(), noRoleIndex); + m_xPosRole = roleHash.key(m_proxy->xPosRole().toLatin1(), noRoleIndex); + m_yPosRole = roleHash.key(m_proxy->yPosRole().toLatin1(), Qt::DisplayRole); + m_zPosRole = roleHash.key(m_proxy->zPosRole().toLatin1(), noRoleIndex); int rowCount = m_itemModel->rowCount(); int columnCount = m_itemModel->columnCount(); @@ -70,41 +149,58 @@ void SurfaceItemModelHandler::resolveModel() for (int i = 0; i < rowCount; i++) { QSurfaceDataRow &newProxyRow = *m_proxyArray->at(i); for (int j = 0; j < columnCount; j++) { - float xPos = j; - float zPos = i; - if (xPosRole != noRoleIndex) { - xPos = m_itemModel->index(i, j).data(xPosRole).toFloat(); + QModelIndex index = m_itemModel->index(i, j); + QVariant xValueVar = index.data(m_xPosRole); + QVariant yValueVar = index.data(m_yPosRole); + QVariant zValueVar = index.data(m_zPosRole); + float xPos; + float yPos; + float zPos; + if (m_xPosRole != noRoleIndex) { + if (m_haveXPosPattern) + xPos = xValueVar.toString().replace(m_xPosPattern, m_xPosReplace).toFloat(); + else + xPos = xValueVar.toFloat(); } else { QString header = m_itemModel->headerData(j, Qt::Horizontal).toString(); bool ok = false; float headerValue = header.toFloat(&ok); if (ok) xPos = headerValue; + else + xPos = float(j); } - if (zPosRole != noRoleIndex) { - zPos = m_itemModel->index(i, j).data(zPosRole).toFloat(); + if (m_haveYPosPattern) + yPos = yValueVar.toString().replace(m_yPosPattern, m_yPosReplace).toFloat(); + else + yPos = yValueVar.toFloat(); + + if (m_zPosRole != noRoleIndex) { + if (m_haveZPosPattern) + zPos = zValueVar.toString().replace(m_zPosPattern, m_zPosReplace).toFloat(); + else + zPos = zValueVar.toFloat(); } else { QString header = m_itemModel->headerData(i, Qt::Vertical).toString(); bool ok = false; float headerValue = header.toFloat(&ok); if (ok) zPos = headerValue; + else + zPos = float(i); } - newProxyRow[j].setPosition( - QVector3D(xPos, - m_itemModel->index(i, j).data(yPosRole).toFloat(), - zPos)); + newProxyRow[j].setPosition(QVector3D(xPos, yPos, zPos)); } } } else { int rowRole = roleHash.key(m_proxy->rowRole().toLatin1()); int columnRole = roleHash.key(m_proxy->columnRole().toLatin1()); - if (xPosRole == noRoleIndex) - xPosRole = columnRole; - if (zPosRole == noRoleIndex) - zPosRole = rowRole; + if (m_xPosRole == noRoleIndex) + m_xPosRole = columnRole; + if (m_zPosRole == noRoleIndex) + m_zPosRole = rowRole; bool generateRows = m_proxy->autoRowCategories(); bool generateColumns = m_proxy->autoColumnCategories(); @@ -116,6 +212,14 @@ void SurfaceItemModelHandler::resolveModel() QHash<QString, bool> rowListHash; QHash<QString, bool> columnListHash; + bool cumulative = m_proxy->multiMatchBehavior() == QItemModelSurfaceDataProxy::MMBAverage + || m_proxy->multiMatchBehavior() == QItemModelSurfaceDataProxy::MMBCumulativeY; + bool average = m_proxy->multiMatchBehavior() == QItemModelSurfaceDataProxy::MMBAverage; + bool takeFirst = m_proxy->multiMatchBehavior() == QItemModelSurfaceDataProxy::MMBFirst; + QHash<QString, QHash<QString, int> > *matchCountMap = 0; + if (cumulative) + matchCountMap = new QHash<QString, QHash<QString, int> >; + // Sort values into rows and columns typedef QHash<QString, QVector3D> ColumnValueMap; QHash <QString, ColumnValueMap> itemValueMap; @@ -123,11 +227,45 @@ void SurfaceItemModelHandler::resolveModel() for (int j = 0; j < columnCount; j++) { QModelIndex index = m_itemModel->index(i, j); QString rowRoleStr = index.data(rowRole).toString(); + if (haveRowPattern) + rowRoleStr.replace(rowPattern, rowReplace); QString columnRoleStr = index.data(columnRole).toString(); - QVector3D itemPos(index.data(xPosRole).toReal(), - index.data(yPosRole).toReal(), - index.data(zPosRole).toReal()); - itemValueMap[rowRoleStr][columnRoleStr] = itemPos; + if (haveColPattern) + columnRoleStr.replace(colPattern, colReplace); + QVariant xValueVar = index.data(m_xPosRole); + QVariant yValueVar = index.data(m_yPosRole); + QVariant zValueVar = index.data(m_zPosRole); + float xPos; + float yPos; + float zPos; + if (m_haveXPosPattern) + xPos = xValueVar.toString().replace(m_xPosPattern, m_xPosReplace).toFloat(); + else + xPos = xValueVar.toFloat(); + if (m_haveYPosPattern) + yPos = yValueVar.toString().replace(m_yPosPattern, m_yPosReplace).toFloat(); + else + yPos = yValueVar.toFloat(); + if (m_haveZPosPattern) + zPos = zValueVar.toString().replace(m_zPosPattern, m_zPosReplace).toFloat(); + else + zPos = zValueVar.toFloat(); + + QVector3D itemPos(xPos, yPos, zPos); + + if (cumulative) + (*matchCountMap)[rowRoleStr][columnRoleStr]++; + + if (cumulative) { + itemValueMap[rowRoleStr][columnRoleStr] += itemPos; + } else { + if (takeFirst && itemValueMap.contains(rowRoleStr)) { + if (itemValueMap.value(rowRoleStr).contains(columnRoleStr)) + continue; // We already have a value for this row/column combo + } + itemValueMap[rowRoleStr][columnRoleStr] = itemPos; + } + if (generateRows && !rowListHash.value(rowRoleStr, false)) { rowListHash.insert(rowRoleStr, true); rowList << rowRoleStr; @@ -161,9 +299,22 @@ void SurfaceItemModelHandler::resolveModel() for (int i = 0; i < rowList.size(); i++) { QString rowKey = rowList.at(i); QSurfaceDataRow &newProxyRow = *m_proxyArray->at(i); - for (int j = 0; j < columnList.size(); j++) - newProxyRow[j].setPosition(itemValueMap[rowKey][columnList.at(j)]); + for (int j = 0; j < columnList.size(); j++) { + QVector3D &itemPos = itemValueMap[rowKey][columnList.at(j)]; + if (cumulative) { + if (average) { + itemPos /= float((*matchCountMap)[rowKey][columnList.at(j)]); + } else { // cumulativeY + float divisor = float((*matchCountMap)[rowKey][columnList.at(j)]); + itemPos.setX(itemPos.x() / divisor); + itemPos.setZ(itemPos.z() / divisor); + } + } + newProxyRow[j].setPosition(itemPos); + } } + + delete matchCountMap; } m_proxy->resetArray(m_proxyArray); diff --git a/src/datavisualization/data/surfaceitemmodelhandler_p.h b/src/datavisualization/data/surfaceitemmodelhandler_p.h index ae426433..572788d6 100644 --- a/src/datavisualization/data/surfaceitemmodelhandler_p.h +++ b/src/datavisualization/data/surfaceitemmodelhandler_p.h @@ -41,11 +41,27 @@ public: SurfaceItemModelHandler(QItemModelSurfaceDataProxy *proxy, QObject *parent = 0); virtual ~SurfaceItemModelHandler(); +public slots: + virtual void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, + const QVector<int> &roles = QVector<int> ()); + protected: void virtual resolveModel(); QItemModelSurfaceDataProxy *m_proxy; // Not owned QSurfaceDataArray *m_proxyArray; // Not owned + int m_xPosRole; + int m_yPosRole; + int m_zPosRole; + QRegExp m_xPosPattern; + QRegExp m_yPosPattern; + QRegExp m_zPosPattern; + QString m_xPosReplace; + QString m_yPosReplace; + QString m_zPosReplace; + bool m_haveXPosPattern; + bool m_haveYPosPattern; + bool m_haveZPosPattern; }; QT_END_NAMESPACE_DATAVISUALIZATION |