forked from qt-creator/qt-creator
Add output filtering for Application Output pane
Task-number: QTCREATORBUG-16356 Change-Id: Ibf6cca1915ef56c50c01cd3c23e7798453506a05 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: André Hartmann <aha_1980@gmx.de> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
This commit is contained in:
@@ -62,6 +62,9 @@ public:
|
|||||||
virtual void clear() {}
|
virtual void clear() {}
|
||||||
void setBoldFontEnabled(bool enabled);
|
void setBoldFontEnabled(bool enabled);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void contentChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initFormats();
|
void initFormats();
|
||||||
virtual void clearLastLine();
|
virtual void clearLastLine();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ HEADERS += \
|
|||||||
$$PWD/ifindfilter.h \
|
$$PWD/ifindfilter.h \
|
||||||
$$PWD/ifindsupport.h \
|
$$PWD/ifindsupport.h \
|
||||||
$$PWD/itemviewfind.h \
|
$$PWD/itemviewfind.h \
|
||||||
|
$$PWD/optionspopup.h \
|
||||||
$$PWD/searchresultcolor.h \
|
$$PWD/searchresultcolor.h \
|
||||||
$$PWD/searchresulttreeitemdelegate.h \
|
$$PWD/searchresulttreeitemdelegate.h \
|
||||||
$$PWD/searchresulttreeitemroles.h \
|
$$PWD/searchresulttreeitemroles.h \
|
||||||
@@ -29,6 +30,7 @@ SOURCES += \
|
|||||||
$$PWD/ifindfilter.cpp \
|
$$PWD/ifindfilter.cpp \
|
||||||
$$PWD/ifindsupport.cpp \
|
$$PWD/ifindsupport.cpp \
|
||||||
$$PWD/itemviewfind.cpp \
|
$$PWD/itemviewfind.cpp \
|
||||||
|
$$PWD/optionspopup.cpp \
|
||||||
$$PWD/searchresulttreeitemdelegate.cpp \
|
$$PWD/searchresulttreeitemdelegate.cpp \
|
||||||
$$PWD/searchresulttreeitems.cpp \
|
$$PWD/searchresulttreeitems.cpp \
|
||||||
$$PWD/searchresulttreemodel.cpp \
|
$$PWD/searchresulttreemodel.cpp \
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "findtoolbar.h"
|
#include "findtoolbar.h"
|
||||||
#include "ifindfilter.h"
|
#include "ifindfilter.h"
|
||||||
#include "findplugin.h"
|
#include "findplugin.h"
|
||||||
|
#include "optionspopup.h"
|
||||||
|
|
||||||
#include <coreplugin/coreicons.h>
|
#include <coreplugin/coreicons.h>
|
||||||
#include <coreplugin/coreplugin.h>
|
#include <coreplugin/coreplugin.h>
|
||||||
@@ -659,7 +660,8 @@ void FindToolBar::findFlagsChanged()
|
|||||||
|
|
||||||
void FindToolBar::findEditButtonClicked()
|
void FindToolBar::findEditButtonClicked()
|
||||||
{
|
{
|
||||||
auto popup = new OptionsPopup(m_ui.findEdit);
|
auto popup = new OptionsPopup(m_ui.findEdit, {Constants::CASE_SENSITIVE, Constants::WHOLE_WORDS,
|
||||||
|
Constants::REGULAR_EXPRESSIONS, Constants::PRESERVE_CASE});
|
||||||
popup->show();
|
popup->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,71 +1016,5 @@ void FindToolBar::updateReplaceEnabled()
|
|||||||
m_replacePreviousAction->setEnabled(globalsEnabled);
|
m_replacePreviousAction->setEnabled(globalsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionsPopup::OptionsPopup(QWidget *parent)
|
|
||||||
: QWidget(parent, Qt::Popup)
|
|
||||||
{
|
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
|
||||||
auto layout = new QVBoxLayout(this);
|
|
||||||
layout->setContentsMargins(2, 2, 2, 2);
|
|
||||||
layout->setSpacing(2);
|
|
||||||
setLayout(layout);
|
|
||||||
QCheckBox *firstCheckBox = createCheckboxForCommand(Constants::CASE_SENSITIVE);
|
|
||||||
layout->addWidget(firstCheckBox);
|
|
||||||
layout->addWidget(createCheckboxForCommand(Constants::WHOLE_WORDS));
|
|
||||||
layout->addWidget(createCheckboxForCommand(Constants::REGULAR_EXPRESSIONS));
|
|
||||||
layout->addWidget(createCheckboxForCommand(Constants::PRESERVE_CASE));
|
|
||||||
firstCheckBox->setFocus();
|
|
||||||
move(parent->mapToGlobal(QPoint(0, -sizeHint().height())));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OptionsPopup::event(QEvent *ev)
|
|
||||||
{
|
|
||||||
if (ev->type() == QEvent::ShortcutOverride) {
|
|
||||||
auto ke = static_cast<QKeyEvent *>(ev);
|
|
||||||
if (ke->key() == Qt::Key_Escape && !ke->modifiers()) {
|
|
||||||
ev->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QWidget::event(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OptionsPopup::eventFilter(QObject *obj, QEvent *ev)
|
|
||||||
{
|
|
||||||
auto checkbox = qobject_cast<QCheckBox *>(obj);
|
|
||||||
if (ev->type() == QEvent::KeyPress && checkbox) {
|
|
||||||
auto ke = static_cast<QKeyEvent *>(ev);
|
|
||||||
if (!ke->modifiers() && (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return)) {
|
|
||||||
checkbox->click();
|
|
||||||
ev->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QWidget::eventFilter(obj, ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OptionsPopup::actionChanged()
|
|
||||||
{
|
|
||||||
auto action = qobject_cast<QAction *>(sender());
|
|
||||||
QTC_ASSERT(action, return);
|
|
||||||
QCheckBox *checkbox = m_checkboxMap.value(action);
|
|
||||||
QTC_ASSERT(checkbox, return);
|
|
||||||
checkbox->setEnabled(action->isEnabled());
|
|
||||||
}
|
|
||||||
|
|
||||||
QCheckBox *OptionsPopup::createCheckboxForCommand(Id id)
|
|
||||||
{
|
|
||||||
QAction *action = ActionManager::command(id)->action();
|
|
||||||
QCheckBox *checkbox = new QCheckBox(action->text());
|
|
||||||
checkbox->setToolTip(action->toolTip());
|
|
||||||
checkbox->setChecked(action->isChecked());
|
|
||||||
checkbox->setEnabled(action->isEnabled());
|
|
||||||
checkbox->installEventFilter(this); // enter key handling
|
|
||||||
QObject::connect(checkbox, &QCheckBox::clicked, action, &QAction::setChecked);
|
|
||||||
QObject::connect(action, &QAction::changed, this, &OptionsPopup::actionChanged);
|
|
||||||
m_checkboxMap.insert(action, checkbox);
|
|
||||||
return checkbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|||||||
@@ -43,25 +43,6 @@ class FindToolBarPlaceHolder;
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class OptionsPopup : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit OptionsPopup(QWidget *parent);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool event(QEvent *ev) override;
|
|
||||||
bool eventFilter(QObject *obj, QEvent *ev) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void actionChanged();
|
|
||||||
|
|
||||||
QCheckBox *createCheckboxForCommand(Id id);
|
|
||||||
|
|
||||||
QMap<QAction *, QCheckBox *> m_checkboxMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FindToolBar : public Utils::StyledBar
|
class FindToolBar : public Utils::StyledBar
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|||||||
110
src/plugins/coreplugin/find/optionspopup.cpp
Normal file
110
src/plugins/coreplugin/find/optionspopup.cpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "optionspopup.h"
|
||||||
|
|
||||||
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
OptionsPopup::OptionsPopup(QWidget *parent, const QVector<Id> &commands)
|
||||||
|
: QWidget(parent, Qt::Popup)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
auto layout = new QVBoxLayout(this);
|
||||||
|
layout->setContentsMargins(2, 2, 2, 2);
|
||||||
|
layout->setSpacing(2);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
for (const Id &command : commands) {
|
||||||
|
QCheckBox *checkBox = createCheckboxForCommand(command);
|
||||||
|
if (first) {
|
||||||
|
checkBox->setFocus();
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
layout->addWidget(checkBox);
|
||||||
|
}
|
||||||
|
move(parent->mapToGlobal(QPoint(0, -sizeHint().height())));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OptionsPopup::event(QEvent *ev)
|
||||||
|
{
|
||||||
|
if (ev->type() == QEvent::ShortcutOverride) {
|
||||||
|
auto ke = static_cast<QKeyEvent *>(ev);
|
||||||
|
if (ke->key() == Qt::Key_Escape && !ke->modifiers()) {
|
||||||
|
ev->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QWidget::event(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OptionsPopup::eventFilter(QObject *obj, QEvent *ev)
|
||||||
|
{
|
||||||
|
auto checkbox = qobject_cast<QCheckBox *>(obj);
|
||||||
|
if (ev->type() == QEvent::KeyPress && checkbox) {
|
||||||
|
auto ke = static_cast<QKeyEvent *>(ev);
|
||||||
|
if (!ke->modifiers() && (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return)) {
|
||||||
|
checkbox->click();
|
||||||
|
ev->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QWidget::eventFilter(obj, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsPopup::actionChanged()
|
||||||
|
{
|
||||||
|
auto action = qobject_cast<QAction *>(sender());
|
||||||
|
QTC_ASSERT(action, return);
|
||||||
|
QCheckBox *checkbox = m_checkboxMap.value(action);
|
||||||
|
QTC_ASSERT(checkbox, return);
|
||||||
|
checkbox->setEnabled(action->isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
QCheckBox *OptionsPopup::createCheckboxForCommand(Id id)
|
||||||
|
{
|
||||||
|
QAction *action = ActionManager::command(id)->action();
|
||||||
|
QCheckBox *checkbox = new QCheckBox(action->text());
|
||||||
|
checkbox->setToolTip(action->toolTip());
|
||||||
|
checkbox->setChecked(action->isChecked());
|
||||||
|
checkbox->setEnabled(action->isEnabled());
|
||||||
|
checkbox->installEventFilter(this); // enter key handling
|
||||||
|
QObject::connect(checkbox, &QCheckBox::clicked, action, &QAction::setChecked);
|
||||||
|
QObject::connect(action, &QAction::changed, this, &OptionsPopup::actionChanged);
|
||||||
|
m_checkboxMap.insert(action, checkbox);
|
||||||
|
return checkbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core
|
||||||
59
src/plugins/coreplugin/find/optionspopup.h
Normal file
59
src/plugins/coreplugin/find/optionspopup.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <coreplugin/id.h>
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QAction;
|
||||||
|
class QCheckBox;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class CORE_EXPORT OptionsPopup : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
OptionsPopup(QWidget *parent, const QVector<Id> &commands);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool event(QEvent *ev) override;
|
||||||
|
bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void actionChanged();
|
||||||
|
|
||||||
|
QCheckBox *createCheckboxForCommand(Id id);
|
||||||
|
|
||||||
|
QMap<QAction *, QCheckBox *> m_checkboxMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <utils/synchronousprocess.h>
|
#include <utils/synchronousprocess.h>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QTextBlock>
|
#include <QTextBlock>
|
||||||
|
|
||||||
@@ -67,6 +68,9 @@ public:
|
|||||||
int maxCharCount = Core::Constants::DEFAULT_MAX_CHAR_COUNT;
|
int maxCharCount = Core::Constants::DEFAULT_MAX_CHAR_COUNT;
|
||||||
Qt::MouseButton mouseButtonPressed = Qt::NoButton;
|
Qt::MouseButton mouseButtonPressed = Qt::NoButton;
|
||||||
QTextCursor cursor;
|
QTextCursor cursor;
|
||||||
|
QString filterText;
|
||||||
|
QTextBlock lastFilteredBlock;
|
||||||
|
OutputWindow::FilterModeFlags filterMode = OutputWindow::FilterModeFlag::Default;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
@@ -196,8 +200,10 @@ OutputFormatter *OutputWindow::formatter() const
|
|||||||
void OutputWindow::setFormatter(OutputFormatter *formatter)
|
void OutputWindow::setFormatter(OutputFormatter *formatter)
|
||||||
{
|
{
|
||||||
d->formatter = formatter;
|
d->formatter = formatter;
|
||||||
if (d->formatter)
|
if (d->formatter) {
|
||||||
d->formatter->setPlainTextEdit(this);
|
d->formatter->setPlainTextEdit(this);
|
||||||
|
connect(d->formatter, &OutputFormatter::contentChanged, this, &OutputWindow::filterNewContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutputWindow::showEvent(QShowEvent *e)
|
void OutputWindow::showEvent(QShowEvent *e)
|
||||||
@@ -252,6 +258,99 @@ void OutputWindow::setWheelZoomEnabled(bool enabled)
|
|||||||
d->m_zoomEnabled = enabled;
|
d->m_zoomEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OutputWindow::setHighlightBgColor(const QColor &bgColor)
|
||||||
|
{
|
||||||
|
m_highlightBgColor = bgColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputWindow::setHighlightTextColor(const QColor &textColor)
|
||||||
|
{
|
||||||
|
m_highlightTextColor = textColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OutputWindow::filterText() const
|
||||||
|
{
|
||||||
|
return d->filterText;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputWindow::setFilterText(const QString &filterText)
|
||||||
|
{
|
||||||
|
if (d->filterText != filterText) {
|
||||||
|
d->lastFilteredBlock = {};
|
||||||
|
d->filterText = filterText;
|
||||||
|
|
||||||
|
// Update textedit's background color
|
||||||
|
if (filterText.isEmpty()) {
|
||||||
|
d->formatter->plainTextEdit()->setPalette({});
|
||||||
|
} else {
|
||||||
|
QPalette pal;
|
||||||
|
pal.setColor(QPalette::Active, QPalette::Base, m_highlightBgColor);
|
||||||
|
pal.setColor(QPalette::Inactive, QPalette::Base, m_highlightBgColor.darker(120));
|
||||||
|
pal.setColor(QPalette::Active, QPalette::Text, m_highlightTextColor);
|
||||||
|
pal.setColor(QPalette::Inactive, QPalette::Text, m_highlightTextColor.darker(120));
|
||||||
|
d->formatter->plainTextEdit()->setPalette(pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
setReadOnly(!filterText.isEmpty());
|
||||||
|
filterNewContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputWindow::FilterModeFlags OutputWindow::filterMode() const
|
||||||
|
{
|
||||||
|
return d->filterMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputWindow::setFilterMode(OutputWindow::FilterModeFlag filterMode, bool enabled)
|
||||||
|
{
|
||||||
|
if (d->filterMode.testFlag(filterMode) != enabled) {
|
||||||
|
d->filterMode.setFlag(filterMode, enabled);
|
||||||
|
d->lastFilteredBlock = {};
|
||||||
|
filterNewContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputWindow::filterNewContent()
|
||||||
|
{
|
||||||
|
bool atBottom = isScrollbarAtBottom();
|
||||||
|
QPlainTextEdit *textEdit = d->formatter->plainTextEdit();
|
||||||
|
if (!textEdit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QTextDocument *document = textEdit->document();
|
||||||
|
|
||||||
|
auto &lastBlock = d->lastFilteredBlock;
|
||||||
|
|
||||||
|
if (!lastBlock.isValid())
|
||||||
|
lastBlock = document->begin();
|
||||||
|
|
||||||
|
if (d->filterMode.testFlag(OutputWindow::FilterModeFlag::RegExp)) {
|
||||||
|
QRegularExpression regExp(d->filterText);
|
||||||
|
if (!d->filterMode.testFlag(OutputWindow::FilterModeFlag::CaseSensitive))
|
||||||
|
regExp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
|
||||||
|
|
||||||
|
for (; lastBlock != document->end(); lastBlock = lastBlock.next())
|
||||||
|
lastBlock.setVisible(d->filterText.isEmpty()
|
||||||
|
|| regExp.match(lastBlock.text()).hasMatch());
|
||||||
|
} 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));
|
||||||
|
} else {
|
||||||
|
for (; lastBlock != document->end(); lastBlock = lastBlock.next())
|
||||||
|
lastBlock.setVisible(d->filterText.isEmpty()
|
||||||
|
|| lastBlock.text().toLower().contains(d->filterText.toLower()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastBlock = document->lastBlock();
|
||||||
|
textEdit->setDocument(document);
|
||||||
|
|
||||||
|
if (atBottom)
|
||||||
|
scrollToBottom();
|
||||||
|
}
|
||||||
|
|
||||||
QString OutputWindow::doNewlineEnforcement(const QString &out)
|
QString OutputWindow::doNewlineEnforcement(const QString &out)
|
||||||
{
|
{
|
||||||
d->scrollToBottom = true;
|
d->scrollToBottom = true;
|
||||||
@@ -280,6 +379,19 @@ int OutputWindow::maxCharCount() const
|
|||||||
return d->maxCharCount;
|
return d->maxCharCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OutputWindow::isReadOnly() const
|
||||||
|
{
|
||||||
|
if (d->formatter)
|
||||||
|
return d->formatter->plainTextEdit()->isReadOnly();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputWindow::setReadOnly(bool readOnly)
|
||||||
|
{
|
||||||
|
if (d->formatter)
|
||||||
|
d->formatter->plainTextEdit()->setReadOnly(readOnly);
|
||||||
|
}
|
||||||
|
|
||||||
void OutputWindow::appendMessage(const QString &output, OutputFormat format)
|
void OutputWindow::appendMessage(const QString &output, OutputFormat format)
|
||||||
{
|
{
|
||||||
QString out = SynchronousProcess::normalizeNewlines(output);
|
QString out = SynchronousProcess::normalizeNewlines(output);
|
||||||
|
|||||||
@@ -45,6 +45,13 @@ class CORE_EXPORT OutputWindow : public QPlainTextEdit
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum class FilterModeFlag {
|
||||||
|
Default = 0x00, // Plain text, non case sensitive, for initialization
|
||||||
|
RegExp = 0x01,
|
||||||
|
CaseSensitive = 0x02,
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(FilterModeFlags, FilterModeFlag)
|
||||||
|
|
||||||
OutputWindow(Context context, QWidget *parent = nullptr);
|
OutputWindow(Context context, QWidget *parent = nullptr);
|
||||||
~OutputWindow() override;
|
~OutputWindow() override;
|
||||||
|
|
||||||
@@ -65,10 +72,21 @@ public:
|
|||||||
void setMaxCharCount(int count);
|
void setMaxCharCount(int count);
|
||||||
int maxCharCount() const;
|
int maxCharCount() const;
|
||||||
|
|
||||||
|
bool isReadOnly() const;
|
||||||
|
void setReadOnly(bool readOnly);
|
||||||
|
|
||||||
void setBaseFont(const QFont &newFont);
|
void setBaseFont(const QFont &newFont);
|
||||||
float fontZoom() const;
|
float fontZoom() const;
|
||||||
void setFontZoom(float zoom);
|
void setFontZoom(float zoom);
|
||||||
void setWheelZoomEnabled(bool enabled);
|
void setWheelZoomEnabled(bool enabled);
|
||||||
|
void setHighlightBgColor(const QColor &bgColor);
|
||||||
|
void setHighlightTextColor(const QColor &textColor);
|
||||||
|
|
||||||
|
QString filterText() const;
|
||||||
|
void setFilterText(const QString &filterText);
|
||||||
|
|
||||||
|
FilterModeFlags filterMode() const;
|
||||||
|
void setFilterMode(FilterModeFlag filterMode, bool enabled);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void wheelZoom();
|
void wheelZoom();
|
||||||
@@ -92,6 +110,10 @@ private:
|
|||||||
QTime m_lastMessage;
|
QTime m_lastMessage;
|
||||||
void enableUndoRedo();
|
void enableUndoRedo();
|
||||||
QString doNewlineEnforcement(const QString &out);
|
QString doNewlineEnforcement(const QString &out);
|
||||||
|
void filterNewContent();
|
||||||
|
|
||||||
|
QColor m_highlightBgColor;
|
||||||
|
QColor m_highlightTextColor;
|
||||||
|
|
||||||
Internal::OutputWindowPrivate *d;
|
Internal::OutputWindowPrivate *d;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include <coreplugin/actionmanager/command.h>
|
#include <coreplugin/actionmanager/command.h>
|
||||||
#include <coreplugin/coreconstants.h>
|
#include <coreplugin/coreconstants.h>
|
||||||
#include <coreplugin/find/basetextfind.h>
|
#include <coreplugin/find/basetextfind.h>
|
||||||
|
#include <coreplugin/find/optionspopup.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/outputwindow.h>
|
#include <coreplugin/outputwindow.h>
|
||||||
#include <texteditor/behaviorsettings.h>
|
#include <texteditor/behaviorsettings.h>
|
||||||
@@ -99,6 +100,12 @@ const char CLEAN_OLD_OUTPUT_KEY[] = "ProjectExplorer/Settings/CleanOldAppOutput"
|
|||||||
const char MERGE_CHANNELS_KEY[] = "ProjectExplorer/Settings/MergeStdErrAndStdOut";
|
const char MERGE_CHANNELS_KEY[] = "ProjectExplorer/Settings/MergeStdErrAndStdOut";
|
||||||
const char WRAP_OUTPUT_KEY[] = "ProjectExplorer/Settings/WrapAppOutput";
|
const char WRAP_OUTPUT_KEY[] = "ProjectExplorer/Settings/WrapAppOutput";
|
||||||
const char MAX_LINES_KEY[] = "ProjectExplorer/Settings/MaxAppOutputLines";
|
const char MAX_LINES_KEY[] = "ProjectExplorer/Settings/MaxAppOutputLines";
|
||||||
|
|
||||||
|
|
||||||
|
// Output filtering
|
||||||
|
const char FILTER_REGULAR_EXPRESSIONS[] = "OutputFilter.RegularExpressions";
|
||||||
|
const char FILTER_CASE_SENSITIVE[] = "OutputFilter.CaseSensitive";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
@@ -180,6 +187,7 @@ AppOutputPane::AppOutputPane() :
|
|||||||
m_zoomInButton(new QToolButton),
|
m_zoomInButton(new QToolButton),
|
||||||
m_zoomOutButton(new QToolButton),
|
m_zoomOutButton(new QToolButton),
|
||||||
m_settingsButton(new QToolButton),
|
m_settingsButton(new QToolButton),
|
||||||
|
m_filterOutputLineEdit(new Utils::FancyLineEdit),
|
||||||
m_formatterWidget(new QWidget)
|
m_formatterWidget(new QWidget)
|
||||||
{
|
{
|
||||||
setObjectName("AppOutputPane"); // Used in valgrind engine
|
setObjectName("AppOutputPane"); // Used in valgrind engine
|
||||||
@@ -237,6 +245,32 @@ AppOutputPane::AppOutputPane() :
|
|||||||
Core::ICore::showOptionsDialog(OPTIONS_PAGE_ID);
|
Core::ICore::showOptionsDialog(OPTIONS_PAGE_ID);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_filterActionRegexp = new QAction(this);
|
||||||
|
m_filterActionRegexp->setCheckable(true);
|
||||||
|
m_filterActionRegexp->setText(tr("Use Regular Expressions"));
|
||||||
|
connect(m_filterActionRegexp, &QAction::toggled, this, &AppOutputPane::setRegularExpressions);
|
||||||
|
|
||||||
|
Core::ActionManager::registerAction(m_filterActionRegexp, FILTER_REGULAR_EXPRESSIONS);
|
||||||
|
|
||||||
|
m_filterActionCaseSensitive = new QAction(this);
|
||||||
|
m_filterActionCaseSensitive->setCheckable(true);
|
||||||
|
m_filterActionCaseSensitive->setText(tr("Case Sensitive"));
|
||||||
|
connect(m_filterActionCaseSensitive, &QAction::toggled, this, &AppOutputPane::setCaseSensitive);
|
||||||
|
Core::ActionManager::registerAction(m_filterActionCaseSensitive, FILTER_CASE_SENSITIVE);
|
||||||
|
|
||||||
|
m_filterOutputLineEdit->setPlaceholderText(tr("Filter output..."));
|
||||||
|
m_filterOutputLineEdit->setButtonVisible(Utils::FancyLineEdit::Left, true);
|
||||||
|
m_filterOutputLineEdit->setButtonIcon(Utils::FancyLineEdit::Left, Utils::Icons::MAGNIFIER.icon());
|
||||||
|
m_filterOutputLineEdit->setFiltering(true);
|
||||||
|
m_filterOutputLineEdit->setEnabled(false);
|
||||||
|
connect(m_filterOutputLineEdit, &Utils::FancyLineEdit::textChanged, this, &AppOutputPane::updateFilter);
|
||||||
|
connect(m_filterOutputLineEdit, &Utils::FancyLineEdit::returnPressed, this, &AppOutputPane::updateFilter);
|
||||||
|
|
||||||
|
connect(m_filterOutputLineEdit, &Utils::FancyLineEdit::leftButtonClicked, this, [&](){
|
||||||
|
if (currentIndex() >= 0)
|
||||||
|
AppOutputPane::filterOutputButtonClicked();
|
||||||
|
});
|
||||||
|
|
||||||
auto formatterWidgetsLayout = new QHBoxLayout;
|
auto formatterWidgetsLayout = new QHBoxLayout;
|
||||||
formatterWidgetsLayout->setContentsMargins(QMargins());
|
formatterWidgetsLayout->setContentsMargins(QMargins());
|
||||||
m_formatterWidget->setLayout(formatterWidgetsLayout);
|
m_formatterWidget->setLayout(formatterWidgetsLayout);
|
||||||
@@ -354,7 +388,7 @@ QWidget *AppOutputPane::outputWidget(QWidget *)
|
|||||||
QList<QWidget*> AppOutputPane::toolBarWidgets() const
|
QList<QWidget*> AppOutputPane::toolBarWidgets() const
|
||||||
{
|
{
|
||||||
return { m_reRunButton, m_stopButton, m_attachButton, m_zoomInButton,
|
return { m_reRunButton, m_stopButton, m_attachButton, m_zoomInButton,
|
||||||
m_zoomOutButton, m_settingsButton, m_formatterWidget };
|
m_settingsButton, m_zoomOutButton, m_filterOutputLineEdit, m_formatterWidget };
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AppOutputPane::displayName() const
|
QString AppOutputPane::displayName() const
|
||||||
@@ -399,9 +433,14 @@ void AppOutputPane::setFocus()
|
|||||||
|
|
||||||
void AppOutputPane::updateFontSettings()
|
void AppOutputPane::updateFontSettings()
|
||||||
{
|
{
|
||||||
QFont f = TextEditor::TextEditorSettings::fontSettings().font();
|
const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::fontSettings();
|
||||||
for (const RunControlTab &rcTab : qAsConst(m_runControlTabs))
|
for (const RunControlTab &rcTab : qAsConst(m_runControlTabs)) {
|
||||||
rcTab.window->setBaseFont(f);
|
rcTab.window->setBaseFont(fs.font());
|
||||||
|
rcTab.window->setHighlightBgColor(fs.toTextCharFormat(TextEditor::C_SEARCH_RESULT)
|
||||||
|
.background().color());
|
||||||
|
rcTab.window->setHighlightTextColor(fs.toTextCharFormat(TextEditor::C_SEARCH_RESULT)
|
||||||
|
.foreground().color());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppOutputPane::updateBehaviorSettings()
|
void AppOutputPane::updateBehaviorSettings()
|
||||||
@@ -411,6 +450,44 @@ void AppOutputPane::updateBehaviorSettings()
|
|||||||
rcTab.window->setWheelZoomEnabled(zoomEnabled);
|
rcTab.window->setWheelZoomEnabled(zoomEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppOutputPane::updateFilter()
|
||||||
|
{
|
||||||
|
const QString filter = m_filterOutputLineEdit->text();
|
||||||
|
const int index = currentIndex();
|
||||||
|
if (index != -1)
|
||||||
|
m_runControlTabs.at(index).window->setFilterText(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppOutputPane::configureCurrentWindow()
|
||||||
|
{
|
||||||
|
using Core::OutputWindow;
|
||||||
|
const QString filter = m_filterOutputLineEdit->text();
|
||||||
|
const int index = currentIndex();
|
||||||
|
if (index != -1) {
|
||||||
|
Core::OutputWindow *currWindow = m_runControlTabs.at(index).window;
|
||||||
|
currWindow->setFilterText(filter);
|
||||||
|
currWindow->setFilterMode(OutputWindow::FilterModeFlag::RegExp, m_filterRegexp);
|
||||||
|
currWindow->setFilterMode(OutputWindow::FilterModeFlag::CaseSensitive, m_filterCaseSensitive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppOutputPane::filterOutputButtonClicked()
|
||||||
|
{
|
||||||
|
auto popup = new Core::OptionsPopup(m_filterOutputLineEdit,
|
||||||
|
{FILTER_REGULAR_EXPRESSIONS, FILTER_CASE_SENSITIVE});
|
||||||
|
popup->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppOutputPane::setRegularExpressions(bool regularExpressions)
|
||||||
|
{
|
||||||
|
m_filterRegexp = regularExpressions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppOutputPane::setCaseSensitive(bool caseSensitive)
|
||||||
|
{
|
||||||
|
m_filterCaseSensitive = caseSensitive;
|
||||||
|
}
|
||||||
|
|
||||||
void AppOutputPane::createNewOutputWindow(RunControl *rc)
|
void AppOutputPane::createNewOutputWindow(RunControl *rc)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(rc, return);
|
QTC_ASSERT(rc, return);
|
||||||
@@ -459,6 +536,7 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
|
|||||||
}
|
}
|
||||||
// Create new
|
// Create new
|
||||||
static int counter = 0;
|
static int counter = 0;
|
||||||
|
const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::fontSettings();
|
||||||
Core::Id contextId = Core::Id(C_APP_OUTPUT).withSuffix(counter++);
|
Core::Id contextId = Core::Id(C_APP_OUTPUT).withSuffix(counter++);
|
||||||
Core::Context context(contextId);
|
Core::Context context(contextId);
|
||||||
Core::OutputWindow *ow = new Core::OutputWindow(context, m_tabWidget);
|
Core::OutputWindow *ow = new Core::OutputWindow(context, m_tabWidget);
|
||||||
@@ -467,7 +545,11 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
|
|||||||
ow->setWordWrapEnabled(m_settings.wrapOutput);
|
ow->setWordWrapEnabled(m_settings.wrapOutput);
|
||||||
ow->setMaxCharCount(m_settings.maxCharCount);
|
ow->setMaxCharCount(m_settings.maxCharCount);
|
||||||
ow->setWheelZoomEnabled(TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming);
|
ow->setWheelZoomEnabled(TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming);
|
||||||
ow->setBaseFont(TextEditor::TextEditorSettings::fontSettings().font());
|
ow->setBaseFont(fs.font());
|
||||||
|
ow->setHighlightBgColor(fs.toTextCharFormat(TextEditor::C_SEARCH_RESULT)
|
||||||
|
.background().color());
|
||||||
|
ow->setHighlightTextColor(fs.toTextCharFormat(TextEditor::C_SEARCH_RESULT)
|
||||||
|
.foreground().color());
|
||||||
ow->setFontZoom(m_zoom);
|
ow->setFontZoom(m_zoom);
|
||||||
|
|
||||||
connect(ow, &Core::OutputWindow::wheelZoom, this, [this, ow]() {
|
connect(ow, &Core::OutputWindow::wheelZoom, this, [this, ow]() {
|
||||||
@@ -483,6 +565,7 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
|
|||||||
m_tabWidget->addTab(ow, rc->displayName());
|
m_tabWidget->addTab(ow, rc->displayName());
|
||||||
qCDebug(appOutputLog) << "AppOutputPane::createNewOutputWindow: Adding tab for" << rc;
|
qCDebug(appOutputLog) << "AppOutputPane::createNewOutputWindow: Adding tab for" << rc;
|
||||||
updateCloseActions();
|
updateCloseActions();
|
||||||
|
m_filterOutputLineEdit->setEnabled(m_tabWidget->count() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppOutputPane::handleOldOutput(Core::OutputWindow *window) const
|
void AppOutputPane::handleOldOutput(Core::OutputWindow *window) const
|
||||||
@@ -645,6 +728,7 @@ void AppOutputPane::closeTab(int tabIndex, CloseTabMode closeTabMode)
|
|||||||
runControl->initiateFinish(); // Will self-destruct.
|
runControl->initiateFinish(); // Will self-destruct.
|
||||||
m_runControlTabs.removeAt(index);
|
m_runControlTabs.removeAt(index);
|
||||||
updateCloseActions();
|
updateCloseActions();
|
||||||
|
m_filterOutputLineEdit->setEnabled(m_tabWidget->count() > 0);
|
||||||
|
|
||||||
if (m_runControlTabs.isEmpty())
|
if (m_runControlTabs.isEmpty())
|
||||||
hide();
|
hide();
|
||||||
@@ -726,7 +810,9 @@ void AppOutputPane::tabChanged(int i)
|
|||||||
{
|
{
|
||||||
const int index = indexOf(m_tabWidget->widget(i));
|
const int index = indexOf(m_tabWidget->widget(i));
|
||||||
if (i != -1 && index != -1) {
|
if (i != -1 && index != -1) {
|
||||||
enableButtons(m_runControlTabs.at(index).runControl);
|
const RunControlTab &controlTab = m_runControlTabs[index];
|
||||||
|
controlTab.window->setFilterText(m_filterOutputLineEdit->text());
|
||||||
|
enableButtons(controlTab.runControl);
|
||||||
} else {
|
} else {
|
||||||
enableDefaultButtons();
|
enableDefaultButtons();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <coreplugin/ioutputpane.h>
|
#include <coreplugin/ioutputpane.h>
|
||||||
#include <coreplugin/dialogs/ioptionspage.h>
|
#include <coreplugin/dialogs/ioptionspage.h>
|
||||||
|
|
||||||
|
#include <utils/fancylineedit.h>
|
||||||
#include <utils/outputformat.h>
|
#include <utils/outputformat.h>
|
||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
@@ -145,6 +146,12 @@ private:
|
|||||||
void updateFontSettings();
|
void updateFontSettings();
|
||||||
void storeZoomFactor();
|
void storeZoomFactor();
|
||||||
void updateBehaviorSettings();
|
void updateBehaviorSettings();
|
||||||
|
void updateFilter();
|
||||||
|
void configureCurrentWindow();
|
||||||
|
void filterOutputButtonClicked();
|
||||||
|
|
||||||
|
void setCaseSensitive(bool caseSensitive);
|
||||||
|
void setRegularExpressions(bool regularExpressions);
|
||||||
|
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void storeSettings() const;
|
void storeSettings() const;
|
||||||
@@ -163,9 +170,14 @@ private:
|
|||||||
QToolButton *m_zoomInButton;
|
QToolButton *m_zoomInButton;
|
||||||
QToolButton *m_zoomOutButton;
|
QToolButton *m_zoomOutButton;
|
||||||
QToolButton * const m_settingsButton;
|
QToolButton * const m_settingsButton;
|
||||||
|
QAction *m_filterActionRegexp = nullptr;
|
||||||
|
QAction *m_filterActionCaseSensitive = nullptr;
|
||||||
|
Utils::FancyLineEdit *m_filterOutputLineEdit = nullptr;
|
||||||
QWidget *m_formatterWidget;
|
QWidget *m_formatterWidget;
|
||||||
float m_zoom;
|
float m_zoom;
|
||||||
AppOutputSettings m_settings;
|
AppOutputSettings m_settings;
|
||||||
|
bool m_filterRegexp = false;
|
||||||
|
bool m_filterCaseSensitive = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AppOutputSettingsPage : public Core::IOptionsPage
|
class AppOutputSettingsPage : public Core::IOptionsPage
|
||||||
|
|||||||
@@ -187,6 +187,8 @@ void QtOutputFormatter::appendMessage(const QString &txt, const QTextCharFormat
|
|||||||
appendMessagePart(output.text, output.format);
|
appendMessagePart(output.text, output.format);
|
||||||
|
|
||||||
d->cursor.endEditBlock();
|
d->cursor.endEditBlock();
|
||||||
|
|
||||||
|
emit contentChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtOutputFormatter::appendLine(const LinkResult &lr, const QString &line, OutputFormat format)
|
void QtOutputFormatter::appendLine(const LinkResult &lr, const QString &line, OutputFormat format)
|
||||||
|
|||||||
Reference in New Issue
Block a user