Core: Add infrastructure to do additional filtering on search results

... and make use of it to let users filter C++ "find references" results
by access type.

Fixes: QTCREATORBUG-19373
Change-Id: Ib5cadde1cfd235026d8e69da51daa6374808d3f3
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Christian Kandeler
2020-12-11 16:14:43 +01:00
parent f6d4170c05
commit f3d7717b31
9 changed files with 358 additions and 55 deletions

View File

@@ -27,13 +27,68 @@
#include "searchresulttreeitems.h" #include "searchresulttreeitems.h"
#include "searchresulttreeitemroles.h" #include "searchresulttreeitemroles.h"
#include <utils/algorithm.h>
#include <QApplication> #include <QApplication>
#include <QFont> #include <QFont>
#include <QFontMetrics> #include <QFontMetrics>
#include <QDebug> #include <QDebug>
using namespace Core; namespace Core {
using namespace Core::Internal; namespace Internal {
class SearchResultTreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
SearchResultTreeModel(QObject *parent = nullptr);
~SearchResultTreeModel() override;
void setShowReplaceUI(bool show);
void setTextEditorFont(const QFont &font, const SearchResultColors &colors);
Qt::ItemFlags flags(const QModelIndex &index) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QModelIndex next(const QModelIndex &idx, bool includeGenerated = false, bool *wrapped = nullptr) const;
QModelIndex prev(const QModelIndex &idx, bool includeGenerated = false, bool *wrapped = nullptr) const;
QList<QModelIndex> addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode);
static SearchResultTreeItem *treeItemAtIndex(const QModelIndex &idx);
signals:
void jumpToSearchResult(const QString &fileName, int lineNumber,
int searchTermStart, int searchTermLength);
public slots:
void clear();
private:
QModelIndex index(SearchResultTreeItem *item) const;
void addResultsToCurrentParent(const QList<SearchResultItem> &items, SearchResult::AddMode mode);
QSet<SearchResultTreeItem *> addPath(const QStringList &path);
QVariant data(const SearchResultTreeItem *row, int role) const;
bool setCheckState(const QModelIndex &idx, Qt::CheckState checkState, bool firstCall = true);
QModelIndex nextIndex(const QModelIndex &idx, bool *wrapped = nullptr) const;
QModelIndex prevIndex(const QModelIndex &idx, bool *wrapped = nullptr) const;
SearchResultTreeItem *m_rootItem;
SearchResultTreeItem *m_currentParent;
SearchResultColors m_colors;
QModelIndex m_currentIndex;
QStringList m_currentPath; // the path that belongs to the current parent
QFont m_textEditorFont;
bool m_showReplaceUI;
bool m_editorFontIsUsed;
};
SearchResultTreeModel::SearchResultTreeModel(QObject *parent) SearchResultTreeModel::SearchResultTreeModel(QObject *parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent)
@@ -425,8 +480,6 @@ void SearchResultTreeModel::clear()
QModelIndex SearchResultTreeModel::nextIndex(const QModelIndex &idx, bool *wrapped) const QModelIndex SearchResultTreeModel::nextIndex(const QModelIndex &idx, bool *wrapped) const
{ {
if (wrapped)
*wrapped = false;
// pathological // pathological
if (!idx.isValid()) if (!idx.isValid())
return index(0, 0); return index(0, 0);
@@ -468,8 +521,6 @@ QModelIndex SearchResultTreeModel::next(const QModelIndex &idx, bool includeGene
QModelIndex SearchResultTreeModel::prevIndex(const QModelIndex &idx, bool *wrapped) const QModelIndex SearchResultTreeModel::prevIndex(const QModelIndex &idx, bool *wrapped) const
{ {
if (wrapped)
*wrapped = false;
QModelIndex current = idx; QModelIndex current = idx;
bool checkForChildren = true; bool checkForChildren = true;
if (current.isValid()) { if (current.isValid()) {
@@ -502,3 +553,106 @@ QModelIndex SearchResultTreeModel::prev(const QModelIndex &idx, bool includeGene
} while (value != idx && !includeGenerated && treeItemAtIndex(value)->isGenerated()); } while (value != idx && !includeGenerated && treeItemAtIndex(value)->isGenerated());
return value; return value;
} }
SearchResultFilterModel::SearchResultFilterModel(QObject *parent) : QSortFilterProxyModel(parent)
{
setSourceModel(new SearchResultTreeModel(this));
}
void SearchResultFilterModel::setFilter(SearchResultFilter *filter)
{
if (m_filter)
m_filter->disconnect(this);
m_filter = filter;
if (m_filter) {
connect(m_filter, &SearchResultFilter::filterChanged,
this, [this] {
invalidateFilter();
emit filterInvalidated();
});
}
invalidateFilter();
}
void SearchResultFilterModel::setShowReplaceUI(bool show)
{
sourceModel()->setShowReplaceUI(show);
}
void SearchResultFilterModel::setTextEditorFont(const QFont &font, const SearchResultColors &colors)
{
sourceModel()->setTextEditorFont(font, colors);
}
QList<QModelIndex> SearchResultFilterModel::addResults(const QList<SearchResultItem> &items,
SearchResult::AddMode mode)
{
QList<QModelIndex> sourceIndexes = sourceModel()->addResults(items, mode);
sourceIndexes = Utils::filtered(sourceIndexes, [this](const QModelIndex &idx) {
return filterAcceptsRow(idx.row(), idx.parent());
});
return Utils::transform(sourceIndexes,
[this](const QModelIndex &idx) { return mapFromSource(idx); });
}
void SearchResultFilterModel::clear()
{
sourceModel()->clear();
}
QModelIndex SearchResultFilterModel::nextOrPrev(const QModelIndex &idx, bool *wrapped,
const std::function<QModelIndex (const QModelIndex &)> &func) const
{
if (wrapped)
*wrapped = false;
const QModelIndex sourceIndex = mapToSource(idx);
QModelIndex nextOrPrevSourceIndex = func(sourceIndex);
while (nextOrPrevSourceIndex != sourceIndex
&& !filterAcceptsRow(nextOrPrevSourceIndex.row(), nextOrPrevSourceIndex.parent())) {
nextOrPrevSourceIndex = func(nextOrPrevSourceIndex);
}
return mapFromSource(nextOrPrevSourceIndex);
}
QModelIndex SearchResultFilterModel::next(const QModelIndex &idx, bool includeGenerated,
bool *wrapped) const
{
return nextOrPrev(idx, wrapped, [this, includeGenerated, wrapped](const QModelIndex &index) {
return sourceModel()->next(index, includeGenerated, wrapped); });
}
QModelIndex SearchResultFilterModel::prev(const QModelIndex &idx, bool includeGenerated,
bool *wrapped) const
{
return nextOrPrev(idx, wrapped, [this, includeGenerated, wrapped](const QModelIndex &index) {
return sourceModel()->prev(index, includeGenerated, wrapped); });
}
bool SearchResultFilterModel::filterAcceptsRow(int source_row,
const QModelIndex &source_parent) const
{
const QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
const SearchResultTreeItem * const item = SearchResultTreeModel::treeItemAtIndex(idx);
if (!item)
return false;
if (!m_filter)
return true;
if (item->item.userData.isValid())
return m_filter->matches(item->item);
const int childCount = sourceModel()->rowCount(idx);
for (int i = 0; i < childCount; ++i) {
if (filterAcceptsRow(i, idx))
return true;
}
return false;
}
SearchResultTreeModel *SearchResultFilterModel::sourceModel() const
{
return static_cast<SearchResultTreeModel *>(QSortFilterProxyModel::sourceModel());
}
} // namespace Internal
} // namespace Core
#include <searchresulttreemodel.moc>

View File

@@ -28,64 +28,43 @@
#include "searchresultwindow.h" #include "searchresultwindow.h"
#include "searchresultcolor.h" #include "searchresultcolor.h"
#include <QAbstractItemModel>
#include <QFont> #include <QFont>
#include <QSortFilterProxyModel>
#include <functional>
namespace Core { namespace Core {
namespace Internal { namespace Internal {
class SearchResultTreeItem; class SearchResultTreeModel;
class SearchResultTreeModel : public QAbstractItemModel class SearchResultFilterModel : public QSortFilterProxyModel
{ {
Q_OBJECT Q_OBJECT
public: public:
SearchResultTreeModel(QObject *parent = nullptr); SearchResultFilterModel(QObject *parent = nullptr);
~SearchResultTreeModel() override;
void setFilter(SearchResultFilter *filter);
void setShowReplaceUI(bool show); void setShowReplaceUI(bool show);
void setTextEditorFont(const QFont &font, const SearchResultColors &colors); void setTextEditorFont(const QFont &font, const SearchResultColors &colors);
Qt::ItemFlags flags(const QModelIndex &index) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QModelIndex next(const QModelIndex &idx, bool includeGenerated = false, bool *wrapped = nullptr) const;
QModelIndex prev(const QModelIndex &idx, bool includeGenerated = false, bool *wrapped = nullptr) const;
QList<QModelIndex> addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode); QList<QModelIndex> addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode);
void clear();
QModelIndex next(const QModelIndex &idx, bool includeGenerated = false,
bool *wrapped = nullptr) const;
QModelIndex prev(const QModelIndex &idx, bool includeGenerated = false,
bool *wrapped = nullptr) const;
signals: signals:
void jumpToSearchResult(const QString &fileName, int lineNumber, void filterInvalidated();
int searchTermStart, int searchTermLength);
public slots:
void clear();
private: private:
QModelIndex index(SearchResultTreeItem *item) const; bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
void addResultsToCurrentParent(const QList<SearchResultItem> &items, SearchResult::AddMode mode);
QSet<SearchResultTreeItem *> addPath(const QStringList &path);
QVariant data(const SearchResultTreeItem *row, int role) const;
bool setCheckState(const QModelIndex &idx, Qt::CheckState checkState, bool firstCall = true);
QModelIndex nextIndex(const QModelIndex &idx, bool *wrapped = nullptr) const;
QModelIndex prevIndex(const QModelIndex &idx, bool *wrapped = nullptr) const;
static SearchResultTreeItem *treeItemAtIndex(const QModelIndex &idx);
SearchResultTreeItem *m_rootItem; QModelIndex nextOrPrev(const QModelIndex &idx, bool *wrapped,
SearchResultTreeItem *m_currentParent; const std::function<QModelIndex(const QModelIndex &)> &func) const;
SearchResultColors m_colors; SearchResultTreeModel *sourceModel() const;
QModelIndex m_currentIndex;
QStringList m_currentPath; // the path that belongs to the current parent SearchResultFilter *m_filter = nullptr;
QFont m_textEditorFont;
bool m_showReplaceUI;
bool m_editorFontIsUsed;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -28,18 +28,39 @@
#include "searchresulttreemodel.h" #include "searchresulttreemodel.h"
#include "searchresulttreeitemdelegate.h" #include "searchresulttreeitemdelegate.h"
#include <utils/qtcassert.h>
#include <QHeaderView> #include <QHeaderView>
#include <QKeyEvent> #include <QKeyEvent>
#include <QVBoxLayout>
namespace Core { namespace Core {
namespace Internal { namespace Internal {
class FilterWidget : public QWidget
{
public:
FilterWidget(QWidget *parent, QWidget *content) : QWidget(parent, Qt::Popup)
{
setAttribute(Qt::WA_DeleteOnClose);
const auto layout = new QVBoxLayout(this);
layout->setContentsMargins(2, 2, 2, 2);
layout->setSpacing(2);
layout->addWidget(content);
setLayout(layout);
move(parent->mapToGlobal(QPoint(0, -sizeHint().height())));
}
};
SearchResultTreeView::SearchResultTreeView(QWidget *parent) SearchResultTreeView::SearchResultTreeView(QWidget *parent)
: Utils::TreeView(parent) : Utils::TreeView(parent)
, m_model(new SearchResultTreeModel(this)) , m_model(new SearchResultFilterModel(this))
, m_autoExpandResults(false) , m_autoExpandResults(false)
{ {
setModel(m_model); setModel(m_model);
connect(m_model, &SearchResultFilterModel::filterInvalidated,
this, &SearchResultTreeView::filterInvalidated);
setItemDelegate(new SearchResultTreeItemDelegate(8, this)); setItemDelegate(new SearchResultTreeItemDelegate(8, this));
setIndentation(14); setIndentation(14);
setUniformRowHeights(true); setUniformRowHeights(true);
@@ -80,6 +101,27 @@ void SearchResultTreeView::addResults(const QList<SearchResultItem> &items, Sear
} }
} }
void SearchResultTreeView::setFilter(SearchResultFilter *filter)
{
m_filter = filter;
if (m_filter)
m_filter->setParent(this);
m_model->setFilter(filter);
emit filterChanged();
}
bool SearchResultTreeView::hasFilter() const
{
return m_filter;
}
void SearchResultTreeView::showFilterWidget(QWidget *parent)
{
QTC_ASSERT(hasFilter(), return);
const auto optionsWidget = new FilterWidget(parent, m_filter->createWidget());
optionsWidget->show();
}
void SearchResultTreeView::keyPressEvent(QKeyEvent *event) void SearchResultTreeView::keyPressEvent(QKeyEvent *event)
{ {
if ((event->key() == Qt::Key_Return if ((event->key() == Qt::Key_Return
@@ -118,7 +160,7 @@ void SearchResultTreeView::setTabWidth(int tabWidth)
doItemsLayout(); doItemsLayout();
} }
SearchResultTreeModel *SearchResultTreeView::model() const SearchResultFilterModel *SearchResultTreeView::model() const
{ {
return m_model; return m_model;
} }

View File

@@ -34,7 +34,7 @@ class SearchResultColor;
namespace Internal { namespace Internal {
class SearchResultTreeModel; class SearchResultFilterModel;
class SearchResultTreeView : public Utils::TreeView class SearchResultTreeView : public Utils::TreeView
{ {
@@ -47,21 +47,27 @@ public:
void setTextEditorFont(const QFont &font, const SearchResultColors &colors); void setTextEditorFont(const QFont &font, const SearchResultColors &colors);
void setTabWidth(int tabWidth); void setTabWidth(int tabWidth);
SearchResultTreeModel *model() const; SearchResultFilterModel *model() const;
void addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode); void addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode);
void setFilter(SearchResultFilter *filter);
bool hasFilter() const;
void showFilterWidget(QWidget *parent);
void keyPressEvent(QKeyEvent *event) override; void keyPressEvent(QKeyEvent *event) override;
bool event(QEvent *e) override; bool event(QEvent *e) override;
signals: signals:
void jumpToSearchResult(const SearchResultItem &item); void jumpToSearchResult(const SearchResultItem &item);
void filterInvalidated();
void filterChanged();
public slots: public slots:
void clear(); void clear();
void emitJumpToSearchResult(const QModelIndex &index); void emitJumpToSearchResult(const QModelIndex &index);
protected: protected:
SearchResultTreeModel *m_model; SearchResultFilterModel *m_model;
SearchResultFilter *m_filter = nullptr;
bool m_autoExpandResults; bool m_autoExpandResults;
}; };

View File

@@ -134,6 +134,10 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
m_searchResultTreeView = new SearchResultTreeView(this); m_searchResultTreeView = new SearchResultTreeView(this);
m_searchResultTreeView->setFrameStyle(QFrame::NoFrame); m_searchResultTreeView->setFrameStyle(QFrame::NoFrame);
m_searchResultTreeView->setAttribute(Qt::WA_MacShowFocusRect, false); m_searchResultTreeView->setAttribute(Qt::WA_MacShowFocusRect, false);
connect(m_searchResultTreeView, &SearchResultTreeView::filterInvalidated,
this, &SearchResultWidget::filterInvalidated);
connect(m_searchResultTreeView, &SearchResultTreeView::filterChanged,
this, &SearchResultWidget::filterChanged);
auto agg = new Aggregation::Aggregate; auto agg = new Aggregation::Aggregate;
agg->add(m_searchResultTreeView); agg->add(m_searchResultTreeView);
agg->add(new ItemViewFind(m_searchResultTreeView, agg->add(new ItemViewFind(m_searchResultTreeView,
@@ -443,6 +447,21 @@ void SearchResultWidget::setSearchAgainEnabled(bool enabled)
m_searchAgainButton->setEnabled(enabled); m_searchAgainButton->setEnabled(enabled);
} }
void SearchResultWidget::setFilter(SearchResultFilter *filter)
{
m_searchResultTreeView->setFilter(filter);
}
bool SearchResultWidget::hasFilter() const
{
return m_searchResultTreeView->hasFilter();
}
void SearchResultWidget::showFilterWidget(QWidget *parent)
{
m_searchResultTreeView->showFilterWidget(parent);
}
void SearchResultWidget::setReplaceEnabled(bool enabled) void SearchResultWidget::setReplaceEnabled(bool enabled)
{ {
m_replaceButton->setEnabled(enabled); m_replaceButton->setEnabled(enabled);
@@ -513,7 +532,7 @@ void SearchResultWidget::searchAgain()
QList<SearchResultItem> SearchResultWidget::checkedItems() const QList<SearchResultItem> SearchResultWidget::checkedItems() const
{ {
QList<SearchResultItem> result; QList<SearchResultItem> result;
SearchResultTreeModel *model = m_searchResultTreeView->model(); SearchResultFilterModel *model = m_searchResultTreeView->model();
const int fileCount = model->rowCount(); const int fileCount = model->rowCount();
for (int i = 0; i < fileCount; ++i) { for (int i = 0; i < fileCount; ++i) {
QModelIndex fileIndex = model->index(i, 0); QModelIndex fileIndex = model->index(i, 0);

View File

@@ -90,7 +90,9 @@ public:
void setSearchAgainSupported(bool supported); void setSearchAgainSupported(bool supported);
void setSearchAgainEnabled(bool enabled); void setSearchAgainEnabled(bool enabled);
void setFilter(SearchResultFilter *filter);
bool hasFilter() const;
void showFilterWidget(QWidget *parent);
void setReplaceEnabled(bool enabled); void setReplaceEnabled(bool enabled);
public slots: public slots:
@@ -107,6 +109,8 @@ signals:
void restarted(); void restarted();
void visibilityChanged(bool visible); void visibilityChanged(bool visible);
void requestPopup(bool focus); void requestPopup(bool focus);
void filterInvalidated();
void filterChanged();
void navigateStateChanged(); void navigateStateChanged();

View File

@@ -110,10 +110,12 @@ namespace Internal {
void moveWidgetToTop(); void moveWidgetToTop();
void popupRequested(bool focus); void popupRequested(bool focus);
void handleExpandCollapseToolButton(bool checked); void handleExpandCollapseToolButton(bool checked);
void updateFilterButton();
SearchResultWindow *q; SearchResultWindow *q;
QList<Internal::SearchResultWidget *> m_searchResultWidgets; QList<Internal::SearchResultWidget *> m_searchResultWidgets;
QToolButton *m_expandCollapseButton; QToolButton *m_expandCollapseButton;
QToolButton *m_filterButton;
QToolButton *m_newSearchButton; QToolButton *m_newSearchButton;
QAction *m_expandCollapseAction; QAction *m_expandCollapseAction;
static const bool m_initiallyExpand; static const bool m_initiallyExpand;
@@ -168,6 +170,11 @@ namespace Internal {
cmd->setAttribute(Command::CA_UpdateText); cmd->setAttribute(Command::CA_UpdateText);
m_expandCollapseButton->setDefaultAction(cmd->action()); m_expandCollapseButton->setDefaultAction(cmd->action());
m_filterButton = new QToolButton(m_widget);
m_filterButton->setText(tr("Filter Results"));
m_filterButton->setIcon(Utils::Icons::FILTER.icon());
m_filterButton->setEnabled(false);
QAction *newSearchAction = new QAction(tr("New Search"), this); QAction *newSearchAction = new QAction(tr("New Search"), this);
newSearchAction->setIcon(Utils::Icons::NEWSEARCH_TOOLBAR.icon()); newSearchAction->setIcon(Utils::Icons::NEWSEARCH_TOOLBAR.icon());
cmd = ActionManager::command(Constants::ADVANCED_FIND); cmd = ActionManager::command(Constants::ADVANCED_FIND);
@@ -178,6 +185,13 @@ namespace Internal {
connect(m_expandCollapseAction, &QAction::toggled, connect(m_expandCollapseAction, &QAction::toggled,
this, &SearchResultWindowPrivate::handleExpandCollapseToolButton); this, &SearchResultWindowPrivate::handleExpandCollapseToolButton);
connect(m_filterButton, &QToolButton::clicked, this, [this] {
if (!isSearchVisible())
return;
m_searchResultWidgets.at(visibleSearchIndex())->showFilterWidget(m_filterButton);
});
connect(m_widget, &QStackedWidget::currentChanged,
this, &SearchResultWindowPrivate::updateFilterButton);
} }
void SearchResultWindowPrivate::setCurrentIndex(int index, bool focus) void SearchResultWindowPrivate::setCurrentIndex(int index, bool focus)
@@ -445,7 +459,7 @@ QWidget *SearchResultWindow::outputWidget(QWidget *)
*/ */
QList<QWidget*> SearchResultWindow::toolBarWidgets() const QList<QWidget*> SearchResultWindow::toolBarWidgets() const
{ {
return {d->m_expandCollapseButton, d->m_newSearchButton, d->m_spacer, return {d->m_expandCollapseButton, d->m_filterButton, d->m_newSearchButton, d->m_spacer,
d->m_historyLabel, d->m_spacer2, d->m_recentSearchesBox}; d->m_historyLabel, d->m_spacer2, d->m_recentSearchesBox};
} }
@@ -496,6 +510,12 @@ SearchResult *SearchResultWindow::startNewSearch(const QString &label,
} }
} }
auto widget = new SearchResultWidget; auto widget = new SearchResultWidget;
connect(widget, &SearchResultWidget::filterInvalidated, this, [this, widget] {
if (widget == d->m_searchResultWidgets.at(d->visibleSearchIndex()))
d->handleExpandCollapseToolButton(d->m_expandCollapseButton->isChecked());
});
connect(widget, &SearchResultWidget::filterChanged,
d, &SearchResultWindowPrivate::updateFilterButton);
d->m_searchResultWidgets.prepend(widget); d->m_searchResultWidgets.prepend(widget);
d->m_widget->insertWidget(1, widget); d->m_widget->insertWidget(1, widget);
connect(widget, &SearchResultWidget::navigateStateChanged, connect(widget, &SearchResultWidget::navigateStateChanged,
@@ -615,6 +635,12 @@ void SearchResultWindowPrivate::handleExpandCollapseToolButton(bool checked)
} }
} }
void SearchResultWindowPrivate::updateFilterButton()
{
m_filterButton->setEnabled(isSearchVisible()
&& m_searchResultWidgets.at(visibleSearchIndex())->hasFilter());
}
/*! /*!
\internal \internal
*/ */
@@ -833,6 +859,11 @@ void SearchResult::addResults(const QList<SearchResultItem> &items, AddMode mode
emit countChanged(m_widget->count()); emit countChanged(m_widget->count());
} }
void SearchResult::setFilter(SearchResultFilter *filter)
{
m_widget->setFilter(filter);
}
/*! /*!
Notifies the \uicontrol {Search Results} output pane that the current search Notifies the \uicontrol {Search Results} output pane that the current search
has been \a canceled, and the UI should reflect that. has been \a canceled, and the UI should reflect that.

View File

@@ -45,6 +45,18 @@ namespace Internal {
} }
class SearchResultWindow; class SearchResultWindow;
class CORE_EXPORT SearchResultFilter : public QObject
{
Q_OBJECT
public:
virtual QWidget *createWidget() = 0;
virtual bool matches(const SearchResultItem &item) const = 0;
signals:
void filterChanged();
};
class CORE_EXPORT SearchResult : public QObject class CORE_EXPORT SearchResult : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -77,6 +89,7 @@ public slots:
const QVariant &userData = QVariant(), const QVariant &userData = QVariant(),
SearchResultColor::Style style = SearchResultColor::Style::Default); SearchResultColor::Style style = SearchResultColor::Style::Default);
void addResults(const QList<SearchResultItem> &items, AddMode mode); void addResults(const QList<SearchResultItem> &items, AddMode mode);
void setFilter(SearchResultFilter *filter); // Takes ownership
void finishSearch(bool canceled); void finishSearch(bool canceled);
void setTextToReplace(const QString &textToReplace); void setTextToReplace(const QString &textToReplace);
void restart(); void restart();

View File

@@ -49,6 +49,7 @@
#include <QCheckBox> #include <QCheckBox>
#include <QDir> #include <QDir>
#include <QFutureWatcher> #include <QFutureWatcher>
#include <QVBoxLayout>
#include <functional> #include <functional>
@@ -169,6 +170,58 @@ static QList<QByteArray> fullIdForSymbol(CPlusPlus::Symbol *symbol)
namespace { namespace {
class Filter : public Core::SearchResultFilter
{
QWidget *createWidget() override
{
const auto widget = new QWidget;
const auto layout = new QVBoxLayout(widget);
layout->setContentsMargins(0, 0, 0, 0);
const auto readsCheckBox = new QCheckBox(tr("Reads"));
readsCheckBox->setChecked(m_showReads);
const auto writesCheckBox = new QCheckBox(tr("Writes"));
writesCheckBox->setChecked(m_showWrites);
const auto otherCheckBox = new QCheckBox(tr("Other"));
otherCheckBox->setChecked(m_showOther);
layout->addWidget(readsCheckBox);
layout->addWidget(writesCheckBox);
layout->addWidget(otherCheckBox);
connect(readsCheckBox, &QCheckBox::toggled,
this, [this](bool checked) { setValue(m_showReads, checked); });
connect(writesCheckBox, &QCheckBox::toggled,
this, [this](bool checked) { setValue(m_showWrites, checked); });
connect(otherCheckBox, &QCheckBox::toggled,
this, [this](bool checked) { setValue(m_showOther, checked); });
return widget;
}
bool matches(const SearchResultItem &item) const override
{
switch (static_cast<CPlusPlus::Usage::Type>(item.userData.toInt())) {
case CPlusPlus::Usage::Type::Read:
return m_showReads;
case CPlusPlus::Usage::Type::Write:
case CPlusPlus::Usage::Type::WritableRef:
case CPlusPlus::Usage::Type::Initialization:
return m_showWrites;
case CPlusPlus::Usage::Type::Declaration:
case CPlusPlus::Usage::Type::Other:
return m_showOther;
}
return false;
}
void setValue(bool &member, bool value)
{
member = value;
emit filterChanged();
}
bool m_showReads = true;
bool m_showWrites = true;
bool m_showOther = true;
};
class ProcessFile class ProcessFile
{ {
const WorkingCopy workingCopy; const WorkingCopy workingCopy;
@@ -339,6 +392,7 @@ void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol,
SearchResultWindow::PreserveCaseDisabled, SearchResultWindow::PreserveCaseDisabled,
QLatin1String("CppEditor")); QLatin1String("CppEditor"));
search->setTextToReplace(replacement); search->setTextToReplace(replacement);
search->setFilter(new Filter);
auto renameFilesCheckBox = new QCheckBox(); auto renameFilesCheckBox = new QCheckBox();
renameFilesCheckBox->setVisible(false); renameFilesCheckBox->setVisible(false);
search->setAdditionalReplaceWidget(renameFilesCheckBox); search->setAdditionalReplaceWidget(renameFilesCheckBox);
@@ -570,7 +624,8 @@ static void displayResults(SearchResult *search, QFutureWatcher<CPlusPlus::Usage
for (int index = first; index != last; ++index) { for (int index = first; index != last; ++index) {
const CPlusPlus::Usage result = watcher->future().resultAt(index); const CPlusPlus::Usage result = watcher->future().resultAt(index);
search->addResult(result.path.toString(), result.line, result.lineText, search->addResult(result.path.toString(), result.line, result.lineText,
result.col, result.len, {}, colorStyleForUsageType(result.type)); result.col, result.len, int(result.type),
colorStyleForUsageType(result.type));
if (parameters.prettySymbolName.isEmpty()) if (parameters.prettySymbolName.isEmpty())
continue; continue;