1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2018 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QtCore/QtCore> |
30 | #include <QtGui/QStandardItemModel> |
31 | |
32 | class TestModel : public QAbstractTableModel |
33 | { |
34 | Q_OBJECT |
35 | Q_PROPERTY(int rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged) |
36 | Q_PROPERTY(int columnCount READ columnCount WRITE setColumnCount NOTIFY columnCountChanged) |
37 | |
38 | public: |
39 | TestModel(QObject *parent = nullptr) |
40 | : QAbstractTableModel(parent) |
41 | {} |
42 | |
43 | TestModel(int rows, int columns, QObject *parent = nullptr) |
44 | : QAbstractTableModel(parent) |
45 | , m_rows(rows) |
46 | , m_columns(columns) |
47 | {} |
48 | |
49 | TestModel(int rows, int columns, bool dataCanBeFetched, QObject *parent = nullptr) |
50 | : QAbstractTableModel(parent) |
51 | , m_rows(rows) |
52 | , m_columns(columns) |
53 | , m_dataCanBeFetched(dataCanBeFetched) |
54 | {} |
55 | |
56 | int rowCount(const QModelIndex & = QModelIndex()) const override { return m_rows; } |
57 | void setRowCount(int count) { beginResetModel(); m_rows = count; emit rowCountChanged(); endResetModel(); } |
58 | |
59 | int columnCount(const QModelIndex & = QModelIndex()) const override { return m_columns; } |
60 | void setColumnCount(int count) { beginResetModel(); m_columns = count; emit columnCountChanged(); endResetModel(); } |
61 | |
62 | QVariant data(const QModelIndex &index, int role) const override |
63 | { |
64 | if (!index.isValid() || role != Qt::DisplayRole) |
65 | return QVariant(); |
66 | |
67 | int serializedIndex = index.row() + (index.column() * m_columns); |
68 | if (modelData.contains(key: serializedIndex)) |
69 | return modelData.value(key: serializedIndex); |
70 | return QStringLiteral("%1" ).arg(a: index.row()); |
71 | } |
72 | |
73 | Q_INVOKABLE QVariant dataFromSerializedIndex(int index) const |
74 | { |
75 | if (modelData.contains(key: index)) |
76 | return modelData.value(key: index); |
77 | return QString(); |
78 | } |
79 | |
80 | QHash<int, QByteArray> roleNames() const override |
81 | { |
82 | return { {Qt::DisplayRole, "display" } }; |
83 | } |
84 | |
85 | Q_INVOKABLE void setModelData(const QPoint &cell, const QSize &span, const QString &string) |
86 | { |
87 | for (int c = 0; c < span.width(); ++c) { |
88 | for (int r = 0; r < span.height(); ++r) { |
89 | const int changedRow = cell.y() + r; |
90 | const int changedColumn = cell.x() + c; |
91 | const int serializedIndex = changedRow + (changedColumn * m_rows); |
92 | modelData.insert(key: serializedIndex, value: string); |
93 | } |
94 | } |
95 | |
96 | const auto topLeftIndex = createIndex(arow: cell.y(), acolumn: cell.x(), adata: nullptr); |
97 | const auto bottomRightIndex = createIndex(arow: cell.y() + span.height() - 1, acolumn: cell.x() + span.width() - 1, adata: nullptr); |
98 | emit dataChanged(topLeft: topLeftIndex, bottomRight: bottomRightIndex); |
99 | } |
100 | |
101 | bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override |
102 | { |
103 | if (row < 0 || count <= 0) |
104 | return false; |
105 | |
106 | beginInsertRows(parent, first: row, last: row + count - 1); |
107 | m_rows += count; |
108 | endInsertRows(); |
109 | return true; |
110 | } |
111 | |
112 | bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override |
113 | { |
114 | if (!checkIndex(index: createIndex(arow: row, acolumn: 0)) || !checkIndex(index: createIndex(arow: row + count - 1, acolumn: 0))) |
115 | return false; |
116 | |
117 | beginRemoveRows(parent, first: row, last: row + count - 1); |
118 | m_rows -= count; |
119 | for (int c = 0; c < m_columns; ++c) { |
120 | for (int r = 0; r < count; ++r) { |
121 | const int serializedIndex = (row + r) + (c * m_rows); |
122 | modelData.remove(key: serializedIndex); |
123 | } |
124 | } |
125 | endRemoveRows(); |
126 | return true; |
127 | } |
128 | |
129 | bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override |
130 | { |
131 | if (column < 0 || count <= 0) |
132 | return false; |
133 | |
134 | beginInsertColumns(parent, first: column, last: column + count - 1); |
135 | m_columns += count; |
136 | endInsertColumns(); |
137 | return true; |
138 | } |
139 | |
140 | bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override |
141 | { |
142 | if (!checkIndex(index: createIndex(arow: 0, acolumn: column)) || !checkIndex(index: createIndex(arow: 0, acolumn: column + count - 1))) |
143 | return false; |
144 | |
145 | beginRemoveColumns(parent, first: column, last: column + count - 1); |
146 | m_columns -= count; |
147 | endRemoveColumns(); |
148 | return true; |
149 | } |
150 | |
151 | bool canFetchMore(const QModelIndex &parent) const override |
152 | { |
153 | Q_UNUSED(parent) |
154 | return m_dataCanBeFetched; |
155 | } |
156 | |
157 | void swapRows(int row1, int row2) |
158 | { |
159 | layoutAboutToBeChanged(); |
160 | Q_ASSERT(modelData.contains(row1)); |
161 | Q_ASSERT(modelData.contains(row2)); |
162 | const QString tmp = modelData[row1]; |
163 | modelData[row1] = modelData[row2]; |
164 | modelData[row2] = tmp; |
165 | layoutChanged(); |
166 | } |
167 | |
168 | void fetchMore(const QModelIndex &parent) override |
169 | { |
170 | Q_UNUSED(parent) |
171 | addRow(row: m_rows - 1); |
172 | } |
173 | |
174 | void clear() { |
175 | beginResetModel(); |
176 | m_rows = 0; |
177 | m_columns = 0; |
178 | modelData.clear(); |
179 | endResetModel(); |
180 | } |
181 | |
182 | Q_INVOKABLE void addRow(int row) |
183 | { |
184 | insertRow(arow: row, aparent: QModelIndex()); |
185 | } |
186 | |
187 | signals: |
188 | void rowCountChanged(); |
189 | void columnCountChanged(); |
190 | |
191 | private: |
192 | int m_rows = 0; |
193 | int m_columns = 0; |
194 | bool m_dataCanBeFetched = false; |
195 | QHash<int, QString> modelData; |
196 | }; |
197 | |
198 | #define TestModelAsVariant(...) QVariant::fromValue(QSharedPointer<TestModel>(new TestModel(__VA_ARGS__))) |
199 | |