summaryrefslogtreecommitdiffstats
path: root/src/corelib/itemmodels
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/itemmodels')
-rw-r--r--src/corelib/itemmodels/itemmodels.pri63
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.cpp831
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.h308
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel_p.h111
-rw-r--r--src/corelib/itemmodels/qabstractproxymodel.cpp230
-rw-r--r--src/corelib/itemmodels/qabstractproxymodel.h57
-rw-r--r--src/corelib/itemmodels/qabstractproxymodel_p.h80
-rw-r--r--src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp247
-rw-r--r--src/corelib/itemmodels/qconcatenatetablesproxymodel.h55
-rw-r--r--src/corelib/itemmodels/qidentityproxymodel.cpp339
-rw-r--r--src/corelib/itemmodels/qidentityproxymodel.h65
-rw-r--r--src/corelib/itemmodels/qidentityproxymodel_p.h72
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel.cpp571
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel.h151
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel_p.h86
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.cpp1337
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.h130
-rw-r--r--src/corelib/itemmodels/qstringlistmodel.cpp63
-rw-r--r--src/corelib/itemmodels/qstringlistmodel.h42
-rw-r--r--src/corelib/itemmodels/qtransposeproxymodel.cpp94
-rw-r--r--src/corelib/itemmodels/qtransposeproxymodel.h40
-rw-r--r--src/corelib/itemmodels/qtransposeproxymodel_p.h46
22 files changed, 2549 insertions, 2469 deletions
diff --git a/src/corelib/itemmodels/itemmodels.pri b/src/corelib/itemmodels/itemmodels.pri
deleted file mode 100644
index ebeac6e211..0000000000
--- a/src/corelib/itemmodels/itemmodels.pri
+++ /dev/null
@@ -1,63 +0,0 @@
-# Qt itemmodels core module
-
-!qtConfig(itemmodel): return()
-
-HEADERS += \
- itemmodels/qabstractitemmodel.h \
- itemmodels/qabstractitemmodel_p.h \
- itemmodels/qitemselectionmodel.h \
- itemmodels/qitemselectionmodel_p.h
-
-SOURCES += \
- itemmodels/qabstractitemmodel.cpp \
- itemmodels/qitemselectionmodel.cpp
-
-qtConfig(proxymodel) {
- HEADERS += \
- itemmodels/qabstractproxymodel.h \
- itemmodels/qabstractproxymodel_p.h
-
- SOURCES += \
- itemmodels/qabstractproxymodel.cpp
-
- qtConfig(concatenatetablesproxymodel) {
- HEADERS += \
- itemmodels/qconcatenatetablesproxymodel.h
-
- SOURCES += \
- itemmodels/qconcatenatetablesproxymodel.cpp
- }
-
- qtConfig(identityproxymodel) {
- HEADERS += \
- itemmodels/qidentityproxymodel.h
-
- SOURCES += \
- itemmodels/qidentityproxymodel.cpp
- }
-
- qtConfig(sortfilterproxymodel) {
- HEADERS += \
- itemmodels/qsortfilterproxymodel.h
-
- SOURCES += \
- itemmodels/qsortfilterproxymodel.cpp
- }
-
- qtConfig(transposeproxymodel) {
- HEADERS += \
- itemmodels/qtransposeproxymodel.h \
- itemmodels/qtransposeproxymodel_p.h
-
- SOURCES += \
- itemmodels/qtransposeproxymodel.cpp
- }
-}
-
-qtConfig(stringlistmodel) {
- HEADERS += \
- itemmodels/qstringlistmodel.h
-
- SOURCES += \
- itemmodels/qstringlistmodel.cpp
-}
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp
index 46ac703615..cd29f2fcc2 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.cpp
+++ b/src/corelib/itemmodels/qabstractitemmodel.cpp
@@ -1,41 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qabstractitemmodel.h"
#include <private/qabstractitemmodel_p.h>
@@ -44,26 +9,32 @@
#include <qsize.h>
#include <qmimedata.h>
#include <qdebug.h>
-#include <qvector.h>
-#include <qregexp.h>
-#include <qregularexpression.h>
+#include <qlist.h>
+#if QT_CONFIG(regularexpression)
+# include <qregularexpression.h>
+#endif
#include <qstack.h>
+#include <qmap.h>
#include <qbitarray.h>
#include <qdatetime.h>
#include <qloggingcategory.h>
+#include <functional>
+
#include <limits.h>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcCheckIndex, "qt.core.qabstractitemmodel.checkindex")
+QT_IMPL_METATYPE_EXTERN(QModelIndexList)
+
QPersistentModelIndexData *QPersistentModelIndexData::create(const QModelIndex &index)
{
Q_ASSERT(index.isValid()); // we will _never_ insert an invalid index in the list
QPersistentModelIndexData *d = nullptr;
QAbstractItemModel *model = const_cast<QAbstractItemModel *>(index.model());
- QHash<QModelIndex, QPersistentModelIndexData *> &indexes = model->d_func()->persistent.indexes;
+ QMultiHash<QModelIndex, QPersistentModelIndexData *> &indexes = model->d_func()->persistent.indexes;
const auto it = indexes.constFind(index);
if (it != indexes.cend()) {
d = (*it);
@@ -90,6 +61,226 @@ void QPersistentModelIndexData::destroy(QPersistentModelIndexData *data)
}
/*!
+ \class QModelRoleData
+ \inmodule QtCore
+ \since 6.0
+ \ingroup model-view
+ \brief The QModelRoleData class holds a role and the data associated to that role.
+
+ QModelRoleData objects store an item role (which is a value from the
+ Qt::ItemDataRole enumeration, or an arbitrary integer for a custom role)
+ as well as the data associated with that role.
+
+ A QModelRoleData object is typically created by views or delegates,
+ setting which role they want to fetch the data for. The object
+ is then passed to models (see QAbstractItemModel::multiData()),
+ which populate the data corresponding to the role stored. Finally,
+ the view visualizes the data retrieved from the model.
+
+ \sa {Model/View Programming}, QModelRoleDataSpan
+*/
+
+/*!
+ \fn QModelRoleData::QModelRoleData(int role) noexcept
+
+ Constructs a QModelRoleData object for the given \a role.
+
+ \sa Qt::ItemDataRole
+*/
+
+/*!
+ \fn int QModelRoleData::role() const noexcept
+
+ Returns the role held by this object.
+
+ \sa Qt::ItemDataRole
+*/
+
+/*!
+ \fn const QVariant &QModelRoleData::data() const noexcept
+
+ Returns the data held by this object.
+
+ \sa setData()
+*/
+
+/*!
+ \fn QVariant &QModelRoleData::data() noexcept
+
+ Returns the data held by this object as a modifiable reference.
+
+ \sa setData()
+*/
+
+/*!
+ \fn template <typename T> void QModelRoleData::setData(T &&value)
+
+ Sets the data held by this object to \a value.
+ \a value must be of a datatype which can be stored in a QVariant.
+
+ \sa data(), clearData(), Q_DECLARE_METATYPE
+*/
+
+/*!
+ \fn void QModelRoleData::clearData() noexcept
+
+ Clears the data held by this object. Note that the role is
+ unchanged; only the data is cleared.
+
+ \sa data()
+*/
+
+/*!
+ \class QModelRoleDataSpan
+ \inmodule QtCore
+ \since 6.0
+ \ingroup model-view
+ \brief The QModelRoleDataSpan class provides a span over QModelRoleData objects.
+
+ A QModelRoleDataSpan is used as an abstraction over an array of
+ QModelRoleData objects.
+
+ Like a view, QModelRoleDataSpan provides a small object (pointer
+ and size) that can be passed to functions that need to examine the
+ contents of the array. A QModelRoleDataSpan can be constructed from
+ any array-like sequence (plain arrays, QVector, std::vector,
+ QVarLengthArray, and so on). Moreover, it does not own the
+ sequence, which must therefore be kept alive longer than any
+ QModelRoleDataSpan objects referencing it.
+
+ Unlike a view, QModelRoleDataSpan is a span, so it allows for
+ modifications to the underlying elements.
+
+ QModelRoleDataSpan's main use case is making it possible
+ for a model to return the data corresponding to different roles
+ in one call.
+
+ In order to draw one element from a model, a view (through its
+ delegates) will generally request multiple roles for the same index
+ by calling \c{data()} as many times as needed:
+
+ \snippet code/src_corelib_kernel_qabstractitemmodel.cpp 13
+
+ QModelRoleDataSpan allows a view to request the same data
+ using just one function call.
+
+ This is achieved by having the view prepare a suitable array of
+ QModelRoleData objects, each initialized with the role that should
+ be fetched. The array is then wrapped in a QModelRoleDataSpan
+ object, which is then passed to a model's \c{multiData()} function.
+
+ \snippet code/src_corelib_kernel_qabstractitemmodel.cpp 14
+
+ Views are encouraged to store the array of QModelRoleData objects
+ (and, possibly, the corresponding span) and re-use it in subsequent
+ calls to the model. This allows to reduce the memory allocations
+ related with creating and returning QVariant objects.
+
+ Finally, given a QModelRoleDataSpan object, the model's
+ responsibility is to fill in the data corresponding to each role in
+ the span. How this is done depends on the concrete model class.
+ Here's a sketch of a possible implementation that iterates over the
+ span and uses \c{setData()} on each element:
+
+ \snippet code/src_corelib_kernel_qabstractitemmodel.cpp 15
+
+ \sa {Model/View Programming}, QAbstractItemModel::multiData()
+*/
+
+/*!
+ \fn QModelRoleDataSpan::QModelRoleDataSpan() noexcept
+
+ Constructs an empty QModelRoleDataSpan. Its data() will be set to
+ \nullptr, and its length to zero.
+*/
+
+/*!
+ \fn QModelRoleDataSpan::QModelRoleDataSpan(QModelRoleData &modelRoleData) noexcept
+
+ Constructs an QModelRoleDataSpan spanning over \a modelRoleData,
+ seen as a 1-element array.
+*/
+
+/*!
+ \fn QModelRoleDataSpan::QModelRoleDataSpan(QModelRoleData *modelRoleData, qsizetype len)
+
+ Constructs an QModelRoleDataSpan spanning over the array beginning
+ at \a modelRoleData and with length \a len.
+
+ \note The array must be kept alive as long as this object has not
+ been destructed.
+*/
+
+/*!
+ \fn template <typename Container, QModelRoleDataSpan::if_compatible_container<Container> = true> QModelRoleDataSpan::QModelRoleDataSpan(Container &c) noexcept
+
+ Constructs an QModelRoleDataSpan spanning over the container \a c,
+ which can be any contiguous container of QModelRoleData objects.
+ For instance, it can be a \c{QVector<QModelRoleData>},
+ a \c{std::array<QModelRoleData, 10>} and so on.
+
+ \note The container must be kept alive as long as this object has not
+ been destructed.
+*/
+
+/*!
+ \fn qsizetype QModelRoleDataSpan::size() const noexcept
+
+ Returns the length of the span represented by this object.
+*/
+
+/*!
+ \fn qsizetype QModelRoleDataSpan::length() const noexcept
+
+ Returns the length of the span represented by this object.
+*/
+
+/*!
+ \fn QModelRoleData *QModelRoleDataSpan::data() const noexcept
+
+ Returns a pointer to the beginning of the span represented by this
+ object.
+*/
+
+/*!
+ \fn QModelRoleData *QModelRoleDataSpan::begin() const noexcept
+
+ Returns a pointer to the beginning of the span represented by this
+ object.
+*/
+
+/*!
+ \fn QModelRoleData *QModelRoleDataSpan::end() const noexcept
+
+ Returns a pointer to the imaginary element one past the end of the
+ span represented by this object.
+*/
+
+/*!
+ \fn QModelRoleData &QModelRoleDataSpan::operator[](qsizetype index) const
+
+ Returns a modifiable reference to the QModelRoleData at position
+ \a index in the span.
+
+ \note \a index must be a valid index for this span (0 <= \a index < size()).
+*/
+
+/*!
+ \fn const QVariant *QModelRoleDataSpan::dataForRole(int role) const
+
+ Returns the data associated with the first QModelRoleData in the
+ span that has its role equal to \a role. If such a QModelRoleData
+ object does not exist, the behavior is undefined.
+
+ \note Avoid calling this function from the model's side, as a
+ model cannot possibly know in advance which roles are in a given
+ QModelRoleDataSpan. This function is instead suitable for views and
+ delegates, which have control over the roles in the span.
+
+ \sa QModelRoleData::data()
+*/
+
+/*!
\class QPersistentModelIndex
\inmodule QtCore
\ingroup shared
@@ -108,6 +299,9 @@ void QPersistentModelIndexData::destroy(QPersistentModelIndexData *data)
It is good practice to check that persistent model indexes are valid
before using them.
+ \note You cannot store a QStandardItemModel's QPersistentModelIndex
+ in one of the model's items.
+
\sa {Model/View Programming}, QModelIndex, QAbstractItemModel
*/
@@ -188,7 +382,7 @@ QPersistentModelIndex::~QPersistentModelIndex()
model index are used when comparing with another persistent model index.
*/
-bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const
+bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const noexcept
{
if (d && other.d)
return d->index == other.d->index;
@@ -205,12 +399,12 @@ bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const
model index are used when comparing with another persistent model index.
*/
-bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const
+bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const noexcept
{
if (d && other.d)
return d->index < other.d->index;
- return d < other.d;
+ return std::less<>{}(d, other.d);
}
/*!
@@ -263,17 +457,16 @@ QPersistentModelIndex &QPersistentModelIndex::operator=(const QModelIndex &other
}
/*!
- \fn QPersistentModelIndex::operator const QModelIndex&() const
+ \fn QPersistentModelIndex::operator QModelIndex() const
- Cast operator that returns a const QModelIndex&.
+ Cast operator that returns a QModelIndex.
*/
-QPersistentModelIndex::operator const QModelIndex&() const
+QPersistentModelIndex::operator QModelIndex() const
{
- static const QModelIndex invalid;
if (d)
return d->index;
- return invalid;
+ return QModelIndex();
}
/*!
@@ -284,7 +477,7 @@ QPersistentModelIndex::operator const QModelIndex&() const
model index are used when comparing with another model index.
*/
-bool QPersistentModelIndex::operator==(const QModelIndex &other) const
+bool QPersistentModelIndex::operator==(const QModelIndex &other) const noexcept
{
if (d)
return d->index == other;
@@ -298,7 +491,7 @@ bool QPersistentModelIndex::operator==(const QModelIndex &other) const
location as the \a other model index; otherwise returns \c{false}.
*/
-bool QPersistentModelIndex::operator!=(const QModelIndex &other) const
+bool QPersistentModelIndex::operator!=(const QModelIndex &other) const noexcept
{
if (d)
return d->index != other;
@@ -348,6 +541,22 @@ void *QPersistentModelIndex::internalPointer() const
}
/*!
+ \fn const void *QPersistentModelIndex::constInternalPointer() const
+ \since 6.0
+ \internal
+
+ Returns a \c{const void} \c{*} pointer used by the model to
+ associate the index with the internal data structure.
+*/
+
+const void *QPersistentModelIndex::constInternalPointer() const
+{
+ if (d)
+ return d->index.constInternalPointer();
+ return nullptr;
+}
+
+/*!
\fn quintptr QPersistentModelIndex::internalId() const
\internal
@@ -390,37 +599,31 @@ QModelIndex QPersistentModelIndex::sibling(int row, int column) const
return QModelIndex();
}
-#if QT_DEPRECATED_SINCE(5, 8)
/*!
- \obsolete
-
- Use QAbstractItemModel::index() instead.
-
- Returns the child of the model index that is stored in the given \a row
- and \a column.
+ Returns the data for the given \a role for the item referred to by the
+ index.
- \sa parent(), sibling()
+ \sa Qt::ItemDataRole, QAbstractItemModel::setData()
*/
-
-QModelIndex QPersistentModelIndex::child(int row, int column) const
+QVariant QPersistentModelIndex::data(int role) const
{
if (d)
- return d->index.model()->index(row, column, d->index);
- return QModelIndex();
+ return d->index.data(role);
+ return QVariant();
}
-#endif
+
/*!
- Returns the data for the given \a role for the item referred to by the
+ Populates the given \a roleDataSpan for the item referred to by the
index.
+ \since 6.0
\sa Qt::ItemDataRole, QAbstractItemModel::setData()
*/
-QVariant QPersistentModelIndex::data(int role) const
+void QPersistentModelIndex::multiData(QModelRoleDataSpan roleDataSpan) const
{
if (d)
- return d->index.data(role);
- return QVariant();
+ d->index.multiData(roleDataSpan);
}
/*!
@@ -483,6 +686,7 @@ QDebug operator<<(QDebug dbg, const QPersistentModelIndex &idx)
class QEmptyItemModel : public QAbstractItemModel
{
+ Q_OBJECT
public:
explicit QEmptyItemModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {}
QModelIndex index(int, int, const QModelIndex &) const override { return QModelIndex(); }
@@ -497,9 +701,7 @@ Q_GLOBAL_STATIC(QEmptyItemModel, qEmptyModel)
QAbstractItemModelPrivate::QAbstractItemModelPrivate()
- : QObjectPrivate(),
- supportedDragActions(-1),
- roleNames(defaultRoleNames())
+ : QObjectPrivate()
{
}
@@ -514,7 +716,7 @@ QAbstractItemModel *QAbstractItemModelPrivate::staticEmptyModel()
void QAbstractItemModelPrivate::invalidatePersistentIndexes()
{
- for (QPersistentModelIndexData *data : qAsConst(persistent.indexes))
+ for (QPersistentModelIndexData *data : std::as_const(persistent.indexes))
data->index = QModelIndex();
persistent.indexes.clear();
}
@@ -534,7 +736,7 @@ void QAbstractItemModelPrivate::invalidatePersistentIndex(const QModelIndex &ind
}
using DefaultRoleNames = QHash<int, QByteArray>;
-Q_GLOBAL_STATIC_WITH_ARGS(DefaultRoleNames, qDefaultRoleNames, (
+Q_GLOBAL_STATIC(DefaultRoleNames, qDefaultRoleNames,
{
{ Qt::DisplayRole, "display" },
{ Qt::DecorationRole, "decoration" },
@@ -542,7 +744,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(DefaultRoleNames, qDefaultRoleNames, (
{ Qt::ToolTipRole, "toolTip" },
{ Qt::StatusTipRole, "statusTip" },
{ Qt::WhatsThisRole, "whatsThis" },
- }))
+ })
const QHash<int,QByteArray> &QAbstractItemModelPrivate::defaultRoleNames()
{
@@ -552,32 +754,32 @@ const QHash<int,QByteArray> &QAbstractItemModelPrivate::defaultRoleNames()
bool QAbstractItemModelPrivate::isVariantLessThan(const QVariant &left, const QVariant &right,
Qt::CaseSensitivity cs, bool isLocaleAware)
{
- if (left.userType() == QVariant::Invalid)
+ if (left.userType() == QMetaType::UnknownType)
return false;
- if (right.userType() == QVariant::Invalid)
+ if (right.userType() == QMetaType::UnknownType)
return true;
switch (left.userType()) {
- case QVariant::Int:
+ case QMetaType::Int:
return left.toInt() < right.toInt();
- case QVariant::UInt:
+ case QMetaType::UInt:
return left.toUInt() < right.toUInt();
- case QVariant::LongLong:
+ case QMetaType::LongLong:
return left.toLongLong() < right.toLongLong();
- case QVariant::ULongLong:
+ case QMetaType::ULongLong:
return left.toULongLong() < right.toULongLong();
case QMetaType::Float:
return left.toFloat() < right.toFloat();
- case QVariant::Double:
+ case QMetaType::Double:
return left.toDouble() < right.toDouble();
- case QVariant::Char:
+ case QMetaType::QChar:
return left.toChar() < right.toChar();
- case QVariant::Date:
+ case QMetaType::QDate:
return left.toDate() < right.toDate();
- case QVariant::Time:
+ case QMetaType::QTime:
return left.toTime() < right.toTime();
- case QVariant::DateTime:
+ case QMetaType::QDateTime:
return left.toDateTime() < right.toDateTime();
- case QVariant::String:
+ case QMetaType::QString:
default:
if (isLocaleAware)
return left.toString().localeAwareCompare(right.toString()) < 0;
@@ -591,19 +793,19 @@ static uint typeOfVariant(const QVariant &value)
{
//return 0 for integer, 1 for floating point and 2 for other
switch (value.userType()) {
- case QVariant::Bool:
- case QVariant::Int:
- case QVariant::UInt:
- case QVariant::LongLong:
- case QVariant::ULongLong:
- case QVariant::Char:
+ case QMetaType::Bool:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ case QMetaType::QChar:
case QMetaType::Short:
case QMetaType::UShort:
case QMetaType::UChar:
case QMetaType::ULong:
case QMetaType::Long:
return 0;
- case QVariant::Double:
+ case QMetaType::Double:
case QMetaType::Float:
return 1;
default:
@@ -641,13 +843,13 @@ void QAbstractItemModelPrivate::removePersistentIndexData(QPersistentModelIndexD
Q_UNUSED(removed);
}
// make sure our optimization still works
- for (int i = persistent.moved.count() - 1; i >= 0; --i) {
+ for (int i = persistent.moved.size() - 1; i >= 0; --i) {
int idx = persistent.moved.at(i).indexOf(data);
if (idx >= 0)
persistent.moved[i].remove(idx);
}
// update the references to invalidated persistent indexes
- for (int i = persistent.invalidated.count() - 1; i >= 0; --i) {
+ for (int i = persistent.invalidated.size() - 1; i >= 0; --i) {
int idx = persistent.invalidated.at(i).indexOf(data);
if (idx >= 0)
persistent.invalidated[i].remove(idx);
@@ -660,11 +862,9 @@ void QAbstractItemModelPrivate::rowsAboutToBeInserted(const QModelIndex &parent,
{
Q_Q(QAbstractItemModel);
Q_UNUSED(last);
- QVector<QPersistentModelIndexData *> persistent_moved;
+ QList<QPersistentModelIndexData *> persistent_moved;
if (first < q->rowCount(parent)) {
- for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = persistent.indexes.constBegin();
- it != persistent.indexes.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
+ for (auto *data : std::as_const(persistent.indexes)) {
const QModelIndex &index = data->index;
if (index.row() >= first && index.isValid() && index.parent() == parent) {
persistent_moved.append(data);
@@ -677,11 +877,9 @@ void QAbstractItemModelPrivate::rowsAboutToBeInserted(const QModelIndex &parent,
void QAbstractItemModelPrivate::rowsInserted(const QModelIndex &parent,
int first, int last)
{
- QVector<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop();
- int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested
- for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_moved.constBegin();
- it != persistent_moved.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
+ const QList<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop();
+ const int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested
+ for (auto *data : persistent_moved) {
QModelIndex old = data->index;
persistent.indexes.erase(persistent.indexes.constFind(old));
data->index = q_func()->index(old.row() + count, old.column(), parent);
@@ -695,19 +893,14 @@ void QAbstractItemModelPrivate::rowsInserted(const QModelIndex &parent,
void QAbstractItemModelPrivate::itemsAboutToBeMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation)
{
- QVector<QPersistentModelIndexData *> persistent_moved_explicitly;
- QVector<QPersistentModelIndexData *> persistent_moved_in_source;
- QVector<QPersistentModelIndexData *> persistent_moved_in_destination;
-
- QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it;
- const QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator begin = persistent.indexes.constBegin();
- const QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator end = persistent.indexes.constEnd();
+ QList<QPersistentModelIndexData *> persistent_moved_explicitly;
+ QList<QPersistentModelIndexData *> persistent_moved_in_source;
+ QList<QPersistentModelIndexData *> persistent_moved_in_destination;
const bool sameParent = (srcParent == destinationParent);
const bool movingUp = (srcFirst > destinationChild);
- for ( it = begin; it != end; ++it) {
- QPersistentModelIndexData *data = *it;
+ for (auto *data : std::as_const(persistent.indexes)) {
const QModelIndex &index = data->index;
const QModelIndex &parent = index.parent();
const bool isSourceIndex = (parent == srcParent);
@@ -758,16 +951,10 @@ void QAbstractItemModelPrivate::itemsAboutToBeMoved(const QModelIndex &srcParent
column value depending on the value of \a orientation. The indexes may also be moved to a different parent if \a parent
differs from the existing parent for the index.
*/
-void QAbstractItemModelPrivate::movePersistentIndexes(const QVector<QPersistentModelIndexData *> &indexes, int change, const QModelIndex &parent, Qt::Orientation orientation)
+void QAbstractItemModelPrivate::movePersistentIndexes(const QList<QPersistentModelIndexData *> &indexes, int change,
+ const QModelIndex &parent, Qt::Orientation orientation)
{
- QVector<QPersistentModelIndexData *>::const_iterator it;
- const QVector<QPersistentModelIndexData *>::const_iterator begin = indexes.constBegin();
- const QVector<QPersistentModelIndexData *>::const_iterator end = indexes.constEnd();
-
- for (it = begin; it != end; ++it)
- {
- QPersistentModelIndexData *data = *it;
-
+ for (auto *data : indexes) {
int row = data->index.row();
int column = data->index.column();
@@ -788,9 +975,9 @@ void QAbstractItemModelPrivate::movePersistentIndexes(const QVector<QPersistentM
void QAbstractItemModelPrivate::itemsMoved(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation)
{
- QVector<QPersistentModelIndexData *> moved_in_destination = persistent.moved.pop();
- QVector<QPersistentModelIndexData *> moved_in_source = persistent.moved.pop();
- QVector<QPersistentModelIndexData *> moved_explicitly = persistent.moved.pop();
+ const QList<QPersistentModelIndexData *> moved_in_destination = persistent.moved.pop();
+ const QList<QPersistentModelIndexData *> moved_in_source = persistent.moved.pop();
+ const QList<QPersistentModelIndexData *> moved_explicitly = persistent.moved.pop();
const bool sameParent = (sourceParent == destinationParent);
const bool movingUp = (sourceFirst > destinationChild);
@@ -807,13 +994,11 @@ void QAbstractItemModelPrivate::itemsMoved(const QModelIndex &sourceParent, int
void QAbstractItemModelPrivate::rowsAboutToBeRemoved(const QModelIndex &parent,
int first, int last)
{
- QVector<QPersistentModelIndexData *> persistent_moved;
- QVector<QPersistentModelIndexData *> persistent_invalidated;
+ QList<QPersistentModelIndexData *> persistent_moved;
+ QList<QPersistentModelIndexData *> persistent_invalidated;
// find the persistent indexes that are affected by the change, either by being in the removed subtree
// or by being on the same level and below the removed rows
- for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = persistent.indexes.constBegin();
- it != persistent.indexes.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
+ for (auto *data : std::as_const(persistent.indexes)) {
bool level_changed = false;
QModelIndex current = data->index;
while (current.isValid()) {
@@ -837,11 +1022,9 @@ void QAbstractItemModelPrivate::rowsAboutToBeRemoved(const QModelIndex &parent,
void QAbstractItemModelPrivate::rowsRemoved(const QModelIndex &parent,
int first, int last)
{
- QVector<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop();
- int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested
- for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_moved.constBegin();
- it != persistent_moved.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
+ const QList<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop();
+ const int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested
+ for (auto *data : persistent_moved) {
QModelIndex old = data->index;
persistent.indexes.erase(persistent.indexes.constFind(old));
data->index = q_func()->index(old.row() - count, old.column(), parent);
@@ -851,11 +1034,11 @@ void QAbstractItemModelPrivate::rowsRemoved(const QModelIndex &parent,
qWarning() << "QAbstractItemModel::endRemoveRows: Invalid index (" << old.row() - count << ',' << old.column() << ") in model" << q_func();
}
}
- QVector<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop();
- for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_invalidated.constBegin();
- it != persistent_invalidated.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
- persistent.indexes.erase(persistent.indexes.constFind(data->index));
+ const QList<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop();
+ for (auto *data : persistent_invalidated) {
+ auto pit = persistent.indexes.constFind(data->index);
+ if (pit != persistent.indexes.cend())
+ persistent.indexes.erase(pit);
data->index = QModelIndex();
}
}
@@ -865,11 +1048,9 @@ void QAbstractItemModelPrivate::columnsAboutToBeInserted(const QModelIndex &pare
{
Q_Q(QAbstractItemModel);
Q_UNUSED(last);
- QVector<QPersistentModelIndexData *> persistent_moved;
+ QList<QPersistentModelIndexData *> persistent_moved;
if (first < q->columnCount(parent)) {
- for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = persistent.indexes.constBegin();
- it != persistent.indexes.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
+ for (auto *data : std::as_const(persistent.indexes)) {
const QModelIndex &index = data->index;
if (index.column() >= first && index.isValid() && index.parent() == parent)
persistent_moved.append(data);
@@ -881,11 +1062,9 @@ void QAbstractItemModelPrivate::columnsAboutToBeInserted(const QModelIndex &pare
void QAbstractItemModelPrivate::columnsInserted(const QModelIndex &parent,
int first, int last)
{
- QVector<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop();
- int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested
- for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_moved.constBegin();
- it != persistent_moved.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
+ const QList<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop();
+ const int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested
+ for (auto *data : persistent_moved) {
QModelIndex old = data->index;
persistent.indexes.erase(persistent.indexes.constFind(old));
data->index = q_func()->index(old.row(), old.column() + count, parent);
@@ -894,19 +1073,17 @@ void QAbstractItemModelPrivate::columnsInserted(const QModelIndex &parent,
} else {
qWarning() << "QAbstractItemModel::endInsertColumns: Invalid index (" << old.row() << ',' << old.column() + count << ") in model" << q_func();
}
- }
+ }
}
void QAbstractItemModelPrivate::columnsAboutToBeRemoved(const QModelIndex &parent,
int first, int last)
{
- QVector<QPersistentModelIndexData *> persistent_moved;
- QVector<QPersistentModelIndexData *> persistent_invalidated;
+ QList<QPersistentModelIndexData *> persistent_moved;
+ QList<QPersistentModelIndexData *> persistent_invalidated;
// find the persistent indexes that are affected by the change, either by being in the removed subtree
// or by being on the same level and to the right of the removed columns
- for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = persistent.indexes.constBegin();
- it != persistent.indexes.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
+ for (auto *data : std::as_const(persistent.indexes)) {
bool level_changed = false;
QModelIndex current = data->index;
while (current.isValid()) {
@@ -931,11 +1108,9 @@ void QAbstractItemModelPrivate::columnsAboutToBeRemoved(const QModelIndex &paren
void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
int first, int last)
{
- QVector<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop();
- int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested
- for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_moved.constBegin();
- it != persistent_moved.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
+ const QList<QPersistentModelIndexData *> persistent_moved = persistent.moved.pop();
+ const int count = (last - first) + 1; // it is important to only use the delta, because the change could be nested
+ for (auto *data : persistent_moved) {
QModelIndex old = data->index;
persistent.indexes.erase(persistent.indexes.constFind(old));
data->index = q_func()->index(old.row(), old.column() - count, parent);
@@ -945,11 +1120,11 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
qWarning() << "QAbstractItemModel::endRemoveColumns: Invalid index (" << old.row() << ',' << old.column() - count << ") in model" << q_func();
}
}
- QVector<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop();
- for (QVector<QPersistentModelIndexData *>::const_iterator it = persistent_invalidated.constBegin();
- it != persistent_invalidated.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
- persistent.indexes.erase(persistent.indexes.constFind(data->index));
+ const QList<QPersistentModelIndexData *> persistent_invalidated = persistent.invalidated.pop();
+ for (auto *data : persistent_invalidated) {
+ auto index = persistent.indexes.constFind(data->index);
+ if (index != persistent.indexes.constEnd())
+ persistent.indexes.erase(index);
data->index = QModelIndex();
}
}
@@ -1062,6 +1237,15 @@ void QAbstractItemModel::resetInternalData()
*/
/*!
+ \fn const void *QModelIndex::constInternalPointer() const
+
+ Returns a \c{const void} \c{*} pointer used by the model to associate
+ the index with the internal data structure.
+
+ \sa QAbstractItemModel::createIndex()
+*/
+
+/*!
\fn quintptr QModelIndex::internalId() const
Returns a \c{quintptr} used by the model to associate
@@ -1122,25 +1306,17 @@ void QAbstractItemModel::resetInternalData()
*/
/*!
- \fn QModelIndex QModelIndex::child(int row, int column) const
-
- \obsolete
-
- Use QAbstractItemModel::index() instead.
-
- Returns the child of the model index that is stored in the given \a row and
- \a column.
-
- \note This function does not work for an invalid model index which is often
- used as the root index.
+ \fn QVariant QModelIndex::data(int role) const
- \sa parent(), sibling()
+ Returns the data for the given \a role for the item referred to by the
+ index.
*/
/*!
- \fn QVariant QModelIndex::data(int role) const
+ \fn void QModelIndex::multiData(QModelRoleDataSpan roleDataSpan) const
+ \since 6.0
- Returns the data for the given \a role for the item referred to by the
+ Populates the given \a roleDataSpan for the item referred to by the
index.
*/
@@ -1324,10 +1500,12 @@ void QAbstractItemModel::resetInternalData()
rows to the model, \l{QAbstractItemModel::}{beginInsertRows()} and
\l{QAbstractItemModel::}{endInsertRows()} must be called.
+ \include models.qdocinc {thread-safety-section1}{QAbstractItemModel}
+
\sa {Model Classes}, {Model Subclassing Reference}, QModelIndex,
QAbstractItemView, {Using drag and drop with item views},
- {Simple DOM Model Example}, {Simple Tree Model Example},
- {Editable Tree Model Example}, {Fetch More Example}
+ {Simple Tree Model Example}, {Editable Tree Model Example},
+ {Fetch More Example}
*/
/*!
@@ -1566,7 +1744,13 @@ QAbstractItemModel::~QAbstractItemModel()
For example:
- \snippet ../widgets/itemviews/simpledommodel/dommodel.cpp 2
+ \code
+ int MyModel::columnCount(const QModelIndex &parent) const
+ {
+ Q_UNUSED(parent);
+ return 3;
+ }
+ \endcode
\note When implementing a table based model, columnCount() should return 0
when the parent is valid.
@@ -1575,7 +1759,7 @@ QAbstractItemModel::~QAbstractItemModel()
*/
/*!
- \fn void QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>())
+ \fn void QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles = QList<int>())
This signal is emitted whenever the data in an existing item changes.
@@ -1651,13 +1835,13 @@ QAbstractItemModel::~QAbstractItemModel()
*/
/*!
- \fn void QAbstractItemModel::rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
+ \fn void QAbstractItemModel::rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
\since 4.6
This signal is emitted after rows have been moved within the
- model. The items between \a start and \a end
- inclusive, under the given \a parent item have been moved to \a destination
- starting at the row \a row.
+ model. The items between \a sourceStart and \a sourceEnd
+ inclusive, under the given \a sourceParent item have been moved to \a destinationParent
+ starting at the row \a destinationRow.
\b{Note:} Components connected to this signal use it to adapt to changes
in the model's dimensions. It can only be emitted by the QAbstractItemModel
@@ -1683,13 +1867,13 @@ QAbstractItemModel::~QAbstractItemModel()
*/
/*!
- \fn void QAbstractItemModel::columnsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column)
+ \fn void QAbstractItemModel::columnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn)
\since 4.6
This signal is emitted after columns have been moved within the
- model. The items between \a start and \a end
- inclusive, under the given \a parent item have been moved to \a destination
- starting at the column \a column.
+ model. The items between \a sourceStart and \a sourceEnd
+ inclusive, under the given \a sourceParent item have been moved to \a destinationParent
+ starting at the column \a destinationColumn.
\b{Note:} Components connected to this signal use it to adapt to changes
in the model's dimensions. It can only be emitted by the QAbstractItemModel
@@ -1858,7 +2042,6 @@ bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value
return false;
}
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
/*!
\since 6.0
Removes the data stored in all the roles for the given \a index.
@@ -1873,7 +2056,6 @@ bool QAbstractItemModel::clearItemData(const QModelIndex &index)
Q_UNUSED(index);
return false;
}
-#endif
/*!
\fn QVariant QAbstractItemModel::data(const QModelIndex &index, int role) const = 0
@@ -1882,7 +2064,7 @@ bool QAbstractItemModel::clearItemData(const QModelIndex &index)
by the \a index.
\note If you do not have a value to return, return an \b invalid
- QVariant instead of returning 0.
+ (default-constructed) QVariant.
\sa Qt::ItemDataRole, setData(), headerData()
*/
@@ -1899,7 +2081,7 @@ bool QAbstractItemModel::clearItemData(const QModelIndex &index)
*/
bool QAbstractItemModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
{
- // ### Qt 6: Consider change the semantics of this function,
+ // ### TODO: Consider change the semantics of this function,
// or deprecating/removing it altogether.
//
// For instance, it should try setting *all* the data
@@ -1942,14 +2124,14 @@ QStringList QAbstractItemModel::mimeTypes() const
mimeTypes(). If you reimplement mimeTypes() in your custom model to return
more MIME types, reimplement this function to make use of them.
- If the list of \a indexes is empty, or there are no supported MIME types, 0
- is returned rather than a serialized empty list.
+ If the list of \a indexes is empty, or there are no supported MIME types,
+ \nullptr is returned rather than a serialized empty list.
\sa mimeTypes(), dropMimeData()
*/
QMimeData *QAbstractItemModel::mimeData(const QModelIndexList &indexes) const
{
- if (indexes.count() <= 0)
+ if (indexes.size() <= 0)
return nullptr;
QStringList types = mimeTypes();
if (types.isEmpty())
@@ -1957,7 +2139,7 @@ QMimeData *QAbstractItemModel::mimeData(const QModelIndexList &indexes) const
QMimeData *data = new QMimeData();
QString format = types.at(0);
QByteArray encoded;
- QDataStream stream(&encoded, QIODevice::WriteOnly);
+ QDataStream stream(&encoded, QDataStream::WriteOnly);
encodeData(indexes, stream);
data->setData(format, encoded);
return data;
@@ -1980,15 +2162,15 @@ bool QAbstractItemModel::canDropMimeData(const QMimeData *data, Qt::DropAction a
int row, int column,
const QModelIndex &parent) const
{
- Q_UNUSED(row)
- Q_UNUSED(column)
- Q_UNUSED(parent)
+ Q_UNUSED(row);
+ Q_UNUSED(column);
+ Q_UNUSED(parent);
if (!(action & supportedDropActions()))
return false;
const QStringList modelTypes = mimeTypes();
- for (int i = 0; i < modelTypes.count(); ++i) {
+ for (int i = 0; i < modelTypes.size(); ++i) {
if (data->hasFormat(modelTypes.at(i)))
return true;
}
@@ -2045,7 +2227,7 @@ bool QAbstractItemModel::dropMimeData(const QMimeData *data, Qt::DropAction acti
column = 0;
// decode and insert
QByteArray encoded = data->data(format);
- QDataStream stream(&encoded, QIODevice::ReadOnly);
+ QDataStream stream(&encoded, QDataStream::ReadOnly);
return decodeData(row, column, parent, stream);
}
@@ -2080,34 +2262,10 @@ Qt::DropActions QAbstractItemModel::supportedDropActions() const
*/
Qt::DropActions QAbstractItemModel::supportedDragActions() const
{
- Q_D(const QAbstractItemModel);
- if (int(d->supportedDragActions) != -1)
- return d->supportedDragActions;
return supportedDropActions();
}
/*!
- \internal
- */
-void QAbstractItemModel::doSetSupportedDragActions(Qt::DropActions actions)
-{
- Q_D(QAbstractItemModel);
- d->supportedDragActions = actions;
-}
-
-/*!
- \since 4.2
- \obsolete
- \fn void QAbstractItemModel::setSupportedDragActions(Qt::DropActions actions)
-
- This function is obsolete. Reimplement supportedDragActions() instead.
-
- Sets the supported drag \a actions for the items in the model.
-
- \sa supportedDragActions(), {Using drag and drop with item views}
-*/
-
-/*!
\note The base class implementation of this function does nothing and
returns \c{false}.
@@ -2353,13 +2511,15 @@ QModelIndexList QAbstractItemModel::match(const QModelIndex &start, int role,
Qt::MatchFlags flags) const
{
QModelIndexList result;
- uint matchType = flags & 0x0F;
+ uint matchType = (flags & Qt::MatchTypeMask).toInt();
Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
- bool recurse = flags & Qt::MatchRecursive;
- bool wrap = flags & Qt::MatchWrap;
+ bool recurse = flags.testAnyFlag(Qt::MatchRecursive);
+ bool wrap = flags.testAnyFlag(Qt::MatchWrap);
bool allHits = (hits == -1);
QString text; // only convert to a string if it is needed
+#if QT_CONFIG(regularexpression)
QRegularExpression rx; // only create it if needed
+#endif
const int column = start.column();
QModelIndex p = parent(start);
int from = start.row();
@@ -2367,7 +2527,7 @@ QModelIndexList QAbstractItemModel::match(const QModelIndex &start, int role,
// iterates twice if wrapping
for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
- for (int r = from; (r < to) && (allHits || result.count() < hits); ++r) {
+ for (int r = from; (r < to) && (allHits || result.size() < hits); ++r) {
QModelIndex idx = index(r, column, p);
if (!idx.isValid())
continue;
@@ -2377,9 +2537,10 @@ QModelIndexList QAbstractItemModel::match(const QModelIndex &start, int role,
if (value == v)
result.append(idx);
} else { // QString or regular expression based matching
+#if QT_CONFIG(regularexpression)
if (matchType == Qt::MatchRegularExpression) {
if (rx.pattern().isEmpty()) {
- if (value.type() == QVariant::RegularExpression) {
+ if (value.userType() == QMetaType::QRegularExpression) {
rx = value.toRegularExpression();
} else {
rx.setPattern(value.toString());
@@ -2388,29 +2549,29 @@ QModelIndexList QAbstractItemModel::match(const QModelIndex &start, int role,
}
}
} else if (matchType == Qt::MatchWildcard) {
- if (rx.pattern().isEmpty())
- rx.setPattern(QRegularExpression::wildcardToRegularExpression(value.toString()));
+ if (rx.pattern().isEmpty()) {
+ const QString pattern = QRegularExpression::wildcardToRegularExpression(value.toString(), QRegularExpression::NonPathWildcardConversion);
+ rx.setPattern(pattern);
+ }
if (cs == Qt::CaseInsensitive)
rx.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
- } else {
+ } else
+#endif
+ {
if (text.isEmpty()) // lazy conversion
text = value.toString();
}
QString t = v.toString();
switch (matchType) {
-#if QT_DEPRECATED_SINCE(5, 15)
- case Qt::MatchRegExp:
- if (QRegExp(text, cs).exactMatch(t))
- result.append(idx);
- break;
-#endif
+#if QT_CONFIG(regularexpression)
case Qt::MatchRegularExpression:
Q_FALLTHROUGH();
case Qt::MatchWildcard:
if (t.contains(rx))
result.append(idx);
break;
+#endif
case Qt::MatchStartsWith:
if (t.startsWith(text, cs))
result.append(idx);
@@ -2434,7 +2595,7 @@ QModelIndexList QAbstractItemModel::match(const QModelIndex &start, int role,
if (hasChildren(parent)) { // search the hierarchy
result += match(index(0, column, parent), role,
(text.isEmpty() ? value : text),
- (allHits ? -1 : hits - result.count()), flags);
+ (allHits ? -1 : hits - result.size()), flags);
}
}
}
@@ -2457,30 +2618,6 @@ QSize QAbstractItemModel::span(const QModelIndex &) const
}
/*!
- \fn void QAbstractItemModel::setRoleNames(const QHash<int,QByteArray> &roleNames)
- \since 4.6
- \obsolete
-
- This function is obsolete. Reimplement roleNames() instead.
-
- Sets the model's role names to \a roleNames.
-
- This function allows mapping of role identifiers to role property names in
- scripting languages.
-
- \sa roleNames()
-*/
-
-/*!
- \internal
- */
-void QAbstractItemModel::doSetRoleNames(const QHash<int,QByteArray> &roleNames)
-{
- Q_D(QAbstractItemModel);
- d->roleNames = roleNames;
-}
-
-/*!
\since 4.6
Returns the model's role names.
@@ -2513,8 +2650,7 @@ void QAbstractItemModel::doSetRoleNames(const QHash<int,QByteArray> &roleNames)
*/
QHash<int,QByteArray> QAbstractItemModel::roleNames() const
{
- Q_D(const QAbstractItemModel);
- return d->roleNames;
+ return QAbstractItemModelPrivate::defaultRoleNames();
}
/*!
@@ -2585,7 +2721,7 @@ bool QAbstractItemModel::setHeaderData(int section, Qt::Orientation orientation,
}
/*!
- \fn QModelIndex QAbstractItemModel::createIndex(int row, int column, void *ptr) const
+ \fn QModelIndex QAbstractItemModel::createIndex(int row, int column, const void *ptr) const
Creates a model index for the given \a row and \a column with the internal
pointer \a ptr.
@@ -2615,9 +2751,8 @@ bool QAbstractItemModel::setHeaderData(int section, Qt::Orientation orientation,
*/
void QAbstractItemModel::encodeData(const QModelIndexList &indexes, QDataStream &stream) const
{
- QModelIndexList::ConstIterator it = indexes.begin();
- for (; it != indexes.end(); ++it)
- stream << (*it).row() << (*it).column() << itemData(*it);
+ for (const auto &index : indexes)
+ stream << index.row() << index.column() << itemData(index);
}
/*!
@@ -2630,8 +2765,8 @@ bool QAbstractItemModel::decodeData(int row, int column, const QModelIndex &pare
int left = INT_MAX;
int bottom = 0;
int right = 0;
- QVector<int> rows, columns;
- QVector<QMap<int, QVariant> > data;
+ QList<int> rows, columns;
+ QList<QMap<int, QVariant>> data;
while (!stream.atEnd()) {
int r, c;
@@ -2652,16 +2787,16 @@ bool QAbstractItemModel::decodeData(int row, int column, const QModelIndex &pare
int dragColumnCount = right - left + 1;
// Compute the number of continuous rows upon insertion and modify the rows to match
- QVector<int> rowsToInsert(bottom + 1);
- for (int i = 0; i < rows.count(); ++i)
+ QList<int> rowsToInsert(bottom + 1);
+ for (int i = 0; i < rows.size(); ++i)
rowsToInsert[rows.at(i)] = 1;
- for (int i = 0; i < rowsToInsert.count(); ++i) {
+ for (int i = 0; i < rowsToInsert.size(); ++i) {
if (rowsToInsert.at(i) == 1){
rowsToInsert[i] = dragRowCount;
++dragRowCount;
}
}
- for (int i = 0; i < rows.count(); ++i)
+ for (int i = 0; i < rows.size(); ++i)
rows[i] = top + rowsToInsert.at(rows.at(i));
QBitArray isWrittenTo(dragRowCount * dragColumnCount);
@@ -2677,7 +2812,7 @@ bool QAbstractItemModel::decodeData(int row, int column, const QModelIndex &pare
row = qMax(0, row);
column = qMax(0, column);
- QVector<QPersistentModelIndex> newIndexes(data.size());
+ QList<QPersistentModelIndex> newIndexes(data.size());
// set the data in the table
for (int j = 0; j < data.size(); ++j) {
int relativeRow = rows.at(j) - top;
@@ -2863,6 +2998,13 @@ bool QAbstractItemModelPrivate::allowMove(const QModelIndex &srcParent, int star
}
/*!
+ \internal
+
+ see QTBUG-94546
+ */
+void QAbstractItemModelPrivate::executePendingOperations() const { }
+
+/*!
\since 4.6
Begins a row move operation.
@@ -3190,9 +3332,8 @@ bool QAbstractItemModel::beginMoveColumns(const QModelIndex &sourceParent, int s
destinationChange.needsAdjust = destinationParent.isValid() && destinationParent.row() >= sourceLast && destinationParent.parent() == sourceParent;
d->changes.push(destinationChange);
- d->itemsAboutToBeMoved(sourceParent, sourceFirst, sourceLast, destinationParent, destinationChild, Qt::Horizontal);
-
emit columnsAboutToBeMoved(sourceParent, sourceFirst, sourceLast, destinationParent, destinationChild, QPrivateSignal());
+ d->itemsAboutToBeMoved(sourceParent, sourceFirst, sourceLast, destinationParent, destinationChild, Qt::Horizontal);
return true;
}
@@ -3225,33 +3366,10 @@ void QAbstractItemModel::endMoveColumns()
adjustedSource = createIndex(adjustedSource.row(), adjustedSource.column() + numMoved, adjustedSource.internalPointer());
d->itemsMoved(adjustedSource, removeChange.first, removeChange.last, adjustedDestination, insertChange.first, Qt::Horizontal);
-
emit columnsMoved(adjustedSource, removeChange.first, removeChange.last, adjustedDestination, insertChange.first, QPrivateSignal());
}
/*!
- \fn void QAbstractItemModel::reset()
- \obsolete
-
- Resets the model to its original state in any attached views.
-
- This function emits the signals modelAboutToBeReset() and modelReset().
-
- \note Use beginResetModel() and endResetModel() instead whenever possible.
- Use this method only if there is no way to call beginResetModel() before invalidating the model.
- Otherwise it could lead to unexpected behaviour, especially when used with proxy models.
-
- For example, in this code both signals modelAboutToBeReset() and modelReset()
- are emitted \e after the data changes:
-
- \snippet code/src_corelib_kernel_qabstractitemmodel.cpp 10
-
- Instead you should use:
-
- \snippet code/src_corelib_kernel_qabstractitemmodel.cpp 11
-*/
-
-/*!
Begins a model reset operation.
A reset operation resets the model to its current state in any attached views.
@@ -3294,7 +3412,7 @@ void QAbstractItemModel::endResetModel()
{
Q_D(QAbstractItemModel);
d->invalidatePersistentIndexes();
- QMetaObject::invokeMethod(this, "resetInternalData");
+ resetInternalData();
emit modelReset(QPrivateSignal());
}
@@ -3340,9 +3458,9 @@ void QAbstractItemModel::changePersistentIndexList(const QModelIndexList &from,
Q_D(QAbstractItemModel);
if (d->persistent.indexes.isEmpty())
return;
- QVector<QPersistentModelIndexData *> toBeReinserted;
- toBeReinserted.reserve(to.count());
- for (int i = 0; i < from.count(); ++i) {
+ QList<QPersistentModelIndexData *> toBeReinserted;
+ toBeReinserted.reserve(to.size());
+ for (int i = 0; i < from.size(); ++i) {
if (from.at(i) == to.at(i))
continue;
const auto it = d->persistent.indexes.constFind(from.at(i));
@@ -3355,11 +3473,8 @@ void QAbstractItemModel::changePersistentIndexList(const QModelIndexList &from,
}
}
- for (QVector<QPersistentModelIndexData *>::const_iterator it = toBeReinserted.constBegin();
- it != toBeReinserted.constEnd() ; ++it) {
- QPersistentModelIndexData *data = *it;
+ for (auto *data : std::as_const(toBeReinserted))
d->persistent.insertMultiAtEnd(data->index, data);
- }
}
/*!
@@ -3371,12 +3486,9 @@ QModelIndexList QAbstractItemModel::persistentIndexList() const
{
Q_D(const QAbstractItemModel);
QModelIndexList result;
- result.reserve(d->persistent.indexes.count());
- for (QHash<QModelIndex, QPersistentModelIndexData *>::const_iterator it = d->persistent.indexes.constBegin();
- it != d->persistent.indexes.constEnd(); ++it) {
- QPersistentModelIndexData *data = *it;
+ result.reserve(d->persistent.indexes.size());
+ for (auto *data : std::as_const(d->persistent.indexes))
result.append(data->index);
- }
return result;
}
@@ -3516,6 +3628,61 @@ bool QAbstractItemModel::checkIndex(const QModelIndex &index, CheckIndexOptions
}
/*!
+ \since 6.0
+
+ Fills the \a roleDataSpan with the requested data for the given \a index.
+
+ The default implementation will call simply data() for each role in
+ the span. A subclass can reimplement this function to provide data
+ to views more efficiently:
+
+ \snippet code/src_corelib_kernel_qabstractitemmodel.cpp 15
+
+ In the snippet above, \c{index} is the same for the entire call.
+ This means that accessing to the necessary data structures in order
+ to retrieve the information for \c{index} can be done only once
+ (hoisting the relevant code out of the loop).
+
+ The usage of QModelRoleData::setData(), or similarly
+ QVariant::setValue(), is encouraged over constructing a QVariant
+ separately and using a plain assignment operator; this is
+ because the former allow to re-use the memory already allocated for
+ the QVariant object stored inside a QModelRoleData, while the latter
+ always allocates the new variant and then destroys the old one.
+
+ Note that views may call multiData() with spans that have been used
+ in previous calls, and therefore may already contain some data.
+ Therefore, it is imperative that if the model cannot return the
+ data for a given role, then it must clear the data in the
+ corresponding QModelRoleData object. This can be done by calling
+ QModelRoleData::clearData(), or similarly by setting a default
+ constructed QVariant, and so on. Failure to clear the data will
+ result in the view believing that the "old" data is meant to be
+ used for the corresponding role.
+
+ Finally, in order to avoid code duplication, a subclass may also
+ decide to reimplement data() in terms of multiData(), by supplying
+ a span of just one element:
+
+ \snippet code/src_corelib_kernel_qabstractitemmodel.cpp 16
+
+ \note Models are not allowed to modify the roles in the span, or
+ to rearrange the span elements. Doing so results in undefined
+ behavior.
+
+ \note It is illegal to pass an invalid model index to this function.
+
+ \sa QModelRoleDataSpan, data()
+*/
+void QAbstractItemModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
+{
+ Q_ASSERT(checkIndex(index, CheckIndexOption::IndexIsValid));
+
+ for (QModelRoleData &d : roleDataSpan)
+ d.setData(data(index, d.role()));
+}
+
+/*!
\class QAbstractTableModel
\inmodule QtCore
\brief The QAbstractTableModel class provides an abstract model that can be
@@ -3572,10 +3739,9 @@ bool QAbstractItemModel::checkIndex(const QModelIndex &index, CheckIndexOptions
\note Some general guidelines for subclassing models are available in the
\l{Model Subclassing Reference}.
- \note
+ \include models.qdocinc {thread-safety-section1}{QAbstractTableModel}
- \sa {Model Classes}, QAbstractItemModel, QAbstractListModel,
- {Pixelator Example}
+ \sa {Model Classes}, QAbstractItemModel, QAbstractListModel
*/
/*!
@@ -3726,7 +3892,7 @@ Qt::ItemFlags QAbstractTableModel::flags(const QModelIndex &index) const
\l{Model Subclassing Reference}.
\sa {Model Classes}, {Model Subclassing Reference}, QAbstractItemView,
- QAbstractTableModel, {Item Views Puzzle Example}
+ QAbstractTableModel
*/
/*!
@@ -3845,14 +4011,14 @@ bool QAbstractTableModel::dropMimeData(const QMimeData *data, Qt::DropAction act
return false;
QByteArray encoded = data->data(format);
- QDataStream stream(&encoded, QIODevice::ReadOnly);
+ QDataStream stream(&encoded, QDataStream::ReadOnly);
// if the drop is on an item, replace the data in the items
if (parent.isValid() && row == -1 && column == -1) {
int top = INT_MAX;
int left = INT_MAX;
- QVector<int> rows, columns;
- QVector<QMap<int, QVariant> > data;
+ QList<int> rows, columns;
+ QList<QMap<int, QVariant>> data;
while (!stream.atEnd()) {
int r, c;
@@ -3896,14 +4062,14 @@ bool QAbstractListModel::dropMimeData(const QMimeData *data, Qt::DropAction acti
return false;
QByteArray encoded = data->data(format);
- QDataStream stream(&encoded, QIODevice::ReadOnly);
+ QDataStream stream(&encoded, QDataStream::ReadOnly);
// if the drop is on an item, replace the data in the items
if (parent.isValid() && row == -1 && column == -1) {
int top = INT_MAX;
int left = INT_MAX;
- QVector<int> rows, columns;
- QVector<QMap<int, QVariant> > data;
+ QList<int> rows, columns;
+ QList<QMap<int, QVariant>> data;
while (!stream.atEnd()) {
int r, c;
@@ -3970,7 +4136,7 @@ bool QAbstractListModel::dropMimeData(const QMimeData *data, Qt::DropAction acti
*/
/*!
- \fn uint qHash(const QPersistentModelIndex &index, uint seed = 0)
+ \fn size_t qHash(const QPersistentModelIndex &index, size_t seed = 0)
\since 5.0
\relates QPersistentModelIndex
@@ -3991,8 +4157,8 @@ bool QAbstractListModel::dropMimeData(const QMimeData *data, Qt::DropAction acti
*/
void QAbstractItemModelPrivate::Persistent::insertMultiAtEnd(const QModelIndex& key, QPersistentModelIndexData *data)
{
- QHash<QModelIndex,QPersistentModelIndexData *>::iterator newIt = indexes.insert(key, data);
- QHash<QModelIndex,QPersistentModelIndexData *>::iterator it = newIt;
+ auto newIt = indexes.insert(key, data);
+ auto it = newIt;
++it;
while (it != indexes.end() && it.key() == key) {
qSwap(*newIt,*it);
@@ -4004,3 +4170,4 @@ void QAbstractItemModelPrivate::Persistent::insertMultiAtEnd(const QModelIndex&
QT_END_NAMESPACE
#include "moc_qabstractitemmodel.cpp"
+#include "qabstractitemmodel.moc"
diff --git a/src/corelib/itemmodels/qabstractitemmodel.h b/src/corelib/itemmodels/qabstractitemmodel.h
index 43649cf79b..8f22f14989 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.h
+++ b/src/corelib/itemmodels/qabstractitemmodel.h
@@ -1,84 +1,150 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTITEMMODEL_H
#define QABSTRACTITEMMODEL_H
-#include <QtCore/qvariant.h>
-#include <QtCore/qobject.h>
#include <QtCore/qhash.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
QT_REQUIRE_CONFIG(itemmodel);
QT_BEGIN_NAMESPACE
+class QModelRoleData
+{
+ int m_role;
+ QVariant m_data;
+
+public:
+ explicit QModelRoleData(int role) noexcept
+ : m_role(role)
+ {}
+
+ constexpr int role() const noexcept { return m_role; }
+ constexpr QVariant &data() noexcept { return m_data; }
+ constexpr const QVariant &data() const noexcept { return m_data; }
+
+ template <typename T>
+ constexpr void setData(T &&value) noexcept(noexcept(m_data.setValue(std::forward<T>(value))))
+ { m_data.setValue(std::forward<T>(value)); }
+
+ void clearData() noexcept { m_data.clear(); }
+};
+
+Q_DECLARE_TYPEINFO(QModelRoleData, Q_RELOCATABLE_TYPE);
+
+class QModelRoleDataSpan;
+
+namespace QtPrivate {
+template <typename T, typename Enable = void>
+struct IsContainerCompatibleWithModelRoleDataSpan : std::false_type {};
+
+template <typename T>
+struct IsContainerCompatibleWithModelRoleDataSpan<T, std::enable_if_t<std::conjunction_v<
+ // lacking concepts and ranges, we accept any T whose std::data yields a suitable pointer ...
+ std::is_convertible<decltype( std::data(std::declval<T &>()) ), QModelRoleData *>,
+ // ... and that has a suitable size ...
+ std::is_convertible<decltype( std::size(std::declval<T &>()) ), qsizetype>,
+ // ... and it's a range as it defines an iterator-like API
+ std::is_convertible<
+ typename std::iterator_traits<decltype( std::begin(std::declval<T &>()) )>::value_type,
+ QModelRoleData
+ >,
+ std::is_convertible<
+ decltype( std::begin(std::declval<T &>()) != std::end(std::declval<T &>()) ),
+ bool>,
+ // Don't make an accidental copy constructor
+ std::negation<std::is_same<std::decay_t<T>, QModelRoleDataSpan>>
+ >>> : std::true_type {};
+} // namespace QtPrivate
+
+class QModelRoleDataSpan
+{
+ QModelRoleData *m_modelRoleData = nullptr;
+ qsizetype m_len = 0;
+
+ template <typename T>
+ using if_compatible_container = std::enable_if_t<QtPrivate::IsContainerCompatibleWithModelRoleDataSpan<T>::value, bool>;
+
+public:
+ constexpr QModelRoleDataSpan() noexcept {}
+
+ constexpr QModelRoleDataSpan(QModelRoleData &modelRoleData) noexcept
+ : m_modelRoleData(&modelRoleData),
+ m_len(1)
+ {}
+
+ constexpr QModelRoleDataSpan(QModelRoleData *modelRoleData, qsizetype len)
+ : m_modelRoleData(modelRoleData),
+ m_len(len)
+ {}
+
+ template <typename Container, if_compatible_container<Container> = true>
+ constexpr QModelRoleDataSpan(Container &c) noexcept(noexcept(std::data(c)) && noexcept(std::size(c)))
+ : m_modelRoleData(std::data(c)),
+ m_len(qsizetype(std::size(c)))
+ {}
+
+ constexpr qsizetype size() const noexcept { return m_len; }
+ constexpr qsizetype length() const noexcept { return m_len; }
+ constexpr QModelRoleData *data() const noexcept { return m_modelRoleData; }
+ constexpr QModelRoleData *begin() const noexcept { return m_modelRoleData; }
+ constexpr QModelRoleData *end() const noexcept { return m_modelRoleData + m_len; }
+ constexpr QModelRoleData &operator[](qsizetype index) const { return m_modelRoleData[index]; }
+
+ constexpr QVariant *dataForRole(int role) const
+ {
+#ifdef __cpp_lib_constexpr_algorithms
+ auto result = std::find_if(begin(), end(), [role](const QModelRoleData &roleData) {
+ return roleData.role() == role;
+ });
+#else
+ auto result = begin();
+ const auto e = end();
+ for (; result != e; ++result) {
+ if (result->role() == role)
+ break;
+ }
+#endif
+
+ return Q_ASSERT(result != end()), &result->data();
+ }
+};
+
+Q_DECLARE_TYPEINFO(QModelRoleDataSpan, Q_RELOCATABLE_TYPE);
class QAbstractItemModel;
class QPersistentModelIndex;
-class Q_CORE_EXPORT QModelIndex
+class QModelIndex
{
friend class QAbstractItemModel;
public:
- Q_DECL_CONSTEXPR inline QModelIndex() noexcept : r(-1), c(-1), i(0), m(nullptr) {}
+ constexpr inline QModelIndex() noexcept : r(-1), c(-1), i(0), m(nullptr) {}
// compiler-generated copy/move ctors/assignment operators are fine!
- Q_DECL_CONSTEXPR inline int row() const noexcept { return r; }
- Q_DECL_CONSTEXPR inline int column() const noexcept { return c; }
- Q_DECL_CONSTEXPR inline quintptr internalId() const noexcept { return i; }
+ constexpr inline int row() const noexcept { return r; }
+ constexpr inline int column() const noexcept { return c; }
+ constexpr inline quintptr internalId() const noexcept { return i; }
inline void *internalPointer() const noexcept { return reinterpret_cast<void*>(i); }
+ inline const void *constInternalPointer() const noexcept { return reinterpret_cast<const void *>(i); }
inline QModelIndex parent() const;
inline QModelIndex sibling(int row, int column) const;
inline QModelIndex siblingAtColumn(int column) const;
inline QModelIndex siblingAtRow(int row) const;
-#if QT_DEPRECATED_SINCE(5, 8)
- QT_DEPRECATED_X("Use QAbstractItemModel::index") inline QModelIndex child(int row, int column) const;
-#endif
inline QVariant data(int role = Qt::DisplayRole) const;
+ inline void multiData(QModelRoleDataSpan roleDataSpan) const;
inline Qt::ItemFlags flags() const;
- Q_DECL_CONSTEXPR inline const QAbstractItemModel *model() const noexcept { return m; }
- Q_DECL_CONSTEXPR inline bool isValid() const noexcept { return (r >= 0) && (c >= 0) && (m != nullptr); }
- Q_DECL_CONSTEXPR inline bool operator==(const QModelIndex &other) const noexcept
+ constexpr inline const QAbstractItemModel *model() const noexcept { return m; }
+ constexpr inline bool isValid() const noexcept { return (r >= 0) && (c >= 0) && (m != nullptr); }
+ constexpr inline bool operator==(const QModelIndex &other) const noexcept
{ return (other.r == r) && (other.i == i) && (other.c == c) && (other.m == m); }
- Q_DECL_CONSTEXPR inline bool operator!=(const QModelIndex &other) const noexcept
+ constexpr inline bool operator!=(const QModelIndex &other) const noexcept
{ return !(*this == other); }
- Q_DECL_CONSTEXPR inline bool operator<(const QModelIndex &other) const noexcept
+ constexpr inline bool operator<(const QModelIndex &other) const noexcept
{
return r < other.r
|| (r == other.r && (c < other.c
@@ -86,15 +152,15 @@ public:
|| (i == other.i && std::less<const QAbstractItemModel *>()(m, other.m))))));
}
private:
- inline QModelIndex(int arow, int acolumn, void *ptr, const QAbstractItemModel *amodel) noexcept
+ inline QModelIndex(int arow, int acolumn, const void *ptr, const QAbstractItemModel *amodel) noexcept
: r(arow), c(acolumn), i(reinterpret_cast<quintptr>(ptr)), m(amodel) {}
- Q_DECL_CONSTEXPR inline QModelIndex(int arow, int acolumn, quintptr id, const QAbstractItemModel *amodel) noexcept
+ constexpr inline QModelIndex(int arow, int acolumn, quintptr id, const QAbstractItemModel *amodel) noexcept
: r(arow), c(acolumn), i(id), m(amodel) {}
int r, c;
quintptr i;
const QAbstractItemModel *m;
};
-Q_DECLARE_TYPEINFO(QModelIndex, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QModelIndex, Q_RELOCATABLE_TYPE);
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug, const QModelIndex &);
@@ -103,7 +169,7 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QModelIndex &);
class QPersistentModelIndexData;
// qHash is a friend, but we can't use default arguments for friends (§8.3.6.4)
-uint qHash(const QPersistentModelIndex &index, uint seed = 0) noexcept;
+size_t qHash(const QPersistentModelIndex &index, size_t seed = 0) noexcept;
class Q_CORE_EXPORT QPersistentModelIndex
{
@@ -112,43 +178,43 @@ public:
QPersistentModelIndex(const QModelIndex &index);
QPersistentModelIndex(const QPersistentModelIndex &other);
~QPersistentModelIndex();
- bool operator<(const QPersistentModelIndex &other) const;
- bool operator==(const QPersistentModelIndex &other) const;
- inline bool operator!=(const QPersistentModelIndex &other) const
+ bool operator<(const QPersistentModelIndex &other) const noexcept;
+ bool operator==(const QPersistentModelIndex &other) const noexcept;
+ inline bool operator!=(const QPersistentModelIndex &other) const noexcept
{ return !operator==(other); }
QPersistentModelIndex &operator=(const QPersistentModelIndex &other);
inline QPersistentModelIndex(QPersistentModelIndex &&other) noexcept
- : d(other.d) { other.d = nullptr; }
- inline QPersistentModelIndex &operator=(QPersistentModelIndex &&other) noexcept
- { qSwap(d, other.d); return *this; }
- inline void swap(QPersistentModelIndex &other) noexcept { qSwap(d, other.d); }
- bool operator==(const QModelIndex &other) const;
- bool operator!=(const QModelIndex &other) const;
+ : d(std::exchange(other.d, nullptr)) {}
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPersistentModelIndex)
+ void swap(QPersistentModelIndex &other) noexcept { qt_ptr_swap(d, other.d); }
+ bool operator==(const QModelIndex &other) const noexcept;
+ bool operator!=(const QModelIndex &other) const noexcept;
QPersistentModelIndex &operator=(const QModelIndex &other);
- operator const QModelIndex&() const;
+ operator QModelIndex() const;
int row() const;
int column() const;
void *internalPointer() const;
+ const void *constInternalPointer() const;
quintptr internalId() const;
QModelIndex parent() const;
QModelIndex sibling(int row, int column) const;
-#if QT_DEPRECATED_SINCE(5, 8)
- QT_DEPRECATED_X("Use QAbstractItemModel::index") QModelIndex child(int row, int column) const;
-#endif
QVariant data(int role = Qt::DisplayRole) const;
+ void multiData(QModelRoleDataSpan roleDataSpan) const;
Qt::ItemFlags flags() const;
const QAbstractItemModel *model() const;
bool isValid() const;
private:
QPersistentModelIndexData *d;
- friend uint qHash(const QPersistentModelIndex &, uint seed) noexcept;
+ friend size_t qHash(const QPersistentModelIndex &, size_t seed) noexcept;
+ friend bool qHashEquals(const QPersistentModelIndex &a, const QPersistentModelIndex &b) noexcept
+ { return a.d == b.d; }
#ifndef QT_NO_DEBUG_STREAM
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QPersistentModelIndex &);
#endif
};
Q_DECLARE_SHARED(QPersistentModelIndex)
-inline uint qHash(const QPersistentModelIndex &index, uint seed) noexcept
+inline size_t qHash(const QPersistentModelIndex &index, size_t seed) noexcept
{ return qHash(index.d, seed); }
@@ -156,7 +222,6 @@ inline uint qHash(const QPersistentModelIndex &index, uint seed) noexcept
Q_CORE_EXPORT QDebug operator<<(QDebug, const QPersistentModelIndex &);
#endif
-template<typename T> class QList;
typedef QList<QModelIndex> QModelIndexList;
class QMimeData;
@@ -171,8 +236,7 @@ class Q_CORE_EXPORT QAbstractItemModel : public QObject
friend class QPersistentModelIndexData;
friend class QAbstractItemViewPrivate;
- friend class QIdentityProxyModel;
- friend class QTransposeProxyModelPrivate;
+ friend class QAbstractProxyModel;
public:
explicit QAbstractItemModel(QObject *parent = nullptr);
@@ -198,9 +262,7 @@ public:
virtual QMap<int, QVariant> itemData(const QModelIndex &index) const;
virtual bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles);
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
virtual bool clearItemData(const QModelIndex &index);
-#endif
virtual QStringList mimeTypes() const;
virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
@@ -209,35 +271,30 @@ public:
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent);
virtual Qt::DropActions supportedDropActions() const;
-
virtual Qt::DropActions supportedDragActions() const;
-#if QT_DEPRECATED_SINCE(5, 0)
- QT_DEPRECATED void setSupportedDragActions(Qt::DropActions actions)
- { doSetSupportedDragActions(actions); }
-#endif
- virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
- virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex());
- virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
- virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex());
- virtual bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
+ Q_INVOKABLE Q_REVISION(6, 4) virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ Q_INVOKABLE Q_REVISION(6, 4) virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex());
+ Q_INVOKABLE Q_REVISION(6, 4) virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ Q_INVOKABLE Q_REVISION(6, 4) virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex());
+ Q_INVOKABLE Q_REVISION(6, 4) virtual bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
const QModelIndex &destinationParent, int destinationChild);
- virtual bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
+ Q_INVOKABLE Q_REVISION(6, 4) virtual bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
const QModelIndex &destinationParent, int destinationChild);
- inline bool insertRow(int row, const QModelIndex &parent = QModelIndex());
- inline bool insertColumn(int column, const QModelIndex &parent = QModelIndex());
- inline bool removeRow(int row, const QModelIndex &parent = QModelIndex());
- inline bool removeColumn(int column, const QModelIndex &parent = QModelIndex());
- inline bool moveRow(const QModelIndex &sourceParent, int sourceRow,
+ Q_INVOKABLE Q_REVISION(6, 4) inline bool insertRow(int row, const QModelIndex &parent = QModelIndex());
+ Q_INVOKABLE Q_REVISION(6, 4) inline bool insertColumn(int column, const QModelIndex &parent = QModelIndex());
+ Q_INVOKABLE Q_REVISION(6, 4) inline bool removeRow(int row, const QModelIndex &parent = QModelIndex());
+ Q_INVOKABLE Q_REVISION(6, 4) inline bool removeColumn(int column, const QModelIndex &parent = QModelIndex());
+ Q_INVOKABLE Q_REVISION(6, 4) inline bool moveRow(const QModelIndex &sourceParent, int sourceRow,
const QModelIndex &destinationParent, int destinationChild);
- inline bool moveColumn(const QModelIndex &sourceParent, int sourceColumn,
+ Q_INVOKABLE Q_REVISION(6, 4) inline bool moveColumn(const QModelIndex &sourceParent, int sourceColumn,
const QModelIndex &destinationParent, int destinationChild);
Q_INVOKABLE virtual void fetchMore(const QModelIndex &parent);
Q_INVOKABLE virtual bool canFetchMore(const QModelIndex &parent) const;
Q_INVOKABLE virtual Qt::ItemFlags flags(const QModelIndex &index) const;
- virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+ Q_INVOKABLE Q_REVISION(6, 4) virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
virtual QModelIndex buddy(const QModelIndex &index) const;
Q_INVOKABLE virtual QModelIndexList match(const QModelIndex &start, int role,
const QVariant &value, int hits = 1,
@@ -266,10 +323,13 @@ public:
Q_ENUM(CheckIndexOption)
Q_DECLARE_FLAGS(CheckIndexOptions, CheckIndexOption)
- Q_REQUIRED_RESULT bool checkIndex(const QModelIndex &index, CheckIndexOptions options = CheckIndexOption::NoOption) const;
+ [[nodiscard]] bool checkIndex(const QModelIndex &index, CheckIndexOptions options = CheckIndexOption::NoOption) const;
+
+ virtual void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const;
Q_SIGNALS:
- void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &roles = QList<int>());
void headerDataChanged(Qt::Orientation orientation, int first, int last);
void layoutChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
void layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
@@ -290,25 +350,22 @@ Q_SIGNALS:
void modelReset(QPrivateSignal);
void rowsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal);
- void rowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row, QPrivateSignal);
+ void rowsMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal);
void columnsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn, QPrivateSignal);
- void columnsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column, QPrivateSignal);
+ void columnsMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn, QPrivateSignal);
public Q_SLOTS:
virtual bool submit();
virtual void revert();
protected Q_SLOTS:
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- virtual
-#endif
- void resetInternalData();
+ virtual void resetInternalData();
protected:
QAbstractItemModel(QAbstractItemModelPrivate &dd, QObject *parent = nullptr);
- inline QModelIndex createIndex(int row, int column, void *data = nullptr) const;
+ inline QModelIndex createIndex(int row, int column, const void *data = nullptr) const;
inline QModelIndex createIndex(int row, int column, quintptr id) const;
void encodeData(const QModelIndexList &indexes, QDataStream &stream) const;
@@ -332,15 +389,6 @@ protected:
bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationColumn);
void endMoveColumns();
-
-#if QT_DEPRECATED_SINCE(5,0)
- QT_DEPRECATED void reset()
- {
- beginResetModel();
- endResetModel();
- }
-#endif
-
void beginResetModel();
void endResetModel();
@@ -348,17 +396,7 @@ protected:
void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to);
QModelIndexList persistentIndexList() const;
-#if QT_DEPRECATED_SINCE(5,0)
- QT_DEPRECATED void setRoleNames(const QHash<int,QByteArray> &theRoleNames)
- {
- doSetRoleNames(theRoleNames);
- }
-#endif
-
private:
- void doSetRoleNames(const QHash<int,QByteArray> &roleNames);
- void doSetSupportedDragActions(Qt::DropActions actions);
-
Q_DECLARE_PRIVATE(QAbstractItemModel)
Q_DISABLE_COPY(QAbstractItemModel)
};
@@ -379,7 +417,7 @@ inline bool QAbstractItemModel::moveRow(const QModelIndex &sourceParent, int sou
inline bool QAbstractItemModel::moveColumn(const QModelIndex &sourceParent, int sourceColumn,
const QModelIndex &destinationParent, int destinationChild)
{ return moveColumns(sourceParent, sourceColumn, 1, destinationParent, destinationChild); }
-inline QModelIndex QAbstractItemModel::createIndex(int arow, int acolumn, void *adata) const
+inline QModelIndex QAbstractItemModel::createIndex(int arow, int acolumn, const void *adata) const
{ return QModelIndex(arow, acolumn, adata, this); }
inline QModelIndex QAbstractItemModel::createIndex(int arow, int acolumn, quintptr aid) const
{ return QModelIndex(arow, acolumn, aid, this); }
@@ -451,22 +489,26 @@ inline QModelIndex QModelIndex::siblingAtColumn(int acolumn) const
inline QModelIndex QModelIndex::siblingAtRow(int arow) const
{ return m ? (r == arow) ? *this : m->sibling(arow, c, *this) : QModelIndex(); }
-#if QT_DEPRECATED_SINCE(5, 8)
-inline QModelIndex QModelIndex::child(int arow, int acolumn) const
-{ return m ? m->index(arow, acolumn, *this) : QModelIndex(); }
-#endif
-
inline QVariant QModelIndex::data(int arole) const
{ return m ? m->data(*this, arole) : QVariant(); }
+inline void QModelIndex::multiData(QModelRoleDataSpan roleDataSpan) const
+{ if (m) m->multiData(*this, roleDataSpan); }
+
inline Qt::ItemFlags QModelIndex::flags() const
{ return m ? m->flags(*this) : Qt::ItemFlags(); }
-inline uint qHash(const QModelIndex &index) noexcept
-{ return uint((uint(index.row()) << 4) + index.column() + index.internalId()); }
+inline size_t qHash(const QModelIndex &index, size_t seed = 0) noexcept
+{
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ return qHashMulti(seed, index.row(), index.column(), index.internalId());
+#else
+ return size_t((size_t(index.row()) << 4) + size_t(index.column()) + index.internalId()) ^ seed;
+#endif
+}
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QModelIndexList)
+QT_DECL_METATYPE_EXTERN(QModelIndexList, Q_CORE_EXPORT)
#endif // QABSTRACTITEMMODEL_H
diff --git a/src/corelib/itemmodels/qabstractitemmodel_p.h b/src/corelib/itemmodels/qabstractitemmodel_p.h
index 92a440a125..e34dc3262c 100644
--- a/src/corelib/itemmodels/qabstractitemmodel_p.h
+++ b/src/corelib/itemmodels/qabstractitemmodel_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTITEMMODEL_P_H
#define QABSTRACTITEMMODEL_P_H
@@ -82,7 +46,8 @@ public:
~QAbstractItemModelPrivate();
void removePersistentIndexData(QPersistentModelIndexData *data);
- void movePersistentIndexes(const QVector<QPersistentModelIndexData *> &indexes, int change, const QModelIndex &parent, Qt::Orientation orientation);
+ void movePersistentIndexes(const QList<QPersistentModelIndexData *> &indexes, int change, const QModelIndex &parent,
+ Qt::Orientation orientation);
void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
void rowsInserted(const QModelIndex &parent, int first, int last);
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
@@ -98,6 +63,9 @@ public:
void itemsMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation);
bool allowMove(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation);
+ // ugly hack for QTreeModel, see QTBUG-94546
+ virtual void executePendingOperations() const;
+
inline QModelIndex createIndex(int row, int column, void *data = nullptr) const {
return q_func()->createIndex(row, column, data);
}
@@ -114,8 +82,8 @@ public:
void invalidatePersistentIndex(const QModelIndex &index);
struct Change {
- Q_DECL_CONSTEXPR Change() : parent(), first(-1), last(-1), needsAdjust(false) {}
- Q_DECL_CONSTEXPR Change(const QModelIndex &p, int f, int l) : parent(p), first(f), last(l), needsAdjust(false) {}
+ constexpr Change() : parent(), first(-1), last(-1), needsAdjust(false) {}
+ constexpr Change(const QModelIndex &p, int f, int l) : parent(p), first(f), last(l), needsAdjust(false) {}
QModelIndex parent;
int first, last;
@@ -135,26 +103,73 @@ public:
// rowsMoved signal.
bool needsAdjust;
- Q_DECL_CONSTEXPR bool isValid() const { return first >= 0 && last >= 0; }
+ constexpr bool isValid() const { return first >= 0 && last >= 0; }
};
QStack<Change> changes;
struct Persistent {
Persistent() {}
QMultiHash<QModelIndex, QPersistentModelIndexData *> indexes;
- QStack<QVector<QPersistentModelIndexData *> > moved;
- QStack<QVector<QPersistentModelIndexData *> > invalidated;
+ QStack<QList<QPersistentModelIndexData *>> moved;
+ QStack<QList<QPersistentModelIndexData *>> invalidated;
void insertMultiAtEnd(const QModelIndex& key, QPersistentModelIndexData *data);
} persistent;
- Qt::DropActions supportedDragActions;
-
- QHash<int,QByteArray> roleNames;
static const QHash<int,QByteArray> &defaultRoleNames();
static bool isVariantLessThan(const QVariant &left, const QVariant &right,
Qt::CaseSensitivity cs = Qt::CaseSensitive, bool isLocaleAware = false);
};
-Q_DECLARE_TYPEINFO(QAbstractItemModelPrivate::Change, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QAbstractItemModelPrivate::Change, Q_RELOCATABLE_TYPE);
+
+namespace QtPrivate {
+
+/*!
+ \internal
+ This is a workaround for QTBUG-75172.
+
+ Some predefined model roles are supposed to use certain enum/flag
+ types (e.g. fetching Qt::TextAlignmentRole is supposed to return a
+ variant containing a Qt::Alignment object).
+
+ For historical reasons, a plain `int` was used sometimes. This is
+ surprising to end-users and also sloppy on Qt's part; users were
+ forced to use `int` rather than the correct datatype.
+
+ This function tries both the "right" type and plain `int`, for a
+ given QVariant. This fixes the problem (using the correct datatype)
+ but also keeps compatibility with existing code using `int`.
+
+ ### Qt 7: get rid of this. Always use the correct datatype.
+*/
+template <typename T>
+T legacyEnumValueFromModelData(const QVariant &data)
+{
+ static_assert(std::is_enum_v<T>);
+ if (data.userType() == qMetaTypeId<T>()) {
+ return data.value<T>();
+ } else if (std::is_same_v<std::underlying_type_t<T>, int> ||
+ std::is_same_v<std::underlying_type_t<T>, uint>) {
+ return T(data.toInt());
+ }
+
+ return T();
+}
+
+template <typename T>
+T legacyFlagValueFromModelData(const QVariant &data)
+{
+ if (data.userType() == qMetaTypeId<T>()) {
+ return data.value<T>();
+ } else if (std::is_same_v<std::underlying_type_t<typename T::enum_type>, int> ||
+ std::is_same_v<std::underlying_type_t<typename T::enum_type>, uint>) {
+ return T::fromInt(data.toInt());
+ }
+
+ return T();
+}
+
+} // namespace QtPrivate
+
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qabstractproxymodel.cpp b/src/corelib/itemmodels/qabstractproxymodel.cpp
index 87559cd6b2..abdeefb4da 100644
--- a/src/corelib/itemmodels/qabstractproxymodel.cpp
+++ b/src/corelib/itemmodels/qabstractproxymodel.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qabstractproxymodel.h"
#include "qitemselectionmodel.h"
#include <private/qabstractproxymodel_p.h>
#include <QtCore/QSize>
#include <QtCore/QStringList>
+#include <QtCore/QMap>
QT_BEGIN_NAMESPACE
@@ -90,6 +55,87 @@ void QAbstractProxyModelPrivate::_q_sourceModelDestroyed()
model = QAbstractItemModelPrivate::staticEmptyModel();
}
+void QAbstractProxyModelPrivate::emitHeaderDataChanged()
+{
+ Q_Q(QAbstractProxyModel);
+
+ if (updateHorizontalHeader) {
+ if (auto columnCount = q->columnCount(); columnCount > 0)
+ emit q->headerDataChanged(Qt::Horizontal, 0, columnCount - 1);
+ }
+
+ if (updateVerticalHeader) {
+ if (auto rowCount = q->rowCount(); rowCount > 0)
+ emit q->headerDataChanged(Qt::Vertical, 0, rowCount - 1);
+ }
+
+ updateHorizontalHeader = false;
+ updateVerticalHeader = false;
+}
+
+void QAbstractProxyModelPrivate::scheduleHeaderUpdate(Qt::Orientation orientation)
+{
+ const bool isUpdateScheduled = updateHorizontalHeader || updateVerticalHeader;
+
+ if (orientation == Qt::Horizontal && !updateHorizontalHeader)
+ updateHorizontalHeader = true;
+ else if (orientation == Qt::Vertical && !updateVerticalHeader)
+ updateVerticalHeader = true;
+ else
+ return;
+
+ if (!isUpdateScheduled) {
+ Q_Q(QAbstractProxyModel);
+ QMetaObject::invokeMethod(q, [this]() { emitHeaderDataChanged(); }, Qt::QueuedConnection);
+ }
+}
+
+void QAbstractProxyModelPrivate::_q_sourceModelRowsAboutToBeInserted(const QModelIndex &parent, int, int)
+{
+ if (parent.isValid())
+ return;
+ sourceHadZeroRows = model->rowCount() == 0;
+}
+
+void QAbstractProxyModelPrivate::_q_sourceModelRowsInserted(const QModelIndex &parent, int, int)
+{
+ if (parent.isValid())
+ return;
+ if (sourceHadZeroRows)
+ scheduleHeaderUpdate(Qt::Horizontal);
+}
+
+void QAbstractProxyModelPrivate::_q_sourceModelRowsRemoved(const QModelIndex &parent, int, int)
+{
+ if (parent.isValid())
+ return;
+ if (model->rowCount() == 0)
+ scheduleHeaderUpdate(Qt::Horizontal);
+}
+
+void QAbstractProxyModelPrivate::_q_sourceModelColumnsAboutToBeInserted(const QModelIndex &parent, int, int)
+{
+ if (parent.isValid())
+ return;
+ sourceHadZeroColumns = model->columnCount() == 0;
+}
+
+void QAbstractProxyModelPrivate::_q_sourceModelColumnsInserted(const QModelIndex &parent, int, int)
+{
+ if (parent.isValid())
+ return;
+ if (sourceHadZeroColumns)
+ scheduleHeaderUpdate(Qt::Vertical);
+}
+
+void QAbstractProxyModelPrivate::_q_sourceModelColumnsRemoved(const QModelIndex &parent, int, int)
+{
+ if (parent.isValid())
+ return;
+ if (model->columnCount() == 0)
+ scheduleHeaderUpdate(Qt::Vertical);
+}
+
/*!
Constructs a proxy model with the given \a parent.
*/
@@ -128,31 +174,45 @@ QAbstractProxyModel::~QAbstractProxyModel()
void QAbstractProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
Q_D(QAbstractProxyModel);
- if (sourceModel != d->model) {
- if (d->model)
- disconnect(d->model, SIGNAL(destroyed()), this, SLOT(_q_sourceModelDestroyed()));
+ d->model.removeBindingUnlessInWrapper();
+ // Special case to handle nullptr models. Otherwise we will have unwanted
+ // notifications.
+ const QAbstractItemModel *currentModel = d->model.valueBypassingBindings();
+ if (!sourceModel && currentModel == QAbstractItemModelPrivate::staticEmptyModel())
+ return;
+ static const struct {
+ const char *signalName;
+ const char *slotName;
+ } connectionTable[] = {
+ // clang-format off
+ { SIGNAL(destroyed()), SLOT(_q_sourceModelDestroyed()) },
+ { SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), SLOT(_q_sourceModelRowsAboutToBeInserted(QModelIndex,int,int)) },
+ { SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(_q_sourceModelRowsInserted(QModelIndex,int,int)) },
+ { SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(_q_sourceModelRowsRemoved(QModelIndex,int,int)) },
+ { SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), SLOT(_q_sourceModelColumnsAboutToBeInserted(QModelIndex,int,int)) },
+ { SIGNAL(columnsInserted(QModelIndex,int,int)), SLOT(_q_sourceModelColumnsInserted(QModelIndex,int,int)) },
+ { SIGNAL(columnsRemoved(QModelIndex,int,int)), SLOT(_q_sourceModelColumnsRemoved(QModelIndex,int,int)) }
+ // clang-format on
+ };
+
+ if (sourceModel != currentModel) {
+ if (currentModel) {
+ for (const auto &c : connectionTable)
+ disconnect(currentModel, c.signalName, this, c.slotName);
+ }
if (sourceModel) {
- d->model = sourceModel;
- connect(d->model, SIGNAL(destroyed()), this, SLOT(_q_sourceModelDestroyed()));
+ d->model.setValueBypassingBindings(sourceModel);
+ for (const auto &c : connectionTable)
+ connect(sourceModel, c.signalName, this, c.slotName);
} else {
- d->model = QAbstractItemModelPrivate::staticEmptyModel();
+ d->model.setValueBypassingBindings(QAbstractItemModelPrivate::staticEmptyModel());
}
- d->roleNames = d->model->roleNames();
- emit sourceModelChanged(QPrivateSignal());
+ d->model.notify();
}
}
/*!
- Clears the roleNames of this proxy model.
-*/
-void QAbstractProxyModel::resetInternalData()
-{
- Q_D(QAbstractProxyModel);
- d->roleNames = d->model->roleNames();
-}
-
-/*!
Returns the model that contains the data that is available through the proxy model.
*/
QAbstractItemModel *QAbstractProxyModel::sourceModel() const
@@ -163,6 +223,12 @@ QAbstractItemModel *QAbstractProxyModel::sourceModel() const
return d->model;
}
+QBindable<QAbstractItemModel *> QAbstractProxyModel::bindableSourceModel()
+{
+ Q_D(QAbstractProxyModel);
+ return QBindable<QAbstractItemModel *>(&d->model);
+}
+
/*!
\reimp
*/
@@ -251,13 +317,17 @@ QVariant QAbstractProxyModel::data(const QModelIndex &proxyIndex, int role) cons
QVariant QAbstractProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
Q_D(const QAbstractProxyModel);
- int sourceSection;
+ int sourceSection = section;
if (orientation == Qt::Horizontal) {
- const QModelIndex proxyIndex = index(0, section);
- sourceSection = mapToSource(proxyIndex).column();
+ if (rowCount() > 0) {
+ const QModelIndex proxyIndex = index(0, section);
+ sourceSection = mapToSource(proxyIndex).column();
+ }
} else {
- const QModelIndex proxyIndex = index(section, 0);
- sourceSection = mapToSource(proxyIndex).row();
+ if (columnCount() > 0) {
+ const QModelIndex proxyIndex = index(section, 0);
+ sourceSection = mapToSource(proxyIndex).row();
+ }
}
return d->model->headerData(sourceSection, orientation, role);
}
@@ -267,7 +337,8 @@ QVariant QAbstractProxyModel::headerData(int section, Qt::Orientation orientatio
*/
QMap<int, QVariant> QAbstractProxyModel::itemData(const QModelIndex &proxyIndex) const
{
- return QAbstractItemModel::itemData(proxyIndex);
+ Q_D(const QAbstractProxyModel);
+ return d->model->itemData(mapToSource(proxyIndex));
}
/*!
@@ -293,7 +364,8 @@ bool QAbstractProxyModel::setData(const QModelIndex &index, const QVariant &valu
*/
bool QAbstractProxyModel::setItemData(const QModelIndex &index, const QMap< int, QVariant >& roles)
{
- return QAbstractItemModel::setItemData(index, roles);
+ Q_D(QAbstractProxyModel);
+ return d->model->setItemData(mapToSource(index), roles);
}
/*!
@@ -313,7 +385,6 @@ bool QAbstractProxyModel::setHeaderData(int section, Qt::Orientation orientation
return d->model->setHeaderData(sourceSection, orientation, value, role);
}
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
/*!
\reimp
\since 6.0
@@ -323,7 +394,6 @@ bool QAbstractProxyModel::clearItemData(const QModelIndex &index)
Q_D(QAbstractProxyModel);
return d->model->clearItemData(mapToSource(index));
}
-#endif
/*!
\reimp
@@ -394,7 +464,7 @@ QMimeData* QAbstractProxyModel::mimeData(const QModelIndexList &indexes) const
{
Q_D(const QAbstractProxyModel);
QModelIndexList list;
- list.reserve(indexes.count());
+ list.reserve(indexes.size());
for (const QModelIndex &index : indexes)
list << mapToSource(index);
return d->model->mimeData(list);
@@ -477,6 +547,36 @@ Qt::DropActions QAbstractProxyModel::supportedDropActions() const
return d->model->supportedDropActions();
}
+/*!
+ \reimp
+ */
+QHash<int,QByteArray> QAbstractProxyModel::roleNames() const
+{
+ Q_D(const QAbstractProxyModel);
+ return d->model->roleNames();
+}
+
+/*!
+ Equivalent to calling createIndex on the source model.
+
+ This method is useful if your proxy model wants to maintain the
+ parent-child relationship of items in the source model.
+ When reimplementing mapToSource(), you can call this method to
+ create an index for row \a row and column \a col of the source model.
+
+ A typical use would be to save the internal pointer coming from the source model
+ in the proxy index when reimplementing mapFromSource() and use the same internal
+ pointer as \a internalPtr to recover the original source index when
+ reimplementing mapToSource().
+ \since 6.2
+ */
+QModelIndex QAbstractProxyModel::createSourceIndex(int row, int col, void *internalPtr) const
+{
+ if (sourceModel())
+ return sourceModel()->createIndex(row, col, internalPtr);
+ return QModelIndex();
+}
+
QT_END_NAMESPACE
#include "moc_qabstractproxymodel.cpp"
diff --git a/src/corelib/itemmodels/qabstractproxymodel.h b/src/corelib/itemmodels/qabstractproxymodel.h
index c9a73b6a31..8652f500df 100644
--- a/src/corelib/itemmodels/qabstractproxymodel.h
+++ b/src/corelib/itemmodels/qabstractproxymodel.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTPROXYMODEL_H
#define QABSTRACTPROXYMODEL_H
@@ -52,7 +16,8 @@ class QItemSelection;
class Q_CORE_EXPORT QAbstractProxyModel : public QAbstractItemModel
{
Q_OBJECT
- Q_PROPERTY(QAbstractItemModel* sourceModel READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged)
+ Q_PROPERTY(QAbstractItemModel *sourceModel READ sourceModel WRITE setSourceModel
+ NOTIFY sourceModelChanged BINDABLE bindableSourceModel)
public:
explicit QAbstractProxyModel(QObject *parent = nullptr);
@@ -60,6 +25,7 @@ public:
virtual void setSourceModel(QAbstractItemModel *sourceModel);
QAbstractItemModel *sourceModel() const;
+ QBindable<QAbstractItemModel *> bindableSourceModel();
Q_INVOKABLE virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const = 0;
Q_INVOKABLE virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const = 0;
@@ -78,9 +44,7 @@ public:
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
bool setItemData(const QModelIndex& index, const QMap<int, QVariant> &roles) override;
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override;
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool clearItemData(const QModelIndex &index) override;
-#endif
QModelIndex buddy(const QModelIndex &index) const override;
bool canFetchMore(const QModelIndex &parent) const override;
@@ -98,20 +62,25 @@ public:
QStringList mimeTypes() const override;
Qt::DropActions supportedDragActions() const override;
Qt::DropActions supportedDropActions() const override;
+ QHash<int, QByteArray> roleNames() const override;
Q_SIGNALS:
void sourceModelChanged(QPrivateSignal);
-protected Q_SLOTS:
- void resetInternalData();
-
protected:
+ QModelIndex createSourceIndex(int row, int col, void *internalPtr) const;
QAbstractProxyModel(QAbstractProxyModelPrivate &, QObject *parent);
private:
Q_DECLARE_PRIVATE(QAbstractProxyModel)
Q_DISABLE_COPY(QAbstractProxyModel)
Q_PRIVATE_SLOT(d_func(), void _q_sourceModelDestroyed())
+ Q_PRIVATE_SLOT(d_func(), void _q_sourceModelRowsAboutToBeInserted(QModelIndex, int, int))
+ Q_PRIVATE_SLOT(d_func(), void _q_sourceModelRowsInserted(QModelIndex, int, int))
+ Q_PRIVATE_SLOT(d_func(), void _q_sourceModelRowsRemoved(QModelIndex, int, int))
+ Q_PRIVATE_SLOT(d_func(), void _q_sourceModelColumnsAboutToBeInserted(QModelIndex, int, int))
+ Q_PRIVATE_SLOT(d_func(), void _q_sourceModelColumnsInserted(QModelIndex, int, int))
+ Q_PRIVATE_SLOT(d_func(), void _q_sourceModelColumnsRemoved(QModelIndex, int, int))
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qabstractproxymodel_p.h b/src/corelib/itemmodels/qabstractproxymodel_p.h
index a95687c970..d33666d00b 100644
--- a/src/corelib/itemmodels/qabstractproxymodel_p.h
+++ b/src/corelib/itemmodels/qabstractproxymodel_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTPROXYMODEL_P_H
#define QABSTRACTPROXYMODEL_P_H
@@ -52,7 +16,9 @@
//
//
+#include "qabstractproxymodel.h"
#include "private/qabstractitemmodel_p.h"
+#include "private/qproperty_p.h"
QT_REQUIRE_CONFIG(proxymodel);
@@ -62,11 +28,45 @@ class Q_CORE_EXPORT QAbstractProxyModelPrivate : public QAbstractItemModelPrivat
{
Q_DECLARE_PUBLIC(QAbstractProxyModel)
public:
- QAbstractProxyModelPrivate() : QAbstractItemModelPrivate(), model(nullptr) {}
- QAbstractItemModel *model;
+ QAbstractProxyModelPrivate()
+ : QAbstractItemModelPrivate(),
+ sourceHadZeroRows(false),
+ sourceHadZeroColumns(false),
+ updateVerticalHeader(false),
+ updateHorizontalHeader(false)
+ {}
+ void setModelForwarder(QAbstractItemModel *sourceModel)
+ {
+ q_func()->setSourceModel(sourceModel);
+ }
+ void modelChangedForwarder()
+ {
+ Q_EMIT q_func()->sourceModelChanged(QAbstractProxyModel::QPrivateSignal());
+ }
+ QAbstractItemModel *getModelForwarder() const { return q_func()->sourceModel(); }
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QAbstractProxyModelPrivate, QAbstractItemModel *, model,
+ &QAbstractProxyModelPrivate::setModelForwarder,
+ &QAbstractProxyModelPrivate::modelChangedForwarder,
+ &QAbstractProxyModelPrivate::getModelForwarder, nullptr)
virtual void _q_sourceModelDestroyed();
+ void _q_sourceModelRowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
+ void _q_sourceModelRowsInserted(const QModelIndex &parent, int first, int last);
+ void _q_sourceModelRowsRemoved(const QModelIndex &parent, int first, int last);
+ void _q_sourceModelColumnsAboutToBeInserted(const QModelIndex &parent, int first, int last);
+ void _q_sourceModelColumnsInserted(const QModelIndex &parent, int first, int last);
+ void _q_sourceModelColumnsRemoved(const QModelIndex &parent, int first, int last);
+
void mapDropCoordinatesToSource(int row, int column, const QModelIndex &parent,
int *source_row, int *source_column, QModelIndex *source_parent) const;
+
+ void scheduleHeaderUpdate(Qt::Orientation orientation);
+ void emitHeaderDataChanged();
+
+ unsigned int sourceHadZeroRows : 1;
+ unsigned int sourceHadZeroColumns : 1;
+ unsigned int updateVerticalHeader : 1;
+ unsigned int updateHorizontalHeader : 1;
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp b/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp
index 3afa132483..3a49d37cff 100644
--- a/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp
+++ b/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qconcatenatetablesproxymodel.h"
#include <private/qabstractitemmodel_p.h>
#include "qsize.h"
+#include "qmap.h"
#include "qdebug.h"
QT_BEGIN_NAMESPACE
@@ -61,26 +26,43 @@ public:
};
SourceModelForRowResult sourceModelForRow(int row) const;
- void _q_slotRowsAboutToBeInserted(const QModelIndex &, int start, int end);
- void _q_slotRowsInserted(const QModelIndex &, int start, int end);
- void _q_slotRowsAboutToBeRemoved(const QModelIndex &, int start, int end);
- void _q_slotRowsRemoved(const QModelIndex &, int start, int end);
- void _q_slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_slotColumnsInserted(const QModelIndex &parent, int, int);
- void _q_slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_slotColumnsRemoved(const QModelIndex &parent, int, int);
- void _q_slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QVector<int> &roles);
- void _q_slotSourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
- void _q_slotSourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
- void _q_slotModelAboutToBeReset();
- void _q_slotModelReset();
+ void slotRowsAboutToBeInserted(const QModelIndex &, int start, int end);
+ void slotRowsInserted(const QModelIndex &, int start, int end);
+ void slotRowsAboutToBeRemoved(const QModelIndex &, int start, int end);
+ void slotRowsRemoved(const QModelIndex &, int start, int end);
+ void slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void slotColumnsInserted(const QModelIndex &parent, int, int);
+ void slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void slotColumnsRemoved(const QModelIndex &parent, int, int);
+ void slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QList<int> &roles);
+ void slotSourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
+ void slotSourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
+ void slotModelAboutToBeReset();
+ void slotModelReset();
int columnCountAfterChange(const QAbstractItemModel *model, int newCount) const;
int calculatedColumnCount() const;
void updateColumnCount();
bool mapDropCoordinatesToSource(int row, int column, const QModelIndex &parent,
int *sourceRow, int *sourceColumn, QModelIndex *sourceParent, QAbstractItemModel **sourceModel) const;
- QVector<QAbstractItemModel *> m_models;
+ struct ModelInfo {
+ using ConnArray = std::array<QMetaObject::Connection, 13>;
+ ModelInfo(QAbstractItemModel *m, ConnArray &&con)
+ : model(m), connections(std::move(con)) {}
+ QAbstractItemModel *model = nullptr;
+ ConnArray connections;
+ };
+ QList<ModelInfo> m_models;
+
+ QList<ModelInfo>::const_iterator findSourceModel(const QAbstractItemModel *m) const
+ {
+ auto byModelPtr = [m](const auto &modInfo) { return modInfo.model == m; };
+ return std::find_if(m_models.cbegin(), m_models.cend(), byModelPtr);
+ }
+
+ bool containsSourceModel(const QAbstractItemModel *m) const
+ { return findSourceModel(m) != m_models.cend(); }
+
int m_rowCount; // have to maintain it here since we can't compute during model destruction
int m_columnCount;
@@ -88,8 +70,8 @@ public:
int m_newColumnCount;
// for layoutAboutToBeChanged/layoutChanged
- QVector<QPersistentModelIndex> layoutChangePersistentIndexes;
- QVector<QModelIndex> layoutChangeProxyIndexes;
+ QList<QPersistentModelIndex> layoutChangePersistentIndexes;
+ QList<QModelIndex> layoutChangeProxyIndexes;
};
QConcatenateTablesProxyModelPrivate::QConcatenateTablesProxyModelPrivate()
@@ -151,7 +133,7 @@ QModelIndex QConcatenateTablesProxyModel::mapFromSource(const QModelIndex &sourc
if (!sourceIndex.isValid())
return QModelIndex();
const QAbstractItemModel *sourceModel = sourceIndex.model();
- if (!d->m_models.contains(const_cast<QAbstractItemModel *>(sourceModel))) {
+ if (!d->containsSourceModel(sourceModel)) {
qWarning("QConcatenateTablesProxyModel: index from wrong model passed to mapFromSource");
Q_ASSERT(!"QConcatenateTablesProxyModel: index from wrong model passed to mapFromSource");
return QModelIndex();
@@ -243,7 +225,7 @@ Qt::ItemFlags QConcatenateTablesProxyModel::flags(const QModelIndex &index) cons
return Qt::NoItemFlags;
Q_ASSERT(checkIndex(index));
if (!index.isValid())
- return d->m_models.at(0)->flags(index);
+ return d->m_models.at(0).model->flags(index);
const QModelIndex sourceIndex = mapToSource(index);
Q_ASSERT(sourceIndex.isValid());
return sourceIndex.model()->flags(sourceIndex);
@@ -261,7 +243,7 @@ QVariant QConcatenateTablesProxyModel::headerData(int section, Qt::Orientation o
return QVariant();
switch (orientation) {
case Qt::Horizontal:
- return d->m_models.at(0)->headerData(section, orientation, role);
+ return d->m_models.at(0).model->headerData(section, orientation, role);
case Qt::Vertical: {
const auto result = d->sourceModelForRow(section);
Q_ASSERT(result.sourceModel);
@@ -313,8 +295,8 @@ QModelIndex QConcatenateTablesProxyModel::parent(const QModelIndex &index) const
int QConcatenateTablesProxyModel::rowCount(const QModelIndex &parent) const
{
Q_D(const QConcatenateTablesProxyModel);
- Q_ASSERT(checkIndex(parent, QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); // flat model
- Q_UNUSED(parent);
+ if (parent.isValid())
+ return 0; // flat model
return d->m_rowCount;
}
@@ -327,7 +309,7 @@ QStringList QConcatenateTablesProxyModel::mimeTypes() const
Q_D(const QConcatenateTablesProxyModel);
if (d->m_models.isEmpty())
return QStringList();
- return d->m_models.at(0)->mimeTypes();
+ return d->m_models.at(0).model->mimeTypes();
}
/*!
@@ -350,7 +332,7 @@ QMimeData *QConcatenateTablesProxyModel::mimeData(const QModelIndexList &indexes
Q_ASSERT(checkIndex(firstIndex, CheckIndexOption::IndexIsValid));
const auto result = d->sourceModelForRow(firstIndex.row());
QModelIndexList sourceIndexes;
- sourceIndexes.reserve(indexes.count());
+ sourceIndexes.reserve(indexes.size());
for (const QModelIndex &index : indexes) {
const QModelIndex sourceIndex = mapToSource(index);
Q_ASSERT(sourceIndex.model() == result.sourceModel); // see documentation above
@@ -369,7 +351,7 @@ bool QConcatenateTablesProxyModelPrivate::mapDropCoordinatesToSource(int row, in
// Drop after the last item
if (row == -1 || row == m_rowCount) {
*sourceRow = -1;
- *sourceModel = m_models.constLast();
+ *sourceModel = m_models.constLast().model;
return true;
}
// Drop between toplevel items
@@ -448,6 +430,21 @@ QSize QConcatenateTablesProxyModel::span(const QModelIndex &index) const
}
/*!
+ Returns a list of models that were added as source models for this proxy model.
+
+ \since 5.15
+*/
+QList<QAbstractItemModel *> QConcatenateTablesProxyModel::sourceModels() const
+{
+ Q_D(const QConcatenateTablesProxyModel);
+ QList<QAbstractItemModel *> ret;
+ ret.reserve(d->m_models.size());
+ for (const auto &info : d->m_models)
+ ret.push_back(info.model);
+ return ret;
+}
+
+/*!
Adds a source model \a sourceModel, below all previously added source models.
The ownership of \a sourceModel is not affected by this.
@@ -458,30 +455,42 @@ void QConcatenateTablesProxyModel::addSourceModel(QAbstractItemModel *sourceMode
{
Q_D(QConcatenateTablesProxyModel);
Q_ASSERT(sourceModel);
- Q_ASSERT(!d->m_models.contains(sourceModel));
- connect(sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), this, SLOT(_q_slotDataChanged(QModelIndex,QModelIndex,QVector<int>)));
- connect(sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(_q_slotRowsInserted(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(_q_slotRowsRemoved(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_slotRowsAboutToBeInserted(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_slotRowsAboutToBeRemoved(QModelIndex,int,int)));
-
- connect(sourceModel, SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(_q_slotColumnsInserted(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(_q_slotColumnsRemoved(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_slotColumnsAboutToBeInserted(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_slotColumnsAboutToBeRemoved(QModelIndex,int,int)));
-
- connect(sourceModel, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_slotSourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint)));
- connect(sourceModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_slotSourceLayoutChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint)));
- connect(sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_slotModelAboutToBeReset()));
- connect(sourceModel, SIGNAL(modelReset()), this, SLOT(_q_slotModelReset()));
+ Q_ASSERT(!d->containsSourceModel(sourceModel));
const int newRows = sourceModel->rowCount();
if (newRows > 0)
beginInsertRows(QModelIndex(), d->m_rowCount, d->m_rowCount + newRows - 1);
d->m_rowCount += newRows;
- d->m_models.append(sourceModel);
+ d->m_models.emplace_back(sourceModel, std::array{
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::dataChanged,
+ d, &QConcatenateTablesProxyModelPrivate::slotDataChanged),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsInserted,
+ d, &QConcatenateTablesProxyModelPrivate::slotRowsInserted),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsRemoved,
+ d, &QConcatenateTablesProxyModelPrivate::slotRowsRemoved),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsAboutToBeInserted,
+ d, &QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeInserted),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved,
+ d, &QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeRemoved),
+
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsInserted,
+ d, &QConcatenateTablesProxyModelPrivate::slotColumnsInserted),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsRemoved,
+ d, &QConcatenateTablesProxyModelPrivate::slotColumnsRemoved),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsAboutToBeInserted,
+ d, &QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeInserted),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved,
+ d, &QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeRemoved),
+
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged,
+ d, &QConcatenateTablesProxyModelPrivate::slotSourceLayoutAboutToBeChanged),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::layoutChanged,
+ d, &QConcatenateTablesProxyModelPrivate::slotSourceLayoutChanged),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset,
+ d, &QConcatenateTablesProxyModelPrivate::slotModelAboutToBeReset),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::modelReset,
+ d, &QConcatenateTablesProxyModelPrivate::slotModelReset),
+ });
if (newRows > 0)
endInsertRows();
@@ -496,15 +505,18 @@ void QConcatenateTablesProxyModel::addSourceModel(QAbstractItemModel *sourceMode
void QConcatenateTablesProxyModel::removeSourceModel(QAbstractItemModel *sourceModel)
{
Q_D(QConcatenateTablesProxyModel);
- Q_ASSERT(d->m_models.contains(sourceModel));
- disconnect(sourceModel, nullptr, this, nullptr);
+
+ auto it = d->findSourceModel(sourceModel);
+ Q_ASSERT(it != d->m_models.cend());
+ for (auto &c : it->connections)
+ disconnect(c);
const int rowsRemoved = sourceModel->rowCount();
const int rowsPrior = d->computeRowsPrior(sourceModel); // location of removed section
if (rowsRemoved > 0)
beginRemoveRows(QModelIndex(), rowsPrior, rowsPrior + rowsRemoved - 1);
- d->m_models.removeOne(sourceModel);
+ d->m_models.erase(it);
d->m_rowCount -= rowsRemoved;
if (rowsRemoved > 0)
endRemoveRows();
@@ -512,7 +524,8 @@ void QConcatenateTablesProxyModel::removeSourceModel(QAbstractItemModel *sourceM
d->updateColumnCount();
}
-void QConcatenateTablesProxyModelPrivate::_q_slotRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeInserted(const QModelIndex &parent,
+ int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // not supported, the proxy is a flat model
@@ -522,7 +535,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotRowsAboutToBeInserted(const QMo
q->beginInsertRows(QModelIndex(), rowsPrior + start, rowsPrior + end);
}
-void QConcatenateTablesProxyModelPrivate::_q_slotRowsInserted(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotRowsInserted(const QModelIndex &parent, int start,
+ int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -531,7 +545,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotRowsInserted(const QModelIndex
q->endInsertRows();
}
-void QConcatenateTablesProxyModelPrivate::_q_slotRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeRemoved(const QModelIndex &parent,
+ int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -541,7 +556,7 @@ void QConcatenateTablesProxyModelPrivate::_q_slotRowsAboutToBeRemoved(const QMod
q->beginRemoveRows(QModelIndex(), rowsPrior + start, rowsPrior + end);
}
-void QConcatenateTablesProxyModelPrivate::_q_slotRowsRemoved(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotRowsRemoved(const QModelIndex &parent, int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -550,7 +565,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotRowsRemoved(const QModelIndex &
q->endRemoveRows();
}
-void QConcatenateTablesProxyModelPrivate::_q_slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeInserted(const QModelIndex &parent,
+ int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -566,7 +582,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotColumnsAboutToBeInserted(const
m_newColumnCount = newColCount;
}
-void QConcatenateTablesProxyModelPrivate::_q_slotColumnsInserted(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotColumnsInserted(const QModelIndex &parent, int start,
+ int end)
{
Q_UNUSED(start);
Q_UNUSED(end);
@@ -579,7 +596,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotColumnsInserted(const QModelInd
}
}
-void QConcatenateTablesProxyModelPrivate::_q_slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeRemoved(const QModelIndex &parent,
+ int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -593,7 +611,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotColumnsAboutToBeRemoved(const Q
m_newColumnCount = newColCount;
}
-void QConcatenateTablesProxyModelPrivate::_q_slotColumnsRemoved(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotColumnsRemoved(const QModelIndex &parent, int start,
+ int end)
{
Q_Q(QConcatenateTablesProxyModel);
Q_UNUSED(start);
@@ -606,19 +625,27 @@ void QConcatenateTablesProxyModelPrivate::_q_slotColumnsRemoved(const QModelInde
}
}
-void QConcatenateTablesProxyModelPrivate::_q_slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QVector<int> &roles)
+void QConcatenateTablesProxyModelPrivate::slotDataChanged(const QModelIndex &from,
+ const QModelIndex &to,
+ const QList<int> &roles)
{
Q_Q(QConcatenateTablesProxyModel);
Q_ASSERT(from.isValid());
Q_ASSERT(to.isValid());
+ if (from.column() >= m_columnCount)
+ return;
+ QModelIndex adjustedTo = to;
+ if (to.column() >= m_columnCount)
+ adjustedTo = to.siblingAtColumn(m_columnCount - 1);
const QModelIndex myFrom = q->mapFromSource(from);
Q_ASSERT(q->checkIndex(myFrom, QAbstractItemModel::CheckIndexOption::IndexIsValid));
- const QModelIndex myTo = q->mapFromSource(to);
+ const QModelIndex myTo = q->mapFromSource(adjustedTo);
Q_ASSERT(q->checkIndex(myTo, QAbstractItemModel::CheckIndexOption::IndexIsValid));
emit q->dataChanged(myFrom, myTo, roles);
}
-void QConcatenateTablesProxyModelPrivate::_q_slotSourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
+void QConcatenateTablesProxyModelPrivate::slotSourceLayoutAboutToBeChanged(
+ const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QConcatenateTablesProxyModel);
@@ -631,7 +658,7 @@ void QConcatenateTablesProxyModelPrivate::_q_slotSourceLayoutAboutToBeChanged(co
layoutChangePersistentIndexes.reserve(persistentIndexList.size());
layoutChangeProxyIndexes.reserve(persistentIndexList.size());
- for (const QPersistentModelIndex &proxyPersistentIndex : persistentIndexList) {
+ for (const QModelIndex &proxyPersistentIndex : persistentIndexList) {
layoutChangeProxyIndexes.append(proxyPersistentIndex);
Q_ASSERT(proxyPersistentIndex.isValid());
const QPersistentModelIndex srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
@@ -640,7 +667,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotSourceLayoutAboutToBeChanged(co
}
}
-void QConcatenateTablesProxyModelPrivate::_q_slotSourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
+void QConcatenateTablesProxyModelPrivate::slotSourceLayoutChanged(
+ const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QConcatenateTablesProxyModel);
if (!sourceParents.isEmpty() && !sourceParents.contains(QModelIndex()))
@@ -657,20 +685,20 @@ void QConcatenateTablesProxyModelPrivate::_q_slotSourceLayoutChanged(const QList
emit q->layoutChanged({}, hint);
}
-void QConcatenateTablesProxyModelPrivate::_q_slotModelAboutToBeReset()
+void QConcatenateTablesProxyModelPrivate::slotModelAboutToBeReset()
{
Q_Q(QConcatenateTablesProxyModel);
- Q_ASSERT(m_models.contains(const_cast<QAbstractItemModel *>(static_cast<const QAbstractItemModel *>(q->sender()))));
+ Q_ASSERT(containsSourceModel(static_cast<QAbstractItemModel *>(q->sender())));
q->beginResetModel();
// A reset might reduce both rowCount and columnCount, and we can't notify of both at the same time,
// and notifying of one after the other leaves an intermediary invalid situation.
// So the only safe choice is to forward it as a full reset.
}
-void QConcatenateTablesProxyModelPrivate::_q_slotModelReset()
+void QConcatenateTablesProxyModelPrivate::slotModelReset()
{
Q_Q(QConcatenateTablesProxyModel);
- Q_ASSERT(m_models.contains(const_cast<QAbstractItemModel *>(static_cast<const QAbstractItemModel *>(q->sender()))));
+ Q_ASSERT(containsSourceModel(static_cast<QAbstractItemModel *>(q->sender())));
m_columnCount = calculatedColumnCount();
m_rowCount = computeRowsPrior(nullptr);
q->endResetModel();
@@ -681,10 +709,11 @@ int QConcatenateTablesProxyModelPrivate::calculatedColumnCount() const
if (m_models.isEmpty())
return 0;
- const auto it = std::min_element(m_models.begin(), m_models.end(), [](const QAbstractItemModel* model1, const QAbstractItemModel* model2) {
- return model1->columnCount() < model2->columnCount();
- });
- return (*it)->columnCount();
+ auto byColumnCount = [](const auto &a, const auto &b) {
+ return a.model->columnCount() < b.model->columnCount();
+ };
+ const auto it = std::min_element(m_models.begin(), m_models.end(), byColumnCount);
+ return it->model->columnCount();
}
void QConcatenateTablesProxyModelPrivate::updateColumnCount()
@@ -707,8 +736,8 @@ void QConcatenateTablesProxyModelPrivate::updateColumnCount()
int QConcatenateTablesProxyModelPrivate::columnCountAfterChange(const QAbstractItemModel *model, int newCount) const
{
int newColumnCount = 0;
- for (int i = 0; i < m_models.count(); ++i) {
- const QAbstractItemModel *mod = m_models.at(i);
+ for (qsizetype i = 0; i < m_models.size(); ++i) {
+ const QAbstractItemModel *mod = m_models.at(i).model;
const int colCount = mod == model ? newCount : mod->columnCount();
if (i == 0)
newColumnCount = colCount;
@@ -721,7 +750,7 @@ int QConcatenateTablesProxyModelPrivate::columnCountAfterChange(const QAbstractI
int QConcatenateTablesProxyModelPrivate::computeRowsPrior(const QAbstractItemModel *sourceModel) const
{
int rowsPrior = 0;
- for (const QAbstractItemModel *model : m_models) {
+ for (const auto &[model, _] : m_models) {
if (model == sourceModel)
break;
rowsPrior += model->rowCount();
@@ -733,7 +762,7 @@ QConcatenateTablesProxyModelPrivate::SourceModelForRowResult QConcatenateTablesP
{
QConcatenateTablesProxyModelPrivate::SourceModelForRowResult result;
int rowCount = 0;
- for (QAbstractItemModel *model : m_models) {
+ for (const auto &[model, _] : m_models) {
const int subRowCount = model->rowCount();
if (rowCount + subRowCount > row) {
result.sourceModel = model;
diff --git a/src/corelib/itemmodels/qconcatenatetablesproxymodel.h b/src/corelib/itemmodels/qconcatenatetablesproxymodel.h
index 69b3a2ba09..9dbebd7b88 100644
--- a/src/corelib/itemmodels/qconcatenatetablesproxymodel.h
+++ b/src/corelib/itemmodels/qconcatenatetablesproxymodel.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCONCATENATEROWSPROXYMODEL_H
#define QCONCATENATEROWSPROXYMODEL_H
@@ -56,6 +20,7 @@ public:
explicit QConcatenateTablesProxyModel(QObject *parent = nullptr);
~QConcatenateTablesProxyModel();
+ QList<QAbstractItemModel *> sourceModels() const;
Q_SCRIPTABLE void addSourceModel(QAbstractItemModel *sourceModel);
Q_SCRIPTABLE void removeSourceModel(QAbstractItemModel *sourceModel);
@@ -81,20 +46,6 @@ public:
private:
Q_DECLARE_PRIVATE(QConcatenateTablesProxyModel)
Q_DISABLE_COPY(QConcatenateTablesProxyModel)
-
- Q_PRIVATE_SLOT(d_func(), void _q_slotRowsAboutToBeInserted(const QModelIndex &, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotRowsInserted(const QModelIndex &, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotRowsAboutToBeRemoved(const QModelIndex &, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotRowsRemoved(const QModelIndex &, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotColumnsInserted(const QModelIndex &parent, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotColumnsRemoved(const QModelIndex &parent, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QVector<int> &roles))
- Q_PRIVATE_SLOT(d_func(), void _q_slotSourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint))
- Q_PRIVATE_SLOT(d_func(), void _q_slotSourceLayoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint))
- Q_PRIVATE_SLOT(d_func(), void _q_slotModelAboutToBeReset())
- Q_PRIVATE_SLOT(d_func(), void _q_slotModelReset())
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qidentityproxymodel.cpp b/src/corelib/itemmodels/qidentityproxymodel.cpp
index f5684c6eda..89fa7e5c07 100644
--- a/src/corelib/itemmodels/qidentityproxymodel.cpp
+++ b/src/corelib/itemmodels/qidentityproxymodel.cpp
@@ -1,84 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qidentityproxymodel.h"
+#include "qidentityproxymodel_p.h"
#include "qitemselectionmodel.h"
#include <private/qabstractproxymodel_p.h>
QT_BEGIN_NAMESPACE
-class QIdentityProxyModelPrivate : public QAbstractProxyModelPrivate
-{
- QIdentityProxyModelPrivate()
- {
-
- }
-
- Q_DECLARE_PUBLIC(QIdentityProxyModel)
-
- QList<QPersistentModelIndex> layoutChangePersistentIndexes;
- QModelIndexList proxyIndexes;
-
- void _q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_sourceRowsInserted(const QModelIndex &parent, int start, int end);
- void _q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_sourceRowsRemoved(const QModelIndex &parent, int start, int end);
- void _q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest);
- void _q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest);
-
- void _q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_sourceColumnsInserted(const QModelIndex &parent, int start, int end);
- void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end);
- void _q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest);
- void _q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest);
-
- void _q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
- void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last);
-
- void _q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
- void _q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
- void _q_sourceModelAboutToBeReset();
- void _q_sourceModelReset();
-
-};
-
/*!
\since 4.8
\class QIdentityProxyModel
@@ -215,7 +144,7 @@ QItemSelection QIdentityProxyModel::mapSelectionFromSource(const QItemSelection&
QItemSelection::const_iterator it = selection.constBegin();
const QItemSelection::const_iterator end = selection.constEnd();
- proxySelection.reserve(selection.count());
+ proxySelection.reserve(selection.size());
for ( ; it != end; ++it) {
Q_ASSERT(it->model() == d->model);
const QItemSelectionRange range(mapFromSource(it->topLeft()), mapFromSource(it->bottomRight()));
@@ -238,7 +167,7 @@ QItemSelection QIdentityProxyModel::mapSelectionToSource(const QItemSelection& s
QItemSelection::const_iterator it = selection.constBegin();
const QItemSelection::const_iterator end = selection.constEnd();
- sourceSelection.reserve(selection.count());
+ sourceSelection.reserve(selection.size());
for ( ; it != end; ++it) {
Q_ASSERT(it->model() == this);
const QItemSelectionRange range(mapToSource(it->topLeft()), mapToSource(it->bottomRight()));
@@ -257,7 +186,7 @@ QModelIndex QIdentityProxyModel::mapToSource(const QModelIndex& proxyIndex) cons
if (!d->model || !proxyIndex.isValid())
return QModelIndex();
Q_ASSERT(proxyIndex.model() == this);
- return d->model->createIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer());
+ return createSourceIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer());
}
/*!
@@ -274,7 +203,7 @@ QModelIndexList QIdentityProxyModel::match(const QModelIndex& start, int role, c
QModelIndexList::const_iterator it = sourceList.constBegin();
const QModelIndexList::const_iterator end = sourceList.constEnd();
QModelIndexList proxyList;
- proxyList.reserve(sourceList.count());
+ proxyList.reserve(sourceList.size());
for ( ; it != end; ++it)
proxyList.append(mapFromSource(*it));
return proxyList;
@@ -361,97 +290,108 @@ void QIdentityProxyModel::setSourceModel(QAbstractItemModel* newSourceModel)
{
beginResetModel();
- if (sourceModel()) {
- disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(sourceModel(), SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(sourceModel(), SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(sourceModel(), SIGNAL(modelAboutToBeReset()),
- this, SLOT(_q_sourceModelAboutToBeReset()));
- disconnect(sourceModel(), SIGNAL(modelReset()),
- this, SLOT(_q_sourceModelReset()));
- disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>)));
- disconnect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
- disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
- disconnect(sourceModel(), SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
- }
+ Q_D(QIdentityProxyModel);
+
+ // Call QObject::disconnect() unconditionally, if there is an existing source
+ // model, it's disconnected, and if there isn't, then calling disconnect() on
+ // a default-constructed Connection does nothing
+ for (const auto &c : d->m_sourceModelConnections)
+ QObject::disconnect(c);
QAbstractProxyModel::setSourceModel(newSourceModel);
if (sourceModel()) {
- connect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(sourceModel(), SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(columnsInserted(QModelIndex,int,int)),
- SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(columnsRemoved(QModelIndex,int,int)),
- SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(sourceModel(), SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(sourceModel(), SIGNAL(modelAboutToBeReset()),
- SLOT(_q_sourceModelAboutToBeReset()));
- connect(sourceModel(), SIGNAL(modelReset()),
- SLOT(_q_sourceModelReset()));
- connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>)));
- connect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
- connect(sourceModel(), SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
- connect(sourceModel(), SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ auto *m = sourceModel();
+ d->m_sourceModelConnections = {
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeInserted, d,
+ &QIdentityProxyModelPrivate::sourceRowsAboutToBeInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsInserted, d,
+ &QIdentityProxyModelPrivate::sourceRowsInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeRemoved, d,
+ &QIdentityProxyModelPrivate::sourceRowsAboutToBeRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsRemoved, d,
+ &QIdentityProxyModelPrivate::sourceRowsRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeMoved, d,
+ &QIdentityProxyModelPrivate::sourceRowsAboutToBeMoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsMoved, d,
+ &QIdentityProxyModelPrivate::sourceRowsMoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeInserted, d,
+ &QIdentityProxyModelPrivate::sourceColumnsAboutToBeInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsInserted, d,
+ &QIdentityProxyModelPrivate::sourceColumnsInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeRemoved, d,
+ &QIdentityProxyModelPrivate::sourceColumnsAboutToBeRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsRemoved, d,
+ &QIdentityProxyModelPrivate::sourceColumnsRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeMoved, d,
+ &QIdentityProxyModelPrivate::sourceColumnsAboutToBeMoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsMoved, d,
+ &QIdentityProxyModelPrivate::sourceColumnsMoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::modelAboutToBeReset, d,
+ &QIdentityProxyModelPrivate::sourceModelAboutToBeReset),
+ QObjectPrivate::connect(m, &QAbstractItemModel::modelReset, d,
+ &QIdentityProxyModelPrivate::sourceModelReset),
+ QObjectPrivate::connect(m, &QAbstractItemModel::dataChanged, d,
+ &QIdentityProxyModelPrivate::sourceDataChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::headerDataChanged, d,
+ &QIdentityProxyModelPrivate::sourceHeaderDataChanged),
+ };
+
+ if (d->m_handleLayoutChanges) {
+ d->m_sourceModelConnections.emplace_back(
+ QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged, d,
+ &QIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged));
+ d->m_sourceModelConnections.emplace_back(
+ QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged, d,
+ &QIdentityProxyModelPrivate::sourceLayoutChanged));
+ }
}
endResetModel();
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+/*!
+ \since 6.7
+
+ If \a b is \c true, this proxy model will handle the source model layout
+ changes (by connecting to \c QAbstractItemModel::layoutAboutToBeChanged
+ and \c QAbstractItemModel::layoutChanged singals).
+
+ The default is for this proxy model to handle the source model layout
+ changes.
+
+ In sub-classes of QIdentityProxyModel, it may be useful to set this to
+ \c false if you need to specially handle the source model layout changes.
+
+ \note Calling this method will only have an effect after calling setSourceModel().
+*/
+void QIdentityProxyModel::setHandleSourceLayoutChanges(bool b)
+{
+ d_func()->m_handleLayoutChanges = b;
+}
+
+/*!
+ \since 6.7
+
+ Returns \c true if this proxy model handles the source model layout
+ changes, otherwise returns \c false.
+*/
+bool QIdentityProxyModel::isHandleSourceLayoutChanges() const
+{
+ return d_func()->m_handleLayoutChanges;
+}
+
+void QIdentityProxyModelPrivate::sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
q->beginInsertColumns(q->mapFromSource(parent), start, end);
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest)
+void QIdentityProxyModelPrivate::sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent,
+ int sourceStart, int sourceEnd,
+ const QModelIndex &destParent,
+ int dest)
{
Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true);
Q_ASSERT(destParent.isValid() ? destParent.model() == model : true);
@@ -459,47 +399,51 @@ void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(const QModelInde
q->beginMoveColumns(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest);
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
q->beginRemoveColumns(q->mapFromSource(parent), start, end);
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsInserted(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceColumnsInserted(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
- Q_UNUSED(parent)
- Q_UNUSED(start)
- Q_UNUSED(end)
+ Q_UNUSED(parent);
+ Q_UNUSED(start);
+ Q_UNUSED(end);
q->endInsertColumns();
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest)
+void QIdentityProxyModelPrivate::sourceColumnsMoved(const QModelIndex &sourceParent,
+ int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest)
{
Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true);
Q_ASSERT(destParent.isValid() ? destParent.model() == model : true);
Q_Q(QIdentityProxyModel);
- Q_UNUSED(sourceParent)
- Q_UNUSED(sourceStart)
- Q_UNUSED(sourceEnd)
- Q_UNUSED(destParent)
- Q_UNUSED(dest)
+ Q_UNUSED(sourceParent);
+ Q_UNUSED(sourceStart);
+ Q_UNUSED(sourceEnd);
+ Q_UNUSED(destParent);
+ Q_UNUSED(dest);
q->endMoveColumns();
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceColumnsRemoved(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
- Q_UNUSED(parent)
- Q_UNUSED(start)
- Q_UNUSED(end)
+ Q_UNUSED(parent);
+ Q_UNUSED(start);
+ Q_UNUSED(end);
q->endRemoveColumns();
}
-void QIdentityProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
+void QIdentityProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight,
+ const QList<int> &roles)
{
Q_ASSERT(topLeft.isValid() ? topLeft.model() == model : true);
Q_ASSERT(bottomRight.isValid() ? bottomRight.model() == model : true);
@@ -507,13 +451,15 @@ void QIdentityProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &topLeft
emit q->dataChanged(q->mapFromSource(topLeft), q->mapFromSource(bottomRight), roles);
}
-void QIdentityProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last)
+void QIdentityProxyModelPrivate::sourceHeaderDataChanged(Qt::Orientation orientation, int first,
+ int last)
{
Q_Q(QIdentityProxyModel);
emit q->headerDataChanged(orientation, first, last);
}
-void QIdentityProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
+void QIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged(
+ const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QIdentityProxyModel);
@@ -532,7 +478,7 @@ void QIdentityProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList<QPe
emit q->layoutAboutToBeChanged(parents, hint);
const auto proxyPersistentIndexes = q->persistentIndexList();
- for (const QPersistentModelIndex &proxyPersistentIndex : proxyPersistentIndexes) {
+ for (const QModelIndex &proxyPersistentIndex : proxyPersistentIndexes) {
proxyIndexes << proxyPersistentIndex;
Q_ASSERT(proxyPersistentIndex.isValid());
const QPersistentModelIndex srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
@@ -541,7 +487,8 @@ void QIdentityProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList<QPe
}
}
-void QIdentityProxyModelPrivate::_q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
+void QIdentityProxyModelPrivate::sourceLayoutChanged(
+ const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QIdentityProxyModel);
@@ -567,26 +514,29 @@ void QIdentityProxyModelPrivate::_q_sourceLayoutChanged(const QList<QPersistentM
emit q->layoutChanged(parents, hint);
}
-void QIdentityProxyModelPrivate::_q_sourceModelAboutToBeReset()
+void QIdentityProxyModelPrivate::sourceModelAboutToBeReset()
{
Q_Q(QIdentityProxyModel);
q->beginResetModel();
}
-void QIdentityProxyModelPrivate::_q_sourceModelReset()
+void QIdentityProxyModelPrivate::sourceModelReset()
{
Q_Q(QIdentityProxyModel);
q->endResetModel();
}
-void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start,
+ int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
q->beginInsertRows(q->mapFromSource(parent), start, end);
}
-void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest)
+void QIdentityProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &sourceParent,
+ int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest)
{
Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true);
Q_ASSERT(destParent.isValid() ? destParent.model() == model : true);
@@ -594,43 +544,46 @@ void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeMoved(const QModelIndex &
q->beginMoveRows(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest);
}
-void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start,
+ int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
q->beginRemoveRows(q->mapFromSource(parent), start, end);
}
-void QIdentityProxyModelPrivate::_q_sourceRowsInserted(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
- Q_UNUSED(parent)
- Q_UNUSED(start)
- Q_UNUSED(end)
+ Q_UNUSED(parent);
+ Q_UNUSED(start);
+ Q_UNUSED(end);
q->endInsertRows();
}
-void QIdentityProxyModelPrivate::_q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest)
+void QIdentityProxyModelPrivate::sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart,
+ int sourceEnd, const QModelIndex &destParent,
+ int dest)
{
Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true);
Q_ASSERT(destParent.isValid() ? destParent.model() == model : true);
Q_Q(QIdentityProxyModel);
- Q_UNUSED(sourceParent)
- Q_UNUSED(sourceStart)
- Q_UNUSED(sourceEnd)
- Q_UNUSED(destParent)
- Q_UNUSED(dest)
+ Q_UNUSED(sourceParent);
+ Q_UNUSED(sourceStart);
+ Q_UNUSED(sourceEnd);
+ Q_UNUSED(destParent);
+ Q_UNUSED(dest);
q->endMoveRows();
}
-void QIdentityProxyModelPrivate::_q_sourceRowsRemoved(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
- Q_UNUSED(parent)
- Q_UNUSED(start)
- Q_UNUSED(end)
+ Q_UNUSED(parent);
+ Q_UNUSED(start);
+ Q_UNUSED(end);
q->endRemoveRows();
}
diff --git a/src/corelib/itemmodels/qidentityproxymodel.h b/src/corelib/itemmodels/qidentityproxymodel.h
index 4c14e6176a..c8fc9d21b7 100644
--- a/src/corelib/itemmodels/qidentityproxymodel.h
+++ b/src/corelib/itemmodels/qidentityproxymodel.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIDENTITYPROXYMODEL_H
@@ -80,34 +44,15 @@ public:
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override;
bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild) override;
+ bool isHandleSourceLayoutChanges() const;
+
protected:
QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent);
+ void setHandleSourceLayoutChanges(bool);
private:
Q_DECLARE_PRIVATE(QIdentityProxyModel)
Q_DISABLE_COPY(QIdentityProxyModel)
-
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeInserted(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsInserted(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeRemoved(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsRemoved(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))
-
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeInserted(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsInserted(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsRemoved(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int))
-
- Q_PRIVATE_SLOT(d_func(), void _q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last))
-
- Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceModelAboutToBeReset())
- Q_PRIVATE_SLOT(d_func(), void _q_sourceModelReset())
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qidentityproxymodel_p.h b/src/corelib/itemmodels/qidentityproxymodel_p.h
new file mode 100644
index 0000000000..78e1f5316c
--- /dev/null
+++ b/src/corelib/itemmodels/qidentityproxymodel_p.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QIDENTITYPROXYMODEL_P_H
+#define QIDENTITYPROXYMODEL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QAbstractItemModel*. This header file may change from version
+// to version without notice, or even be removed.
+//
+// We mean it.
+//
+//
+
+#include <QtCore/private/qabstractproxymodel_p.h>
+#include <QtCore/qidentityproxymodel.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_CORE_EXPORT QIdentityProxyModelPrivate : public QAbstractProxyModelPrivate
+{
+ Q_DECLARE_PUBLIC(QIdentityProxyModel)
+
+public:
+ QIdentityProxyModelPrivate()
+ {
+ }
+
+ QList<QPersistentModelIndex> layoutChangePersistentIndexes;
+ QModelIndexList proxyIndexes;
+
+ void sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void sourceRowsInserted(const QModelIndex &parent, int start, int end);
+ void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
+ void sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest);
+ void sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest);
+
+ void sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void sourceColumnsInserted(const QModelIndex &parent, int start, int end);
+ void sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void sourceColumnsRemoved(const QModelIndex &parent, int start, int end);
+ void sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart,
+ int sourceEnd, const QModelIndex &destParent, int dest);
+ void sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest);
+
+ void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &roles);
+ void sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last);
+
+ void sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents,
+ QAbstractItemModel::LayoutChangeHint hint);
+ void sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents,
+ QAbstractItemModel::LayoutChangeHint hint);
+ void sourceModelAboutToBeReset();
+ void sourceModelReset();
+
+private:
+ bool m_handleLayoutChanges = true;
+ QVarLengthArray<QMetaObject::Connection, 18> m_sourceModelConnections;
+};
+
+QT_END_NAMESPACE
+
+#endif // QIDENTITYPROXYMODEL_P_H
diff --git a/src/corelib/itemmodels/qitemselectionmodel.cpp b/src/corelib/itemmodels/qitemselectionmodel.cpp
index e4ac5da299..6df60aaf61 100644
--- a/src/corelib/itemmodels/qitemselectionmodel.cpp
+++ b/src/corelib/itemmodels/qitemselectionmodel.cpp
@@ -1,44 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qitemselectionmodel.h"
+#include "qitemselectionmodel_p.h"
+
#include <private/qitemselectionmodel_p.h>
+#include <private/qabstractitemmodel_p.h>
+#include <private/qduplicatetracker_p.h>
+#include <private/qoffsetstringarray_p.h>
#include <qdebug.h>
#include <algorithm>
@@ -46,6 +15,9 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QItemSelectionRange)
+QT_IMPL_METATYPE_EXTERN(QItemSelection)
+
/*!
\class QItemSelectionRange
\inmodule QtCore
@@ -55,6 +27,8 @@ QT_BEGIN_NAMESPACE
\ingroup model-view
+ \compares equality
+
A QItemSelectionRange contains information about a range of
selected items in a model. A range of items is a contiguous array
of model items, extending to cover a number of adjacent rows and
@@ -86,14 +60,6 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QItemSelectionRange::QItemSelectionRange(const QItemSelectionRange &other)
-
- Copy constructor. Constructs a new selection range with the same contents
- as the \a other range given.
-
-*/
-
-/*!
\fn QItemSelectionRange::QItemSelectionRange(const QModelIndex &topLeft, const QModelIndex &bottomRight)
Constructs a new selection range containing only the index specified
@@ -230,13 +196,6 @@ bool QItemSelectionRange::intersects(const QItemSelectionRange &other) const
}
/*!
- \fn QItemSelectionRange QItemSelectionRange::intersect(const QItemSelectionRange &other) const
- \obsolete
-
- Use intersected(\a other) instead.
-*/
-
-/*!
\fn QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &other) const
\since 4.2
@@ -259,68 +218,29 @@ QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &
}
/*!
- \fn bool QItemSelectionRange::operator==(const QItemSelectionRange &other) const
+ \fn bool QItemSelectionRange::operator==(const QItemSelectionRange &lhs, const QItemSelectionRange &rhs)
- Returns \c true if the selection range is exactly the same as the \a other
+ Returns \c true if \a lhs selection range is exactly the same as the \a rhs
range given; otherwise returns \c false.
*/
/*!
- \fn bool QItemSelectionRange::operator!=(const QItemSelectionRange &other) const
+ \fn bool QItemSelectionRange::operator!=(const QItemSelectionRange &lhs, const QItemSelectionRange &rhs)
- Returns \c true if the selection range differs from the \a other range given;
+ Returns \c true if \a lhs selection range differs from the \a rhs range given;
otherwise returns \c false.
*/
/*!
- Returns \c true if the selection range is less than the \a other
- range given; otherwise returns \c false.
-
- The less than calculation is not directly useful to developers - the way that ranges
- with different parents compare is not defined. This operator only exists so that the
- class can be used with QMap.
-
-*/
-bool QItemSelectionRange::operator<(const QItemSelectionRange &other) const
-{
- // ### Qt 6: This is inconsistent with op== and needs to be fixed, nay,
- // ### removed, but cannot, because it was inline up to and including 5.9
-
- // Comparing parents will compare the models, but if two equivalent ranges
- // in two different models have invalid parents, they would appear the same
- if (other.tl.model() == tl.model()) {
- // parent has to be calculated, so we only do so once.
- const QModelIndex topLeftParent = tl.parent();
- const QModelIndex otherTopLeftParent = other.tl.parent();
- if (topLeftParent == otherTopLeftParent) {
- if (other.tl.row() == tl.row()) {
- if (other.tl.column() == tl.column()) {
- if (other.br.row() == br.row()) {
- return br.column() < other.br.column();
- }
- return br.row() < other.br.row();
- }
- return tl.column() < other.tl.column();
- }
- return tl.row() < other.tl.row();
- }
- return topLeftParent < otherTopLeftParent;
- }
-
- std::less<const QAbstractItemModel *> less;
- return less(tl.model(), other.tl.model());
-}
-
-/*!
\fn bool QItemSelectionRange::isValid() const
Returns \c true if the selection range is valid; otherwise returns \c false.
*/
-static void rowLengthsFromRange(const QItemSelectionRange &range, QVector<QPair<QPersistentModelIndex, uint> > &result)
+static void rowLengthsFromRange(const QItemSelectionRange &range, QList<std::pair<QPersistentModelIndex, uint>> &result)
{
if (range.isValid() && range.model()) {
const QModelIndex topLeft = range.topLeft();
@@ -331,11 +251,16 @@ static void rowLengthsFromRange(const QItemSelectionRange &range, QVector<QPair<
// We don't need to keep track of ItemIsSelectable and ItemIsEnabled here. That is
// required in indexesFromRange() because that method is called from public API
// which requires the limitation.
- result.push_back(qMakePair(QPersistentModelIndex(topLeft.sibling(row, column)), width));
+ result.emplace_back(topLeft.sibling(row, column), width);
}
}
}
+static bool isSelectableAndEnabled(Qt::ItemFlags flags)
+{
+ return flags.testFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+}
+
template<typename ModelIndexContainer>
static void indexesFromRange(const QItemSelectionRange &range, ModelIndexContainer &result)
{
@@ -347,8 +272,7 @@ static void indexesFromRange(const QItemSelectionRange &range, ModelIndexContain
const QModelIndex columnLeader = topLeft.sibling(row, topLeft.column());
for (int column = topLeft.column(); column <= right; ++column) {
QModelIndex index = columnLeader.sibling(row, column);
- Qt::ItemFlags flags = range.model()->flags(index);
- if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
+ if (isSelectableAndEnabled(range.model()->flags(index)))
result.push_back(index);
}
}
@@ -365,7 +289,9 @@ static ModelIndexContainer qSelectionIndexes(const QItemSelection &selection)
}
/*!
- Returns \c true if the selection range contains no selectable item
+ Returns \c true if the selection range contains either no items
+ or only items which are either disabled or marked as not selectable.
+
\since 4.7
*/
@@ -377,8 +303,7 @@ bool QItemSelectionRange::isEmpty() const
for (int column = left(); column <= right(); ++column) {
for (int row = top(); row <= bottom(); ++row) {
QModelIndex index = model()->index(row, column, parent());
- Qt::ItemFlags flags = model()->flags(index);
- if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
+ if (isSelectableAndEnabled(model()->flags(index)))
return false;
}
}
@@ -491,7 +416,7 @@ void QItemSelection::select(const QModelIndex &topLeft, const QModelIndex &botto
bool QItemSelection::contains(const QModelIndex &index) const
{
- if (index.flags() & Qt::ItemIsSelectable) {
+ if (isSelectableAndEnabled(index.flags())) {
QList<QItemSelectionRange>::const_iterator it = begin();
for (; it != end(); ++it)
if ((*it).contains(index))
@@ -509,9 +434,9 @@ QModelIndexList QItemSelection::indexes() const
return qSelectionIndexes<QModelIndexList>(*this);
}
-static QVector<QPair<QPersistentModelIndex, uint> > qSelectionPersistentRowLengths(const QItemSelection &sel)
+static QList<std::pair<QPersistentModelIndex, uint>> qSelectionPersistentRowLengths(const QItemSelection &sel)
{
- QVector<QPair<QPersistentModelIndex, uint> > result;
+ QList<std::pair<QPersistentModelIndex, uint>> result;
for (const QItemSelectionRange &range : sel)
rowLengthsFromRange(range, result);
return result;
@@ -535,25 +460,23 @@ void QItemSelection::merge(const QItemSelection &other, QItemSelectionModel::Sel
command & QItemSelectionModel::Toggle))
return;
- QItemSelection newSelection = other;
+ QItemSelection newSelection;
+ newSelection.reserve(other.size());
// Collect intersections
QItemSelection intersections;
- QItemSelection::iterator it = newSelection.begin();
- while (it != newSelection.end()) {
- if (!(*it).isValid()) {
- it = newSelection.erase(it);
+ for (const auto &range : other) {
+ if (!range.isValid())
continue;
+ newSelection.push_back(range);
+ for (int t = 0; t < size(); ++t) {
+ if (range.intersects(at(t)))
+ intersections.append(at(t).intersected(range));
}
- for (int t = 0; t < count(); ++t) {
- if ((*it).intersects(at(t)))
- intersections.append(at(t).intersected(*it));
- }
- ++it;
}
// Split the old (and new) ranges using the intersections
- for (int i = 0; i < intersections.count(); ++i) { // for each intersection
- for (int t = 0; t < count();) { // splitt each old range
+ for (int i = 0; i < intersections.size(); ++i) { // for each intersection
+ for (int t = 0; t < size();) { // splitt each old range
if (at(t).intersects(intersections.at(i))) {
split(at(t), intersections.at(i), this);
removeAt(t);
@@ -562,7 +485,7 @@ void QItemSelection::merge(const QItemSelection &other, QItemSelectionModel::Sel
}
}
// only split newSelection if Toggle is specified
- for (int n = 0; (command & QItemSelectionModel::Toggle) && n < newSelection.count();) {
+ for (int n = 0; (command & QItemSelectionModel::Toggle) && n < newSelection.size();) {
if (newSelection.at(n).intersects(intersections.at(i))) {
split(newSelection.at(n), intersections.at(i), &newSelection);
newSelection.removeAt(n);
@@ -629,52 +552,55 @@ void QItemSelection::split(const QItemSelectionRange &range,
void QItemSelectionModelPrivate::initModel(QAbstractItemModel *m)
{
- struct Cx {
- const char *signal;
- const char *slot;
- };
- static const Cx connections[] = {
- { SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)) },
- { SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)) },
- { SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)) },
- { SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- SLOT(_q_columnsAboutToBeInserted(QModelIndex,int,int)) },
- { SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_layoutAboutToBeChanged()) },
- { SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_layoutAboutToBeChanged()) },
- { SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_layoutChanged()) },
- { SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_layoutChanged()) },
- { SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)) },
- { SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)) },
- { SIGNAL(modelReset()),
- SLOT(reset()) },
- { nullptr, nullptr }
- };
-
- if (model == m)
+ Q_Q(QItemSelectionModel);
+ const QAbstractItemModel *oldModel = model.valueBypassingBindings();
+ if (oldModel == m)
return;
- Q_Q(QItemSelectionModel);
- if (model) {
- for (const Cx *cx = &connections[0]; cx->signal; cx++)
- QObject::disconnect(model, cx->signal, q, cx->slot);
+ if (oldModel) {
q->reset();
+ disconnectModel();
}
- model = m;
- if (model) {
- for (const Cx *cx = &connections[0]; cx->signal; cx++)
- QObject::connect(model, cx->signal, q, cx->slot);
+
+ // Caller has to call notify(), unless calling during construction (the common case).
+ model.setValueBypassingBindings(m);
+
+ if (m) {
+ connections = std::array<QMetaObject::Connection, 12> {
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &QItemSelectionModelPrivate::rowsAboutToBeRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeRemoved,
+ this, &QItemSelectionModelPrivate::columnsAboutToBeRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeInserted,
+ this, &QItemSelectionModelPrivate::rowsAboutToBeInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeInserted,
+ this, &QItemSelectionModelPrivate::columnsAboutToBeInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeMoved,
+ this, &QItemSelectionModelPrivate::triggerLayoutToBeChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeMoved,
+ this, &QItemSelectionModelPrivate::triggerLayoutToBeChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsMoved,
+ this, &QItemSelectionModelPrivate::triggerLayoutChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsMoved,
+ this, &QItemSelectionModelPrivate::triggerLayoutChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged,
+ this, &QItemSelectionModelPrivate::layoutAboutToBeChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged,
+ this, &QItemSelectionModelPrivate::layoutChanged),
+ QObject::connect(m, &QAbstractItemModel::modelReset,
+ q, &QItemSelectionModel::reset),
+ QObjectPrivate::connect(m, &QAbstractItemModel::destroyed,
+ this, &QItemSelectionModelPrivate::modelDestroyed)
+ };
}
}
+void QItemSelectionModelPrivate::disconnectModel()
+{
+ for (auto &connection : connections)
+ QObject::disconnect(connection);
+}
+
/*!
\internal
@@ -692,7 +618,7 @@ QItemSelection QItemSelectionModelPrivate::expandSelection(const QItemSelection
QItemSelection expanded;
if (command & QItemSelectionModel::Rows) {
- for (int i = 0; i < selection.count(); ++i) {
+ for (int i = 0; i < selection.size(); ++i) {
QModelIndex parent = selection.at(i).parent();
int colCount = model->columnCount(parent);
QModelIndex tl = model->index(selection.at(i).top(), 0, parent);
@@ -702,7 +628,7 @@ QItemSelection QItemSelectionModelPrivate::expandSelection(const QItemSelection
}
}
if (command & QItemSelectionModel::Columns) {
- for (int i = 0; i < selection.count(); ++i) {
+ for (int i = 0; i < selection.size(); ++i) {
QModelIndex parent = selection.at(i).parent();
int rowCount = model->rowCount(parent);
QModelIndex tl = model->index(0, selection.at(i).left(), parent);
@@ -717,22 +643,27 @@ QItemSelection QItemSelectionModelPrivate::expandSelection(const QItemSelection
/*!
\internal
*/
-void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &parent,
+void QItemSelectionModelPrivate::rowsAboutToBeRemoved(const QModelIndex &parent,
int start, int end)
{
Q_Q(QItemSelectionModel);
+ Q_ASSERT(start <= end);
finalize();
// update current index
if (currentIndex.isValid() && parent == currentIndex.parent()
&& currentIndex.row() >= start && currentIndex.row() <= end) {
QModelIndex old = currentIndex;
- if (start > 0) // there are rows left above the change
+ if (start > 0) {
+ // there are rows left above the change
currentIndex = model->index(start - 1, old.column(), parent);
- else if (model && end < model->rowCount(parent) - 1) // there are rows left below the change
+ } else if (model.value() && end < model->rowCount(parent) - 1) {
+ // there are rows left below the change
currentIndex = model->index(end + 1, old.column(), parent);
- else // there are no rows left in the table
+ } else {
+ // there are no rows left in the table
currentIndex = QModelIndex();
+ }
emit q->currentChanged(currentIndex, old);
emit q->currentRowChanged(currentIndex, old);
if (currentIndex.column() != old.column())
@@ -741,6 +672,7 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &pare
QItemSelection deselected;
QItemSelection newParts;
+ bool indexesOfSelectionChanged = false;
QItemSelection::iterator it = ranges.begin();
while (it != ranges.end()) {
if (it->topLeft().parent() != parent) { // Check parents until reaching root or contained in range
@@ -752,6 +684,8 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &pare
deselected.append(*it);
it = ranges.erase(it);
} else {
+ if (itParent.isValid() && end < itParent.row())
+ indexesOfSelectionChanged = true;
++it;
}
} else if (start <= it->bottom() && it->bottom() <= end // Full inclusion
@@ -776,19 +710,23 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &pare
deselected.append(removedRange);
QItemSelection::split(*it, removedRange, &newParts);
it = ranges.erase(it);
- } else
+ } else if (end < it->top()) { // deleted row before selection
+ indexesOfSelectionChanged = true;
+ ++it;
+ } else {
++it;
+ }
}
ranges.append(newParts);
- if (!deselected.isEmpty())
+ if (!deselected.isEmpty() || indexesOfSelectionChanged)
emit q->selectionChanged(QItemSelection(), deselected);
}
/*!
\internal
*/
-void QItemSelectionModelPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent,
+void QItemSelectionModelPrivate::columnsAboutToBeRemoved(const QModelIndex &parent,
int start, int end)
{
Q_Q(QItemSelectionModel);
@@ -797,12 +735,16 @@ void QItemSelectionModelPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &p
if (currentIndex.isValid() && parent == currentIndex.parent()
&& currentIndex.column() >= start && currentIndex.column() <= end) {
QModelIndex old = currentIndex;
- if (start > 0) // there are columns to the left of the change
+ if (start > 0) {
+ // there are columns to the left of the change
currentIndex = model->index(old.row(), start - 1, parent);
- else if (model && end < model->columnCount() - 1) // there are columns to the right of the change
+ } else if (model.value() && end < model->columnCount() - 1) {
+ // there are columns to the right of the change
currentIndex = model->index(old.row(), end + 1, parent);
- else // there are no columns left in the table
+ } else {
+ // there are no columns left in the table
currentIndex = QModelIndex();
+ }
emit q->currentChanged(currentIndex, old);
if (currentIndex.row() != old.row())
emit q->currentRowChanged(currentIndex, old);
@@ -821,7 +763,7 @@ void QItemSelectionModelPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &p
Split selection ranges if columns are about to be inserted in the middle.
*/
-void QItemSelectionModelPrivate::_q_columnsAboutToBeInserted(const QModelIndex &parent,
+void QItemSelectionModelPrivate::columnsAboutToBeInserted(const QModelIndex &parent,
int start, int end)
{
Q_UNUSED(end);
@@ -829,11 +771,12 @@ void QItemSelectionModelPrivate::_q_columnsAboutToBeInserted(const QModelIndex &
QList<QItemSelectionRange> split;
QList<QItemSelectionRange>::iterator it = ranges.begin();
for (; it != ranges.end(); ) {
- if ((*it).isValid() && (*it).parent() == parent
+ const QModelIndex &itParent = it->parent();
+ if ((*it).isValid() && itParent == parent
&& (*it).left() < start && (*it).right() >= start) {
- QModelIndex bottomMiddle = model->index((*it).bottom(), start - 1, (*it).parent());
+ QModelIndex bottomMiddle = model->index((*it).bottom(), start - 1, itParent);
QItemSelectionRange left((*it).topLeft(), bottomMiddle);
- QModelIndex topMiddle = model->index((*it).top(), start, (*it).parent());
+ QModelIndex topMiddle = model->index((*it).top(), start, itParent);
QItemSelectionRange right(topMiddle, (*it).bottomRight());
it = ranges.erase(it);
split.append(left);
@@ -850,28 +793,38 @@ void QItemSelectionModelPrivate::_q_columnsAboutToBeInserted(const QModelIndex &
Split selection ranges if rows are about to be inserted in the middle.
*/
-void QItemSelectionModelPrivate::_q_rowsAboutToBeInserted(const QModelIndex &parent,
+void QItemSelectionModelPrivate::rowsAboutToBeInserted(const QModelIndex &parent,
int start, int end)
{
+ Q_Q(QItemSelectionModel);
Q_UNUSED(end);
finalize();
QList<QItemSelectionRange> split;
QList<QItemSelectionRange>::iterator it = ranges.begin();
+ bool indexesOfSelectionChanged = false;
for (; it != ranges.end(); ) {
- if ((*it).isValid() && (*it).parent() == parent
+ const QModelIndex &itParent = it->parent();
+ if ((*it).isValid() && itParent == parent
&& (*it).top() < start && (*it).bottom() >= start) {
- QModelIndex middleRight = model->index(start - 1, (*it).right(), (*it).parent());
+ QModelIndex middleRight = model->index(start - 1, (*it).right(), itParent);
QItemSelectionRange top((*it).topLeft(), middleRight);
- QModelIndex middleLeft = model->index(start, (*it).left(), (*it).parent());
+ QModelIndex middleLeft = model->index(start, (*it).left(), itParent);
QItemSelectionRange bottom(middleLeft, (*it).bottomRight());
it = ranges.erase(it);
split.append(top);
split.append(bottom);
+ } else if ((*it).isValid() && itParent == parent // insertion before selection
+ && (*it).top() >= start) {
+ indexesOfSelectionChanged = true;
+ ++it;
} else {
++it;
}
}
ranges += split;
+
+ if (indexesOfSelectionChanged)
+ emit q->selectionChanged(QItemSelection(), QItemSelection());
}
/*!
@@ -881,7 +834,8 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeInserted(const QModelIndex &par
preparation for the layoutChanged() signal, where the indexes can be
merged again.
*/
-void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
+void QItemSelectionModelPrivate::layoutAboutToBeChanged(const QList<QPersistentModelIndex> &,
+ QAbstractItemModel::LayoutChangeHint hint)
{
savedPersistentIndexes.clear();
savedPersistentCurrentIndexes.clear();
@@ -890,7 +844,7 @@ void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged(const QList<QPersiste
// optimization for when all indexes are selected
// (only if there is lots of items (1000) because this is not entirely correct)
- if (ranges.isEmpty() && currentSelection.count() == 1) {
+ if (ranges.isEmpty() && currentSelection.size() == 1) {
QItemSelectionRange range = currentSelection.constFirst();
QModelIndex parent = range.parent();
tableRowCount = model->rowCount(parent);
@@ -916,21 +870,21 @@ void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged(const QList<QPersiste
savedPersistentRowLengths = qSelectionPersistentRowLengths(ranges);
savedPersistentCurrentRowLengths = qSelectionPersistentRowLengths(currentSelection);
} else {
- savedPersistentIndexes = qSelectionIndexes<QVector<QPersistentModelIndex>>(ranges);
- savedPersistentCurrentIndexes = qSelectionIndexes<QVector<QPersistentModelIndex>>(currentSelection);
+ savedPersistentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(ranges);
+ savedPersistentCurrentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(currentSelection);
}
}
/*!
\internal
*/
-static QItemSelection mergeRowLengths(const QVector<QPair<QPersistentModelIndex, uint> > &rowLengths)
+static QItemSelection mergeRowLengths(const QList<std::pair<QPersistentModelIndex, uint>> &rowLengths)
{
if (rowLengths.isEmpty())
return QItemSelection();
QItemSelection result;
int i = 0;
- while (i < rowLengths.count()) {
+ while (i < rowLengths.size()) {
const QPersistentModelIndex &tl = rowLengths.at(i).first;
if (!tl.isValid()) {
++i;
@@ -938,7 +892,7 @@ static QItemSelection mergeRowLengths(const QVector<QPair<QPersistentModelIndex,
}
QPersistentModelIndex br = tl;
const uint length = rowLengths.at(i).second;
- while (++i < rowLengths.count()) {
+ while (++i < rowLengths.size()) {
const QPersistentModelIndex &next = rowLengths.at(i).first;
if (!next.isValid())
continue;
@@ -963,12 +917,12 @@ static QItemSelection mergeRowLengths(const QVector<QPair<QPersistentModelIndex,
Merges \a indexes into an item selection made up of ranges.
Assumes that the indexes are sorted.
*/
-static QItemSelection mergeIndexes(const QVector<QPersistentModelIndex> &indexes)
+static QItemSelection mergeIndexes(const QList<QPersistentModelIndex> &indexes)
{
QItemSelection colSpans;
// merge columns
int i = 0;
- while (i < indexes.count()) {
+ while (i < indexes.size()) {
const QPersistentModelIndex &tl = indexes.at(i);
if (!tl.isValid()) {
++i;
@@ -978,7 +932,7 @@ static QItemSelection mergeIndexes(const QVector<QPersistentModelIndex> &indexes
QModelIndex brParent = br.parent();
int brRow = br.row();
int brColumn = br.column();
- while (++i < indexes.count()) {
+ while (++i < indexes.size()) {
const QPersistentModelIndex &next = indexes.at(i);
if (!next.isValid())
continue;
@@ -1001,11 +955,11 @@ static QItemSelection mergeIndexes(const QVector<QPersistentModelIndex> &indexes
// merge rows
QItemSelection rowSpans;
i = 0;
- while (i < colSpans.count()) {
+ while (i < colSpans.size()) {
QModelIndex tl = colSpans.at(i).topLeft();
QModelIndex br = colSpans.at(i).bottomRight();
QModelIndex prevTl = tl;
- while (++i < colSpans.count()) {
+ while (++i < colSpans.size()) {
QModelIndex nextTl = colSpans.at(i).topLeft();
QModelIndex nextBr = colSpans.at(i).bottomRight();
@@ -1028,7 +982,7 @@ static QItemSelection mergeIndexes(const QVector<QPersistentModelIndex> &indexes
/*!
\internal
- Sort predicate function for QItemSelectionModelPrivate::_q_layoutChanged(),
+ Sort predicate function for QItemSelectionModelPrivate::layoutChanged(),
sorting by parent first in addition to operator<(). This is to prevent
fragmentation of the selection by grouping indexes with the same row, column
of different parents next to each other, which may happen when a selection
@@ -1046,7 +1000,7 @@ static bool qt_PersistentModelIndexLessThan(const QPersistentModelIndex &i1, con
Merge the selected indexes into selection ranges again.
*/
-void QItemSelectionModelPrivate::_q_layoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
+void QItemSelectionModelPrivate::layoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
{
// special case for when all indexes are selected
if (tableSelected && tableColCount == model->columnCount(tableParent)
@@ -1104,6 +1058,40 @@ void QItemSelectionModelPrivate::_q_layoutChanged(const QList<QPersistentModelIn
}
/*!
+ \internal
+
+ Called when the used model gets destroyed.
+
+ It is impossible to have a correct implementation here.
+ In the following situation, there are two contradicting rules:
+
+ \code
+ QProperty<QAbstractItemModel *> leader(mymodel);
+ QItemSelectionModel myItemSelectionModel;
+ myItemSelectionModel.bindableModel().setBinding([&](){ return leader.value(); }
+ delete mymodel;
+ QAbstractItemModel *returnedModel = myItemSelectionModel.model();
+ \endcode
+
+ What should returnedModel be in this situation?
+
+ Rules for bindable properties say that myItemSelectionModel.model()
+ should return the same as leader.value(), namely the pointer to the now deleted model.
+
+ However, backward compatibility requires myItemSelectionModel.model() to return a
+ nullptr, because that was done in the past after the model used was deleted.
+
+ We decide to break the new rule, imposed by bindable properties, and not break the old
+ rule, because that may break existing code.
+*/
+void QItemSelectionModelPrivate::modelDestroyed()
+{
+ model.setValueBypassingBindings(nullptr);
+ disconnectModel();
+ model.notify();
+}
+
+/*!
\class QItemSelectionModel
\inmodule QtCore
@@ -1139,7 +1127,7 @@ void QItemSelectionModelPrivate::_q_layoutChanged(const QList<QPersistentModelIn
\l{QItemSelectionModel::hasSelection()}{hasSelection}, and
\l{QItemSelectionModel::currentIndex()}{currentIndex} are meta-object properties.
- \sa {Model/View Programming}, QAbstractItemModel, {Chart Example}
+ \sa {Model/View Programming}, QAbstractItemModel
*/
/*!
@@ -1232,6 +1220,11 @@ void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::
Note the that the current index changes independently from the selection.
Also note that this signal will not be emitted when the item model is reset.
+ Items which stay selected but change their index are not included in
+ \a selected and \a deselected. Thus, this signal might be emitted with both
+ \a selected and \a deselected empty, if only the indices of selected items
+ change.
+
\sa select(), currentChanged()
*/
@@ -1273,10 +1266,10 @@ struct IsNotValid {
typedef bool result_type;
struct is_transparent : std::true_type {};
template <typename T>
- Q_DECL_CONSTEXPR bool operator()(T &t) const noexcept(noexcept(t.isValid()))
+ constexpr bool operator()(T &t) const noexcept(noexcept(t.isValid()))
{ return !t.isValid(); }
template <typename T>
- Q_DECL_CONSTEXPR bool operator()(T *t) const noexcept(noexcept(t->isValid()))
+ constexpr bool operator()(T *t) const noexcept(noexcept(t->isValid()))
{ return !t->isValid(); }
};
}
@@ -1291,7 +1284,7 @@ struct IsNotValid {
void QItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
{
Q_D(QItemSelectionModel);
- if (!d->model) {
+ if (!d->model.value()) {
qWarning("QItemSelectionModel: Selecting when no model has been set will result in a no-op.");
return;
}
@@ -1303,11 +1296,9 @@ void QItemSelectionModel::select(const QItemSelection &selection, QItemSelection
// If d->ranges is non-empty when the source model is reset the persistent indexes
// it contains will be invalid. We can't clear them in a modelReset slot because that might already
// be too late if another model observer is connected to the same modelReset slot and is invoked first
- // it might call select() on this selection model before any such QItemSelectionModelPrivate::_q_modelReset() slot
+ // it might call select() on this selection model before any such QItemSelectionModelPrivate::modelReset() slot
// is invoked, so it would not be cleared yet. We clear it invalid ranges in it here.
- using namespace QtFunctionObjects;
- d->ranges.erase(std::remove_if(d->ranges.begin(), d->ranges.end(), IsNotValid()),
- d->ranges.end());
+ d->ranges.removeIf(QtFunctionObjects::IsNotValid());
QItemSelection old = d->ranges;
old.merge(d->currentSelection, d->currentCommand);
@@ -1378,7 +1369,7 @@ void QItemSelectionModel::reset()
void QItemSelectionModel::clearSelection()
{
Q_D(QItemSelectionModel);
- if (d->ranges.count() == 0 && d->currentSelection.count() == 0)
+ if (d->ranges.size() == 0 && d->currentSelection.size() == 0)
return;
select(QItemSelection(), Clear);
@@ -1398,7 +1389,7 @@ void QItemSelectionModel::clearSelection()
void QItemSelectionModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
{
Q_D(QItemSelectionModel);
- if (!d->model) {
+ if (!d->model.value()) {
qWarning("QItemSelectionModel: Setting the current index when no model has been set will result in a no-op.");
return;
}
@@ -1449,7 +1440,7 @@ bool QItemSelectionModel::isSelected(const QModelIndex &index) const
}
// check currentSelection
- if (d->currentSelection.count()) {
+ if (d->currentSelection.size()) {
if ((d->currentCommand & Deselect) && selected)
selected = !d->currentSelection.contains(index);
else if (d->currentCommand & Toggle)
@@ -1458,10 +1449,8 @@ bool QItemSelectionModel::isSelected(const QModelIndex &index) const
selected = d->currentSelection.contains(index);
}
- if (selected) {
- Qt::ItemFlags flags = d->model->flags(index);
- return (flags & Qt::ItemIsSelectable);
- }
+ if (selected)
+ return isSelectableAndEnabled(d->model->flags(index));
return false;
}
@@ -1473,18 +1462,21 @@ bool QItemSelectionModel::isSelected(const QModelIndex &index) const
Note that this function is usually faster than calling isSelected()
on all items in the same row and that unselectable items are
ignored.
+
+ \note Since Qt 5.15, the default argument for \a parent is an empty
+ model index.
*/
bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) const
{
Q_D(const QItemSelectionModel);
- if (!d->model)
+ if (!d->model.value())
return false;
if (parent.isValid() && d->model != parent.model())
return false;
// return false if row exist in currentSelection (Deselect)
- if (d->currentCommand & Deselect && d->currentSelection.count()) {
- for (int i=0; i<d->currentSelection.count(); ++i) {
+ if (d->currentCommand & Deselect && d->currentSelection.size()) {
+ for (int i=0; i<d->currentSelection.size(); ++i) {
if (d->currentSelection.at(i).parent() == parent &&
row >= d->currentSelection.at(i).top() &&
row <= d->currentSelection.at(i).bottom())
@@ -1493,19 +1485,18 @@ bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) cons
}
// return false if ranges in both currentSelection and ranges
// intersect and have the same row contained
- if (d->currentCommand & Toggle && d->currentSelection.count()) {
- for (int i=0; i<d->currentSelection.count(); ++i)
+ if (d->currentCommand & Toggle && d->currentSelection.size()) {
+ for (int i=0; i<d->currentSelection.size(); ++i)
if (d->currentSelection.at(i).top() <= row &&
d->currentSelection.at(i).bottom() >= row)
- for (int j=0; j<d->ranges.count(); ++j)
+ for (int j=0; j<d->ranges.size(); ++j)
if (d->ranges.at(j).top() <= row && d->ranges.at(j).bottom() >= row
&& d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid())
return false;
}
auto isSelectable = [&](int row, int column) {
- Qt::ItemFlags flags = d->model->index(row, column, parent).flags();
- return (flags & Qt::ItemIsSelectable);
+ return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
};
const int colCount = d->model->columnCount(parent);
@@ -1513,7 +1504,7 @@ bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) cons
// add ranges and currentSelection and check through them all
QList<QItemSelectionRange>::const_iterator it;
QList<QItemSelectionRange> joined = d->ranges;
- if (d->currentSelection.count())
+ if (d->currentSelection.size())
joined += d->currentSelection;
for (int column = 0; column < colCount; ++column) {
if (!isSelectable(row, column)) {
@@ -1545,18 +1536,21 @@ bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) cons
Note that this function is usually faster than calling isSelected()
on all items in the same column and that unselectable items are
ignored.
+
+ \note Since Qt 5.15, the default argument for \a parent is an empty
+ model index.
*/
bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent) const
{
Q_D(const QItemSelectionModel);
- if (!d->model)
+ if (!d->model.value())
return false;
if (parent.isValid() && d->model != parent.model())
return false;
// return false if column exist in currentSelection (Deselect)
- if (d->currentCommand & Deselect && d->currentSelection.count()) {
- for (int i = 0; i < d->currentSelection.count(); ++i) {
+ if (d->currentCommand & Deselect && d->currentSelection.size()) {
+ for (int i = 0; i < d->currentSelection.size(); ++i) {
if (d->currentSelection.at(i).parent() == parent &&
column >= d->currentSelection.at(i).left() &&
column <= d->currentSelection.at(i).right())
@@ -1565,11 +1559,11 @@ bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent
}
// return false if ranges in both currentSelection and the selection model
// intersect and have the same column contained
- if (d->currentCommand & Toggle && d->currentSelection.count()) {
- for (int i = 0; i < d->currentSelection.count(); ++i) {
+ if (d->currentCommand & Toggle && d->currentSelection.size()) {
+ for (int i = 0; i < d->currentSelection.size(); ++i) {
if (d->currentSelection.at(i).left() <= column &&
d->currentSelection.at(i).right() >= column) {
- for (int j = 0; j < d->ranges.count(); ++j) {
+ for (int j = 0; j < d->ranges.size(); ++j) {
if (d->ranges.at(j).left() <= column && d->ranges.at(j).right() >= column
&& d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid()) {
return false;
@@ -1580,8 +1574,7 @@ bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent
}
auto isSelectable = [&](int row, int column) {
- Qt::ItemFlags flags = d->model->index(row, column, parent).flags();
- return (flags & Qt::ItemIsSelectable);
+ return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
};
const int rowCount = d->model->rowCount(parent);
int unselectable = 0;
@@ -1589,7 +1582,7 @@ bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent
// add ranges and currentSelection and check through them all
QList<QItemSelectionRange>::const_iterator it;
QList<QItemSelectionRange> joined = d->ranges;
- if (d->currentSelection.count())
+ if (d->currentSelection.size())
joined += d->currentSelection;
for (int row = 0; row < rowCount; ++row) {
if (!isSelectable(row, column)) {
@@ -1616,18 +1609,21 @@ bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent
/*!
Returns \c true if there are any items selected in the \a row with the given
\a parent.
+
+ \note Since Qt 5.15, the default argument for \a parent is an empty
+ model index.
*/
bool QItemSelectionModel::rowIntersectsSelection(int row, const QModelIndex &parent) const
{
Q_D(const QItemSelectionModel);
- if (!d->model)
+ if (!d->model.value())
return false;
if (parent.isValid() && d->model != parent.model())
return false;
QItemSelection sel = d->ranges;
sel.merge(d->currentSelection, d->currentCommand);
- for (const QItemSelectionRange &range : qAsConst(sel)) {
+ for (const QItemSelectionRange &range : std::as_const(sel)) {
if (range.parent() != parent)
return false;
int top = range.top();
@@ -1636,8 +1632,7 @@ bool QItemSelectionModel::rowIntersectsSelection(int row, const QModelIndex &par
int right = range.right();
if (top <= row && bottom >= row) {
for (int j = left; j <= right; j++) {
- const Qt::ItemFlags flags = d->model->index(row, j, parent).flags();
- if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
+ if (isSelectableAndEnabled(d->model->index(row, j, parent).flags()))
return true;
}
}
@@ -1649,18 +1644,21 @@ bool QItemSelectionModel::rowIntersectsSelection(int row, const QModelIndex &par
/*!
Returns \c true if there are any items selected in the \a column with the given
\a parent.
+
+ \note Since Qt 5.15, the default argument for \a parent is an empty
+ model index.
*/
bool QItemSelectionModel::columnIntersectsSelection(int column, const QModelIndex &parent) const
{
Q_D(const QItemSelectionModel);
- if (!d->model)
+ if (!d->model.value())
return false;
if (parent.isValid() && d->model != parent.model())
return false;
QItemSelection sel = d->ranges;
sel.merge(d->currentSelection, d->currentCommand);
- for (const QItemSelectionRange &range : qAsConst(sel)) {
+ for (const QItemSelectionRange &range : std::as_const(sel)) {
if (range.parent() != parent)
return false;
int top = range.top();
@@ -1669,8 +1667,7 @@ bool QItemSelectionModel::columnIntersectsSelection(int column, const QModelInde
int right = range.right();
if (left <= column && right >= column) {
for (int j = top; j <= bottom; j++) {
- const Qt::ItemFlags flags = d->model->index(j, column, parent).flags();
- if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
+ if (isSelectableAndEnabled(d->model->index(j, column, parent).flags()))
return true;
}
}
@@ -1680,20 +1677,47 @@ bool QItemSelectionModel::columnIntersectsSelection(int column, const QModelInde
}
/*!
+ \internal
+
+ Check whether the selection is empty.
+ In contrast to selection.isEmpty(), this takes into account
+ whether items are enabled and whether they are selectable.
+*/
+static bool selectionIsEmpty(const QItemSelection &selection)
+{
+ return std::all_of(selection.begin(), selection.end(),
+ [](const QItemSelectionRange &r) { return r.isEmpty(); });
+}
+
+/*!
\since 4.2
- Returns \c true if the selection model contains any selection ranges;
+ Returns \c true if the selection model contains any selected item,
otherwise returns \c false.
*/
bool QItemSelectionModel::hasSelection() const
{
Q_D(const QItemSelectionModel);
+
+ // QTreeModel unfortunately sorts itself lazily.
+ // When it sorts itself, it emits are layoutChanged signal.
+ // This layoutChanged signal invalidates d->ranges here.
+ // So QTreeModel must not sort itself while we are iterating over
+ // d->ranges here. It sorts itself in executePendingOperations,
+ // thus preventing the sort to happen inside of selectionIsEmpty below.
+ // Sad story, read more in QTBUG-94546
+ const QAbstractItemModel *model = QItemSelectionModel::model();
+ if (model != nullptr) {
+ auto model_p = static_cast<const QAbstractItemModelPrivate *>(QObjectPrivate::get(model));
+ model_p->executePendingOperations();
+ }
+
if (d->currentCommand & (Toggle | Deselect)) {
QItemSelection sel = d->ranges;
sel.merge(d->currentSelection, d->currentCommand);
- return !sel.isEmpty();
+ return !selectionIsEmpty(sel);
} else {
- return !(d->ranges.isEmpty() && d->currentSelection.isEmpty());
+ return !(selectionIsEmpty(d->ranges) && selectionIsEmpty(d->currentSelection));
}
}
@@ -1709,6 +1733,25 @@ QModelIndexList QItemSelectionModel::selectedIndexes() const
return selected.indexes();
}
+struct RowOrColumnDefinition {
+ QModelIndex parent;
+ int rowOrColumn;
+
+ friend bool operator==(const RowOrColumnDefinition &lhs, const RowOrColumnDefinition &rhs) noexcept
+ { return lhs.parent == rhs.parent && lhs.rowOrColumn == rhs.rowOrColumn; }
+ friend bool operator!=(const RowOrColumnDefinition &lhs, const RowOrColumnDefinition &rhs) noexcept
+ { return !operator==(lhs, rhs); }
+};
+size_t qHash(const RowOrColumnDefinition &key, size_t seed = 0) noexcept
+{
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, key.parent);
+ seed = hash(seed, key.rowOrColumn);
+ return seed;
+}
+
+QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(RowOrColumnDefinition)
+
/*!
\since 4.2
Returns the indexes in the given \a column for the rows where all columns are selected.
@@ -1719,18 +1762,15 @@ QModelIndexList QItemSelectionModel::selectedIndexes() const
QModelIndexList QItemSelectionModel::selectedRows(int column) const
{
QModelIndexList indexes;
- //the QSet contains pairs of parent modelIndex
- //and row number
- QSet< QPair<QModelIndex, int> > rowsSeen;
+
+ QDuplicateTracker<RowOrColumnDefinition> rowsSeen;
const QItemSelection ranges = selection();
- for (int i = 0; i < ranges.count(); ++i) {
+ for (int i = 0; i < ranges.size(); ++i) {
const QItemSelectionRange &range = ranges.at(i);
QModelIndex parent = range.parent();
for (int row = range.top(); row <= range.bottom(); row++) {
- QPair<QModelIndex, int> rowDef = qMakePair(parent, row);
- if (!rowsSeen.contains(rowDef)) {
- rowsSeen << rowDef;
+ if (!rowsSeen.hasSeen({parent, row})) {
if (isRowSelected(row, parent)) {
indexes.append(model()->index(row, column, parent));
}
@@ -1751,18 +1791,15 @@ QModelIndexList QItemSelectionModel::selectedRows(int column) const
QModelIndexList QItemSelectionModel::selectedColumns(int row) const
{
QModelIndexList indexes;
- //the QSet contains pairs of parent modelIndex
- //and column number
- QSet< QPair<QModelIndex, int> > columnsSeen;
+
+ QDuplicateTracker<RowOrColumnDefinition> columnsSeen;
const QItemSelection ranges = selection();
- for (int i = 0; i < ranges.count(); ++i) {
+ for (int i = 0; i < ranges.size(); ++i) {
const QItemSelectionRange &range = ranges.at(i);
QModelIndex parent = range.parent();
for (int column = range.left(); column <= range.right(); column++) {
- QPair<QModelIndex, int> columnDef = qMakePair(parent, column);
- if (!columnsSeen.contains(columnDef)) {
- columnsSeen << columnDef;
+ if (!columnsSeen.hasSeen({parent, column})) {
if (isColumnSelected(column, parent)) {
indexes.append(model()->index(row, column, parent));
}
@@ -1783,10 +1820,7 @@ const QItemSelection QItemSelectionModel::selection() const
selected.merge(d->currentSelection, d->currentCommand);
// make sure we have no invalid ranges
// ### should probably be handled more generic somewhere else
- using namespace QtFunctionObjects;
- selected.erase(std::remove_if(selected.begin(), selected.end(),
- IsNotValid()),
- selected.end());
+ selected.removeIf(QtFunctionObjects::IsNotValid());
return selected;
}
@@ -1827,7 +1861,7 @@ const QItemSelection QItemSelectionModel::selection() const
*/
QAbstractItemModel *QItemSelectionModel::model()
{
- return d_func()->model;
+ return d_func()->model.value();
}
/*!
@@ -1835,7 +1869,12 @@ QAbstractItemModel *QItemSelectionModel::model()
*/
const QAbstractItemModel *QItemSelectionModel::model() const
{
- return d_func()->model;
+ return d_func()->model.value();
+}
+
+QBindable<QAbstractItemModel *> QItemSelectionModel::bindableModel()
+{
+ return &d_func()->model;
}
/*!
@@ -1848,11 +1887,11 @@ const QAbstractItemModel *QItemSelectionModel::model() const
void QItemSelectionModel::setModel(QAbstractItemModel *model)
{
Q_D(QItemSelectionModel);
- if (d->model == model)
+ d->model.removeBindingUnlessInWrapper();
+ if (d->model.valueBypassingBindings() == model)
return;
-
d->initModel(model);
- emit modelChanged(model);
+ d->model.notify();
}
/*!
@@ -1878,9 +1917,9 @@ void QItemSelectionModel::emitSelectionChanged(const QItemSelection &newSelectio
// remove equal ranges
bool advance;
- for (int o = 0; o < deselected.count(); ++o) {
+ for (int o = 0; o < deselected.size(); ++o) {
advance = true;
- for (int s = 0; s < selected.count() && o < deselected.count();) {
+ for (int s = 0; s < selected.size() && o < deselected.size();) {
if (deselected.at(o) == selected.at(s)) {
deselected.removeAt(o);
selected.removeAt(s);
@@ -1895,17 +1934,17 @@ void QItemSelectionModel::emitSelectionChanged(const QItemSelection &newSelectio
// find intersections
QItemSelection intersections;
- for (int o = 0; o < deselected.count(); ++o) {
- for (int s = 0; s < selected.count(); ++s) {
+ for (int o = 0; o < deselected.size(); ++o) {
+ for (int s = 0; s < selected.size(); ++s) {
if (deselected.at(o).intersects(selected.at(s)))
intersections.append(deselected.at(o).intersected(selected.at(s)));
}
}
// compare remaining ranges with intersections and split them to find deselected and selected
- for (int i = 0; i < intersections.count(); ++i) {
+ for (int i = 0; i < intersections.size(); ++i) {
// split deselected
- for (int o = 0; o < deselected.count();) {
+ for (int o = 0; o < deselected.size();) {
if (deselected.at(o).intersects(intersections.at(i))) {
QItemSelection::split(deselected.at(o), intersections.at(i), &deselected);
deselected.removeAt(o);
@@ -1914,7 +1953,7 @@ void QItemSelectionModel::emitSelectionChanged(const QItemSelection &newSelectio
}
}
// split selected
- for (int s = 0; s < selected.count();) {
+ for (int s = 0; s < selected.size();) {
if (selected.at(s).intersects(intersections.at(i))) {
QItemSelection::split(selected.at(s), intersections.at(i), &selected);
selected.removeAt(s);
diff --git a/src/corelib/itemmodels/qitemselectionmodel.h b/src/corelib/itemmodels/qitemselectionmodel.h
index 5820695592..c4b8dadc97 100644
--- a/src/corelib/itemmodels/qitemselectionmodel.h
+++ b/src/corelib/itemmodels/qitemselectionmodel.h
@@ -1,51 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QITEMSELECTIONMODEL_H
#define QITEMSELECTIONMODEL_H
#include <QtCore/qglobal.h>
-#include <QtCore/qset.h>
-#include <QtCore/qvector.h>
-#include <QtCore/qlist.h>
#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qset.h>
QT_REQUIRE_CONFIG(itemmodel);
@@ -55,25 +18,14 @@ class Q_CORE_EXPORT QItemSelectionRange
{
public:
- inline QItemSelectionRange() : tl(), br() {}
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- // ### Qt 6: remove them all, the compiler-generated ones are fine
- inline QItemSelectionRange(const QItemSelectionRange &other)
- : tl(other.tl), br(other.br) {}
- QItemSelectionRange(QItemSelectionRange &&other) noexcept
- : tl(std::move(other.tl)), br(std::move(other.br)) {}
- QItemSelectionRange &operator=(QItemSelectionRange &&other) noexcept
- { tl = std::move(other.tl); br = std::move(other.br); return *this; }
- QItemSelectionRange &operator=(const QItemSelectionRange &other)
- { tl = other.tl; br = other.br; return *this; }
-#endif // Qt < 6
+ QItemSelectionRange() = default;
QItemSelectionRange(const QModelIndex &topL, const QModelIndex &bottomR) : tl(topL), br(bottomR) {}
explicit QItemSelectionRange(const QModelIndex &index) : tl(index), br(tl) {}
void swap(QItemSelectionRange &other) noexcept
{
- qSwap(tl, other.tl);
- qSwap(br, other.br);
+ tl.swap(other.tl);
+ br.swap(other.br);
}
inline int top() const { return tl.row(); }
@@ -103,19 +55,14 @@ public:
}
bool intersects(const QItemSelectionRange &other) const;
-#if QT_DEPRECATED_SINCE(5, 0)
- inline QItemSelectionRange intersect(const QItemSelectionRange &other) const
- { return intersected(other); }
-#endif
QItemSelectionRange intersected(const QItemSelectionRange &other) const;
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const QItemSelectionRange &other) const
- { return (tl == other.tl && br == other.br); }
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QItemSelectionRange &other) const
- { return !operator==(other); }
- bool operator<(const QItemSelectionRange &other) const;
-
+ { return !operator==(other); }
+#endif
inline bool isValid() const
{
return (tl.isValid() && br.isValid() && tl.parent() == br.parent()
@@ -127,9 +74,15 @@ public:
QModelIndexList indexes() const;
private:
+ friend bool comparesEqual(const QItemSelectionRange &lhs,
+ const QItemSelectionRange &rhs) noexcept
+ {
+ return (lhs.tl == rhs.tl && lhs.br == rhs.br);
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QItemSelectionRange)
QPersistentModelIndex tl, br;
};
-Q_DECLARE_TYPEINFO(QItemSelectionRange, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QItemSelectionRange, Q_RELOCATABLE_TYPE);
class QItemSelection;
class QItemSelectionModelPrivate;
@@ -137,11 +90,16 @@ class QItemSelectionModelPrivate;
class Q_CORE_EXPORT QItemSelectionModel : public QObject
{
Q_OBJECT
- Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
- Q_PROPERTY(bool hasSelection READ hasSelection NOTIFY selectionChanged STORED false DESIGNABLE false)
- Q_PROPERTY(QModelIndex currentIndex READ currentIndex NOTIFY currentChanged STORED false DESIGNABLE false)
- Q_PROPERTY(QItemSelection selection READ selection NOTIFY selectionChanged STORED false DESIGNABLE false)
- Q_PROPERTY(QModelIndexList selectedIndexes READ selectedIndexes NOTIFY selectionChanged STORED false DESIGNABLE false)
+ Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged
+ BINDABLE bindableModel)
+ Q_PROPERTY(bool hasSelection READ hasSelection NOTIFY selectionChanged STORED false
+ DESIGNABLE false)
+ Q_PROPERTY(QModelIndex currentIndex READ currentIndex NOTIFY currentChanged STORED false
+ DESIGNABLE false)
+ Q_PROPERTY(QItemSelection selection READ selection NOTIFY selectionChanged STORED false
+ DESIGNABLE false)
+ Q_PROPERTY(QModelIndexList selectedIndexes READ selectedIndexes NOTIFY selectionChanged
+ STORED false DESIGNABLE false)
Q_DECLARE_PRIVATE(QItemSelectionModel)
@@ -184,9 +142,9 @@ public:
Q_INVOKABLE QModelIndexList selectedColumns(int row = 0) const;
const QItemSelection selection() const;
- // ### Qt 6: Merge these two as "QAbstractItemModel *model() const"
const QAbstractItemModel *model() const;
QAbstractItemModel *model();
+ QBindable<QAbstractItemModel *> bindableModel();
void setModel(QAbstractItemModel *model);
@@ -213,54 +171,29 @@ protected:
private:
Q_DISABLE_COPY(QItemSelectionModel)
- Q_PRIVATE_SLOT(d_func(), void _q_columnsAboutToBeRemoved(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_rowsAboutToBeRemoved(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_columnsAboutToBeInserted(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_rowsAboutToBeInserted(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoHint))
- Q_PRIVATE_SLOT(d_func(), void _q_layoutChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoHint))
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QItemSelectionModel::SelectionFlags)
-// dummy implentation of qHash() necessary for instantiating QList<QItemSelectionRange>::toSet() with MSVC
-inline uint qHash(const QItemSelectionRange &) { return 0; }
-
-#ifdef Q_CC_MSVC
-
-/*
- ### Qt 6:
- ### This needs to be removed for next releases of Qt. It is a workaround for vc++ because
- ### Qt exports QItemSelection that inherits QList<QItemSelectionRange>.
-*/
-
-# ifndef Q_TEMPLATE_EXTERN
-# if defined(QT_BUILD_CORE_LIB)
-# define Q_TEMPLATE_EXTERN
-# else
-# define Q_TEMPLATE_EXTERN extern
-# endif
-# endif
-Q_TEMPLATE_EXTERN template class Q_CORE_EXPORT QList<QItemSelectionRange>;
-#endif // Q_CC_MSVC
-
-class Q_CORE_EXPORT QItemSelection : public QList<QItemSelectionRange>
+// We export each out-of-line method individually to prevent MSVC from
+// exporting the whole QList class.
+class QItemSelection : public QList<QItemSelectionRange>
{
public:
- QItemSelection() noexcept : QList<QItemSelectionRange>() {}
- QItemSelection(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ using QList<QItemSelectionRange>::QList;
+ Q_CORE_EXPORT QItemSelection(const QModelIndex &topLeft, const QModelIndex &bottomRight);
// reusing QList::swap() here is OK!
- void select(const QModelIndex &topLeft, const QModelIndex &bottomRight);
- bool contains(const QModelIndex &index) const;
- QModelIndexList indexes() const;
- void merge(const QItemSelection &other, QItemSelectionModel::SelectionFlags command);
- static void split(const QItemSelectionRange &range,
+ Q_CORE_EXPORT void select(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ Q_CORE_EXPORT bool contains(const QModelIndex &index) const;
+ Q_CORE_EXPORT QModelIndexList indexes() const;
+ Q_CORE_EXPORT void merge(const QItemSelection &other, QItemSelectionModel::SelectionFlags command);
+ Q_CORE_EXPORT static void split(const QItemSelectionRange &range,
const QItemSelectionRange &other,
QItemSelection *result);
};
-Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QItemSelection)
+Q_DECLARE_SHARED(QItemSelection)
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug, const QItemSelectionRange &);
@@ -268,7 +201,7 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QItemSelectionRange &);
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QItemSelectionRange)
-Q_DECLARE_METATYPE(QItemSelection)
+QT_DECL_METATYPE_EXTERN(QItemSelectionRange, Q_CORE_EXPORT)
+QT_DECL_METATYPE_EXTERN(QItemSelection, Q_CORE_EXPORT)
#endif // QITEMSELECTIONMODEL_H
diff --git a/src/corelib/itemmodels/qitemselectionmodel_p.h b/src/corelib/itemmodels/qitemselectionmodel_p.h
index ba85f22be3..689cd26bd2 100644
--- a/src/corelib/itemmodels/qitemselectionmodel_p.h
+++ b/src/corelib/itemmodels/qitemselectionmodel_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QITEMSELECTIONMODEL_P_H
#define QITEMSELECTIONMODEL_P_H
@@ -51,7 +15,10 @@
// We mean it.
//
+#include "qitemselectionmodel.h"
#include "private/qobject_p.h"
+#include "private/qproperty_p.h"
+#include <array>
QT_REQUIRE_CONFIG(itemmodel);
@@ -62,8 +29,7 @@ class QItemSelectionModelPrivate: public QObjectPrivate
Q_DECLARE_PUBLIC(QItemSelectionModel)
public:
QItemSelectionModelPrivate()
- : model(nullptr),
- currentCommand(QItemSelectionModel::NoUpdate),
+ : currentCommand(QItemSelectionModel::NoUpdate),
tableSelected(false), tableColCount(0), tableRowCount(0) {}
QItemSelection expandSelection(const QItemSelection &selection,
@@ -71,12 +37,23 @@ public:
void initModel(QAbstractItemModel *model);
- void _q_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_rowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_columnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
- void _q_layoutChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
+ void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void columnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
+ void triggerLayoutToBeChanged()
+ {
+ layoutAboutToBeChanged(QList<QPersistentModelIndex>(), QAbstractItemModel::NoLayoutChangeHint);
+ }
+
+ void layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
+ void triggerLayoutChanged()
+ {
+ layoutChanged(QList<QPersistentModelIndex>(), QAbstractItemModel::NoLayoutChangeHint);
+ }
+
+ void modelDestroyed();
inline void remove(QList<QItemSelectionRange> &r)
{
@@ -92,19 +69,26 @@ public:
currentSelection.clear();
}
- QPointer<QAbstractItemModel> model;
+ void setModel(QAbstractItemModel *mod) { q_func()->setModel(mod); }
+ void disconnectModel();
+ void modelChanged(QAbstractItemModel *mod) { emit q_func()->modelChanged(mod); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QItemSelectionModelPrivate, QAbstractItemModel *, model,
+ &QItemSelectionModelPrivate::setModel,
+ &QItemSelectionModelPrivate::modelChanged, nullptr)
+
QItemSelection ranges;
QItemSelection currentSelection;
QPersistentModelIndex currentIndex;
QItemSelectionModel::SelectionFlags currentCommand;
- QVector<QPersistentModelIndex> savedPersistentIndexes;
- QVector<QPersistentModelIndex> savedPersistentCurrentIndexes;
- QVector<QPair<QPersistentModelIndex, uint> > savedPersistentRowLengths;
- QVector<QPair<QPersistentModelIndex, uint> > savedPersistentCurrentRowLengths;
+ QList<QPersistentModelIndex> savedPersistentIndexes;
+ QList<QPersistentModelIndex> savedPersistentCurrentIndexes;
+ QList<std::pair<QPersistentModelIndex, uint>> savedPersistentRowLengths;
+ QList<std::pair<QPersistentModelIndex, uint>> savedPersistentCurrentRowLengths;
// optimization when all indexes are selected
bool tableSelected;
QPersistentModelIndex tableParent;
int tableColCount, tableRowCount;
+ std::array<QMetaObject::Connection, 12> connections;
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
index 21303549ab..a5284dbad4 100644
--- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp
+++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
@@ -1,57 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsortfilterproxymodel.h"
#include "qitemselectionmodel.h"
#include <qsize.h>
#include <qdebug.h>
#include <qdatetime.h>
-#include <qpair.h>
#include <qstringlist.h>
#include <private/qabstractitemmodel_p.h>
#include <private/qabstractproxymodel_p.h>
+#include <private/qproperty_p.h>
#include <algorithm>
QT_BEGIN_NAMESPACE
-typedef QVector<QPair<QModelIndex, QPersistentModelIndex> > QModelIndexPairList;
+using QModelIndexPairList = QList<std::pair<QModelIndex, QPersistentModelIndex>>;
struct QSortFilterProxyModelDataChanged
{
@@ -62,7 +26,7 @@ struct QSortFilterProxyModelDataChanged
QModelIndex bottomRight;
};
-static inline QSet<int> qVectorToSet(const QVector<int> &vector)
+static inline QSet<int> qListToSet(const QList<int> &vector)
{
return {vector.begin(), vector.end()};
}
@@ -142,177 +106,165 @@ private:
int end;
};
-class RegularExpressionData {
+class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QSortFilterProxyModel)
-private:
- enum class ExpressionType {
- RegExp,
-#if QT_CONFIG(regularexpression)
- RegularExpression
-#endif
+ enum class Direction {
+ Rows = 1,
+ Columns = 2,
+ All = Rows | Columns
};
-public:
- RegularExpressionData() :
- m_type(ExpressionType::RegExp)
- {}
+ struct Mapping {
+ QList<int> source_rows;
+ QList<int> source_columns;
+ QList<int> proxy_rows;
+ QList<int> proxy_columns;
+ QList<QModelIndex> mapped_children;
+ QModelIndex source_parent;
+ };
-#if QT_CONFIG(regularexpression)
- QRegularExpression regularExpression() const
+ mutable QHash<QModelIndex, Mapping*> source_index_mapping;
+
+ void setSortCaseSensitivityForwarder(Qt::CaseSensitivity cs)
{
- if (m_type == ExpressionType::RegularExpression)
- return m_regularExpression;
- return QRegularExpression();
+ q_func()->setSortCaseSensitivity(cs);
}
-
- void setRegularExpression(const QRegularExpression &rx)
+ void sortCaseSensitivityChangedForwarder(Qt::CaseSensitivity cs)
{
- m_type = ExpressionType::RegularExpression;
- m_regularExpression = rx;
- m_regExp = QRegExp();
+ emit q_func()->sortCaseSensitivityChanged(cs);
}
-#endif
- QRegExp regExp() const
+ void setSortRoleForwarder(int role) { q_func()->setSortRole(role); }
+ void sortRoleChangedForwarder(int role) { emit q_func()->sortRoleChanged(role); }
+
+ void setSortLocaleAwareForwarder(bool on) { q_func()->setSortLocaleAware(on); }
+ void sortLocaleAwareChangedForwarder(bool on) { emit q_func()->sortLocaleAwareChanged(on); }
+
+ void setFilterKeyColumnForwarder(int column) { q_func()->setFilterKeyColumn(column); }
+
+ void setFilterRoleForwarder(int role) { q_func()->setFilterRole(role); }
+ void filterRoleChangedForwarder(int role) { emit q_func()->filterRoleChanged(role); }
+
+ void setRecursiveFilteringEnabledForwarder(bool recursive)
{
- if (m_type == ExpressionType::RegExp)
- return m_regExp;
- return QRegExp();
+ q_func()->setRecursiveFilteringEnabled(recursive);
}
-
- void setRegExp(const QRegExp &rx)
+ void recursiveFilteringEnabledChangedForwarder(bool recursive)
{
- m_type = ExpressionType::RegExp;
- m_regExp = rx;
-#if QT_CONFIG(regularexpression)
- m_regularExpression = QRegularExpression();
-#endif
-
+ emit q_func()->recursiveFilteringEnabledChanged(recursive);
}
- bool isEmpty() const
+ void setAutoAcceptChildRowsForwarder(bool accept) { q_func()->setAutoAcceptChildRows(accept); }
+ void autoAcceptChildRowsChangedForwarder(bool accept)
{
- bool result = true;
- switch (m_type) {
- case ExpressionType::RegExp:
- result = m_regExp.isEmpty();
- break;
-#if QT_CONFIG(regularexpression)
- case ExpressionType::RegularExpression:
- result = m_regularExpression.pattern().isEmpty();
- break;
-#endif
- }
- return result;
+ emit q_func()->autoAcceptChildRowsChanged(accept);
}
- Qt::CaseSensitivity caseSensitivity() const
+ void setDynamicSortFilterForwarder(bool enable) { q_func()->setDynamicSortFilter(enable); }
+
+ void setFilterCaseSensitivityForwarder(Qt::CaseSensitivity cs)
{
- Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
- switch (m_type) {
- case ExpressionType::RegExp:
- sensitivity = m_regExp.caseSensitivity();
- break;
-#if QT_CONFIG(regularexpression)
- case ExpressionType::RegularExpression:
- {
- QRegularExpression::PatternOptions options = m_regularExpression.patternOptions();
- if (!(options & QRegularExpression::CaseInsensitiveOption))
- sensitivity = Qt::CaseSensitive;
- }
- break;
-#endif
- }
- return sensitivity;
+ q_func()->setFilterCaseSensitivity(cs);
}
-
- void setCaseSensitivity(Qt::CaseSensitivity cs)
+ void filterCaseSensitivityChangedForwarder(Qt::CaseSensitivity cs)
{
- switch (m_type) {
- case ExpressionType::RegExp:
- m_regExp.setCaseSensitivity(cs);
- break;
-#if QT_CONFIG(regularexpression)
- case ExpressionType::RegularExpression:
- {
- QRegularExpression::PatternOptions options = m_regularExpression.patternOptions();
- options.setFlag(QRegularExpression::CaseInsensitiveOption, cs == Qt::CaseSensitive);
- m_regularExpression.setPatternOptions(options);
- }
- break;
-#endif
- }
+ emit q_func()->filterCaseSensitivityChanged(cs);
}
- bool hasMatch(const QString &str) const
+ void setFilterRegularExpressionForwarder(const QRegularExpression &re)
{
- bool result = false;
- switch (m_type) {
- case ExpressionType::RegExp:
- result = str.contains(m_regExp);
- break;
-#if QT_CONFIG(regularexpression)
- case ExpressionType::RegularExpression:
- result = str.contains(m_regularExpression);
- break;
-#endif
- }
- return result;
+ q_func()->setFilterRegularExpression(re);
}
-private:
- ExpressionType m_type;
- QRegExp m_regExp;
-#if QT_CONFIG(regularexpression)
- QRegularExpression m_regularExpression;
-#endif
-};
+ int source_sort_column = -1;
+ int proxy_sort_column = -1;
+ Qt::SortOrder sort_order = Qt::AscendingOrder;
+ bool complete_insert = false;
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, Qt::CaseSensitivity, sort_casesensitivity,
+ &QSortFilterProxyModelPrivate::setSortCaseSensitivityForwarder,
+ &QSortFilterProxyModelPrivate::sortCaseSensitivityChangedForwarder, Qt::CaseSensitive)
-class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
-{
- Q_DECLARE_PUBLIC(QSortFilterProxyModel)
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QSortFilterProxyModelPrivate, int, sort_role,
+ &QSortFilterProxyModelPrivate::setSortRoleForwarder,
+ &QSortFilterProxyModelPrivate::sortRoleChangedForwarder,
+ Qt::DisplayRole)
-public:
- struct Mapping {
- QVector<int> source_rows;
- QVector<int> source_columns;
- QVector<int> proxy_rows;
- QVector<int> proxy_columns;
- QVector<QModelIndex> mapped_children;
- QHash<QModelIndex, Mapping *>::const_iterator map_iter;
- };
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QSortFilterProxyModelPrivate, int, filter_column,
+ &QSortFilterProxyModelPrivate::setFilterKeyColumnForwarder,
+ 0)
- mutable QHash<QModelIndex, Mapping*> source_index_mapping;
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QSortFilterProxyModelPrivate, int, filter_role,
+ &QSortFilterProxyModelPrivate::setFilterRoleForwarder,
+ &QSortFilterProxyModelPrivate::filterRoleChangedForwarder,
+ Qt::DisplayRole)
- int source_sort_column;
- int proxy_sort_column;
- Qt::SortOrder sort_order;
- Qt::CaseSensitivity sort_casesensitivity;
- int sort_role;
- bool sort_localeaware;
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, bool, sort_localeaware,
+ &QSortFilterProxyModelPrivate::setSortLocaleAwareForwarder,
+ &QSortFilterProxyModelPrivate::sortLocaleAwareChangedForwarder, false)
- int filter_column;
- int filter_role;
- RegularExpressionData filter_data;
- QModelIndex last_top_source;
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, bool, filter_recursive,
+ &QSortFilterProxyModelPrivate::setRecursiveFilteringEnabledForwarder,
+ &QSortFilterProxyModelPrivate::recursiveFilteringEnabledChangedForwarder, false)
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, bool, accept_children,
+ &QSortFilterProxyModelPrivate::setAutoAcceptChildRowsForwarder,
+ &QSortFilterProxyModelPrivate::autoAcceptChildRowsChangedForwarder, false)
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QSortFilterProxyModelPrivate, bool, dynamic_sortfilter,
+ &QSortFilterProxyModelPrivate::setDynamicSortFilterForwarder,
+ true)
- bool filter_recursive;
- bool complete_insert;
- bool dynamic_sortfilter;
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, Qt::CaseSensitivity, filter_casesensitive,
+ &QSortFilterProxyModelPrivate::setFilterCaseSensitivityForwarder,
+ &QSortFilterProxyModelPrivate::filterCaseSensitivityChangedForwarder, Qt::CaseSensitive)
+
+ Q_OBJECT_COMPAT_PROPERTY(QSortFilterProxyModelPrivate, QRegularExpression,
+ filter_regularexpression,
+ &QSortFilterProxyModelPrivate::setFilterRegularExpressionForwarder)
+
+ QModelIndex last_top_source;
QRowsRemoval itemsBeingRemoved;
QModelIndexPairList saved_persistent_indexes;
QList<QPersistentModelIndex> saved_layoutChange_parents;
+ std::array<QMetaObject::Connection, 18> sourceConnections;
+
QHash<QModelIndex, Mapping *>::const_iterator create_mapping(
const QModelIndex &source_parent) const;
+ QHash<QModelIndex, Mapping *>::const_iterator create_mapping_recursive(
+ const QModelIndex &source_parent) const;
QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const;
QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const;
bool can_create_mapping(const QModelIndex &source_parent) const;
void remove_from_mapping(const QModelIndex &source_parent);
+ /*
+ * Legacy: changing the pattern through a string does not change the
+ * case sensitivity.
+ */
+ void set_filter_pattern(const QString &pattern)
+ {
+ QRegularExpression re = filter_regularexpression.valueBypassingBindings();
+ const auto cs = re.patternOptions() & QRegularExpression::CaseInsensitiveOption;
+ re.setPattern(pattern);
+ re.setPatternOptions(cs);
+ // This is a helper function, which is supposed to be called from a
+ // more complicated context. Because of that, the caller is responsible
+ // for calling notify() and removeBindingUnlessInWrapper(), if needed.
+ filter_regularexpression.setValueBypassingBindings(re);
+ }
+
inline QHash<QModelIndex, Mapping *>::const_iterator index_to_iterator(
const QModelIndex &proxy_index) const
{
@@ -321,7 +273,7 @@ public:
const void *p = proxy_index.internalPointer();
Q_ASSERT(p);
QHash<QModelIndex, Mapping *>::const_iterator it =
- static_cast<const Mapping*>(p)->map_iter;
+ source_index_mapping.constFind(static_cast<const Mapping*>(p)->source_parent);
Q_ASSERT(it != source_index_mapping.constEnd());
Q_ASSERT(it.value());
return it;
@@ -335,7 +287,7 @@ public:
void _q_sourceDataChanged(const QModelIndex &source_top_left,
const QModelIndex &source_bottom_right,
- const QVector<int> &roles);
+ const QList<int> &roles);
void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end);
void _q_sourceAboutToBeReset();
@@ -378,27 +330,27 @@ public:
void sort();
bool update_source_sort_column();
int find_source_sort_column() const;
- void sort_source_rows(QVector<int> &source_rows,
+ void sort_source_rows(QList<int> &source_rows,
const QModelIndex &source_parent) const;
- QVector<QPair<int, QVector<int > > > proxy_intervals_for_source_items_to_add(
- const QVector<int> &proxy_to_source, const QVector<int> &source_items,
+ QList<std::pair<int, QList<int>>> proxy_intervals_for_source_items_to_add(
+ const QList<int> &proxy_to_source, const QList<int> &source_items,
const QModelIndex &source_parent, Qt::Orientation orient) const;
- QVector<QPair<int, int > > proxy_intervals_for_source_items(
- const QVector<int> &source_to_proxy, const QVector<int> &source_items) const;
+ QList<std::pair<int, int>> proxy_intervals_for_source_items(
+ const QList<int> &source_to_proxy, const QList<int> &source_items) const;
void insert_source_items(
- QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
- const QVector<int> &source_items, const QModelIndex &source_parent,
+ QList<int> &source_to_proxy, QList<int> &proxy_to_source,
+ const QList<int> &source_items, const QModelIndex &source_parent,
Qt::Orientation orient, bool emit_signal = true);
void remove_source_items(
- QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
- const QVector<int> &source_items, const QModelIndex &source_parent,
+ QList<int> &source_to_proxy, QList<int> &proxy_to_source,
+ const QList<int> &source_items, const QModelIndex &source_parent,
Qt::Orientation orient, bool emit_signal = true);
void remove_proxy_interval(
- QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
+ QList<int> &source_to_proxy, QList<int> &proxy_to_source,
int proxy_start, int proxy_end, const QModelIndex &proxy_parent,
Qt::Orientation orient, bool emit_signal = true);
- void build_source_to_proxy_mapping(
- const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const;
+ static inline void build_source_to_proxy_mapping(
+ const QList<int> &proxy_to_source, QList<int> &source_to_proxy, int start = 0);
void source_items_inserted(const QModelIndex &source_parent,
int start, int end, Qt::Orientation orient);
void source_items_about_to_be_removed(const QModelIndex &source_parent,
@@ -406,16 +358,16 @@ public:
void source_items_removed(const QModelIndex &source_parent,
int start, int end, Qt::Orientation orient);
void proxy_item_range(
- const QVector<int> &source_to_proxy, const QVector<int> &source_items,
+ const QList<int> &source_to_proxy, const QList<int> &source_items,
int &proxy_low, int &proxy_high) const;
QModelIndexPairList store_persistent_indexes() const;
void update_persistent_indexes(const QModelIndexPairList &source_indexes);
void filter_about_to_be_changed(const QModelIndex &source_parent = QModelIndex());
- void filter_changed(const QModelIndex &source_parent = QModelIndex());
+ void filter_changed(Direction dir, const QModelIndex &source_parent = QModelIndex());
QSet<int> handle_filter_changed(
- QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
+ QList<int> &source_to_proxy, QList<int> &proxy_to_source,
const QModelIndex &source_parent, Qt::Orientation orient);
void updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
@@ -423,14 +375,20 @@ public:
void _q_sourceModelDestroyed() override;
- bool needsReorder(const QVector<int> &source_rows, const QModelIndex &source_parent) const;
+ bool needsReorder(const QList<int> &source_rows, const QModelIndex &source_parent) const;
bool filterAcceptsRowInternal(int source_row, const QModelIndex &source_parent) const;
- bool filterRecursiveAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+ bool recursiveChildAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+ bool recursiveParentAcceptsRow(const QModelIndex &source_parent) const;
};
typedef QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping *> IndexMap;
+static bool operator&(QSortFilterProxyModelPrivate::Direction a, QSortFilterProxyModelPrivate::Direction b)
+{
+ return int(a) & int(b);
+}
+
void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed()
{
QAbstractProxyModelPrivate::_q_sourceModelDestroyed();
@@ -441,23 +399,49 @@ void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed()
bool QSortFilterProxyModelPrivate::filterAcceptsRowInternal(int source_row, const QModelIndex &source_parent) const
{
Q_Q(const QSortFilterProxyModel);
- return filter_recursive
- ? filterRecursiveAcceptsRow(source_row, source_parent)
- : q->filterAcceptsRow(source_row, source_parent);
+
+ if (q->filterAcceptsRow(source_row, source_parent))
+ return true;
+
+ // Go up the tree and accept this row if a parent is accepted
+ if (accept_children && recursiveParentAcceptsRow(source_parent))
+ return true;
+
+ // Go down the tree and accept this row if a child is accepted
+ if (filter_recursive && recursiveChildAcceptsRow(source_row, source_parent))
+ return true;
+
+ return false;
}
-bool QSortFilterProxyModelPrivate::filterRecursiveAcceptsRow(int source_row, const QModelIndex &source_parent) const
+bool QSortFilterProxyModelPrivate::recursiveParentAcceptsRow(const QModelIndex &source_parent) const
{
Q_Q(const QSortFilterProxyModel);
- if (q->filterAcceptsRow(source_row, source_parent))
- return true;
+ if (source_parent.isValid()) {
+ const QModelIndex index = source_parent.parent();
+
+ if (q->filterAcceptsRow(source_parent.row(), index))
+ return true;
+
+ return recursiveParentAcceptsRow(index);
+ }
+
+ return false;
+}
+
+bool QSortFilterProxyModelPrivate::recursiveChildAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ Q_Q(const QSortFilterProxyModel);
const QModelIndex index = model->index(source_row, 0, source_parent);
const int count = model->rowCount(index);
for (int i = 0; i < count; ++i) {
- if (filterRecursiveAcceptsRow(i, index))
+ if (q->filterAcceptsRow(i, index))
+ return true;
+
+ if (recursiveChildAcceptsRow(i, index))
return true;
}
@@ -467,7 +451,7 @@ bool QSortFilterProxyModelPrivate::filterRecursiveAcceptsRow(int source_row, con
void QSortFilterProxyModelPrivate::remove_from_mapping(const QModelIndex &source_parent)
{
if (Mapping *m = source_index_mapping.take(source_parent)) {
- for (const QModelIndex &mappedIdx : qAsConst(m->mapped_children))
+ for (const QModelIndex &mappedIdx : std::as_const(m->mapped_children))
remove_from_mapping(mappedIdx);
delete m;
}
@@ -517,8 +501,7 @@ IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping(
m->proxy_columns.resize(source_cols);
build_source_to_proxy_mapping(m->source_columns, m->proxy_columns);
- it = IndexMap::const_iterator(source_index_mapping.insert(source_parent, m));
- m->map_iter = it;
+ m->source_parent = source_parent;
if (source_parent.isValid()) {
QModelIndex source_grand_parent = source_parent.parent();
@@ -527,12 +510,36 @@ IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping(
it2.value()->mapped_children.append(source_parent);
}
+ it = IndexMap::const_iterator(source_index_mapping.insert(source_parent, m));
Q_ASSERT(it != source_index_mapping.constEnd());
Q_ASSERT(it.value());
return it;
}
+// Go up the tree, creating mappings, unless of course the parent is filtered out
+IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping_recursive(const QModelIndex &source_parent) const
+{
+ if (source_parent.isValid()) {
+ const QModelIndex source_grand_parent = source_parent.parent();
+ IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent);
+ IndexMap::const_iterator end = source_index_mapping.constEnd();
+ if (it == end) {
+ it = create_mapping_recursive(source_grand_parent);
+ end = source_index_mapping.constEnd();
+ if (it == end)
+ return end;
+ }
+ Mapping *gm = it.value();
+ if (gm->proxy_rows.at(source_parent.row()) == -1 ||
+ gm->proxy_columns.at(source_parent.column()) == -1) {
+ // Can't do, parent is filtered
+ return end;
+ }
+ }
+ return create_mapping(source_parent);
+}
+
QModelIndex QSortFilterProxyModelPrivate::proxy_to_source(const QModelIndex &proxy_index) const
{
if (!proxy_index.isValid())
@@ -670,7 +677,7 @@ int QSortFilterProxyModelPrivate::find_source_sort_column() const
Sorts the given \a source_rows according to current sort column and order.
*/
void QSortFilterProxyModelPrivate::sort_source_rows(
- QVector<int> &source_rows, const QModelIndex &source_parent) const
+ QList<int> &source_rows, const QModelIndex &source_parent) const
{
Q_Q(const QSortFilterProxyModel);
if (source_sort_column >= 0) {
@@ -681,8 +688,10 @@ void QSortFilterProxyModelPrivate::sort_source_rows(
QSortFilterProxyModelGreaterThan gt(source_sort_column, source_parent, model, q);
std::stable_sort(source_rows.begin(), source_rows.end(), gt);
}
- } else { // restore the source model order
- std::stable_sort(source_rows.begin(), source_rows.end());
+ } else if (sort_order == Qt::AscendingOrder) {
+ std::stable_sort(source_rows.begin(), source_rows.end(), std::less{});
+ } else {
+ std::stable_sort(source_rows.begin(), source_rows.end(), std::greater{});
}
}
@@ -697,10 +706,10 @@ void QSortFilterProxyModelPrivate::sort_source_rows(
The result is a vector of pairs, where each pair represents a
(start, end) tuple, sorted in ascending order.
*/
-QVector<QPair<int, int > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items(
- const QVector<int> &source_to_proxy, const QVector<int> &source_items) const
+QList<std::pair<int, int>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items(
+ const QList<int> &source_to_proxy, const QList<int> &source_items) const
{
- QVector<QPair<int, int> > proxy_intervals;
+ QList<std::pair<int, int>> proxy_intervals;
if (source_items.isEmpty())
return proxy_intervals;
@@ -717,22 +726,19 @@ QVector<QPair<int, int > > QSortFilterProxyModelPrivate::proxy_intervals_for_sou
++source_items_index;
}
// Add interval to result
- proxy_intervals.append(QPair<int, int>(first_proxy_item, last_proxy_item));
+ proxy_intervals.emplace_back(first_proxy_item, last_proxy_item);
}
std::stable_sort(proxy_intervals.begin(), proxy_intervals.end());
// Consolidate adjacent intervals
for (int i = proxy_intervals.size()-1; i > 0; --i) {
- QPair<int, int> &interval = proxy_intervals[i];
- QPair<int, int> &preceeding_interval = proxy_intervals[i - 1];
+ std::pair<int, int> &interval = proxy_intervals[i];
+ std::pair<int, int> &preceeding_interval = proxy_intervals[i - 1];
if (interval.first == preceeding_interval.second + 1) {
preceeding_interval.second = interval.second;
interval.first = interval.second = -1;
}
}
- proxy_intervals.erase(
- std::remove_if(proxy_intervals.begin(), proxy_intervals.end(),
- [](QPair<int, int> &interval) { return interval.first < 0; }),
- proxy_intervals.end());
+ proxy_intervals.removeIf([](std::pair<int, int> interval) { return interval.first < 0; });
return proxy_intervals;
}
@@ -745,21 +751,23 @@ QVector<QPair<int, int > > QSortFilterProxyModelPrivate::proxy_intervals_for_sou
rows/columnsRemoved(start, end) signals will be generated.
*/
void QSortFilterProxyModelPrivate::remove_source_items(
- QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
- const QVector<int> &source_items, const QModelIndex &source_parent,
+ QList<int> &source_to_proxy, QList<int> &proxy_to_source,
+ const QList<int> &source_items, const QModelIndex &source_parent,
Qt::Orientation orient, bool emit_signal)
{
Q_Q(QSortFilterProxyModel);
QModelIndex proxy_parent = q->mapFromSource(source_parent);
- if (!proxy_parent.isValid() && source_parent.isValid())
+ if (!proxy_parent.isValid() && source_parent.isValid()) {
+ proxy_to_source.clear();
return; // nothing to do (already removed)
+ }
const auto proxy_intervals = proxy_intervals_for_source_items(
source_to_proxy, source_items);
const auto end = proxy_intervals.rend();
for (auto it = proxy_intervals.rbegin(); it != end; ++it) {
- const QPair<int, int> &interval = *it;
+ const std::pair<int, int> &interval = *it;
const int proxy_start = interval.first;
const int proxy_end = interval.second;
remove_proxy_interval(source_to_proxy, proxy_to_source, proxy_start, proxy_end,
@@ -775,7 +783,7 @@ void QSortFilterProxyModelPrivate::remove_source_items(
(inclusive) from this proxy model.
*/
void QSortFilterProxyModelPrivate::remove_proxy_interval(
- QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, int proxy_start, int proxy_end,
+ QList<int> &source_to_proxy, QList<int> &proxy_to_source, int proxy_start, int proxy_end,
const QModelIndex &proxy_parent, Qt::Orientation orient, bool emit_signal)
{
Q_Q(QSortFilterProxyModel);
@@ -787,9 +795,11 @@ void QSortFilterProxyModelPrivate::remove_proxy_interval(
}
// Remove items from proxy-to-source mapping
+ for (int i = proxy_start; i <= proxy_end; ++i)
+ source_to_proxy[proxy_to_source.at(i)] = -1;
proxy_to_source.remove(proxy_start, proxy_end - proxy_start + 1);
- build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
+ build_source_to_proxy_mapping(proxy_to_source, source_to_proxy, proxy_start);
if (emit_signal) {
if (orient == Qt::Vertical)
@@ -811,22 +821,21 @@ void QSortFilterProxyModelPrivate::remove_proxy_interval(
items), where items is a vector containing the (sorted) source items that
should be inserted at that proxy model location.
*/
-QVector<QPair<int, QVector<int > > > QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add(
- const QVector<int> &proxy_to_source, const QVector<int> &source_items,
+QList<std::pair<int, QList<int>>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add(
+ const QList<int> &proxy_to_source, const QList<int> &source_items,
const QModelIndex &source_parent, Qt::Orientation orient) const
{
Q_Q(const QSortFilterProxyModel);
- QVector<QPair<int, QVector<int> > > proxy_intervals;
+ QList<std::pair<int, QList<int>>> proxy_intervals;
if (source_items.isEmpty())
return proxy_intervals;
int proxy_low = 0;
int proxy_item = 0;
int source_items_index = 0;
- QVector<int> source_items_in_interval;
bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter);
while (source_items_index < source_items.size()) {
- source_items_in_interval.clear();
+ QList<int> source_items_in_interval;
int first_new_source_item = source_items.at(source_items_index);
source_items_in_interval.append(first_new_source_item);
++source_items_index;
@@ -872,7 +881,7 @@ QVector<QPair<int, QVector<int > > > QSortFilterProxyModelPrivate::proxy_interva
}
// Add interval to result
- proxy_intervals.append(QPair<int, QVector<int> >(proxy_item, source_items_in_interval));
+ proxy_intervals.emplace_back(proxy_item, std::move(source_items_in_interval));
}
return proxy_intervals;
}
@@ -886,8 +895,8 @@ QVector<QPair<int, QVector<int > > > QSortFilterProxyModelPrivate::proxy_interva
that the proper rows/columnsInserted(start, end) signals will be generated.
*/
void QSortFilterProxyModelPrivate::insert_source_items(
- QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
- const QVector<int> &source_items, const QModelIndex &source_parent,
+ QList<int> &source_to_proxy, QList<int> &proxy_to_source,
+ const QList<int> &source_items, const QModelIndex &source_parent,
Qt::Orientation orient, bool emit_signal)
{
Q_Q(QSortFilterProxyModel);
@@ -900,9 +909,9 @@ void QSortFilterProxyModelPrivate::insert_source_items(
const auto end = proxy_intervals.rend();
for (auto it = proxy_intervals.rbegin(); it != end; ++it) {
- const QPair<int, QVector<int> > &interval = *it;
+ const std::pair<int, QList<int>> &interval = *it;
const int proxy_start = interval.first;
- const QVector<int> &source_items = interval.second;
+ const QList<int> &source_items = interval.second;
const int proxy_end = proxy_start + source_items.size() - 1;
if (emit_signal) {
@@ -912,10 +921,11 @@ void QSortFilterProxyModelPrivate::insert_source_items(
q->beginInsertColumns(proxy_parent, proxy_start, proxy_end);
}
- for (int i = 0; i < source_items.size(); ++i)
- proxy_to_source.insert(proxy_start + i, source_items.at(i));
+ // TODO: use the range QList::insert() overload once it is implemented (QTBUG-58633).
+ proxy_to_source.insert(proxy_start, source_items.size(), 0);
+ std::copy(source_items.cbegin(), source_items.cend(), proxy_to_source.begin() + proxy_start);
- build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
+ build_source_to_proxy_mapping(proxy_to_source, source_to_proxy, proxy_start);
if (emit_signal) {
if (orient == Qt::Vertical)
@@ -951,20 +961,20 @@ void QSortFilterProxyModelPrivate::source_items_inserted(
it = create_mapping(source_parent);
Mapping *m = it.value();
QModelIndex proxy_parent = q->mapFromSource(source_parent);
- if (m->source_rows.count() > 0) {
- q->beginInsertRows(proxy_parent, 0, m->source_rows.count() - 1);
+ if (m->source_rows.size() > 0) {
+ q->beginInsertRows(proxy_parent, 0, m->source_rows.size() - 1);
q->endInsertRows();
}
- if (m->source_columns.count() > 0) {
- q->beginInsertColumns(proxy_parent, 0, m->source_columns.count() - 1);
+ if (m->source_columns.size() > 0) {
+ q->beginInsertColumns(proxy_parent, 0, m->source_columns.size() - 1);
q->endInsertColumns();
}
return;
}
Mapping *m = it.value();
- QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
- QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
+ QList<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
+ QList<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
int delta_item_count = end - start + 1;
int old_item_count = source_to_proxy.size();
@@ -991,7 +1001,7 @@ void QSortFilterProxyModelPrivate::source_items_inserted(
}
// Figure out which items to add to mapping based on filter
- QVector<int> source_items;
+ QList<int> source_items;
for (int i = start; i <= end; ++i) {
if ((orient == Qt::Vertical)
? filterAcceptsRowInternal(i, source_parent)
@@ -1005,8 +1015,8 @@ void QSortFilterProxyModelPrivate::source_items_inserted(
// If it was new rows make sure to create mappings for columns so that a
// valid mapping can be retrieved later and vice-versa.
- QVector<int> &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns;
- QVector<int> &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns;
+ QList<int> &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns;
+ QList<int> &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns;
if (orthogonal_source_to_proxy.isEmpty()) {
const int ortho_end = (orient == Qt::Horizontal) ? model->rowCount(source_parent) : model->columnCount(source_parent);
@@ -1051,11 +1061,11 @@ void QSortFilterProxyModelPrivate::source_items_about_to_be_removed(
}
Mapping *m = it.value();
- QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
- QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
+ QList<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
+ QList<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
// figure out which items to remove
- QVector<int> source_items_to_remove;
+ QList<int> source_items_to_remove;
int proxy_count = proxy_to_source.size();
for (int proxy_item = 0; proxy_item < proxy_count; ++proxy_item) {
int source_item = proxy_to_source.at(proxy_item);
@@ -1084,8 +1094,8 @@ void QSortFilterProxyModelPrivate::source_items_removed(
}
Mapping *m = it.value();
- QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
- QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
+ QList<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
+ QList<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
if (end >= source_to_proxy.size())
end = source_to_proxy.size() - 1;
@@ -1128,8 +1138,8 @@ void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &sour
Qt::Orientation orient, int start, int end, int delta_item_count, bool remove)
{
// see if any mapped children should be (re)moved
- QVector<QPair<QModelIndex, Mapping*> > moved_source_index_mappings;
- QVector<QModelIndex>::iterator it2 = parent_mapping->mapped_children.begin();
+ QList<std::pair<QModelIndex, Mapping *>> moved_source_index_mappings;
+ auto it2 = parent_mapping->mapped_children.begin();
for ( ; it2 != parent_mapping->mapped_children.end();) {
const QModelIndex source_child_index = *it2;
const int pos = (orient == Qt::Vertical)
@@ -1162,14 +1172,14 @@ void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &sour
Mapping *cm = source_index_mapping.take(source_child_index);
Q_ASSERT(cm);
// we do not reinsert right away, because the new index might be identical with another, old index
- moved_source_index_mappings.append(QPair<QModelIndex, Mapping*>(new_index, cm));
+ moved_source_index_mappings.emplace_back(new_index, cm);
}
}
// reinsert moved, mapped indexes
- QVector<QPair<QModelIndex, Mapping*> >::iterator it = moved_source_index_mappings.begin();
- for (; it != moved_source_index_mappings.end(); ++it) {
- (*it).second->map_iter = QHash<QModelIndex, Mapping *>::const_iterator(source_index_mapping.insert((*it).first, (*it).second));
+ for (auto &pair : std::as_const(moved_source_index_mappings)) {
+ pair.second->source_parent = pair.first;
+ source_index_mapping.insert(pair.first, pair.second);
}
}
@@ -1177,12 +1187,12 @@ void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &sour
\internal
*/
void QSortFilterProxyModelPrivate::proxy_item_range(
- const QVector<int> &source_to_proxy, const QVector<int> &source_items,
+ const QList<int> &source_to_proxy, const QList<int> &source_items,
int &proxy_low, int &proxy_high) const
{
proxy_low = INT_MAX;
proxy_high = INT_MIN;
- for (int i = 0; i < source_items.count(); ++i) {
+ for (int i = 0; i < source_items.size(); ++i) {
int proxy_item = source_to_proxy.at(source_items.at(i));
Q_ASSERT(proxy_item != -1);
if (proxy_item < proxy_low)
@@ -1196,11 +1206,12 @@ void QSortFilterProxyModelPrivate::proxy_item_range(
\internal
*/
void QSortFilterProxyModelPrivate::build_source_to_proxy_mapping(
- const QVector<int> &proxy_to_source, QVector<int> &source_to_proxy) const
+ const QList<int> &proxy_to_source, QList<int> &source_to_proxy, int start)
{
- source_to_proxy.fill(-1);
- int proxy_count = proxy_to_source.size();
- for (int i = 0; i < proxy_count; ++i)
+ if (start == 0)
+ source_to_proxy.fill(-1);
+ const int proxy_count = proxy_to_source.size();
+ for (int i = start; i < proxy_count; ++i)
source_to_proxy[proxy_to_source.at(i)] = i;
}
@@ -1214,11 +1225,11 @@ QModelIndexPairList QSortFilterProxyModelPrivate::store_persistent_indexes() con
{
Q_Q(const QSortFilterProxyModel);
QModelIndexPairList source_indexes;
- source_indexes.reserve(persistent.indexes.count());
- for (const QPersistentModelIndexData *data : qAsConst(persistent.indexes)) {
+ source_indexes.reserve(persistent.indexes.size());
+ for (const QPersistentModelIndexData *data : std::as_const(persistent.indexes)) {
const QModelIndex &proxy_index = data->index;
QModelIndex source_index = q->mapToSource(proxy_index);
- source_indexes.append(qMakePair(proxy_index, QPersistentModelIndex(source_index)));
+ source_indexes.emplace_back(proxy_index, source_index);
}
return source_indexes;
}
@@ -1234,7 +1245,7 @@ void QSortFilterProxyModelPrivate::update_persistent_indexes(
{
Q_Q(QSortFilterProxyModel);
QModelIndexList from, to;
- const int numSourceIndexes = source_indexes.count();
+ const int numSourceIndexes = source_indexes.size();
from.reserve(numSourceIndexes);
to.reserve(numSourceIndexes);
for (const auto &indexPair : source_indexes) {
@@ -1256,9 +1267,10 @@ void QSortFilterProxyModelPrivate::update_persistent_indexes(
*/
void QSortFilterProxyModelPrivate::filter_about_to_be_changed(const QModelIndex &source_parent)
{
- if (!filter_data.isEmpty() &&
- source_index_mapping.constFind(source_parent) == source_index_mapping.constEnd())
- create_mapping(source_parent);
+ if (!filter_regularexpression.valueBypassingBindings().pattern().isEmpty()
+ && source_index_mapping.constFind(source_parent) == source_index_mapping.constEnd()) {
+ create_mapping(source_parent);
+ }
}
@@ -1268,32 +1280,32 @@ void QSortFilterProxyModelPrivate::filter_about_to_be_changed(const QModelIndex
Updates the proxy model (adds/removes rows) based on the
new filter.
*/
-void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_parent)
+void QSortFilterProxyModelPrivate::filter_changed(Direction dir, const QModelIndex &source_parent)
{
IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
if (it == source_index_mapping.constEnd())
return;
Mapping *m = it.value();
- QSet<int> rows_removed = handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical);
- QSet<int> columns_removed = handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal);
+ const QSet<int> rows_removed = (dir & Direction::Rows) ? handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical) : QSet<int>();
+ const QSet<int> columns_removed = (dir & Direction::Columns) ? handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal) : QSet<int>();
// We need to iterate over a copy of m->mapped_children because otherwise it may be changed by other code, invalidating
// the iterator it2.
// The m->mapped_children vector can be appended to with indexes which are no longer filtered
// out (in create_mapping) when this function recurses for child indexes.
- const QVector<QModelIndex> mappedChildren = m->mapped_children;
- QVector<int> indexesToRemove;
+ const QList<QModelIndex> mappedChildren = m->mapped_children;
+ QList<int> indexesToRemove;
for (int i = 0; i < mappedChildren.size(); ++i) {
const QModelIndex &source_child_index = mappedChildren.at(i);
if (rows_removed.contains(source_child_index.row()) || columns_removed.contains(source_child_index.column())) {
indexesToRemove.push_back(i);
remove_from_mapping(source_child_index);
} else {
- filter_changed(source_child_index);
+ filter_changed(dir, source_child_index);
}
}
- QVector<int>::const_iterator removeIt = indexesToRemove.constEnd();
- const QVector<int>::const_iterator removeBegin = indexesToRemove.constBegin();
+ QList<int>::const_iterator removeIt = indexesToRemove.constEnd();
+ const QList<int>::const_iterator removeBegin = indexesToRemove.constBegin();
// We can't just remove these items from mappedChildren while iterating above and then
// do something like m->mapped_children = mappedChildren, because mapped_children might
@@ -1311,13 +1323,13 @@ void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_pare
returns the removed items indexes
*/
QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
- QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
+ QList<int> &source_to_proxy, QList<int> &proxy_to_source,
const QModelIndex &source_parent, Qt::Orientation orient)
{
Q_Q(QSortFilterProxyModel);
// Figure out which mapped items to remove
- QVector<int> source_items_remove;
- for (int i = 0; i < proxy_to_source.count(); ++i) {
+ QList<int> source_items_remove;
+ for (int i = 0; i < proxy_to_source.size(); ++i) {
const int source_item = proxy_to_source.at(i);
if ((orient == Qt::Vertical)
? !filterAcceptsRowInternal(source_item, source_parent)
@@ -1327,7 +1339,7 @@ QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
}
}
// Figure out which non-mapped items to insert
- QVector<int> source_items_insert;
+ QList<int> source_items_insert;
int source_count = source_to_proxy.size();
for (int source_item = 0; source_item < source_count; ++source_item) {
if (source_to_proxy.at(source_item) == -1) {
@@ -1348,10 +1360,10 @@ QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
insert_source_items(source_to_proxy, proxy_to_source,
source_items_insert, source_parent, orient);
}
- return qVectorToSet(source_items_remove);
+ return qListToSet(source_items_remove);
}
-bool QSortFilterProxyModelPrivate::needsReorder(const QVector<int> &source_rows, const QModelIndex &source_parent) const
+bool QSortFilterProxyModelPrivate::needsReorder(const QList<int> &source_rows, const QModelIndex &source_parent) const
{
Q_Q(const QSortFilterProxyModel);
Q_ASSERT(source_sort_column != -1);
@@ -1380,7 +1392,7 @@ bool QSortFilterProxyModelPrivate::needsReorder(const QVector<int> &source_rows,
void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &source_top_left,
const QModelIndex &source_bottom_right,
- const QVector<int> &roles)
+ const QList<int> &roles)
{
Q_Q(QSortFilterProxyModel);
if (!source_top_left.isValid() || !source_bottom_right.isValid())
@@ -1404,21 +1416,30 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
const QModelIndex &source_bottom_right = data_changed.bottomRight;
const QModelIndex source_parent = source_top_left.parent();
+ bool change_in_unmapped_parent = false;
IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
if (it == source_index_mapping.constEnd()) {
- // Don't care, since we don't have mapping for this index
- continue;
+ // We don't have mapping for this index, so we cannot know how things
+ // changed (in case the change affects filtering) in order to forward
+ // the change correctly.
+ // But we can at least forward the signal "as is", if the row isn't
+ // filtered out, this is better than nothing.
+ it = create_mapping_recursive(source_parent);
+ if (it == source_index_mapping.constEnd())
+ continue;
+ change_in_unmapped_parent = true;
}
+
Mapping *m = it.value();
// Figure out how the source changes affect us
- QVector<int> source_rows_remove;
- QVector<int> source_rows_insert;
- QVector<int> source_rows_change;
- QVector<int> source_rows_resort;
- int end = qMin(source_bottom_right.row(), m->proxy_rows.count() - 1);
+ QList<int> source_rows_remove;
+ QList<int> source_rows_insert;
+ QList<int> source_rows_change;
+ QList<int> source_rows_resort;
+ int end = qMin(source_bottom_right.row(), m->proxy_rows.size() - 1);
for (int source_row = source_top_left.row(); source_row <= end; ++source_row) {
- if (dynamic_sortfilter) {
+ if (dynamic_sortfilter && !change_in_unmapped_parent) {
if (m->proxy_rows.at(source_row) != -1) {
if (!filterAcceptsRowInternal(source_row, source_parent)) {
// This source row no longer satisfies the filter, so it must be removed
@@ -1445,8 +1466,8 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
if (!source_rows_remove.isEmpty()) {
remove_source_items(m->proxy_rows, m->source_rows,
source_rows_remove, source_parent, Qt::Vertical);
- QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove);
- QVector<QModelIndex>::iterator childIt = m->mapped_children.end();
+ QSet<int> source_rows_remove_set = qListToSet(source_rows_remove);
+ QList<QModelIndex>::iterator childIt = m->mapped_children.end();
while (childIt != m->mapped_children.begin()) {
--childIt;
const QModelIndex source_child_index = *childIt;
@@ -1489,15 +1510,19 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
while (source_left_column < source_bottom_right.column()
&& m->proxy_columns.at(source_left_column) == -1)
++source_left_column;
- const QModelIndex proxy_top_left = create_index(
- proxy_start_row, m->proxy_columns.at(source_left_column), it);
- int source_right_column = source_bottom_right.column();
- while (source_right_column > source_top_left.column()
- && m->proxy_columns.at(source_right_column) == -1)
- --source_right_column;
- const QModelIndex proxy_bottom_right = create_index(
- proxy_end_row, m->proxy_columns.at(source_right_column), it);
- emit q->dataChanged(proxy_top_left, proxy_bottom_right, roles);
+ if (m->proxy_columns.at(source_left_column) != -1) {
+ const QModelIndex proxy_top_left = create_index(
+ proxy_start_row, m->proxy_columns.at(source_left_column), it);
+ int source_right_column = source_bottom_right.column();
+ while (source_right_column > source_top_left.column()
+ && m->proxy_columns.at(source_right_column) == -1)
+ --source_right_column;
+ if (m->proxy_columns.at(source_right_column) != -1) {
+ const QModelIndex proxy_bottom_right = create_index(
+ proxy_end_row, m->proxy_columns.at(source_right_column), it);
+ emit q->dataChanged(proxy_top_left, proxy_bottom_right, roles);
+ }
+ }
}
}
@@ -1517,14 +1542,14 @@ void QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation or
Q_Q(QSortFilterProxyModel);
Mapping *m = create_mapping(QModelIndex()).value();
- const QVector<int> &source_to_proxy = (orientation == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
+ const QList<int> &source_to_proxy = (orientation == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
- QVector<int> proxy_positions;
+ QList<int> proxy_positions;
proxy_positions.reserve(end - start + 1);
{
Q_ASSERT(source_to_proxy.size() > end);
- QVector<int>::const_iterator it = source_to_proxy.constBegin() + start;
- const QVector<int>::const_iterator endIt = source_to_proxy.constBegin() + end + 1;
+ QList<int>::const_iterator it = source_to_proxy.constBegin() + start;
+ const QList<int>::const_iterator endIt = source_to_proxy.constBegin() + end + 1;
for ( ; it != endIt; ++it) {
if (*it != -1)
proxy_positions.push_back(*it);
@@ -1564,8 +1589,7 @@ void QSortFilterProxyModelPrivate::_q_sourceReset()
_q_clearMapping();
// All internal structures are deleted in clear()
q->endResetModel();
- update_source_sort_column();
- if (dynamic_sortfilter && update_source_sort_column())
+ if (update_source_sort_column() && dynamic_sortfilter)
sort();
}
@@ -1629,8 +1653,8 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted(
const bool toplevel = !source_parent.isValid();
const bool recursive_accepted = filter_recursive && !toplevel && filterAcceptsRowInternal(source_parent.row(), source_parent.parent());
- //Force the creation of a mapping now, even if its empty.
- //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items
+ //Force the creation of a mapping now, even if it's empty.
+ //We need it because the proxy can be accessed at the moment it emits rowsAboutToBeInserted in insert_source_items
if (!filter_recursive || toplevel || recursive_accepted) {
if (can_create_mapping(source_parent))
create_mapping(source_parent);
@@ -1678,7 +1702,7 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsInserted(
return;
// last_top_source should now become visible
- _q_sourceDataChanged(last_top_source, last_top_source, QVector<int>());
+ _q_sourceDataChanged(last_top_source, last_top_source, QList<int>());
}
}
@@ -1714,7 +1738,7 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsRemoved(
}
if (to_hide.isValid())
- _q_sourceDataChanged(to_hide, to_hide, QVector<int>());
+ _q_sourceDataChanged(to_hide, to_hide, QList<int>());
}
}
@@ -1749,8 +1773,8 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(
{
Q_UNUSED(start);
Q_UNUSED(end);
- //Force the creation of a mapping now, even if its empty.
- //We need it because the proxy can be acessed at the moment it emits columnsAboutToBeInserted in insert_source_items
+ //Force the creation of a mapping now, even if it's empty.
+ //We need it because the proxy can be accessed at the moment it emits columnsAboutToBeInserted in insert_source_items
if (can_create_mapping(source_parent))
create_mapping(source_parent);
}
@@ -1797,7 +1821,10 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved(
source_sort_column = -1;
}
- proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
+ if (source_sort_column >= 0)
+ proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
+ else
+ proxy_sort_column = -1;
}
void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(
@@ -1919,9 +1946,9 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved(
\section1 Filtering
In addition to sorting, QSortFilterProxyModel can be used to hide items
- that do not match a certain filter. The filter is specified using a QRegExp
+ that do not match a certain filter. The filter is specified using a QRegularExpression
object and is applied to the filterRole() (Qt::DisplayRole by default) of
- each item, for a given column. The QRegExp object can be used to match a
+ each item, for a given column. The QRegularExpression object can be used to match a
regular expression, a wildcard pattern, or a fixed string. For example:
\snippet qsortfilterproxymodel-details/main.cpp 5
@@ -1949,8 +1976,9 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved(
example.)
If you are working with large amounts of filtering and have to invoke
- invalidateFilter() repeatedly, using reset() may be more efficient,
- depending on the implementation of your model. However, reset() returns the
+ invalidateFilter() repeatedly, using beginResetModel() / endResetModel() may
+ be more efficient, depending on the implementation of your model. However,
+ beginResetModel() / endResetModel() returns the
proxy model to its original state, losing selection information, and will
cause the proxy model to be repopulated.
@@ -1969,21 +1997,6 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved(
\note Some general guidelines for subclassing models are available in the
\l{Model Subclassing Reference}.
- \note With Qt 5, regular expression support has been improved through the
- QRegularExpression class. QSortFilterProxyModel dating back prior to that
- class creation, it originally supported only QRegExp. Since Qt 5.12,
- QRegularExpression APIs have been added. Therefore, QRegExp APIs should be
- considered deprecated and the QRegularExpression version should be used in
- place.
-
- \warning Don't mix calls to the getters and setters of different regexp types
- as this will lead to unexpected results. For maximum compatibility, the original
- implementation has been kept. Therefore, if, for example, a call to
- setFilterRegularExpression is made followed by another one to
- setFilterFixedString, the first call will setup a QRegularExpression object
- to use as filter while the second will setup a QRegExp in FixedString mode.
- However, this is an implementation detail that might change in the future.
-
\sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming},
{Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example}, QIdentityProxyModel
*/
@@ -1996,17 +2009,8 @@ QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent)
: QAbstractProxyModel(*new QSortFilterProxyModelPrivate, parent)
{
Q_D(QSortFilterProxyModel);
- d->proxy_sort_column = d->source_sort_column = -1;
- d->sort_order = Qt::AscendingOrder;
- d->sort_casesensitivity = Qt::CaseSensitive;
- d->sort_role = Qt::DisplayRole;
- d->sort_localeaware = false;
- d->filter_column = 0;
- d->filter_role = Qt::DisplayRole;
- d->filter_recursive = false;
- d->dynamic_sortfilter = true;
- d->complete_insert = false;
- connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping()));
+ QObjectPrivate::connect(this, &QAbstractItemModel::modelReset, d,
+ &QSortFilterProxyModelPrivate::_q_clearMapping);
}
/*!
@@ -2031,56 +2035,10 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
beginResetModel();
- disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>)));
-
- disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
-
- disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
-
- disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
-
- disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
-
- disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
-
- disconnect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
-
- disconnect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
-
- disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
- disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
+ if (d->model) {
+ for (const QMetaObject::Connection &connection : std::as_const(d->sourceConnections))
+ disconnect(connection);
+ }
// same as in _q_sourceReset()
d->invalidatePersistentIndexes();
@@ -2088,57 +2046,61 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
QAbstractProxyModel::setSourceModel(sourceModel);
- connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector<int>)));
+ d->sourceConnections = std::array<QMetaObject::Connection, 18>{
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::dataChanged, d,
+ &QSortFilterProxyModelPrivate::_q_sourceDataChanged),
- connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::headerDataChanged, d,
+ &QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged),
- connect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsAboutToBeInserted, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted),
- connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsInserted, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsInserted),
- connect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeInserted, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted),
- connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsInserted, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsInserted),
- connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsAboutToBeRemoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved),
- connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsRemoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsRemoved),
- connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeRemoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved),
- connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsRemoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved),
- connect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsAboutToBeMoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeMoved),
- connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsMoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsMoved),
- connect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeMoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeMoved),
- connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsMoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsMoved),
- connect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::layoutAboutToBeChanged, d,
+ &QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged),
- connect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::layoutChanged, d,
+ &QSortFilterProxyModelPrivate::_q_sourceLayoutChanged),
- connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
- connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::modelAboutToBeReset, d,
+ &QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::modelReset, d,
+ &QSortFilterProxyModelPrivate::_q_sourceReset)
+ };
endResetModel();
if (d->update_source_sort_column() && d->dynamic_sortfilter)
d->sort();
@@ -2155,7 +2117,7 @@ QModelIndex QSortFilterProxyModel::index(int row, int column, const QModelIndex
QModelIndex source_parent = mapToSource(parent); // parent is already mapped at this point
IndexMap::const_iterator it = d->create_mapping(source_parent); // but make sure that the children are mapped
- if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column)
+ if (it.value()->source_rows.size() <= row || it.value()->source_columns.size() <= column)
return QModelIndex();
return d->create_index(row, column, it);
@@ -2186,7 +2148,7 @@ QModelIndex QSortFilterProxyModel::sibling(int row, int column, const QModelInde
return QModelIndex();
const IndexMap::const_iterator it = d->index_to_iterator(idx);
- if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column)
+ if (it.value()->source_rows.size() <= row || it.value()->source_columns.size() <= column)
return QModelIndex();
return d->create_index(row, column, it);
@@ -2202,7 +2164,7 @@ int QSortFilterProxyModel::rowCount(const QModelIndex &parent) const
if (parent.isValid() && !source_parent.isValid())
return 0;
IndexMap::const_iterator it = d->create_mapping(source_parent);
- return it.value()->source_rows.count();
+ return it.value()->source_rows.size();
}
/*!
@@ -2215,7 +2177,7 @@ int QSortFilterProxyModel::columnCount(const QModelIndex &parent) const
if (parent.isValid() && !source_parent.isValid())
return 0;
IndexMap::const_iterator it = d->create_mapping(source_parent);
- return it.value()->source_columns.count();
+ return it.value()->source_columns.size();
}
/*!
@@ -2234,7 +2196,7 @@ bool QSortFilterProxyModel::hasChildren(const QModelIndex &parent) const
return true; //we assume we might have children that can be fetched
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- return m->source_rows.count() != 0 && m->source_columns.count() != 0;
+ return m->source_rows.size() != 0 && m->source_columns.size() != 0;
}
/*!
@@ -2268,15 +2230,15 @@ QVariant QSortFilterProxyModel::headerData(int section, Qt::Orientation orientat
{
Q_D(const QSortFilterProxyModel);
IndexMap::const_iterator it = d->create_mapping(QModelIndex());
- if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
+ if (it.value()->source_rows.size() * it.value()->source_columns.size() > 0)
return QAbstractProxyModel::headerData(section, orientation, role);
int source_section;
if (orientation == Qt::Vertical) {
- if (section < 0 || section >= it.value()->source_rows.count())
+ if (section < 0 || section >= it.value()->source_rows.size())
return QVariant();
source_section = it.value()->source_rows.at(section);
} else {
- if (section < 0 || section >= it.value()->source_columns.count())
+ if (section < 0 || section >= it.value()->source_columns.size())
return QVariant();
source_section = it.value()->source_columns.at(section);
}
@@ -2291,15 +2253,15 @@ bool QSortFilterProxyModel::setHeaderData(int section, Qt::Orientation orientati
{
Q_D(QSortFilterProxyModel);
IndexMap::const_iterator it = d->create_mapping(QModelIndex());
- if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
+ if (it.value()->source_rows.size() * it.value()->source_columns.size() > 0)
return QAbstractProxyModel::setHeaderData(section, orientation, value, role);
int source_section;
if (orientation == Qt::Vertical) {
- if (section < 0 || section >= it.value()->source_rows.count())
+ if (section < 0 || section >= it.value()->source_rows.size())
return false;
source_section = it.value()->source_rows.at(section);
} else {
- if (section < 0 || section >= it.value()->source_columns.count())
+ if (section < 0 || section >= it.value()->source_columns.size())
return false;
source_section = it.value()->source_columns.at(section);
}
@@ -2313,7 +2275,7 @@ QMimeData *QSortFilterProxyModel::mimeData(const QModelIndexList &indexes) const
{
Q_D(const QSortFilterProxyModel);
QModelIndexList source_indexes;
- source_indexes.reserve(indexes.count());
+ source_indexes.reserve(indexes.size());
for (const QModelIndex &idx : indexes)
source_indexes << mapToSource(idx);
return d->model->mimeData(source_indexes);
@@ -2359,10 +2321,10 @@ bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &pa
if (parent.isValid() && !source_parent.isValid())
return false;
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- if (row > m->source_rows.count())
+ if (row > m->source_rows.size())
return false;
- int source_row = (row >= m->source_rows.count()
- ? m->proxy_rows.count()
+ int source_row = (row >= m->source_rows.size()
+ ? m->proxy_rows.size()
: m->source_rows.at(row));
return d->model->insertRows(source_row, count, source_parent);
}
@@ -2379,10 +2341,10 @@ bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelInd
if (parent.isValid() && !source_parent.isValid())
return false;
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- if (column > m->source_columns.count())
+ if (column > m->source_columns.size())
return false;
- int source_column = (column >= m->source_columns.count()
- ? m->proxy_columns.count()
+ int source_column = (column >= m->source_columns.size()
+ ? m->proxy_columns.size()
: m->source_columns.at(column));
return d->model->insertColumns(source_column, count, source_parent);
}
@@ -2399,22 +2361,22 @@ bool QSortFilterProxyModel::removeRows(int row, int count, const QModelIndex &pa
if (parent.isValid() && !source_parent.isValid())
return false;
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- if (row + count > m->source_rows.count())
+ if (row + count > m->source_rows.size())
return false;
if ((count == 1)
- || ((d->source_sort_column < 0) && (m->proxy_rows.count() == m->source_rows.count()))) {
+ || ((d->source_sort_column < 0) && (m->proxy_rows.size() == m->source_rows.size()))) {
int source_row = m->source_rows.at(row);
return d->model->removeRows(source_row, count, source_parent);
}
// remove corresponding source intervals
// ### if this proves to be slow, we can switch to single-row removal
- QVector<int> rows;
+ QList<int> rows;
rows.reserve(count);
for (int i = row; i < row + count; ++i)
rows.append(m->source_rows.at(i));
std::sort(rows.begin(), rows.end());
- int pos = rows.count() - 1;
+ int pos = rows.size() - 1;
bool ok = true;
while (pos >= 0) {
const int source_end = rows.at(pos--);
@@ -2441,19 +2403,19 @@ bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelInd
if (parent.isValid() && !source_parent.isValid())
return false;
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- if (column + count > m->source_columns.count())
+ if (column + count > m->source_columns.size())
return false;
- if ((count == 1) || (m->proxy_columns.count() == m->source_columns.count())) {
+ if ((count == 1) || (m->proxy_columns.size() == m->source_columns.size())) {
int source_column = m->source_columns.at(column);
return d->model->removeColumns(source_column, count, source_parent);
}
// remove corresponding source intervals
- QVector<int> columns;
+ QList<int> columns;
columns.reserve(count);
for (int i = column; i < column + count; ++i)
columns.append(m->source_columns.at(i));
- int pos = columns.count() - 1;
+ int pos = columns.size() - 1;
bool ok = true;
while (pos >= 0) {
const int source_end = columns.at(pos--);
@@ -2473,11 +2435,7 @@ bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelInd
*/
void QSortFilterProxyModel::fetchMore(const QModelIndex &parent)
{
- Q_D(QSortFilterProxyModel);
- QModelIndex source_parent;
- if (d->indexValid(parent))
- source_parent = mapToSource(parent);
- d->model->fetchMore(source_parent);
+ QAbstractProxyModel::fetchMore(parent);
}
/*!
@@ -2485,11 +2443,7 @@ void QSortFilterProxyModel::fetchMore(const QModelIndex &parent)
*/
bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const
{
- Q_D(const QSortFilterProxyModel);
- QModelIndex source_parent;
- if (d->indexValid(parent))
- source_parent = mapToSource(parent);
- return d->model->canFetchMore(source_parent);
+ return QAbstractProxyModel::canFetchMore(parent);
}
/*!
@@ -2497,11 +2451,7 @@ bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const
*/
Qt::ItemFlags QSortFilterProxyModel::flags(const QModelIndex &index) const
{
- Q_D(const QSortFilterProxyModel);
- QModelIndex source_index;
- if (d->indexValid(index))
- source_index = mapToSource(index);
- return d->model->flags(source_index);
+ return QAbstractProxyModel::flags(index);
}
/*!
@@ -2542,7 +2492,10 @@ QSize QSortFilterProxyModel::span(const QModelIndex &index) const
}
/*!
- \reimp
+ \reimp
+ Sorts the model by \a column in the given \a order.
+ If the sort \a column is less than zero, the model will be sorted by source model row
+ in the given \a order.
*/
void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
{
@@ -2557,9 +2510,12 @@ void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
/*!
\since 4.5
- \brief the column currently used for sorting
+ \return the column currently used for sorting
+
+ This returns the most recently used sort column. The default value is -1,
+ which means that this proxy model does not sort.
- This returns the most recently used sort column.
+ \sa sort()
*/
int QSortFilterProxyModel::sortColumn() const
{
@@ -2569,9 +2525,12 @@ int QSortFilterProxyModel::sortColumn() const
/*!
\since 4.5
- \brief the order currently used for sorting
+ \return the order currently used for sorting
- This returns the most recently used sort order.
+ This returns the most recently used sort order. The default value is
+ Qt::AscendingOrder.
+
+ \sa sort()
*/
Qt::SortOrder QSortFilterProxyModel::sortOrder() const
{
@@ -2580,61 +2539,61 @@ Qt::SortOrder QSortFilterProxyModel::sortOrder() const
}
/*!
- \property QSortFilterProxyModel::filterRegExp
- \brief the QRegExp used to filter the contents of the source model
-
- Setting this property overwrites the current
- \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}.
- By default, the QRegExp is an empty string matching all contents.
-
- If no QRegExp or an empty string is set, everything in the source model
- will be accepted.
-
- \sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString()
-*/
-QRegExp QSortFilterProxyModel::filterRegExp() const
-{
- Q_D(const QSortFilterProxyModel);
- return d->filter_data.regExp();
-}
-
-void QSortFilterProxyModel::setFilterRegExp(const QRegExp &regExp)
-{
- Q_D(QSortFilterProxyModel);
- d->filter_about_to_be_changed();
- d->filter_data.setRegExp(regExp);
- d->filter_changed();
-}
-
-#if QT_CONFIG(regularexpression)
-/*!
\since 5.12
\property QSortFilterProxyModel::filterRegularExpression
\brief the QRegularExpression used to filter the contents of the source model
- Setting this property overwrites the current
- \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}.
+ Setting this property through the QRegularExpression overload overwrites the
+ current \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}.
By default, the QRegularExpression is an empty string matching all contents.
If no QRegularExpression or an empty string is set, everything in the source
model will be accepted.
+ \note Setting this property propagates the case sensitivity of the new
+ regular expression to the \l filterCaseSensitivity property, and so breaks
+ its binding. Likewise explicitly setting \l filterCaseSensitivity changes
+ the case sensitivity of the current regular expression, thereby breaking
+ its binding.
+
\sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString()
*/
QRegularExpression QSortFilterProxyModel::filterRegularExpression() const
{
Q_D(const QSortFilterProxyModel);
- return d->filter_data.regularExpression();
+ return d->filter_regularexpression;
+}
+
+QBindable<QRegularExpression> QSortFilterProxyModel::bindableFilterRegularExpression()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<QRegularExpression>(&d->filter_regularexpression);
}
void QSortFilterProxyModel::setFilterRegularExpression(const QRegularExpression &regularExpression)
{
Q_D(QSortFilterProxyModel);
+ const QScopedPropertyUpdateGroup guard;
+ const bool regExpChanged =
+ regularExpression != d->filter_regularexpression.valueBypassingBindings();
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
+ d->filter_casesensitive.removeBindingUnlessInWrapper();
+ const Qt::CaseSensitivity cs = d->filter_casesensitive.valueBypassingBindings();
d->filter_about_to_be_changed();
- d->filter_data.setRegularExpression(regularExpression);
- d->filter_changed();
+ const Qt::CaseSensitivity updatedCs =
+ regularExpression.patternOptions() & QRegularExpression::CaseInsensitiveOption
+ ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ d->filter_regularexpression.setValueBypassingBindings(regularExpression);
+ if (cs != updatedCs)
+ d->filter_casesensitive.setValueBypassingBindings(updatedCs);
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ // Do not change the evaluation logic, but notify only if the regular
+ // expression has actually changed.
+ if (regExpChanged)
+ d->filter_regularexpression.notify();
+ if (cs != updatedCs)
+ d->filter_casesensitive.notify();
}
-#endif
/*!
\property QSortFilterProxyModel::filterKeyColumn
@@ -2652,37 +2611,82 @@ int QSortFilterProxyModel::filterKeyColumn() const
void QSortFilterProxyModel::setFilterKeyColumn(int column)
{
+ // While introducing new bindable properties, we still update the value
+ // unconditionally (even if it didn't really change), and call the
+ // filter_about_to_be_changed()/filter_changed() methods, so that we do
+ // not break any code. However we do notify the observing bindings only
+ // if the column has actually changed
Q_D(QSortFilterProxyModel);
+ d->filter_column.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
- d->filter_column = column;
- d->filter_changed();
+ const auto oldColumn = d->filter_column.valueBypassingBindings();
+ d->filter_column.setValueBypassingBindings(column);
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ if (oldColumn != column)
+ d->filter_column.notify();
+}
+
+QBindable<int> QSortFilterProxyModel::bindableFilterKeyColumn()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<int>(&d->filter_column);
}
/*!
\property QSortFilterProxyModel::filterCaseSensitivity
- \brief the case sensitivity of the QRegExp pattern used to filter the
- contents of the source model
+ \brief the case sensitivity of the QRegularExpression pattern used to filter the
+ contents of the source model.
By default, the filter is case sensitive.
- \sa filterRegExp, sortCaseSensitivity
+ \note Setting this property propagates the new case sensitivity to the
+ \l filterRegularExpression property, and so breaks its binding. Likewise
+ explicitly setting \l filterRegularExpression changes the current case
+ sensitivity, thereby breaking its binding.
+
+ \sa filterRegularExpression, sortCaseSensitivity
*/
+
+/*!
+ \since 5.15
+ \fn void QSortFilterProxyModel::filterCaseSensitivityChanged(Qt::CaseSensitivity filterCaseSensitivity)
+ \brief This signal is emitted when the case sensitivity of the filter
+ changes to \a filterCaseSensitivity.
+ */
Qt::CaseSensitivity QSortFilterProxyModel::filterCaseSensitivity() const
{
Q_D(const QSortFilterProxyModel);
- return d->filter_data.caseSensitivity();
+ return d->filter_casesensitive;
}
void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs)
{
Q_D(QSortFilterProxyModel);
- if (cs == d->filter_data.caseSensitivity())
+ d->filter_casesensitive.removeBindingUnlessInWrapper();
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
+ if (cs == d->filter_casesensitive)
return;
+
+ const QScopedPropertyUpdateGroup guard;
+ QRegularExpression::PatternOptions options =
+ d->filter_regularexpression.value().patternOptions();
+ options.setFlag(QRegularExpression::CaseInsensitiveOption, cs == Qt::CaseInsensitive);
+ d->filter_casesensitive.setValueBypassingBindings(cs);
+
d->filter_about_to_be_changed();
- d->filter_data.setCaseSensitivity(cs);
- d->filter_changed();
- emit filterCaseSensitivityChanged(cs);
+ QRegularExpression re = d->filter_regularexpression;
+ re.setPatternOptions(options);
+ d->filter_regularexpression.setValueBypassingBindings(re);
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->filter_regularexpression.notify();
+ d->filter_casesensitive.notify();
+}
+
+QBindable<Qt::CaseSensitivity> QSortFilterProxyModel::bindableFilterCaseSensitivity()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<Qt::CaseSensitivity>(&d->filter_casesensitive);
}
/*!
@@ -2694,6 +2698,13 @@ void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs)
\sa filterCaseSensitivity, lessThan()
*/
+
+/*!
+ \since 5.15
+ \fn void QSortFilterProxyModel::sortCaseSensitivityChanged(Qt::CaseSensitivity sortCaseSensitivity)
+ \brief This signal is emitted when the case sensitivity for sorting
+ changes to \a sortCaseSensitivity.
+*/
Qt::CaseSensitivity QSortFilterProxyModel::sortCaseSensitivity() const
{
Q_D(const QSortFilterProxyModel);
@@ -2703,12 +2714,19 @@ Qt::CaseSensitivity QSortFilterProxyModel::sortCaseSensitivity() const
void QSortFilterProxyModel::setSortCaseSensitivity(Qt::CaseSensitivity cs)
{
Q_D(QSortFilterProxyModel);
+ d->sort_casesensitivity.removeBindingUnlessInWrapper();
if (d->sort_casesensitivity == cs)
return;
- d->sort_casesensitivity = cs;
+ d->sort_casesensitivity.setValueBypassingBindings(cs);
d->sort();
- emit sortCaseSensitivityChanged(cs);
+ d->sort_casesensitivity.notify(); // also emits a signal
+}
+
+QBindable<Qt::CaseSensitivity> QSortFilterProxyModel::bindableSortCaseSensitivity()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<Qt::CaseSensitivity>(&d->sort_casesensitivity);
}
/*!
@@ -2720,6 +2738,13 @@ void QSortFilterProxyModel::setSortCaseSensitivity(Qt::CaseSensitivity cs)
\sa sortCaseSensitivity, lessThan()
*/
+
+/*!
+ \since 5.15
+ \fn void QSortFilterProxyModel::sortLocaleAwareChanged(bool sortLocaleAware)
+ \brief This signal is emitted when the locale aware setting
+ changes to \a sortLocaleAware.
+*/
bool QSortFilterProxyModel::isSortLocaleAware() const
{
Q_D(const QSortFilterProxyModel);
@@ -2729,33 +2754,21 @@ bool QSortFilterProxyModel::isSortLocaleAware() const
void QSortFilterProxyModel::setSortLocaleAware(bool on)
{
Q_D(QSortFilterProxyModel);
+ d->sort_localeaware.removeBindingUnlessInWrapper();
if (d->sort_localeaware == on)
return;
- d->sort_localeaware = on;
+ d->sort_localeaware.setValueBypassingBindings(on);
d->sort();
- emit sortLocaleAwareChanged(on);
+ d->sort_localeaware.notify(); // also emits a signal
}
-/*!
- \overload
-
- Sets the regular expression used to filter the contents
- of the source model to \a pattern.
-
- \sa setFilterCaseSensitivity(), setFilterWildcard(), setFilterFixedString(), filterRegExp()
-*/
-void QSortFilterProxyModel::setFilterRegExp(const QString &pattern)
+QBindable<bool> QSortFilterProxyModel::bindableIsSortLocaleAware()
{
Q_D(QSortFilterProxyModel);
- d->filter_about_to_be_changed();
- QRegExp rx(pattern);
- rx.setCaseSensitivity(d->filter_data.caseSensitivity());
- d->filter_data.setRegExp(rx);
- d->filter_changed();
+ return QBindable<bool>(&d->sort_localeaware);
}
-#if QT_CONFIG(regularexpression)
/*!
\since 5.12
@@ -2765,46 +2778,70 @@ void QSortFilterProxyModel::setFilterRegExp(const QString &pattern)
This method should be preferred for new code as it will use
QRegularExpression internally.
+ This method will reset the regular expression options
+ but respect case sensitivity.
+
+ \note Calling this method updates the regular expression, thereby breaking
+ the binding for \l filterRegularExpression. However it has no effect on the
+ \l filterCaseSensitivity bindings.
+
\sa setFilterCaseSensitivity(), setFilterWildcard(), setFilterFixedString(), filterRegularExpression()
*/
void QSortFilterProxyModel::setFilterRegularExpression(const QString &pattern)
{
Q_D(QSortFilterProxyModel);
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
- QRegularExpression rx(pattern);
- d->filter_data.setRegularExpression(rx);
- d->filter_changed();
+ d->set_filter_pattern(pattern);
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->filter_regularexpression.notify();
}
-#endif
/*!
Sets the wildcard expression used to filter the contents
of the source model to the given \a pattern.
- \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterFixedString(), filterRegExp()
+ This method will reset the regular expression options
+ but respect case sensitivity.
+
+ \note Calling this method updates the regular expression, thereby breaking
+ the binding for \l filterRegularExpression. However it has no effect on the
+ \l filterCaseSensitivity bindings.
+
+ \sa setFilterCaseSensitivity(), setFilterRegularExpression(), setFilterFixedString(), filterRegularExpression()
*/
void QSortFilterProxyModel::setFilterWildcard(const QString &pattern)
{
Q_D(QSortFilterProxyModel);
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
- QRegExp rx(pattern, d->filter_data.caseSensitivity(), QRegExp::Wildcard);
- d->filter_data.setRegExp(rx);
- d->filter_changed();
+ d->set_filter_pattern(QRegularExpression::wildcardToRegularExpression(
+ pattern, QRegularExpression::UnanchoredWildcardConversion));
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->filter_regularexpression.notify();
}
/*!
Sets the fixed string used to filter the contents
of the source model to the given \a pattern.
- \sa setFilterCaseSensitivity(), setFilterRegExp(), setFilterWildcard(), filterRegExp()
+ This method will reset the regular expression options
+ but respect case sensitivity.
+
+ \note Calling this method updates the regular expression, thereby breaking
+ the binding for \l filterRegularExpression. However it has no effect on the
+ \l filterCaseSensitivity bindings.
+
+ \sa setFilterCaseSensitivity(), setFilterRegularExpression(), setFilterWildcard(), filterRegularExpression()
*/
void QSortFilterProxyModel::setFilterFixedString(const QString &pattern)
{
Q_D(QSortFilterProxyModel);
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
- QRegExp rx(pattern, d->filter_data.caseSensitivity(), QRegExp::FixedString);
- d->filter_data.setRegExp(rx);
- d->filter_changed();
+ d->set_filter_pattern(QRegularExpression::escape(pattern));
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->filter_regularexpression.notify();
}
/*!
@@ -2822,6 +2859,8 @@ void QSortFilterProxyModel::setFilterFixedString(const QString &pattern)
QComboBox.
The default value is true.
+
+ \sa sortColumn()
*/
bool QSortFilterProxyModel::dynamicSortFilter() const
{
@@ -2831,21 +2870,43 @@ bool QSortFilterProxyModel::dynamicSortFilter() const
void QSortFilterProxyModel::setDynamicSortFilter(bool enable)
{
+ // While introducing new bindable properties, we still update the value
+ // unconditionally (even if it didn't really change), and call the
+ // sort() method, so that we do not break any code.
+ // However we do notify the observing bindings only if the value has
+ // actually changed.
Q_D(QSortFilterProxyModel);
- d->dynamic_sortfilter = enable;
+ d->dynamic_sortfilter.removeBindingUnlessInWrapper();
+ const bool valueChanged = d->dynamic_sortfilter.value() != enable;
+ d->dynamic_sortfilter.setValueBypassingBindings(enable);
if (enable)
d->sort();
+ if (valueChanged)
+ d->dynamic_sortfilter.notify();
+}
+
+QBindable<bool> QSortFilterProxyModel::bindableDynamicSortFilter()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<bool>(&d->dynamic_sortfilter);
}
/*!
\since 4.2
\property QSortFilterProxyModel::sortRole
- \brief the item role that is used to query the source model's data when sorting items
+ \brief the item role that is used to query the source model's data when
+ sorting items.
The default value is Qt::DisplayRole.
\sa lessThan()
*/
+
+/*!
+ \since 5.15
+ \fn void QSortFilterProxyModel::sortRoleChanged(int sortRole)
+ \brief This signal is emitted when the sort role changes to \a sortRole.
+*/
int QSortFilterProxyModel::sortRole() const
{
Q_D(const QSortFilterProxyModel);
@@ -2855,22 +2916,36 @@ int QSortFilterProxyModel::sortRole() const
void QSortFilterProxyModel::setSortRole(int role)
{
Q_D(QSortFilterProxyModel);
- if (d->sort_role == role)
+ d->sort_role.removeBindingUnlessInWrapper();
+ if (d->sort_role.valueBypassingBindings() == role)
return;
- d->sort_role = role;
+ d->sort_role.setValueBypassingBindings(role);
d->sort();
- emit sortRoleChanged(role);
+ d->sort_role.notify(); // also emits a signal
+}
+
+QBindable<int> QSortFilterProxyModel::bindableSortRole()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<int>(&d->sort_role);
}
/*!
\since 4.2
\property QSortFilterProxyModel::filterRole
- \brief the item role that is used to query the source model's data when filtering items
+ \brief the item role that is used to query the source model's data when
+ filtering items.
The default value is Qt::DisplayRole.
\sa filterAcceptsRow()
*/
+
+/*!
+ \since 5.15
+ \fn void QSortFilterProxyModel::filterRoleChanged(int filterRole)
+ \brief This signal is emitted when the filter role changes to \a filterRole.
+*/
int QSortFilterProxyModel::filterRole() const
{
Q_D(const QSortFilterProxyModel);
@@ -2880,12 +2955,19 @@ int QSortFilterProxyModel::filterRole() const
void QSortFilterProxyModel::setFilterRole(int role)
{
Q_D(QSortFilterProxyModel);
- if (d->filter_role == role)
+ d->filter_role.removeBindingUnlessInWrapper();
+ if (d->filter_role.valueBypassingBindings() == role)
return;
d->filter_about_to_be_changed();
- d->filter_role = role;
- d->filter_changed();
- emit filterRoleChanged(role);
+ d->filter_role.setValueBypassingBindings(role);
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->filter_role.notify(); // also emits a signal
+}
+
+QBindable<int> QSortFilterProxyModel::bindableFilterRole()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<int>(&d->filter_role);
}
/*!
@@ -2896,8 +2978,16 @@ void QSortFilterProxyModel::setFilterRole(int role)
The default value is false.
+ \sa autoAcceptChildRows
\sa filterAcceptsRow()
*/
+
+/*!
+ \since 5.15
+ \fn void QSortFilterProxyModel::recursiveFilteringEnabledChanged(bool recursiveFilteringEnabled)
+ \brief This signal is emitted when the recursive filter setting is changed
+ to \a recursiveFilteringEnabled.
+*/
bool QSortFilterProxyModel::isRecursiveFilteringEnabled() const
{
Q_D(const QSortFilterProxyModel);
@@ -2907,25 +2997,66 @@ bool QSortFilterProxyModel::isRecursiveFilteringEnabled() const
void QSortFilterProxyModel::setRecursiveFilteringEnabled(bool recursive)
{
Q_D(QSortFilterProxyModel);
+ d->filter_recursive.removeBindingUnlessInWrapper();
if (d->filter_recursive == recursive)
return;
d->filter_about_to_be_changed();
- d->filter_recursive = recursive;
- d->filter_changed();
- emit recursiveFilteringEnabledChanged(recursive);
+ d->filter_recursive.setValueBypassingBindings(recursive);
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->filter_recursive.notify(); // also emits a signal
}
-#if QT_DEPRECATED_SINCE(5, 11)
+QBindable<bool> QSortFilterProxyModel::bindableRecursiveFilteringEnabled()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<bool>(&d->filter_recursive);
+}
+
+/*!
+ \since 6.0
+ \property QSortFilterProxyModel::autoAcceptChildRows
+ \brief if true the proxy model will not filter out children of accepted
+ rows, even if they themselves would be filtered out otherwise.
+
+ The default value is false.
+
+ \sa recursiveFilteringEnabled
+ \sa filterAcceptsRow()
+*/
+
/*!
- \obsolete
+ \since 6.0
+ \fn void QSortFilterProxyModel::autoAcceptChildRowsChanged(bool autoAcceptChildRows)
+
+ \brief This signals is emitted when the value of the \a autoAcceptChildRows property is changed.
- This function is obsolete. Use invalidate() instead.
+ \sa autoAcceptChildRows
*/
-void QSortFilterProxyModel::clear()
+bool QSortFilterProxyModel::autoAcceptChildRows() const
+{
+ Q_D(const QSortFilterProxyModel);
+ return d->accept_children;
+}
+
+void QSortFilterProxyModel::setAutoAcceptChildRows(bool accept)
{
- invalidate();
+ Q_D(QSortFilterProxyModel);
+ d->accept_children.removeBindingUnlessInWrapper();
+ if (d->accept_children == accept)
+ return;
+
+ d->filter_about_to_be_changed();
+ d->accept_children.setValueBypassingBindings(accept);
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->accept_children.notify(); // also emits a signal
+}
+
+QBindable<bool> QSortFilterProxyModel::bindableAutoAcceptChildRows()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<bool>(&d->accept_children);
}
-#endif
+
/*!
\since 4.3
@@ -2941,32 +3072,66 @@ void QSortFilterProxyModel::invalidate()
emit layoutChanged();
}
-#if QT_DEPRECATED_SINCE(5, 11)
/*!
- \obsolete
+ \since 4.3
+
+ Invalidates the current filtering.
- This function is obsolete. Use invalidateFilter() instead.
+ This function should be called if you are implementing custom filtering
+ (e.g. filterAcceptsRow()), and your filter parameters have changed.
+
+ \sa invalidate()
+ \sa invalidateColumnsFilter()
+ \sa invalidateRowsFilter()
*/
-void QSortFilterProxyModel::filterChanged()
+void QSortFilterProxyModel::invalidateFilter()
{
- invalidateFilter();
+ Q_D(QSortFilterProxyModel);
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::All);
}
-#endif
/*!
- \since 4.3
+ \since 6.0
- Invalidates the current filtering.
+ Invalidates the current filtering for the columns.
This function should be called if you are implementing custom filtering
- (e.g. filterAcceptsRow()), and your filter parameters have changed.
+ (by filterAcceptsColumn()), and your filter parameters have changed.
+ This differs from invalidateFilter() in that it will not invoke
+ filterAcceptsRow(), but only filterAcceptsColumn(). You can use this
+ instead of invalidateFilter() if you want to hide or show a column where
+ the rows don't change.
\sa invalidate()
+ \sa invalidateFilter()
+ \sa invalidateRowsFilter()
*/
-void QSortFilterProxyModel::invalidateFilter()
+void QSortFilterProxyModel::invalidateColumnsFilter()
+{
+ Q_D(QSortFilterProxyModel);
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Columns);
+}
+
+/*!
+ \since 6.0
+
+ Invalidates the current filtering for the rows.
+
+ This function should be called if you are implementing custom filtering
+ (by filterAcceptsRow()), and your filter parameters have changed.
+ This differs from invalidateFilter() in that it will not invoke
+ filterAcceptsColumn(), but only filterAcceptsRow(). You can use this
+ instead of invalidateFilter() if you want to hide or show a row where
+ the columns don't change.
+
+ \sa invalidate()
+ \sa invalidateFilter()
+ \sa invalidateColumnsFilter()
+*/
+void QSortFilterProxyModel::invalidateRowsFilter()
{
Q_D(QSortFilterProxyModel);
- d->filter_changed();
+ d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
}
/*!
@@ -3026,43 +3191,41 @@ bool QSortFilterProxyModel::lessThan(const QModelIndex &source_left, const QMode
should be accepted or not. This can be changed by setting the
\l{QSortFilterProxyModel::filterRole}{filterRole} property.
- \sa filterAcceptsColumn(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard()
+ \sa filterAcceptsColumn(), setFilterFixedString(), setFilterRegularExpression(), setFilterWildcard()
*/
bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
Q_D(const QSortFilterProxyModel);
- if (d->filter_data.isEmpty())
+ if (d->filter_regularexpression.value().pattern().isEmpty())
return true;
+
+ int column_count = d->model->columnCount(source_parent);
if (d->filter_column == -1) {
- int column_count = d->model->columnCount(source_parent);
for (int column = 0; column < column_count; ++column) {
QModelIndex source_index = d->model->index(source_row, column, source_parent);
QString key = d->model->data(source_index, d->filter_role).toString();
- if (d->filter_data.hasMatch(key))
+ if (key.contains(d->filter_regularexpression.value()))
return true;
}
return false;
}
- QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
- if (!source_index.isValid()) // the column may not exist
+
+ if (d->filter_column >= column_count) // the column may not exist
return true;
+ QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
QString key = d->model->data(source_index, d->filter_role).toString();
- return d->filter_data.hasMatch(key);
+ return key.contains(d->filter_regularexpression.value());
}
/*!
Returns \c true if the item in the column indicated by the given \a source_column
and \a source_parent should be included in the model; otherwise returns \c false.
- The default implementation returns \c true if the value held by the relevant item
- matches the filter string, wildcard string or regular expression.
-
- \note By default, the Qt::DisplayRole is used to determine if the column
- should be accepted or not. This can be changed by setting the \l
- filterRole property.
+ \note The default implementation always returns \c true. You must reimplement this
+ method to get the described behavior.
- \sa filterAcceptsRow(), setFilterFixedString(), setFilterRegExp(), setFilterWildcard()
+ \sa filterAcceptsRow(), setFilterFixedString(), setFilterRegularExpression(), setFilterWildcard()
*/
bool QSortFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
{
diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.h b/src/corelib/itemmodels/qsortfilterproxymodel.h
index 91253dd601..9d5b2fac9f 100644
--- a/src/corelib/itemmodels/qsortfilterproxymodel.h
+++ b/src/corelib/itemmodels/qsortfilterproxymodel.h
@@ -1,51 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSORTFILTERPROXYMODEL_H
#define QSORTFILTERPROXYMODEL_H
#include <QtCore/qabstractproxymodel.h>
-#include <QtCore/qregexp.h>
-#if QT_CONFIG(regularexpression)
-# include <QtCore/qregularexpression.h>
-#endif
+#include <QtCore/qregularexpression.h>
QT_REQUIRE_CONFIG(sortfilterproxymodel);
@@ -62,18 +23,29 @@ class Q_CORE_EXPORT QSortFilterProxyModel : public QAbstractProxyModel
friend class QSortFilterProxyModelGreaterThan;
Q_OBJECT
- Q_PROPERTY(QRegExp filterRegExp READ filterRegExp WRITE setFilterRegExp)
-#if QT_CONFIG(regularexpression)
- Q_PROPERTY(QRegularExpression filterRegularExpression READ filterRegularExpression WRITE setFilterRegularExpression)
-#endif
- Q_PROPERTY(int filterKeyColumn READ filterKeyColumn WRITE setFilterKeyColumn)
- Q_PROPERTY(bool dynamicSortFilter READ dynamicSortFilter WRITE setDynamicSortFilter)
- Q_PROPERTY(Qt::CaseSensitivity filterCaseSensitivity READ filterCaseSensitivity WRITE setFilterCaseSensitivity NOTIFY filterCaseSensitivityChanged)
- Q_PROPERTY(Qt::CaseSensitivity sortCaseSensitivity READ sortCaseSensitivity WRITE setSortCaseSensitivity NOTIFY sortCaseSensitivityChanged)
- Q_PROPERTY(bool isSortLocaleAware READ isSortLocaleAware WRITE setSortLocaleAware NOTIFY sortLocaleAwareChanged)
- Q_PROPERTY(int sortRole READ sortRole WRITE setSortRole NOTIFY sortRoleChanged)
- Q_PROPERTY(int filterRole READ filterRole WRITE setFilterRole NOTIFY filterRoleChanged)
- Q_PROPERTY(bool recursiveFilteringEnabled READ isRecursiveFilteringEnabled WRITE setRecursiveFilteringEnabled NOTIFY recursiveFilteringEnabledChanged)
+ Q_PROPERTY(QRegularExpression filterRegularExpression READ filterRegularExpression
+ WRITE setFilterRegularExpression BINDABLE bindableFilterRegularExpression)
+ Q_PROPERTY(int filterKeyColumn READ filterKeyColumn WRITE setFilterKeyColumn
+ BINDABLE bindableFilterKeyColumn)
+ Q_PROPERTY(bool dynamicSortFilter READ dynamicSortFilter WRITE setDynamicSortFilter
+ BINDABLE bindableDynamicSortFilter)
+ Q_PROPERTY(Qt::CaseSensitivity filterCaseSensitivity READ filterCaseSensitivity
+ WRITE setFilterCaseSensitivity NOTIFY filterCaseSensitivityChanged
+ BINDABLE bindableFilterCaseSensitivity)
+ Q_PROPERTY(Qt::CaseSensitivity sortCaseSensitivity READ sortCaseSensitivity
+ WRITE setSortCaseSensitivity NOTIFY sortCaseSensitivityChanged
+ BINDABLE bindableSortCaseSensitivity)
+ Q_PROPERTY(bool isSortLocaleAware READ isSortLocaleAware WRITE setSortLocaleAware
+ NOTIFY sortLocaleAwareChanged BINDABLE bindableIsSortLocaleAware)
+ Q_PROPERTY(int sortRole READ sortRole WRITE setSortRole NOTIFY sortRoleChanged
+ BINDABLE bindableSortRole)
+ Q_PROPERTY(int filterRole READ filterRole WRITE setFilterRole NOTIFY filterRoleChanged
+ BINDABLE bindableFilterRole)
+ Q_PROPERTY(bool recursiveFilteringEnabled READ isRecursiveFilteringEnabled
+ WRITE setRecursiveFilteringEnabled NOTIFY recursiveFilteringEnabledChanged
+ BINDABLE bindableRecursiveFilteringEnabled)
+ Q_PROPERTY(bool autoAcceptChildRows READ autoAcceptChildRows WRITE setAutoAcceptChildRows
+ NOTIFY autoAcceptChildRowsChanged BINDABLE bindableAutoAcceptChildRows)
public:
explicit QSortFilterProxyModel(QObject *parent = nullptr);
@@ -87,51 +59,53 @@ public:
QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const override;
QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection) const override;
- QRegExp filterRegExp() const;
-
-#if QT_CONFIG(regularexpression)
QRegularExpression filterRegularExpression() const;
-#endif
+ QBindable<QRegularExpression> bindableFilterRegularExpression();
int filterKeyColumn() const;
void setFilterKeyColumn(int column);
+ QBindable<int> bindableFilterKeyColumn();
Qt::CaseSensitivity filterCaseSensitivity() const;
void setFilterCaseSensitivity(Qt::CaseSensitivity cs);
+ QBindable<Qt::CaseSensitivity> bindableFilterCaseSensitivity();
Qt::CaseSensitivity sortCaseSensitivity() const;
void setSortCaseSensitivity(Qt::CaseSensitivity cs);
+ QBindable<Qt::CaseSensitivity> bindableSortCaseSensitivity();
bool isSortLocaleAware() const;
void setSortLocaleAware(bool on);
+ QBindable<bool> bindableIsSortLocaleAware();
int sortColumn() const;
Qt::SortOrder sortOrder() const;
bool dynamicSortFilter() const;
void setDynamicSortFilter(bool enable);
+ QBindable<bool> bindableDynamicSortFilter();
int sortRole() const;
void setSortRole(int role);
+ QBindable<int> bindableSortRole();
int filterRole() const;
void setFilterRole(int role);
+ QBindable<int> bindableFilterRole();
bool isRecursiveFilteringEnabled() const;
void setRecursiveFilteringEnabled(bool recursive);
+ QBindable<bool> bindableRecursiveFilteringEnabled();
+
+ bool autoAcceptChildRows() const;
+ void setAutoAcceptChildRows(bool accept);
+ QBindable<bool> bindableAutoAcceptChildRows();
public Q_SLOTS:
- void setFilterRegExp(const QString &pattern);
- void setFilterRegExp(const QRegExp &regExp);
-#if QT_CONFIG(regularexpression)
void setFilterRegularExpression(const QString &pattern);
void setFilterRegularExpression(const QRegularExpression &regularExpression);
-#endif
void setFilterWildcard(const QString &pattern);
void setFilterFixedString(const QString &pattern);
-#if QT_DEPRECATED_SINCE(5, 11)
- QT_DEPRECATED_X("Use QSortFilterProxyModel::invalidate") void clear();
-#endif
void invalidate();
protected:
@@ -139,10 +113,9 @@ protected:
virtual bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const;
virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
-#if QT_DEPRECATED_SINCE(5, 11)
- QT_DEPRECATED_X("Use QSortFilterProxyModel::invalidateFilter") void filterChanged();
-#endif
void invalidateFilter();
+ void invalidateRowsFilter();
+ void invalidateColumnsFilter();
public:
using QObject::parent;
@@ -194,30 +167,11 @@ Q_SIGNALS:
void sortRoleChanged(int sortRole);
void filterRoleChanged(int filterRole);
void recursiveFilteringEnabledChanged(bool recursiveFilteringEnabled);
+ void autoAcceptChildRowsChanged(bool autoAcceptChildRows);
private:
Q_DECLARE_PRIVATE(QSortFilterProxyModel)
Q_DISABLE_COPY(QSortFilterProxyModel)
-
- Q_PRIVATE_SLOT(d_func(), void _q_sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right, const QVector<int> &roles))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceAboutToBeReset())
- Q_PRIVATE_SLOT(d_func(), void _q_sourceReset())
- Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsInserted(const QModelIndex &source_parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsRemoved(const QModelIndex &source_parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeInserted(const QModelIndex &source_parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsInserted(const QModelIndex &source_parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsRemoved(const QModelIndex &source_parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int))
- Q_PRIVATE_SLOT(d_func(), void _q_clearMapping())
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qstringlistmodel.cpp b/src/corelib/itemmodels/qstringlistmodel.cpp
index a950783ed8..dfbe72b289 100644
--- a/src/corelib/itemmodels/qstringlistmodel.cpp
+++ b/src/corelib/itemmodels/qstringlistmodel.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*
A simple model that uses a QStringList as its data source.
@@ -43,7 +7,8 @@
#include "qstringlistmodel.h"
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
#include <algorithm>
@@ -121,7 +86,7 @@ int QStringListModel::rowCount(const QModelIndex &parent) const
if (parent.isValid())
return 0;
- return lst.count();
+ return lst.size();
}
/*!
@@ -129,7 +94,7 @@ int QStringListModel::rowCount(const QModelIndex &parent) const
*/
QModelIndex QStringListModel::sibling(int row, int column, const QModelIndex &idx) const
{
- if (!idx.isValid() || column != 0 || row >= lst.count() || row < 0)
+ if (!idx.isValid() || column != 0 || row >= lst.size() || row < 0)
return QModelIndex();
return createIndex(row, 0);
@@ -231,7 +196,6 @@ bool QStringListModel::setData(const QModelIndex &index, const QVariant &value,
return false;
}
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
/*!
\reimp
\since 6.0
@@ -240,7 +204,6 @@ bool QStringListModel::clearItemData(const QModelIndex &index)
{
return setData(index, QVariant(), Qt::EditRole);
}
-#endif
/*!
Inserts \a count rows into the model, beginning at the given \a row.
@@ -329,12 +292,12 @@ bool QStringListModel::moveRows(const QModelIndex &sourceParent, int sourceRow,
return true;
}
-static bool ascendingLessThan(const QPair<QString, int> &s1, const QPair<QString, int> &s2)
+static bool ascendingLessThan(const std::pair<QString, int> &s1, const std::pair<QString, int> &s2)
{
return s1.first < s2.first;
}
-static bool decendingLessThan(const QPair<QString, int> &s1, const QPair<QString, int> &s2)
+static bool decendingLessThan(const std::pair<QString, int> &s1, const std::pair<QString, int> &s2)
{
return s1.first > s2.first;
}
@@ -346,11 +309,11 @@ void QStringListModel::sort(int, Qt::SortOrder order)
{
emit layoutAboutToBeChanged(QList<QPersistentModelIndex>(), VerticalSortHint);
- QVector<QPair<QString, int> > list;
- const int lstCount = lst.count();
+ QList<std::pair<QString, int>> list;
+ const int lstCount = lst.size();
list.reserve(lstCount);
for (int i = 0; i < lstCount; ++i)
- list.append(QPair<QString, int>(lst.at(i), i));
+ list.emplace_back(lst.at(i), i);
if (order == Qt::AscendingOrder)
std::sort(list.begin(), list.end(), ascendingLessThan);
@@ -358,7 +321,7 @@ void QStringListModel::sort(int, Qt::SortOrder order)
std::sort(list.begin(), list.end(), decendingLessThan);
lst.clear();
- QVector<int> forwarding(lstCount);
+ QList<int> forwarding(lstCount);
for (int i = 0; i < lstCount; ++i) {
lst.append(list.at(i).first);
forwarding[list.at(i).second] = i;
@@ -366,7 +329,7 @@ void QStringListModel::sort(int, Qt::SortOrder order)
QModelIndexList oldList = persistentIndexList();
QModelIndexList newList;
- const int numOldIndexes = oldList.count();
+ const int numOldIndexes = oldList.size();
newList.reserve(numOldIndexes);
for (int i = 0; i < numOldIndexes; ++i)
newList.append(index(forwarding.at(oldList.at(i).row()), 0));
diff --git a/src/corelib/itemmodels/qstringlistmodel.h b/src/corelib/itemmodels/qstringlistmodel.h
index 86725ea80b..b93a9c7173 100644
--- a/src/corelib/itemmodels/qstringlistmodel.h
+++ b/src/corelib/itemmodels/qstringlistmodel.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSTRINGLISTMODEL_H
#define QSTRINGLISTMODEL_H
@@ -59,9 +23,7 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool clearItemData(const QModelIndex &index) override;
-#endif
Qt::ItemFlags flags(const QModelIndex &index) const override;
diff --git a/src/corelib/itemmodels/qtransposeproxymodel.cpp b/src/corelib/itemmodels/qtransposeproxymodel.cpp
index 4853f90632..621b54782e 100644
--- a/src/corelib/itemmodels/qtransposeproxymodel.cpp
+++ b/src/corelib/itemmodels/qtransposeproxymodel.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Luca Beldi <v.ronin@yahoo.it>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Luca Beldi <v.ronin@yahoo.it>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtransposeproxymodel.h"
#include <private/qtransposeproxymodel_p.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qsize.h>
+#include <QtCore/qmap.h>
QT_BEGIN_NAMESPACE
@@ -49,9 +14,8 @@ QModelIndex QTransposeProxyModelPrivate::uncheckedMapToSource(const QModelIndex
{
if (!model || !proxyIndex.isValid())
return QModelIndex();
- if (proxyIndex.internalPointer())
- return model->createIndex(proxyIndex.column(), proxyIndex.row(), proxyIndex.internalPointer());
- return model->index(proxyIndex.column(), proxyIndex.row());
+ Q_Q(const QTransposeProxyModel);
+ return q->createSourceIndex(proxyIndex.column(), proxyIndex.row(), proxyIndex.internalPointer());
}
QModelIndex QTransposeProxyModelPrivate::uncheckedMapFromSource(const QModelIndex &sourceIndex) const
@@ -65,9 +29,10 @@ QModelIndex QTransposeProxyModelPrivate::uncheckedMapFromSource(const QModelInde
void QTransposeProxyModelPrivate::onLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QTransposeProxyModel);
+ Q_ASSERT(layoutChangeProxyIndexes.size() == layoutChangePersistentIndexes.size());
QModelIndexList toList;
toList.reserve(layoutChangePersistentIndexes.size());
- for (const QPersistentModelIndex &persistIdx : qAsConst(layoutChangePersistentIndexes))
+ for (const QPersistentModelIndex &persistIdx : std::as_const(layoutChangePersistentIndexes))
toList << q->mapFromSource(persistIdx);
q->changePersistentIndexList(layoutChangeProxyIndexes, toList);
layoutChangeProxyIndexes.clear();
@@ -84,34 +49,42 @@ void QTransposeProxyModelPrivate::onLayoutChanged(const QList<QPersistentModelIn
emit q->layoutChanged(proxyParents, proxyHint);
}
-void QTransposeProxyModelPrivate::onLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
+void QTransposeProxyModelPrivate::onLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QTransposeProxyModel);
+ QList<QPersistentModelIndex> proxyParents;
+ proxyParents.reserve(sourceParents.size());
+ for (const QPersistentModelIndex &parent : sourceParents) {
+ if (!parent.isValid()) {
+ proxyParents << QPersistentModelIndex();
+ continue;
+ }
+ const QModelIndex mappedParent = q->mapFromSource(parent);
+ Q_ASSERT(mappedParent.isValid());
+ proxyParents << mappedParent;
+ }
+ QAbstractItemModel::LayoutChangeHint proxyHint = QAbstractItemModel::NoLayoutChangeHint;
+ if (hint == QAbstractItemModel::VerticalSortHint)
+ proxyHint = QAbstractItemModel::HorizontalSortHint;
+ else if (hint == QAbstractItemModel::HorizontalSortHint)
+ proxyHint = QAbstractItemModel::VerticalSortHint;
+ emit q->layoutAboutToBeChanged(proxyParents, proxyHint);
const QModelIndexList proxyPersistentIndexes = q->persistentIndexList();
layoutChangeProxyIndexes.clear();
layoutChangePersistentIndexes.clear();
layoutChangeProxyIndexes.reserve(proxyPersistentIndexes.size());
layoutChangePersistentIndexes.reserve(proxyPersistentIndexes.size());
- for (const QPersistentModelIndex &proxyPersistentIndex : proxyPersistentIndexes) {
+ for (const QModelIndex &proxyPersistentIndex : proxyPersistentIndexes) {
layoutChangeProxyIndexes << proxyPersistentIndex;
Q_ASSERT(proxyPersistentIndex.isValid());
const QPersistentModelIndex srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
Q_ASSERT(srcPersistentIndex.isValid());
layoutChangePersistentIndexes << srcPersistentIndex;
}
- QList<QPersistentModelIndex> proxyParents;
- proxyParents.reserve(parents.size());
- for (auto& srcParent : parents)
- proxyParents << q->mapFromSource(srcParent);
- QAbstractItemModel::LayoutChangeHint proxyHint = QAbstractItemModel::NoLayoutChangeHint;
- if (hint == QAbstractItemModel::VerticalSortHint)
- proxyHint = QAbstractItemModel::HorizontalSortHint;
- else if (hint == QAbstractItemModel::HorizontalSortHint)
- proxyHint = QAbstractItemModel::VerticalSortHint;
- emit q->layoutAboutToBeChanged(proxyParents, proxyHint);
}
-void QTransposeProxyModelPrivate::onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
+void QTransposeProxyModelPrivate::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &roles)
{
Q_Q(QTransposeProxyModel);
emit q->dataChanged(q->mapFromSource(topLeft), q->mapFromSource(bottomRight), roles);
@@ -162,6 +135,7 @@ void QTransposeProxyModelPrivate::onRowsAboutToBeMoved(const QModelIndex &source
/*!
\since 5.13
\class QTransposeProxyModel
+ \inmodule QtCore
\brief This proxy transposes the source model.
This model will make the rows of the source model become columns of the proxy model and vice-versa.
@@ -198,14 +172,14 @@ void QTransposeProxyModel::setSourceModel(QAbstractItemModel* newSourceModel)
return;
beginResetModel();
if (d->model) {
- for (const QMetaObject::Connection& discIter : qAsConst(d->sourceConnections))
+ for (const QMetaObject::Connection& discIter : std::as_const(d->sourceConnections))
disconnect(discIter);
}
d->sourceConnections.clear();
QAbstractProxyModel::setSourceModel(newSourceModel);
if (d->model) {
using namespace std::placeholders;
- d->sourceConnections = QVector<QMetaObject::Connection>{
+ d->sourceConnections = QList<QMetaObject::Connection>{
connect(d->model, &QAbstractItemModel::modelAboutToBeReset, this, &QTransposeProxyModel::beginResetModel),
connect(d->model, &QAbstractItemModel::modelReset, this, &QTransposeProxyModel::endResetModel),
connect(d->model, &QAbstractItemModel::dataChanged, this, std::bind(&QTransposeProxyModelPrivate::onDataChanged, d, _1, _2, _3)),
@@ -439,8 +413,8 @@ bool QTransposeProxyModel::moveColumns(const QModelIndex &sourceParent, int sour
*/
void QTransposeProxyModel::sort(int column, Qt::SortOrder order)
{
- Q_UNUSED(column)
- Q_UNUSED(order)
+ Q_UNUSED(column);
+ Q_UNUSED(order);
return;
}
diff --git a/src/corelib/itemmodels/qtransposeproxymodel.h b/src/corelib/itemmodels/qtransposeproxymodel.h
index 854a547fd4..67ce6f3bef 100644
--- a/src/corelib/itemmodels/qtransposeproxymodel.h
+++ b/src/corelib/itemmodels/qtransposeproxymodel.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Luca Beldi <v.ronin@yahoo.it>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Luca Beldi <v.ronin@yahoo.it>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTRANSPOSEPROXYMODEL_H
#define QTRANSPOSEPROXYMODEL_H
diff --git a/src/corelib/itemmodels/qtransposeproxymodel_p.h b/src/corelib/itemmodels/qtransposeproxymodel_p.h
index fb5ce5c117..2e0c09b95b 100644
--- a/src/corelib/itemmodels/qtransposeproxymodel_p.h
+++ b/src/corelib/itemmodels/qtransposeproxymodel_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Luca Beldi <v.ronin@yahoo.it>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Luca Beldi <v.ronin@yahoo.it>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTRANSPOSEPROXYMODEL_P_H
#define QTRANSPOSEPROXYMODEL_P_H
@@ -62,14 +26,14 @@ class QTransposeProxyModelPrivate : public QAbstractProxyModelPrivate
Q_DISABLE_COPY(QTransposeProxyModelPrivate)
private:
QTransposeProxyModelPrivate() = default;
- QVector<QMetaObject::Connection> sourceConnections;
- QVector<QPersistentModelIndex> layoutChangePersistentIndexes;
+ QList<QMetaObject::Connection> sourceConnections;
+ QList<QPersistentModelIndex> layoutChangePersistentIndexes;
QModelIndexList layoutChangeProxyIndexes;
QModelIndex uncheckedMapToSource(const QModelIndex &proxyIndex) const;
QModelIndex uncheckedMapFromSource(const QModelIndex &sourceIndex) const;
void onLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
void onLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
- void onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles);
+ void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles);
void onHeaderDataChanged(Qt::Orientation orientation, int first, int last);
void onColumnsAboutToBeInserted(const QModelIndex &parent, int first, int last);
void onColumnsAboutToBeRemoved(const QModelIndex &parent, int first, int last);