forked from qt-creator/qt-creator
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:
@@ -27,13 +27,68 @@
|
||||
#include "searchresulttreeitems.h"
|
||||
#include "searchresulttreeitemroles.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
#include <QDebug>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Core::Internal;
|
||||
namespace Core {
|
||||
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)
|
||||
: QAbstractItemModel(parent)
|
||||
@@ -425,8 +480,6 @@ void SearchResultTreeModel::clear()
|
||||
|
||||
QModelIndex SearchResultTreeModel::nextIndex(const QModelIndex &idx, bool *wrapped) const
|
||||
{
|
||||
if (wrapped)
|
||||
*wrapped = false;
|
||||
// pathological
|
||||
if (!idx.isValid())
|
||||
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
|
||||
{
|
||||
if (wrapped)
|
||||
*wrapped = false;
|
||||
QModelIndex current = idx;
|
||||
bool checkForChildren = true;
|
||||
if (current.isValid()) {
|
||||
@@ -502,3 +553,106 @@ QModelIndex SearchResultTreeModel::prev(const QModelIndex &idx, bool includeGene
|
||||
} while (value != idx && !includeGenerated && treeItemAtIndex(value)->isGenerated());
|
||||
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>
|
||||
|
@@ -28,64 +28,43 @@
|
||||
#include "searchresultwindow.h"
|
||||
#include "searchresultcolor.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QFont>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace Core {
|
||||
namespace Internal {
|
||||
|
||||
class SearchResultTreeItem;
|
||||
class SearchResultTreeModel;
|
||||
|
||||
class SearchResultTreeModel : public QAbstractItemModel
|
||||
class SearchResultFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SearchResultTreeModel(QObject *parent = nullptr);
|
||||
~SearchResultTreeModel() override;
|
||||
SearchResultFilterModel(QObject *parent = nullptr);
|
||||
|
||||
void setFilter(SearchResultFilter *filter);
|
||||
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);
|
||||
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:
|
||||
void jumpToSearchResult(const QString &fileName, int lineNumber,
|
||||
int searchTermStart, int searchTermLength);
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void filterInvalidated();
|
||||
|
||||
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;
|
||||
static SearchResultTreeItem *treeItemAtIndex(const QModelIndex &idx);
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
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;
|
||||
QModelIndex nextOrPrev(const QModelIndex &idx, bool *wrapped,
|
||||
const std::function<QModelIndex(const QModelIndex &)> &func) const;
|
||||
SearchResultTreeModel *sourceModel() const;
|
||||
|
||||
SearchResultFilter *m_filter = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -28,18 +28,39 @@
|
||||
#include "searchresulttreemodel.h"
|
||||
#include "searchresulttreeitemdelegate.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QKeyEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace Core {
|
||||
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)
|
||||
: Utils::TreeView(parent)
|
||||
, m_model(new SearchResultTreeModel(this))
|
||||
, m_model(new SearchResultFilterModel(this))
|
||||
, m_autoExpandResults(false)
|
||||
{
|
||||
setModel(m_model);
|
||||
connect(m_model, &SearchResultFilterModel::filterInvalidated,
|
||||
this, &SearchResultTreeView::filterInvalidated);
|
||||
|
||||
setItemDelegate(new SearchResultTreeItemDelegate(8, this));
|
||||
setIndentation(14);
|
||||
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)
|
||||
{
|
||||
if ((event->key() == Qt::Key_Return
|
||||
@@ -118,7 +160,7 @@ void SearchResultTreeView::setTabWidth(int tabWidth)
|
||||
doItemsLayout();
|
||||
}
|
||||
|
||||
SearchResultTreeModel *SearchResultTreeView::model() const
|
||||
SearchResultFilterModel *SearchResultTreeView::model() const
|
||||
{
|
||||
return m_model;
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ class SearchResultColor;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class SearchResultTreeModel;
|
||||
class SearchResultFilterModel;
|
||||
|
||||
class SearchResultTreeView : public Utils::TreeView
|
||||
{
|
||||
@@ -47,21 +47,27 @@ public:
|
||||
void setTextEditorFont(const QFont &font, const SearchResultColors &colors);
|
||||
void setTabWidth(int tabWidth);
|
||||
|
||||
SearchResultTreeModel *model() const;
|
||||
SearchResultFilterModel *model() const;
|
||||
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;
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
signals:
|
||||
void jumpToSearchResult(const SearchResultItem &item);
|
||||
void filterInvalidated();
|
||||
void filterChanged();
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void emitJumpToSearchResult(const QModelIndex &index);
|
||||
|
||||
protected:
|
||||
SearchResultTreeModel *m_model;
|
||||
SearchResultFilterModel *m_model;
|
||||
SearchResultFilter *m_filter = nullptr;
|
||||
bool m_autoExpandResults;
|
||||
};
|
||||
|
||||
|
@@ -134,6 +134,10 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
|
||||
m_searchResultTreeView = new SearchResultTreeView(this);
|
||||
m_searchResultTreeView->setFrameStyle(QFrame::NoFrame);
|
||||
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;
|
||||
agg->add(m_searchResultTreeView);
|
||||
agg->add(new ItemViewFind(m_searchResultTreeView,
|
||||
@@ -443,6 +447,21 @@ void SearchResultWidget::setSearchAgainEnabled(bool 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)
|
||||
{
|
||||
m_replaceButton->setEnabled(enabled);
|
||||
@@ -513,7 +532,7 @@ void SearchResultWidget::searchAgain()
|
||||
QList<SearchResultItem> SearchResultWidget::checkedItems() const
|
||||
{
|
||||
QList<SearchResultItem> result;
|
||||
SearchResultTreeModel *model = m_searchResultTreeView->model();
|
||||
SearchResultFilterModel *model = m_searchResultTreeView->model();
|
||||
const int fileCount = model->rowCount();
|
||||
for (int i = 0; i < fileCount; ++i) {
|
||||
QModelIndex fileIndex = model->index(i, 0);
|
||||
|
@@ -90,7 +90,9 @@ public:
|
||||
|
||||
void setSearchAgainSupported(bool supported);
|
||||
void setSearchAgainEnabled(bool enabled);
|
||||
|
||||
void setFilter(SearchResultFilter *filter);
|
||||
bool hasFilter() const;
|
||||
void showFilterWidget(QWidget *parent);
|
||||
void setReplaceEnabled(bool enabled);
|
||||
|
||||
public slots:
|
||||
@@ -107,6 +109,8 @@ signals:
|
||||
void restarted();
|
||||
void visibilityChanged(bool visible);
|
||||
void requestPopup(bool focus);
|
||||
void filterInvalidated();
|
||||
void filterChanged();
|
||||
|
||||
void navigateStateChanged();
|
||||
|
||||
|
@@ -110,10 +110,12 @@ namespace Internal {
|
||||
void moveWidgetToTop();
|
||||
void popupRequested(bool focus);
|
||||
void handleExpandCollapseToolButton(bool checked);
|
||||
void updateFilterButton();
|
||||
|
||||
SearchResultWindow *q;
|
||||
QList<Internal::SearchResultWidget *> m_searchResultWidgets;
|
||||
QToolButton *m_expandCollapseButton;
|
||||
QToolButton *m_filterButton;
|
||||
QToolButton *m_newSearchButton;
|
||||
QAction *m_expandCollapseAction;
|
||||
static const bool m_initiallyExpand;
|
||||
@@ -168,6 +170,11 @@ namespace Internal {
|
||||
cmd->setAttribute(Command::CA_UpdateText);
|
||||
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);
|
||||
newSearchAction->setIcon(Utils::Icons::NEWSEARCH_TOOLBAR.icon());
|
||||
cmd = ActionManager::command(Constants::ADVANCED_FIND);
|
||||
@@ -178,6 +185,13 @@ namespace Internal {
|
||||
connect(m_expandCollapseAction, &QAction::toggled,
|
||||
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)
|
||||
@@ -445,7 +459,7 @@ QWidget *SearchResultWindow::outputWidget(QWidget *)
|
||||
*/
|
||||
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};
|
||||
}
|
||||
|
||||
@@ -496,6 +510,12 @@ SearchResult *SearchResultWindow::startNewSearch(const QString &label,
|
||||
}
|
||||
}
|
||||
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_widget->insertWidget(1, widget);
|
||||
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
|
||||
*/
|
||||
@@ -833,6 +859,11 @@ void SearchResult::addResults(const QList<SearchResultItem> &items, AddMode mode
|
||||
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
|
||||
has been \a canceled, and the UI should reflect that.
|
||||
|
@@ -45,6 +45,18 @@ namespace Internal {
|
||||
}
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -77,6 +89,7 @@ public slots:
|
||||
const QVariant &userData = QVariant(),
|
||||
SearchResultColor::Style style = SearchResultColor::Style::Default);
|
||||
void addResults(const QList<SearchResultItem> &items, AddMode mode);
|
||||
void setFilter(SearchResultFilter *filter); // Takes ownership
|
||||
void finishSearch(bool canceled);
|
||||
void setTextToReplace(const QString &textToReplace);
|
||||
void restart();
|
||||
|
@@ -49,6 +49,7 @@
|
||||
#include <QCheckBox>
|
||||
#include <QDir>
|
||||
#include <QFutureWatcher>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <functional>
|
||||
|
||||
@@ -169,6 +170,58 @@ static QList<QByteArray> fullIdForSymbol(CPlusPlus::Symbol *symbol)
|
||||
|
||||
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
|
||||
{
|
||||
const WorkingCopy workingCopy;
|
||||
@@ -339,6 +392,7 @@ void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol,
|
||||
SearchResultWindow::PreserveCaseDisabled,
|
||||
QLatin1String("CppEditor"));
|
||||
search->setTextToReplace(replacement);
|
||||
search->setFilter(new Filter);
|
||||
auto renameFilesCheckBox = new QCheckBox();
|
||||
renameFilesCheckBox->setVisible(false);
|
||||
search->setAdditionalReplaceWidget(renameFilesCheckBox);
|
||||
@@ -570,7 +624,8 @@ static void displayResults(SearchResult *search, QFutureWatcher<CPlusPlus::Usage
|
||||
for (int index = first; index != last; ++index) {
|
||||
const CPlusPlus::Usage result = watcher->future().resultAt(index);
|
||||
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())
|
||||
continue;
|
||||
|
Reference in New Issue
Block a user