diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -151,7 +151,7 @@ HistorySizeDialog.ui HistorySizeWidget.ui PrintOptions.ui - settings/FileLocationSettings.ui + settings/TemporaryFilesSettings.ui settings/GeneralSettings.ui settings/PartInfo.ui settings/ProfileSettings.ui @@ -175,7 +175,8 @@ Application.cpp MainWindow.cpp main.cpp - settings/FileLocationSettings.cpp + settings/ConfigurationDialog.cpp + settings/TemporaryFilesSettings.cpp settings/GeneralSettings.cpp settings/ProfileSettings.cpp settings/TabBarSettings.cpp) diff --git a/src/EditProfileGeneralPage.ui b/src/EditProfileGeneralPage.ui --- a/src/EditProfileGeneralPage.ui +++ b/src/EditProfileGeneralPage.ui @@ -305,7 +305,7 @@ - <html><head/><body><p><span style=" font-style:italic;">Settings → Configure Konsole → General → Use current window size on next startup</span> must be disabled for these entries to work.</p></body></html> + <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> Qt::RichText diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -57,7 +57,8 @@ #include "KonsoleSettings.h" #include "WindowSystemInfo.h" #include "TerminalDisplay.h" -#include "settings/FileLocationSettings.h" +#include "settings/ConfigurationDialog.h" +#include "settings/TemporaryFilesSettings.h" #include "settings/GeneralSettings.h" #include "settings/ProfileSettings.h" #include "settings/TabBarSettings.h" @@ -723,39 +724,39 @@ void MainWindow::showSettingsDialog(const bool showProfilePage) { - if (KConfigDialog::showDialog(QStringLiteral("settings"))) { + static ConfigurationDialog *confDialog = nullptr; + if (confDialog) { + confDialog->show(); return; } - KConfigDialog *settingsDialog = new KConfigDialog(this, QStringLiteral("settings"), KonsoleSettings::self()); - settingsDialog->setFaceType(KPageDialog::List); + confDialog = new ConfigurationDialog(this, KonsoleSettings::self()); - auto generalSettings = new GeneralSettings(settingsDialog); - settingsDialog->addPage(generalSettings, - i18nc("@title Preferences page name", "General"), - QStringLiteral("utilities-terminal")); + const QString generalPageName = i18nc("@title Preferences page name", "General"); + auto *generalPage = new KPageWidgetItem(new GeneralSettings(confDialog), generalPageName); + generalPage->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); + confDialog->addPage(generalPage, true); - auto profileSettings = new ProfileSettings(settingsDialog); - KPageWidgetItem *profilePage = settingsDialog->addPage(profileSettings, - i18nc("@title Preferences page name", - "Profiles"), - QStringLiteral("configure")); + const QString profilePageName = i18nc("@title Preferences page name", "Profiles"); + auto profilePage = new KPageWidgetItem(new ProfileSettings(confDialog), profilePageName); + profilePage->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); + confDialog->addPage(profilePage, true); - auto tabBarSettings = new TabBarSettings(settingsDialog); - settingsDialog->addPage(tabBarSettings, - i18nc("@title Preferences page name", "TabBar"), - QStringLiteral("system-run")); + const QString tabBarPageName = i18nc("@title Preferences page name", "Tab Bar"); + auto tabBarPage = new KPageWidgetItem(new TabBarSettings(confDialog), tabBarPageName); + tabBarPage->setIcon(QIcon::fromTheme(QStringLiteral("system-run"))); + confDialog->addPage(tabBarPage, true); - auto fileLocationSettings = new FileLocationSettings(settingsDialog); - settingsDialog->addPage(fileLocationSettings, - i18nc("@title Preferences page name", "File Location"), - QStringLiteral("configure")); + const QString temporaryFilesPageName = i18nc("@title Preferences page name", "Temporary Files"); + auto temporaryFilesPage = new KPageWidgetItem(new TemporaryFilesSettings(confDialog), temporaryFilesPageName); + temporaryFilesPage->setIcon(QIcon::fromTheme(QStringLiteral("inode-directory"))); + confDialog->addPage(temporaryFilesPage, true); if (showProfilePage) { - settingsDialog->setCurrentPage(profilePage); + confDialog->setCurrentPage(profilePage); } - settingsDialog->show(); + confDialog->show(); } void MainWindow::applyKonsoleSettings() diff --git a/src/settings/ConfigurationDialog.h b/src/settings/ConfigurationDialog.h new file mode 100644 --- /dev/null +++ b/src/settings/ConfigurationDialog.h @@ -0,0 +1,289 @@ +/* + Copyright 2019 by Mariusz Glebocki + + Based on KConfigDialog and KConfigDialogManager from KConfigWidgets + + Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net) + Copyright (C) 2003 Waldo Bastian + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. +*/ + +#ifndef CONFIGURATIONDIALOG_H +#define CONFIGURATIONDIALOG_H + +// Qt +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include + +// Konsole +#include "konsoleprivate_export.h" + +class KConfig; +class KCoreConfigSkeleton; +class KConfigDialogManager; + +namespace Konsole { + +class ConfigDialogButtonGroupManager; + +// KConfigDialog-like class, as the original KConfigDialog wraps +// all pages in QScrollArea. KConfigDialog, when fixed, should +// be source compatible with this class, so simple class replace +// should suffice. +class KONSOLEPRIVATE_EXPORT ConfigurationDialog: public KPageDialog +{ + Q_OBJECT + +Q_SIGNALS: + void widgetModified(); + void settingsChanged(); + +public: + explicit ConfigurationDialog(QWidget *parent, KCoreConfigSkeleton *config); + ~ConfigurationDialog() override = default; + + void addPage(KPageWidgetItem *item, bool manage); + +protected Q_SLOTS: + void updateButtons(); + void settingsChangedSlot(); + +protected: + void setApplyButtonEnabled(bool enabled); + void setRestoreDefaultsButtonEnabled(bool enabled); + void showEvent(QShowEvent *event) override; + +private: + Q_DISABLE_COPY(ConfigurationDialog) + + KConfigDialogManager *_manager = nullptr; + ConfigDialogButtonGroupManager *_groupManager = nullptr; + bool _shown = false; +}; + +// KConfigDialogManager-like class for managing QButtonGroups, +// which are not supported by KConfigDialogManager yet. When +// support will be available in minimum KF5 used by Konsole, +// just remove this class and all expressions which refer to it. +class ConfigDialogButtonGroupManager: public QObject +{ + Q_OBJECT + +public: + ConfigDialogButtonGroupManager(QObject *parent, KCoreConfigSkeleton *config) + : QObject(parent) + , _config(config) + { + Q_ASSERT(config); + connect(_config, &KCoreConfigSkeleton::configChanged, + this, &ConfigDialogButtonGroupManager::updateWidgets); + } + + void addChildren(const QObject *parentObj) + { + for (const QObject *child: parentObj->children()) { + if (!child->objectName().startsWith(ManagedNamePrefix)) { + continue; + } + + const char *className = child->metaObject()->className(); + if (qstrcmp(className, "QButtonGroup") == 0) { + add(qobject_cast(child)); + } + } + } + void add(const QButtonGroup *obj) + { + Q_ASSERT(obj->exclusive()); + connect(obj, QOverload::of(&QButtonGroup::buttonToggled), + this, &ConfigDialogButtonGroupManager::setButtonState, Qt::UniqueConnection); + _groups.append(obj); + + } + + bool hasChanged() const { + for(const QButtonGroup *group: qAsConst(_groups)) { + int value = buttonToEnumValue(group->checkedButton()); + const auto enumItem = groupToConfigItemEnum(group); + + if(!enumItem->isEqual(value)) { + return true; + } + } + return false; + } + + bool isDefault() const { + bool useDefaults = _config->useDefaults(true); + bool result = !hasChanged(); + _config->useDefaults(useDefaults); + return result; + } + +Q_SIGNALS: + void settingsChanged(); + void widgetModified(); + +public Q_SLOTS: + void updateWidgets() + { + bool prevSignalsBlocked = signalsBlocked(); + bool changed = false; + blockSignals(true); + for(const QButtonGroup *group: qAsConst(_groups)) { + auto *enumItem = groupToConfigItemEnum(group); + if(!enumItem) { + continue; + } + + int value = enumItem->value(); + const QString &valueName = enumItem->choices().at(value).name; + QAbstractButton *currentButton = nullptr; + for(auto &button: group->buttons()) { + if(button->objectName() == valueName) { + currentButton = button; + break; + } + } + if(!currentButton) { + return; + } + currentButton->setChecked(true); + changed = true; + } + blockSignals(prevSignalsBlocked); + if(changed) { + QTimer::singleShot(0, this, &ConfigDialogButtonGroupManager::widgetModified); + } + } + + void updateWidgetsDefault() { + bool useDefaults = _config->useDefaults(true); + updateWidgets(); + _config->useDefaults(useDefaults); + } + + void updateSettings() { + bool updateConfig = false; + for(const QButtonGroup *group: qAsConst(_groups)) { + auto *enumItem = groupToConfigItemEnum(group); + if(!enumItem) { + continue; + } + const auto *currentButton = group->checkedButton(); + if(!currentButton) { + continue; + } + const int value = buttonToEnumValue(currentButton); + if(value < 0) { + continue; + } + + if(!enumItem->isEqual(value)) { + enumItem->setValue(value); + updateConfig = true; + } + } + if(updateConfig) { + _config->save(); + emit settingsChanged(); + } + } + +protected Q_SLOTS: + void setButtonState(QAbstractButton *button, bool checked) + { + Q_ASSERT(button); + Q_ASSERT(button->group()); + if(!checked) { + // Both deselected and selected buttons trigger this slot, ignore the deselected one + return; + } + auto *enumItem = groupToConfigItemEnum(button->group()); + if(!enumItem) { + return; + } + + int value = buttonToEnumValue(button); + if(value < 0) { + return; + } + + emit settingsChanged(); + } + +private: + // Returns configuration item associated with the group + KCoreConfigSkeleton::ItemEnum * groupToConfigItemEnum(const QButtonGroup *group) const { + Q_ASSERT(group); + const QString key = group->objectName().mid(ManagedNamePrefix.length()); + auto *item = _config->findItem(key); + if(!item) { + return nullptr; + } + auto *enumItem = dynamic_cast(item); + if(!enumItem) { + return nullptr; + } + return enumItem; + } + + // Returns a value the button represents in its group + int buttonToEnumValue(const QAbstractButton *button) const { + Q_ASSERT(button); + Q_ASSERT(button->group()); + + if(_buttonValues.contains(button)) { + return _buttonValues[button]; + } + + const auto *enumItem = groupToConfigItemEnum(button->group()); + if(!enumItem) { + return -1; + } + const auto &choices = enumItem->choices(); + + const QString buttonName = button->objectName(); + int value = -1; + for(int i = 0; i < choices.size(); ++i) { + if(buttonName == choices.at(i).name) { + value = i; + break; + } + } + _buttonValues[button] = value; + return value; + } + + static const QString ManagedNamePrefix; + + mutable QMap _buttonValues; + KCoreConfigSkeleton *_config = nullptr; + QList _groups; +}; + +} + +#endif // CONFIGURATIONDIALOG_H diff --git a/src/settings/ConfigurationDialog.cpp b/src/settings/ConfigurationDialog.cpp new file mode 100644 --- /dev/null +++ b/src/settings/ConfigurationDialog.cpp @@ -0,0 +1,165 @@ +/* + Copyright 2019 by Mariusz Glebocki + + Based on KConfigDialog from KConfigWidgets + + Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net) + Copyright (C) 2003 Waldo Bastian + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. +*/ + +// Own +#include "ConfigurationDialog.h" + +// Qt +#include +#include + +// KDE +#include +#include +#include + + +using namespace Konsole; + + +const QString ConfigDialogButtonGroupManager::ManagedNamePrefix = QStringLiteral("kcfg_"); + + +ConfigurationDialog::ConfigurationDialog(QWidget *parent, KCoreConfigSkeleton *config) + : KPageDialog(parent) +{ + setWindowTitle(i18nc("@title:window", "Configure")); + // Setting this after modifying buttonBox results in initial focus set to buttonBox. + setFaceType(KPageDialog::List); + + buttonBox()->setStandardButtons(QDialogButtonBox::RestoreDefaults + | QDialogButtonBox::Ok + | QDialogButtonBox::Apply + | QDialogButtonBox::Cancel); + connect(buttonBox()->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, + this, &ConfigurationDialog::updateButtons); + connect(buttonBox()->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, + this, &ConfigurationDialog::updateButtons); + + _manager = new KConfigDialogManager(this, config); + connect(_manager, SIGNAL(settingsChanged()), this, SLOT(settingsChangedSlot())); + connect(_manager, SIGNAL(widgetModified()), this, SLOT(updateButtons())); + + connect(buttonBox()->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, + _manager, &KConfigDialogManager::updateSettings); + connect(buttonBox()->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, + _manager, &KConfigDialogManager::updateSettings); + connect(buttonBox()->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, + _manager, &KConfigDialogManager::updateWidgets); + connect(buttonBox()->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, + _manager, &KConfigDialogManager::updateWidgetsDefault); + + _groupManager = new ConfigDialogButtonGroupManager(this, config); + connect(_groupManager, SIGNAL(settingsChanged()), this, SLOT(settingsChangedSlot())); + connect(_groupManager, SIGNAL(widgetModified()), this, SLOT(updateButtons())); + + connect(buttonBox()->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, + _groupManager, &ConfigDialogButtonGroupManager::updateSettings); + connect(buttonBox()->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, + _groupManager, &ConfigDialogButtonGroupManager::updateSettings); + connect(buttonBox()->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, + _groupManager, &ConfigDialogButtonGroupManager::updateWidgets); + connect(buttonBox()->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, + _groupManager, &ConfigDialogButtonGroupManager::updateWidgetsDefault); + + setApplyButtonEnabled(false); +} + +void ConfigurationDialog::addPage(KPageWidgetItem *item, bool manage) +{ + Q_ASSERT(item); + Q_ASSERT(item->widget()); + + KPageDialog::addPage(item); + + if (manage) { + _manager->addWidget(item->widget()); + _groupManager->addChildren(item->widget()); + } + + if (_shown && manage) { + QPushButton *defaultButton = buttonBox()->button(QDialogButtonBox::RestoreDefaults); + if (defaultButton) { + bool isDefault = defaultButton->isEnabled() && _manager->isDefault(); + defaultButton->setEnabled(!isDefault); + } + } +} + +void ConfigurationDialog::updateButtons() +{ + static bool onlyOnce = false; + if (onlyOnce) { + return; + } + onlyOnce = true; + + bool has_changed = _manager->hasChanged() || _groupManager->hasChanged(); + setApplyButtonEnabled(has_changed); + + bool is_default = _manager->isDefault() && _groupManager->isDefault(); + setRestoreDefaultsButtonEnabled(!is_default); + + emit widgetModified(); + onlyOnce = false; +} + +void ConfigurationDialog::settingsChangedSlot() +{ + updateButtons(); + emit settingsChanged(); +} + +void ConfigurationDialog::setApplyButtonEnabled(bool enabled) +{ + QPushButton *applyButton = buttonBox()->button(QDialogButtonBox::Apply); + if (applyButton) { + applyButton->setEnabled(enabled); + } +} + +void ConfigurationDialog::setRestoreDefaultsButtonEnabled(bool enabled) +{ + QPushButton *restoreDefaultsButton = buttonBox()->button(QDialogButtonBox::RestoreDefaults); + if (restoreDefaultsButton) { + restoreDefaultsButton->setEnabled(enabled); + } +} + +void Konsole::ConfigurationDialog::showEvent(QShowEvent *event) +{ + if (!_shown) { + _manager->updateWidgets(); + _groupManager->updateWidgets(); + + bool hasChanged = _manager->hasChanged() || _groupManager->hasChanged(); + setApplyButtonEnabled(hasChanged); + + bool isDefault = _manager->isDefault() || _groupManager->isDefault(); + setRestoreDefaultsButtonEnabled(!isDefault); + + _shown = true; + } + KPageDialog::showEvent(event); +} diff --git a/src/settings/FileLocationSettings.cpp b/src/settings/FileLocationSettings.cpp deleted file mode 100644 --- a/src/settings/FileLocationSettings.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright 2015 Kurt Hindenburg - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License or (at your option) version 3 or any later version - accepted by the membership of KDE e.V. (or its successor appro- - ved by the membership of KDE e.V.), which shall act as a proxy - defined in Section 14 of version 3 of the license. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. -*/ - -// Own -#include "FileLocationSettings.h" - -#include -#include - -using namespace Konsole; - -FileLocationSettings::FileLocationSettings(QWidget* aParent) : QWidget(aParent) -{ - setupUi(this); - - // TODO: worth adding gauge on free disk space? - useSystemLocationText->setText(QDir::tempPath()); - useUsersHomeLocationText->setText(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); - kcfg_scrollbackUseSpecifiedLocationDirectory->setMode(KFile::Directory); - -} - -FileLocationSettings::~FileLocationSettings() = default; - diff --git a/src/settings/FileLocationSettings.ui b/src/settings/FileLocationSettings.ui deleted file mode 100644 --- a/src/settings/FileLocationSettings.ui +++ /dev/null @@ -1,252 +0,0 @@ - - - FileLocationSettings - - - - 0 - 0 - 494 - 354 - - - - - - - - 0 - 0 - - - - <b>Scrollback File Location</b><p>Use this groupbox to determine where Konsole will store the scrollback files.</p> - - - Scrollback File Location - - - - - - These settings only apply when Profile->Scrolling->Unlimited scrollback is selected. - - - true - - - - - - - Use system &location - - - true - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 50 - 20 - - - - - - - - - - - - - - - - - - 0 - 0 - - - - Use user specific location - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 50 - 20 - - - - - - - - - - - - - - - - - - 0 - 0 - - - - Use specified loca&tion - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 50 - 20 - - - - - - - - - 2 - 0 - - - - text/css - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 30 - - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - For the 'Use user specific location', any application using KonsolePart will have the app name instead of konsole. - - - true - - - - - - - - 10 - 75 - true - true - - - - QFrame::NoFrame - - - QFrame::Raised - - - For any changes to take effect, quit Konsole and restart. - - - Qt::AlignCenter - - - true - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 50 - - - - - - - - - KUrlRequester - QFrame -
kurlrequester.h
- 1 -
-
- - -
diff --git a/src/settings/GeneralSettings.ui b/src/settings/GeneralSettings.ui --- a/src/settings/GeneralSettings.ui +++ b/src/settings/GeneralSettings.ui @@ -6,264 +6,301 @@ 0 0 - 528 - 448 + 385 + 384
1 0 - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - QLayout::SetNoConstraint + + + 0 - - - - Konsole Window - - - - - - - 0 - 0 - - - - Show menubar by default - - - - - - - - 0 - 0 - - - - Show hint for terminal size after resizing - - - - - - - - 0 - 0 - - - - If enabled, profile settings will be ignored - - - Use current window size on next startup - - - - - - - - 0 - 0 - - - - When launching Konsole re-use existing process if possible - - - Run all Konsole windows in a single process - - - - - - - - 0 - 0 - - - - Enable menu accelerators - - - - - - - - 0 - 0 - - - - Show window title on the titlebar - - - - - - - Remove window titlebar and frame - - - - + + 0 + + + 0 + + + 0 + + + 6 + + + + + + 0 + 0 + + + + Sets whether search should start from the bottom + + + Search backwards + - - - - - - QLayout::SetNoConstraint - - - - - Default Search Settings - - - - - - - 0 - 0 - - - - Sets whether the search is case sensitive - - - Search is case sensitive - - - - - - - - 0 - 0 - - - - Match using regular expressions - - - - - - - - 0 - 0 - - - - Highlight all search matches - - - - - - - - 0 - 0 - - - - Sets whether search should start from the bottom - - - Search backwards - - - - + + + + + 0 + 0 + + + + Enable menu accelerators + + + + + + + + 0 + 0 + + + + Sets whether the search is case sensitive + + + Case sensitive + + + + + + + + 0 + 0 + + + + Show menubar + + + + + + + + 0 + 0 + + + + If enabled, profile settings will be ignored + + + Remember window size + + + + + + 0 + 0 + + + + Show window title on the titlebar + + + + + + + + 0 + 0 + + + + When launching Konsole re-use existing process if possible + + + Run all Konsole windows in a single process + + + + + + + Remove window titlebar and frame + + + + + + + + 0 + 0 + + + + Highlight all matches + + + + + + + + 0 + 0 + + + + Show hint for terminal size after resizing + + + + + + + Notifications: + + + + + + + Search: + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 16 + + + + + + + + 0 + + + + + + 0 + 0 + + + + All dialogs will be shown again + + + Enable all "Don't Ask Again" messages + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Process and window: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Match using regular expressions + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 16 + + + + - - - - 0 - 0 - - - - Notifications - - - - - - Qt::Horizontal - - - - 117 - 20 - - - - - - - - - 0 - 0 - - - - All dialogs will be shown again - - - Enable all "Don't Ask Again" messages - - - - - - - Qt::Horizontal - - - - 116 - 20 - - - - - - - - - + Qt::Vertical 20 - 60 + 40 diff --git a/src/settings/ProfileSettings.h b/src/settings/ProfileSettings.h --- a/src/settings/ProfileSettings.h +++ b/src/settings/ProfileSettings.h @@ -23,6 +23,7 @@ // Qt #include #include +#include // KDE @@ -45,7 +46,6 @@ { Q_OBJECT - friend class FavoriteItemDelegate; friend class ShortcutItemDelegate; public: @@ -72,8 +72,6 @@ void setSelectedAsDefault(); void createProfile(); void editSelected(); - void moveUpSelected(); - void moveDownSelected(); void itemDataChanged(QStandardItem *item); @@ -99,18 +97,25 @@ // their default / non-default profile status void updateDefaultItem(); void updateItemsForProfile(const Profile::Ptr &profile,const QList &items) const; + void updateShortcutField(QStandardItem *item, bool isFavorite) const; // updates the profile table to be in sync with the // session manager void populateTable(); int rowForProfile(const Profile::Ptr &profile) const; QStandardItemModel *_sessionModel; - static const int ProfileNameColumn = 0; - static const int FavoriteStatusColumn = 1; - static const int ShortcutColumn = 2; - static const int ProfileKeyRole = Qt::UserRole + 1; - static const int ShortcutRole = Qt::UserRole + 1; + enum Column { + FavoriteStatusColumn = 0, + ProfileNameColumn = 1, + ShortcutColumn = 2, + ProfileColumn = 3, + }; + + enum Role { + ProfilePtrRole = Qt::UserRole + 1, + ShortcutRole, + }; }; class StyledBackgroundPainter @@ -120,17 +125,15 @@ const QModelIndex &index); }; -class FavoriteItemDelegate : public QStyledItemDelegate +class FilteredKeySequenceEdit: public QKeySequenceEdit { Q_OBJECT public: - explicit FavoriteItemDelegate(QObject *parent = nullptr); + explicit FilteredKeySequenceEdit(QWidget *parent = nullptr): QKeySequenceEdit(parent) {} - bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, - const QModelIndex &index) Q_DECL_OVERRIDE; - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const Q_DECL_OVERRIDE; +protected: + void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; }; class ShortcutItemDelegate : public QStyledItemDelegate @@ -146,9 +149,12 @@ const QModelIndex &index) const Q_DECL_OVERRIDE; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; + QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const Q_DECL_OVERRIDE; + void destroyEditor(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE; private Q_SLOTS: - void editorModified(const QKeySequence &keys); + void editorModified(); private: mutable QSet _modifiedEditors; diff --git a/src/settings/ProfileSettings.cpp b/src/settings/ProfileSettings.cpp --- a/src/settings/ProfileSettings.cpp +++ b/src/settings/ProfileSettings.cpp @@ -19,14 +19,15 @@ // Own #include "ProfileSettings.h" +#include // Qt #include #include #include +#include // KDE -#include #include #include #include @@ -47,30 +48,19 @@ { setupUi(this); - // hide vertical header - sessionTable->verticalHeader()->hide(); - sessionTable->setShowGrid(false); - - sessionTable->setItemDelegateForColumn(FavoriteStatusColumn, new FavoriteItemDelegate(this)); - sessionTable->setItemDelegateForColumn(ShortcutColumn, new ShortcutItemDelegate(this)); - sessionTable->setEditTriggers(sessionTable->editTriggers() | QAbstractItemView::SelectedClicked); + profilesList->setItemDelegateForColumn(ShortcutColumn, new ShortcutItemDelegate(this)); // double clicking the profile name opens the profile edit dialog - connect(sessionTable, &QTableView::doubleClicked, this, &Konsole::ProfileSettings::doubleClicked); + connect(profilesList, &QAbstractItemView::doubleClicked, this, &Konsole::ProfileSettings::doubleClicked); // populate the table with profiles populateTable(); // listen for changes to profiles connect(ProfileManager::instance(), &Konsole::ProfileManager::profileAdded, this, &Konsole::ProfileSettings::addItems); connect(ProfileManager::instance(), &Konsole::ProfileManager::profileRemoved, this, &Konsole::ProfileSettings::removeItems); connect(ProfileManager::instance(), &Konsole::ProfileManager::profileChanged, this, &Konsole::ProfileSettings::updateItems); - connect(ProfileManager::instance() , &Konsole::ProfileManager::favoriteStatusChanged, this, &Konsole::ProfileSettings::updateFavoriteStatus); - - // resize the session table to the full width of the table - sessionTable->horizontalHeader()->setHighlightSections(false); - sessionTable->horizontalHeader()->setStretchLastSection(true); - sessionTable->resizeColumnsToContents(); + connect(ProfileManager::instance(), &Konsole::ProfileManager::favoriteStatusChanged, this, &Konsole::ProfileSettings::updateFavoriteStatus); // setup buttons connect(newProfileButton, &QPushButton::clicked, this, &Konsole::ProfileSettings::createProfile); @@ -91,16 +81,34 @@ { if (item->column() == ShortcutColumn) { QKeySequence sequence = QKeySequence::fromString(item->text()); - ProfileManager::instance()->setShortcut(item->data(ShortcutRole).value(), + QStandardItem *idItem = item->model()->item(item->row(), ProfileColumn); + ProfileManager::instance()->setShortcut(idItem->data(ProfilePtrRole).value(), sequence); + } else if (item->column() == FavoriteStatusColumn) { + QStandardItem *idItem = item->model()->item(item->row(), ProfileColumn); + const bool isFavorite = item->checkState() == Qt::Checked; + ProfileManager::instance()->setFavorite(idItem->data(ProfilePtrRole).value(), + isFavorite); + updateShortcutField(item->model()->item(item->row(), ShortcutColumn), isFavorite); + } +} + +void ProfileSettings::updateShortcutField(QStandardItem *item, bool isFavorite) const +{ + if(isFavorite) { + item->setToolTip(i18nc("@info:tooltip", "Double click to change shortcut")); + item->setForeground(palette().color(QPalette::Normal, QPalette::Text)); + } else { + item->setToolTip(i18nc("@info:tooltip", "Shortcut won't work while the profile is not marked as visible.")); + item->setForeground(palette().color(QPalette::Disabled, QPalette::Text)); } } int ProfileSettings::rowForProfile(const Profile::Ptr &profile) const { const int rowCount = _sessionModel->rowCount(); for (int i = 0; i < rowCount; i++) { - if (_sessionModel->item(i, ProfileNameColumn)->data(ProfileKeyRole) + if (_sessionModel->item(i, ProfileColumn)->data(ProfilePtrRole) .value() == profile) { return i; } @@ -124,36 +132,39 @@ } const auto items = QList { - _sessionModel->item(row, ProfileNameColumn), _sessionModel->item(row, FavoriteStatusColumn), - _sessionModel->item(row, ShortcutColumn) + _sessionModel->item(row, ProfileNameColumn), + _sessionModel->item(row, ShortcutColumn), + _sessionModel->item(row, ProfileColumn), }; updateItemsForProfile(profile, items); } void ProfileSettings::updateItemsForProfile(const Profile::Ptr &profile, const QList& items) const { + // "Enabled" checkbox + const auto isEnabled = ProfileManager::instance()->findFavorites().contains(profile); + items[FavoriteStatusColumn]->setCheckState(isEnabled ? Qt::Checked : Qt::Unchecked); + items[FavoriteStatusColumn]->setCheckable(true); + items[FavoriteStatusColumn]->setToolTip( + i18nc("@info:tooltip List item's checkbox for making item (profile) visible in a menu", + "Show profile in menu")); + // Profile Name items[ProfileNameColumn]->setText(profile->name()); if (!profile->icon().isEmpty()) { items[ProfileNameColumn]->setIcon(QIcon::fromTheme(profile->icon())); } - items[ProfileNameColumn]->setData(QVariant::fromValue(profile), ProfileKeyRole); // only allow renaming the profile from the edit profile dialog // so as to use ProfileManager::checkProfileName() items[ProfileNameColumn]->setEditable(false); - // Favorite Status - const auto isFavorite = ProfileManager::instance()->findFavorites().contains(profile); - const auto icon = isFavorite ? QIcon::fromTheme(QStringLiteral("dialog-ok-apply")) : QIcon(); - items[FavoriteStatusColumn]->setData(icon, Qt::DecorationRole); - items[FavoriteStatusColumn]->setData(QVariant::fromValue(profile), ProfileKeyRole); - items[FavoriteStatusColumn]->setToolTip(i18nc("@info:tooltip", "Click to toggle status")); - // Shortcut const auto shortcut = ProfileManager::instance()->shortcut(profile).toString(); items[ShortcutColumn]->setText(shortcut); - items[ShortcutColumn]->setData(QVariant::fromValue(profile), ShortcutRole); - items[ShortcutColumn]->setToolTip(i18nc("@info:tooltip", "Double click to change shortcut")); + updateShortcutField(items[ShortcutColumn], isEnabled); + + // Profile ID (pointer to profile) - intended to be hidden in a view + items[ProfileColumn]->setData(QVariant::fromValue(profile), ProfilePtrRole); } void ProfileSettings::doubleClicked(const QModelIndex &index) @@ -174,23 +185,64 @@ const auto items = QList { new QStandardItem(), new QStandardItem(), - new QStandardItem() + new QStandardItem(), + new QStandardItem(), }; updateItemsForProfile(profile, items); _sessionModel->appendRow(items); } void ProfileSettings::populateTable() { - Q_ASSERT(!sessionTable->model()); + Q_ASSERT(!profilesList->model()); - sessionTable->setModel(_sessionModel); + profilesList->setModel(_sessionModel); _sessionModel->clear(); // setup session table - _sessionModel->setHorizontalHeaderLabels({i18nc("@title:column Profile label", "Name"), - i18nc("@title:column Display profile in file menu", "Show"), - i18nc("@title:column Profile shortcut text", "Shortcut")}); + _sessionModel->setHorizontalHeaderLabels({ + QString(), // set using header item below + i18nc("@title:column Profile name", "Name"), + i18nc("@title:column Profile keyboard shortcut", "Shortcut"), + QString(), + }); + auto *favoriteColumnHeaderItem = new QStandardItem(); + favoriteColumnHeaderItem->setIcon(QIcon::fromTheme(QStringLiteral("visibility"))); + favoriteColumnHeaderItem->setToolTip( + i18nc("@info:tooltip List item's checkbox for making item (profile) visible in a menu", + "Show profile in menu")); + _sessionModel->setHorizontalHeaderItem(FavoriteStatusColumn, favoriteColumnHeaderItem); + + // Calculate favorite column width. resizeColumnToContents() + // is not used because it takes distance between checkbox and + // text into account, but there is no text and it looks weird. + const int headerMargin = style()->pixelMetric(QStyle::PM_HeaderMargin, nullptr, + profilesList->header()); + const int iconWidth = style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, + profilesList->header()); + const int favoriteHeaderWidth = headerMargin * 2 + iconWidth; + QStyleOptionViewItem opt; + opt.features = QStyleOptionViewItem::HasCheckIndicator | QStyleOptionViewItem::HasDecoration; + const QRect checkBoxRect = style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, + &opt, profilesList); + // When right edge is at x < 0 it is assumed the checkbox is + // placed on the right item's side and the margin between right + // checkbox edge and right item edge should be used. + const int checkBoxMargin = checkBoxRect.right() >= 0 ? checkBoxRect.x() + : 0 - checkBoxRect.right(); + const int favoriteItemWidth = checkBoxMargin * 2 + checkBoxRect.width(); + auto *listHeader = profilesList->header(); + + profilesList->setColumnWidth(FavoriteStatusColumn, + qMax(favoriteHeaderWidth, favoriteItemWidth)); + profilesList->resizeColumnToContents(ProfileNameColumn); + listHeader->setSectionResizeMode(FavoriteStatusColumn, QHeaderView::ResizeMode::Fixed); + listHeader->setSectionResizeMode(ProfileNameColumn, QHeaderView::ResizeMode::Stretch); + listHeader->setSectionResizeMode(ShortcutColumn, QHeaderView::ResizeMode::ResizeToContents); + listHeader->setStretchLastSection(false); + listHeader->setSectionsMovable(false); + + profilesList->hideColumn(ProfileColumn); QList profiles = ProfileManager::instance()->allProfiles(); ProfileManager::instance()->sortProfiles(profiles); @@ -207,51 +259,53 @@ // // it appears that the selection model is changed when the model itself is replaced, // so the signals need to be reconnected each time the model is updated. - connect(sessionTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &Konsole::ProfileSettings::tableSelectionChanged); - - sessionTable->selectRow(0); + connect(profilesList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &Konsole::ProfileSettings::tableSelectionChanged); } void ProfileSettings::updateDefaultItem() { Profile::Ptr defaultProfile = ProfileManager::instance()->defaultProfile(); + const QString defaultItemSuffix = i18nc("Default list item's name suffix (with separator)", " (default)"); + const int rowCount = _sessionModel->rowCount(); for (int i = 0; i < rowCount; i++) { - QStandardItem* item = _sessionModel->item(i); + QStandardItem* item = _sessionModel->item(i, ProfileNameColumn); QFont itemFont = item->font(); + QStandardItem* profileIdItem = _sessionModel->item(i, ProfileColumn); + auto profile = profileIdItem->data().value(); + const bool isDefault = (defaultProfile == profile); + const QString cleanItemName = profile != nullptr ? profile->name() : QString(); - bool isDefault = (defaultProfile == item->data().value()); - - if (isDefault && !itemFont.bold()) { - QIcon icon(KIconLoader::global()->loadIcon(defaultProfile->icon(), KIconLoader::Small, 0, KIconLoader::DefaultState, QStringList(QStringLiteral("emblem-favorite")))); - item->setIcon(icon); - itemFont.setBold(true); + if (isDefault) { + itemFont.setItalic(true); item->setFont(itemFont); - } else if (!isDefault && itemFont.bold()) { - QModelIndex index = _sessionModel->index(i, ProfileNameColumn); - Profile::Ptr profile = index.data(ProfileSettings::ProfileKeyRole).value(); - if (profile != nullptr) { - item->setIcon(QIcon::fromTheme(profile->icon())); - } - itemFont.setBold(false); + item->setText(cleanItemName + defaultItemSuffix); + } else if (!isDefault) { + // FIXME: use default font + itemFont.setItalic(false); item->setFont(itemFont); + item->setText(cleanItemName); } } } void ProfileSettings::tableSelectionChanged(const QItemSelection&) { - const int selectedRows = sessionTable->selectionModel()->selectedRows().count(); const ProfileManager* manager = ProfileManager::instance(); - const bool isNotDefault = (selectedRows > 0) && currentProfile() != manager->defaultProfile(); - const bool isDeletable = (selectedRows > 1) || - (selectedRows == 1 && isProfileDeletable(currentProfile())); + bool isNotDefault = true; + bool isDeletable = true; - newProfileButton->setEnabled(selectedRows < 2); + const auto profiles = selectedProfiles(); + for (const auto &profile: profiles) { + isNotDefault = isNotDefault && (profile != manager->defaultProfile()); + isDeletable = isDeletable && isProfileDeletable(profile); + } + + newProfileButton->setEnabled(profiles.count() < 2); // FIXME: At some point editing 2+ profiles no longer works - editProfileButton->setEnabled(selectedRows == 1); + editProfileButton->setEnabled(profiles.count() == 1); // do not allow the default session type to be removed - deleteProfileButton->setEnabled(isDeletable && isNotDefault); - setAsDefaultButton->setEnabled(isNotDefault && (selectedRows < 2)); + deleteProfileButton->setEnabled(isDeletable && isNotDefault && (profiles.count() > 0)); + setAsDefaultButton->setEnabled(isNotDefault && (profiles.count() == 1)); } void ProfileSettings::deleteSelected() { @@ -272,26 +326,6 @@ updateDefaultItem(); } -void ProfileSettings::moveUpSelected() -{ - Q_ASSERT(_sessionModel); - - const int rowIndex = sessionTable->currentIndex().row(); - const QListitems = _sessionModel->takeRow(rowIndex); - _sessionModel->insertRow(rowIndex - 1, items); - sessionTable->selectRow(rowIndex - 1); -} - -void ProfileSettings::moveDownSelected() -{ - Q_ASSERT(_sessionModel); - - const int rowIndex = sessionTable->currentIndex().row(); - const QListitems = _sessionModel->takeRow(rowIndex); - _sessionModel->insertRow(rowIndex + 1, items); - sessionTable->selectRow(rowIndex + 1); -} - void ProfileSettings::createProfile() { // setup a temporary profile which is a clone of the selected profile @@ -302,6 +336,7 @@ auto newProfile = Profile::Ptr(new Profile(ProfileManager::instance()->fallbackProfile())); newProfile->clone(sourceProfile, true); + // TODO: add number suffix when the name is taken newProfile->setProperty(Profile::Name, i18nc("@item This will be used as part of the file name", "New Profile")); newProfile->setProperty(Profile::UntranslatedName, QStringLiteral("New Profile")); newProfile->setProperty(Profile::MenuIndex, QStringLiteral("0")); @@ -351,29 +386,29 @@ QList ProfileSettings::selectedProfiles() const { QList list; - QItemSelectionModel* selection = sessionTable->selectionModel(); + QItemSelectionModel* selection = profilesList->selectionModel(); if (selection == nullptr) { return list; } foreach(const QModelIndex & index, selection->selectedIndexes()) { - if (index.column() == ProfileNameColumn) { - list << index.data(ProfileKeyRole).value(); + if (index.column() == ProfileColumn) { + list << index.data(ProfilePtrRole).value(); } } return list; } Profile::Ptr ProfileSettings::currentProfile() const { - QItemSelectionModel* selection = sessionTable->selectionModel(); + QItemSelectionModel* selection = profilesList->selectionModel(); if ((selection == nullptr) || selection->selectedRows().count() != 1) { return Profile::Ptr(); } - return selection-> - selectedIndexes().first().data(ProfileKeyRole).value(); + return selection-> + selectedIndexes().at(ProfileColumn).data(ProfilePtrRole).value(); } bool ProfileSettings::isProfileDeletable(Profile::Ptr profile) const { @@ -395,19 +430,17 @@ const int rowCount = _sessionModel->rowCount(); for (int i = 0; i < rowCount; i++) { - QModelIndex index = _sessionModel->index(i, FavoriteStatusColumn); - if (index.data(ProfileKeyRole).value() == profile) { - // FIXME: On desktops without this icon, it is impossible to - // determine if a profile is a favorite in this dialog. - // Consider changing to using QStandardItem::setCheckable - const QIcon icon = favorite ? QIcon::fromTheme(QStringLiteral("dialog-ok-apply")) : QIcon(); - _sessionModel->setData(index, icon, Qt::DecorationRole); + auto *item = _sessionModel->item(i, ProfileColumn); + if (item->data(ProfilePtrRole).value() == profile) { + auto *favoriteItem = _sessionModel->item(i, FavoriteStatusColumn); + favoriteItem->setCheckState(favorite ? Qt::Checked : Qt::Unchecked); + break; } } } void ProfileSettings::setShortcutEditorVisible(bool visible) { - sessionTable->setColumnHidden(ShortcutColumn, !visible); + profilesList->setColumnHidden(ShortcutColumn, !visible); } void StyledBackgroundPainter::drawBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex&) @@ -420,55 +453,15 @@ style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, widget); } -// This adds a checkmark and the appropriate background in the "Show" -// column of the Manage Profiles->Profiles page. -FavoriteItemDelegate::FavoriteItemDelegate(QObject* aParent) - : QStyledItemDelegate(aParent) -{ -} -void FavoriteItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const -{ - // See implementation of QStyledItemDelegate::paint() - QStyleOptionViewItem opt = option; - initStyleOption(&opt, index); - - StyledBackgroundPainter::drawBackground(painter, opt, index); - - int margin = (opt.rect.height() - opt.decorationSize.height()) / 2; - margin++; - - opt.rect.setTop(opt.rect.top() + margin); - opt.rect.setBottom(opt.rect.bottom() - margin); - - QIcon icon = index.data(Qt::DecorationRole).value(); - icon.paint(painter, opt.rect, Qt::AlignCenter); -} - -bool FavoriteItemDelegate::editorEvent(QEvent* aEvent, QAbstractItemModel*, - const QStyleOptionViewItem&, const QModelIndex& index) -{ - if (aEvent->type() == QEvent::MouseButtonPress || - aEvent->type() == QEvent::KeyPress || - aEvent->type() == QEvent::MouseButtonDblClick) { - Profile::Ptr profile = index.data(ProfileSettings::ProfileKeyRole).value(); - const bool isFavorite = ProfileManager::instance()->findFavorites().contains(profile); - - ProfileManager::instance()->setFavorite(profile, !isFavorite); - } - - return true; -} ShortcutItemDelegate::ShortcutItemDelegate(QObject* aParent) : QStyledItemDelegate(aParent), _modifiedEditors(QSet()), _itemsBeingEdited(QSet()) { } -void ShortcutItemDelegate::editorModified(const QKeySequence& keys) +void ShortcutItemDelegate::editorModified() { - Q_UNUSED(keys); - - auto* editor = qobject_cast(sender()); + auto* editor = qobject_cast(sender()); Q_ASSERT(editor); _modifiedEditors.insert(editor); emit commitData(editor); @@ -483,7 +476,7 @@ return; } - QString shortcut = qobject_cast(editor)->keySequence().toString(); + QString shortcut = qobject_cast(editor)->keySequence().toString(); model->setData(index, shortcut, Qt::DisplayRole); _modifiedEditors.remove(editor); @@ -493,13 +486,11 @@ { _itemsBeingEdited.insert(index); - auto editor = new KKeySequenceWidget(aParent); - editor->setFocusPolicy(Qt::StrongFocus); - editor->setModifierlessAllowed(false); + auto editor = new FilteredKeySequenceEdit(aParent); QString shortcutString = index.data(Qt::DisplayRole).toString(); editor->setKeySequence(QKeySequence::fromString(shortcutString)); - connect(editor, &KKeySequenceWidget::keySequenceChanged, this, &Konsole::ShortcutItemDelegate::editorModified); - editor->captureKeySequence(); + connect(editor, &QKeySequenceEdit::editingFinished, this, &Konsole::ShortcutItemDelegate::editorModified); + editor->setFocus(Qt::FocusReason::MouseFocusReason); return editor; } void ShortcutItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, @@ -512,3 +503,43 @@ } } +QSize Konsole::ShortcutItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + const QString shortcutString = index.data(Qt::DisplayRole).toString(); + QFontMetrics fm = option.fontMetrics; + + static const int editorMargins = 16; // chosen empirically + const int width = fm.horizontalAdvance(shortcutString + QStringLiteral(", ...")) + + editorMargins; + + return QSize(width, QStyledItemDelegate::sizeHint(option, index).height()); +} + +void Konsole::ShortcutItemDelegate::destroyEditor(QWidget *editor, const QModelIndex &index) const +{ + _itemsBeingEdited.remove(index); + _modifiedEditors.remove(editor); + editor->deleteLater(); +} + +void Konsole::FilteredKeySequenceEdit::keyPressEvent(QKeyEvent *event) +{ + if(event->modifiers() == Qt::NoModifier) { + switch(event->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + emit editingFinished(); + return; + case Qt::Key_Backspace: + case Qt::Key_Delete: + clear(); + emit editingFinished(); + event->accept(); + return; + default: + event->accept(); + return; + } + } + QKeySequenceEdit::keyPressEvent(event); +} diff --git a/src/settings/ProfileSettings.ui b/src/settings/ProfileSettings.ui --- a/src/settings/ProfileSettings.ui +++ b/src/settings/ProfileSettings.ui @@ -6,105 +6,137 @@ 0 0 - 645 - 315 + 384 + 384 - - - - - true - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectRows - - - QAbstractItemView::ScrollPerPixel - - - QAbstractItemView::ScrollPerPixel - - - false - - - - - - - Create a new profile based upon the selected profile - - - &New Profile... - - - - - - - false - - - Edit the selected profile(s) - - - &Edit Profile... - - - - - - - false - - - Delete the selected profile(s) - - - &Delete Profile - - - - - - - false - - - Set the selected profile as the default for new terminal sessions - + + + 0 + + + 0 + + + 0 + + + 0 + + + - &Set as Default - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - The 'Show' column must be checked for these shortcuts to work. + Profiles marked as visible will appear in context and File menu. A shortcut for switching current terminal's profile can be assigned to each entry. However, only shortcuts of visible profiles will work. true + + + + 0 + + + + + 6 + + + + + Create a new profile based upon the selected profile + + + &New... + + + + + + + false + + + Edit the selected profile(s) + + + &Edit... + + + + + + + false + + + Delete the selected profile(s) + + + &Remove + + + + + + + false + + + Set the selected profile as the default for new terminal sessions + + + &Set as Default + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + true + + + QAbstractItemView::ExtendedSelection + + + false + + + true + + + false + + + false + + + 8 + + + true + + + + + diff --git a/src/settings/TabBarSettings.cpp b/src/settings/TabBarSettings.cpp --- a/src/settings/TabBarSettings.cpp +++ b/src/settings/TabBarSettings.cpp @@ -26,6 +26,16 @@ TabBarSettings::TabBarSettings(QWidget* aParent) : QWidget(aParent) { setupUi(this); + + // Enable CSS file selector only when tabbar is visible and custom css is active + const auto updateStyleSheetFileEnable = [this](bool) { + kcfg_TabBarUserStyleSheetFile->setEnabled(kcfg_TabBarUseUserStyleSheet->isChecked() + && !AlwaysHideTabBar->isChecked()); + }; + connect(kcfg_TabBarUseUserStyleSheet, &QAbstractButton::toggled, + this, updateStyleSheetFileEnable); + connect(AlwaysHideTabBar, &QAbstractButton::toggled, + this, updateStyleSheetFileEnable); } TabBarSettings::~TabBarSettings() = default; diff --git a/src/settings/TabBarSettings.ui b/src/settings/TabBarSettings.ui --- a/src/settings/TabBarSettings.ui +++ b/src/settings/TabBarSettings.ui @@ -6,228 +6,563 @@ 0 0 - 503 - 375 + 384 + 512 - - - - - Appearance + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 - - - - - Tab bar position: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 1 - 0 - - - - - Always Show Tab Bar - - - - - Show Tab Bar When Needed - - - - - Always Hide Tab Bar - - - - - - - - Tab bar visibility: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 1 - 0 - - - - - Above Terminal Area - - - - - Below Terminal Area - - - - - - - - Close Tab button: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 1 - 0 - - - - - On each tab - - - - - On the tab bar - - - - - None - - - - - - - - Show 'New Tab' button - - - - - - - Expand Individual Tab Widths to Full Window - - - - - - - - 2 - 0 - - - - text/css - - - - - - - Use user-defined stylesheet - - - - - - - Close tab on middle-click - - - - - + + + + &Never + + + kcfg_TabBarVisibility + + + + + + + Use user-defined stylesheet: + + + + + + + After c&urrent tab + + + kcfg_NewTabBehavior + + + + + + + Close tab on middle-click + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 16 + 20 + + + + + + + + None + + + kcfg_CloseTabButton + + + + + + + Show Close Tab button: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + text/css + + + (none) + + + + + + + On &the tab bar + + + kcfg_CloseTabButton + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 16 + + + + + + + + On each tab + + + kcfg_CloseTabButton + + + + + + + Miscellaneous: + + + + + + + Put new tabs: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 16 + + + + + + + + Position: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + At the end + + + kcfg_NewTabBehavior + + + + + + + When needed + + + kcfg_TabBarVisibility + + + + + + + A&lways + + + kcfg_TabBarVisibility + + + + + + + Below terminal area + + + kcfg_TabBarPosition + + + + + + + Above terminal area + + + kcfg_TabBarPosition + + + + + + + Expand individual tab widths to full window + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 16 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 16 + + + + + + + + Show: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + - - - - Behavior - - - - - - New tab behavior: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 1 - 0 - - - - - Put New Tab At The End - - - - - Put New Tab After Current Tab - - - - - - - - + Qt::Vertical 20 - 4 + 0 - - KComboBox - QComboBox -
kcombobox.h
-
KUrlRequester QFrame
kurlrequester.h
1
+ + ShowTabBarWhenNeeded + AlwaysShowTabBar + AlwaysHideTabBar + Bottom + Top + OnEachTab + OnTabBar + None + PutNewTabAtTheEnd + PutNewTabAfterCurrentTab + kcfg_CloseTabOnMiddleMouseButton + kcfg_ExpandTabWidth + kcfg_TabBarUseUserStyleSheet + - + + + AlwaysHideTabBar + toggled(bool) + kcfg_TabBarUseUserStyleSheet + setDisabled(bool) + + + 141 + 72 + + + 141 + 420 + + + + + AlwaysHideTabBar + toggled(bool) + PutNewTabAfterCurrentTab + setDisabled(bool) + + + 141 + 72 + + + 141 + 320 + + + + + AlwaysHideTabBar + toggled(bool) + kcfg_CloseTabOnMiddleMouseButton + setDisabled(bool) + + + 141 + 72 + + + 141 + 368 + + + + + AlwaysHideTabBar + toggled(bool) + None + setDisabled(bool) + + + 141 + 72 + + + 141 + 246 + + + + + AlwaysHideTabBar + toggled(bool) + showCloseTabButtonLabel + setDisabled(bool) + + + 141 + 72 + + + 21 + 194 + + + + + AlwaysHideTabBar + toggled(bool) + OnTabBar + setDisabled(bool) + + + 141 + 72 + + + 141 + 220 + + + + + AlwaysHideTabBar + toggled(bool) + Bottom + setDisabled(bool) + + + 141 + 72 + + + 141 + 146 + + + + + AlwaysHideTabBar + toggled(bool) + OnEachTab + setDisabled(bool) + + + 141 + 72 + + + 141 + 194 + + + + + AlwaysHideTabBar + toggled(bool) + miscellaneousLabel + setDisabled(bool) + + + 141 + 72 + + + 63 + 368 + + + + + AlwaysHideTabBar + toggled(bool) + putNewTabsLabel + setDisabled(bool) + + + 141 + 72 + + + 21 + 294 + + + + + AlwaysHideTabBar + toggled(bool) + positionLabel + setDisabled(bool) + + + 141 + 72 + + + 21 + 120 + + + + + AlwaysHideTabBar + toggled(bool) + PutNewTabAtTheEnd + setDisabled(bool) + + + 141 + 72 + + + 141 + 294 + + + + + AlwaysHideTabBar + toggled(bool) + Top + setDisabled(bool) + + + 141 + 72 + + + 141 + 120 + + + + + AlwaysHideTabBar + toggled(bool) + kcfg_ExpandTabWidth + setDisabled(bool) + + + 141 + 72 + + + 141 + 394 + + + + + + + + + + diff --git a/src/settings/FileLocationSettings.h b/src/settings/TemporaryFilesSettings.h rename from src/settings/FileLocationSettings.h rename to src/settings/TemporaryFilesSettings.h --- a/src/settings/FileLocationSettings.h +++ b/src/settings/TemporaryFilesSettings.h @@ -21,16 +21,16 @@ #ifndef FILELOCATIONSETTINGS_H #define FILELOCATIONSETTINGS_H -#include "ui_FileLocationSettings.h" +#include "ui_TemporaryFilesSettings.h" namespace Konsole { -class FileLocationSettings : public QWidget, private Ui::FileLocationSettings +class TemporaryFilesSettings : public QWidget, private Ui::TemporaryFilesSettings { Q_OBJECT public: - explicit FileLocationSettings(QWidget *aParent = nullptr); - ~FileLocationSettings() Q_DECL_OVERRIDE; + explicit TemporaryFilesSettings(QWidget *aParent = nullptr); + ~TemporaryFilesSettings() override = default; }; } diff --git a/src/settings/TemporaryFilesSettings.cpp b/src/settings/TemporaryFilesSettings.cpp new file mode 100644 --- /dev/null +++ b/src/settings/TemporaryFilesSettings.cpp @@ -0,0 +1,55 @@ +/* + Copyright 2015 Kurt Hindenburg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor appro- + ved by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. +*/ + +// Own +#include "TemporaryFilesSettings.h" + +// Qt +#include + +using namespace Konsole; + + + +TemporaryFilesSettings::TemporaryFilesSettings(QWidget* aParent) : QWidget(aParent) +{ + setupUi(this); + + const QString tempPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation); + QString cachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); +#ifdef Q_OS_UNIX + // Use "~" instead of full path. It looks nice and helps + // in cases when home path is realy long. + const QString homePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); + if(cachePath.startsWith(homePath)) { + cachePath.replace(0, homePath.length(), QStringLiteral("~")); + } +#endif + + // There's no way of doing this with strings placed in .ui file + kcfg_scrollbackUseSystemLocation->setText( + i18nc("@option:radio File location; %1: path to directory placeholder", + "System temporary directory (%1)", tempPath)); + kcfg_scrollbackUseCacheLocation->setText( + i18nc("@option:radio File location; %1: path to directory placeholder", + "User cache directory (%1)", cachePath)); + + kcfg_scrollbackUseSpecifiedLocationDirectory->setMode(KFile::Directory); +} diff --git a/src/settings/TemporaryFilesSettings.ui b/src/settings/TemporaryFilesSettings.ui new file mode 100644 --- /dev/null +++ b/src/settings/TemporaryFilesSettings.ui @@ -0,0 +1,162 @@ + + + TemporaryFilesSettings + + + + 0 + 0 + 384 + 384 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + + + Scrollback file location: + + + + + + + false + + + + 0 + 0 + + + + text/css + + + + + + + + 0 + 0 + + + + User cache directory (...) + + + + + + + + 0 + 0 + + + + Custom: + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 16 + 20 + + + + + + + + + 0 + 0 + + + + System temporary directory (...) + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 50 + + + + + + + + + KUrlRequester + QFrame +
kurlrequester.h
+ 1 +
+
+ + + + kcfg_scrollbackUseSpecifiedLocation + toggled(bool) + kcfg_scrollbackUseSpecifiedLocationDirectory + setEnabled(bool) + + + 146 + 66 + + + 186 + 85 + + + + +