aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2018-08-10 12:00:45 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2019-01-15 12:32:08 +0000
commit8396dc86f28e89a920d85f59518fac79da8480eb (patch)
treee38220c0049d50f289625563933b702cc39bc540 /tests
parentaca0351c7ce933503b042fd8d745d220c7dd331d (diff)
StorageModel manual test: use DelegateChoices to show data graphically
This demonstrates that DelegateChooser and DelegateChoice are working with TableView. In this use case, DelegateChooser uses a role from the model to decide which delegate type to instantiate. So we need the model to provide a type role that it can switch on. Conveniently, by using the Q_ENUM registration of the Type enum, it automatically becomes possible to match against the stringified versions of those enum values in the DelegateChoice.roleValue property. To demonstrate a set of roles which would work for almost any kind of numeric data, we choose to have a Value role for the current value, corresponding to the width of the bar or the numerator of the ratio; and ValueMax for the maximum possible value, corresponding to the total width of the bar graph, or the denominator of the ratio. ValueDisplay and ValueMaxDisplay are roles which provide string-formatted versions of those for labeling purposes. Maybe in the future we could consider adding those (plus ValueMin and ValueMinDisplay) to the ItemDataRole enum; because almost any kind of data model could need to provide numeric data, but for some reason we have only made it easy to provide strings (DisplayRole) and booleans (CheckStateRole). Likewise some sort of type role could be standardized at the same time. Free / used space is graphically shown as a bar graph. QStorageInfo provides bytesFree() but not bytesUsed(), but it's more conventional to show a bar which grows wider as more space is used, so we reverse it visually by showing a red background with the bytesFree bar anchored to the right. Thus the width of the red part showing through is proportional to bytes used. The three flags isReady, isReadOnly and isValid are shown with simulated checkboxes. This manual test is now on its way to becoming an example of how to use row, column and role effectively together. It's not enough to say that TableView is only for spreadsheet-like views, displaying only text in each cell. To display more than text, we can do the same thing that we have done in the past with models designed for display with ListView: use the role, so that data(index, role) gets called multiple times for each cell, to get the values that each delegate type needs to use to render itself. Change-Id: I1060eacc2b7d25f420411828258e7d94ee0bdd0b Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/manual/tableview/storagemodel/main.qml74
-rw-r--r--tests/manual/tableview/storagemodel/storagemodel.cpp82
-rw-r--r--tests/manual/tableview/storagemodel/storagemodel.h25
3 files changed, 149 insertions, 32 deletions
diff --git a/tests/manual/tableview/storagemodel/main.qml b/tests/manual/tableview/storagemodel/main.qml
index 2603fba0e2..725d7da7b0 100644
--- a/tests/manual/tableview/storagemodel/main.qml
+++ b/tests/manual/tableview/storagemodel/main.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -38,13 +38,14 @@
****************************************************************************/
import QtQuick 2.12
-import QtQuick.Window 2.3
+import QtQuick.Window 2.12
+import Qt.labs.qmlmodels 1.0
import StorageModel 0.1
Window {
id: window
- width: 640
- height: 480
+ width: 480
+ height: 300
visible: true
color: "darkgray"
title: "Storage Volumes"
@@ -57,17 +58,62 @@ Window {
model: StorageModel { }
columnSpacing: 1
rowSpacing: 1
- delegate: Rectangle {
- id: tableDelegate
- implicitWidth: displayText.implicitWidth + 8
- implicitHeight: displayText.implicitHeight + 14
+ delegate: DelegateChooser {
+ role: "type"
+ DelegateChoice {
+ roleValue: "Value"
+ delegate: Rectangle {
+ color: "tomato"
+ implicitWidth: Math.max(100, label.implicitWidth + 8)
+ implicitHeight: label.implicitHeight + 4
- Text {
- id: displayText
- anchors.bottom: parent.bottom
- anchors.left: parent.left
- anchors.leftMargin: 4
- text: display
+ Rectangle {
+ x: parent.width - width
+ width: value * parent.width / valueMax
+ height: parent.height
+ color: "white"
+ }
+
+ Text {
+ id: label
+ anchors.baseline: parent.bottom
+ anchors.baselineOffset: -4
+ anchors.left: parent.left
+ anchors.leftMargin: 4
+ text: valueDisplay + " of " + valueMaxDisplay + " " + heading
+ }
+ }
+ }
+ DelegateChoice {
+ roleValue: "Flag"
+ // We could use a checkbox here but that would be another component (e.g. from Controls)
+ delegate: Rectangle {
+ implicitWidth: checkBox.implicitWidth + 8
+ implicitHeight: checkBox.implicitHeight + 4
+ Text {
+ id: checkBox
+ anchors.baseline: parent.bottom
+ anchors.baselineOffset: -4
+ anchors.left: parent.left
+ anchors.leftMargin: 4
+ text: (checkState ? "☑ " : "☐ ") + heading
+ }
+ }
+ }
+ DelegateChoice {
+ // roleValue: "String" // default delegate
+ delegate: Rectangle {
+ implicitWidth: stringLabel.implicitWidth + 8
+ implicitHeight: stringLabel.implicitHeight + 4
+ Text {
+ id: stringLabel
+ anchors.baseline: parent.bottom
+ anchors.baselineOffset: -4
+ anchors.left: parent.left
+ anchors.leftMargin: 4
+ text: display
+ }
+ }
}
}
}
diff --git a/tests/manual/tableview/storagemodel/storagemodel.cpp b/tests/manual/tableview/storagemodel/storagemodel.cpp
index b6b861a1a8..b43454b249 100644
--- a/tests/manual/tableview/storagemodel/storagemodel.cpp
+++ b/tests/manual/tableview/storagemodel/storagemodel.cpp
@@ -63,6 +63,20 @@ StorageModel::StorageModel(QObject *parent) :
refresh();
}
+QHash<int, QByteArray> StorageModel::roleNames() const {
+ static auto roles = QHash<int, QByteArray> {
+ { int(Role::Type), "type" },
+ { int(Role::Heading), "heading" },
+ { int(Role::Value), "value" },
+ { int(Role::ValueMax), "valueMax" },
+ { int(Role::ValueDisplay), "valueDisplay" },
+ { int(Role::ValueMaxDisplay), "valueMaxDisplay" },
+ { Qt::CheckStateRole, "checkState" },
+ };
+ static auto ret = roles.unite(QAbstractTableModel::roleNames());;
+ return ret;
+}
+
void StorageModel::refresh()
{
beginResetModel();
@@ -92,7 +106,6 @@ Qt::ItemFlags StorageModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags result = QAbstractTableModel::flags(index);
switch (Column(index.column())) {
- case Column::Available:
case Column::IsReady:
case Column::IsReadOnly:
case Column::IsValid:
@@ -109,7 +122,9 @@ QVariant StorageModel::data(const QModelIndex &index, int role) const
if (!index.isValid())
return QVariant();
- if (role == Qt::DisplayRole) {
+ switch (role) {
+ case Qt::DisplayRole:
+ case int(Role::ValueDisplay): {
const QStorageInfo &volume = m_volumes.at(index.row());
switch (Column(index.column())) {
case Column::RootPath:
@@ -120,12 +135,8 @@ QVariant StorageModel::data(const QModelIndex &index, int role) const
return volume.device();
case Column::FileSystemName:
return volume.fileSystemType();
- case Column::Total:
- return QLocale().formattedDataSize(volume.bytesTotal());
case Column::Free:
return QLocale().formattedDataSize(volume.bytesFree());
- case Column::Available:
- return QLocale().formattedDataSize(volume.bytesAvailable());
case Column::IsReady:
return volume.isReady();
case Column::IsReadOnly:
@@ -135,7 +146,8 @@ QVariant StorageModel::data(const QModelIndex &index, int role) const
default:
break;
}
- } else if (role == Qt::CheckStateRole) {
+ } break;
+ case Qt::CheckStateRole: {
const QStorageInfo &volume = m_volumes.at(index.row());
switch (Column(index.column())) {
case Column::IsReady:
@@ -147,17 +159,16 @@ QVariant StorageModel::data(const QModelIndex &index, int role) const
default:
break;
}
- } else if (role == Qt::TextAlignmentRole) {
+ } break;
+ case Qt::TextAlignmentRole:
switch (Column(index.column())) {
- case Column::Total:
case Column::Free:
- case Column::Available:
return Qt::AlignTrailing;
default:
break;
}
return Qt::AlignLeading;
- } else if (role == Qt::ToolTipRole) {
+ case Qt::ToolTipRole: {
QLocale locale;
const QStorageInfo &volume = m_volumes.at(index.row());
return tr("Root path : %1\n"
@@ -186,6 +197,51 @@ QVariant StorageModel::data(const QModelIndex &index, int role) const
arg(volume.isValid() ? tr("true") : tr("false")).
arg(volume.isRoot() ? tr("true") : tr("false"));
}
+ case int(Role::Type):
+ switch (Column(index.column())) {
+ case Column::RootPath:
+ case Column::Name:
+ case Column::Device:
+ case Column::FileSystemName:
+ return QVariant::fromValue(Type::String);
+ break;
+ case Column::Free:
+ return QVariant::fromValue(Type::Value);
+ case Column::IsReady:
+ case Column::IsReadOnly:
+ case Column::IsValid:
+ return QVariant::fromValue(Type::Flag);
+ default:
+ break;
+ }
+ break;
+ case int(Role::Heading):
+ return headerData(index.column());
+ case int(Role::Value):
+ switch (Column(index.column())) {
+ case Column::Free:
+ return m_volumes.at(index.row()).bytesFree();
+ default:
+ break;
+ }
+ break;
+ case int(Role::ValueMax):
+ switch (Column(index.column())) {
+ case Column::Free:
+ return m_volumes.at(index.row()).bytesTotal();
+ default:
+ break;
+ }
+ break;
+ case int(Role::ValueMaxDisplay):
+ switch (Column(index.column())) {
+ case Column::Free:
+ return QLocale().formattedDataSize(m_volumes.at(index.row()).bytesTotal());
+ default:
+ break;
+ }
+ break;
+ } // switch (role)
return QVariant();
}
@@ -206,12 +262,8 @@ QVariant StorageModel::headerData(int section, Qt::Orientation orientation, int
return tr("Device");
case Column::FileSystemName:
return tr("File System");
- case Column::Total:
- return tr("Total");
case Column::Free:
return tr("Free");
- case Column::Available:
- return tr("Available");
case Column::IsReady:
return tr("Ready");
case Column::IsReadOnly:
diff --git a/tests/manual/tableview/storagemodel/storagemodel.h b/tests/manual/tableview/storagemodel/storagemodel.h
index 1f6f6f8b1f..6cbab3d850 100644
--- a/tests/manual/tableview/storagemodel/storagemodel.h
+++ b/tests/manual/tableview/storagemodel/storagemodel.h
@@ -65,23 +65,42 @@ public:
Name,
Device,
FileSystemName,
- Total,
Free,
- Available,
IsReady,
IsReadOnly,
IsValid,
Count
};
+ Q_ENUM(Column)
+
+ enum class Role : int {
+ Type = Qt::UserRole + 1,
+ Heading,
+ Value,
+ ValueMax, // If we had ValueMin, it would always be zero in this example
+ ValueDisplay,
+ ValueMaxDisplay,
+ Count
+ };
+ Q_ENUM(Role)
+
+ enum class Type : int {
+ String, // use Qt::DisplayRole
+ Value, // use Role::Value and Role::ValueMax
+ Flag, // use Qt::CheckStateRole
+ Count
+ };
+ Q_ENUM(Type)
explicit StorageModel(QObject *parent = nullptr);
int columnCount(const QModelIndex &parent) const override;
int rowCount(const QModelIndex &parent) const override;
+ QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex &index, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
- QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+ QVariant headerData(int section, Qt::Orientation orientation = Qt::Horizontal, int role = Qt::DisplayRole) const override;
public slots:
void refresh();