diff options
Diffstat (limited to 'src/corelib/itemmodels')
-rw-r--r-- | src/corelib/itemmodels/qabstractitemmodel.cpp | 17 | ||||
-rw-r--r-- | src/corelib/itemmodels/qabstractitemmodel.h | 3 | ||||
-rw-r--r-- | src/corelib/itemmodels/qsortfilterproxymodel.cpp | 247 | ||||
-rw-r--r-- | src/corelib/itemmodels/qsortfilterproxymodel.h | 10 |
4 files changed, 258 insertions, 19 deletions
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index 3a6f67521f..e816add91d 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -1866,6 +1866,23 @@ 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. + Returns \c{true} if successful; otherwise returns \c{false}. + The dataChanged() signal should be emitted if the data was successfully + removed. + The base class implementation returns \c{false} + \sa data(), itemData(), setData(), setItemData() +*/ +bool QAbstractItemModel::clearItemData(const QModelIndex &index) +{ + Q_UNUSED(index); + return false; +} +#endif + /*! \fn QVariant QAbstractItemModel::data(const QModelIndex &index, int role) const = 0 diff --git a/src/corelib/itemmodels/qabstractitemmodel.h b/src/corelib/itemmodels/qabstractitemmodel.h index 21171124f9..bec71b0606 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.h +++ b/src/corelib/itemmodels/qabstractitemmodel.h @@ -198,6 +198,9 @@ 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; diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 6728f0106b..6b59b0723b 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -43,6 +43,7 @@ #include <qdebug.h> #include <qdatetime.h> #include <qpair.h> +#include <qregularexpression.h> #include <qstringlist.h> #include <private/qabstractitemmodel_p.h> #include <private/qabstractproxymodel_p.h> @@ -146,6 +147,133 @@ private: int end; }; +class RegularExpressionData { + +private: + enum class ExpressionType { + RegExp, +#if QT_CONFIG(regularexpression) + RegularExpression +#endif + }; + +public: + RegularExpressionData() : + m_type(ExpressionType::RegExp) + {} + +#if QT_CONFIG(regularexpression) + QRegularExpression regularExpression() const + { + if (m_type == ExpressionType::RegularExpression) + return m_regularExpression; + return QRegularExpression(); + } + + void setRegularExpression(const QRegularExpression &rx) + { + m_type = ExpressionType::RegularExpression; + m_regularExpression = rx; + m_regExp = QRegExp(); + } +#endif + + QRegExp regExp() const + { + if (m_type == ExpressionType::RegExp) + return m_regExp; + return QRegExp(); + } + + void setRegExp(const QRegExp &rx) + { + m_type = ExpressionType::RegExp; + m_regExp = rx; +#if QT_CONFIG(regularexpression) + m_regularExpression = QRegularExpression(); +#endif + + } + + bool isEmpty() const + { + 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; + } + + Qt::CaseSensitivity caseSensitivity() const + { + 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; + } + + void setCaseSensitivity(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 + } + } + + bool hasMatch(const QString &str) const + { + 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; + } + +private: + ExpressionType m_type; + QRegExp m_regExp; +#if QT_CONFIG(regularexpression) + QRegularExpression m_regularExpression; +#endif +}; + + class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate { Q_DECLARE_PUBLIC(QSortFilterProxyModel) @@ -171,7 +299,7 @@ public: int filter_column; int filter_role; - QRegExp filter_regexp; + RegularExpressionData filter_data; QModelIndex last_top_source; bool filter_recursive; @@ -574,6 +702,19 @@ QVector<QPair<int, int > > QSortFilterProxyModelPrivate::proxy_intervals_for_sou proxy_intervals.append(QPair<int, int>(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]; + 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()); return proxy_intervals; } @@ -1096,7 +1237,7 @@ void QSortFilterProxyModelPrivate::update_persistent_indexes( */ void QSortFilterProxyModelPrivate::filter_about_to_be_changed(const QModelIndex &source_parent) { - if (!filter_regexp.pattern().isEmpty() && + if (!filter_data.isEmpty() && source_index_mapping.constFind(source_parent) == source_index_mapping.constEnd()) create_mapping(source_parent); } @@ -1773,9 +1914,9 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved( If a parent item doesn't match the filter, none of its children will be shown. - A common use case is to let the user specify the filter regexp, wildcard - pattern, or fixed string in a QLineEdit and to connect the - \l{QLineEdit::textChanged()}{textChanged()} signal to setFilterRegExp(), + A common use case is to let the user specify the filter regular expression, + wildcard pattern, or fixed string in a QLineEdit and to connect the + \l{QLineEdit::textChanged()}{textChanged()} signal to setFilterRegularExpression(), setFilterWildcard(), or setFilterFixedString() to reapply the filter. Custom filtering behavior can be achieved by reimplementing the @@ -1812,6 +1953,21 @@ 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 */ @@ -2424,17 +2580,47 @@ Qt::SortOrder QSortFilterProxyModel::sortOrder() const QRegExp QSortFilterProxyModel::filterRegExp() const { Q_D(const QSortFilterProxyModel); - return d->filter_regexp; + return d->filter_data.regExp(); } void QSortFilterProxyModel::setFilterRegExp(const QRegExp ®Exp) { Q_D(QSortFilterProxyModel); d->filter_about_to_be_changed(); - d->filter_regexp = regExp; + 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}. + 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. + + \sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString() +*/ +QRegularExpression QSortFilterProxyModel::filterRegularExpression() const +{ + Q_D(const QSortFilterProxyModel); + return d->filter_data.regularExpression(); +} + +void QSortFilterProxyModel::setFilterRegularExpression(const QRegularExpression ®ularExpression) +{ + Q_D(QSortFilterProxyModel); + d->filter_about_to_be_changed(); + d->filter_data.setRegularExpression(regularExpression); + d->filter_changed(); +} +#endif + /*! \property QSortFilterProxyModel::filterKeyColumn \brief the column where the key used to filter the contents of the @@ -2470,16 +2656,16 @@ void QSortFilterProxyModel::setFilterKeyColumn(int column) Qt::CaseSensitivity QSortFilterProxyModel::filterCaseSensitivity() const { Q_D(const QSortFilterProxyModel); - return d->filter_regexp.caseSensitivity(); + return d->filter_data.caseSensitivity(); } void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs) { Q_D(QSortFilterProxyModel); - if (cs == d->filter_regexp.caseSensitivity()) + if (cs == d->filter_data.caseSensitivity()) return; d->filter_about_to_be_changed(); - d->filter_regexp.setCaseSensitivity(cs); + d->filter_data.setCaseSensitivity(cs); d->filter_changed(); } @@ -2545,11 +2731,33 @@ void QSortFilterProxyModel::setFilterRegExp(const QString &pattern) { Q_D(QSortFilterProxyModel); d->filter_about_to_be_changed(); - d->filter_regexp.setPatternSyntax(QRegExp::RegExp); - d->filter_regexp.setPattern(pattern); + QRegExp rx(pattern); + d->filter_data.setRegExp(rx); d->filter_changed(); } +#if QT_CONFIG(regularexpression) +/*! + \since 5.12 + + Sets the regular expression used to filter the contents + of the source model to \a pattern. + + This method should be preferred for new code as it will use + QRegularExpression internally. + + \sa setFilterCaseSensitivity(), setFilterWildcard(), setFilterFixedString(), filterRegularExpression() +*/ +void QSortFilterProxyModel::setFilterRegularExpression(const QString &pattern) +{ + Q_D(QSortFilterProxyModel); + d->filter_about_to_be_changed(); + QRegularExpression rx(pattern); + d->filter_data.setRegularExpression(rx); + d->filter_changed(); +} +#endif + /*! Sets the wildcard expression used to filter the contents of the source model to the given \a pattern. @@ -2560,8 +2768,8 @@ void QSortFilterProxyModel::setFilterWildcard(const QString &pattern) { Q_D(QSortFilterProxyModel); d->filter_about_to_be_changed(); - d->filter_regexp.setPatternSyntax(QRegExp::Wildcard); - d->filter_regexp.setPattern(pattern); + QRegExp rx(pattern, d->filter_data.caseSensitivity(), QRegExp::Wildcard); + d->filter_data.setRegExp(rx); d->filter_changed(); } @@ -2575,8 +2783,8 @@ void QSortFilterProxyModel::setFilterFixedString(const QString &pattern) { Q_D(QSortFilterProxyModel); d->filter_about_to_be_changed(); - d->filter_regexp.setPatternSyntax(QRegExp::FixedString); - d->filter_regexp.setPattern(pattern); + QRegExp rx(pattern, d->filter_data.caseSensitivity(), QRegExp::FixedString); + d->filter_data.setRegExp(rx); d->filter_changed(); } @@ -2801,14 +3009,15 @@ bool QSortFilterProxyModel::lessThan(const QModelIndex &source_left, const QMode bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { Q_D(const QSortFilterProxyModel); - if (d->filter_regexp.isEmpty()) + + if (d->filter_data.isEmpty()) return true; 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 (key.contains(d->filter_regexp)) + if (d->filter_data.hasMatch(key)) return true; } return false; @@ -2817,7 +3026,7 @@ bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex & if (!source_index.isValid()) // the column may not exist return true; QString key = d->model->data(source_index, d->filter_role).toString(); - return key.contains(d->filter_regexp); + return d->filter_data.hasMatch(key); } /*! diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.h b/src/corelib/itemmodels/qsortfilterproxymodel.h index 907ceb8e6d..0b7c69f37d 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.h +++ b/src/corelib/itemmodels/qsortfilterproxymodel.h @@ -42,6 +42,7 @@ #include <QtCore/qabstractproxymodel.h> #include <QtCore/qregexp.h> +#include <QtCore/qregularexpression.h> QT_REQUIRE_CONFIG(sortfilterproxymodel); @@ -59,6 +60,9 @@ class Q_CORE_EXPORT QSortFilterProxyModel : public QAbstractProxyModel 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) @@ -83,6 +87,9 @@ public: QRegExp filterRegExp() const; void setFilterRegExp(const QRegExp ®Exp); + QRegularExpression filterRegularExpression() const; + void setFilterRegularExpression(const QRegularExpression ®ularExpression); + int filterKeyColumn() const; void setFilterKeyColumn(int column); @@ -112,6 +119,9 @@ public: public Q_SLOTS: void setFilterRegExp(const QString &pattern); +#if QT_CONFIG(regularexpression) + void setFilterRegularExpression(const QString &pattern); +#endif void setFilterWildcard(const QString &pattern); void setFilterFixedString(const QString &pattern); #if QT_DEPRECATED_SINCE(5, 11) |