summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/datavisualization/data/baritemmodelhandler.cpp50
-rw-r--r--src/datavisualization/data/baritemmodelhandler_p.h6
-rw-r--r--src/datavisualization/data/scatteritemmodelhandler.cpp6
-rw-r--r--src/datavisualization/data/surfaceitemmodelhandler.cpp78
-rw-r--r--src/datavisualization/data/surfaceitemmodelhandler_p.h7
-rw-r--r--src/datavisualization/engine/bars3dcontroller.cpp6
-rw-r--r--src/datavisualization/engine/bars3drenderer.cpp13
-rw-r--r--tests/itemmodeltest/itemmodeltest.pro11
-rw-r--r--tests/itemmodeltest/main.cpp293
-rw-r--r--tests/tests.pro3
10 files changed, 439 insertions, 34 deletions
diff --git a/src/datavisualization/data/baritemmodelhandler.cpp b/src/datavisualization/data/baritemmodelhandler.cpp
index 4f44fe1d..3b02c1e3 100644
--- a/src/datavisualization/data/baritemmodelhandler.cpp
+++ b/src/datavisualization/data/baritemmodelhandler.cpp
@@ -26,7 +26,9 @@ 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)
{
}
@@ -34,6 +36,34 @@ 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++) {
+ QBarDataItem item;
+ item.setValue(m_itemModel->index(i, j).data(m_valueRole).toFloat());
+ if (m_rotationRole != noRoleIndex)
+ item.setRotation(m_itemModel->index(i, j).data(m_rotationRole).toFloat());
+ m_proxy->setItem(i, j, item);
+ }
+ }
+ }
+ }
+}
+
// Resolve entire item model into QBarDataArray.
void BarItemModelHandler::resolveModel()
{
@@ -54,8 +84,8 @@ void BarItemModelHandler::resolveModel()
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 +101,9 @@ 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());
+ newProxyRow[j].setValue(m_itemModel->index(i, j).data(m_valueRole).toFloat());
+ if (m_rotationRole != noRoleIndex)
+ newProxyRow[j].setRotation(m_itemModel->index(i, j).data(m_rotationRole).toFloat());
}
}
// Generate labels from headers if using model rows/columns
@@ -104,9 +134,9 @@ void BarItemModelHandler::resolveModel()
QModelIndex index = m_itemModel->index(i, j);
QString rowRoleStr = index.data(rowRole).toString();
QString columnRoleStr = index.data(columnRole).toString();
- itemValueMap[rowRoleStr][columnRoleStr] = index.data(valueRole).toReal();
- if (rotationRole != noRoleIndex)
- itemRotationMap[rowRoleStr][columnRoleStr] = index.data(rotationRole).toReal();
+ itemValueMap[rowRoleStr][columnRoleStr] = index.data(m_valueRole).toFloat();
+ if (m_rotationRole != noRoleIndex)
+ itemRotationMap[rowRoleStr][columnRoleStr] = index.data(m_rotationRole).toFloat();
if (generateRows && !rowListHash.value(rowRoleStr, false)) {
rowListHash.insert(rowRoleStr, true);
rowList << rowRoleStr;
@@ -142,7 +172,7 @@ void BarItemModelHandler::resolveModel()
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)
+ if (m_rotationRole != noRoleIndex)
newProxyRow[j].setRotation(itemRotationMap[rowKey][columnList.at(j)]);
}
}
diff --git a/src/datavisualization/data/baritemmodelhandler_p.h b/src/datavisualization/data/baritemmodelhandler_p.h
index 7bf7b0a1..737e0055 100644
--- a/src/datavisualization/data/baritemmodelhandler_p.h
+++ b/src/datavisualization/data/baritemmodelhandler_p.h
@@ -41,12 +41,18 @@ 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;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/scatteritemmodelhandler.cpp b/src/datavisualization/data/scatteritemmodelhandler.cpp
index 08ed12f3..280f2a23 100644
--- a/src/datavisualization/data/scatteritemmodelhandler.cpp
+++ b/src/datavisualization/data/scatteritemmodelhandler.cpp
@@ -25,7 +25,11 @@ 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)
{
}
diff --git a/src/datavisualization/data/surfaceitemmodelhandler.cpp b/src/datavisualization/data/surfaceitemmodelhandler.cpp
index f4383dbf..584ddf28 100644
--- a/src/datavisualization/data/surfaceitemmodelhandler.cpp
+++ b/src/datavisualization/data/surfaceitemmodelhandler.cpp
@@ -25,7 +25,10 @@ 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)
{
}
@@ -33,6 +36,45 @@ 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++) {
+ QSurfaceDataItem item;
+ const QSurfaceDataItem *oldItem = m_proxy->itemAt(i, j);
+ float xPos;
+ float zPos;
+ if (m_xPosRole != noRoleIndex)
+ xPos = m_itemModel->index(i, j).data(m_xPosRole).toFloat();
+ else
+ xPos = oldItem->x();
+ if (m_zPosRole != noRoleIndex)
+ zPos = m_itemModel->index(i, j).data(m_zPosRole).toFloat();
+ else
+ zPos = oldItem->z();
+ item.setPosition(QVector3D(xPos,
+ m_itemModel->index(i, j).data(m_yPosRole).toFloat(),
+ zPos));
+ m_proxy->setItem(i, j, item);
+ }
+ }
+ }
+ }
+}
+
// Resolve entire item model into QSurfaceDataArray.
void SurfaceItemModelHandler::resolveModel()
{
@@ -52,9 +94,9 @@ void SurfaceItemModelHandler::resolveModel()
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,10 +112,10 @@ 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();
+ float xPos = float(j);
+ float zPos = float(i);
+ if (m_xPosRole != noRoleIndex) {
+ xPos = m_itemModel->index(i, j).data(m_xPosRole).toFloat();
} else {
QString header = m_itemModel->headerData(j, Qt::Horizontal).toString();
bool ok = false;
@@ -82,8 +124,8 @@ void SurfaceItemModelHandler::resolveModel()
xPos = headerValue;
}
- if (zPosRole != noRoleIndex) {
- zPos = m_itemModel->index(i, j).data(zPosRole).toFloat();
+ if (m_zPosRole != noRoleIndex) {
+ zPos = m_itemModel->index(i, j).data(m_zPosRole).toFloat();
} else {
QString header = m_itemModel->headerData(i, Qt::Vertical).toString();
bool ok = false;
@@ -94,17 +136,17 @@ void SurfaceItemModelHandler::resolveModel()
newProxyRow[j].setPosition(
QVector3D(xPos,
- m_itemModel->index(i, j).data(yPosRole).toFloat(),
+ m_itemModel->index(i, j).data(m_yPosRole).toFloat(),
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();
@@ -124,9 +166,9 @@ void SurfaceItemModelHandler::resolveModel()
QModelIndex index = m_itemModel->index(i, j);
QString rowRoleStr = index.data(rowRole).toString();
QString columnRoleStr = index.data(columnRole).toString();
- QVector3D itemPos(index.data(xPosRole).toReal(),
- index.data(yPosRole).toReal(),
- index.data(zPosRole).toReal());
+ QVector3D itemPos(index.data(m_xPosRole).toFloat(),
+ index.data(m_yPosRole).toFloat(),
+ index.data(m_zPosRole).toFloat());
itemValueMap[rowRoleStr][columnRoleStr] = itemPos;
if (generateRows && !rowListHash.value(rowRoleStr, false)) {
rowListHash.insert(rowRoleStr, true);
diff --git a/src/datavisualization/data/surfaceitemmodelhandler_p.h b/src/datavisualization/data/surfaceitemmodelhandler_p.h
index ae426433..dbed0a60 100644
--- a/src/datavisualization/data/surfaceitemmodelhandler_p.h
+++ b/src/datavisualization/data/surfaceitemmodelhandler_p.h
@@ -41,11 +41,18 @@ 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;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/bars3dcontroller.cpp b/src/datavisualization/engine/bars3dcontroller.cpp
index 99fa8223..35b24218 100644
--- a/src/datavisualization/engine/bars3dcontroller.cpp
+++ b/src/datavisualization/engine/bars3dcontroller.cpp
@@ -148,7 +148,6 @@ void Bars3DController::handleRowsChanged(int startIndex, int count)
if (!oldChangeCount)
m_changedRows.reserve(count);
- int selectedRow = m_selectedBar.x();
for (int i = 0; i < count; i++) {
bool newItem = true;
int candidate = startIndex + i;
@@ -162,7 +161,7 @@ void Bars3DController::handleRowsChanged(int startIndex, int count)
if (newItem) {
ChangeRow newChangeItem = {series, candidate};
m_changedRows.append(newChangeItem);
- if (series == m_selectedBarSeries && selectedRow == candidate)
+ if (series == m_selectedBarSeries && m_selectedBar.x() == candidate)
series->d_ptr->markItemLabelDirty();
}
}
@@ -516,7 +515,8 @@ void Bars3DController::setSelectedBar(const QPoint &position, QBar3DSeries *seri
adjustSelectionPosition(pos, series);
if (selectionMode().testFlag(QAbstract3DGraph::SelectionSlice)) {
- // If the selected bar is outside data window, or there is no visible selected bar, disable slicing
+ // If the selected bar is outside data window, or there is no visible selected bar,
+ // disable slicing.
if (pos.x() < m_axisZ->min() || pos.x() > m_axisZ->max()
|| pos.y() < m_axisX->min() || pos.y() > m_axisX->max()
|| !series->isVisible()) {
diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp
index ab7bb4ca..f93d20b6 100644
--- a/src/datavisualization/engine/bars3drenderer.cpp
+++ b/src/datavisualization/engine/bars3drenderer.cpp
@@ -337,8 +337,14 @@ void Bars3DRenderer::updateRows(const QVector<Bars3DController::ChangeRow> &rows
if (!cache->isVisible() && !cache->dataDirty())
cache->setDataDirty(true);
}
- if (cache->isVisible())
+ if (cache->isVisible()) {
updateRenderRow(dataArray->at(row), cache->renderArray()[row - minRow]);
+ if (m_cachedIsSlicingActivated
+ && cache == m_selectedSeriesCache
+ && m_selectedBarPos.x() == row) {
+ m_selectionDirty = true; // Need to update slice view
+ }
+ }
}
}
@@ -370,6 +376,11 @@ void Bars3DRenderer::updateItems(const QVector<Bars3DController::ChangeItem> &it
if (cache->isVisible()) {
updateRenderItem(dataArray->at(row)->at(col),
cache->renderArray()[row - minRow][col - minCol]);
+ if (m_cachedIsSlicingActivated
+ && cache == m_selectedSeriesCache
+ && m_selectedBarPos == QPoint(row, col)) {
+ m_selectionDirty = true; // Need to update slice view
+ }
}
}
}
diff --git a/tests/itemmodeltest/itemmodeltest.pro b/tests/itemmodeltest/itemmodeltest.pro
new file mode 100644
index 00000000..d1cf0959
--- /dev/null
+++ b/tests/itemmodeltest/itemmodeltest.pro
@@ -0,0 +1,11 @@
+android|ios {
+ error( "This test is not supported for android or ios." )
+}
+
+!include( ../tests.pri ) {
+ error( "Couldn't find the tests.pri file!" )
+}
+
+SOURCES += main.cpp
+
+QT += widgets
diff --git a/tests/itemmodeltest/main.cpp b/tests/itemmodeltest/main.cpp
new file mode 100644
index 00000000..419ee162
--- /dev/null
+++ b/tests/itemmodeltest/main.cpp
@@ -0,0 +1,293 @@
+/****************************************************************************
+**
+** 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 <QtDataVisualization/q3dbars.h>
+#include <QtDataVisualization/q3dsurface.h>
+#include <QtDataVisualization/qcategory3daxis.h>
+#include <QtDataVisualization/qitemmodelbardataproxy.h>
+#include <QtDataVisualization/qitemmodelsurfacedataproxy.h>
+#include <QtDataVisualization/qvalue3daxis.h>
+#include <QtDataVisualization/q3dscene.h>
+#include <QtDataVisualization/q3dcamera.h>
+#include <QtDataVisualization/qbar3dseries.h>
+#include <QtDataVisualization/q3dtheme.h>
+
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QVBoxLayout>
+#include <QtWidgets/QTableWidget>
+#include <QtGui/QScreen>
+#include <QtCore/QTimer>
+#include <QtCore/QDebug>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QPushButton>
+
+#define USE_STATIC_DATA
+
+using namespace QtDataVisualization;
+
+class GraphDataGenerator : public QObject
+{
+public:
+ explicit GraphDataGenerator(Q3DBars *bargraph, Q3DSurface * surfaceGraph,
+ QTableWidget *tableWidget);
+ ~GraphDataGenerator();
+
+ void setupModel();
+ void addRow();
+ void changeStyle();
+ void changePresetCamera();
+ void changeTheme();
+ void start();
+ void selectFromTable(const QPoint &selection);
+ void selectedFromTable(int currentRow, int currentColumn, int previousRow, int previousColumn);
+ void fixTableSize();
+ void changeSelectedButtonClicked();
+
+private:
+ Q3DBars *m_barGraph;
+ Q3DSurface *m_surfaceGraph;
+ QTimer *m_dataTimer;
+ QTimer *m_styleTimer;
+ QTimer *m_presetTimer;
+ QTimer *m_themeTimer;
+ int m_columnCount;
+ int m_rowCount;
+ QTableWidget *m_tableWidget; // not owned
+};
+
+GraphDataGenerator::GraphDataGenerator(Q3DBars *bargraph, Q3DSurface * surfaceGraph,
+ QTableWidget *tableWidget)
+ : m_barGraph(bargraph),
+ m_surfaceGraph(surfaceGraph),
+ m_dataTimer(0),
+ m_styleTimer(0),
+ m_presetTimer(0),
+ m_themeTimer(0),
+ m_columnCount(100),
+ m_rowCount(50),
+ m_tableWidget(tableWidget)
+{
+ // Set up bar specifications; make the bars as wide as they are deep,
+ // and add a small space between them
+ m_barGraph->setBarThickness(1.0f);
+ m_barGraph->setBarSpacing(QSizeF(0.2, 0.2));
+
+#ifndef USE_STATIC_DATA
+ // Set up sample space; make it as deep as it's wide
+ m_barGraph->rowAxis()->setRange(0, m_rowCount);
+ m_barGraph->columnAxis()->setRange(0, m_columnCount);
+ m_tableWidget->setColumnCount(m_columnCount);
+
+ // Set selection mode to full
+ m_barGraph->setSelectionMode(QAbstract3DGraph::SelectionItemRowAndColumn);
+
+ // Hide axis labels by explicitly setting one empty string as label list
+ m_barGraph->rowAxis()->setLabels(QStringList(QString()));
+ m_barGraph->columnAxis()->setLabels(QStringList(QString()));
+
+ m_barGraph->seriesList().at(0)->setItemLabelFormat(QStringLiteral("@valueLabel"));
+#else
+ // Set selection mode to slice row
+ m_barGraph->setSelectionMode(
+ QAbstract3DGraph::SelectionItemAndRow | QAbstract3DGraph::SelectionSlice);
+ m_surfaceGraph->setSelectionMode(
+ QAbstract3DGraph::SelectionItemAndRow | QAbstract3DGraph::SelectionSlice);
+#endif
+}
+
+GraphDataGenerator::~GraphDataGenerator()
+{
+ if (m_dataTimer) {
+ m_dataTimer->stop();
+ delete m_dataTimer;
+ }
+ delete m_barGraph;
+ delete m_surfaceGraph;
+}
+
+void GraphDataGenerator::start()
+{
+#ifndef USE_STATIC_DATA
+ m_dataTimer = new QTimer();
+ m_dataTimer->setTimerType(Qt::CoarseTimer);
+ QObject::connect(m_dataTimer, &QTimer::timeout, this, &GraphDataGenerator::addRow);
+ m_dataTimer->start(0);
+ m_tableWidget->setFixedWidth(m_graph->width());
+#else
+ setupModel();
+
+ // Table needs to be shown before the size of its headers can be accurately obtained,
+ // so we postpone it a bit
+ m_dataTimer = new QTimer();
+ m_dataTimer->setSingleShot(true);
+ QObject::connect(m_dataTimer, &QTimer::timeout, this, &GraphDataGenerator::fixTableSize);
+ m_dataTimer->start(0);
+#endif
+}
+
+void GraphDataGenerator::setupModel()
+{
+ // Set up row and column names
+ QStringList days;
+ days << "Monday" << "Tuesday" << "Wednesday" << "Thursday" << "Friday" << "Saturday" << "Sunday";
+ QStringList weeks;
+ weeks << "week 1" << "week 2" << "week 3" << "week 4" << "week 5";
+
+ // Set up data Mon Tue Wed Thu Fri Sat Sun
+ float hours[5][7] = {{2.0f, 1.0f, 3.0f, 0.2f, 1.0f, 5.0f, 10.0f}, // week 1
+ {0.5f, 1.0f, 3.0f, 1.0f, 2.0f, 2.0f, 3.0f}, // week 2
+ {1.0f, 1.0f, 2.0f, 1.0f, 4.0f, 4.0f, 4.0f}, // week 3
+ {0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.3f}, // week 4
+ {3.0f, 3.0f, 6.0f, 2.0f, 2.0f, 1.0f, 1.0f}}; // week 5
+
+ // Add labels
+ m_barGraph->rowAxis()->setTitle("Week of year");
+ m_barGraph->columnAxis()->setTitle("Day of week");
+ m_barGraph->valueAxis()->setTitle("Hours spent on the Internet");
+ m_barGraph->valueAxis()->setLabelFormat("%.1f h");
+
+ m_surfaceGraph->axisZ()->setTitle("Week of year");
+ m_surfaceGraph->axisX()->setTitle("Day of week");
+ m_surfaceGraph->axisY()->setTitle("Hours spent on the Internet");
+ m_surfaceGraph->axisY()->setLabelFormat("%.1f h");
+
+ m_tableWidget->setRowCount(5);
+ m_tableWidget->setColumnCount(7);
+ m_tableWidget->setHorizontalHeaderLabels(days);
+ m_tableWidget->setVerticalHeaderLabels(weeks);
+ m_tableWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ m_tableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ m_tableWidget->setCurrentCell(-1, -1);
+
+ for (int week = 0; week < weeks.size(); week++) {
+ for (int day = 0; day < days.size(); day++) {
+ QModelIndex index = m_tableWidget->model()->index(week, day);
+ m_tableWidget->model()->setData(index, hours[week][day]);
+ }
+ }
+}
+
+void GraphDataGenerator::addRow()
+{
+ m_tableWidget->model()->insertRow(0);
+ if (m_tableWidget->model()->rowCount() > m_rowCount)
+ m_tableWidget->model()->removeRow(m_rowCount);
+ for (int i = 0; i < m_columnCount; i++) {
+ QModelIndex index = m_tableWidget->model()->index(0, i);
+ m_tableWidget->model()->setData(index,
+ ((float)i / (float)m_columnCount) / 2.0f + (float)(rand() % 30) / 100.0f);
+ }
+ m_tableWidget->resizeColumnsToContents();
+}
+
+void GraphDataGenerator::selectFromTable(const QPoint &selection)
+{
+ m_tableWidget->setFocus();
+ m_tableWidget->setCurrentCell(selection.x(), selection.y());
+}
+
+void GraphDataGenerator::selectedFromTable(int currentRow, int currentColumn,
+ int previousRow, int previousColumn)
+{
+ Q_UNUSED(previousRow)
+ Q_UNUSED(previousColumn)
+ m_barGraph->seriesList().at(0)->setSelectedBar(QPoint(currentRow, currentColumn));
+ m_surfaceGraph->seriesList().at(0)->setSelectedPoint(QPoint(currentRow, currentColumn));
+}
+
+void GraphDataGenerator::fixTableSize()
+{
+ int width = m_tableWidget->horizontalHeader()->length();
+ width += m_tableWidget->verticalHeader()->width();
+ m_tableWidget->setFixedWidth(width + 2);
+ int height = m_tableWidget->verticalHeader()->length();
+ height += m_tableWidget->horizontalHeader()->height();
+ m_tableWidget->setFixedHeight(height + 2);
+}
+
+void GraphDataGenerator::changeSelectedButtonClicked()
+{
+ // Change all selected cells to a random value 1-10
+ QVariant value = QVariant::fromValue(float((rand() % 10) + 1));
+ QList<QTableWidgetItem *> selectedItems = m_tableWidget->selectedItems();
+ foreach (QTableWidgetItem *item, selectedItems)
+ item->setData(Qt::DisplayRole, value);
+}
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ Q3DBars *barGraph = new Q3DBars();
+ Q3DSurface *surfaceGraph = new Q3DSurface();
+ QWidget *barContainer = QWidget::createWindowContainer(barGraph);
+ QWidget *surfaceContainer = QWidget::createWindowContainer(surfaceGraph);
+
+ barContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ barContainer->setFocusPolicy(Qt::StrongFocus);
+ surfaceContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ surfaceContainer->setFocusPolicy(Qt::StrongFocus);
+
+ QWidget widget;
+ QVBoxLayout *mainLayout = new QVBoxLayout(&widget);
+ QHBoxLayout *graphLayout = new QHBoxLayout();
+ QVBoxLayout *buttonLayout = new QVBoxLayout();
+ QHBoxLayout *bottomLayout = new QHBoxLayout();
+ QTableWidget *tableWidget = new QTableWidget(&widget);
+ QPushButton *changeSelectedButton = new QPushButton(&widget);
+ changeSelectedButton->setText(QStringLiteral("Change Selected"));
+
+ buttonLayout->addWidget(changeSelectedButton);
+ graphLayout->addWidget(barContainer);
+ graphLayout->addWidget(surfaceContainer);
+ bottomLayout->addLayout(buttonLayout);
+ bottomLayout->addWidget(tableWidget);
+ mainLayout->addLayout(graphLayout);
+ mainLayout->addLayout(bottomLayout);
+
+ tableWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ tableWidget->setAlternatingRowColors(true);
+ widget.setWindowTitle(QStringLiteral("Hours spent on the Internet"));
+
+ // Since we are dealing with QTableWidget, the model will already have data sorted properly
+ // into rows and columns, so we simply set useModelCategories property to true to utilize this.
+ QItemModelBarDataProxy *barProxy = new QItemModelBarDataProxy(tableWidget->model());
+ QItemModelSurfaceDataProxy *surfaceProxy = new QItemModelSurfaceDataProxy(tableWidget->model());
+ barProxy->setUseModelCategories(true);
+ surfaceProxy->setUseModelCategories(true);
+ QBar3DSeries *barSeries = new QBar3DSeries(barProxy);
+ QSurface3DSeries *surfaceSeries = new QSurface3DSeries(surfaceProxy);
+ barSeries->setMesh(QAbstract3DSeries::MeshPyramid);
+ barGraph->addSeries(barSeries);
+ surfaceGraph->addSeries(surfaceSeries);
+
+ GraphDataGenerator generator(barGraph, surfaceGraph, tableWidget);
+ QObject::connect(barSeries, &QBar3DSeries::selectedBarChanged, &generator,
+ &GraphDataGenerator::selectFromTable);
+ QObject::connect(surfaceSeries, &QSurface3DSeries::selectedPointChanged, &generator,
+ &GraphDataGenerator::selectFromTable);
+ QObject::connect(tableWidget, &QTableWidget::currentCellChanged, &generator,
+ &GraphDataGenerator::selectedFromTable);
+ QObject::connect(changeSelectedButton, &QPushButton::clicked, &generator,
+ &GraphDataGenerator::changeSelectedButtonClicked);
+
+ QSize screenSize = barGraph->screen()->size();
+ widget.resize(QSize(screenSize.width() / 2, screenSize.height() / 2));
+ widget.show();
+ generator.start();
+ return app.exec();
+}
diff --git a/tests/tests.pro b/tests/tests.pro
index 613534e9..7b690c7d 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -14,7 +14,8 @@ SUBDIRS += barstest \
qmldynamicdata \
multigraphs \
directional \
- qmlmultiwindow
+ qmlmultiwindow \
+ itemmodeltest
#SUBDIRS += kinectsurface