From bcbaf5d3491f2e5bd45e6014dc6cfa5349c59ea8 Mon Sep 17 00:00:00 2001 From: Joshua Noack Date: Wed, 7 Mar 2018 10:21:45 -0500 Subject: [PATCH] Konsole: Use KMessageWidget in TerminalDisplay Summary: Depends on D10862 Before: {F5734372} After: {F5734369} Read-only: {F5734370} Both: {F5734371} This also fixes the overlapped scrollbar (see first screenshot). Test Plan: Tested before and after, behaviour is the same. Reviewers: #konsole, hindenburg Reviewed By: #konsole, hindenburg Subscribers: herrold, hindenburg, ngraham Tags: #konsole Differential Revision: https://phabricator.kde.org/D10935 --- src/SessionController.cpp | 6 ++ src/TerminalDisplay.cpp | 123 ++++++++++++++++++++++++++------------ src/TerminalDisplay.h | 18 +++++- 3 files changed, 107 insertions(+), 40 deletions(-) diff --git a/src/SessionController.cpp b/src/SessionController.cpp index bd905d9e..b9db38ac 100644 --- a/src/SessionController.cpp +++ b/src/SessionController.cpp @@ -1537,6 +1537,12 @@ void SessionController::updateReadOnlyActionState(QAction *action, bool readonly if (editAction != nullptr) { editAction->setEnabled(!readonly); } + + // Without the timer, when detaching a tab while the message widget is visible, + // the size of the terminal becomes really small... + QTimer::singleShot(0, this, [this, readonly]() { + _view->updateReadOnlyState(readonly); + }); } bool SessionController::isReadOnly() const diff --git a/src/TerminalDisplay.cpp b/src/TerminalDisplay.cpp index 3d3dce99..3fcd3124 100644 --- a/src/TerminalDisplay.cpp +++ b/src/TerminalDisplay.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -55,6 +55,7 @@ #include #include #include +#include #include // Konsole @@ -333,7 +334,7 @@ TerminalDisplay::TerminalDisplay(QWidget* parent) : QWidget(parent) , _screenWindow(nullptr) , _bellMasked(false) - , _gridLayout(nullptr) + , _verticalLayout(new QVBoxLayout(this)) , _fontHeight(1) , _fontWidth(1) , _fontAscent(1) @@ -373,7 +374,7 @@ TerminalDisplay::TerminalDisplay(QWidget* parent) , _resizeWidget(nullptr) , _resizeTimer(nullptr) , _flowControlWarningEnabled(false) - , _outputSuspendedLabel(nullptr) + , _outputSuspendedMessageWidget(nullptr) , _lineSpacing(0) , _blendColor(qRgba(0, 0, 0, 0xff)) , _filterChain(new TerminalImageFilterChain()) @@ -387,6 +388,7 @@ TerminalDisplay::TerminalDisplay(QWidget* parent) , _trimTrailingSpaces(false) , _margin(1) , _centerContents(false) + , _readOnlyMessageWidget(nullptr) , _opacity(1.0) { // terminal applications are not designed with Right-To-Left in mind, @@ -435,10 +437,18 @@ TerminalDisplay::TerminalDisplay(QWidget* parent) // that TerminalDisplay will handle repainting its entire area. setAttribute(Qt::WA_OpaquePaintEvent); - _gridLayout = new QGridLayout; - _gridLayout->setContentsMargins(0, 0, 0, 0); + // Add the stretch item once, the KMessageWidgets are inserted at index 0. + _verticalLayout->addStretch(); + _verticalLayout->setSpacing(0); - setLayout(_gridLayout); + setLayout(_verticalLayout); + + // Take the scrollbar into account and add a margin to the layout. Without the timer the scrollbar width + // is garbage. + QTimer::singleShot(0, this, [this]() { + const int scrollBarWidth = _scrollBar->isVisible() ? geometry().intersected(_scrollBar->geometry()).width() : 0; + _verticalLayout->setContentsMargins(0, 0, scrollBarWidth, 0); + }); new AutoScrollHandler(this); @@ -455,6 +465,11 @@ TerminalDisplay::~TerminalDisplay() delete[] _image; delete _filterChain; + delete _readOnlyMessageWidget; + delete _outputSuspendedMessageWidget; + + _readOnlyMessageWidget = nullptr; + _outputSuspendedMessageWidget = nullptr; } /* ------------------------------------------------------------------------- */ @@ -972,7 +987,11 @@ void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) // if the flow control warning is enabled this will interfere with the // scrolling optimizations and cause artifacts. the simple solution here // is to just disable the optimization whilst it is visible - if ((_outputSuspendedLabel != nullptr) && _outputSuspendedLabel->isVisible()) { + if ((_outputSuspendedMessageWidget != nullptr) && _outputSuspendedMessageWidget->isVisible()) { + return; + } + + if ((_readOnlyMessageWidget != nullptr) && _readOnlyMessageWidget->isVisible()) { return; } @@ -2071,6 +2090,19 @@ void TerminalDisplay::mousePressEvent(QMouseEvent* ev) return; } + // Ignore clicks on the message widget + if (_readOnlyMessageWidget != nullptr) { + if (_readOnlyMessageWidget->isVisible() && _readOnlyMessageWidget->frameGeometry().contains(ev->pos())) { + return; + } + } + + if (_outputSuspendedMessageWidget != nullptr) { + if (_outputSuspendedMessageWidget->isVisible() && _outputSuspendedMessageWidget->frameGeometry().contains(ev->pos())) { + return; + } + } + int charLine; int charColumn; getCharacterPosition(ev->pos(), charLine, charColumn); @@ -3290,49 +3322,31 @@ void TerminalDisplay::setFlowControlWarningEnabled(bool enable) void TerminalDisplay::outputSuspended(bool suspended) { //create the label when this function is first called - if (_outputSuspendedLabel == nullptr) { + if (_outputSuspendedMessageWidget == nullptr) { //This label includes a link to an English language website //describing the 'flow control' (Xon/Xoff) feature found in almost //all terminal emulators. //If there isn't a suitable article available in the target language the link //can simply be removed. - _outputSuspendedLabel = new QLabel(i18n("Output has been " - "suspended" - " by pressing Ctrl+S." - " Press Ctrl+Q to resume." - " Click here to dismiss this message.")); - - QPalette palette(_outputSuspendedLabel->palette()); - KColorScheme::adjustBackground(palette, KColorScheme::NeutralBackground); - _outputSuspendedLabel->setPalette(palette); - _outputSuspendedLabel->setAutoFillBackground(true); - _outputSuspendedLabel->setBackgroundRole(QPalette::Base); - _outputSuspendedLabel->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); - _outputSuspendedLabel->setContentsMargins(5, 5, 5, 5); - _outputSuspendedLabel->setWordWrap(true); - _outputSuspendedLabel->setFocusProxy(this); - - connect(_outputSuspendedLabel, &QLabel::linkActivated, this, [this](const QString &url) { + auto linkHandler = [this](const QString &url) { if (url == QLatin1String("#close")) { - _outputSuspendedLabel->setVisible(false); + _outputSuspendedMessageWidget->hide(); } else { QDesktopServices::openUrl(QUrl(url)); } - }); + }; - //enable activation of "Xon/Xoff" link in label - _outputSuspendedLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse | - Qt::LinksAccessibleByKeyboard); - _outputSuspendedLabel->setOpenExternalLinks(false); - _outputSuspendedLabel->setVisible(false); + _outputSuspendedMessageWidget = createMessageWidget(i18n("Output has been " + "suspended" + " by pressing Ctrl+S." + " Press Ctrl+Q to resume." + " Click here to dismiss this message."), linkHandler); - _gridLayout->addWidget(_outputSuspendedLabel); - _gridLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, - QSizePolicy::Expanding), - 1, 0); + _outputSuspendedMessageWidget->setMessageType(KMessageWidget::Warning); + _outputSuspendedMessageWidget->hide(); } - _outputSuspendedLabel->setVisible(suspended); + _outputSuspendedMessageWidget->setVisible(suspended); } void TerminalDisplay::dismissOutputSuspendedMessage() @@ -3340,6 +3354,41 @@ void TerminalDisplay::dismissOutputSuspendedMessage() outputSuspended(false); } +KMessageWidget* TerminalDisplay::createMessageWidget(const QString &text, std::function linkHandler) { + auto widget = new KMessageWidget(text); + widget->setWordWrap(true); + widget->setFocusProxy(this); + widget->setCloseButtonVisible(false); + widget->setCursor(Qt::ArrowCursor); + + connect(widget, &KMessageWidget::linkActivated, this, linkHandler); + + _verticalLayout->insertWidget(0, widget); + return widget; +} + +void TerminalDisplay::updateReadOnlyState(bool readonly) { + + if (readonly) { + // Lazy create the readonly messagewidget + if (_readOnlyMessageWidget == nullptr) { + + auto linkHandler = [this](const QString &url) { + if (url == QLatin1String("#close")) { + _readOnlyMessageWidget->hide(); + } + }; + + _readOnlyMessageWidget = createMessageWidget(i18n("This terminal is read-only. Dismiss"), linkHandler); + _readOnlyMessageWidget->setIcon(QIcon::fromTheme(QStringLiteral("object-locked"))); + } + } + + if (_readOnlyMessageWidget != nullptr) { + _readOnlyMessageWidget->setVisible(readonly); + } +} + void TerminalDisplay::scrollScreenWindow(enum ScreenWindow::RelativeScrollMode mode, int amount) { _screenWindow->scrollBy(mode, amount, _scrollFullPage); diff --git a/src/TerminalDisplay.h b/src/TerminalDisplay.h index 9c652959..69a208e5 100644 --- a/src/TerminalDisplay.h +++ b/src/TerminalDisplay.h @@ -21,6 +21,8 @@ #ifndef TERMINALDISPLAY_H #define TERMINALDISPLAY_H +#include + // Qt #include #include @@ -40,13 +42,15 @@ class QDropEvent; class QLabel; class QTimer; class QEvent; -class QGridLayout; +class QVBoxLayout; class QKeyEvent; class QScrollBar; class QShowEvent; class QHideEvent; class QTimerEvent; +class KMessageWidget; + namespace Konsole { class FilterChain; class TerminalImageFilterChain; @@ -651,6 +655,9 @@ public Q_SLOTS: */ void setCenterContents(bool enable); + // Used to show/hide the message widget + void updateReadOnlyState(bool readonly); + Q_SIGNALS: /** @@ -863,13 +870,16 @@ private: // Uses the current settings for trimming whitespace and preserving linebreaks to create a proper flag value for Screen Screen::DecodingOptions currentDecodingOptions(); + // Boilerplate setup for MessageWidget + KMessageWidget* createMessageWidget(const QString &text, std::function linkHandler); + // the window onto the terminal screen which this display // is currently showing. QPointer _screenWindow; bool _bellMasked; - QGridLayout *_gridLayout; + QVBoxLayout *_verticalLayout; bool _fixedFont; // has fixed pitch int _fontHeight; // height @@ -952,7 +962,7 @@ private: //widgets related to the warning message that appears when the user presses Ctrl+S to suspend //terminal output - informing them what has happened and how to resume output - QLabel *_outputSuspendedLabel; + KMessageWidget *_outputSuspendedMessageWidget; uint _lineSpacing; @@ -1000,6 +1010,8 @@ private: int _margin; // the contents margin bool _centerContents; // center the contents between margins + KMessageWidget *_readOnlyMessageWidget; // Message shown at the top when read-only mode gets activated + qreal _opacity; ScrollState _scrollWheelState;