Port QtCreator over to use filterRegularExpression

QSortFilterProxyModel::filterRegExp is going to go away in Qt6,
so port over to use QRegularExpression instead.

This required some changes where setFilterWildcard/FixedString()
was being used, as those would instantiate QRegExp based filters
in Qt 5, and will use QRegularExpression in Qt 6. Use the generic
setFilterRegularExpression here, to keep things portable between
5 and 6.

Change-Id: I6379be781aa3821b10ba783c088f82c1a0970911
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Lars Knoll
2020-03-27 11:56:25 +01:00
parent 553c3c2c74
commit 47e576528e
18 changed files with 48 additions and 67 deletions

View File

@@ -25,7 +25,7 @@ https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html
Prerequisites: Prerequisites:
* Qt 5.11.0 or later * Qt 5.12.0 or later
* Qt WebEngine module for QtWebEngine based help viewer * Qt WebEngine module for QtWebEngine based help viewer
* On Windows: * On Windows:
* ActiveState Active Perl * ActiveState Active Perl
@@ -89,7 +89,7 @@ For detailed information on the supported compilers, see
for example, `c:\work`. If you plan to use MinGW and Microsoft Visual for example, `c:\work`. If you plan to use MinGW and Microsoft Visual
Studio simultaneously or mix different Qt versions, we recommend Studio simultaneously or mix different Qt versions, we recommend
creating a directory structure which reflects that. For example: creating a directory structure which reflects that. For example:
`C:\work\qt5.11.0-vs15, C:\work\qt5.11.0-mingw`. `C:\work\qt5.12.0-vs15, C:\work\qt5.12.0-mingw`.
4. Download and install Perl from <https://www.activestate.com/activeperl> 4. Download and install Perl from <https://www.activestate.com/activeperl>
and check that perl.exe is added to the path. Run `perl -v` to verify and check that perl.exe is added to the path. Run `perl -v` to verify

View File

@@ -1,9 +1,9 @@
include(qtcreator.pri) include(qtcreator.pri)
#version check qt #version check qt
!minQtVersion(5, 11, 0) { !minQtVersion(5, 12, 0) {
message("Cannot build $$IDE_DISPLAY_NAME with Qt version $${QT_VERSION}.") message("Cannot build $$IDE_DISPLAY_NAME with Qt version $${QT_VERSION}.")
error("Use at least Qt 5.11.0.") error("Use at least Qt 5.12.0.")
} }
include(doc/doc.pri) include(doc/doc.pri)

View File

@@ -37,9 +37,9 @@ bool CategorySortFilterModel::filterAcceptsRow(int source_row,
{ {
if (!source_parent.isValid()) { if (!source_parent.isValid()) {
// category items should be visible if any of its children match // category items should be visible if any of its children match
const QRegExp &regexp = filterRegExp(); const QRegularExpression &regexp = filterRegularExpression();
const QModelIndex &categoryIndex = sourceModel()->index(source_row, 0, source_parent); const QModelIndex &categoryIndex = sourceModel()->index(source_row, 0, source_parent);
if (regexp.indexIn(sourceModel()->data(categoryIndex, filterRole()).toString()) != -1) if (regexp.match(sourceModel()->data(categoryIndex, filterRole()).toString()).hasMatch())
return true; return true;
const int rowCount = sourceModel()->rowCount(categoryIndex); const int rowCount = sourceModel()->rowCount(categoryIndex);
for (int row = 0; row < rowCount; ++row) { for (int row = 0; row < rowCount; ++row) {

View File

@@ -264,30 +264,6 @@ private:
} }
}; };
class FileFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
FileFilterModel(QObject *parent = nullptr)
: QSortFilterProxyModel(parent)
{}
private:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
{
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
const int rowCount = sourceModel()->rowCount(index);
if (rowCount == 0) // No children -> file node!
return sourceModel()->data(index).toString().contains(filterRegExp());
for (int row = 0; row < rowCount; ++row) {
if (filterAcceptsRow(row, index))
return true;
}
return false;
}
};
SelectableFilesDialog::SelectableFilesDialog(const ProjectInfo &projectInfo, SelectableFilesDialog::SelectableFilesDialog(const ProjectInfo &projectInfo,
const FileInfoProviders &fileInfoProviders, const FileInfoProviders &fileInfoProviders,
int initialProviderIndex) int initialProviderIndex)

View File

@@ -36,6 +36,7 @@
#include <QIcon> #include <QIcon>
#include <QLabel> #include <QLabel>
#include <QPushButton> #include <QPushButton>
#include <QRegularExpression>
using namespace Utils; using namespace Utils;
@@ -227,11 +228,11 @@ const QList<Core::IOptionsPage *> Core::IOptionsPage::allOptionsPages()
} }
/*! /*!
Is used by the \uicontrol Options dialog search filter to match \a searchKeyWord to this options Is used by the \uicontrol Options dialog search filter to match \a regexp to this options
page. This defaults to take the widget and then looks for all child labels, check boxes, push page. This defaults to take the widget and then looks for all child labels, check boxes, push
buttons, and group boxes. Should return \c true when a match is found. buttons, and group boxes. Should return \c true when a match is found.
*/ */
bool Core::IOptionsPage::matches(const QString &searchKeyWord) const bool Core::IOptionsPage::matches(const QRegularExpression &regexp) const
{ {
if (!m_keywordsInitialized) { if (!m_keywordsInitialized) {
auto that = const_cast<IOptionsPage *>(this); auto that = const_cast<IOptionsPage *>(this);
@@ -251,7 +252,7 @@ bool Core::IOptionsPage::matches(const QString &searchKeyWord) const
m_keywordsInitialized = true; m_keywordsInitialized = true;
} }
foreach (const QString &keyword, m_keywords) foreach (const QString &keyword, m_keywords)
if (keyword.contains(searchKeyWord, Qt::CaseInsensitive)) if (keyword.contains(regexp))
return true; return true;
return false; return false;
} }

