feat: add Konsole recipe source and patches
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2018 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "DetachableTabBar.h"
|
||||
#include "KonsoleSettings.h"
|
||||
#include "widgets/ViewContainer.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMimeData>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include <KAcceleratorManager>
|
||||
|
||||
#include <QColor>
|
||||
#include <QPainter>
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
DetachableTabBar::DetachableTabBar(QWidget *parent)
|
||||
: QTabBar(parent)
|
||||
, dragType(DragType::NONE)
|
||||
, _originalCursor(cursor())
|
||||
, tabId(-1)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
setElideMode(Qt::TextElideMode::ElideLeft);
|
||||
KAcceleratorManager::setNoAccel(this);
|
||||
}
|
||||
|
||||
void DetachableTabBar::setColor(int idx, const QColor &color)
|
||||
{
|
||||
setTabData(idx, color);
|
||||
}
|
||||
|
||||
void DetachableTabBar::removeColor(int idx)
|
||||
{
|
||||
setTabData(idx, QVariant());
|
||||
}
|
||||
|
||||
void DetachableTabBar::middleMouseButtonClickAt(const QPoint &pos)
|
||||
{
|
||||
tabId = tabAt(pos);
|
||||
|
||||
if (tabId != -1) {
|
||||
Q_EMIT closeTab(tabId);
|
||||
}
|
||||
}
|
||||
|
||||
void DetachableTabBar::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QTabBar::mousePressEvent(event);
|
||||
_containers = window()->findChildren<Konsole::TabbedViewContainer *>();
|
||||
}
|
||||
|
||||
void DetachableTabBar::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QTabBar::mouseMoveEvent(event);
|
||||
auto widgetAtPos = qApp->topLevelAt(event->globalPosition().toPoint());
|
||||
if (widgetAtPos != nullptr) {
|
||||
if (window() == widgetAtPos->window()) {
|
||||
if (dragType != DragType::NONE) {
|
||||
dragType = DragType::NONE;
|
||||
setCursor(_originalCursor);
|
||||
}
|
||||
} else {
|
||||
if (dragType != DragType::WINDOW) {
|
||||
dragType = DragType::WINDOW;
|
||||
setCursor(QCursor(Qt::DragMoveCursor));
|
||||
}
|
||||
}
|
||||
} else if (!contentsRect().adjusted(-30, -30, 30, 30).contains(event->pos())) {
|
||||
// Don't let it detach the last tab.
|
||||
if (count() == 1) {
|
||||
return;
|
||||
}
|
||||
if (dragType != DragType::OUTSIDE) {
|
||||
dragType = DragType::OUTSIDE;
|
||||
setCursor(QCursor(Qt::DragCopyCursor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DetachableTabBar::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QTabBar::mouseReleaseEvent(event);
|
||||
|
||||
switch (event->button()) {
|
||||
case Qt::MiddleButton:
|
||||
if (KonsoleSettings::closeTabOnMiddleMouseButton()) {
|
||||
middleMouseButtonClickAt(event->pos());
|
||||
}
|
||||
|
||||
tabId = tabAt(event->pos());
|
||||
if (tabId == -1) {
|
||||
Q_EMIT newTabRequest();
|
||||
}
|
||||
break;
|
||||
case Qt::LeftButton:
|
||||
_containers = window()->findChildren<Konsole::TabbedViewContainer *>();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
setCursor(_originalCursor);
|
||||
|
||||
if (contentsRect().adjusted(-30, -30, 30, 30).contains(event->pos())) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto widgetAtPos = qApp->topLevelAt(event->globalPosition().toPoint());
|
||||
if (widgetAtPos == nullptr) {
|
||||
if (count() != 1) {
|
||||
Q_EMIT detachTab(currentIndex());
|
||||
}
|
||||
} else if (window() != widgetAtPos->window()) {
|
||||
if (_containers.size() == 1 || count() > 1) {
|
||||
Q_EMIT moveTabToWindow(currentIndex(), widgetAtPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DetachableTabBar::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
const auto dragId = QStringLiteral("konsole/terminal_display");
|
||||
if (!event->mimeData()->hasFormat(dragId)) {
|
||||
return;
|
||||
}
|
||||
auto other_pid = event->mimeData()->data(dragId).toInt();
|
||||
// don't accept the drop if it's another instance of konsole
|
||||
if (qApp->applicationPid() != other_pid) {
|
||||
return;
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void DetachableTabBar::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
int tabIdx = tabAt(event->position().toPoint());
|
||||
if (tabIdx != -1) {
|
||||
setCurrentIndex(tabIdx);
|
||||
}
|
||||
}
|
||||
|
||||
void DetachableTabBar::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QTabBar::paintEvent(event);
|
||||
if (!event->isAccepted()) {
|
||||
return; // Reduces repainting
|
||||
}
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setPen(Qt::NoPen);
|
||||
|
||||
for (int tabIndex = 0; tabIndex < count(); tabIndex++) {
|
||||
const QVariant data = tabData(tabIndex);
|
||||
if (!data.isValid() || data.isNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QColor varColor = data.value<QColor>();
|
||||
if (!varColor.isValid() || varColor.alpha() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
painter.setBrush(varColor);
|
||||
QRect tRect = tabRect(tabIndex);
|
||||
tRect.setTop(painter.fontMetrics().height() + 6); // Color bar top position consider a height the font and fixed spacing of 6px
|
||||
tRect.setHeight(4);
|
||||
tRect.setLeft(tRect.left() + 6);
|
||||
tRect.setWidth(tRect.width() - 6);
|
||||
painter.drawRect(tRect);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "moc_DetachableTabBar.cpp"
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2018 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef DETACHABLETABBAR_H
|
||||
#define DETACHABLETABBAR_H
|
||||
|
||||
#include <QCursor>
|
||||
#include <QTabBar>
|
||||
|
||||
class QColor;
|
||||
class QPaintEvent;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
class TabbedViewContainer;
|
||||
class DetachableTabBar : public QTabBar
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class DragType : unsigned char {
|
||||
NONE,
|
||||
OUTSIDE,
|
||||
WINDOW,
|
||||
};
|
||||
|
||||
explicit DetachableTabBar(QWidget *parent = nullptr);
|
||||
|
||||
void setColor(int idx, const QColor &color);
|
||||
void removeColor(int idx);
|
||||
Q_SIGNALS:
|
||||
void detachTab(int index);
|
||||
void moveTabToWindow(int tabIndex, QWidget *otherWindow);
|
||||
void closeTab(int index);
|
||||
void newTabRequest();
|
||||
|
||||
protected:
|
||||
void middleMouseButtonClickAt(const QPoint &pos);
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
DragType dragType;
|
||||
QCursor _originalCursor;
|
||||
QList<TabbedViewContainer *> _containers;
|
||||
int tabId;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,320 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditProfileAdvancedPage</class>
|
||||
<widget class="QWidget" name="EditProfileAdvancedPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout">
|
||||
<item row="0" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="urlHintsLabel">
|
||||
<property name="text">
|
||||
<string>Key combination to show URL hints:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" stretch="0,1">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="urlHintsModifierShift">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="key on keyboard">Shift</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonFollowStyle</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="urlHintsModifierCtrl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="key on keyboard">Ctrl</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonFollowStyle</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="urlHintsModifierAlt">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="key on keyboard">Alt</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonFollowStyle</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="urlHintsModifierMeta">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="key on keyboard">Meta</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonFollowStyle</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string comment="Items that do not fit in other categories">Miscellaneous:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="enableReverseUrlHints">
|
||||
<property name="toolTip">
|
||||
<string>Number URL hints in reverse, starting from the bottom</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reverse URL hint numbering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="enableBlinkingTextButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Allow terminal programs to create blinking sections of text</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Allow blinking text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="enableFlowControlButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Allow the output to be suspended by pressing Ctrl+S</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Flow control</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="7" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>&Default character encoding:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>selectEncodingButton</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QPushButton" name="selectEncodingButton">
|
||||
<property name="text">
|
||||
<string notr="true">DEFAULTENCODING</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="peekPrimaryLabel">
|
||||
<property name="text">
|
||||
<string>Shortcut for peeking the primary screen:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QKeySequenceEdit" name="peekPrimaryWidget"/>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_linenums">
|
||||
<property name="text">
|
||||
<string>Line Numbers:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QRadioButton" name="lineNumsNever">
|
||||
<property name="text">
|
||||
<string comment="Never">&Never</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">lineNums</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QRadioButton" name="lineNumsURL">
|
||||
<property name="text">
|
||||
<string comment="When showing URL hints">When &URL hints show</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">lineNums</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QRadioButton" name="lineNumsAlways">
|
||||
<property name="text">
|
||||
<string comment="Always">A&lways</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">lineNums</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>111</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>urlHintsModifierShift</tabstop>
|
||||
<tabstop>urlHintsModifierCtrl</tabstop>
|
||||
<tabstop>urlHintsModifierAlt</tabstop>
|
||||
<tabstop>urlHintsModifierMeta</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="lineNums"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
|
||||
SPDX-FileCopyrightText: 2018 Harald Sitter <sitter@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef EDITPROFILEDIALOG_H
|
||||
#define EDITPROFILEDIALOG_H
|
||||
|
||||
#include <QtGlobal>
|
||||
// KDE
|
||||
#include <KNSCore/Entry>
|
||||
#include <KPageDialog>
|
||||
|
||||
// Konsole
|
||||
#include "colorscheme/ColorScheme.h"
|
||||
#include "colorscheme/ColorSchemeEditor.h"
|
||||
#include "colorscheme/ColorSchemeViewDelegate.h"
|
||||
#include "konsoleprivate_export.h"
|
||||
|
||||
#include "profile/Profile.h"
|
||||
#include "profile/ProfileGroup.h"
|
||||
|
||||
#include "Enumeration.h"
|
||||
#include "FontDialog.h"
|
||||
#include "LabelsAligner.h"
|
||||
#include "keyboardtranslator/KeyboardTranslatorManager.h"
|
||||
|
||||
class KPluralHandlingSpinBox;
|
||||
class KLocalizedString;
|
||||
class QItemSelectionModel;
|
||||
class QTextCodec;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class EditProfileGeneralPage;
|
||||
class EditProfileTabsPage;
|
||||
class EditProfileAppearancePage;
|
||||
class EditProfileScrollingPage;
|
||||
class EditProfileKeyboardPage;
|
||||
class EditProfileMousePage;
|
||||
class EditProfileAdvancedPage;
|
||||
}
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
/**
|
||||
* A dialog which allows the user to edit a profile.
|
||||
* After the dialog is created, it can be initialized with the settings
|
||||
* for a profile using setProfile(). When the user makes changes to the
|
||||
* dialog and accepts the changes, the dialog will update the
|
||||
* profile in the SessionManager by calling the SessionManager's
|
||||
* changeProfile() method.
|
||||
*
|
||||
* Some changes made in the dialog are preview-only changes which cause
|
||||
* the SessionManager's changeProfile() method to be called with
|
||||
* the persistent argument set to false. These changes are then
|
||||
* un-done when the dialog is closed.
|
||||
*/
|
||||
class KONSOLEPRIVATE_EXPORT EditProfileDialog : public KPageDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Constructs a new dialog with the specified parent. */
|
||||
explicit EditProfileDialog(QWidget *parent = nullptr);
|
||||
~EditProfileDialog() override;
|
||||
|
||||
enum InitialProfileState {
|
||||
ExistingProfile,
|
||||
NewProfile,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the dialog with the settings for the specified session
|
||||
* type.
|
||||
*
|
||||
* When the dialog closes, the profile will be updated in the SessionManager
|
||||
* with the altered settings.
|
||||
*
|
||||
* @param profile The profile to be edited
|
||||
* @param state Indicates whether @p profile is an already existing profile
|
||||
* or a new one being created
|
||||
*/
|
||||
void setProfile(const Profile::Ptr &profile, InitialProfileState state = EditProfileDialog::ExistingProfile);
|
||||
|
||||
/**
|
||||
* Selects the text in the profile name edit area.
|
||||
* When the dialog is being used to create a new profile,
|
||||
* this can be used to draw the user's attention to the profile name
|
||||
* and make it easy for them to change it.
|
||||
*/
|
||||
void selectProfileName();
|
||||
|
||||
public Q_SLOTS:
|
||||
// reimplemented
|
||||
void accept() override;
|
||||
// reimplemented
|
||||
void reject() override;
|
||||
|
||||
private Q_SLOTS:
|
||||
QSize sizeHint() const override;
|
||||
|
||||
// sets up the specified tab page if necessary
|
||||
void preparePage(KPageWidgetItem *current, KPageWidgetItem *before = nullptr);
|
||||
|
||||
// saves changes to profile
|
||||
void save();
|
||||
|
||||
// general page
|
||||
void selectInitialDir();
|
||||
void selectIcon();
|
||||
|
||||
void profileNameChanged(const QString &name);
|
||||
void initialDirChanged(const QString &dir);
|
||||
void startInSameDir(bool);
|
||||
void commandChanged(const QString &command);
|
||||
void semanticUpDown(bool);
|
||||
void semanticInputClick(bool enable);
|
||||
|
||||
// tab page
|
||||
void tabTitleFormatChanged(const QString &format);
|
||||
void remoteTabTitleFormatChanged(const QString &format);
|
||||
void tabColorChanged(const QColor &color);
|
||||
void silenceSecondsChanged(int);
|
||||
|
||||
void terminalColumnsEntryChanged(int);
|
||||
void terminalRowsEntryChanged(int);
|
||||
void showTerminalSizeHint(bool);
|
||||
void setDimWhenInactive(bool);
|
||||
void setDimValue(int value);
|
||||
void setBorderWhenActive(bool);
|
||||
void setFocusBorderColor(const QColor &color);
|
||||
void showEnvironmentEditor();
|
||||
|
||||
// appearance page
|
||||
void setAntialiasText(bool enable);
|
||||
void setBoldIntense(bool enable);
|
||||
void useFontLineCharacters(bool enable);
|
||||
void useFontBrailleCharacters(bool enable);
|
||||
void newColorScheme();
|
||||
void editColorScheme();
|
||||
void saveColorScheme(const ColorScheme &scheme, bool isNewScheme);
|
||||
void removeColorScheme();
|
||||
void setVerticalLine(bool);
|
||||
void setVerticalLineColumn(int);
|
||||
// void focusBorderColor();
|
||||
void focusBorderColorChanged(const QColor &color);
|
||||
void toggleBlinkingCursor(bool);
|
||||
void setCursorShape(int);
|
||||
void autoCursorColor();
|
||||
void customCursorColor();
|
||||
void customCursorColorChanged(const QColor &);
|
||||
void customCursorTextColorChanged(const QColor &);
|
||||
void terminalMarginChanged(int margin);
|
||||
void lineSpacingChanged(int);
|
||||
void setTerminalCenter(bool enable);
|
||||
void togglebidiRendering(bool);
|
||||
void togglebidiTableDirOverride(bool);
|
||||
void togglebidiLineLTR(bool);
|
||||
|
||||
void gotNewColorSchemes(const QList<KNSCore::Entry> &changedEntries);
|
||||
|
||||
/**
|
||||
* Deletes the selected colorscheme from the user's home dir location
|
||||
* so that the original one from the system-wide location can be used
|
||||
* instead
|
||||
*/
|
||||
void resetColorScheme();
|
||||
|
||||
void colorSchemeSelected();
|
||||
void previewColorScheme(const QModelIndex &index);
|
||||
void showFontDialog();
|
||||
void showEmojiFontDialog();
|
||||
void toggleMouseWheelZoom(bool enable);
|
||||
|
||||
// scrolling page
|
||||
void historyModeChanged(Enum::HistoryModeEnum mode);
|
||||
|
||||
void historySizeChanged(int);
|
||||
|
||||
void scrollFullPage();
|
||||
void scrollHalfPage();
|
||||
void toggleHighlightScrolledLines(bool enable);
|
||||
void toggleReflowLines(bool enable);
|
||||
|
||||
void toggleScrollbarMarkerColor(QColor color);
|
||||
void toggleScrollbarMarkerSize(double pSize);
|
||||
|
||||
// keyboard page
|
||||
void editKeyBinding();
|
||||
void newKeyBinding();
|
||||
void keyBindingSelected();
|
||||
void removeKeyBinding();
|
||||
void resetKeyBindings();
|
||||
|
||||
// mouse page
|
||||
void toggleUnderlineFiles(bool enable);
|
||||
void toggleUnderlineLinks(bool);
|
||||
void toggleOpenLinksByDirectClick(bool);
|
||||
void textEditorCmdEditLineChanged(const QString &text);
|
||||
void toggleCtrlRequiredForDrag(bool);
|
||||
void toggleDropUrlsAsText(bool);
|
||||
void toggleCopyTextToClipboard(bool);
|
||||
void toggleCopyTextAsHTML(bool);
|
||||
void toggleTrimLeadingSpacesInSelectedText(bool);
|
||||
void toggleTrimTrailingSpacesInSelectedText(bool);
|
||||
void pasteFromX11Selection();
|
||||
void pasteFromClipboard();
|
||||
void toggleAlternateScrolling(bool enable);
|
||||
void toggleAllowColorFilter(bool enable);
|
||||
void toggleAllowMouseTracking(bool allow);
|
||||
|
||||
void TripleClickModeChanged(int);
|
||||
void wordCharactersChanged(const QString &);
|
||||
|
||||
// advanced page
|
||||
void toggleBlinkingText(bool);
|
||||
void toggleFlowControl(bool);
|
||||
void updateUrlHintsModifier(bool);
|
||||
void toggleReverseUrlHints(bool);
|
||||
|
||||
void setDefaultCodec(QTextCodec *);
|
||||
|
||||
void setTextEditorCombo(const Profile::Ptr &profile);
|
||||
|
||||
void toggleAllowLinkEscapeSequence(bool);
|
||||
void linkEscapeSequenceTextsChanged();
|
||||
|
||||
void peekPrimaryKeySequenceChanged();
|
||||
|
||||
void toggleWordMode(bool mode);
|
||||
void toggleWordModeAttr(bool mode);
|
||||
void toggleWordModeAscii(bool mode);
|
||||
void toggleWordModeBrahmic(bool mode);
|
||||
void toggleIgnoreWcWidth(bool ignore);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(EditProfileDialog)
|
||||
|
||||
enum PageID {
|
||||
GeneralPage = 0,
|
||||
TabsPage,
|
||||
AppearancePage,
|
||||
ScrollingPage,
|
||||
KeyboardPage,
|
||||
MousePage,
|
||||
AdvancedPage,
|
||||
PagesCount,
|
||||
};
|
||||
|
||||
// initialize various pages of the dialog
|
||||
void setupGeneralPage(const Profile::Ptr &profile);
|
||||
void setupTabsPage(const Profile::Ptr &profile);
|
||||
void setupAppearancePage(const Profile::Ptr &profile);
|
||||
void setupKeyboardPage(const Profile::Ptr &profile);
|
||||
void setupScrollingPage(const Profile::Ptr &profile);
|
||||
void setupAdvancedPage(const Profile::Ptr &profile);
|
||||
void setupMousePage(const Profile::Ptr &profile);
|
||||
|
||||
void setMessageGeneralPage(const QString &msg);
|
||||
|
||||
int maxSpinBoxWidth(const KPluralHandlingSpinBox *spinBox, const KLocalizedString &suffix);
|
||||
|
||||
// Returns the name of the colorScheme used in the current profile
|
||||
const QString currentColorSchemeName() const;
|
||||
|
||||
// select @p selectedColorSchemeName after the changes are saved
|
||||
// in the colorScheme editor
|
||||
void updateColorSchemeList(const QString &selectedColorSchemeName = QString());
|
||||
|
||||
void updateColorSchemeButtons();
|
||||
|
||||
// Convenience method
|
||||
KeyboardTranslatorManager *_keyManager = KeyboardTranslatorManager::instance();
|
||||
|
||||
// Updates the key bindings list widget on the Keyboard tab and selects
|
||||
// @p selectKeyBindingsName
|
||||
void updateKeyBindingsList(const QString &selectKeyBindingsName = QString());
|
||||
void updateKeyBindingsButtons();
|
||||
void showKeyBindingEditor(bool isNewTranslator);
|
||||
|
||||
void showColorSchemeEditor(bool isNewScheme);
|
||||
void closeColorSchemeEditor();
|
||||
|
||||
void preview(Profile::Property prop, const QVariant &value);
|
||||
void unpreview(Profile::Property prop);
|
||||
void unpreviewAll();
|
||||
void enableIfNonEmptySelection(QWidget *widget, QItemSelectionModel *selectionModel);
|
||||
|
||||
void updateCaption(const Profile::Ptr &profile);
|
||||
void updateTransparencyWarning();
|
||||
|
||||
void updateFontPreview(QFont font);
|
||||
void updateEmojiFontPreview(QFont font);
|
||||
|
||||
// Update _tempProfile in a way of respecting the apply button.
|
||||
// When used with some previewed property, this method should
|
||||
// always come after the preview operation.
|
||||
void updateTempProfileProperty(Profile::Property, const QVariant &value);
|
||||
|
||||
// helper method for clearing all _tempProfile properties and marking it hidden
|
||||
void resetTempProfile();
|
||||
|
||||
// Enable or disable apply button, used only within
|
||||
// updateTempProfileProperty() or when toggling the default profile.
|
||||
void updateButtonApply();
|
||||
|
||||
static QString groupProfileNames(const ProfileGroup::Ptr &group, int maxLength = -1);
|
||||
|
||||
struct ButtonGroupOption {
|
||||
QAbstractButton *button;
|
||||
int value;
|
||||
};
|
||||
struct ButtonGroupOptions {
|
||||
QButtonGroup *group;
|
||||
Profile::Property profileProperty;
|
||||
bool preview;
|
||||
QVector<ButtonGroupOption> buttons;
|
||||
};
|
||||
void setupButtonGroup(const ButtonGroupOptions &options, const Profile::Ptr &profile);
|
||||
|
||||
// returns false if:
|
||||
// - the profile name is empty
|
||||
// - the name matches the name of an already existing profile
|
||||
// - the existing profile config file is read-only
|
||||
// otherwise returns true.
|
||||
bool isProfileNameValid();
|
||||
|
||||
Ui::EditProfileGeneralPage *_generalUi = nullptr;
|
||||
Ui::EditProfileTabsPage *_tabsUi = nullptr;
|
||||
Ui::EditProfileAppearancePage *_appearanceUi = nullptr;
|
||||
Ui::EditProfileScrollingPage *_scrollingUi = nullptr;
|
||||
Ui::EditProfileKeyboardPage *_keyboardUi = nullptr;
|
||||
Ui::EditProfileMousePage *_mouseUi = nullptr;
|
||||
Ui::EditProfileAdvancedPage *_advancedUi = nullptr;
|
||||
|
||||
using PageSetupMethod = void (EditProfileDialog::*)(const Profile::Ptr &);
|
||||
struct Page {
|
||||
Page(PageSetupMethod page = nullptr, bool update = false)
|
||||
: setupPage(page)
|
||||
, needsUpdate(update)
|
||||
{
|
||||
}
|
||||
|
||||
PageSetupMethod setupPage;
|
||||
bool needsUpdate;
|
||||
};
|
||||
|
||||
QMap<KPageWidgetItem *, Page> _pages;
|
||||
KPageWidgetItem *_generalPageItem = nullptr;
|
||||
|
||||
Profile::Ptr _tempProfile;
|
||||
Profile::Ptr _profile;
|
||||
|
||||
bool _isDefault = false;
|
||||
|
||||
Profile::PropertyMap _previewedProperties;
|
||||
|
||||
ColorSchemeEditor *_colorDialog = nullptr;
|
||||
QDialogButtonBox *_buttonBox = nullptr;
|
||||
FontDialog *_fontDialog = nullptr;
|
||||
FontDialog *_emojiFontDialog = nullptr;
|
||||
|
||||
InitialProfileState _profileState = ExistingProfile;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // EDITPROFILEDIALOG_H
|
||||
@@ -0,0 +1,700 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditProfileGeneralPage</class>
|
||||
<widget class="QWidget" name="EditProfileGeneralPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>642</width>
|
||||
<height>498</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="KMessageWidget" name="generalPageMessageWidget"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="documentMode">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="general">
|
||||
<attribute name="title">
|
||||
<string>General Settings</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout">
|
||||
<item row="1" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QPushButton" name="iconSelectButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select the icon displayed on tabs using this profile</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QVBoxLayout" name="profileNameLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="profileNameEdit">
|
||||
<property name="toolTip">
|
||||
<string>A descriptive name for the profile</string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string comment="@label:textbox">Profile name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="setAsDefaultButton">
|
||||
<property name="text">
|
||||
<string>Default Profile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Command:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>commandEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="commandEdit">
|
||||
<property name="toolTip">
|
||||
<string>The command to execute when new terminal sessions are created using this profile</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>/bin/sh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>I&nitial directory:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>initialDirEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="initialDirEdit">
|
||||
<property name="toolTip">
|
||||
<string>The initial working directory for new terminal sessions using this profile</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>/home/username</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QToolButton" name="dirSelectButton">
|
||||
<property name="toolTip">
|
||||
<string>Choose the initial directory</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="startInSameDirButton">
|
||||
<property name="text">
|
||||
<string>Start in same directory as current session</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Environment:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>environmentEditButton</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="environmentEditButton">
|
||||
<property name="toolTip">
|
||||
<string>Edit the list of environment variables and associated values</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Edit...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="8" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Initial terminal si&ze:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>terminalColumnsEntry</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1" colspan="2">
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="KPluralHandlingSpinBox" name="terminalColumnsEntry">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="KPluralHandlingSpinBox" name="terminalRowsEntry">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="9" column="1" colspan="2">
|
||||
<widget class="QLabel" name="useCurrentWindowSizeNote">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="@info"><html><head/><body><p><span style=" font-style:italic;">Settings → Configure Konsole → General → Remember window size</span> must be disabled for these entries to work.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::TextFormat::RichText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="terminalBellLabel">
|
||||
<property name="text">
|
||||
<string>&Terminal bell mode:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>terminalBellCombo</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<layout class="QHBoxLayout" name="terminalBellLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="terminalBellCombo"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="semantic">
|
||||
<attribute name="title">
|
||||
<string>Semantic Integration</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout">
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="semanticUpDown">
|
||||
<property name="text">
|
||||
<string>Up/Down Arrows emulation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="semanticInputClick">
|
||||
<property name="text">
|
||||
<string>Mouse click in input line moves cursor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Semantic hints:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QRadioButton" name="semanticHintsNever">
|
||||
<property name="text">
|
||||
<string comment="Never">Never</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">semanticHints</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QRadioButton" name="semanticHintsURL">
|
||||
<property name="text">
|
||||
<string comment="When showing URL hints">When URL hints show</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">semanticHints</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QRadioButton" name="semanticHintsAlways">
|
||||
<property name="text">
|
||||
<string comment="Always">Always</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">semanticHints</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="20" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Red error bars:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="20" column="1">
|
||||
<widget class="QRadioButton" name="errorBarsNever">
|
||||
<property name="text">
|
||||
<string comment="Never">Never</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">errorBars</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="21" column="1">
|
||||
<widget class="QRadioButton" name="errorBarsURL">
|
||||
<property name="text">
|
||||
<string comment="When showing URL hints">When URL hints show</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">errorBars</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="22" column="1">
|
||||
<widget class="QRadioButton" name="errorBarsAlways">
|
||||
<property name="text">
|
||||
<string comment="Always">Always</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">errorBars</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="30" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Red error background:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="30" column="1">
|
||||
<widget class="QRadioButton" name="errorBackgroundNever">
|
||||
<property name="text">
|
||||
<string comment="Never">Never</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">errorBackground</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="31" column="1">
|
||||
<widget class="QRadioButton" name="errorBackgroundURL">
|
||||
<property name="text">
|
||||
<string comment="When showing URL hints">When URL hints show</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">errorBackground</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="32" column="1">
|
||||
<widget class="QRadioButton" name="errorBackgroundAlways">
|
||||
<property name="text">
|
||||
<string comment="Always">Always</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">errorBackground</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="40" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_40">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Alternating bars:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="40" column="1">
|
||||
<widget class="QRadioButton" name="alternatingBarsNever">
|
||||
<property name="text">
|
||||
<string comment="Never">Never</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">alternatingBars</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="41" column="1">
|
||||
<widget class="QRadioButton" name="alternatingBarsURL">
|
||||
<property name="text">
|
||||
<string comment="When showing URL hints">When URL hints show</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">alternatingBars</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="42" column="1">
|
||||
<widget class="QRadioButton" name="alternatingBarsAlways">
|
||||
<property name="text">
|
||||
<string comment="Always">Always</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">alternatingBars</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="50" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_50">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Alternating background:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="50" column="1">
|
||||
<widget class="QRadioButton" name="alternatingBackgroundNever">
|
||||
<property name="text">
|
||||
<string comment="Never">Never</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">alternatingBackground</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="51" column="1">
|
||||
<widget class="QRadioButton" name="alternatingBackgroundURL">
|
||||
<property name="text">
|
||||
<string comment="When showing URL hints">When URL hints show</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">alternatingBackground</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="52" column="1">
|
||||
<widget class="QRadioButton" name="alternatingBackgroundAlways">
|
||||
<property name="text">
|
||||
<string comment="Always">Always</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">alternatingBackground</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="99" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KPluralHandlingSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>kpluralhandlingspinbox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>KMessageWidget</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>kmessagewidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>environmentEditButton</tabstop>
|
||||
<tabstop>terminalColumnsEntry</tabstop>
|
||||
<tabstop>terminalRowsEntry</tabstop>
|
||||
<tabstop>semanticHintsNever</tabstop>
|
||||
<tabstop>semanticHintsURL</tabstop>
|
||||
<tabstop>semanticHintsAlways</tabstop>
|
||||
<tabstop>errorBarsNever</tabstop>
|
||||
<tabstop>errorBarsURL</tabstop>
|
||||
<tabstop>errorBarsAlways</tabstop>
|
||||
<tabstop>errorBackgroundNever</tabstop>
|
||||
<tabstop>errorBackgroundURL</tabstop>
|
||||
<tabstop>errorBackgroundAlways</tabstop>
|
||||
<tabstop>alternatingBarsNever</tabstop>
|
||||
<tabstop>alternatingBarsURL</tabstop>
|
||||
<tabstop>alternatingBarsAlways</tabstop>
|
||||
<tabstop>alternatingBackgroundNever</tabstop>
|
||||
<tabstop>alternatingBackgroundURL</tabstop>
|
||||
<tabstop>alternatingBackgroundAlways</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="errorBars"/>
|
||||
<buttongroup name="errorBackground"/>
|
||||
<buttongroup name="alternatingBars"/>
|
||||
<buttongroup name="semanticHints"/>
|
||||
<buttongroup name="alternatingBackground"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
@@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditProfileKeyboardPage</class>
|
||||
<widget class="QWidget" name="EditProfileKeyboardPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="note">
|
||||
<property name="text">
|
||||
<string comment="@info">Key bindings control how combinations of keystrokes in the terminal window are converted into the stream of characters that is then sent to the current terminal program. For more information on how to customize the key bindings check the Konsole Handbook.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="keyBindingsGroup" native="true">
|
||||
<layout class="QGridLayout" rowstretch="0,1">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="QListView" name="keyBindingList">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="newKeyBindingsButton">
|
||||
<property name="toolTip">
|
||||
<string>Create a new key bindings scheme based upon the selected bindings</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="@action:button Create an alternate key binding">New...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="editKeyBindingsButton">
|
||||
<property name="toolTip">
|
||||
<string>Edit the selected key bindings scheme</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Edit...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeKeyBindingsButton">
|
||||
<property name="toolTip">
|
||||
<string>Delete the selected key bindings scheme</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="resetKeyBindingsButton">
|
||||
<property name="toolTip">
|
||||
<string>Reset the selected key bindings scheme to its default values</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Defaults</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>keyBindingList</tabstop>
|
||||
<tabstop>newKeyBindingsButton</tabstop>
|
||||
<tabstop>editKeyBindingsButton</tabstop>
|
||||
<tabstop>removeKeyBindingsButton</tabstop>
|
||||
<tabstop>resetKeyBindingsButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,497 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditProfileMousePage</class>
|
||||
<widget class="QWidget" name="EditProfileMousePage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>993</width>
|
||||
<height>632</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="documentMode">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Text interaction</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="toolTip">
|
||||
<string comment="@info:tooltip">Characters which are considered part of a word when double-clicking to select whole words in the terminal.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Word characters:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>wordCharacterEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="wordCharacterEdit">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="@info:tooltip">Characters which are considered part of a word when double-clicking to select whole words in the terminal.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Triple-click selects:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QRadioButton" name="tripleClickSelectsTheWholeLine">
|
||||
<property name="text">
|
||||
<string>&The whole line</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">tripleClickMode</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QRadioButton" name="tripleClickSelectsFromMousePosition">
|
||||
<property name="text">
|
||||
<string>From mouse position to the end of &line</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">tripleClickMode</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Middle-click pastes:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QRadioButton" name="pasteFromClipboardButton">
|
||||
<property name="text">
|
||||
<string>From clipboard</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">pasteFrom</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QRadioButton" name="pasteFromX11SelectionButton">
|
||||
<property name="text">
|
||||
<string>From selection</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">pasteFrom</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Copy options:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QCheckBox" name="copyTextToClipboardButton">
|
||||
<property name="toolTip">
|
||||
<string>Automatically copy selected text into clipboard</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy on select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QCheckBox" name="copyTextAsHTMLButton">
|
||||
<property name="toolTip">
|
||||
<string>Copy text as HTML (including formatting, font faces, colors... etc)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy text as HTML</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="trimLeadingSpacesButton">
|
||||
<property name="toolTip">
|
||||
<string>Trim leading spaces in selected text, useful in some instances</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trim leading spaces</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="trimTrailingSpacesButton">
|
||||
<property name="toolTip">
|
||||
<string>Trim trailing spaces in selected text, useful in some instances</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trim trailing spaces</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string comment="Items that do not fit in other categories">Miscellaneous</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="underlineURILayout">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="underlineLinksButton">
|
||||
<property name="toolTip">
|
||||
<string>Text recognized as a link or an email address will be underlined when hovered by the mouse pointer.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Underline links</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="underlineFilesButton">
|
||||
<property name="toolTip">
|
||||
<string>Text recognized as a file will be underlined when hovered by the mouse pointer.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Underline files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="textEditorCommandLabel">
|
||||
<property name="toolTip">
|
||||
<string comment="@info:tooltip">Text editor to use when opening text file URLs at a given line/column.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Text Editor Command: </string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>textEditorCombo</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="textEditorCombo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="@info:tooltip">Text editor to use when opening text file URLs at a given line/column.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="textEditorCustomBtn">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Edit...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="openLinksByDirectClickButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Text recognized as a file, link or an email address can be opened by direct mouse click.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open files/links by direct click</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="allowLinkEscapeSequenceButton">
|
||||
<property name="text">
|
||||
<string>Allow escape sequences for links</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="allowLinkEscapeSequenceButtonWarning">
|
||||
<property name="text">
|
||||
<string><b>WARNING</b>: This has security implications as it allows malicious URLs to be shown as another URL or hidden.<br>Make sure you understand the implications before turning this on.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::TextFormat::RichText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="indent">
|
||||
<number>30</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Allowed link formats: </string>
|
||||
</property>
|
||||
<property name="indent">
|
||||
<number>30</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="linkEscapeSequenceTexts">
|
||||
<property name="toolTip">
|
||||
<string>The formats of possible links, like http://, https:// and file://</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ctrlRequiredForDragButton">
|
||||
<property name="toolTip">
|
||||
<string>Selected text will require control key plus click to drag.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Require Ctrl key for drag && drop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableAlternateScrollingButton">
|
||||
<property name="toolTip">
|
||||
<string>Mouse scroll wheel will emulate up/down key presses in programs that use the Alternate Screen buffer (e.g. less)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Alternate Screen buffer scrolling</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="dropUrlsAsText">
|
||||
<property name="toolTip">
|
||||
<string>Always paste dropped files and URLs as text without offering move, copy and link actions.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disable drag && drop menu for files && URLs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableMouseWheelZoomButton">
|
||||
<property name="toolTip">
|
||||
<string>Pressing Ctrl+scrollwheel will increase/decrease the text size.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Allow Ctrl+scrollwheel to zoom text size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="allowColorFilters">
|
||||
<property name="toolTip">
|
||||
<string>When positioning the mouse over a hexadecimal color it will be displayed in a frame next to the mouse pointer</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Preview Colors on hover</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="allowMouseTrackingButton">
|
||||
<property name="toolTip">
|
||||
<string>Some terminal applications have mouse support, this allows them to get it by default. It can be toggled on/off while running as well.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Allow terminal applications to handle clicks and drags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>tabWidget</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>allowLinkEscapeSequenceButton</sender>
|
||||
<signal>clicked(bool)</signal>
|
||||
<receiver>linkEscapeSequenceTexts</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>193</x>
|
||||
<y>109</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>218</x>
|
||||
<y>151</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="tripleClickMode"/>
|
||||
<buttongroup name="pasteFrom"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
@@ -0,0 +1,300 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditProfileScrollingPage</class>
|
||||
<widget class="QWidget" name="EditProfileScrollingPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout">
|
||||
<item row="0" column="0" alignment="Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTop">
|
||||
<widget class="QLabel" name="historySizeLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scrollback:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Konsole::HistorySizeWidget" name="historySizeWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scroll Page Up/Down:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QRadioButton" name="scrollHalfPage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Scroll the page the half height of window</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Half screen heigh&t</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">scrollAmount</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QRadioButton" name="scrollFullPage">
|
||||
<property name="toolTip">
|
||||
<string>Scroll the page the full height of window</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>F&ull screen height</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">scrollAmount</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0" alignment="Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignVCenter">
|
||||
<widget class="QLabel" name="labelSize">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scrollbar position:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QRadioButton" name="scrollBarRightButton">
|
||||
<property name="toolTip">
|
||||
<string>Show the scroll bar on the right side of the terminal window</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="@option:radio Show scrollbar on the right side">Ri&ght side</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">scrollBarPosition</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QRadioButton" name="scrollBarLeftButton">
|
||||
<property name="toolTip">
|
||||
<string>Show the scroll bar on the left side of the terminal window</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="@option:radio Show scrollbar on the left side">&Left side</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">scrollBarPosition</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QRadioButton" name="scrollBarHiddenButton">
|
||||
<property name="text">
|
||||
<string comment="@option:radio Hide the scroll bar">Hidden</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">scrollBarPosition</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="9" column="0" alignment="Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignVCenter">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Highlighting:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QCheckBox" name="highlightScrolledLinesButton">
|
||||
<property name="text">
|
||||
<string>Highlight the lines coming into view</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" alignment="Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignVCenter">
|
||||
<widget class="QLabel" name="labelReflowLines">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reflow Lines:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="reflowLinesButton">
|
||||
<property name="text">
|
||||
<string>Reflow lines when terminal resizes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="labelMarkerColor">
|
||||
<property name="text">
|
||||
<string>Color of scrollbar markers:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="KColorButton" name="markerColorButton">
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="labelMarkerSize">
|
||||
<property name="text">
|
||||
<string>Size of each marker (as a percentage of scrollbar length):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QDoubleSpinBox" name="markerSizeWidget">
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0.1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> %</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Konsole::HistorySizeWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>widgets/HistorySizeWidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="scrollBarPosition"/>
|
||||
<buttongroup name="scrollAmount"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
@@ -0,0 +1,153 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditProfileTabsPage</class>
|
||||
<widget class="QWidget" name="EditProfileTabsPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" stretch="0,1">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Tab Titles</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="Konsole::RenameTabWidget" name="renameTabWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="tabMonitoringGroup">
|
||||
<property name="title">
|
||||
<string>Tab Monitoring</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<item row="0" column="0" alignment="Qt::AlignRight">
|
||||
<widget class="QLabel" name="silenceSecondsLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Threshold for continuous silence:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>silenceSecondsSpinner</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="KPluralHandlingSpinBox" name="silenceSecondsSpinner">
|
||||
<property name="toolTip">
|
||||
<string>The threshold for continuous silence to be detected by Konsole</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>3600</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Konsole::RenameTabWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>widgets/RenameTabWidget.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>KPluralHandlingSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>KPluralHandlingSpinBox</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
|
||||
SPDX-FileCopyrightText: 2012 Jekyll Wu <adaptee@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "widgets/HistorySizeWidget.h"
|
||||
|
||||
// Qt
|
||||
#include <QAbstractButton>
|
||||
#include <QButtonGroup>
|
||||
#include <QWhatsThis>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
// Konsole
|
||||
#include "ui_HistorySizeWidget.h"
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
HistorySizeWidget::HistorySizeWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, _ui(nullptr)
|
||||
{
|
||||
_ui = new Ui::HistorySizeWidget();
|
||||
_ui->setupUi(this);
|
||||
|
||||
// focus and select the spinner automatically when appropriate
|
||||
_ui->fixedSizeHistoryButton->setFocusProxy(_ui->historyLineSpinner);
|
||||
connect(_ui->fixedSizeHistoryButton, &QRadioButton::clicked, _ui->historyLineSpinner, &KPluralHandlingSpinBox::selectAll);
|
||||
|
||||
auto modeGroup = new QButtonGroup(this);
|
||||
modeGroup->addButton(_ui->noHistoryButton);
|
||||
modeGroup->addButton(_ui->fixedSizeHistoryButton);
|
||||
modeGroup->addButton(_ui->unlimitedHistoryButton);
|
||||
connect(modeGroup, static_cast<void (QButtonGroup::*)(QAbstractButton *)>(&QButtonGroup::buttonClicked), this, &Konsole::HistorySizeWidget::buttonClicked);
|
||||
|
||||
_ui->historyLineSpinner->setSuffix(ki18ncp("@label:textbox Unit of scrollback", " line", " lines"));
|
||||
setLineCount(HistorySizeWidget::DefaultLineCount);
|
||||
|
||||
connect(_ui->historyLineSpinner,
|
||||
static_cast<void (KPluralHandlingSpinBox::*)(int)>(&KPluralHandlingSpinBox::valueChanged),
|
||||
this,
|
||||
&Konsole::HistorySizeWidget::historySizeChanged);
|
||||
|
||||
auto warningButtonSizePolicy = _ui->fixedSizeHistoryWarningButton->sizePolicy();
|
||||
warningButtonSizePolicy.setRetainSizeWhenHidden(true);
|
||||
|
||||
_ui->fixedSizeHistoryWarningButton->setSizePolicy(warningButtonSizePolicy);
|
||||
_ui->fixedSizeHistoryWarningButton->hide();
|
||||
connect(_ui->fixedSizeHistoryButton, &QAbstractButton::toggled, _ui->historyLineSpinner, &QWidget::setEnabled);
|
||||
connect(_ui->fixedSizeHistoryButton, &QAbstractButton::toggled, _ui->fixedSizeHistoryWarningButton, &QWidget::setVisible);
|
||||
connect(_ui->fixedSizeHistoryWarningButton, &QToolButton::clicked, this, [this](bool) {
|
||||
const QString message = i18nc("@info:whatsthis",
|
||||
"When using this option, the scrollback data will be saved to RAM. If you choose a huge value, your system may run out "
|
||||
"of free RAM and cause serious issues with your system.");
|
||||
const QPoint pos = QPoint(_ui->fixedSizeHistoryWrapper->width() / 2, _ui->fixedSizeHistoryWrapper->height());
|
||||
QWhatsThis::showText(_ui->fixedSizeHistoryWrapper->mapToGlobal(pos), message, _ui->fixedSizeHistoryWrapper);
|
||||
});
|
||||
|
||||
_ui->unlimitedHistoryWarningButton->setSizePolicy(warningButtonSizePolicy);
|
||||
_ui->unlimitedHistoryWarningButton->hide();
|
||||
connect(_ui->unlimitedHistoryButton, &QAbstractButton::toggled, _ui->unlimitedHistoryWarningButton, &QWidget::setVisible);
|
||||
connect(_ui->unlimitedHistoryWarningButton, &QToolButton::clicked, this, [this](bool) {
|
||||
const auto message =
|
||||
xi18nc("@info:tooltip",
|
||||
"When using this option, the scrollback data will be written unencrypted to temporary files. Those temporary files will be "
|
||||
"deleted automatically when Konsole is closed in a normal manner.<nl/>Use <emphasis>Settings → Configure Konsole → Temporary "
|
||||
"Files</emphasis> to select the location of the temporary files.");
|
||||
const QPoint pos = QPoint(_ui->unlimitedHistoryWrapper->width() / 2, _ui->unlimitedHistoryWrapper->height());
|
||||
QWhatsThis::showText(_ui->unlimitedHistoryWrapper->mapToGlobal(pos), message, _ui->unlimitedHistoryWrapper);
|
||||
});
|
||||
|
||||
// Make radio buttons height equal
|
||||
// fixedSizeHistoryWrapper contains radio + spinbox + toolbutton, so it
|
||||
// has height always equal to or larger than single radio button, and
|
||||
// radio + toolbutton
|
||||
const int radioButtonHeight = _ui->fixedSizeHistoryWrapper->sizeHint().height();
|
||||
_ui->noHistoryButton->setMinimumHeight(radioButtonHeight);
|
||||
_ui->unlimitedHistoryButton->setMinimumHeight(radioButtonHeight);
|
||||
}
|
||||
|
||||
HistorySizeWidget::~HistorySizeWidget()
|
||||
{
|
||||
delete _ui;
|
||||
}
|
||||
|
||||
void HistorySizeWidget::buttonClicked(QAbstractButton *)
|
||||
{
|
||||
Enum::HistoryModeEnum selectedMode = mode();
|
||||
Q_EMIT historyModeChanged(selectedMode);
|
||||
}
|
||||
|
||||
void HistorySizeWidget::setMode(Enum::HistoryModeEnum aMode)
|
||||
{
|
||||
if (aMode == Enum::NoHistory) {
|
||||
_ui->noHistoryButton->setChecked(true);
|
||||
} else if (aMode == Enum::FixedSizeHistory) {
|
||||
_ui->fixedSizeHistoryButton->setChecked(true);
|
||||
} else if (aMode == Enum::UnlimitedHistory) {
|
||||
_ui->unlimitedHistoryButton->setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
Enum::HistoryModeEnum HistorySizeWidget::mode() const
|
||||
{
|
||||
if (_ui->noHistoryButton->isChecked()) {
|
||||
return Enum::NoHistory;
|
||||
} else if (_ui->fixedSizeHistoryButton->isChecked()) {
|
||||
return Enum::FixedSizeHistory;
|
||||
} else if (_ui->unlimitedHistoryButton->isChecked()) {
|
||||
return Enum::UnlimitedHistory;
|
||||
}
|
||||
|
||||
Q_ASSERT(false);
|
||||
return Enum::NoHistory;
|
||||
}
|
||||
|
||||
void HistorySizeWidget::setLineCount(int lines)
|
||||
{
|
||||
_ui->historyLineSpinner->setValue(lines);
|
||||
_ui->historyLineSpinner->setSingleStep(lines / 10);
|
||||
}
|
||||
|
||||
int HistorySizeWidget::lineCount() const
|
||||
{
|
||||
return _ui->historyLineSpinner->value();
|
||||
}
|
||||
|
||||
int HistorySizeWidget::preferredLabelHeight()
|
||||
{
|
||||
Q_ASSERT(_ui);
|
||||
Q_ASSERT(_ui->noHistoryButton);
|
||||
|
||||
return _ui->fixedSizeHistoryWrapper->sizeHint().height();
|
||||
}
|
||||
|
||||
#include "moc_HistorySizeWidget.cpp"
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
|
||||
SPDX-FileCopyrightText: 2012 Jekyll Wu <adaptee@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HISTORYSIZEWIDGET_H
|
||||
#define HISTORYSIZEWIDGET_H
|
||||
|
||||
// Qt
|
||||
#include <QWidget>
|
||||
|
||||
// Konsole
|
||||
#include "Enumeration.h"
|
||||
|
||||
class QAbstractButton;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class HistorySizeWidget;
|
||||
}
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
/**
|
||||
* A widget for controlling history related options
|
||||
*/
|
||||
class HistorySizeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit HistorySizeWidget(QWidget *parent);
|
||||
~HistorySizeWidget() override;
|
||||
|
||||
/** Specifies the history mode. */
|
||||
void setMode(Enum::HistoryModeEnum aMode);
|
||||
|
||||
/** Returns the history mode chosen by the user. */
|
||||
Enum::HistoryModeEnum mode() const;
|
||||
|
||||
/** Sets the number of lines for the fixed size history mode. */
|
||||
void setLineCount(int lines);
|
||||
|
||||
/**
|
||||
* Returns the number of lines of history to remember.
|
||||
* This is only valid when mode() == FixedSizeHistory,
|
||||
* and returns 0 otherwise.
|
||||
*/
|
||||
int lineCount() const;
|
||||
|
||||
/**
|
||||
* Return height which should be set on the widget's label
|
||||
* to align with the first widget's item
|
||||
*/
|
||||
int preferredLabelHeight();
|
||||
|
||||
Q_SIGNALS:
|
||||
/** Emitted when the history mode is changed. */
|
||||
void historyModeChanged(Enum::HistoryModeEnum);
|
||||
|
||||
/** Emitted when the history size is changed. */
|
||||
void historySizeChanged(int);
|
||||
|
||||
private Q_SLOTS:
|
||||
void buttonClicked(QAbstractButton *);
|
||||
|
||||
private:
|
||||
Ui::HistorySizeWidget *_ui;
|
||||
|
||||
// 1000 lines was the default in the KDE3 series
|
||||
static const int DefaultLineCount = 1000;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // HISTORYSIZEWIDGET_H
|
||||
@@ -0,0 +1,192 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>HistorySizeWidget</class>
|
||||
<widget class="QWidget" name="HistorySizeWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>320</width>
|
||||
<height>84</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="fixedSizeHistoryWrapper" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="fixedSizeHistoryButton">
|
||||
<property name="toolTip">
|
||||
<string>Limit the remembered output to a fixed number of lines</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fi&xed size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="KPluralHandlingSpinBox" name="historyLineSpinner">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Number of lines of output to remember</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="fixedSizeHistoryWarningButton">
|
||||
<property name="icon">
|
||||
<iconset theme="emblem-warning"/>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="unlimitedHistoryWrapper" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item alignment="Qt::AlignmentFlag::AlignVCenter">
|
||||
<widget class="QRadioButton" name="unlimitedHistoryButton">
|
||||
<property name="toolTip">
|
||||
<string>Remember all output produced by the terminal</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="Save all lines to the scrollback history">&Unlimited</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignmentFlag::AlignVCenter">
|
||||
<widget class="QToolButton" name="unlimitedHistoryWarningButton">
|
||||
<property name="icon">
|
||||
<iconset theme="emblem-warning"/>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="noHistoryButton">
|
||||
<property name="toolTip">
|
||||
<string>Do not remember previous output</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="Do not save any lines to the scrollback history">&None</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KPluralHandlingSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>kpluralhandlingspinbox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2006-2008 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "widgets/IncrementalSearchBar.h"
|
||||
|
||||
// Qt
|
||||
#include <QApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QTimer>
|
||||
#include <QToolButton>
|
||||
|
||||
// KDE
|
||||
#include "KonsoleSettings.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KStatefulBrush>
|
||||
#include <QLineEdit>
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
IncrementalSearchBar::IncrementalSearchBar(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, _searchEdit(nullptr)
|
||||
, _caseSensitive(nullptr)
|
||||
, _regExpression(nullptr)
|
||||
, _highlightMatches(nullptr)
|
||||
, _reverseSearch(nullptr)
|
||||
, _noWrap(nullptr)
|
||||
, _findNextButton(nullptr)
|
||||
, _findPreviousButton(nullptr)
|
||||
, _searchFromButton(nullptr)
|
||||
, _searchTimer(nullptr)
|
||||
{
|
||||
setPalette(qApp->palette());
|
||||
setAutoFillBackground(true);
|
||||
|
||||
// SubWindow flag limits tab focus switching to this widget
|
||||
setWindowFlags(windowFlags() | Qt::SubWindow);
|
||||
|
||||
_searchEdit = new QLineEdit(this);
|
||||
_searchEdit->setClearButtonEnabled(true);
|
||||
_searchEdit->installEventFilter(this);
|
||||
_searchEdit->setPlaceholderText(i18nc("@label:textbox", "Find..."));
|
||||
_searchEdit->setObjectName(QStringLiteral("search-edit"));
|
||||
_searchEdit->setToolTip(i18nc("@info:tooltip", "Enter the text to search for here"));
|
||||
_searchEdit->setCursor(Qt::IBeamCursor);
|
||||
_searchEdit->setStyleSheet(QString());
|
||||
_searchEdit->setFont(QApplication::font());
|
||||
// When the widget focus is set, focus input box instead
|
||||
setFocusProxy(_searchEdit);
|
||||
|
||||
setCursor(Qt::ArrowCursor);
|
||||
// text box may be a minimum of 6 characters wide and a maximum of 10 characters wide
|
||||
// (since the maxWidth metric is used here, more characters probably will fit in than 6
|
||||
// and 10)
|
||||
QFontMetrics metrics(_searchEdit->font());
|
||||
int maxWidth = metrics.maxWidth();
|
||||
_searchEdit->setMinimumWidth(maxWidth * 6);
|
||||
_searchEdit->setMaximumWidth(maxWidth * 10);
|
||||
|
||||
_searchTimer = new QTimer(this);
|
||||
_searchTimer->setInterval(250);
|
||||
_searchTimer->setSingleShot(true);
|
||||
connect(_searchTimer, &QTimer::timeout, this, &Konsole::IncrementalSearchBar::notifySearchChanged);
|
||||
connect(_searchEdit, &QLineEdit::textChanged, _searchTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
|
||||
|
||||
_findNextButton = new QToolButton(this);
|
||||
_findNextButton->setObjectName(QStringLiteral("find-next-button"));
|
||||
_findNextButton->setText(i18nc("@action:button Go to the next phrase", "Next"));
|
||||
_findNextButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
_findNextButton->setAutoRaise(true);
|
||||
_findNextButton->setToolTip(i18nc("@info:tooltip", "Find the next match for the current search phrase"));
|
||||
_findNextButton->installEventFilter(this);
|
||||
connect(_findNextButton, &QToolButton::clicked, this, &Konsole::IncrementalSearchBar::findNextClicked);
|
||||
|
||||
_findPreviousButton = new QToolButton(this);
|
||||
_findPreviousButton->setAutoRaise(true);
|
||||
_findPreviousButton->setObjectName(QStringLiteral("find-previous-button"));
|
||||
_findPreviousButton->setText(i18nc("@action:button Go to the previous phrase", "Previous"));
|
||||
_findPreviousButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
_findPreviousButton->setToolTip(i18nc("@info:tooltip", "Find the previous match for the current search phrase"));
|
||||
_findPreviousButton->installEventFilter(this);
|
||||
connect(_findPreviousButton, &QToolButton::clicked, this, &Konsole::IncrementalSearchBar::findPreviousClicked);
|
||||
|
||||
_searchFromButton = new QToolButton(this);
|
||||
_searchFromButton->setAutoRaise(true);
|
||||
_searchFromButton->setObjectName(QStringLiteral("search-from-button"));
|
||||
_searchFromButton->installEventFilter(this);
|
||||
connect(_searchFromButton, &QToolButton::clicked, this, &Konsole::IncrementalSearchBar::searchFromClicked);
|
||||
|
||||
auto optionsButton = new QToolButton(this);
|
||||
optionsButton->setObjectName(QStringLiteral("find-options-button"));
|
||||
optionsButton->setCheckable(false);
|
||||
optionsButton->setPopupMode(QToolButton::InstantPopup);
|
||||
optionsButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
optionsButton->setToolTip(i18nc("@info:tooltip", "Display the options menu"));
|
||||
optionsButton->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
|
||||
optionsButton->setAutoRaise(true);
|
||||
optionsButton->installEventFilter(this);
|
||||
|
||||
auto closeButton = new QToolButton(this);
|
||||
closeButton->setObjectName(QStringLiteral("close-button"));
|
||||
closeButton->setToolTip(i18nc("@info:tooltip", "Close the search bar"));
|
||||
closeButton->setAutoRaise(true);
|
||||
closeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close")));
|
||||
closeButton->installEventFilter(this);
|
||||
connect(closeButton, &QToolButton::clicked, this, &Konsole::IncrementalSearchBar::closeClicked);
|
||||
|
||||
// Fill the options menu
|
||||
auto optionsMenu = new QMenu(this);
|
||||
optionsButton->setMenu(optionsMenu);
|
||||
|
||||
_caseSensitive = optionsMenu->addAction(i18nc("@item:inmenu", "Case sensitive"));
|
||||
_caseSensitive->setCheckable(true);
|
||||
_caseSensitive->setToolTip(i18nc("@info:tooltip", "Sets whether the search is case sensitive"));
|
||||
connect(_caseSensitive, &QAction::toggled, this, &Konsole::IncrementalSearchBar::matchCaseToggled);
|
||||
|
||||
_regExpression = optionsMenu->addAction(i18nc("@item:inmenu", "Match regular expression"));
|
||||
_regExpression->setCheckable(true);
|
||||
connect(_regExpression, &QAction::toggled, this, &Konsole::IncrementalSearchBar::matchRegExpToggled);
|
||||
|
||||
_highlightMatches = optionsMenu->addAction(i18nc("@item:inmenu", "Highlight all matches"));
|
||||
_highlightMatches->setCheckable(true);
|
||||
_highlightMatches->setToolTip(i18nc("@info:tooltip", "Sets whether matching text should be highlighted"));
|
||||
connect(_highlightMatches, &QAction::toggled, this, &Konsole::IncrementalSearchBar::highlightMatchesToggled);
|
||||
|
||||
_reverseSearch = optionsMenu->addAction(i18nc("@item:inmenu", "Search backwards"));
|
||||
_reverseSearch->setCheckable(true);
|
||||
_reverseSearch->setToolTip(i18nc("@info:tooltip", "Sets whether search should start from the bottom"));
|
||||
connect(_reverseSearch, &QAction::toggled, this, &Konsole::IncrementalSearchBar::updateButtonsAccordingToReverseSearchSetting);
|
||||
connect(_reverseSearch, &QAction::toggled, this, &Konsole::IncrementalSearchBar::reverseSearchToggled);
|
||||
updateButtonsAccordingToReverseSearchSetting();
|
||||
|
||||
_noWrap = optionsMenu->addAction(i18nc("@item:inmenu", "No wrap"));
|
||||
_noWrap->setCheckable(true);
|
||||
_noWrap->setToolTip(i18nc("@info:tooltip", "Sets whether search should stop instead of wrapping"));
|
||||
connect(_noWrap, &QAction::toggled, this, &Konsole::IncrementalSearchBar::noWrapToggled);
|
||||
|
||||
setOptions();
|
||||
|
||||
auto barLayout = new QHBoxLayout(this);
|
||||
barLayout->addWidget(_searchEdit);
|
||||
barLayout->addWidget(_findNextButton);
|
||||
barLayout->addWidget(_findPreviousButton);
|
||||
barLayout->addWidget(_searchFromButton);
|
||||
barLayout->addWidget(optionsButton);
|
||||
barLayout->addWidget(closeButton);
|
||||
barLayout->setContentsMargins(4, 4, 4, 4);
|
||||
barLayout->setSpacing(0);
|
||||
|
||||
setLayout(barLayout);
|
||||
adjustSize();
|
||||
clearLineEdit();
|
||||
}
|
||||
|
||||
void IncrementalSearchBar::notifySearchChanged()
|
||||
{
|
||||
Q_EMIT searchChanged(searchText());
|
||||
}
|
||||
|
||||
void IncrementalSearchBar::updateButtonsAccordingToReverseSearchSetting()
|
||||
{
|
||||
Q_ASSERT(_reverseSearch);
|
||||
if (_reverseSearch->isChecked()) {
|
||||
_searchFromButton->setToolTip(i18nc("@info:tooltip", "Search for the current search phrase from the bottom"));
|
||||
_searchFromButton->setIcon(QIcon::fromTheme(QStringLiteral("go-bottom")));
|
||||
_findNextButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up")));
|
||||
_findPreviousButton->setIcon(QIcon::fromTheme(QStringLiteral("go-down")));
|
||||
} else {
|
||||
_searchFromButton->setToolTip(i18nc("@info:tooltip", "Search for the current search phrase from the top"));
|
||||
_searchFromButton->setIcon(QIcon::fromTheme(QStringLiteral("go-top")));
|
||||
_findNextButton->setIcon(QIcon::fromTheme(QStringLiteral("go-down")));
|
||||
_findPreviousButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up")));
|
||||
}
|
||||
}
|
||||
|
||||
QString IncrementalSearchBar::searchText()
|
||||
{
|
||||
return _searchEdit->text();
|
||||
}
|
||||
|
||||
void IncrementalSearchBar::setSearchText(const QString &text)
|
||||
{
|
||||
if (text != searchText()) {
|
||||
_searchEdit->setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
bool IncrementalSearchBar::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
|
||||
auto *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
QToolButton *toolButton = nullptr;
|
||||
|
||||
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
|
||||
if (watched == _searchEdit && event->type() == QEvent::KeyPress) {
|
||||
if (keyEvent->modifiers() == Qt::NoModifier) {
|
||||
_findNextButton->click();
|
||||
return true;
|
||||
}
|
||||
if (keyEvent->modifiers() == Qt::ShiftModifier) {
|
||||
_findPreviousButton->click();
|
||||
return true;
|
||||
}
|
||||
if (keyEvent->modifiers() == Qt::ControlModifier) {
|
||||
_searchFromButton->click();
|
||||
return true;
|
||||
}
|
||||
} else if ((toolButton = qobject_cast<QToolButton *>(watched)) != nullptr) {
|
||||
if (event->type() == QEvent::KeyPress && !toolButton->isDown()) {
|
||||
toolButton->setDown(true);
|
||||
toolButton->pressed();
|
||||
} else if (toolButton->isDown()) {
|
||||
toolButton->setDown(keyEvent->isAutoRepeat());
|
||||
toolButton->released();
|
||||
toolButton->click();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void IncrementalSearchBar::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
static auto movementKeysToPassAlong = QSet<int>{Qt::Key_PageUp, Qt::Key_PageDown, Qt::Key_Up, Qt::Key_Down};
|
||||
|
||||
if (movementKeysToPassAlong.contains(event->key()) && (event->modifiers() == Qt::ShiftModifier)) {
|
||||
Q_EMIT unhandledMovementKeyPressed(event);
|
||||
}
|
||||
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
Q_EMIT closeClicked();
|
||||
}
|
||||
}
|
||||
|
||||
void IncrementalSearchBar::setVisible(bool visible)
|
||||
{
|
||||
QWidget::setVisible(visible);
|
||||
|
||||
if (visible) {
|
||||
focusLineEdit();
|
||||
}
|
||||
}
|
||||
|
||||
void IncrementalSearchBar::setFoundMatch(bool match)
|
||||
{
|
||||
if (_searchEdit->text().isEmpty()) {
|
||||
clearLineEdit();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto backgroundBrush = KStatefulBrush(KColorScheme::View, match ? KColorScheme::PositiveBackground : KColorScheme::NegativeBackground);
|
||||
|
||||
const auto matchStyleSheet = QStringLiteral("QLineEdit{ background-color:%1 }").arg(backgroundBrush.brush(_searchEdit->palette()).color().name());
|
||||
|
||||
_searchEdit->setStyleSheet(matchStyleSheet);
|
||||
}
|
||||
|
||||
void IncrementalSearchBar::clearLineEdit()
|
||||
{
|
||||
_searchEdit->setStyleSheet(QString());
|
||||
}
|
||||
|
||||
void IncrementalSearchBar::focusLineEdit()
|
||||
{
|
||||
_searchEdit->setFocus(Qt::ActiveWindowFocusReason);
|
||||
_searchEdit->selectAll();
|
||||
}
|
||||
|
||||
const QBitArray IncrementalSearchBar::optionsChecked()
|
||||
{
|
||||
QBitArray options(5, false);
|
||||
options.setBit(MatchCase, _caseSensitive->isChecked());
|
||||
options.setBit(RegExp, _regExpression->isChecked());
|
||||
options.setBit(HighlightMatches, _highlightMatches->isChecked());
|
||||
options.setBit(ReverseSearch, _reverseSearch->isChecked());
|
||||
options.setBit(NoWrap, _noWrap->isChecked());
|
||||
return options;
|
||||
}
|
||||
|
||||
void IncrementalSearchBar::setOptions()
|
||||
{
|
||||
_caseSensitive->setChecked(KonsoleSettings::searchCaseSensitive());
|
||||
_regExpression->setChecked(KonsoleSettings::searchRegExpression());
|
||||
_highlightMatches->setChecked(KonsoleSettings::searchHighlightMatches());
|
||||
_reverseSearch->setChecked(KonsoleSettings::searchReverseSearch());
|
||||
_noWrap->setChecked(KonsoleSettings::searchNoWrap());
|
||||
}
|
||||
|
||||
#include "moc_IncrementalSearchBar.cpp"
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2006-2008 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef INCREMENTALSEARCHBAR_H
|
||||
#define INCREMENTALSEARCHBAR_H
|
||||
|
||||
// Qt
|
||||
#include <QBitArray>
|
||||
#include <QWidget>
|
||||
|
||||
#include "konsoleprivate_export.h"
|
||||
|
||||
class QAction;
|
||||
class QTimer;
|
||||
class QLineEdit;
|
||||
class QToolButton;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
/**
|
||||
* A widget which allows users to search incrementally through a document for a
|
||||
* a text string or regular expression.
|
||||
*
|
||||
* The widget consists of a text box into which the user can enter their search text and
|
||||
* buttons to trigger a search for the next and previous matches for the search text.
|
||||
*
|
||||
* When the search text is changed, the searchChanged() signal is emitted. A search through
|
||||
* the document for the new text should begin immediately and the active view of the document
|
||||
* should jump to display any matches if found. setFoundMatch() should be called whenever the
|
||||
* search text changes to indicate whether a match for the text was found in the document.
|
||||
*
|
||||
* findNextClicked() and findPreviousClicked() signals are emitted when the user presses buttons
|
||||
* to find next and previous matches respectively.
|
||||
*
|
||||
* The first indicates whether searches are case sensitive.
|
||||
* The matchCaseToggled() signal is emitted when this is changed.
|
||||
* The second indicates whether the search text should be treated as a plain string or
|
||||
* as a regular expression.
|
||||
* The matchRegExpToggled() signal is emitted when this is changed.
|
||||
*/
|
||||
class KONSOLEPRIVATE_EXPORT IncrementalSearchBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* This enum defines the options that can be checked.
|
||||
*/
|
||||
enum SearchOptions {
|
||||
/** Highlight all matches */
|
||||
HighlightMatches = 0,
|
||||
/** Searches are case-sensitive or not */
|
||||
MatchCase = 1,
|
||||
/** Searches use regular expressions */
|
||||
RegExp = 2,
|
||||
/** Search from the bottom and up **/
|
||||
ReverseSearch = 3,
|
||||
/** Stop search instead of wrapping **/
|
||||
NoWrap = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new incremental search bar with the given parent widget
|
||||
*/
|
||||
explicit IncrementalSearchBar(QWidget *parent = nullptr);
|
||||
|
||||
/* Returns search options that are checked */
|
||||
const QBitArray optionsChecked();
|
||||
|
||||
/**
|
||||
* Sets an indicator for the user as to whether or not a match for the
|
||||
* current search text was found in the document.
|
||||
*
|
||||
* The indicator will not be shown if the search text is empty ( because
|
||||
* the user has not yet entered a query ).
|
||||
*
|
||||
* @param match True if a match was found or false otherwise. If true,
|
||||
* and the search text is non-empty, an indicator that no matches were
|
||||
* found will be shown.
|
||||
*/
|
||||
void setFoundMatch(bool match);
|
||||
|
||||
/** Returns the current search text */
|
||||
QString searchText();
|
||||
|
||||
void setSearchText(const QString &text);
|
||||
|
||||
void focusLineEdit();
|
||||
|
||||
void setOptions();
|
||||
|
||||
// reimplemented
|
||||
void setVisible(bool visible) override;
|
||||
Q_SIGNALS:
|
||||
/** Emitted when the text entered in the search box is altered */
|
||||
void searchChanged(const QString &text);
|
||||
/** Emitted when the user clicks the button to find the next match */
|
||||
void findNextClicked();
|
||||
/** Emitted when the user clicks the button to find the previous match */
|
||||
void findPreviousClicked();
|
||||
/** The search from beginning/end button */
|
||||
void searchFromClicked();
|
||||
/**
|
||||
* Emitted when the user toggles the checkbox to indicate whether
|
||||
* matches for the search text should be highlighted
|
||||
*/
|
||||
void highlightMatchesToggled(bool);
|
||||
/**
|
||||
* Emitted when the user toggles the checkbox to indicate whether
|
||||
* the search direction should be reversed.
|
||||
*/
|
||||
void reverseSearchToggled(bool);
|
||||
/**
|
||||
* Emitted when the user toggles the checkbox to indicate whether
|
||||
* matching for the search text should be case sensitive
|
||||
*/
|
||||
void matchCaseToggled(bool);
|
||||
/**
|
||||
* Emitted when the user toggles the checkbox to indicate whether
|
||||
* the search text should be treated as a plain string or a regular expression
|
||||
*/
|
||||
void matchRegExpToggled(bool);
|
||||
/**
|
||||
* Emitted when the user toggles the checkbox to indicate whether
|
||||
* the search should stop instead of wrapping.
|
||||
*/
|
||||
void noWrapToggled(bool);
|
||||
/** Emitted when the close button is clicked */
|
||||
void closeClicked();
|
||||
/** Emitted when the return button is pressed in the search box */
|
||||
void searchReturnPressed(const QString &text);
|
||||
/** Emitted when shift+return buttons are pressed in the search box */
|
||||
void searchShiftPlusReturnPressed();
|
||||
/** A movement key not handled is forwarded to the terminal display */
|
||||
void unhandledMovementKeyPressed(QKeyEvent *event);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
public Q_SLOTS:
|
||||
void clearLineEdit();
|
||||
|
||||
private Q_SLOTS:
|
||||
void notifySearchChanged();
|
||||
void updateButtonsAccordingToReverseSearchSetting();
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(IncrementalSearchBar)
|
||||
|
||||
QLineEdit *_searchEdit;
|
||||
QAction *_caseSensitive;
|
||||
QAction *_regExpression;
|
||||
QAction *_highlightMatches;
|
||||
QAction *_reverseSearch;
|
||||
QAction *_noWrap;
|
||||
QToolButton *_findNextButton;
|
||||
QToolButton *_findPreviousButton;
|
||||
QToolButton *_searchFromButton;
|
||||
QTimer *_searchTimer;
|
||||
};
|
||||
}
|
||||
#endif // INCREMENTALSEARCHBAR_H
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2020-2020 Gustavo Carneiro <gcarneiroa@hotmail.com>
|
||||
SPDX-FileCopyrightText: 2012-2020 Kurt Hindenburg <kurt.hindenburg@gmail.com>
|
||||
SPDX-FileCopyrightText: 2020-2020 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "KonsolePrintManager.h"
|
||||
|
||||
// Konsole
|
||||
#include "PrintOptions.h"
|
||||
|
||||
// Qt
|
||||
#include <QFont>
|
||||
#include <QPainter>
|
||||
#include <QPoint>
|
||||
#include <QPointer>
|
||||
#include <QPrintDialog>
|
||||
#include <QPrinter>
|
||||
#include <QRect>
|
||||
#include <QWidget>
|
||||
|
||||
// KDE
|
||||
#include <KConfigGroup>
|
||||
#include <KSharedConfig>
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
KonsolePrintManager::KonsolePrintManager(pDrawBackground drawBackground, pDrawContents drawContents, pColorGet colorGet)
|
||||
{
|
||||
_drawBackground = drawBackground;
|
||||
_drawContents = drawContents;
|
||||
_backgroundColor = colorGet;
|
||||
}
|
||||
|
||||
void KonsolePrintManager::printRequest(pPrintContent pContent, QWidget *parent)
|
||||
{
|
||||
if (!pContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPrinter printer;
|
||||
|
||||
QPointer<QPrintDialog> dialog = new QPrintDialog(&printer, parent);
|
||||
auto options = new PrintOptions();
|
||||
|
||||
dialog->setOptionTabs({options});
|
||||
dialog->setWindowTitle(i18n("Print Shell"));
|
||||
// Make MSVC happy by using ultra verbose static_cast :(
|
||||
QObject::connect(dialog, static_cast<void (QPrintDialog::*)()>(&QPrintDialog::accepted), options, &Konsole::PrintOptions::saveSettings);
|
||||
if (dialog->exec() != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(&printer);
|
||||
|
||||
KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("PrintOptions"));
|
||||
|
||||
if (configGroup.readEntry("ScaleOutput", true)) {
|
||||
QRect page_rect = printer.pageLayout().paintRectPixels(printer.resolution());
|
||||
double scale = qMin(page_rect.width() / static_cast<double>(parent->width()), page_rect.height() / static_cast<double>(parent->height()));
|
||||
painter.scale(scale, scale);
|
||||
}
|
||||
|
||||
pContent(painter, configGroup.readEntry("PrinterFriendly", true));
|
||||
}
|
||||
|
||||
void KonsolePrintManager::printContent(QPainter &painter, bool friendly, QPoint columnsLines, pVTFontGet vtFontGet, pVTFontSet vtFontSet)
|
||||
{
|
||||
// Reinitialize the font with the printers paint device so the font
|
||||
// measurement calculations will be done correctly
|
||||
QFont savedFont = vtFontGet();
|
||||
QFont font(savedFont, painter.device());
|
||||
painter.setFont(font);
|
||||
vtFontSet(font);
|
||||
|
||||
QRect rect(0, 0, columnsLines.y(), columnsLines.x());
|
||||
|
||||
if (!friendly) {
|
||||
_drawBackground(painter, rect, _backgroundColor(), true);
|
||||
}
|
||||
_drawContents(painter, rect, friendly);
|
||||
vtFontSet(savedFont);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2020-2020 Gustavo Carneiro <gcarneiroa@hotmail.com>
|
||||
SPDX-FileCopyrightText: 2012-2020 Kurt Hindenburg <kurt.hindenburg@gmail.com>
|
||||
SPDX-FileCopyrightText: 2020-2020 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KONSOLEPRINTMANAGER_H
|
||||
#define KONSOLEPRINTMANAGER_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
class QFont;
|
||||
class QRect;
|
||||
class QColor;
|
||||
class QPoint;
|
||||
class QWidget;
|
||||
class QPainter;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
class KonsolePrintManager
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(QPainter &, bool)> pPrintContent;
|
||||
typedef std::function<QFont()> pVTFontGet;
|
||||
typedef std::function<void(const QFont)> pVTFontSet;
|
||||
typedef std::function<void(QPainter &painter, const QRect &rect, const QColor &backgroundColor, bool useOpacitySetting)> pDrawBackground;
|
||||
typedef std::function<void(QPainter &paint, const QRect &rect, bool friendly)> pDrawContents;
|
||||
typedef std::function<QColor()> pColorGet;
|
||||
|
||||
KonsolePrintManager(pDrawBackground drawBackground, pDrawContents drawContents, pColorGet colorGet);
|
||||
~KonsolePrintManager() = default;
|
||||
|
||||
void printRequest(pPrintContent pContent, QWidget *parent);
|
||||
void printContent(QPainter &painter, bool friendly, QPoint columnsLines, pVTFontGet vtFontGet, pVTFontSet vtFontSet);
|
||||
|
||||
private:
|
||||
pDrawBackground _drawBackground;
|
||||
pDrawContents _drawContents;
|
||||
pColorGet _backgroundColor;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2010 Kurt Hindenburg <kurt.hindenburg@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "widgets/RenameTabWidget.h"
|
||||
|
||||
// Konsole
|
||||
#include "ui_RenameTabWidget.h"
|
||||
|
||||
// KDE
|
||||
#include <KColorCombo>
|
||||
|
||||
// Qt
|
||||
#include <QColor>
|
||||
|
||||
using Konsole::RenameTabWidget;
|
||||
|
||||
RenameTabWidget::RenameTabWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, _ui(nullptr)
|
||||
{
|
||||
_ui = new Ui::RenameTabWidget();
|
||||
_ui->setupUi(this);
|
||||
|
||||
_ui->tabTitleEdit->setClearButtonEnabled(true);
|
||||
_ui->remoteTabTitleEdit->setClearButtonEnabled(true);
|
||||
|
||||
_colorNone = palette().base().color(); // so that item's text is visible in the combo-box
|
||||
_colorNone.setAlpha(0);
|
||||
|
||||
QList<QColor> listColors(_ui->tabColorCombo->colors());
|
||||
listColors.insert(0, _colorNone);
|
||||
_ui->tabColorCombo->setColors(listColors);
|
||||
_ui->tabColorCombo->setItemText(1, i18nc("@label:listbox No color selected", "None"));
|
||||
|
||||
connect(_ui->tabTitleEdit, &QLineEdit::textChanged, this, &Konsole::RenameTabWidget::tabTitleFormatChanged);
|
||||
connect(_ui->remoteTabTitleEdit, &QLineEdit::textChanged, this, &Konsole::RenameTabWidget::remoteTabTitleFormatChanged);
|
||||
connect(_ui->tabColorCombo, &KColorCombo::activated, this, &Konsole::RenameTabWidget::tabColorChanged);
|
||||
|
||||
_ui->tabTitleFormatButton->setContext(Session::LocalTabTitle);
|
||||
connect(_ui->tabTitleFormatButton, &Konsole::TabTitleFormatButton::dynamicElementSelected, this, &Konsole::RenameTabWidget::insertTabTitleText);
|
||||
|
||||
_ui->remoteTabTitleFormatButton->setContext(Session::RemoteTabTitle);
|
||||
connect(_ui->remoteTabTitleFormatButton, &Konsole::TabTitleFormatButton::dynamicElementSelected, this, &Konsole::RenameTabWidget::insertRemoteTabTitleText);
|
||||
}
|
||||
|
||||
RenameTabWidget::~RenameTabWidget()
|
||||
{
|
||||
delete _ui;
|
||||
}
|
||||
|
||||
void RenameTabWidget::focusTabTitleText()
|
||||
{
|
||||
_ui->tabTitleEdit->setFocus();
|
||||
}
|
||||
|
||||
void RenameTabWidget::focusRemoteTabTitleText()
|
||||
{
|
||||
_ui->remoteTabTitleEdit->setFocus();
|
||||
}
|
||||
|
||||
void RenameTabWidget::setTabTitleText(const QString &text)
|
||||
{
|
||||
_ui->tabTitleEdit->setText(text);
|
||||
}
|
||||
|
||||
void RenameTabWidget::setRemoteTabTitleText(const QString &text)
|
||||
{
|
||||
_ui->remoteTabTitleEdit->setText(text);
|
||||
}
|
||||
|
||||
void RenameTabWidget::setColor(const QColor &color)
|
||||
{
|
||||
if (!color.isValid() || color.alpha() == 0) {
|
||||
_ui->tabColorCombo->setColor(_colorNone);
|
||||
} else {
|
||||
_ui->tabColorCombo->setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
QString RenameTabWidget::tabTitleText() const
|
||||
{
|
||||
return _ui->tabTitleEdit->text();
|
||||
}
|
||||
|
||||
QString RenameTabWidget::remoteTabTitleText() const
|
||||
{
|
||||
return _ui->remoteTabTitleEdit->text();
|
||||
}
|
||||
|
||||
QColor RenameTabWidget::color() const
|
||||
{
|
||||
return _ui->tabColorCombo->color();
|
||||
}
|
||||
|
||||
void RenameTabWidget::insertTabTitleText(const QString &text)
|
||||
{
|
||||
_ui->tabTitleEdit->insert(text);
|
||||
focusTabTitleText();
|
||||
}
|
||||
|
||||
void RenameTabWidget::insertRemoteTabTitleText(const QString &text)
|
||||
{
|
||||
_ui->remoteTabTitleEdit->insert(text);
|
||||
focusRemoteTabTitleText();
|
||||
}
|
||||
|
||||
#include "moc_RenameTabWidget.cpp"
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2010 Kurt Hindenburg <kurt.hindenburg@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef RENAMETABWIDGET_H
|
||||
#define RENAMETABWIDGET_H
|
||||
|
||||
// Qt
|
||||
#include <QWidget>
|
||||
|
||||
class QColor;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class RenameTabWidget;
|
||||
}
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
class RenameTabWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RenameTabWidget(QWidget *parent = nullptr);
|
||||
~RenameTabWidget() override;
|
||||
|
||||
QString tabTitleText() const;
|
||||
QString remoteTabTitleText() const;
|
||||
QColor color() const;
|
||||
void setTabTitleText(const QString &);
|
||||
void setRemoteTabTitleText(const QString &);
|
||||
void setColor(const QColor &);
|
||||
|
||||
void focusTabTitleText();
|
||||
void focusRemoteTabTitleText();
|
||||
|
||||
Q_SIGNALS:
|
||||
void tabTitleFormatChanged(const QString &);
|
||||
void remoteTabTitleFormatChanged(const QString &);
|
||||
void tabColorChanged(const QColor &);
|
||||
|
||||
public Q_SLOTS:
|
||||
void insertTabTitleText(const QString &text);
|
||||
void insertRemoteTabTitleText(const QString &text);
|
||||
|
||||
private:
|
||||
Ui::RenameTabWidget *_ui;
|
||||
QColor _colorNone;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,147 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RenameTabWidget</class>
|
||||
<widget class="QWidget" name="RenameTabWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>119</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" columnstretch="0,1,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="remoteTabTitleEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Tab title format used when a remote command (e.g. connection to another computer via SSH) is being executed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="Konsole::TabTitleFormatButton" name="remoteTabTitleFormatButton"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="Konsole::TabTitleFormatButton" name="tabTitleFormatButton"/>
|
||||
</item>
|
||||
<item row="1" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remote tab title format:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>remoteTabTitleEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" alignment="Qt::AlignmentFlag::AlignRight">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Tab title format:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>tabTitleEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="tabTitleEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Normal tab title format</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Tab Co&lor:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>tabColorCombo</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="KColorCombo" name="tabColorCombo">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KColorCombo</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>kcolorcombo.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Konsole::TabTitleFormatButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>widgets/TabTitleFormatButton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>tabTitleEdit</tabstop>
|
||||
<tabstop>tabTitleFormatButton</tabstop>
|
||||
<tabstop>remoteTabTitleEdit</tabstop>
|
||||
<tabstop>remoteTabTitleFormatButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "widgets/TabTitleFormatButton.h"
|
||||
|
||||
// Qt
|
||||
#include <QList>
|
||||
#include <QMenu>
|
||||
|
||||
// KDE
|
||||
#include <KLocalizedString>
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
const TabTitleFormatButton::Element TabTitleFormatButton::_localElements[] = {
|
||||
|
||||
{QStringLiteral("%n"), kli18n("Program Name: %n")},
|
||||
{QStringLiteral("%d"), kli18n("Current Directory (Short): %d")},
|
||||
{QStringLiteral("%D"), kli18n("Current Directory (Long): %D")},
|
||||
{QStringLiteral("%w"), kli18n("Window Title Set by Shell: %w")},
|
||||
{QStringLiteral("%#"), kli18n("Session Number: %#")},
|
||||
{QStringLiteral("%u"), kli18n("User Name: %u")},
|
||||
{QStringLiteral("%h"), kli18n("Local Host: %h")},
|
||||
{QStringLiteral("%B"), kli18n("User's Bourne prompt sigil: %B")}, // ($, or # for superuser)
|
||||
};
|
||||
|
||||
const int TabTitleFormatButton::_localElementCount = sizeof(_localElements) / sizeof(TabTitleFormatButton::Element);
|
||||
|
||||
const TabTitleFormatButton::Element TabTitleFormatButton::_remoteElements[] = {
|
||||
{QStringLiteral("%u"), kli18n("User Name: %u")},
|
||||
{QStringLiteral("%U"), kli18n("User Name@ (if given): %U")},
|
||||
{QStringLiteral("%h"), kli18n("Remote Host (Short): %h")},
|
||||
{QStringLiteral("%H"), kli18n("Remote Host (Long): %H")},
|
||||
{QStringLiteral("%c"), kli18n("Command and arguments: %c")},
|
||||
{QStringLiteral("%w"), kli18n("Window Title Set by Shell: %w")},
|
||||
{QStringLiteral("%#"), kli18n("Session Number: %#")},
|
||||
};
|
||||
const int TabTitleFormatButton::_remoteElementCount = sizeof(_remoteElements) / sizeof(TabTitleFormatButton::Element);
|
||||
|
||||
TabTitleFormatButton::TabTitleFormatButton(QWidget *parent)
|
||||
: QPushButton(parent)
|
||||
, _context(Session::LocalTabTitle)
|
||||
{
|
||||
setText(i18n("Insert"));
|
||||
setMenu(new QMenu());
|
||||
connect(menu(), &QMenu::triggered, this, &Konsole::TabTitleFormatButton::fireElementSelected);
|
||||
}
|
||||
|
||||
TabTitleFormatButton::~TabTitleFormatButton()
|
||||
{
|
||||
menu()->deleteLater();
|
||||
}
|
||||
|
||||
void TabTitleFormatButton::fireElementSelected(QAction *action)
|
||||
{
|
||||
Q_EMIT dynamicElementSelected(action->data().toString());
|
||||
}
|
||||
|
||||
void TabTitleFormatButton::setContext(Session::TabTitleContext titleContext)
|
||||
{
|
||||
_context = titleContext;
|
||||
|
||||
menu()->clear();
|
||||
|
||||
int count = 0;
|
||||
const Element *array = nullptr;
|
||||
|
||||
if (titleContext == Session::LocalTabTitle) {
|
||||
setToolTip(i18nc("@info:tooltip", "Insert title format"));
|
||||
array = _localElements;
|
||||
count = _localElementCount;
|
||||
} else if (titleContext == Session::RemoteTabTitle) {
|
||||
setToolTip(i18nc("@info:tooltip", "Insert remote title format"));
|
||||
array = _remoteElements;
|
||||
count = _remoteElementCount;
|
||||
}
|
||||
|
||||
QList<QAction *> menuActions;
|
||||
menuActions.reserve(count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
auto *action = new QAction(array[i].description.toString(), this);
|
||||
action->setData(array[i].element);
|
||||
menuActions << action;
|
||||
}
|
||||
|
||||
menu()->addActions(menuActions);
|
||||
}
|
||||
|
||||
Session::TabTitleContext TabTitleFormatButton::context() const
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
|
||||
#include "moc_TabTitleFormatButton.cpp"
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef TABTITLEFORMATBUTTON_H
|
||||
#define TABTITLEFORMATBUTTON_H
|
||||
|
||||
// Qt
|
||||
#include <QAction>
|
||||
#include <QPushButton>
|
||||
|
||||
// KDE
|
||||
#include <KLazyLocalizedString>
|
||||
|
||||
// Konsole
|
||||
#include "session/Session.h"
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
class TabTitleFormatButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TabTitleFormatButton(QWidget *parent);
|
||||
~TabTitleFormatButton() override;
|
||||
|
||||
void setContext(Session::TabTitleContext titleContext);
|
||||
Session::TabTitleContext context() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void dynamicElementSelected(const QString &);
|
||||
|
||||
private Q_SLOTS:
|
||||
void fireElementSelected(QAction *);
|
||||
|
||||
private:
|
||||
Session::TabTitleContext _context;
|
||||
|
||||
struct Element {
|
||||
QString element;
|
||||
KLazyLocalizedString description;
|
||||
};
|
||||
static const Element _localElements[];
|
||||
static const int _localElementCount;
|
||||
static const Element _remoteElements[];
|
||||
static const int _remoteElementCount;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TABTITLEFORMATBUTTON_H
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2012 Frederik Gladhorn <gladhorn@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "TerminalDisplayAccessible.h"
|
||||
#include "session/SessionController.h"
|
||||
#include <klocalizedstring.h>
|
||||
|
||||
#include "terminalDisplay/TerminalFonts.h"
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
TerminalDisplayAccessible::TerminalDisplayAccessible(TerminalDisplay *display)
|
||||
: QAccessibleWidget(display, QAccessible::Terminal, display->sessionController() ? display->sessionController()->userTitle() : QString())
|
||||
{
|
||||
}
|
||||
|
||||
QString TerminalDisplayAccessible::text(QAccessible::Text t) const
|
||||
{
|
||||
if (t == QAccessible::Value) {
|
||||
return visibleText();
|
||||
}
|
||||
return QAccessibleWidget::text(t);
|
||||
}
|
||||
|
||||
int TerminalDisplayAccessible::characterCount() const
|
||||
{
|
||||
return display()->_usedLines * display()->_usedColumns;
|
||||
}
|
||||
|
||||
int TerminalDisplayAccessible::cursorPosition() const
|
||||
{
|
||||
if (display()->screenWindow() == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int offset = display()->_usedColumns * display()->screenWindow()->screen()->getCursorY();
|
||||
return offset + display()->screenWindow()->screen()->getCursorX();
|
||||
}
|
||||
|
||||
void TerminalDisplayAccessible::selection(int selectionIndex, int *startOffset, int *endOffset) const
|
||||
{
|
||||
*startOffset = 0;
|
||||
*endOffset = 0;
|
||||
if ((display()->screenWindow() == nullptr) || (selectionIndex != 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int startLine = 0;
|
||||
int startColumn = 0;
|
||||
int endLine = 0;
|
||||
int endColumn = 0;
|
||||
display()->screenWindow()->getSelectionStart(startColumn, startLine);
|
||||
display()->screenWindow()->getSelectionEnd(endColumn, endLine);
|
||||
if ((startLine == endLine) && (startColumn == endColumn)) {
|
||||
return;
|
||||
}
|
||||
*startOffset = positionToOffset(startColumn, startLine);
|
||||
*endOffset = positionToOffset(endColumn, endLine);
|
||||
}
|
||||
|
||||
int TerminalDisplayAccessible::selectionCount() const
|
||||
{
|
||||
if (display()->screenWindow() == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int startLine = 0;
|
||||
int startColumn = 0;
|
||||
int endLine = 0;
|
||||
int endColumn = 0;
|
||||
display()->screenWindow()->getSelectionStart(startColumn, startLine);
|
||||
display()->screenWindow()->getSelectionEnd(endColumn, endLine);
|
||||
return ((startLine == endLine) && (startColumn == endColumn)) ? 0 : 1;
|
||||
}
|
||||
|
||||
QString TerminalDisplayAccessible::visibleText() const
|
||||
{
|
||||
// This function should be const to allow calling it from const interface functions.
|
||||
TerminalDisplay *display = const_cast<TerminalDisplayAccessible *>(this)->display();
|
||||
if (display->screenWindow() == nullptr) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return display->screenWindow()->screen()->text(0, display->_usedColumns * display->_usedLines, Screen::PreserveLineBreaks);
|
||||
}
|
||||
|
||||
void TerminalDisplayAccessible::addSelection(int startOffset, int endOffset)
|
||||
{
|
||||
if (display()->screenWindow() == nullptr) {
|
||||
return;
|
||||
}
|
||||
display()->screenWindow()->setSelectionStart(columnForOffset(startOffset), lineForOffset(startOffset), false);
|
||||
display()->screenWindow()->setSelectionEnd(columnForOffset(endOffset), lineForOffset(endOffset), display()->trimTrailingWhitespace());
|
||||
}
|
||||
|
||||
QString TerminalDisplayAccessible::attributes(int offset, int *startOffset, int *endOffset) const
|
||||
{
|
||||
// FIXME: this function should return css like attributes
|
||||
// as defined in the web ARIA standard
|
||||
Q_UNUSED(offset)
|
||||
*startOffset = 0;
|
||||
*endOffset = characterCount();
|
||||
return QString();
|
||||
}
|
||||
|
||||
QRect TerminalDisplayAccessible::characterRect(int offset) const
|
||||
{
|
||||
int row = offset / display()->_usedColumns;
|
||||
int col = offset - row * display()->_usedColumns;
|
||||
QPoint position = QPoint(col * display()->terminalFont()->fontWidth(), row * display()->terminalFont()->fontHeight());
|
||||
return QRect(position, QSize(display()->terminalFont()->fontWidth(), display()->terminalFont()->fontHeight()));
|
||||
}
|
||||
|
||||
int TerminalDisplayAccessible::offsetAtPoint(const QPoint &point) const
|
||||
{
|
||||
// FIXME return the offset into the text from the given point
|
||||
Q_UNUSED(point)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TerminalDisplayAccessible::removeSelection(int selectionIndex)
|
||||
{
|
||||
if ((display()->screenWindow() == nullptr) || (selectionIndex != 0)) {
|
||||
return;
|
||||
}
|
||||
display()->screenWindow()->clearSelection();
|
||||
}
|
||||
|
||||
void TerminalDisplayAccessible::scrollToSubstring(int startIndex, int endIndex)
|
||||
{
|
||||
// FIXME: make sure the string between startIndex and endIndex is visible
|
||||
Q_UNUSED(startIndex)
|
||||
Q_UNUSED(endIndex)
|
||||
}
|
||||
|
||||
void TerminalDisplayAccessible::setCursorPosition(int position)
|
||||
{
|
||||
if (display()->screenWindow() == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
display()->screenWindow()->screen()->setCursorYX(lineForOffset(position), columnForOffset(position));
|
||||
}
|
||||
|
||||
void *TerminalDisplayAccessible::interface_cast(QAccessible::InterfaceType type)
|
||||
{
|
||||
if (type == QAccessible::TextInterface) {
|
||||
return static_cast<QAccessibleTextInterface *>(this);
|
||||
}
|
||||
|
||||
return QAccessibleWidget::interface_cast(type);
|
||||
}
|
||||
|
||||
void TerminalDisplayAccessible::setSelection(int selectionIndex, int startOffset, int endOffset)
|
||||
{
|
||||
if (selectionIndex != 0) {
|
||||
return;
|
||||
}
|
||||
addSelection(startOffset, endOffset);
|
||||
}
|
||||
|
||||
QString TerminalDisplayAccessible::text(int startOffset, int endOffset) const
|
||||
{
|
||||
if (display()->screenWindow() == nullptr) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return display()->screenWindow()->screen()->text(startOffset, endOffset, Screen::PreserveLineBreaks);
|
||||
}
|
||||
|
||||
TerminalDisplay *TerminalDisplayAccessible::display() const
|
||||
{
|
||||
return qobject_cast<TerminalDisplay *>(widget());
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2012 Frederik Gladhorn <gladhorn@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef TERMINALDISPLAYACCESSIBLE_H
|
||||
#define TERMINALDISPLAYACCESSIBLE_H
|
||||
|
||||
//#include <QtGlobal>
|
||||
|
||||
#include <QAccessibleTextInterface>
|
||||
#include <QAccessibleWidget>
|
||||
|
||||
#include "Screen.h"
|
||||
#include "ScreenWindow.h"
|
||||
#include "terminalDisplay/TerminalDisplay.h"
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
/**
|
||||
* Class implementing the QAccessibleInterface for the terminal display.
|
||||
* This exposes information about the display to assistive technology using the QAccessible framework.
|
||||
*
|
||||
* Most functions are re-implemented from QAccessibleTextInterface.
|
||||
*/
|
||||
class TerminalDisplayAccessible : public QAccessibleWidget, public QAccessibleTextInterface
|
||||
{
|
||||
public:
|
||||
explicit TerminalDisplayAccessible(TerminalDisplay *display);
|
||||
|
||||
QString text(QAccessible::Text t) const override;
|
||||
QString text(int startOffset, int endOffset) const override;
|
||||
int characterCount() const override;
|
||||
|
||||
int selectionCount() const override;
|
||||
void selection(int selectionIndex, int *startOffset, int *endOffset) const override;
|
||||
void addSelection(int startOffset, int endOffset) override;
|
||||
void setSelection(int selectionIndex, int startOffset, int endOffset) override;
|
||||
void removeSelection(int selectionIndex) override;
|
||||
|
||||
QRect characterRect(int offset) const override;
|
||||
int offsetAtPoint(const QPoint &point) const override;
|
||||
void scrollToSubstring(int startIndex, int endIndex) override;
|
||||
|
||||
QString attributes(int offset, int *startOffset, int *endOffset) const override;
|
||||
|
||||
int cursorPosition() const override;
|
||||
void setCursorPosition(int position) override;
|
||||
|
||||
void *interface_cast(QAccessible::InterfaceType type) override;
|
||||
|
||||
private:
|
||||
Konsole::TerminalDisplay *display() const;
|
||||
|
||||
inline int positionToOffset(int column, int line) const
|
||||
{
|
||||
return line * display()->_usedColumns + column;
|
||||
}
|
||||
|
||||
inline int lineForOffset(int offset) const
|
||||
{
|
||||
return offset / display()->_usedColumns;
|
||||
}
|
||||
|
||||
inline int columnForOffset(int offset) const
|
||||
{
|
||||
return offset % display()->_usedColumns;
|
||||
}
|
||||
|
||||
QString visibleText() const;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
#endif // TERMINALDISPLAYACCESSIBLE_H
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "TerminalHeaderBar.h"
|
||||
|
||||
#include "KonsoleSettings.h"
|
||||
#include "ViewProperties.h"
|
||||
#include "session/SessionController.h"
|
||||
#include "terminalDisplay/TerminalDisplay.h"
|
||||
#include "widgets/ViewSplitter.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QApplication>
|
||||
#include <QBoxLayout>
|
||||
#include <QDrag>
|
||||
#include <QLabel>
|
||||
#include <QMimeData>
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include <QSplitter>
|
||||
#include <QStyleOptionTabBarBase>
|
||||
#include <QStylePainter>
|
||||
#include <QTabBar>
|
||||
#include <QToolButton>
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
TerminalHeaderBar::TerminalHeaderBar(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_boxLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||
m_boxLayout->setSpacing(0);
|
||||
m_boxLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// Session icon
|
||||
|
||||
m_terminalIcon = new QLabel(this);
|
||||
m_terminalIcon->setAlignment(Qt::AlignCenter);
|
||||
m_terminalIcon->setFixedSize(20, 20);
|
||||
|
||||
m_boxLayout->addWidget(m_terminalIcon);
|
||||
|
||||
// Status icons
|
||||
|
||||
QLabel **statusIcons[] = {&m_statusIconReadOnly, &m_statusIconCopyInput, &m_statusIconSilence, &m_statusIconActivity, &m_statusIconBell};
|
||||
|
||||
for (auto **statusIcon : statusIcons) {
|
||||
*statusIcon = new QLabel(this);
|
||||
(*statusIcon)->setAlignment(Qt::AlignCenter);
|
||||
(*statusIcon)->setFixedSize(20, 20);
|
||||
(*statusIcon)->setVisible(false);
|
||||
|
||||
m_boxLayout->addWidget(*statusIcon);
|
||||
}
|
||||
|
||||
m_statusIconReadOnly->setPixmap(QIcon::fromTheme(QStringLiteral("object-locked")).pixmap(QSize(16, 16)));
|
||||
m_statusIconCopyInput->setPixmap(QIcon::fromTheme(QStringLiteral("irc-voice")).pixmap(QSize(16, 16)));
|
||||
m_statusIconSilence->setPixmap(QIcon::fromTheme(QStringLiteral("system-suspend")).pixmap(QSize(16, 16)));
|
||||
m_statusIconActivity->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-information")).pixmap(QSize(16, 16)));
|
||||
m_statusIconBell->setPixmap(QIcon::fromTheme(QStringLiteral("notifications")).pixmap(QSize(16, 16)));
|
||||
|
||||
// Title
|
||||
|
||||
m_terminalTitle = new QLabel(this);
|
||||
m_terminalTitle->setFont(QApplication::font());
|
||||
|
||||
m_boxLayout->addStretch();
|
||||
m_boxLayout->addWidget(m_terminalTitle);
|
||||
m_boxLayout->addStretch();
|
||||
|
||||
// Expand button
|
||||
|
||||
m_toggleExpandedMode = new QToolButton(this);
|
||||
m_toggleExpandedMode->setIcon(QIcon::fromTheme(QStringLiteral("view-fullscreen"))); // fake 'expand' icon. VDG input?
|
||||
m_toggleExpandedMode->setAutoRaise(true);
|
||||
m_toggleExpandedMode->setCheckable(true);
|
||||
m_toggleExpandedMode->setToolTip(i18nc("@info:tooltip", "Maximize terminal"));
|
||||
|
||||
connect(m_toggleExpandedMode, &QToolButton::clicked, this, &TerminalHeaderBar::requestToggleExpansion);
|
||||
|
||||
m_boxLayout->addWidget(m_toggleExpandedMode);
|
||||
|
||||
// Move to new tab button
|
||||
|
||||
m_moveToNewTab = new QToolButton(this);
|
||||
m_moveToNewTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
|
||||
m_moveToNewTab->setAutoRaise(true);
|
||||
m_moveToNewTab->setToolTip(i18nc("@info:tooltip", "Move terminal to new tab"));
|
||||
|
||||
connect(m_moveToNewTab, &QToolButton::clicked, this, &TerminalHeaderBar::requestMoveToNewTab);
|
||||
|
||||
m_boxLayout->addWidget(m_moveToNewTab);
|
||||
|
||||
// Close button
|
||||
|
||||
m_closeBtn = new QToolButton(this);
|
||||
m_closeBtn->setIcon(QIcon::fromTheme(QStringLiteral("tab-close")));
|
||||
m_closeBtn->setToolTip(i18nc("@info:tooltip", "Close terminal"));
|
||||
m_closeBtn->setObjectName(QStringLiteral("close-terminal-button"));
|
||||
m_closeBtn->setAutoRaise(true);
|
||||
|
||||
m_boxLayout->addWidget(m_closeBtn);
|
||||
|
||||
// The widget itself
|
||||
|
||||
setLayout(m_boxLayout);
|
||||
setAutoFillBackground(true);
|
||||
setFocusIndicatorState(false);
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::mouseDoubleClickEvent(QMouseEvent *ev)
|
||||
{
|
||||
if (ev->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
m_toggleExpandedMode->click();
|
||||
}
|
||||
|
||||
// Hack until I can detangle the creation of the TerminalViews
|
||||
void TerminalHeaderBar::finishHeaderSetup(ViewProperties *properties)
|
||||
{
|
||||
auto controller = dynamic_cast<SessionController *>(properties);
|
||||
connect(properties, &Konsole::ViewProperties::titleChanged, this, [this, properties] {
|
||||
m_terminalTitle->setText(properties->title());
|
||||
});
|
||||
m_terminalTitle->setText(properties->title());
|
||||
|
||||
connect(properties, &Konsole::ViewProperties::iconChanged, this, [this, properties] {
|
||||
m_terminalIcon->setPixmap(properties->icon().pixmap(QSize(22, 22)));
|
||||
});
|
||||
m_terminalIcon->setPixmap(properties->icon().pixmap(QSize(22, 22)));
|
||||
|
||||
connect(properties, &Konsole::ViewProperties::notificationChanged, this, &Konsole::TerminalHeaderBar::updateNotification);
|
||||
|
||||
connect(properties, &Konsole::ViewProperties::readOnlyChanged, this, &Konsole::TerminalHeaderBar::updateSpecialState);
|
||||
|
||||
connect(properties, &Konsole::ViewProperties::copyInputChanged, this, &Konsole::TerminalHeaderBar::updateSpecialState);
|
||||
|
||||
connect(m_closeBtn, &QToolButton::clicked, controller, &SessionController::closeSession);
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::setFocusIndicatorState(bool focused)
|
||||
{
|
||||
m_terminalIsFocused = focused;
|
||||
update();
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::updateNotification(ViewProperties *item, Session::Notification notification, bool enabled)
|
||||
{
|
||||
Q_UNUSED(item)
|
||||
|
||||
switch (notification) {
|
||||
case Session::Notification::Silence:
|
||||
m_statusIconSilence->setVisible(enabled);
|
||||
break;
|
||||
case Session::Notification::Activity:
|
||||
m_statusIconActivity->setVisible(enabled);
|
||||
break;
|
||||
case Session::Notification::Bell:
|
||||
m_statusIconBell->setVisible(enabled);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::updateSpecialState(ViewProperties *item)
|
||||
{
|
||||
auto controller = dynamic_cast<SessionController *>(item);
|
||||
|
||||
if (controller != nullptr) {
|
||||
m_statusIconReadOnly->setVisible(controller->isReadOnly());
|
||||
m_statusIconCopyInput->setVisible(controller->isCopyInputActive());
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::setExpandedMode(bool expand)
|
||||
{
|
||||
if (m_toggleExpandedMode->isChecked() != expand) {
|
||||
m_toggleExpandedMode->setChecked(expand);
|
||||
}
|
||||
if (expand) {
|
||||
m_toggleExpandedMode->setToolTip(i18nc("@info:tooltip", "Restore terminal"));
|
||||
} else {
|
||||
m_toggleExpandedMode->setToolTip(i18nc("@info:tooltip", "Maximize terminal"));
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::paintEvent(QPaintEvent *paintEvent)
|
||||
{
|
||||
/* Try to get the widget that's 10px above this one.
|
||||
* If the widget is something else than a TerminalWidget, a TabBar or a QSplitter,
|
||||
* draw a 1px line to separate it from the others.
|
||||
*/
|
||||
|
||||
const auto globalPos = parentWidget()->mapToGlobal(pos());
|
||||
auto *widget = qApp->widgetAt(globalPos.x() + 10, globalPos.y() - 10);
|
||||
|
||||
const bool isTabbar = qobject_cast<QTabBar *>(widget) != nullptr;
|
||||
const bool isTerminalWidget = qobject_cast<TerminalDisplay *>(widget) != nullptr;
|
||||
const bool isSplitter = (qobject_cast<QSplitter *>(widget) != nullptr) || (qobject_cast<QSplitterHandle *>(widget) != nullptr);
|
||||
if ((widget != nullptr) && !isTabbar && !isTerminalWidget && !isSplitter) {
|
||||
QStyleOptionTabBarBase optTabBase;
|
||||
QStylePainter p(this);
|
||||
optTabBase.initFrom(this);
|
||||
optTabBase.shape = QTabBar::Shape::RoundedSouth;
|
||||
optTabBase.documentMode = false;
|
||||
p.drawPrimitive(QStyle::PE_FrameTabBarBase, optTabBase);
|
||||
}
|
||||
|
||||
QWidget::paintEvent(paintEvent);
|
||||
if (!m_terminalIsFocused) {
|
||||
auto p = qApp->palette();
|
||||
auto shadowColor = p.color(QPalette::ColorRole::Shadow);
|
||||
shadowColor.setAlphaF(qreal(0.2) * shadowColor.alphaF()); // same as breeze.
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(shadowColor);
|
||||
painter.drawRect(rect());
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::mouseMoveEvent(QMouseEvent *ev)
|
||||
{
|
||||
if (m_toggleExpandedMode->isChecked()) {
|
||||
return;
|
||||
}
|
||||
auto point = ev->pos() - m_startDrag;
|
||||
if (point.manhattanLength() > 10) {
|
||||
auto drag = new QDrag(parent());
|
||||
auto mimeData = new QMimeData();
|
||||
QByteArray payload;
|
||||
payload.setNum(qApp->applicationPid());
|
||||
mimeData->setData(QStringLiteral("konsole/terminal_display"), payload);
|
||||
drag->setMimeData(mimeData);
|
||||
drag->exec();
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::mousePressEvent(QMouseEvent *ev)
|
||||
{
|
||||
m_startDrag = ev->pos();
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::mouseReleaseEvent(QMouseEvent *ev)
|
||||
{
|
||||
Q_UNUSED(ev)
|
||||
}
|
||||
|
||||
QSize TerminalHeaderBar::minimumSizeHint() const
|
||||
{
|
||||
auto height = sizeHint().height();
|
||||
return {height, height};
|
||||
}
|
||||
|
||||
QSplitter *TerminalHeaderBar::getTopLevelSplitter()
|
||||
{
|
||||
QWidget *p = parentWidget();
|
||||
// This is expected.
|
||||
if (qobject_cast<TerminalDisplay *>(p) != nullptr) {
|
||||
p = p->parentWidget();
|
||||
}
|
||||
|
||||
// this is also expected.
|
||||
auto *innerSplitter = qobject_cast<ViewSplitter *>(p);
|
||||
if (innerSplitter == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return innerSplitter->getToplevelSplitter();
|
||||
}
|
||||
|
||||
void TerminalHeaderBar::applyVisibilitySettings()
|
||||
{
|
||||
auto *settings = KonsoleSettings::self();
|
||||
auto toVisibility = settings->splitViewVisibility();
|
||||
const bool singleTerminalView = (getTopLevelSplitter()->findChildren<TerminalDisplay *>().count() == 1);
|
||||
switch (toVisibility) {
|
||||
case KonsoleSettings::AlwaysShowSplitHeader:
|
||||
m_toggleExpandedMode->setDisabled(singleTerminalView);
|
||||
setVisible(true);
|
||||
break;
|
||||
case KonsoleSettings::ShowSplitHeaderWhenNeeded: {
|
||||
const bool visible = !(singleTerminalView);
|
||||
setVisible(visible);
|
||||
} break;
|
||||
case KonsoleSettings::AlwaysHideSplitHeader:
|
||||
setVisible(false);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "moc_TerminalHeaderBar.cpp"
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef TERMINAL_HEADER_BAR_H
|
||||
#define TERMINAL_HEADER_BAR_H
|
||||
|
||||
#include "session/Session.h"
|
||||
#include <QPoint>
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
class QToolButton;
|
||||
class QBoxLayout;
|
||||
class QSplitter;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
class TerminalDisplay;
|
||||
class ViewProperties;
|
||||
|
||||
class TerminalHeaderBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// TODO: Verify if the terminalDisplay is needed, or some other thing like SessionController.
|
||||
explicit TerminalHeaderBar(QWidget *parent = nullptr);
|
||||
void finishHeaderSetup(ViewProperties *properties);
|
||||
QSize minimumSizeHint() const override;
|
||||
void applyVisibilitySettings();
|
||||
QSplitter *getTopLevelSplitter();
|
||||
void setExpandedMode(bool expand);
|
||||
|
||||
public Q_SLOTS:
|
||||
void setFocusIndicatorState(bool focused);
|
||||
/** Shows/hide notification status icon */
|
||||
void updateNotification(ViewProperties *item, Konsole::Session::Notification notification, bool enabled);
|
||||
/** Shows/hide special state status icon (copy input or read-only) */
|
||||
void updateSpecialState(ViewProperties *item);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *paintEvent) override;
|
||||
void mousePressEvent(QMouseEvent *ev) override;
|
||||
void mouseReleaseEvent(QMouseEvent *ev) override;
|
||||
void mouseMoveEvent(QMouseEvent *ev) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *ev) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void requestToggleExpansion();
|
||||
void requestMoveToNewTab();
|
||||
|
||||
private:
|
||||
QBoxLayout *m_boxLayout;
|
||||
QLabel *m_terminalTitle;
|
||||
QLabel *m_terminalIcon;
|
||||
QLabel *m_statusIconReadOnly;
|
||||
QLabel *m_statusIconCopyInput;
|
||||
QLabel *m_statusIconSilence;
|
||||
QLabel *m_statusIconActivity;
|
||||
QLabel *m_statusIconBell;
|
||||
QToolButton *m_closeBtn;
|
||||
QToolButton *m_moveToNewTab;
|
||||
QToolButton *m_toggleExpandedMode;
|
||||
bool m_terminalIsFocused;
|
||||
QPoint m_startDrag;
|
||||
};
|
||||
|
||||
} // namespace Konsole
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,746 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2006-2008 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "widgets/ViewContainer.h"
|
||||
#include "config-konsole.h"
|
||||
|
||||
// Qt
|
||||
#include <QFile>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QTabBar>
|
||||
|
||||
// KDE
|
||||
#include <KActionCollection>
|
||||
#include <KColorScheme>
|
||||
#include <KColorUtils>
|
||||
#include <KLocalizedString>
|
||||
|
||||
// Konsole
|
||||
#include "DetachableTabBar.h"
|
||||
#include "KonsoleSettings.h"
|
||||
#include "ViewProperties.h"
|
||||
#include "profile/ProfileList.h"
|
||||
#include "session/SessionController.h"
|
||||
#include "session/SessionManager.h"
|
||||
#include "terminalDisplay/TerminalDisplay.h"
|
||||
#include "widgets/IncrementalSearchBar.h"
|
||||
#include "widgets/ViewSplitter.h"
|
||||
|
||||
// TODO Perhaps move everything which is Konsole-specific into different files
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
TabbedViewContainer::TabbedViewContainer(ViewManager *connectedViewManager, QWidget *parent)
|
||||
: QTabWidget(parent)
|
||||
, _connectedViewManager(connectedViewManager)
|
||||
, _newTabButton(new QToolButton(this))
|
||||
, _closeTabButton(new QToolButton(this))
|
||||
, _contextMenuTabIndex(-1)
|
||||
, _newTabBehavior(PutNewTabAtTheEnd)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
|
||||
auto tabBarWidget = new DetachableTabBar(this);
|
||||
setTabBar(tabBarWidget);
|
||||
setDocumentMode(true);
|
||||
setMovable(true);
|
||||
connect(tabBarWidget, &DetachableTabBar::moveTabToWindow, this, &TabbedViewContainer::moveTabToWindow);
|
||||
tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
_newTabButton->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
|
||||
_newTabButton->setAutoRaise(true);
|
||||
_newTabButton->setToolTip(i18nc("@info:tooltip", "Open a new tab"));
|
||||
connect(_newTabButton, &QToolButton::clicked, this, &TabbedViewContainer::newViewRequest);
|
||||
|
||||
_closeTabButton->setIcon(QIcon::fromTheme(QStringLiteral("tab-close")));
|
||||
_closeTabButton->setAutoRaise(true);
|
||||
_closeTabButton->setToolTip(i18nc("@info:tooltip", "Close this tab"));
|
||||
connect(_closeTabButton, &QToolButton::clicked, this, [this] {
|
||||
closeCurrentTab();
|
||||
});
|
||||
|
||||
connect(tabBar(), &QTabBar::tabBarDoubleClicked, this, &Konsole::TabbedViewContainer::tabDoubleClicked);
|
||||
connect(tabBar(), &QTabBar::customContextMenuRequested, this, &Konsole::TabbedViewContainer::openTabContextMenu);
|
||||
connect(tabBarWidget, &DetachableTabBar::detachTab, this, [this](int idx) {
|
||||
Q_EMIT detachTab(idx);
|
||||
});
|
||||
connect(tabBarWidget, &DetachableTabBar::closeTab, this, &TabbedViewContainer::closeTerminalTab);
|
||||
connect(tabBarWidget, &DetachableTabBar::newTabRequest, this, [this] {
|
||||
Q_EMIT newViewRequest();
|
||||
});
|
||||
connect(this, &TabbedViewContainer::currentChanged, this, &TabbedViewContainer::currentTabChanged);
|
||||
|
||||
connect(this, &TabbedViewContainer::setColor, tabBarWidget, &DetachableTabBar::setColor);
|
||||
connect(this, &TabbedViewContainer::removeColor, tabBarWidget, &DetachableTabBar::removeColor);
|
||||
|
||||
// The context menu of tab bar
|
||||
_contextPopupMenu = new QMenu(tabBar());
|
||||
connect(_contextPopupMenu, &QMenu::aboutToHide, this, [this]() {
|
||||
// Remove the read-only action when the popup closes
|
||||
for (auto &action : _contextPopupMenu->actions()) {
|
||||
if (action->objectName() == QStringLiteral("view-readonly")) {
|
||||
_contextPopupMenu->removeAction(action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(tabBar(), &QTabBar::tabCloseRequested, this, &TabbedViewContainer::closeTerminalTab);
|
||||
|
||||
auto detachAction = _contextPopupMenu->addAction(QIcon::fromTheme(QStringLiteral("tab-detach")), i18nc("@action:inmenu", "&Detach Tab"), this, [this] {
|
||||
Q_EMIT detachTab(_contextMenuTabIndex);
|
||||
});
|
||||
detachAction->setObjectName(QStringLiteral("tab-detach"));
|
||||
|
||||
auto editAction =
|
||||
_contextPopupMenu->addAction(QIcon::fromTheme(QStringLiteral("edit-rename")), i18nc("@action:inmenu", "&Configure or Rename Tab..."), this, [this] {
|
||||
renameTab(_contextMenuTabIndex);
|
||||
});
|
||||
editAction->setObjectName(QStringLiteral("edit-rename"));
|
||||
|
||||
auto closeAction = _contextPopupMenu->addAction(QIcon::fromTheme(QStringLiteral("tab-close")), i18nc("@action:inmenu", "Close Tab"), this, [this] {
|
||||
closeTerminalTab(_contextMenuTabIndex);
|
||||
});
|
||||
closeAction->setObjectName(QStringLiteral("tab-close"));
|
||||
|
||||
auto profileMenu = new QMenu(this);
|
||||
auto profileList = new ProfileList(false, profileMenu);
|
||||
profileList->syncWidgetActions(profileMenu, true);
|
||||
connect(profileList, &Konsole::ProfileList::profileSelected, this, &TabbedViewContainer::newViewWithProfileRequest);
|
||||
_newTabButton->setMenu(profileMenu);
|
||||
|
||||
konsoleConfigChanged();
|
||||
connect(KonsoleSettings::self(), &KonsoleSettings::configChanged, this, &TabbedViewContainer::konsoleConfigChanged);
|
||||
}
|
||||
|
||||
TabbedViewContainer::~TabbedViewContainer()
|
||||
{
|
||||
for (int i = 0, end = count(); i < end; i++) {
|
||||
auto view = widget(i);
|
||||
disconnect(view, &QWidget::destroyed, this, &Konsole::TabbedViewContainer::viewDestroyed);
|
||||
}
|
||||
}
|
||||
|
||||
ViewSplitter *TabbedViewContainer::activeViewSplitter()
|
||||
{
|
||||
return viewSplitterAt(currentIndex());
|
||||
}
|
||||
|
||||
ViewSplitter *TabbedViewContainer::viewSplitterAt(int index)
|
||||
{
|
||||
return qobject_cast<ViewSplitter *>(widget(index));
|
||||
}
|
||||
|
||||
ViewSplitter *TabbedViewContainer::findSplitter(int id)
|
||||
{
|
||||
for (int i = 0; i < count(); ++i) {
|
||||
auto toplevelSplitter = viewSplitterAt(i);
|
||||
|
||||
if (toplevelSplitter->id() == id)
|
||||
return toplevelSplitter;
|
||||
|
||||
if (auto result = toplevelSplitter->getChildSplitter(id))
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int TabbedViewContainer::currentTabViewCount()
|
||||
{
|
||||
if (auto *splitter = activeViewSplitter()) {
|
||||
return splitter->findChildren<TerminalDisplay *>().count();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void TabbedViewContainer::moveTabToWindow(int index, QWidget *window)
|
||||
{
|
||||
auto splitter = viewSplitterAt(index);
|
||||
auto manager = window->findChild<ViewManager *>();
|
||||
|
||||
QHash<TerminalDisplay *, Session *> sessionsMap = _connectedViewManager->forgetAll(splitter);
|
||||
|
||||
const QList<TerminalDisplay *> displays = splitter->findChildren<TerminalDisplay *>();
|
||||
for (TerminalDisplay *terminal : displays) {
|
||||
manager->attachView(terminal, sessionsMap[terminal]);
|
||||
}
|
||||
auto container = manager->activeContainer();
|
||||
container->addSplitter(splitter);
|
||||
|
||||
auto controller = splitter->activeTerminalDisplay()->sessionController();
|
||||
container->currentSessionControllerChanged(controller);
|
||||
|
||||
forgetView();
|
||||
}
|
||||
|
||||
void TabbedViewContainer::konsoleConfigChanged()
|
||||
{
|
||||
// don't show tabs if we are in KParts mode.
|
||||
// This is a hack, and this needs to be rewritten.
|
||||
// The container should not be part of the KParts, perhaps just the
|
||||
// TerminalDisplay should.
|
||||
|
||||
// ASAN issue if using sessionController->isKonsolePart(), just
|
||||
// duplicate code for now
|
||||
if (qApp->applicationName() != QLatin1String("konsole")) {
|
||||
tabBar()->setVisible(false);
|
||||
} else {
|
||||
// if we start with --show-tabbar or --hide-tabbar we ignore the preferences.
|
||||
setTabBarAutoHide(KonsoleSettings::tabBarVisibility() == KonsoleSettings::EnumTabBarVisibility::ShowTabBarWhenNeeded);
|
||||
if (KonsoleSettings::tabBarVisibility() == KonsoleSettings::EnumTabBarVisibility::AlwaysShowTabBar) {
|
||||
tabBar()->setVisible(true);
|
||||
} else if (KonsoleSettings::tabBarVisibility() == KonsoleSettings::EnumTabBarVisibility::AlwaysHideTabBar) {
|
||||
tabBar()->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
setTabPosition((QTabWidget::TabPosition)KonsoleSettings::tabBarPosition());
|
||||
|
||||
setCornerWidget(KonsoleSettings::newTabButton() ? _newTabButton : nullptr, Qt::TopLeftCorner);
|
||||
_newTabButton->setVisible(KonsoleSettings::newTabButton());
|
||||
|
||||
setCornerWidget(KonsoleSettings::closeTabButton() == 1 ? _closeTabButton : nullptr, Qt::TopRightCorner);
|
||||
_closeTabButton->setVisible(KonsoleSettings::closeTabButton() == 1);
|
||||
|
||||
tabBar()->setTabsClosable(KonsoleSettings::closeTabButton() == 0);
|
||||
|
||||
tabBar()->setExpanding(KonsoleSettings::expandTabWidth());
|
||||
tabBar()->update();
|
||||
|
||||
if (KonsoleSettings::tabBarUseUserStyleSheet()) {
|
||||
setCssFromFile(KonsoleSettings::tabBarUserStyleSheetFile());
|
||||
_stylesheetSet = true;
|
||||
} else {
|
||||
if (_stylesheetSet) {
|
||||
setStyleSheet(QString());
|
||||
_stylesheetSet = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::setCssFromFile(const QUrl &url)
|
||||
{
|
||||
// Let's only deal w/ local files for now
|
||||
if (!url.isLocalFile()) {
|
||||
setStyleSheet(KonsoleSettings::tabBarStyleSheet());
|
||||
}
|
||||
|
||||
QFile file(url.toLocalFile());
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
setStyleSheet(KonsoleSettings::tabBarStyleSheet());
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
setStyleSheet(in.readAll());
|
||||
}
|
||||
|
||||
void TabbedViewContainer::moveActiveView(MoveDirection direction)
|
||||
{
|
||||
if (count() < 2) { // return if only one view
|
||||
return;
|
||||
}
|
||||
const int currentIndex = indexOf(currentWidget());
|
||||
int newIndex = direction == MoveViewLeft ? qMax(currentIndex - 1, 0) : qMin(currentIndex + 1, count() - 1);
|
||||
|
||||
auto swappedWidget = viewSplitterAt(newIndex);
|
||||
auto swappedTitle = tabBar()->tabText(newIndex);
|
||||
auto swappedIcon = tabBar()->tabIcon(newIndex);
|
||||
|
||||
auto currentWidget = viewSplitterAt(currentIndex);
|
||||
auto currentTitle = tabBar()->tabText(currentIndex);
|
||||
auto currentIcon = tabBar()->tabIcon(currentIndex);
|
||||
|
||||
if (newIndex < currentIndex) {
|
||||
insertTab(newIndex, currentWidget, currentIcon, currentTitle);
|
||||
insertTab(currentIndex, swappedWidget, swappedIcon, swappedTitle);
|
||||
} else {
|
||||
insertTab(currentIndex, swappedWidget, swappedIcon, swappedTitle);
|
||||
insertTab(newIndex, currentWidget, currentIcon, currentTitle);
|
||||
}
|
||||
setCurrentIndex(newIndex);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::terminalDisplayDropped(TerminalDisplay *terminalDisplay)
|
||||
{
|
||||
auto *controller = terminalDisplay->sessionController();
|
||||
if (controller->parent() != connectedViewManager()) {
|
||||
// Terminal from another window - recreate SessionController for current ViewManager
|
||||
disconnectTerminalDisplay(terminalDisplay);
|
||||
Session *terminalSession = controller->session();
|
||||
Q_EMIT controller->viewDragAndDropped(controller);
|
||||
connectedViewManager()->attachView(terminalDisplay, terminalSession);
|
||||
connectTerminalDisplay(terminalDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
QSize TabbedViewContainer::sizeHint() const
|
||||
{
|
||||
// QTabWidget::sizeHint() contains some margins added by widgets
|
||||
// style, which were making the initial window size too big.
|
||||
const auto tabsSize = tabBar()->sizeHint();
|
||||
const auto *leftWidget = cornerWidget(Qt::TopLeftCorner);
|
||||
const auto *rightWidget = cornerWidget(Qt::TopRightCorner);
|
||||
const auto leftSize = leftWidget != nullptr ? leftWidget->sizeHint() : QSize(0, 0);
|
||||
const auto rightSize = rightWidget != nullptr ? rightWidget->sizeHint() : QSize(0, 0);
|
||||
|
||||
auto tabBarSize = QSize(0, 0);
|
||||
// isVisible() won't work; this is called when the window is not yet visible
|
||||
if (tabBar()->isVisibleTo(this)) {
|
||||
tabBarSize.setWidth(leftSize.width() + tabsSize.width() + rightSize.width());
|
||||
tabBarSize.setHeight(qMax(tabsSize.height(), qMax(leftSize.height(), rightSize.height())));
|
||||
}
|
||||
|
||||
const auto terminalSize = currentWidget() != nullptr ? currentWidget()->sizeHint() : QSize(0, 0);
|
||||
|
||||
// width
|
||||
// ├──────────────────┤
|
||||
//
|
||||
// ┌──────────────────┐ ┬
|
||||
// │ │ │
|
||||
// │ Terminal │ │
|
||||
// │ │ │ height
|
||||
// ├───┬──────────┬───┤ │ ┬
|
||||
// │ L │ Tabs │ R │ │ │ tab bar height
|
||||
// └───┴──────────┴───┘ ┴ ┴
|
||||
//
|
||||
// L/R = left/right widget
|
||||
|
||||
return {qMax(terminalSize.width(), tabBarSize.width()), tabBarSize.height() + terminalSize.height()};
|
||||
}
|
||||
|
||||
void TabbedViewContainer::addSplitter(ViewSplitter *viewSplitter, int index)
|
||||
{
|
||||
index = insertTab(index, viewSplitter, QString());
|
||||
connect(viewSplitter, &ViewSplitter::destroyed, this, &TabbedViewContainer::viewDestroyed);
|
||||
|
||||
disconnect(viewSplitter, &ViewSplitter::terminalDisplayDropped, nullptr, nullptr);
|
||||
connect(viewSplitter, &ViewSplitter::terminalDisplayDropped, this, &TabbedViewContainer::terminalDisplayDropped);
|
||||
|
||||
const auto terminalDisplays = viewSplitter->findChildren<TerminalDisplay *>();
|
||||
for (TerminalDisplay *terminal : terminalDisplays) {
|
||||
connectTerminalDisplay(terminal);
|
||||
}
|
||||
if (terminalDisplays.count() > 0) {
|
||||
updateTitle(qobject_cast<ViewProperties *>(terminalDisplays.at(0)->sessionController()));
|
||||
updateColor(qobject_cast<ViewProperties *>(terminalDisplays.at(0)->sessionController()));
|
||||
}
|
||||
setCurrentIndex(index);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::addView(TerminalDisplay *view)
|
||||
{
|
||||
auto viewSplitter = new ViewSplitter();
|
||||
viewSplitter->addTerminalDisplay(view, Qt::Horizontal);
|
||||
auto item = view->sessionController();
|
||||
int index = _newTabBehavior == PutNewTabAfterCurrentTab ? currentIndex() + 1 : -1;
|
||||
index = insertTab(index, viewSplitter, item->icon(), item->title());
|
||||
|
||||
connectTerminalDisplay(view);
|
||||
connect(viewSplitter, &ViewSplitter::destroyed, this, &TabbedViewContainer::viewDestroyed);
|
||||
connect(viewSplitter, &ViewSplitter::terminalDisplayDropped, this, &TabbedViewContainer::terminalDisplayDropped);
|
||||
|
||||
// Put this view on the foreground if it requests so, eg. on bell activity
|
||||
connect(view, &TerminalDisplay::activationRequest, this, &Konsole::TabbedViewContainer::activateView);
|
||||
|
||||
setCurrentIndex(index);
|
||||
Q_EMIT viewAdded(view);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::splitView(TerminalDisplay *view, Qt::Orientation orientation)
|
||||
{
|
||||
auto viewSplitter = qobject_cast<ViewSplitter *>(currentWidget());
|
||||
viewSplitter->clearMaximized();
|
||||
viewSplitter->addTerminalDisplay(view, orientation);
|
||||
connectTerminalDisplay(view);
|
||||
// Put this view on the foreground if it requests so, eg. on bell activity
|
||||
connect(view, &TerminalDisplay::activationRequest, this, &Konsole::TabbedViewContainer::activateView);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::connectTerminalDisplay(TerminalDisplay *display)
|
||||
{
|
||||
auto item = display->sessionController();
|
||||
connect(item, &Konsole::SessionController::viewFocused, this, &Konsole::TabbedViewContainer::currentSessionControllerChanged);
|
||||
|
||||
connect(item, &Konsole::ViewProperties::titleChanged, this, &Konsole::TabbedViewContainer::updateTitle);
|
||||
|
||||
connect(item, &Konsole::ViewProperties::colorChanged, this, &Konsole::TabbedViewContainer::updateColor);
|
||||
|
||||
connect(item, &Konsole::ViewProperties::iconChanged, this, &Konsole::TabbedViewContainer::updateIcon);
|
||||
|
||||
connect(item, &Konsole::ViewProperties::activity, this, &Konsole::TabbedViewContainer::updateActivity);
|
||||
|
||||
connect(item, &Konsole::ViewProperties::notificationChanged, this, &Konsole::TabbedViewContainer::updateNotification);
|
||||
|
||||
connect(item, &Konsole::ViewProperties::readOnlyChanged, this, &Konsole::TabbedViewContainer::updateSpecialState);
|
||||
|
||||
connect(item, &Konsole::ViewProperties::copyInputChanged, this, &Konsole::TabbedViewContainer::updateSpecialState);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::disconnectTerminalDisplay(TerminalDisplay *display)
|
||||
{
|
||||
auto item = display->sessionController();
|
||||
item->disconnect(this);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::viewDestroyed(QObject *view)
|
||||
{
|
||||
QWidget *widget = qobject_cast<QWidget *>(view);
|
||||
Q_ASSERT(widget);
|
||||
const int idx = indexOf(widget);
|
||||
|
||||
removeTab(idx);
|
||||
forgetView();
|
||||
_tabIconState.remove(widget);
|
||||
|
||||
Q_EMIT viewRemoved();
|
||||
}
|
||||
|
||||
void TabbedViewContainer::forgetView()
|
||||
{
|
||||
if (count() == 0) {
|
||||
Q_EMIT empty(this);
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::activateView(const QString & /*xdgActivationToken*/)
|
||||
{
|
||||
if (QWidget *widget = qobject_cast<QWidget *>(sender())) {
|
||||
auto topLevelSplitter = qobject_cast<ViewSplitter *>(widget->parentWidget())->getToplevelSplitter();
|
||||
setCurrentWidget(topLevelSplitter);
|
||||
widget->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::activateNextView()
|
||||
{
|
||||
QWidget *active = currentWidget();
|
||||
int index = indexOf(active);
|
||||
setCurrentIndex(index == count() - 1 ? 0 : index + 1);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::activateLastView()
|
||||
{
|
||||
setCurrentIndex(count() - 1);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::activatePreviousView()
|
||||
{
|
||||
QWidget *active = currentWidget();
|
||||
int index = indexOf(active);
|
||||
setCurrentIndex(index == 0 ? count() - 1 : index - 1);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::keyReleaseEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->modifiers() == Qt::NoModifier) {
|
||||
_connectedViewManager->updateTerminalDisplayHistory();
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::closeCurrentTab()
|
||||
{
|
||||
if (currentIndex() != -1) {
|
||||
closeTerminalTab(currentIndex());
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::tabDoubleClicked(int index)
|
||||
{
|
||||
if (index >= 0) {
|
||||
renameTab(index);
|
||||
} else {
|
||||
Q_EMIT newViewRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::renameTab(int index)
|
||||
{
|
||||
if (index != -1) {
|
||||
setCurrentIndex(index);
|
||||
viewSplitterAt(index)->activeTerminalDisplay()->sessionController()->rename();
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::openTabContextMenu(const QPoint &point)
|
||||
{
|
||||
if (point.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_contextMenuTabIndex = tabBar()->tabAt(point);
|
||||
if (_contextMenuTabIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: add a countChanged signal so we can remove this for.
|
||||
// Detaching in mac causes crashes.
|
||||
for (auto action : _contextPopupMenu->actions()) {
|
||||
if (action->objectName() == QStringLiteral("tab-detach")) {
|
||||
action->setEnabled(count() > 1);
|
||||
}
|
||||
}
|
||||
|
||||
_contextPopupMenu->exec(tabBar()->mapToGlobal(point));
|
||||
}
|
||||
|
||||
void TabbedViewContainer::currentTabChanged(int index)
|
||||
{
|
||||
if (index != -1) {
|
||||
auto splitview = qobject_cast<ViewSplitter *>(widget(index));
|
||||
auto view = splitview->activeTerminalDisplay();
|
||||
setTabActivity(index, false);
|
||||
_tabIconState[splitview].notification = Session::NoNotification;
|
||||
if (view != nullptr) {
|
||||
Q_EMIT activeViewChanged(view);
|
||||
updateIcon(view->sessionController());
|
||||
}
|
||||
} else {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::wheelScrolled(int delta)
|
||||
{
|
||||
if (delta < 0) {
|
||||
activateNextView();
|
||||
} else {
|
||||
activatePreviousView();
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::setTabActivity(int index, bool activity)
|
||||
{
|
||||
const QPalette &palette = tabBar()->palette();
|
||||
KColorScheme colorScheme(palette.currentColorGroup());
|
||||
const QColor colorSchemeActive = colorScheme.foreground(KColorScheme::ActiveText).color();
|
||||
|
||||
const QColor normalColor = palette.text().color();
|
||||
const QColor activityColor = KColorUtils::mix(normalColor, colorSchemeActive);
|
||||
|
||||
QColor color = activity ? activityColor : QColor();
|
||||
|
||||
if (color != tabBar()->tabTextColor(index)) {
|
||||
tabBar()->setTabTextColor(index, color);
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::updateTitle(ViewProperties *item)
|
||||
{
|
||||
auto controller = qobject_cast<SessionController *>(item);
|
||||
auto topLevelSplitter = qobject_cast<ViewSplitter *>(controller->view()->parentWidget())->getToplevelSplitter();
|
||||
if (controller->view() != topLevelSplitter->activeTerminalDisplay()) {
|
||||
return;
|
||||
}
|
||||
const int index = indexOf(topLevelSplitter);
|
||||
QString tabText = item->title();
|
||||
|
||||
setTabToolTip(index, tabText);
|
||||
|
||||
// To avoid having & replaced with _ (shortcut indicator)
|
||||
tabText.replace(QLatin1Char('&'), QLatin1String("&&"));
|
||||
setTabText(index, tabText);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::updateColor(ViewProperties *item)
|
||||
{
|
||||
auto controller = qobject_cast<SessionController *>(item);
|
||||
auto topLevelSplitter = qobject_cast<ViewSplitter *>(controller->view()->parentWidget())->getToplevelSplitter();
|
||||
const int index = indexOf(topLevelSplitter);
|
||||
|
||||
Q_EMIT setColor(index, item->color());
|
||||
}
|
||||
|
||||
void TabbedViewContainer::updateIcon(ViewProperties *item)
|
||||
{
|
||||
auto controller = qobject_cast<SessionController *>(item);
|
||||
auto topLevelSplitter = qobject_cast<ViewSplitter *>(controller->view()->parentWidget())->getToplevelSplitter();
|
||||
const int index = indexOf(topLevelSplitter);
|
||||
const auto &state = _tabIconState[topLevelSplitter];
|
||||
|
||||
// Tab icon priority (from highest to lowest):
|
||||
//
|
||||
// 1. Latest Notification
|
||||
// - Inactive tab: Latest notification from any view in a tab. Removed
|
||||
// when tab is activated.
|
||||
// - Active tab: Latest notification from focused view. Removed when
|
||||
// focus changes or when the Session clears its notifications
|
||||
// 2. Copy input or read-only indicator when all views in the tab have
|
||||
// the status
|
||||
// 3. Active view icon
|
||||
|
||||
QIcon icon = item->icon();
|
||||
if (state.notification != Session::NoNotification) {
|
||||
switch (state.notification) {
|
||||
case Session::Bell: {
|
||||
auto session = controller->session();
|
||||
auto profilePtr = SessionManager::instance()->sessionProfile(session);
|
||||
if (profilePtr->property<int>(Profile::BellMode) != Enum::NoBell) {
|
||||
icon = QIcon::fromTheme(QLatin1String("notifications"));
|
||||
}
|
||||
} break;
|
||||
case Session::Activity:
|
||||
icon = QIcon::fromTheme(QLatin1String("dialog-information"));
|
||||
break;
|
||||
case Session::Silence:
|
||||
icon = QIcon::fromTheme(QLatin1String("system-suspend"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (state.broadcast) {
|
||||
icon = QIcon::fromTheme(QLatin1String("irc-voice"));
|
||||
} else if (state.readOnly) {
|
||||
icon = QIcon::fromTheme(QLatin1String("object-locked"));
|
||||
}
|
||||
|
||||
if (tabIcon(index).name() != icon.name()) {
|
||||
setTabIcon(index, icon);
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::updateActivity(ViewProperties *item)
|
||||
{
|
||||
auto controller = qobject_cast<SessionController *>(item);
|
||||
auto topLevelSplitter = qobject_cast<ViewSplitter *>(controller->view()->parentWidget())->getToplevelSplitter();
|
||||
|
||||
const int index = indexOf(topLevelSplitter);
|
||||
if (index != currentIndex()) {
|
||||
setTabActivity(index, true);
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::updateNotification(ViewProperties *item, Session::Notification notification, bool enabled)
|
||||
{
|
||||
auto controller = qobject_cast<SessionController *>(item);
|
||||
auto topLevelSplitter = qobject_cast<ViewSplitter *>(controller->view()->parentWidget())->getToplevelSplitter();
|
||||
const int index = indexOf(topLevelSplitter);
|
||||
auto &state = _tabIconState[topLevelSplitter];
|
||||
|
||||
if (enabled && (index != currentIndex() || controller->view()->hasCompositeFocus())) {
|
||||
state.notification = notification;
|
||||
updateIcon(item);
|
||||
} else if (!enabled && controller->view()->hasCompositeFocus()) {
|
||||
state.notification = Session::NoNotification;
|
||||
updateIcon(item);
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::updateSpecialState(ViewProperties *item)
|
||||
{
|
||||
auto controller = qobject_cast<SessionController *>(item);
|
||||
auto topLevelSplitter = qobject_cast<ViewSplitter *>(controller->view()->parentWidget())->getToplevelSplitter();
|
||||
|
||||
auto &state = _tabIconState[topLevelSplitter];
|
||||
state.readOnly = true;
|
||||
state.broadcast = true;
|
||||
const auto displays = topLevelSplitter->findChildren<TerminalDisplay *>();
|
||||
for (const auto display : displays) {
|
||||
if (!display->sessionController()->isReadOnly()) {
|
||||
state.readOnly = false;
|
||||
}
|
||||
if (!display->sessionController()->isCopyInputActive()) {
|
||||
state.broadcast = false;
|
||||
}
|
||||
}
|
||||
updateIcon(item);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::currentSessionControllerChanged(SessionController *controller)
|
||||
{
|
||||
auto topLevelSplitter = qobject_cast<ViewSplitter *>(controller->view()->parentWidget())->getToplevelSplitter();
|
||||
const int index = indexOf(topLevelSplitter);
|
||||
|
||||
if (index == currentIndex()) {
|
||||
// Active view changed in current tab - clear notifications
|
||||
auto &state = _tabIconState[topLevelSplitter];
|
||||
state.notification = Session::NoNotification;
|
||||
}
|
||||
|
||||
updateTitle(qobject_cast<ViewProperties *>(controller));
|
||||
updateColor(qobject_cast<ViewProperties *>(controller));
|
||||
updateActivity(qobject_cast<ViewProperties *>(controller));
|
||||
updateSpecialState(qobject_cast<ViewProperties *>(controller));
|
||||
}
|
||||
|
||||
void TabbedViewContainer::closeTerminalTab(int idx)
|
||||
{
|
||||
Q_EMIT removeColor(idx);
|
||||
// TODO: This for should probably go to the ViewSplitter
|
||||
for (auto terminal : viewSplitterAt(idx)->findChildren<TerminalDisplay *>()) {
|
||||
terminal->sessionController()->closeSession();
|
||||
}
|
||||
}
|
||||
|
||||
ViewManager *TabbedViewContainer::connectedViewManager()
|
||||
{
|
||||
return _connectedViewManager;
|
||||
}
|
||||
|
||||
void TabbedViewContainer::setNavigationVisibility(ViewManager::NavigationVisibility navigationVisibility)
|
||||
{
|
||||
if (navigationVisibility == ViewManager::NavigationNotSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTabBarAutoHide(navigationVisibility == ViewManager::ShowNavigationAsNeeded);
|
||||
if (navigationVisibility == ViewManager::AlwaysShowNavigation) {
|
||||
tabBar()->setVisible(true);
|
||||
} else if (navigationVisibility == ViewManager::AlwaysHideNavigation) {
|
||||
tabBar()->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TabbedViewContainer::toggleMaximizeCurrentTerminal()
|
||||
{
|
||||
if (auto *terminal = qobject_cast<TerminalDisplay *>(sender())) {
|
||||
terminal->setFocus(Qt::FocusReason::OtherFocusReason);
|
||||
}
|
||||
|
||||
activeViewSplitter()->toggleMaximizeCurrentTerminal();
|
||||
}
|
||||
|
||||
|
||||
void TabbedViewContainer::toggleZoomMaximizeCurrentTerminal()
|
||||
{
|
||||
if (auto *terminal = qobject_cast<TerminalDisplay *>(sender())) {
|
||||
terminal->setFocus(Qt::FocusReason::OtherFocusReason);
|
||||
}
|
||||
|
||||
activeViewSplitter()->toggleZoomMaximizeCurrentTerminal();
|
||||
}
|
||||
|
||||
void TabbedViewContainer::moveTabLeft()
|
||||
{
|
||||
if (currentIndex() == 0) {
|
||||
return;
|
||||
}
|
||||
tabBar()->moveTab(currentIndex(), currentIndex() - 1);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::moveTabRight()
|
||||
{
|
||||
if (currentIndex() == count() - 1) {
|
||||
return;
|
||||
}
|
||||
tabBar()->moveTab(currentIndex(), currentIndex() + 1);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::setNavigationBehavior(int behavior)
|
||||
{
|
||||
_newTabBehavior = static_cast<NewTabBehavior>(behavior);
|
||||
}
|
||||
|
||||
void TabbedViewContainer::moveToNewTab(TerminalDisplay *display)
|
||||
{
|
||||
// Ensure that the current terminal is not maximized so that the other views will be shown properly
|
||||
activeViewSplitter()->clearMaximized();
|
||||
addView(display);
|
||||
}
|
||||
|
||||
#include "moc_ViewContainer.cpp"
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2006-2008 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef VIEWCONTAINER_H
|
||||
#define VIEWCONTAINER_H
|
||||
|
||||
// Qt
|
||||
#include <QObject>
|
||||
#include <QTabWidget>
|
||||
|
||||
// Konsole
|
||||
#include "ViewManager.h"
|
||||
#include "session/Session.h"
|
||||
|
||||
// Qt
|
||||
class QPoint;
|
||||
class QToolButton;
|
||||
class QMenu;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
class ViewProperties;
|
||||
class ViewManager;
|
||||
class TabbedViewContainer;
|
||||
|
||||
/**
|
||||
* An interface for container widgets which can hold one or more views.
|
||||
*
|
||||
* The container widget typically displays a list of the views which
|
||||
* it has and provides a means of switching between them.
|
||||
*
|
||||
* Subclasses should reimplement the addViewWidget() and removeViewWidget() functions
|
||||
* to actually add or remove view widgets from the container widget, as well
|
||||
* as updating any navigation aids.
|
||||
*/
|
||||
class KONSOLEPRIVATE_EXPORT TabbedViewContainer : public QTabWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a new view container with the specified parent.
|
||||
*
|
||||
* @param connectedViewManager Connect the new view to this manager
|
||||
* @param parent The parent object of the container
|
||||
*/
|
||||
TabbedViewContainer(ViewManager *connectedViewManager, QWidget *parent);
|
||||
|
||||
/**
|
||||
* Called when the ViewContainer is destroyed. When reimplementing this in
|
||||
* subclasses, use object->deleteLater() to delete any widgets or other objects
|
||||
* instead of 'delete object'.
|
||||
*/
|
||||
~TabbedViewContainer() override;
|
||||
|
||||
/** Adds a new view to the container widget */
|
||||
void addView(TerminalDisplay *view);
|
||||
void addSplitter(ViewSplitter *viewSplitter, int index = -1);
|
||||
|
||||
/** splits the currently focused Splitter */
|
||||
void splitView(TerminalDisplay *view, Qt::Orientation orientation);
|
||||
|
||||
void setTabActivity(int index, bool activity);
|
||||
|
||||
/** Sets tab title to item title if the view is active */
|
||||
void updateTitle(ViewProperties *item);
|
||||
/** Sets tab color to item color if the view is active */
|
||||
void updateColor(ViewProperties *item);
|
||||
/** Sets tab icon to item icon if the view is active */
|
||||
void updateIcon(ViewProperties *item);
|
||||
/** Sets tab activity status if the tab is not active */
|
||||
void updateActivity(ViewProperties *item);
|
||||
/** Sets tab notification */
|
||||
void updateNotification(ViewProperties *item, Konsole::Session::Notification notification, bool enabled);
|
||||
/** Sets tab special state (copy input or read-only) */
|
||||
void updateSpecialState(ViewProperties *item);
|
||||
|
||||
/** Changes the active view to the next view */
|
||||
void activateNextView();
|
||||
|
||||
/** Changes the active view to the previous view */
|
||||
void activatePreviousView();
|
||||
|
||||
/** Changes the active view to the last view */
|
||||
void activateLastView();
|
||||
|
||||
void setCssFromFile(const QUrl &url);
|
||||
|
||||
ViewSplitter *activeViewSplitter();
|
||||
/**
|
||||
* This enum describes the directions
|
||||
* in which views can be re-arranged within the container
|
||||
* using the moveActiveView() method.
|
||||
*/
|
||||
enum MoveDirection {
|
||||
/** Moves the view to the left. */
|
||||
MoveViewLeft,
|
||||
/** Moves the view to the right. */
|
||||
MoveViewRight,
|
||||
};
|
||||
|
||||
/**
|
||||
* Moves the active view within the container and
|
||||
* updates the order in which the views are shown
|
||||
* in the container's navigation widget.
|
||||
*
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
void moveActiveView(MoveDirection direction);
|
||||
|
||||
/** Sets the menu to be shown when the new view button is clicked.
|
||||
* Only valid if the QuickNewView feature is enabled.
|
||||
* The default implementation does nothing. */
|
||||
// TODO: Re-enable this later.
|
||||
// void setNewViewMenu(QMenu *menu);
|
||||
void renameTab(int index);
|
||||
ViewManager *connectedViewManager();
|
||||
void currentTabChanged(int index);
|
||||
void closeCurrentTab();
|
||||
void wheelScrolled(int delta);
|
||||
void currentSessionControllerChanged(SessionController *controller);
|
||||
void tabDoubleClicked(int index);
|
||||
void openTabContextMenu(const QPoint &point);
|
||||
void setNavigationVisibility(ViewManager::NavigationVisibility navigationVisibility);
|
||||
void moveTabToWindow(int index, QWidget *window);
|
||||
|
||||
void toggleMaximizeCurrentTerminal();
|
||||
void toggleZoomMaximizeCurrentTerminal();
|
||||
/* return the widget(int index) casted to TerminalDisplay*
|
||||
*
|
||||
* The only thing that this class holds are TerminalDisplays, so
|
||||
* this is the only thing that should be used to retrieve widgets.
|
||||
*/
|
||||
ViewSplitter *viewSplitterAt(int index);
|
||||
|
||||
ViewSplitter *findSplitter(int id);
|
||||
|
||||
/**
|
||||
* Returns the number of split views (i.e. TerminalDisplay widgets)
|
||||
* in this tab; if there are no split views, 1 is returned.
|
||||
*/
|
||||
int currentTabViewCount();
|
||||
|
||||
void connectTerminalDisplay(TerminalDisplay *display);
|
||||
void disconnectTerminalDisplay(TerminalDisplay *display);
|
||||
void moveTabLeft();
|
||||
void moveTabRight();
|
||||
|
||||
/**
|
||||
* This enum describes where newly created tab should be placed.
|
||||
*/
|
||||
enum NewTabBehavior {
|
||||
/** Put newly created tab at the end. */
|
||||
PutNewTabAtTheEnd = 0,
|
||||
/** Put newly created tab right after current tab. */
|
||||
PutNewTabAfterCurrentTab = 1,
|
||||
};
|
||||
|
||||
void setNavigationBehavior(int behavior);
|
||||
void terminalDisplayDropped(TerminalDisplay *terminalDisplay);
|
||||
|
||||
void moveToNewTab(TerminalDisplay *display);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
/** Emitted when the container has no more children */
|
||||
void empty(TabbedViewContainer *container);
|
||||
|
||||
/** Emitted when the user requests to open a new view */
|
||||
void newViewRequest();
|
||||
|
||||
/** Requests creation of a new view, with the selected profile. */
|
||||
void newViewWithProfileRequest(const QExplicitlySharedDataPointer<Profile> &profile);
|
||||
|
||||
/** a terminalDisplay was dropped in a child Splitter */
|
||||
|
||||
/**
|
||||
* Emitted when the user requests to move a view from another container
|
||||
* into this container. If 'success' is set to true by a connected slot
|
||||
* then the original view will be removed.
|
||||
*
|
||||
* @param index Index at which to insert the new view in the container
|
||||
* or -1 to append it. This index should be passed to addView() when
|
||||
* the new view has been created.
|
||||
* @param sessionControllerId The identifier of the view.
|
||||
*/
|
||||
void moveViewRequest(int index, int sessionControllerId);
|
||||
|
||||
/** Emitted when the active view changes */
|
||||
void activeViewChanged(TerminalDisplay *view);
|
||||
|
||||
/** Emitted when a view is added to the container. */
|
||||
void viewAdded(TerminalDisplay *view);
|
||||
|
||||
/** Emitted when a view is removed from container. */
|
||||
void viewRemoved();
|
||||
|
||||
/** detach the specific tab */
|
||||
void detachTab(int tabIdx);
|
||||
|
||||
/** set the color tab */
|
||||
void setColor(int index, const QColor &color);
|
||||
|
||||
/** remove the color tab */
|
||||
void removeColor(int idx);
|
||||
|
||||
protected:
|
||||
// close tabs and unregister
|
||||
void closeTerminalTab(int idx);
|
||||
|
||||
void keyReleaseEvent(QKeyEvent *event) override;
|
||||
private Q_SLOTS:
|
||||
void viewDestroyed(QObject *view);
|
||||
void konsoleConfigChanged();
|
||||
void activateView(const QString &xdgActivationToken);
|
||||
|
||||
private:
|
||||
void forgetView();
|
||||
|
||||
struct TabIconState {
|
||||
TabIconState()
|
||||
: readOnly(false)
|
||||
, broadcast(false)
|
||||
, notification(Session::NoNotification)
|
||||
{
|
||||
}
|
||||
|
||||
bool readOnly;
|
||||
bool broadcast;
|
||||
Session::Notification notification;
|
||||
|
||||
bool isAnyStateActive() const
|
||||
{
|
||||
return readOnly || broadcast || (notification != Session::NoNotification);
|
||||
}
|
||||
};
|
||||
|
||||
bool _stylesheetSet = false;
|
||||
|
||||
QHash<const QWidget *, TabIconState> _tabIconState;
|
||||
ViewManager *_connectedViewManager;
|
||||
QMenu *_contextPopupMenu;
|
||||
QToolButton *_newTabButton;
|
||||
QToolButton *_closeTabButton;
|
||||
int _contextMenuTabIndex;
|
||||
NewTabBehavior _newTabBehavior;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // VIEWCONTAINER_H
|
||||
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2006-2008 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "widgets/ViewSplitter.h"
|
||||
#include "KonsoleSettings.h"
|
||||
|
||||
// Qt
|
||||
#include <QApplication>
|
||||
#include <QChildEvent>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QMimeData>
|
||||
|
||||
// C++
|
||||
#include <memory>
|
||||
|
||||
// Konsole
|
||||
#include "terminalDisplay/TerminalDisplay.h"
|
||||
#include "terminalDisplay/TerminalFonts.h"
|
||||
#include "terminalDisplay/TerminalScrollBar.h"
|
||||
#include "widgets/ViewContainer.h"
|
||||
|
||||
using Konsole::TerminalDisplay;
|
||||
using Konsole::ViewSplitter;
|
||||
|
||||
bool ViewSplitter::m_drawTopLevelHandler;
|
||||
Qt::Orientation ViewSplitter::m_topLevelHandlerDrawnOrientation;
|
||||
int ViewSplitter::lastSplitterId = -1;
|
||||
|
||||
// TODO: Connect the TerminalDisplay destroyed signal here.
|
||||
|
||||
namespace
|
||||
{
|
||||
int calculateHandleWidth(int settingsEnum)
|
||||
{
|
||||
switch (settingsEnum) {
|
||||
case Konsole::KonsoleSettings::SplitDragHandleLarge:
|
||||
return 10;
|
||||
case Konsole::KonsoleSettings::SplitDragHandleMedium:
|
||||
return 5;
|
||||
case Konsole::KonsoleSettings::SplitDragHandleSmall:
|
||||
return 1;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ViewSplitter::ViewSplitter(QWidget *parent)
|
||||
: QSplitter(parent)
|
||||
, _id(++lastSplitterId)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
connect(KonsoleSettings::self(), &KonsoleSettings::configChanged, this, [this] {
|
||||
setHandleWidth(calculateHandleWidth(KonsoleSettings::self()->splitDragHandleSize()));
|
||||
});
|
||||
}
|
||||
|
||||
/* This function is called on the toplevel splitter, we need to look at the actual ViewSplitter inside it */
|
||||
void ViewSplitter::adjustActiveTerminalDisplaySize(int percentage)
|
||||
{
|
||||
auto focusedTerminalDisplay = activeTerminalDisplay();
|
||||
Q_ASSERT(focusedTerminalDisplay);
|
||||
|
||||
auto parentSplitter = qobject_cast<ViewSplitter *>(focusedTerminalDisplay->parent());
|
||||
const int containerIndex = parentSplitter->indexOf(activeTerminalDisplay());
|
||||
Q_ASSERT(containerIndex != -1);
|
||||
|
||||
QList<int> containerSizes = parentSplitter->sizes();
|
||||
|
||||
const int oldSize = containerSizes[containerIndex];
|
||||
const auto newSize = static_cast<int>(oldSize * (1.0 + percentage / 100.0));
|
||||
const int perContainerDelta = (count() == 1) ? 0 : ((newSize - oldSize) / (count() - 1)) * (-1);
|
||||
|
||||
for (int &size : containerSizes) {
|
||||
size += perContainerDelta;
|
||||
}
|
||||
containerSizes[containerIndex] = newSize;
|
||||
|
||||
parentSplitter->setSizes(containerSizes);
|
||||
}
|
||||
|
||||
// Get the first splitter that's a parent of the current focused widget.
|
||||
ViewSplitter *ViewSplitter::activeSplitter()
|
||||
{
|
||||
QWidget *widget = focusWidget() != nullptr ? focusWidget() : this;
|
||||
|
||||
ViewSplitter *splitter = nullptr;
|
||||
|
||||
while ((splitter == nullptr) && (widget != nullptr)) {
|
||||
splitter = qobject_cast<ViewSplitter *>(widget);
|
||||
widget = widget->parentWidget();
|
||||
}
|
||||
|
||||
Q_ASSERT(splitter);
|
||||
return splitter;
|
||||
}
|
||||
|
||||
void ViewSplitter::updateSizes()
|
||||
{
|
||||
const int space = (orientation() == Qt::Horizontal ? width() : height()) / count();
|
||||
setSizes(QVector<int>(count(), space).toList());
|
||||
}
|
||||
|
||||
void ViewSplitter::addTerminalDisplay(TerminalDisplay *terminalDisplay, Qt::Orientation containerOrientation, AddBehavior behavior)
|
||||
{
|
||||
ViewSplitter *splitter = activeSplitter();
|
||||
const int currentIndex = splitter->activeTerminalDisplay() == nullptr ? splitter->count() : splitter->indexOf(splitter->activeTerminalDisplay());
|
||||
|
||||
if (splitter->count() < 2) {
|
||||
splitter->insertWidget(behavior == AddBehavior::AddBefore ? currentIndex : currentIndex + 1, terminalDisplay);
|
||||
splitter->setOrientation(containerOrientation);
|
||||
splitter->updateSizes();
|
||||
} else if (containerOrientation == splitter->orientation()) {
|
||||
splitter->insertWidget(behavior == AddBehavior::AddBefore ? currentIndex : currentIndex + 1, terminalDisplay);
|
||||
splitter->updateSizes();
|
||||
} else {
|
||||
QList<int> sizes = splitter->sizes();
|
||||
auto newSplitter = new ViewSplitter();
|
||||
TerminalDisplay *oldTerminalDisplay = splitter->activeTerminalDisplay();
|
||||
const int oldContainerIndex = splitter->indexOf(oldTerminalDisplay);
|
||||
splitter->m_blockPropagatedDeletion = true;
|
||||
newSplitter->addWidget(behavior == AddBehavior::AddBefore ? terminalDisplay : oldTerminalDisplay);
|
||||
newSplitter->addWidget(behavior == AddBehavior::AddBefore ? oldTerminalDisplay : terminalDisplay);
|
||||
newSplitter->setOrientation(containerOrientation);
|
||||
newSplitter->show();
|
||||
splitter->insertWidget(oldContainerIndex, newSplitter);
|
||||
splitter->m_blockPropagatedDeletion = false;
|
||||
splitter->setSizes(sizes);
|
||||
newSplitter->updateSizes();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewSplitter::addTerminalDisplay(TerminalDisplay *terminalDisplay, int index)
|
||||
{
|
||||
auto toplevelSplitter = getToplevelSplitter();
|
||||
|
||||
if (index == -1)
|
||||
index = count();
|
||||
|
||||
if (toplevelSplitter->count() == 2 && toplevelSplitter == qobject_cast<ViewSplitter *>(parent()) && toplevelSplitter->indexOf(terminalDisplay) != -1) {
|
||||
QVector<QWidget *> childWidgets;
|
||||
|
||||
for (int i = 0; i < count(); ++i) {
|
||||
childWidgets.append(widget(i));
|
||||
}
|
||||
|
||||
childWidgets.insert(index, terminalDisplay);
|
||||
|
||||
for (auto child : childWidgets) {
|
||||
toplevelSplitter->addWidget(child);
|
||||
}
|
||||
} else {
|
||||
insertWidget(index, terminalDisplay);
|
||||
}
|
||||
|
||||
updateSizes();
|
||||
}
|
||||
|
||||
void ViewSplitter::addSplitter(ViewSplitter *splitter, int index)
|
||||
{
|
||||
if (index == -1)
|
||||
index = count();
|
||||
|
||||
m_blockPropagatedDeletion = true;
|
||||
|
||||
if (splitter->orientation() == orientation()) {
|
||||
QVector<QWidget *> children;
|
||||
|
||||
for (int i = 0; i < splitter->count(); ++i) {
|
||||
children.append(splitter->widget(i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
insertWidget(index + i, children[i]);
|
||||
}
|
||||
} else {
|
||||
insertWidget(index, splitter);
|
||||
}
|
||||
|
||||
m_blockPropagatedDeletion = false;
|
||||
updateSizes();
|
||||
}
|
||||
|
||||
void ViewSplitter::childEvent(QChildEvent *event)
|
||||
{
|
||||
QSplitter::childEvent(event);
|
||||
|
||||
if (event->removed()) {
|
||||
if (count() == 0) {
|
||||
auto *parent_splitter = qobject_cast<ViewSplitter *>(parent());
|
||||
if (parent_splitter != nullptr) {
|
||||
setParent(nullptr);
|
||||
}
|
||||
deleteLater();
|
||||
} else if (count() == 1) {
|
||||
if (!m_blockPropagatedDeletion) {
|
||||
auto *parent_splitter = qobject_cast<ViewSplitter *>(parent());
|
||||
if (parent_splitter) {
|
||||
parent_splitter->m_blockPropagatedDeletion = true;
|
||||
|
||||
// Force recalculation of sizes to take into account recent
|
||||
// setVisible(true) calls due to a clearMaximize() upon
|
||||
// sessionFinished. Without the refresh() call, the size of
|
||||
// a previously hidden splitter could still be 0. The
|
||||
// documentation of refresh() says "You should not need to
|
||||
// call this function", but it seems we do.
|
||||
parent_splitter->refresh();
|
||||
|
||||
const auto sizes = parent_splitter->sizes();
|
||||
auto *wdg = widget(0);
|
||||
const int oldContainerIndex = parent_splitter->indexOf(this);
|
||||
parent_splitter->replaceWidget(oldContainerIndex, wdg);
|
||||
parent_splitter->m_blockPropagatedDeletion = false;
|
||||
parent_splitter->setSizes(sizes);
|
||||
connect(this, &ViewSplitter::destroyed, wdg, qOverload<>(&QWidget::setFocus));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto terminals = getToplevelSplitter()->findChildren<TerminalDisplay *>();
|
||||
for (auto terminal : terminals) {
|
||||
terminal->headerBar()->applyVisibilitySettings();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewSplitter::handleFocusDirection(Qt::Orientation orientation, int direction)
|
||||
{
|
||||
auto terminalDisplay = activeTerminalDisplay();
|
||||
auto parentSplitter = qobject_cast<ViewSplitter *>(terminalDisplay->parentWidget());
|
||||
auto topSplitter = parentSplitter->getToplevelSplitter();
|
||||
|
||||
// Find the theme's splitter width + extra space to find valid terminal
|
||||
// See https://bugs.kde.org/show_bug.cgi?id=411387 for more info
|
||||
const auto handleWidth = parentSplitter->handleWidth() + 3;
|
||||
|
||||
const auto start = QPoint(terminalDisplay->x(), terminalDisplay->y());
|
||||
const auto startMapped = parentSplitter->mapTo(topSplitter, start);
|
||||
|
||||
const int newX = orientation != Qt::Horizontal ? startMapped.x() + handleWidth
|
||||
: direction == 1 ? startMapped.x() + terminalDisplay->width() + handleWidth
|
||||
: startMapped.x() - handleWidth;
|
||||
|
||||
const int newY = orientation != Qt::Vertical ? startMapped.y() + handleWidth
|
||||
: direction == 1 ? startMapped.y() + terminalDisplay->height() + handleWidth
|
||||
: startMapped.y() - handleWidth;
|
||||
|
||||
const auto newPoint = QPoint(newX, newY);
|
||||
auto child = topSplitter->childAt(newPoint);
|
||||
|
||||
TerminalDisplay *focusTerminal = nullptr;
|
||||
if (auto *terminal = qobject_cast<TerminalDisplay *>(child)) {
|
||||
focusTerminal = terminal;
|
||||
} else if (qobject_cast<QSplitterHandle *>(child) != nullptr) {
|
||||
auto targetSplitter = qobject_cast<QSplitter *>(child->parent());
|
||||
focusTerminal = qobject_cast<TerminalDisplay *>(targetSplitter->widget(0));
|
||||
} else if (qobject_cast<QWidget *>(child) != nullptr) {
|
||||
while (child != nullptr && focusTerminal == nullptr) {
|
||||
focusTerminal = qobject_cast<TerminalDisplay *>(child->parentWidget());
|
||||
child = child->parentWidget();
|
||||
}
|
||||
}
|
||||
if (focusTerminal != nullptr) {
|
||||
focusTerminal->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewSplitter::focusUp()
|
||||
{
|
||||
handleFocusDirection(Qt::Vertical, -1);
|
||||
}
|
||||
|
||||
void ViewSplitter::focusDown()
|
||||
{
|
||||
handleFocusDirection(Qt::Vertical, +1);
|
||||
}
|
||||
|
||||
void ViewSplitter::focusLeft()
|
||||
{
|
||||
handleFocusDirection(Qt::Horizontal, -1);
|
||||
}
|
||||
|
||||
void ViewSplitter::focusRight()
|
||||
{
|
||||
handleFocusDirection(Qt::Horizontal, +1);
|
||||
}
|
||||
|
||||
TerminalDisplay *ViewSplitter::activeTerminalDisplay() const
|
||||
{
|
||||
auto focusedWidget = focusWidget();
|
||||
auto focusedTerminalDisplay = qobject_cast<TerminalDisplay *>(focusedWidget);
|
||||
|
||||
// TD's child can be focused - try to find parent.
|
||||
while (focusedTerminalDisplay == nullptr && focusedWidget != nullptr && focusedWidget != this) {
|
||||
focusedWidget = focusedWidget->parentWidget();
|
||||
focusedTerminalDisplay = qobject_cast<TerminalDisplay *>(focusedWidget);
|
||||
}
|
||||
|
||||
return focusedTerminalDisplay != nullptr ? focusedTerminalDisplay : findChild<TerminalDisplay *>();
|
||||
}
|
||||
|
||||
void ViewSplitter::toggleMaximizeCurrentTerminal()
|
||||
{
|
||||
m_terminalMaximized = !m_terminalMaximized;
|
||||
handleMinimizeMaximize(m_terminalMaximized, false);
|
||||
}
|
||||
|
||||
void ViewSplitter::toggleZoomMaximizeCurrentTerminal()
|
||||
{
|
||||
m_terminalMaximized = !m_terminalMaximized;
|
||||
handleMinimizeMaximize(m_terminalMaximized, true);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void restoreAll(QList<TerminalDisplay *> &&terminalDisplays, QList<ViewSplitter *> &&splitters)
|
||||
{
|
||||
for (auto splitter : splitters) {
|
||||
splitter->setVisible(true);
|
||||
}
|
||||
for (auto terminalDisplay : terminalDisplays) {
|
||||
terminalDisplay->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewSplitter::hideRecurse(TerminalDisplay *currentTerminalDisplay)
|
||||
{
|
||||
bool allHidden = true;
|
||||
|
||||
for (int i = 0, end = count(); i < end; i++) {
|
||||
if (auto *maybeSplitter = qobject_cast<ViewSplitter *>(widget(i))) {
|
||||
allHidden = maybeSplitter->hideRecurse(currentTerminalDisplay) && allHidden;
|
||||
continue;
|
||||
}
|
||||
if (auto maybeTerminalDisplay = qobject_cast<TerminalDisplay *>(widget(i))) {
|
||||
if (maybeTerminalDisplay == currentTerminalDisplay) {
|
||||
allHidden = false;
|
||||
} else {
|
||||
maybeTerminalDisplay->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allHidden) {
|
||||
setVisible(false);
|
||||
}
|
||||
return allHidden;
|
||||
}
|
||||
|
||||
void ViewSplitter::handleMinimizeMaximize(bool maximize, bool zoom)
|
||||
{
|
||||
auto topLevelSplitter = getToplevelSplitter();
|
||||
auto currentTerminalDisplay = topLevelSplitter->activeTerminalDisplay();
|
||||
currentTerminalDisplay->setExpandedMode(maximize);
|
||||
|
||||
auto currentTerminalFont = currentTerminalDisplay->terminalFont()->getVTFont();
|
||||
|
||||
if (maximize) {
|
||||
if (zoom) {
|
||||
fontSizeBeforeMaximization = currentTerminalFont.pointSizeF();
|
||||
auto headerBar = currentTerminalDisplay->headerBar();
|
||||
auto headerBarHeight = headerBar->isVisible() ? headerBar->height() : 0;
|
||||
auto scrollBar = currentTerminalDisplay->scrollBar();
|
||||
auto scrollBarWidth = scrollBar->scrollBarPosition() != Enum::ScrollBarHidden ? scrollBar->width() : 0;
|
||||
|
||||
// This is very inexact, which is fine, because the aspect ratio of
|
||||
// both the scaled font and the terminal can differ anyway.
|
||||
auto scaleFactor = std::min(
|
||||
(topLevelSplitter->width() - scrollBarWidth)
|
||||
/ (currentTerminalDisplay->width() - scrollBarWidth),
|
||||
|
||||
(topLevelSplitter->height() - headerBarHeight)
|
||||
/ (currentTerminalDisplay->height() - headerBarHeight)
|
||||
);
|
||||
auto newSize = int(fontSizeBeforeMaximization * scaleFactor * 0.97);
|
||||
|
||||
if (newSize > fontSizeBeforeMaximization) {
|
||||
currentTerminalFont.setPointSizeF(newSize);
|
||||
currentTerminalDisplay->terminalFont()->setVTFont(currentTerminalFont);
|
||||
}
|
||||
} else {
|
||||
fontSizeBeforeMaximization = 0;
|
||||
}
|
||||
|
||||
for (int i = 0, end = topLevelSplitter->count(); i < end; i++) {
|
||||
auto widgetAt = topLevelSplitter->widget(i);
|
||||
if (auto *maybeSplitter = qobject_cast<ViewSplitter *>(widgetAt)) {
|
||||
maybeSplitter->hideRecurse(currentTerminalDisplay);
|
||||
}
|
||||
if (auto maybeTerminalDisplay = qobject_cast<TerminalDisplay *>(widgetAt)) {
|
||||
if (maybeTerminalDisplay != currentTerminalDisplay) {
|
||||
maybeTerminalDisplay->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// When restoring to un-maximzed state, it doesn't matter if this is done through
|
||||
// toggleMaximizeCurrentTerminal or toggleZoomMaximizeCurrentTerminal.
|
||||
// Only the method which was used to maximize, determines if the font size needs
|
||||
// to be restored.
|
||||
if (fontSizeBeforeMaximization) {
|
||||
currentTerminalFont.setPointSizeF(fontSizeBeforeMaximization);
|
||||
currentTerminalDisplay->terminalFont()->setVTFont(currentTerminalFont);
|
||||
}
|
||||
|
||||
restoreAll(topLevelSplitter->findChildren<TerminalDisplay *>(), topLevelSplitter->findChildren<ViewSplitter *>());
|
||||
}
|
||||
}
|
||||
|
||||
void ViewSplitter::clearMaximized()
|
||||
{
|
||||
ViewSplitter *top = getToplevelSplitter();
|
||||
Q_ASSERT(top);
|
||||
if (top->terminalMaximized()) {
|
||||
top->toggleMaximizeCurrentTerminal();
|
||||
}
|
||||
}
|
||||
|
||||
ViewSplitter *ViewSplitter::getToplevelSplitter()
|
||||
{
|
||||
ViewSplitter *current = this;
|
||||
while (qobject_cast<ViewSplitter *>(current->parentWidget()) != nullptr) {
|
||||
current = qobject_cast<ViewSplitter *>(current->parentWidget());
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
ViewSplitter *ViewSplitter::getChildSplitter(int id)
|
||||
{
|
||||
for (auto childSplitter : findChildren<ViewSplitter *>()) {
|
||||
if (childSplitter->id() == id)
|
||||
return childSplitter;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString ViewSplitter::getChildWidgetsLayout()
|
||||
{
|
||||
QString layoutString;
|
||||
|
||||
for (int i = 0; i < count(); ++i) {
|
||||
if (auto v = qobject_cast<TerminalDisplay *>(widget(i)))
|
||||
layoutString += QString::number(v->id());
|
||||
else if (auto s = qobject_cast<ViewSplitter *>(widget(i)))
|
||||
layoutString += s->getChildWidgetsLayout();
|
||||
|
||||
layoutString += QLatin1Char('|');
|
||||
}
|
||||
|
||||
layoutString.removeLast();
|
||||
|
||||
if (orientation() == Qt::Orientation::Horizontal)
|
||||
layoutString = QLatin1Char('[') + layoutString + QLatin1Char(']');
|
||||
else
|
||||
layoutString = QLatin1Char('{') + layoutString + QLatin1Char('}');
|
||||
|
||||
return QStringLiteral("(%1)").arg(id()) + layoutString;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
TerminalDisplay *currentDragTarget = nullptr;
|
||||
}
|
||||
|
||||
void Konsole::ViewSplitter::dragEnterEvent(QDragEnterEvent *ev)
|
||||
{
|
||||
const auto dragId = QStringLiteral("konsole/terminal_display");
|
||||
if (ev->mimeData()->hasFormat(dragId)) {
|
||||
auto other_pid = ev->mimeData()->data(dragId).toInt();
|
||||
// don't accept the drop if it's another instance of konsole
|
||||
if (qApp->applicationPid() != other_pid) {
|
||||
return;
|
||||
}
|
||||
if (getToplevelSplitter()->terminalMaximized()) {
|
||||
return;
|
||||
}
|
||||
ev->accept();
|
||||
}
|
||||
}
|
||||
|
||||
void Konsole::ViewSplitter::dragMoveEvent(QDragMoveEvent *ev)
|
||||
{
|
||||
auto currentWidget = childAt(ev->position().toPoint());
|
||||
if (auto terminal = qobject_cast<TerminalDisplay *>(currentWidget)) {
|
||||
if ((currentDragTarget != nullptr) && currentDragTarget != terminal) {
|
||||
currentDragTarget->hideDragTarget();
|
||||
}
|
||||
if (terminal == ev->source()) {
|
||||
return;
|
||||
}
|
||||
currentDragTarget = terminal;
|
||||
auto localPos = currentDragTarget->mapFromParent(ev->position().toPoint());
|
||||
currentDragTarget->showDragTarget(localPos);
|
||||
}
|
||||
}
|
||||
|
||||
void Konsole::ViewSplitter::dragLeaveEvent(QDragLeaveEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
if (currentDragTarget != nullptr) {
|
||||
currentDragTarget->hideDragTarget();
|
||||
currentDragTarget = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Konsole::ViewSplitter::dropEvent(QDropEvent *ev)
|
||||
{
|
||||
if (ev->mimeData()->hasFormat(QStringLiteral("konsole/terminal_display"))) {
|
||||
if (getToplevelSplitter()->terminalMaximized()) {
|
||||
return;
|
||||
}
|
||||
if (currentDragTarget != nullptr) {
|
||||
m_blockPropagatedDeletion = true;
|
||||
|
||||
currentDragTarget->hideDragTarget();
|
||||
auto source = qobject_cast<TerminalDisplay *>(ev->source());
|
||||
source->setVisible(false);
|
||||
source->setParent(nullptr);
|
||||
|
||||
currentDragTarget->setFocus(Qt::OtherFocusReason);
|
||||
const auto droppedEdge = currentDragTarget->droppedEdge();
|
||||
|
||||
AddBehavior behavior = droppedEdge == Qt::LeftEdge || droppedEdge == Qt::TopEdge ? AddBehavior::AddBefore : AddBehavior::AddAfter;
|
||||
|
||||
Qt::Orientation orientation = droppedEdge == Qt::LeftEdge || droppedEdge == Qt::RightEdge ? Qt::Horizontal : Qt::Vertical;
|
||||
|
||||
// Add the display so it can be counted correctly by ViewManager
|
||||
addTerminalDisplay(source, orientation, behavior);
|
||||
|
||||
// topLevel is the splitter that's connected with the ViewManager
|
||||
// that in turn can call the SessionController.
|
||||
Q_EMIT getToplevelSplitter()->terminalDisplayDropped(source);
|
||||
source->setVisible(true);
|
||||
currentDragTarget = nullptr;
|
||||
|
||||
m_blockPropagatedDeletion = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Konsole::ViewSplitter::showEvent(QShowEvent *)
|
||||
{
|
||||
// Fixes lost focus in background mode.
|
||||
setFocusProxy(activeSplitter()->activeTerminalDisplay());
|
||||
}
|
||||
|
||||
QPoint Konsole::ViewSplitter::mapToTopLevel(const QPoint &p)
|
||||
{
|
||||
auto parentSplitter = qobject_cast<ViewSplitter *>(parent());
|
||||
if (parentSplitter) {
|
||||
auto next_pos = mapToParent(p);
|
||||
return parentSplitter->mapToTopLevel(next_pos);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
QPoint Konsole::ViewSplitter::mapFromTopLevel(const QPoint &p)
|
||||
{
|
||||
auto parentSplitter = qobject_cast<ViewSplitter *>(parent());
|
||||
if (parentSplitter) {
|
||||
return mapFromParent(parentSplitter->mapFromTopLevel(p));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
Konsole::ViewSplitterHandle::ViewSplitterHandle(Qt::Orientation orientation, QSplitter *parent)
|
||||
: QSplitterHandle(orientation, parent)
|
||||
, mouseReleaseEventCounter(0)
|
||||
{
|
||||
}
|
||||
|
||||
QSplitterHandle *ViewSplitter::createHandle()
|
||||
{
|
||||
return new ViewSplitterHandle(orientation(), this);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
QList<int> allSplitterSizes;
|
||||
|
||||
int search_closest(const QList<int> &sorted_array, int x)
|
||||
{
|
||||
if (sorted_array.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto iter_geq = std::lower_bound(sorted_array.begin(), sorted_array.end(), x);
|
||||
|
||||
if (iter_geq == sorted_array.begin()) {
|
||||
return sorted_array[0];
|
||||
}
|
||||
|
||||
int a = *(iter_geq - 1);
|
||||
int b = *(iter_geq);
|
||||
|
||||
if (abs(x - a) < abs(x - b)) {
|
||||
return a;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
void Konsole::ViewSplitterHandle::mousePressEvent(QMouseEvent *ev)
|
||||
{
|
||||
auto parentSplitter = qobject_cast<ViewSplitter *>(parentWidget());
|
||||
auto topLevelSplitter = parentSplitter->getToplevelSplitter();
|
||||
|
||||
QList<ViewSplitter *> splitters = topLevelSplitter->findChildren<ViewSplitter *>();
|
||||
splitters.append(topLevelSplitter);
|
||||
|
||||
for (auto splitter : splitters) {
|
||||
if (splitter->orientation() != orientation()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int delta = 0;
|
||||
for (auto point : splitter->sizes()) {
|
||||
delta += point;
|
||||
QPoint thisPoint = orientation() == Qt::Horizontal ? QPoint(delta, 0) : QPoint(0, delta);
|
||||
|
||||
QPoint splitterPos = splitter->mapToTopLevel(thisPoint);
|
||||
|
||||
const int ourPos = orientation() == Qt::Horizontal ? splitterPos.x() : splitterPos.y();
|
||||
|
||||
allSplitterSizes.push_back(ourPos);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(std::begin(allSplitterSizes), std::end(allSplitterSizes));
|
||||
|
||||
QPoint thisPoint = parentSplitter->mapToTopLevel(mapToParent(ev->pos()));
|
||||
const int thisValue = search_closest(allSplitterSizes, orientation() == Qt::Horizontal ? thisPoint.x() : thisPoint.y());
|
||||
allSplitterSizes.removeOne(thisValue);
|
||||
{ // context for the splitterSet temporary.
|
||||
auto splitterSet = QSet<int>(std::begin(allSplitterSizes), std::end(allSplitterSizes));
|
||||
allSplitterSizes = QList<int>(std::begin(splitterSet), std::end(splitterSet));
|
||||
}
|
||||
std::sort(std::begin(allSplitterSizes), std::end(allSplitterSizes));
|
||||
|
||||
mouseReleaseEventCounter = 0;
|
||||
|
||||
QSplitterHandle::mousePressEvent(ev);
|
||||
}
|
||||
|
||||
void Konsole::ViewSplitterHandle::mouseReleaseEvent(QMouseEvent *ev)
|
||||
{
|
||||
allSplitterSizes.clear();
|
||||
if (++mouseReleaseEventCounter > 1) {
|
||||
mouseDoubleClickEvent(ev);
|
||||
}
|
||||
QSplitterHandle::mouseReleaseEvent(ev);
|
||||
}
|
||||
|
||||
void Konsole::ViewSplitterHandle::mouseMoveEvent(QMouseEvent *ev)
|
||||
{
|
||||
ViewSplitter *parentSplitter = qobject_cast<ViewSplitter *>(parentWidget());
|
||||
|
||||
QPoint thisPoint = parentSplitter->mapToTopLevel(mapToParent(ev->pos()));
|
||||
|
||||
const int thisValue = orientation() == Qt::Horizontal ? thisPoint.x() : thisPoint.y();
|
||||
const int nearest = search_closest(allSplitterSizes, thisValue);
|
||||
const int threshould = qAbs(nearest - thisValue);
|
||||
if (threshould <= 20) {
|
||||
auto *thisSplitter = qobject_cast<ViewSplitter *>(splitter());
|
||||
QPoint localPoint = thisSplitter->mapFromTopLevel(orientation() == Qt::Horizontal ? QPoint(nearest, 0) : QPoint(0, nearest));
|
||||
moveSplitter(orientation() == Qt::Horizontal ? localPoint.x() : localPoint.y());
|
||||
return;
|
||||
}
|
||||
|
||||
mouseReleaseEventCounter = 0;
|
||||
|
||||
QSplitterHandle::mouseMoveEvent(ev);
|
||||
}
|
||||
|
||||
void Konsole::ViewSplitterHandle::mouseDoubleClickEvent(QMouseEvent *ev)
|
||||
{
|
||||
auto parentSplitter = qobject_cast<ViewSplitter *>(parentWidget());
|
||||
|
||||
if (parentSplitter->count() > 1) {
|
||||
for (int i = 1; i < parentSplitter->count(); i++) {
|
||||
if (parentSplitter->handle(i) != this) {
|
||||
continue;
|
||||
}
|
||||
if (orientation() == Qt::Horizontal) {
|
||||
moveSplitter(parentSplitter->widget(i - 1)->pos().x()
|
||||
+ ((parentSplitter->widget(i)->pos().x() + parentSplitter->widget(i)->width() - (parentSplitter->widget(i - 1)->pos().x())) / 2));
|
||||
} else {
|
||||
moveSplitter(parentSplitter->widget(i - 1)->pos().y()
|
||||
+ ((parentSplitter->widget(i)->pos().y() + parentSplitter->widget(i)->height() - (parentSplitter->widget(i - 1)->pos().y())) / 2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mouseReleaseEventCounter = 0;
|
||||
QSplitterHandle::mouseDoubleClickEvent(ev);
|
||||
}
|
||||
|
||||
#include "moc_ViewSplitter.cpp"
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2006-2008 Robert Knight <robertknight@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef VIEWSPLITTER_H
|
||||
#define VIEWSPLITTER_H
|
||||
|
||||
// Qt
|
||||
#include <QSplitter>
|
||||
#include <QSplitterHandle>
|
||||
|
||||
// Konsole
|
||||
#include "konsoleprivate_export.h"
|
||||
|
||||
class QDragMoveEvent;
|
||||
class QDragEnterEvent;
|
||||
class QDropEvent;
|
||||
class QDragLeaveEvent;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
class TerminalDisplay;
|
||||
|
||||
class ViewSplitterHandle : public QSplitterHandle
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ViewSplitterHandle(Qt::Orientation orientation, QSplitter *parent);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *ev) override;
|
||||
void mouseReleaseEvent(QMouseEvent *ev) override;
|
||||
void mouseMoveEvent(QMouseEvent *ev) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *ev) override;
|
||||
|
||||
private:
|
||||
/* For some reason, the first time we double-click on the splitter handle
|
||||
* the second mouse press event is not fired, nor is the double click event.
|
||||
* We use this counter to detect a double click. */
|
||||
int mouseReleaseEventCounter;
|
||||
};
|
||||
|
||||
/**
|
||||
* A splitter which holds a number of ViewContainer objects and allows
|
||||
* the user to control the size of each view container by dragging a splitter
|
||||
* bar between them.
|
||||
*
|
||||
* Each splitter can also contain child ViewSplitter widgets, allowing
|
||||
* for a hierarchy of view splitters and containers.
|
||||
*
|
||||
* The addContainer() method is used to split the existing view and
|
||||
* insert a new view container.
|
||||
* Containers can only be removed from the hierarchy by deleting them.
|
||||
*/
|
||||
class KONSOLEPRIVATE_EXPORT ViewSplitter : public QSplitter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ViewSplitter(QWidget *parent = nullptr);
|
||||
|
||||
enum class AddBehavior {
|
||||
AddBefore,
|
||||
AddAfter,
|
||||
};
|
||||
/**
|
||||
* Locates the child ViewSplitter widget which currently has the focus
|
||||
* and inserts the container into it.
|
||||
*
|
||||
* @param terminalDisplay The container to insert
|
||||
* @param containerOrientation Specifies whether the view should be split
|
||||
* horizontally or vertically. If the orientation
|
||||
* is the same as the ViewSplitter into which the
|
||||
* container is to be inserted, or if the splitter
|
||||
* has fewer than two child widgets then the container
|
||||
* will be added to that splitter. If the orientation
|
||||
* is different, then a new child splitter
|
||||
* will be created, into which the container will
|
||||
* be inserted.
|
||||
* @param behavior Specifies whether to add new terminal after current
|
||||
* tab or at end.
|
||||
*/
|
||||
void addTerminalDisplay(TerminalDisplay *terminalDisplay, Qt::Orientation containerOrientation, AddBehavior behavior = AddBehavior::AddAfter);
|
||||
|
||||
void addTerminalDisplay(TerminalDisplay *terminalDisplay, int index = -1);
|
||||
|
||||
void addSplitter(ViewSplitter *splitter, int index = -1);
|
||||
|
||||
/** Returns the child ViewSplitter widget which currently has the focus */
|
||||
ViewSplitter *activeSplitter();
|
||||
|
||||
/**
|
||||
* Returns the container which currently has the focus or 0 if none
|
||||
* of the immediate child containers have the focus. This does not
|
||||
* search through child splitters. activeSplitter() can be used
|
||||
* to search recursively through child splitters for the splitter
|
||||
* which currently has the focus.
|
||||
*
|
||||
* To find the currently active container, use
|
||||
* mySplitter->activeSplitter()->activeTerminalDisplay() where
|
||||
* mySplitter is the ViewSplitter widget at the top of the hierarchy.
|
||||
*/
|
||||
TerminalDisplay *activeTerminalDisplay() const;
|
||||
|
||||
/** Makes the current TerminalDisplay expanded to 100% of the view
|
||||
*/
|
||||
void toggleMaximizeCurrentTerminal();
|
||||
|
||||
/** Makes the current TerminalDisplay expanded to 100% of the view, while
|
||||
* scaling the font size
|
||||
*/
|
||||
void toggleZoomMaximizeCurrentTerminal();
|
||||
|
||||
/**
|
||||
* Can be called on any ViewSplitter to find the top level splitter and ensure
|
||||
* the active display isn't maximized. Do nothing if it's not maximized.
|
||||
*
|
||||
* Useful for ViewManager and TabbedViewContainer when removing or adding a
|
||||
* display to the hierarchy so that the layout is reflowed correctly.
|
||||
*/
|
||||
void clearMaximized();
|
||||
|
||||
/** returns the splitter that has no splitter as a parent. */
|
||||
ViewSplitter *getToplevelSplitter();
|
||||
|
||||
ViewSplitter *getChildSplitter(int id);
|
||||
|
||||
QString getChildWidgetsLayout();
|
||||
|
||||
/**
|
||||
* Changes the size of the specified @p container by a given @p percentage.
|
||||
* @p percentage may be positive ( in which case the size of the container
|
||||
* is increased ) or negative ( in which case the size of the container
|
||||
* is decreased ).
|
||||
*
|
||||
* The sizes of the remaining containers are increased or decreased
|
||||
* uniformly to maintain the width of the splitter.
|
||||
*/
|
||||
void adjustActiveTerminalDisplaySize(int percentage);
|
||||
|
||||
void focusUp();
|
||||
void focusDown();
|
||||
void focusLeft();
|
||||
void focusRight();
|
||||
|
||||
void handleFocusDirection(Qt::Orientation orientation, int direction);
|
||||
|
||||
void childEvent(QChildEvent *event) override;
|
||||
bool terminalMaximized() const
|
||||
{
|
||||
return m_terminalMaximized;
|
||||
}
|
||||
|
||||
QSplitterHandle *createHandle() override;
|
||||
|
||||
QPoint mapToTopLevel(const QPoint &p);
|
||||
QPoint mapFromTopLevel(const QPoint &p);
|
||||
|
||||
int id() const
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *ev) override;
|
||||
void dragMoveEvent(QDragMoveEvent *ev) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||
void dropEvent(QDropEvent *ev) override;
|
||||
void showEvent(QShowEvent *) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void terminalDisplayDropped(TerminalDisplay *terminalDisplay);
|
||||
|
||||
private:
|
||||
/** recursively walks the object tree looking for Splitters and
|
||||
* TerminalDisplays, hiding the ones that should be hidden.
|
||||
* If a terminal display is not hidden in a subtree, we cannot
|
||||
* hide the whole tree.
|
||||
*
|
||||
* @p currentTerminalDisplay the only terminal display that will still be visible.
|
||||
*/
|
||||
bool hideRecurse(TerminalDisplay *currentTerminalDisplay);
|
||||
|
||||
/** other classes should use clearmMaximized() */
|
||||
void handleMinimizeMaximize(bool maximize, bool zoom);
|
||||
|
||||
void updateSizes();
|
||||
bool m_terminalMaximized = false;
|
||||
qreal fontSizeBeforeMaximization = 0;
|
||||
bool m_blockPropagatedDeletion = false;
|
||||
|
||||
int _id;
|
||||
|
||||
static bool m_drawTopLevelHandler;
|
||||
static Qt::Orientation m_topLevelHandlerDrawnOrientation;
|
||||
static int lastSplitterId;
|
||||
};
|
||||
}
|
||||
#endif // VIEWSPLITTER_H
|
||||
Reference in New Issue
Block a user