diff options
Diffstat (limited to 'tests/auto/qml/qqmlitemmodels/qtestmodel.h')
-rw-r--r-- | tests/auto/qml/qqmlitemmodels/qtestmodel.h | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmlitemmodels/qtestmodel.h b/tests/auto/qml/qqmlitemmodels/qtestmodel.h new file mode 100644 index 0000000000..bb0a169652 --- /dev/null +++ b/tests/auto/qml/qqmlitemmodels/qtestmodel.h @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q_TEST_MODEL_H +#define Q_TEST_MODEL_H + +#include <QtCore/qabstractitemmodel.h> + +class TestModel: public QAbstractItemModel +{ + Q_OBJECT + +public: + TestModel(QObject *parent = 0): QAbstractItemModel(parent), + fetched(false), rows(10), cols(1), levels(INT_MAX), wrongIndex(false) { init(); } + + TestModel(int _rows, int _cols, QObject *parent = 0): QAbstractItemModel(parent), + fetched(false), rows(_rows), cols(_cols), levels(INT_MAX), wrongIndex(false) { init(); } + + void init() { + decorationsEnabled = false; + alternateChildlessRows = true; + tree = new Node(rows); + } + + inline qint32 level(const QModelIndex &index) const { + Node *n = (Node *)index.internalPointer(); + if (!n) + return -1; + int l = -1; + while (n != tree) { + n = n->parent; + ++l; + } + return l; + } + + void resetModel() + { + beginResetModel(); + fetched = false; + delete tree; + tree = new Node(rows); + endResetModel(); + } + + QString displayData(const QModelIndex &idx) const + { + return QString("[%1,%2,%3,%4]").arg(idx.row()).arg(idx.column()).arg(idx.internalId()).arg(hasChildren(idx)); + } + + bool canFetchMore(const QModelIndex &) const { + return !fetched; + } + + void fetchMore(const QModelIndex &) { + fetched = true; + } + + bool hasChildren(const QModelIndex &parent = QModelIndex()) const { + bool hasFetched = fetched; + fetched = true; + bool r = QAbstractItemModel::hasChildren(parent); + fetched = hasFetched; + return r; + } + + int rowCount(const QModelIndex& parent = QModelIndex()) const { + if (!fetched) + qFatal("%s: rowCount should not be called before fetching", Q_FUNC_INFO); + if ((parent.column() > 0) || (level(parent) > levels) + || (alternateChildlessRows && parent.row() > 0 && (parent.row() & 1))) + return 0; + Node *n = (Node*)parent.internalPointer(); + if (!n) + n = tree; + return n->children.count(); + } + + int columnCount(const QModelIndex& parent = QModelIndex()) const { + if ((parent.column() > 0) || (level(parent) > levels) + || (alternateChildlessRows && parent.row() > 0 && (parent.row() & 1))) + return 0; + return cols; + } + + bool isEditable(const QModelIndex &index) const { + if (index.isValid()) + return true; + return false; + } + + Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const + { + if (row < 0 || column < 0 || (level(parent) > levels) || column >= cols) + return QModelIndex(); + Node *pn = (Node*)parent.internalPointer(); + if (!pn) + pn = tree; + if (row >= pn->children.count()) + return QModelIndex(); + + Node *n = pn->children.at(row); + if (!n) { + n = new Node(rows, pn); + pn->children[row] = n; + } + return createIndex(row, column, n); + } + + QModelIndex parent(const QModelIndex &index) const + { + Node *n = (Node *)index.internalPointer(); + if (!n || n->parent == tree) + return QModelIndex(); + Q_ASSERT(n->parent->parent); + int parentRow = n->parent->parent->children.indexOf(n->parent); + Q_ASSERT(parentRow != -1); + return createIndex(parentRow, 0, n->parent); + } + + QVariant data(const QModelIndex &idx, int role) const + { + if (!idx.isValid()) + return QVariant(); + + Node *pn = (Node *)idx.internalPointer(); + if (!pn) + pn = tree; + if (pn != tree) + pn = pn->parent; + if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols + || idx.row() >= pn->children.count()) { + wrongIndex = true; + qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(), + idx.internalPointer()); + return QVariant(); + } + + if (role == Qt::DisplayRole) { + return displayData(idx); + } + + return QVariant(); + } + + bool setData(const QModelIndex &index, const QVariant &value, int role) + { + Q_UNUSED(value); + QVector<int> changedRole(1, role); + emit dataChanged(index, index, changedRole); + return true; + } + + void groupedSetData(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) + { + emit dataChanged(topLeft, bottomRight, roles); + } + + void changeLayout(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>()) + { + emit layoutAboutToBeChanged(parents); + emit layoutChanged(parents); + } + + bool removeRows(int row, int count, const QModelIndex &parent) + { + beginRemoveRows(parent, row, row + count - 1); + Node *n = (Node *)parent.internalPointer(); + if (!n) + n = tree; + n->removeRows(row, count); + endRemoveRows(); + return true; + } + + void removeLastColumn() + { + beginRemoveColumns(QModelIndex(), cols - 1, cols - 1); + --cols; + endRemoveColumns(); + } + + void removeAllColumns() + { + beginRemoveColumns(QModelIndex(), 0, cols - 1); + cols = 0; + endRemoveColumns(); + } + + bool insertRows(int row, int count, const QModelIndex &parent) + { + beginInsertRows(parent, row, row + count - 1); + Node *n = (Node *)parent.internalPointer(); + if (!n) + n = tree; + n->addRows(row, count); + endInsertRows(); + return true; + } + + bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) + { + Q_ASSERT_X(sourceRow >= 0 && sourceRow < rowCount(sourceParent) + && count > 0 && sourceRow + count < rowCount(sourceParent) + && destinationChild >= 0 && destinationChild <= rowCount(destinationParent), + Q_FUNC_INFO, "Rows out of range."); + Q_ASSERT_X(!(sourceParent == destinationParent && destinationChild >= sourceRow && destinationChild < sourceRow + count), + Q_FUNC_INFO, "Moving rows onto themselves."); + if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild)) + return false; + Node *src = (Node *)sourceParent.internalPointer(); + if (!src) + src = tree; + Node *dest = (Node *)destinationParent.internalPointer(); + if (!dest) + dest = tree; + QVector<Node *> buffer = src->children.mid(sourceRow, count); + if (src != dest) { + src->removeRows(sourceRow, count, true /* keep alive */); + dest->addRows(destinationChild, count); + } else { + QVector<Node *> &c = dest->children; + if (sourceRow < destinationChild) { + memmove(&c[sourceRow], &c[sourceRow + count], sizeof(Node *) * (destinationChild - sourceRow - count)); + destinationChild -= count; + } else { + memmove(&c[destinationChild + count], &c[destinationChild], sizeof(Node *) * (sourceRow - destinationChild)); + } + } + for (int i = 0; i < count; i++) { + Node *n = buffer[i]; + n->parent = dest; + dest->children[i + destinationChild] = n; + } + + endMoveRows(); + return true; + } + + void setDecorationsEnabled(bool enable) + { + decorationsEnabled = enable; + } + + mutable bool fetched; + bool decorationsEnabled; + bool alternateChildlessRows; + int rows, cols; + int levels; + mutable bool wrongIndex; + + struct Node { + Node *parent; + QVector<Node *> children; + + Node(int rows, Node *p = 0) : parent(p) + { + addRows(0, rows); + } + + ~Node() + { + foreach (Node *n, children) + delete n; + } + + void addRows(int row, int count) + { + if (count > 0) { + children.reserve(children.count() + count); + children.insert(row, count, (Node *)0); + } + } + + void removeRows(int row, int count, bool keepAlive = false) + { + int newCount = qMax(children.count() - count, 0); + int effectiveCountDiff = children.count() - newCount; + if (effectiveCountDiff > 0) { + if (!keepAlive) + for (int i = 0; i < effectiveCountDiff; i++) + delete children[i + row]; + children.remove(row, effectiveCountDiff); + } + } + }; + + Node *tree; +}; + +#endif // Q_TEST_MODEL_H |