View File

@@ -64,7 +64,7 @@ public:
using WidgetCreator = std::function<IOptionsPageWidget *()>; using WidgetCreator = std::function<IOptionsPageWidget *()>;
void setWidgetCreator(const WidgetCreator &widgetCreator); void setWidgetCreator(const WidgetCreator &widgetCreator);
virtual bool matches(const QString &searchKeyWord) const; virtual bool matches(const QRegularExpression &regexp) const;
virtual QWidget *widget(); virtual QWidget *widget();
virtual void apply(); virtual void apply();
virtual void finish(); virtual void finish();
@@ -112,7 +112,7 @@ public:
QIcon categoryIcon() const; QIcon categoryIcon() const;
virtual QList<IOptionsPage *> pages() const = 0; virtual QList<IOptionsPage *> pages() const = 0;
virtual bool matches(const QString & /* searchKeyWord*/) const = 0; virtual bool matches(const QRegularExpression &regexp) const = 0;
protected: protected:
void setCategory(Id category) { m_category = category; } void setCategory(Id category) { m_category = category; }

View File

@@ -262,19 +262,18 @@ bool CategoryFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sou
if (QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent)) if (QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent))
return true; return true;
const QString pattern = filterRegExp().pattern(); const QRegularExpression regex = filterRegularExpression();
const CategoryModel *cm = static_cast<CategoryModel*>(sourceModel()); const CategoryModel *cm = static_cast<CategoryModel*>(sourceModel());
const Category *category = cm->categories().at(sourceRow); const Category *category = cm->categories().at(sourceRow);
for (const IOptionsPage *page : category->pages) { for (const IOptionsPage *page : category->pages) {
if (page->displayCategory().contains(pattern, Qt::CaseInsensitive) if (page->displayCategory().contains(regex) || page->displayName().contains(regex)
|| page->displayName().contains(pattern, Qt::CaseInsensitive) || page->matches(regex))
|| page->matches(pattern))
return true; return true;
} }
if (!category->providerPagesCreated) { if (!category->providerPagesCreated) {
for (const IOptionsPageProvider *provider : category->providers) { for (const IOptionsPageProvider *provider : category->providers) {
if (provider->matches(pattern)) if (provider->matches(regex))
return true; return true;
} }
} }
@@ -469,8 +468,14 @@ SettingsDialog::SettingsDialog(QWidget *parent) :
// The order of the slot connection matters here, the filter slot // The order of the slot connection matters here, the filter slot
// opens the matching page after the model has filtered. // opens the matching page after the model has filtered.
connect(m_filterLineEdit, &Utils::FancyLineEdit::filterChanged, connect(m_filterLineEdit,
&m_proxyModel, &QSortFilterProxyModel::setFilterFixedString); &Utils::FancyLineEdit::filterChanged,
&m_proxyModel,
[this](const QString &filter) {
m_proxyModel.setFilterRegularExpression(
QRegularExpression(QRegularExpression::escape(filter),
QRegularExpression::CaseInsensitiveOption));
});
connect(m_filterLineEdit, &Utils::FancyLineEdit::filterChanged, connect(m_filterLineEdit, &Utils::FancyLineEdit::filterChanged,
this, &SettingsDialog::filter); this, &SettingsDialog::filter);
m_categoryList->setFocus(); m_categoryList->setFocus();
@@ -631,12 +636,12 @@ void SettingsDialog::disconnectTabWidgets()
void SettingsDialog::updateEnabledTabs(Category *category, const QString &searchText) void SettingsDialog::updateEnabledTabs(Category *category, const QString &searchText)
{ {
int firstEnabledTab = -1; int firstEnabledTab = -1;
const QRegularExpression regex(QRegularExpression::escape(searchText),
QRegularExpression::CaseInsensitiveOption);
for (int i = 0; i < category->pages.size(); ++i) { for (int i = 0; i < category->pages.size(); ++i) {
const IOptionsPage *page = category->pages.at(i); const IOptionsPage *page = category->pages.at(i);
const bool enabled = searchText.isEmpty() const bool enabled = searchText.isEmpty() || page->category().toString().contains(regex)
|| page->category().toString().contains(searchText, Qt::CaseInsensitive) || page->displayName().contains(regex) || page->matches(regex);
|| page->displayName().contains(searchText, Qt::CaseInsensitive)
|| page->matches(searchText);
category->tabWidget->setTabEnabled(i, enabled); category->tabWidget->setTabEnabled(i, enabled);
if (enabled && firstEnabledTab < 0) if (enabled && firstEnabledTab < 0)
firstEnabledTab = i; firstEnabledTab = i;

View File

@@ -90,8 +90,8 @@ public:
if (!index.isValid()) if (!index.isValid())
return false; return false;
const QRegExp regexp = filterRegExp(); const QRegularExpression regexp = filterRegularExpression();
if (regexp.isEmpty() || sourceModel()->rowCount(index) > 0) if (regexp.pattern().isEmpty() || sourceModel()->rowCount(index) > 0)
return true; return true;
const QString displayText = index.data(Qt::DisplayRole).toString(); const QString displayText = index.data(Qt::DisplayRole).toString();
@@ -548,7 +548,7 @@ void VariableChooserPrivate::updatePositionAndShow(bool)
void VariableChooserPrivate::updateFilter(const QString &filterText) void VariableChooserPrivate::updateFilter(const QString &filterText)
{ {
m_sortModel->setFilterWildcard(filterText); m_sortModel->setFilterRegularExpression(QRegularExpression::wildcardToRegularExpression(filterText));
m_variableTree->expandAll(); m_variableTree->expandAll();
} }

View File

@@ -85,7 +85,7 @@ QList<Core::IOptionsPage *> SettingsPageProvider::pages() const
return FormEditorW::optionsPages(); return FormEditorW::optionsPages();
} }
bool SettingsPageProvider::matches(const QString &searchKeyWord) const bool SettingsPageProvider::matches(const QRegularExpression &regex) const
{ {
// to avoid fully initializing designer when typing something in the options' filter edit // to avoid fully initializing designer when typing something in the options' filter edit
// we hardcode matching of UI text from the designer pages, which are taken if the designer pages // we hardcode matching of UI text from the designer pages, which are taken if the designer pages
@@ -119,7 +119,7 @@ bool SettingsPageProvider::matches(const QString &searchKeyWord) const
m_keywords << Utils::stripAccelerator(QCoreApplication::translate(uitext[i].context, uitext[i].value)); m_keywords << Utils::stripAccelerator(QCoreApplication::translate(uitext[i].context, uitext[i].value));
} }
for (const QString &key : qAsConst(m_keywords)) { for (const QString &key : qAsConst(m_keywords)) {
if (key.contains(searchKeyWord, Qt::CaseInsensitive)) if (key.contains(regex))
return true; return true;
} }
return false; return false;

View File

@@ -63,7 +63,7 @@ public:
SettingsPageProvider(); SettingsPageProvider();
QList<Core::IOptionsPage *> pages() const override; QList<Core::IOptionsPage *> pages() const override;
bool matches(const QString &searchKeyWord) const override; bool matches(const QRegularExpression &regex) const override;
private: private:
mutable bool m_initialized = false; mutable bool m_initialized = false;

View File

@@ -106,7 +106,7 @@ BranchView::BranchView() :
auto filterEdit = new Utils::FancyLineEdit(this); auto filterEdit = new Utils::FancyLineEdit(this);
filterEdit->setFiltering(true); filterEdit->setFiltering(true);
connect(filterEdit, &Utils::FancyLineEdit::textChanged, connect(filterEdit, &Utils::FancyLineEdit::textChanged,
m_filterModel, QOverload<const QString &>::of(&BranchFilterModel::setFilterRegExp)); m_filterModel, QOverload<const QString &>::of(&BranchFilterModel::setFilterRegularExpression));
auto layout = new QVBoxLayout(this); auto layout = new QVBoxLayout(this);
layout->addWidget(filterEdit); layout->addWidget(filterEdit);
layout->addWidget(m_repositoryLabel); layout->addWidget(m_repositoryLabel);

View File

@@ -154,7 +154,7 @@ AddRunConfigDialog::AddRunConfigDialog(Target *target, QWidget *parent)
buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Create")); buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Create"));
connect(filterEdit, &QLineEdit::textChanged, this, [proxyModel](const QString &text) { connect(filterEdit, &QLineEdit::textChanged, this, [proxyModel](const QString &text) {
proxyModel->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive)); proxyModel->setFilterRegularExpression(QRegularExpression(text, QRegularExpression::CaseInsensitiveOption));
}); });
connect(m_view, &TreeView::doubleClicked, this, [this] { accept(); }); connect(m_view, &TreeView::doubleClicked, this, [this] { accept(); });
const auto updateOkButton = [buttonBox, this] { const auto updateOkButton = [buttonBox, this] {

View File

@@ -182,10 +182,10 @@ DeviceProcessesDialogPrivate::DeviceProcessesDialogPrivate(KitChooser *chooser,
// line->setFrameShape(QFrame::HLine); // line->setFrameShape(QFrame::HLine);
// line->setFrameShadow(QFrame::Sunken); // line->setFrameShadow(QFrame::Sunken);
proxyModel.setFilterRegExp(processFilterLineEdit->text()); proxyModel.setFilterRegularExpression(processFilterLineEdit->text());
connect(processFilterLineEdit, QOverload<const QString &>::of(&FancyLineEdit::textChanged), connect(processFilterLineEdit, QOverload<const QString &>::of(&FancyLineEdit::textChanged),
&proxyModel, QOverload<const QString &>::of(&ProcessListFilterModel::setFilterRegExp)); &proxyModel, QOverload<const QString &>::of(&ProcessListFilterModel::setFilterRegularExpression));
connect(procView->selectionModel(), &QItemSelectionModel::selectionChanged, connect(procView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &DeviceProcessesDialogPrivate::updateButtons); this, &DeviceProcessesDialogPrivate::updateButtons);
connect(updateListButton, &QAbstractButton::clicked, connect(updateListButton, &QAbstractButton::clicked,

View File

@@ -202,7 +202,7 @@ void TodoOutputPane::updateKeywordFilter()
int sortColumn = m_todoTreeView->header()->sortIndicatorSection(); int sortColumn = m_todoTreeView->header()->sortIndicatorSection();
Qt::SortOrder sortOrder = m_todoTreeView->header()->sortIndicatorOrder(); Qt::SortOrder sortOrder = m_todoTreeView->header()->sortIndicatorOrder();
m_filteredTodoItemsModel->setFilterRegExp(pattern); m_filteredTodoItemsModel->setFilterRegularExpression(pattern);
m_filteredTodoItemsModel->sort(sortColumn, sortOrder); m_filteredTodoItemsModel->sort(sortColumn, sortOrder);
updateTodoCount(); updateTodoCount();

View File

@@ -109,7 +109,7 @@ bool DataProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_
return false; return false;
// if the filter regexp is a non-empty string, ignore our filters // if the filter regexp is a non-empty string, ignore our filters
if (!filterRegExp().isEmpty()) if (!filterRegularExpression().pattern().isEmpty())
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
// check max rows // check max rows

View File

@@ -554,7 +554,7 @@ void CallgrindToolPrivate::doClear(bool clearParseData)
m_proxyModel.setFilterBaseDir(QString()); m_proxyModel.setFilterBaseDir(QString());
if (m_searchFilter) if (m_searchFilter)
m_searchFilter->clear(); m_searchFilter->clear();
m_proxyModel.setFilterFixedString(QString()); m_proxyModel.setFilterRegularExpression(QRegularExpression());
} }
void CallgrindToolPrivate::setBusyCursor(bool busy) void CallgrindToolPrivate::setBusyCursor(bool busy)
@@ -609,7 +609,7 @@ void CallgrindToolPrivate::stackBrowserChanged()
void CallgrindToolPrivate::updateFilterString() void CallgrindToolPrivate::updateFilterString()
{ {
m_proxyModel.setFilterFixedString(m_searchFilter->text()); m_proxyModel.setFilterRegularExpression(QRegularExpression::escape(m_searchFilter->text()));
} }
void CallgrindToolPrivate::setCostFormat(CostDelegate::CostFormat format) void CallgrindToolPrivate::setCostFormat(CostDelegate::CostFormat format)

View File

@@ -49,6 +49,7 @@
#include <QApplication> #include <QApplication>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QRegularExpression>
#include <QHelpEngine> #include <QHelpEngine>
@@ -76,8 +77,7 @@ BookmarkDialog::BookmarkDialog(BookmarkManager *manager, const QString &title,
proxyModel->setDynamicSortFilter(true); proxyModel->setDynamicSortFilter(true);
proxyModel->setFilterRole(Qt::UserRole + 10); proxyModel->setFilterRole(Qt::UserRole + 10);
proxyModel->setSourceModel(bookmarkManager->treeBookmarkModel()); proxyModel->setSourceModel(bookmarkManager->treeBookmarkModel());
proxyModel->setFilterRegExp(QRegExp(QLatin1String("Folder"), proxyModel->setFilterRegularExpression(QRegularExpression(QLatin1String("Folder")));
Qt::CaseSensitive, QRegExp::FixedString));
ui.treeView->setModel(proxyModel); ui.treeView->setModel(proxyModel);
ui.treeView->expandAll(); ui.treeView->expandAll();
@@ -320,14 +320,14 @@ void BookmarkWidget::filterChanged()
{ {
bool searchBookmarks = searchField->text().isEmpty(); bool searchBookmarks = searchField->text().isEmpty();
if (!searchBookmarks) { if (!searchBookmarks) {
regExp.setPattern(searchField->text()); regExp.setPattern(QRegularExpression::escape(searchField->text()));
filterBookmarkModel->setSourceModel(bookmarkManager->listBookmarkModel()); filterBookmarkModel->setSourceModel(bookmarkManager->listBookmarkModel());
} else { } else {
regExp.setPattern(QString()); regExp.setPattern(QString());
filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel()); filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel());
} }
filterBookmarkModel->setFilterRegExp(regExp); filterBookmarkModel->setFilterRegularExpression(regExp);
const QModelIndex &index = treeView->indexAt(QPoint(1, 1)); const QModelIndex &index = treeView->indexAt(QPoint(1, 1));
if (index.isValid()) if (index.isValid())
@@ -408,8 +408,7 @@ void BookmarkWidget::customContextMenuRequested(const QPoint &point)
void BookmarkWidget::setup() void BookmarkWidget::setup()
{ {
regExp.setPatternSyntax(QRegExp::FixedString); regExp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
regExp.setCaseSensitivity(Qt::CaseInsensitive);
QLayout *vlayout = new QVBoxLayout(this); QLayout *vlayout = new QVBoxLayout(this);
vlayout->setContentsMargins(0, 0, 0, 0); vlayout->setContentsMargins(0, 0, 0, 0);

View File

@@ -122,7 +122,7 @@ private:
void expandItems(); void expandItems();
bool eventFilter(QObject *object, QEvent *event); bool eventFilter(QObject *object, QEvent *event);
QRegExp regExp; QRegularExpression regExp;
TreeView *treeView; TreeView *treeView;
Utils::FancyLineEdit *searchField; Utils::FancyLineEdit *searchField;
BookmarkManager *bookmarkManager; BookmarkManager *bookmarkManager;