Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 429ad275 authored by Joshua Noack's avatar Joshua Noack Committed by Kurt Hindenburg

Disable menu actions when read-only/locked

Summary:
This patch addresses the following points:

- Ignore most DBus methods
- Disable the following actions:
clear-history, clear-history-and-reset, edit-current-profile, switch-profile
adjust-history, send-signal, zmodem-upload, edit-rename (tab bar)

- Session updates all views correctly when readonly changes

{F5754353}

Test Plan:
- Actions do not show when locked
- DBus methods are ignored when locked
- Multiple views in one session get correctly updated

Reviewers: hindenburg, #konsole

Reviewed By: hindenburg, #konsole

Subscribers: ngraham, hindenburg, #konsole

Tags: #konsole

Differential Revision: https://phabricator.kde.org/D11341

(cherry picked from commit 3a1d350b)
parent be6f33bd
......@@ -208,6 +208,10 @@ bool Session::isRunning() const
void Session::setCodec(QTextCodec* codec)
{
if (isReadOnly()) {
return;
}
emulation()->setCodec(codec);
}
......@@ -856,12 +860,20 @@ bool Session::closeInForceWay()
void Session::sendTextToTerminal(const QString& text, const QChar& eol) const
{
if (isReadOnly()) {
return;
}
_emulation->sendText(text + eol);
}
// Only D-Bus calls this function (via SendText or runCommand)
void Session::sendText(const QString& text) const
{
if (isReadOnly()) {
return;
}
#if !defined(REMOVE_SENDTEXT_RUNCOMMAND_DBUS_METHODS)
if (show_disallow_certain_dbus_methods_message) {
......@@ -944,6 +956,10 @@ QStringList Session::environment() const
void Session::setEnvironment(const QStringList& environment)
{
if (isReadOnly()) {
return;
}
_environment = environment;
}
......@@ -1268,6 +1284,10 @@ bool Session::autoClose() const
void Session::setFlowControlEnabled(bool enabled)
{
if (isReadOnly()) {
return;
}
_flowControlEnabled = enabled;
if (_shellProcess != nullptr) {
......@@ -1496,6 +1516,10 @@ QString Session::tabTitleFormat(int context) const
void Session::setHistorySize(int lines)
{
if (isReadOnly()) {
return;
}
if (lines < 0) {
setHistoryType(HistoryTypeFile());
} else if (lines == 0) {
......@@ -1614,8 +1638,9 @@ void Session::setReadOnly(bool readOnly)
if (_readOnly != readOnly) {
_readOnly = readOnly;
// Needed to update the tab icon
emit titleChanged();
// Needed to update the tab icons and all
// attached views.
emit readOnlyChanged();
}
}
......
......@@ -594,6 +594,9 @@ Q_SIGNALS:
/** Emitted when the session's title has changed. */
void titleChanged();
/** Emitted when the session gets locked / unlocked. */
void readOnlyChanged();
/**
* Emitted when the activity state of this session changes.
*
......
......@@ -163,6 +163,7 @@ SessionController::SessionController(Session* session , TerminalDisplay* view, Q
connect(_session.data(), &Konsole::Session::stateChanged, this, &Konsole::SessionController::sessionStateChanged);
// listen to title and icon changes
connect(_session.data(), &Konsole::Session::titleChanged, this, &Konsole::SessionController::sessionTitleChanged);
connect(_session.data(), &Konsole::Session::readOnlyChanged, this, &Konsole::SessionController::sessionReadOnlyChanged);
connect(this, &Konsole::SessionController::tabRenamedByUser, _session, &Konsole::Session::tabRenamedByUser);
......@@ -464,7 +465,6 @@ void SessionController::toggleReadOnly()
QAction *action = qobject_cast<QAction*>(sender());
if (action != nullptr) {
bool readonly = !isReadOnly();
updateReadOnlyActionState(action, readonly);
_session->setReadOnly(readonly);
}
}
......@@ -635,12 +635,6 @@ void SessionController::setupCommonActions()
collection->addAction(QStringLiteral("switch-profile"), _switchProfileMenu);
connect(_switchProfileMenu->menu(), &QMenu::aboutToShow, this, &Konsole::SessionController::prepareSwitchProfileMenu);
// Read-only
action = collection->addAction(QStringLiteral("view-readonly"), this, SLOT(toggleReadOnly()));
action->setText(i18nc("@item:inmenu A read only (locked) session", "Read-only"));
action->setCheckable(true);
updateReadOnlyActionState(action, isReadOnly());
// History
_findAction = KStandardAction::find(this, SLOT(searchBarEvent()), collection);
collection->setDefaultShortcut(_findAction, QKeySequence());
......@@ -659,6 +653,12 @@ void SessionController::setupCommonActions()
collection->addAction(QStringLiteral("set-encoding"), _codecAction);
connect(_codecAction->menu(), &QMenu::aboutToShow, this, &Konsole::SessionController::updateCodecAction);
connect(_codecAction, static_cast<void(KCodecAction::*)(QTextCodec*)>(&KCodecAction::triggered), this, &Konsole::SessionController::changeCodec);
// Read-only
action = collection->addAction(QStringLiteral("view-readonly"), this, SLOT(toggleReadOnly()));
action->setText(i18nc("@item:inmenu A read only (locked) session", "Read-only"));
action->setCheckable(true);
updateReadOnlyActionStates();
}
void SessionController::setupExtraActions()
......@@ -1543,15 +1543,31 @@ void SessionController::updateSessionIcon()
}
}
void SessionController::updateReadOnlyActionState(QAction *action, bool readonly)
void SessionController::updateReadOnlyActionStates()
{
action->setIcon(QIcon::fromTheme(readonly ? QStringLiteral("object-locked") : QStringLiteral("object-unlocked")));
action->setChecked(readonly);
bool readonly = isReadOnly();
QAction *readonlyAction = actionCollection()->action(QStringLiteral("view-readonly"));
Q_ASSERT(readonlyAction != nullptr);
readonlyAction->setIcon(QIcon::fromTheme(readonly ? QStringLiteral("object-locked") : QStringLiteral("object-unlocked")));
readonlyAction->setChecked(readonly);
QAction *editAction = actionCollection()->action(QStringLiteral("edit_paste"));
if (editAction != nullptr) {
editAction->setEnabled(!readonly);
}
auto updateActionState = [this, readonly](const QString &name) {
QAction *action = actionCollection()->action(name);
if (action != nullptr) {
action->setEnabled(!readonly);
}
};
updateActionState(QStringLiteral("edit_paste"));
updateActionState(QStringLiteral("clear-history"));
updateActionState(QStringLiteral("clear-history-and-reset"));
updateActionState(QStringLiteral("edit-current-profile"));
updateActionState(QStringLiteral("switch-profile"));
updateActionState(QStringLiteral("adjust-history"));
updateActionState(QStringLiteral("send-signal"));
updateActionState(QStringLiteral("zmodem-upload"));
_codecAction->setEnabled(!readonly);
// Without the timer, when detaching a tab while the message widget is visible,
// the size of the terminal becomes really small...
......@@ -1590,6 +1606,20 @@ void SessionController::sessionTitleChanged()
emit rawTitleChanged();
}
void SessionController::sessionReadOnlyChanged() {
// Trigger icon update
sessionTitleChanged();
updateReadOnlyActionStates();
// Update all views
for (TerminalDisplay* view : session()->views()) {
if (view != _view.data()) {
view->updateReadOnlyState(isReadOnly());
}
}
}
void SessionController::showDisplayContextMenu(const QPoint& position)
{
// needed to make sure the popup menu is available, even if a hosting
......@@ -1606,6 +1636,8 @@ void SessionController::showDisplayContextMenu(const QPoint& position)
QPointer<QMenu> popup = qobject_cast<QMenu*>(factory()->container(QStringLiteral("session-popup-menu"), this));
if (popup != nullptr) {
updateReadOnlyActionStates();
// prepend content-specific actions such as "Open Link", "Copy Email Address" etc.
QList<QAction*> contentActions = _view->filterActions(position);
auto contentSeparator = new QAction(popup);
......
......@@ -275,6 +275,7 @@ private Q_SLOTS:
void movementKeyFromSearchBarReceived(QKeyEvent *event);
void sessionStateChanged(int state);
void sessionTitleChanged();
void sessionReadOnlyChanged();
void searchTextChanged(const QString &text);
void searchCompleted(bool success);
void searchClosed(); // called when the user clicks on the
......@@ -321,7 +322,7 @@ private:
private:
void updateSessionIcon();
void updateReadOnlyActionState(QAction *action, bool readonly);
void updateReadOnlyActionStates();
QPointer<Session> _session;
QPointer<TerminalDisplay> _view;
......
......@@ -409,6 +409,7 @@ TerminalDisplay::TerminalDisplay(QWidget* parent)
, _margin(1)
, _centerContents(false)
, _readOnlyMessageWidget(nullptr)
, _readOnly(false)
, _opacity(1.0)
{
// terminal applications are not designed with Right-To-Left in mind,
......@@ -3138,7 +3139,7 @@ void TerminalDisplay::doPaste(QString text, bool appendReturn)
return;
}
if (_sessionController->isReadOnly()) {
if (_readOnly) {
return;
}
......@@ -3262,7 +3263,7 @@ void TerminalDisplay::inputMethodEvent(QInputMethodEvent* event)
emit keyPressedSignal(&keyEvent);
}
if (!_sessionController->isReadOnly()) {
if (!_readOnly) {
_inputMethodData.preeditString = event->preeditString();
update(preeditRect() | _inputMethodData.previousPreeditRect);
}
......@@ -3390,6 +3391,9 @@ KMessageWidget* TerminalDisplay::createMessageWidget(const QString &text) {
}
void TerminalDisplay::updateReadOnlyState(bool readonly) {
if (_readOnly == readonly) {
return;
}
if (readonly) {
// Lazy create the readonly messagewidget
......@@ -3402,6 +3406,8 @@ void TerminalDisplay::updateReadOnlyState(bool readonly) {
if (_readOnlyMessageWidget != nullptr) {
readonly ? _readOnlyMessageWidget->animatedShow() : _readOnlyMessageWidget->animatedHide();
}
_readOnly = readonly;
}
void TerminalDisplay::scrollScreenWindow(enum ScreenWindow::RelativeScrollMode mode, int amount)
......@@ -3416,7 +3422,7 @@ void TerminalDisplay::scrollScreenWindow(enum ScreenWindow::RelativeScrollMode m
void TerminalDisplay::keyPressEvent(QKeyEvent* event)
{
if (_sessionController->isReadOnly()) {
if (_readOnly) {
event->accept();
return;
}
......@@ -3468,7 +3474,7 @@ void TerminalDisplay::keyReleaseEvent(QKeyEvent *event)
update();
}
if (_sessionController->isReadOnly()) {
if (_readOnly) {
event->accept();
return;
}
......@@ -3628,7 +3634,7 @@ void TerminalDisplay::dragEnterEvent(QDragEnterEvent* event)
// and pcmanfm
// That also applies in dropEvent()
const auto mimeData = event->mimeData();
if ((!_sessionController->isReadOnly()) && (mimeData != nullptr)
if ((!_readOnly) && (mimeData != nullptr)
&& (mimeData->hasFormat(QStringLiteral("text/plain"))
|| mimeData->hasFormat(QStringLiteral("text/uri-list")))) {
event->acceptProposedAction();
......@@ -3637,7 +3643,7 @@ void TerminalDisplay::dragEnterEvent(QDragEnterEvent* event)
void TerminalDisplay::dropEvent(QDropEvent* event)
{
if (_sessionController->isReadOnly()) {
if (_readOnly) {
event->accept();
return;
}
......
......@@ -1022,6 +1022,9 @@ private:
KMessageWidget *_readOnlyMessageWidget; // Message shown at the top when read-only mode gets activated
// Needed to know wether the mode really changed between update calls
bool _readOnly;
qreal _opacity;
ScrollState _scrollWheelState;
......
......@@ -321,13 +321,13 @@ TabbedViewContainer::TabbedViewContainer(NavigationPosition position,
_contextPopupMenu->addAction(QIcon::fromTheme(QStringLiteral("edit-rename")),
i18nc("@action:inmenu", "&Rename Tab..."), this,
SLOT(tabContextMenuRenameTab()));
_contextPopupMenu->actions().last()->setObjectName(QStringLiteral("edit-rename"));
_contextPopupMenu->addSeparator();
_contextPopupMenu->addAction(QIcon::fromTheme(QStringLiteral("tab-close")),
i18nc("@action:inmenu", "&Close Tab"), this,
SLOT(tabContextMenuCloseTab()));
// The 'new tab' and 'close tab' button
_newTabButton = new QToolButton(_containerWidget);
_newTabButton->setFocusPolicy(Qt::NoFocus);
......@@ -637,6 +637,14 @@ void TabbedViewContainer::openTabContextMenu(const QPoint &point)
const auto readonlyActions = _contextPopupMenu->actions();
_contextPopupMenu->insertAction(readonlyActions.last(), readonlyAction);
}
// Disable tab rename
for (auto *action : _contextPopupMenu->actions()) {
if (action->objectName() == QStringLiteral("edit-rename")) {
action->setEnabled(!sessionController->isReadOnly());
break;
}
}
}
_contextPopupMenu->exec(_tabBar->mapToGlobal(point));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment