diff options
Diffstat (limited to 'src/corelib/itemmodels/qabstractitemmodel.cpp')
-rw-r--r-- | src/corelib/itemmodels/qabstractitemmodel.cpp | 175 |
1 files changed, 168 insertions, 7 deletions
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index f893cf06e3..d826110ec7 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -48,11 +48,14 @@ #include <qstack.h> #include <qbitarray.h> #include <qdatetime.h> +#include <qloggingcategory.h> #include <limits.h> QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcCheckIndex, "qt.core.qabstractitemmodel.checkindex") + QPersistentModelIndexData *QPersistentModelIndexData::create(const QModelIndex &index) { Q_ASSERT(index.isValid()); // we will _never_ insert an invalid index in the list @@ -482,12 +485,12 @@ class QEmptyItemModel : public QAbstractItemModel { public: explicit QEmptyItemModel(QObject *parent = 0) : QAbstractItemModel(parent) {} - QModelIndex index(int, int, const QModelIndex &) const Q_DECL_OVERRIDE { return QModelIndex(); } - QModelIndex parent(const QModelIndex &) const Q_DECL_OVERRIDE { return QModelIndex(); } - int rowCount(const QModelIndex &) const Q_DECL_OVERRIDE { return 0; } - int columnCount(const QModelIndex &) const Q_DECL_OVERRIDE { return 0; } - bool hasChildren(const QModelIndex &) const Q_DECL_OVERRIDE { return false; } - QVariant data(const QModelIndex &, int) const Q_DECL_OVERRIDE { return QVariant(); } + QModelIndex index(int, int, const QModelIndex &) const override { return QModelIndex(); } + QModelIndex parent(const QModelIndex &) const override { return QModelIndex(); } + int rowCount(const QModelIndex &) const override { return 0; } + int columnCount(const QModelIndex &) const override { return 0; } + bool hasChildren(const QModelIndex &) const override { return false; } + QVariant data(const QModelIndex &, int) const override { return QVariant(); } }; Q_GLOBAL_STATIC(QEmptyItemModel, qEmptyModel) @@ -1105,7 +1108,27 @@ void QAbstractItemModel::resetInternalData() Returns the sibling at \a row and \a column. If there is no sibling at this position, an invalid QModelIndex is returned. - \sa parent() + \sa parent(), siblingAtColumn(), siblingAtRow() +*/ + +/*! + \fn QModelIndex QModelIndex::siblingAtColumn(int column) const + + Returns the sibling at \a column for the current row. If there is no sibling + at this position, an invalid QModelIndex is returned. + + \sa sibling(), siblingAtRow() + \since 5.11 +*/ + +/*! + \fn QModelIndex QModelIndex::siblingAtRow(int row) const + + Returns the sibling at \a row for the current column. If there is no sibling + at this position, an invalid QModelIndex is returned. + + \sa sibling(), siblingAtColumn() + \since 5.11 */ /*! @@ -2686,6 +2709,7 @@ bool QAbstractItemModel::decodeData(int row, int column, const QModelIndex &pare void QAbstractItemModel::beginInsertRows(const QModelIndex &parent, int first, int last) { Q_ASSERT(first >= 0); + Q_ASSERT(first <= rowCount(parent)); // == is allowed, to insert at the end Q_ASSERT(last >= first); Q_D(QAbstractItemModel); d->changes.push(QAbstractItemModelPrivate::Change(parent, first, last)); @@ -2741,6 +2765,7 @@ void QAbstractItemModel::beginRemoveRows(const QModelIndex &parent, int first, i { Q_ASSERT(first >= 0); Q_ASSERT(last >= first); + Q_ASSERT(last < rowCount(parent)); Q_D(QAbstractItemModel); d->changes.push(QAbstractItemModelPrivate::Change(parent, first, last)); emit rowsAboutToBeRemoved(parent, first, last, QPrivateSignal()); @@ -2987,6 +3012,7 @@ void QAbstractItemModel::endMoveRows() void QAbstractItemModel::beginInsertColumns(const QModelIndex &parent, int first, int last) { Q_ASSERT(first >= 0); + Q_ASSERT(first <= columnCount(parent)); // == is allowed, to insert at the end Q_ASSERT(last >= first); Q_D(QAbstractItemModel); d->changes.push(QAbstractItemModelPrivate::Change(parent, first, last)); @@ -3043,6 +3069,7 @@ void QAbstractItemModel::beginRemoveColumns(const QModelIndex &parent, int first { Q_ASSERT(first >= 0); Q_ASSERT(last >= first); + Q_ASSERT(last < columnCount(parent)); Q_D(QAbstractItemModel); d->changes.push(QAbstractItemModelPrivate::Change(parent, first, last)); emit columnsAboutToBeRemoved(parent, first, last, QPrivateSignal()); @@ -3316,6 +3343,140 @@ QModelIndexList QAbstractItemModel::persistentIndexList() const return result; } +/*! + \enum QAbstractItemModel::CheckIndexOption + \since 5.11 + + This enum can be used to control the checks performed by + QAbstractItemModel::checkIndex(). + + \value NoOption No check options are specified. + + \value IndexIsValid The model index passed to + QAbstractItemModel::checkIndex() is checked to be a valid model index. + + \value DoNotUseParent Does not perform any check + involving the usage of the parent of the index passed to + QAbstractItemModel::checkIndex(). + + \value ParentIsInvalid The parent of the model index + passed to QAbstractItemModel::checkIndex() is checked to be an invalid + model index. If both this option and DoNotUseParent + are specified, then this option is ignored. +*/ + +/*! + \since 5.11 + + This function checks whether \a index is a legal model index for + this model. A legal model index is either an invalid model index, or a + valid model index for which all the following holds: + + \list + + \li the index' model is \c{this}; + \li the index' row is greater or equal than zero; + \li the index' row is less than the row count for the index' parent; + \li the index' column is greater or equal than zero; + \li the index' column is less than the column count for the index' parent. + + \endlist + + The \a options argument may change some of these checks. If \a options + contains \c{IndexIsValid}, then \a index must be a valid + index; this is useful when reimplementing functions such as \l{data()} or + \l{setData()}, which expect valid indexes. + + If \a options contains \c{DoNotUseParent}, then the + checks that would call \l{parent()} are omitted; this allows calling this + function from a \l{parent()} reimplementation (otherwise, this would result + in endless recursion and a crash). + + If \a options does not contain \c{DoNotUseParent}, and it + contains \c{ParentIsInvalid}, then an additional check is + performed: the parent index is checked for not being valid. This is useful + when implementing flat models such as lists or tables, where no model index + should have a valid parent index. + + This function returns true if all the checks succeeded, and false otherwise. + This allows to use the function in \l{Q_ASSERT} and similar other debugging + mechanisms. If some check failed, a warning message will be printed in the + \c{qt.core.qabstractitemmodel.checkindex} logging category, containing + some information that may be useful for debugging the failure. + + \note This function is a debugging helper for implementing your own item + models. When developing complex models, as well as when building + complicated model hierarchies (e.g. using proxy models), it is useful to + call this function in order to catch bugs relative to illegal model indices + (as defined above) accidentally passed to some QAbstractItemModel API. + + \warning Note that it's undefined behavior to pass illegal indices to item + models, so applications must refrain from doing so, and not rely on any + "defensive" programming that item models could employ to handle illegal + indexes gracefully. + + \sa QModelIndex +*/ +bool QAbstractItemModel::checkIndex(const QModelIndex &index, CheckIndexOptions options) const +{ + if (!index.isValid()) { + if (options & CheckIndexOption::IndexIsValid) { + qCWarning(lcCheckIndex) << "Index" << index << "is not valid (expected valid)"; + return false; + } + return true; + } + + if (index.model() != this) { + qCWarning(lcCheckIndex) << "Index" << index + << "is for model" << index.model() + << "which is different from this model" << this; + return false; + } + + if (index.row() < 0) { + qCWarning(lcCheckIndex) << "Index" << index + << "has negative row" << index.row(); + return false; + } + + if (index.column() < 0) { + qCWarning(lcCheckIndex) << "Index" << index + << "has negative column" << index.column(); + return false; + } + + if (!(options & CheckIndexOption::DoNotUseParent)) { + const QModelIndex parentIndex = index.parent(); + if (options & CheckIndexOption::ParentIsInvalid) { + if (parentIndex.isValid()) { + qCWarning(lcCheckIndex) << "Index" << index + << "has valid parent" << parentIndex + << "(expected an invalid parent)"; + return false; + } + } + + const int rc = rowCount(parentIndex); + if (index.row() >= rc) { + qCWarning(lcCheckIndex) << "Index" << index + << "has out of range row" << index.row() + << "rowCount() is" << rc; + return false; + } + + const int cc = columnCount(parentIndex); + if (index.column() >= cc) { + qCWarning(lcCheckIndex) << "Index" << index + << "has out of range column" << index.column() + << "columnCount() is" << cc; + return false; + + } + } + + return true; +} /*! \class QAbstractTableModel |