From aacfd340ca1f8faebb3fc9e172fbbf625cda1f83 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 18 Nov 2019 13:56:59 +0100 Subject: [PATCH] Output panes: Allow to invert the meaning of the filter field That is, show only the non-matching lines. Task-number: QTCREATORBUG-19596 Change-Id: Iac06a7c4531688dbf97c7d5c4d0cdb80979b5f95 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/ioutputpane.h | 4 ++++ .../coreplugin/messageoutputwindow.cpp | 3 ++- src/plugins/coreplugin/outputpanemanager.cpp | 16 ++++++++++++- src/plugins/coreplugin/outputwindow.cpp | 23 ++++++++++++------- src/plugins/coreplugin/outputwindow.h | 7 +++++- src/plugins/projectexplorer/appoutputpane.cpp | 4 ++-- .../projectexplorer/compileoutputwindow.cpp | 2 +- src/plugins/projectexplorer/taskmodel.cpp | 12 ++++++---- src/plugins/projectexplorer/taskmodel.h | 8 +++++-- src/plugins/projectexplorer/taskwindow.cpp | 3 ++- 10 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/plugins/coreplugin/ioutputpane.h b/src/plugins/coreplugin/ioutputpane.h index ce95be7a1ae..d9a09e56776 100644 --- a/src/plugins/coreplugin/ioutputpane.h +++ b/src/plugins/coreplugin/ioutputpane.h @@ -102,6 +102,7 @@ protected: void setupFilterUi(const QString &historyKey); QString filterText() const; bool filterUsesRegexp() const { return m_filterRegexp; } + bool filterIsInverted() const { return m_invertFilter; } Qt::CaseSensitivity filterCaseSensitivity() const { return m_filterCaseSensitivity; } void setFilteringEnabled(bool enable); QWidget *filterWidget() const { return m_filterOutputLineEdit; } @@ -116,14 +117,17 @@ private: void setRegularExpressions(bool regularExpressions); Id filterRegexpActionId() const; Id filterCaseSensitivityActionId() const; + Id filterInvertedActionId() const; Core::CommandButton * const m_zoomInButton; Core::CommandButton * const m_zoomOutButton; QAction *m_filterActionRegexp = nullptr; QAction *m_filterActionCaseSensitive = nullptr; + QAction *m_invertFilterAction = nullptr; Utils::FancyLineEdit *m_filterOutputLineEdit = nullptr; IContext *m_context = nullptr; bool m_filterRegexp = false; + bool m_invertFilter = false; Qt::CaseSensitivity m_filterCaseSensitivity = Qt::CaseInsensitive; }; diff --git a/src/plugins/coreplugin/messageoutputwindow.cpp b/src/plugins/coreplugin/messageoutputwindow.cpp index c7c752e1556..1ea565705bf 100644 --- a/src/plugins/coreplugin/messageoutputwindow.cpp +++ b/src/plugins/coreplugin/messageoutputwindow.cpp @@ -146,7 +146,8 @@ bool MessageOutputWindow::canNavigate() const void MessageOutputWindow::updateFilter() { - m_widget->updateFilterProperties(filterText(), filterCaseSensitivity(), filterUsesRegexp()); + m_widget->updateFilterProperties(filterText(), filterCaseSensitivity(), filterUsesRegexp(), + filterIsInverted()); } } // namespace Internal diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 00201293827..0d33610eb58 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -155,6 +155,15 @@ void IOutputPane::setupFilterUi(const QString &historyKey) Core::ActionManager::registerAction(m_filterActionCaseSensitive, filterCaseSensitivityActionId()); + m_invertFilterAction = new QAction(this); + m_invertFilterAction->setCheckable(true); + m_invertFilterAction->setText(tr("Show Non-matching Lines")); + connect(m_invertFilterAction, &QAction::toggled, this, [this] { + m_invertFilter = m_invertFilterAction->isChecked(); + updateFilter(); + }); + Core::ActionManager::registerAction(m_invertFilterAction, filterInvertedActionId()); + m_filterOutputLineEdit->setPlaceholderText(tr("Filter output...")); m_filterOutputLineEdit->setButtonVisible(FancyLineEdit::Left, true); m_filterOutputLineEdit->setButtonIcon(FancyLineEdit::Left, Icons::MAGNIFIER.icon()); @@ -213,7 +222,7 @@ void IOutputPane::updateFilter() void IOutputPane::filterOutputButtonClicked() { auto popup = new Core::OptionsPopup(m_filterOutputLineEdit, - {filterRegexpActionId(), filterCaseSensitivityActionId()}); + {filterRegexpActionId(), filterCaseSensitivityActionId(), filterInvertedActionId()}); popup->show(); } @@ -233,6 +242,11 @@ Id IOutputPane::filterCaseSensitivityActionId() const return Id("OutputFilter.CaseSensitive").withSuffix(metaObject()->className()); } +Id IOutputPane::filterInvertedActionId() const +{ + return Id("OutputFilter.Invert").withSuffix(metaObject()->className()); +} + void IOutputPane::setCaseSensitive(bool caseSensitive) { m_filterCaseSensitivity = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index f920ffc3891..cb5c6ac8434 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -280,12 +280,17 @@ void OutputWindow::setWheelZoomEnabled(bool enabled) d->zoomEnabled = enabled; } -void OutputWindow::updateFilterProperties(const QString &filterText, - Qt::CaseSensitivity caseSensitivity, bool isRegexp) +void OutputWindow::updateFilterProperties( + const QString &filterText, + Qt::CaseSensitivity caseSensitivity, + bool isRegexp, + bool isInverted + ) { FilterModeFlags flags; flags.setFlag(FilterModeFlag::CaseSensitive, caseSensitivity == Qt::CaseSensitive) - .setFlag(FilterModeFlag::RegExp, isRegexp); + .setFlag(FilterModeFlag::RegExp, isRegexp) + .setFlag(FilterModeFlag::Inverted, isInverted); if (d->filterMode == flags && d->filterText == filterText) return; d->lastFilteredBlockNumber = -1; @@ -324,6 +329,7 @@ void OutputWindow::filterNewContent() if (!lastBlock.isValid()) lastBlock = document()->begin(); + const bool invert = d->filterMode.testFlag(FilterModeFlag::Inverted); if (d->filterMode.testFlag(OutputWindow::FilterModeFlag::RegExp)) { QRegularExpression regExp(d->filterText); if (!d->filterMode.testFlag(OutputWindow::FilterModeFlag::CaseSensitive)) @@ -331,16 +337,17 @@ void OutputWindow::filterNewContent() for (; lastBlock != document()->end(); lastBlock = lastBlock.next()) lastBlock.setVisible(d->filterText.isEmpty() - || regExp.match(lastBlock.text()).hasMatch()); + || regExp.match(lastBlock.text()).hasMatch() != invert); } else { if (d->filterMode.testFlag(OutputWindow::FilterModeFlag::CaseSensitive)) { for (; lastBlock != document()->end(); lastBlock = lastBlock.next()) lastBlock.setVisible(d->filterText.isEmpty() - || lastBlock.text().contains(d->filterText)); + || lastBlock.text().contains(d->filterText) != invert); } else { - for (; lastBlock != document()->end(); lastBlock = lastBlock.next()) - lastBlock.setVisible(d->filterText.isEmpty() - || lastBlock.text().toLower().contains(d->filterText.toLower())); + for (; lastBlock != document()->end(); lastBlock = lastBlock.next()) { + lastBlock.setVisible(d->filterText.isEmpty() || lastBlock.text().toLower() + .contains(d->filterText.toLower()) != invert); + } } } diff --git a/src/plugins/coreplugin/outputwindow.h b/src/plugins/coreplugin/outputwindow.h index 204a1106a93..a8a44a52474 100644 --- a/src/plugins/coreplugin/outputwindow.h +++ b/src/plugins/coreplugin/outputwindow.h @@ -49,6 +49,7 @@ public: Default = 0x00, // Plain text, non case sensitive, for initialization RegExp = 0x01, CaseSensitive = 0x02, + Inverted = 0x04, }; Q_DECLARE_FLAGS(FilterModeFlags, FilterModeFlag) @@ -78,7 +79,11 @@ public: void resetZoom() { setFontZoom(0); } void setWheelZoomEnabled(bool enabled); - void updateFilterProperties(const QString &filterText, Qt::CaseSensitivity caseSensitivity, bool regexp); + void updateFilterProperties( + const QString &filterText, + Qt::CaseSensitivity caseSensitivity, + bool regexp, + bool isInverted); signals: void wheelZoom(); diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index 28133cfe714..47bfe6ea012 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -378,7 +378,7 @@ void AppOutputPane::updateFilter() const int index = currentIndex(); if (index != -1) { m_runControlTabs.at(index).window->updateFilterProperties( - filterText(), filterCaseSensitivity(), filterUsesRegexp()); + filterText(), filterCaseSensitivity(), filterUsesRegexp(), filterIsInverted()); } } @@ -724,7 +724,7 @@ void AppOutputPane::tabChanged(int i) if (i != -1 && index != -1) { const RunControlTab &controlTab = m_runControlTabs[index]; controlTab.window->updateFilterProperties(filterText(), filterCaseSensitivity(), - filterUsesRegexp()); + filterUsesRegexp(), filterIsInverted()); enableButtons(controlTab.runControl); } else { enableDefaultButtons(); diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp index d92bcc4bbe0..b12c06692eb 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.cpp +++ b/src/plugins/projectexplorer/compileoutputwindow.cpp @@ -354,7 +354,7 @@ void CompileOutputWindow::setSettings(const CompileOutputSettings &settings) void CompileOutputWindow::updateFilter() { m_outputWindow->updateFilterProperties(filterText(), filterCaseSensitivity(), - filterUsesRegexp()); + filterUsesRegexp(), filterIsInverted()); } void CompileOutputWindow::loadSettings() diff --git a/src/plugins/projectexplorer/taskmodel.cpp b/src/plugins/projectexplorer/taskmodel.cpp index 763ec4074c0..5b3511e93c1 100644 --- a/src/plugins/projectexplorer/taskmodel.cpp +++ b/src/plugins/projectexplorer/taskmodel.cpp @@ -351,16 +351,20 @@ int TaskFilterModel::issuesCount(int startRow, int endRow) const return count; } -void TaskFilterModel::updateFilterProperties(const QString &filterText, - Qt::CaseSensitivity caseSensitivity, bool isRegexp) +void TaskFilterModel::updateFilterProperties( + const QString &filterText, + Qt::CaseSensitivity caseSensitivity, + bool isRegexp, + bool isInverted) { if (filterText == m_filterText && m_filterCaseSensitivity == caseSensitivity - && m_filterStringIsRegexp == isRegexp) { + && m_filterStringIsRegexp == isRegexp && m_filterIsInverted == isInverted) { return; } m_filterText = filterText; m_filterCaseSensitivity = caseSensitivity; m_filterStringIsRegexp = isRegexp; + m_filterIsInverted = isInverted; if (m_filterStringIsRegexp) { m_filterRegexp.setPattern(m_filterText); m_filterRegexp.setPatternOptions(m_filterCaseSensitivity == Qt::CaseInsensitive @@ -399,7 +403,7 @@ bool TaskFilterModel::filterAcceptsTask(const Task &task) const return m_filterStringIsRegexp ? m_filterRegexp.isValid() && s.contains(m_filterRegexp) : s.contains(m_filterText, m_filterCaseSensitivity); }; - if (!accepts(task.file.toString()) && !accepts(task.description)) + if ((accepts(task.file.toString()) || accepts(task.description)) == m_filterIsInverted) accept = false; } diff --git a/src/plugins/projectexplorer/taskmodel.h b/src/plugins/projectexplorer/taskmodel.h index f6053785691..b027532e2b0 100644 --- a/src/plugins/projectexplorer/taskmodel.h +++ b/src/plugins/projectexplorer/taskmodel.h @@ -145,8 +145,11 @@ public: bool hasFile(const QModelIndex &index) const { return taskModel()->hasFile(mapToSource(index)); } - void updateFilterProperties(const QString &filterText, Qt::CaseSensitivity caseSensitivity, - bool isRegex); + void updateFilterProperties( + const QString &filterText, + Qt::CaseSensitivity caseSensitivity, + bool isRegex, + bool isInverted); private: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; @@ -157,6 +160,7 @@ private: bool m_includeWarnings; bool m_includeErrors; bool m_filterStringIsRegexp = false; + bool m_filterIsInverted = false; Qt::CaseSensitivity m_filterCaseSensitivity = Qt::CaseInsensitive; QList m_categoryIds; QString m_filterText; diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 77fe6455edd..d7f0c92c84b 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -678,7 +678,8 @@ void TaskWindow::goToPrev() void TaskWindow::updateFilter() { - d->m_filter->updateFilterProperties(filterText(), filterCaseSensitivity(), filterUsesRegexp()); + d->m_filter->updateFilterProperties(filterText(), filterCaseSensitivity(), filterUsesRegexp(), + filterIsInverted()); } bool TaskWindow::canNavigate() const