diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 87667f29..87efe8c0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,222 +1,223 @@ # cmake-options : -DCMAKE_DISABLE_FIND_PACKAGE_LibKonq=TRUE or FALSE; default is FALSE add_definitions(-DTRANSLATION_DOMAIN=\"konsole\") ### Handle DragonFlyBSD here instead of using __DragonFly__ IF(${CMAKE_SYSTEM_NAME} MATCHES "DragonFly") set(HAVE_OS_DRAGONFLYBSD 1) else() set(HAVE_OS_DRAGONFLYBSD 0) endif() IF(NOT (${KF5_VERSION} VERSION_LESS "5.60.0")) set(USE_TERMINALINTERFACEV2 1) endif() include(CheckIncludeFiles) include(ECMAddAppIcon) configure_file(config-konsole.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-konsole.h) ### Tests if(BUILD_TESTING) find_package(Qt5Test ${QT_MIN_VERSION} CONFIG REQUIRED) add_subdirectory(autotests) add_subdirectory(tests) endif() ### Security concerns about sendText and runCommand dbus methods being public option(REMOVE_SENDTEXT_RUNCOMMAND_DBUS_METHODS "Konsole: remove sendText and runCommand dbus methods" OFF) ### Development tools option(KONSOLE_BUILD_UNI2CHARACTERWIDTH "Konsole: build uni2characterwidth executable" OFF) ### Konsole source files shared between embedded terminal and main application # qdbuscpp2xml -m Session.h -o org.kde.konsole.Session.xml # qdbuscpp2xml -M -s ViewManager.h -o org.kde.konsole.Konsole.xml # Generate dbus .xml files; do not store .xml in source folder qt5_generate_dbus_interface(Session.h org.kde.konsole.Session.xml OPTIONS -m) qt5_generate_dbus_interface(ViewManager.h org.kde.konsole.Window.xml OPTIONS -m) qt5_add_dbus_adaptor(sessionadaptors_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.konsole.Session.xml Session.h Konsole::Session) qt5_add_dbus_adaptor(windowadaptors_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.konsole.Window.xml ViewManager.h Konsole::ViewManager) set(konsoleprivate_SRCS ${sessionadaptors_SRCS} ${windowadaptors_SRCS} BookmarkHandler.cpp ColorScheme.cpp ColorSchemeManager.cpp ColorSchemeEditor.cpp CopyInputDialog.cpp EditProfileDialog.cpp FontDialog.cpp Emulation.cpp DetachableTabBar.cpp Filter.cpp History.cpp HistorySizeDialog.cpp HistorySizeWidget.cpp IncrementalSearchBar.cpp KeyBindingEditor.cpp KeyboardTranslator.cpp KeyboardTranslatorManager.cpp ProcessInfo.cpp Profile.cpp ProfileList.cpp ProfileReader.cpp ProfileWriter.cpp ProfileManager.cpp Pty.cpp RenameTabDialog.cpp RenameTabWidget.cpp SaveHistoryTask.cpp SearchHistoryTask.cpp Screen.cpp ScreenWindow.cpp ScrollState.cpp Session.cpp SessionController.cpp SessionManager.cpp SessionListModel.cpp SessionTask.cpp ShellCommand.cpp TabTitleFormatButton.cpp TerminalCharacterDecoder.cpp ExtendedCharTable.cpp TerminalDisplay.cpp TerminalDisplayAccessible.cpp TerminalHeaderBar.cpp LineBlockCharacters.cpp ViewContainer.cpp ViewManager.cpp ViewProperties.cpp ViewSplitter.cpp Vt102Emulation.cpp ZModemDialog.cpp PrintOptions.cpp WindowSystemInfo.cpp CharacterWidth.cpp ${CMAKE_CURRENT_BINARY_DIR}/org.kde.konsole.Window.xml ${CMAKE_CURRENT_BINARY_DIR}/org.kde.konsole.Session.xml) ecm_qt_declare_logging_category(konsoleprivate_SRCS HEADER konsoledebug.h IDENTIFIER KonsoleDebug CATEGORY_NAME org.kde.konsole) kconfig_add_kcfg_files(konsoleprivate_SRCS settings/KonsoleSettings.kcfgc) set(konsole_LIBS KF5::XmlGui Qt5::PrintSupport Qt5::Xml KF5::Notifications KF5::WindowSystem KF5::TextWidgets KF5::GuiAddons KF5::IconThemes KF5::Bookmarks KF5::I18n KF5::Pty KF5::KIOWidgets KF5::DBusAddons KF5::GlobalAccel KF5::NewStuff ) if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") #kinfo_getfile() is in libutil list(APPEND konsole_LIBS util) endif() ### Konsole Application ki18n_wrap_ui(konsoleprivate_SRCS ColorSchemeEditor.ui CopyInputDialog.ui EditProfileGeneralPage.ui EditProfileTabsPage.ui EditProfileAppearancePage.ui EditProfileScrollingPage.ui EditProfileKeyboardPage.ui EditProfileMousePage.ui EditProfileAdvancedPage.ui KeyBindingEditor.ui RenameTabDialog.ui RenameTabWidget.ui HistorySizeDialog.ui HistorySizeWidget.ui PrintOptions.ui - settings/FileLocationSettings.ui + settings/TemporaryFilesSettings.ui settings/GeneralSettings.ui settings/PartInfo.ui settings/ProfileSettings.ui settings/TabBarSettings.ui) # add the resource files for the ui files qt5_add_resources( konsoleprivate_SRCS ../desktop/konsole.qrc) add_library(konsoleprivate ${konsoleprivate_SRCS}) generate_export_header(konsoleprivate BASE_NAME konsoleprivate) target_link_libraries(konsoleprivate PUBLIC ${konsole_LIBS}) set_target_properties(konsoleprivate PROPERTIES VERSION ${KONSOLEPRIVATE_VERSION_STRING} SOVERSION ${KONSOLEPRIVATE_SOVERSION} ) install(TARGETS konsoleprivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) set(konsole_KDEINIT_SRCS Application.cpp MainWindow.cpp main.cpp - settings/FileLocationSettings.cpp + settings/ConfigurationDialog.cpp + settings/TemporaryFilesSettings.cpp settings/GeneralSettings.cpp settings/ProfileSettings.cpp settings/TabBarSettings.cpp) # Sets the icon on Windows and OSX file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../data/icons/*.png") ecm_add_app_icon(kdeinit_konsole ICONS ${ICONS_SRCS}) kf5_add_kdeinit_executable(konsole ${konsole_KDEINIT_SRCS}) target_link_libraries(kdeinit_konsole konsoleprivate KF5::XmlGui KF5::WindowSystem KF5::Bookmarks KF5::I18n KF5::KIOWidgets KF5::NotifyConfig KF5::Crash ) if(APPLE) set_target_properties(konsole PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.konsole" MACOSX_BUNDLE_BUNDLE_NAME "Konsole" MACOSX_BUNDLE_DISPLAY_NAME "Konsole" MACOSX_BUNDLE_INFO_STRING "Konsole, the KDE terminal emulator" MACOSX_BUNDLE_LONG_VERSION_STRING "Konsole ${KDE_APPLICATIONS_VERSION}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}" MACOSX_BUNDLE_BUNDLE_VERSION "${KDE_APPLICATIONS_VERSION}" MACOSX_BUNDLE_COPYRIGHT "1997-2016 The Konsole Developers") endif() install(TARGETS kdeinit_konsole konsole ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ### Embedded Konsole KPart set(konsolepart_PART_SRCS Part.cpp settings/PartInfo.cpp settings/ProfileSettings.cpp) add_library(konsolepart MODULE ${konsolepart_PART_SRCS}) generate_export_header(konsolepart BASE_NAME konsole) kcoreaddons_desktop_to_json(konsolepart ../desktop/konsolepart.desktop) set_target_properties(konsolepart PROPERTIES DEFINE_SYMBOL KONSOLE_PART) target_link_libraries(konsolepart KF5::Parts KF5::XmlGui konsoleprivate) install(TARGETS konsolepart DESTINATION ${KDE_INSTALL_PLUGINDIR}) diff --git a/src/EditProfileGeneralPage.ui b/src/EditProfileGeneralPage.ui index a40b0fc6..48acc48c 100644 --- a/src/EditProfileGeneralPage.ui +++ b/src/EditProfileGeneralPage.ui @@ -1,352 +1,352 @@ EditProfileGeneralPage 0 0 400 400 0 0 0 0 0 6 0 0 48 48 0 0 Select the icon displayed on tabs using this profile 32 32 A descriptive name for the profile Profile name 0 0 Command: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter commandEdit The command to execute when new terminal sessions are created using this profile Qt::LeftToRight /bin/sh 0 0 Initial directory: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter initialDirEdit The initial working directory for new terminal sessions using this profile Qt::LeftToRight /home/username Choose the initial directory ... Start in same directory as current tab 0 0 Environment: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter environmentEditButton 0 Edit the list of environment variables and associated values Edit... Qt::Horizontal 40 20 Qt::Vertical QSizePolicy::Fixed 20 16 0 0 Initial terminal size: terminalColumnsEntry 0 6 0 0 1 999 0 0 1 999 Qt::Horizontal 40 20 0 0 - <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 true Qt::Vertical QSizePolicy::Expanding 20 0 KPluralHandlingSpinBox QSpinBox
KPluralHandlingSpinBox
environmentEditButton terminalColumnsEntry terminalRowsEntry
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 3d7745c5..de8f1035 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1,893 +1,894 @@ /* Copyright 2006-2008 by Robert Knight 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 "MainWindow.h" // Qt #include #include // KDE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Konsole #include "BookmarkHandler.h" #include "SessionController.h" #include "ProfileList.h" #include "Session.h" #include "ViewContainer.h" #include "ViewManager.h" #include "SessionManager.h" #include "ProfileManager.h" #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" using namespace Konsole; MainWindow::MainWindow() : KXmlGuiWindow(), _viewManager(nullptr), _bookmarkHandler(nullptr), _toggleMenuBarAction(nullptr), _newTabMenuAction(nullptr), _pluggedController(nullptr), _menuBarInitialVisibility(true), _menuBarInitialVisibilityApplied(false) { if (!KonsoleSettings::saveGeometryOnExit()) { // If we are not using the global Konsole save geometry on exit, // remove all Height and Width from [MainWindow] from konsolerc // Each screen resolution will have entries (Width 1280=619) KSharedConfigPtr konsoleConfig = KSharedConfig::openConfig(QStringLiteral("konsolerc")); KConfigGroup group = konsoleConfig->group("MainWindow"); QMap configEntries = group.entryMap(); QMapIterator i(configEntries); while (i.hasNext()) { i.next(); if (i.key().startsWith(QLatin1String("Width")) || i.key().startsWith(QLatin1String("Height"))) { group.deleteEntry(i.key()); } } } updateUseTransparency(); // create actions for menus setupActions(); // create view manager _viewManager = new ViewManager(this, actionCollection()); connect(_viewManager, &Konsole::ViewManager::empty, this, &Konsole::MainWindow::close); connect(_viewManager, &Konsole::ViewManager::activeViewChanged, this, &Konsole::MainWindow::activeViewChanged); connect(_viewManager, &Konsole::ViewManager::unplugController, this, &Konsole::MainWindow::disconnectController); connect(_viewManager, &Konsole::ViewManager::viewPropertiesChanged, bookmarkHandler(), &Konsole::BookmarkHandler::setViews); connect(_viewManager, &Konsole::ViewManager::blurSettingChanged, this, &Konsole::MainWindow::setBlur); connect(_viewManager, &Konsole::ViewManager::updateWindowIcon, this, &Konsole::MainWindow::updateWindowIcon); connect(_viewManager, &Konsole::ViewManager::newViewWithProfileRequest, this, &Konsole::MainWindow::newFromProfile); connect(_viewManager, &Konsole::ViewManager::newViewRequest, this, &Konsole::MainWindow::newTab); connect(_viewManager, &Konsole::ViewManager::terminalsDetached, this, &Konsole::MainWindow::terminalsDetached); setCentralWidget(_viewManager->widget()); // disable automatically generated accelerators in top-level // menu items - to avoid conflicting with Alt+[Letter] shortcuts // in terminal applications KAcceleratorManager::setNoAccel(menuBar()); // create menus createGUI(); // remember the original menu accelerators for later use rememberMenuAccelerators(); // replace standard shortcuts which cannot be used in a terminal // emulator (as they are reserved for use by terminal applications) correctStandardShortcuts(); setProfileList(new ProfileList(false, this)); // this must come at the end applyKonsoleSettings(); connect(KonsoleSettings::self(), &Konsole::KonsoleSettings::configChanged, this, &Konsole::MainWindow::applyKonsoleSettings); } void MainWindow::updateUseTransparency() { if (!WindowSystemInfo::HAVE_TRANSPARENCY) { return; } bool useTranslucency = KWindowSystem::compositingActive(); setAttribute(Qt::WA_TranslucentBackground, useTranslucency); setAttribute(Qt::WA_NoSystemBackground, false); WindowSystemInfo::HAVE_TRANSPARENCY = useTranslucency; } void MainWindow::rememberMenuAccelerators() { foreach (QAction *menuItem, menuBar()->actions()) { QString itemText = menuItem->text(); menuItem->setData(itemText); } } // remove accelerators for standard menu items (eg. &File, &View, &Edit) // etc. which are defined in kdelibs/kdeui/xmlgui/ui_standards.rc, again, // to avoid conflicting with Alt+[Letter] terminal shortcuts // // TODO - Modify XMLGUI so that it allows the text for standard actions // defined in ui_standards.rc to be re-defined in the local application // XMLGUI file (konsoleui.rc in this case) - the text for standard items // can then be redefined there to exclude the standard accelerators void MainWindow::removeMenuAccelerators() { foreach (QAction *menuItem, menuBar()->actions()) { menuItem->setText(menuItem->text().replace(QLatin1Char('&'), QString())); } } void MainWindow::restoreMenuAccelerators() { foreach (QAction *menuItem, menuBar()->actions()) { QString itemText = menuItem->data().toString(); menuItem->setText(itemText); } } void MainWindow::correctStandardShortcuts() { // replace F1 shortcut for help contents QAction *helpAction = actionCollection()->action(QStringLiteral("help_contents")); if (helpAction != nullptr) { actionCollection()->setDefaultShortcut(helpAction, QKeySequence()); } // replace Ctrl+B shortcut for bookmarks only if user hasn't already // changed the shortcut; however, if the user changed it to Ctrl+B // this will still get changed to Ctrl+Shift+B QAction *bookmarkAction = actionCollection()->action(QStringLiteral("add_bookmark")); if ((bookmarkAction != nullptr) && bookmarkAction->shortcut() == QKeySequence(Konsole::ACCEL + Qt::Key_B)) { actionCollection()->setDefaultShortcut(bookmarkAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_B); } } ViewManager *MainWindow::viewManager() const { return _viewManager; } void MainWindow::disconnectController(SessionController *controller) { disconnect(controller, &Konsole::SessionController::titleChanged, this, &Konsole::MainWindow::activeViewTitleChanged); disconnect(controller, &Konsole::SessionController::rawTitleChanged, this, &Konsole::MainWindow::updateWindowCaption); disconnect(controller, &Konsole::SessionController::iconChanged, this, &Konsole::MainWindow::updateWindowIcon); if (auto view = controller->view()) { view->removeEventFilter(this); } // KXmlGuiFactory::removeClient() will try to access actions associated // with the controller internally, which may not be valid after the controller // itself is no longer valid (after the associated session and or view have // been destroyed) if (controller->isValid()) { guiFactory()->removeClient(controller); } if (_pluggedController == controller) { _pluggedController = nullptr; } } void MainWindow::activeViewChanged(SessionController *controller) { if (!SessionManager::instance()->sessionProfile(controller->session())) { return; } // associate bookmark menu with current session bookmarkHandler()->setActiveView(controller); disconnect(bookmarkHandler(), &Konsole::BookmarkHandler::openUrl, nullptr, nullptr); connect(bookmarkHandler(), &Konsole::BookmarkHandler::openUrl, controller, &Konsole::SessionController::openUrl); if (!_pluggedController.isNull()) { disconnectController(_pluggedController); } Q_ASSERT(controller); _pluggedController = controller; _pluggedController->view()->installEventFilter(this); setBlur(ViewManager::profileHasBlurEnabled(SessionManager::instance()->sessionProfile(_pluggedController->session()))); // listen for title changes from the current session connect(controller, &Konsole::SessionController::titleChanged, this, &Konsole::MainWindow::activeViewTitleChanged); connect(controller, &Konsole::SessionController::rawTitleChanged, this, &Konsole::MainWindow::updateWindowCaption); connect(controller, &Konsole::SessionController::iconChanged, this, &Konsole::MainWindow::updateWindowIcon); controller->setShowMenuAction(_toggleMenuBarAction); guiFactory()->addClient(controller); // update session title to match newly activated session activeViewTitleChanged(controller); // Update window icon to newly activated session's icon updateWindowIcon(); } void MainWindow::activeViewTitleChanged(ViewProperties *properties) { Q_UNUSED(properties); updateWindowCaption(); } void MainWindow::updateWindowCaption() { if (_pluggedController.isNull()) { return; } const QString &title = _pluggedController->title(); const QString &userTitle = _pluggedController->userTitle(); // use tab title as caption by default QString caption = title; // use window title as caption when this setting is enabled // if the userTitle is empty, use a blank space (using an empty string // removes the dash — before the application name; leaving the dash // looks better) if (KonsoleSettings::showWindowTitleOnTitleBar()) { !userTitle.isEmpty() ? caption = userTitle : caption = QStringLiteral(" "); } setCaption(caption); } void MainWindow::updateWindowIcon() { if ((!_pluggedController.isNull()) && !_pluggedController->icon().isNull()) { setWindowIcon(_pluggedController->icon()); } } void MainWindow::setupActions() { KActionCollection *collection = actionCollection(); // File Menu _newTabMenuAction = new KActionMenu(QIcon::fromTheme(QStringLiteral("tab-new")), i18nc("@action:inmenu", "&New Tab"), collection); collection->setDefaultShortcut(_newTabMenuAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_T); collection->setShortcutsConfigurable(_newTabMenuAction, true); _newTabMenuAction->setAutoRepeat(false); connect(_newTabMenuAction, &KActionMenu::triggered, this, &MainWindow::newTab); collection->addAction(QStringLiteral("new-tab"), _newTabMenuAction); collection->setShortcutsConfigurable(_newTabMenuAction, true); QAction* menuAction = collection->addAction(QStringLiteral("clone-tab")); menuAction->setIcon(QIcon::fromTheme(QStringLiteral("tab-duplicate"))); menuAction->setText(i18nc("@action:inmenu", "&Clone Tab")); collection->setDefaultShortcut(menuAction, QKeySequence()); menuAction->setAutoRepeat(false); connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::cloneTab); menuAction = collection->addAction(QStringLiteral("new-window")); menuAction->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); menuAction->setText(i18nc("@action:inmenu", "New &Window")); collection->setDefaultShortcut(menuAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_N); menuAction->setAutoRepeat(false); connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::newWindow); menuAction = collection->addAction(QStringLiteral("close-window")); menuAction->setIcon(QIcon::fromTheme(QStringLiteral("window-close"))); menuAction->setText(i18nc("@action:inmenu", "Close Window")); collection->setDefaultShortcut(menuAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_Q); connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::close); // Bookmark Menu KActionMenu *bookmarkMenu = new KActionMenu(i18nc("@title:menu", "&Bookmarks"), collection); _bookmarkHandler = new BookmarkHandler(collection, bookmarkMenu->menu(), true, this); collection->addAction(QStringLiteral("bookmark"), bookmarkMenu); connect(_bookmarkHandler, &Konsole::BookmarkHandler::openUrls, this, &Konsole::MainWindow::openUrls); // Settings Menu _toggleMenuBarAction = KStandardAction::showMenubar(menuBar(), SLOT(setVisible(bool)), collection); collection->setDefaultShortcut(_toggleMenuBarAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_M); // Full Screen menuAction = KStandardAction::fullScreen(this, SLOT(viewFullScreen(bool)), this, collection); collection->setDefaultShortcut(menuAction, Qt::Key_F11); KStandardAction::configureNotifications(this, SLOT(configureNotifications()), collection); KStandardAction::keyBindings(this, SLOT(showShortcutsDialog()), collection); KStandardAction::preferences(this, SLOT(showSettingsDialog()), collection); menuAction = collection->addAction(QStringLiteral("manage-profiles")); menuAction->setText(i18nc("@action:inmenu", "Manage Profiles...")); menuAction->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::showManageProfilesDialog); // Set up an shortcut-only action for activating menu bar. menuAction = collection->addAction(QStringLiteral("activate-menu")); menuAction->setText(i18nc("@item", "Activate Menu")); collection->setDefaultShortcut(menuAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_F10); connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::activateMenuBar); } void MainWindow::viewFullScreen(bool fullScreen) { if (fullScreen) { setWindowState(windowState() | Qt::WindowFullScreen); } else { setWindowState(windowState() & ~Qt::WindowFullScreen); } } BookmarkHandler *MainWindow::bookmarkHandler() const { return _bookmarkHandler; } void MainWindow::setProfileList(ProfileList *list) { profileListChanged(list->actions()); connect(list, &Konsole::ProfileList::profileSelected, this, &MainWindow::newFromProfile); connect(list, &Konsole::ProfileList::actionsChanged, this, &Konsole::MainWindow::profileListChanged); } void MainWindow::profileListChanged(const QList &sessionActions) { // If only 1 profile is to be shown in the menu, only display // it if it is the non-default profile. if (sessionActions.size() > 2) { // Update the 'New Tab' KActionMenu if (_newTabMenuAction->menu() != nullptr) { _newTabMenuAction->menu()->clear(); } else { _newTabMenuAction->setMenu(new QMenu()); } foreach (QAction *sessionAction, sessionActions) { _newTabMenuAction->menu()->addAction(sessionAction); // NOTE: defaultProfile seems to not work here, sigh. Profile::Ptr profile = ProfileManager::instance()->defaultProfile(); if (profile && profile->name() == sessionAction->text().remove(QLatin1Char('&'))) { QIcon icon(KIconLoader::global()->loadIcon(profile->icon(), KIconLoader::Small, 0, KIconLoader::DefaultState, QStringList(QStringLiteral("emblem-favorite")))); sessionAction->setIcon(icon); _newTabMenuAction->menu()->setDefaultAction(sessionAction); QFont actionFont = sessionAction->font(); actionFont.setBold(true); sessionAction->setFont(actionFont); } } } else { if (_newTabMenuAction->menu() != nullptr) { _newTabMenuAction->menu()->clear(); } else { _newTabMenuAction->setMenu(new QMenu()); } Profile::Ptr profile = ProfileManager::instance()->defaultProfile(); // NOTE: Compare names w/o any '&' if (sessionActions.size() == 2 && sessionActions[1]->text().remove(QLatin1Char('&')) != profile->name()) { _newTabMenuAction->menu()->addAction(sessionActions[1]); } else { _newTabMenuAction->menu()->deleteLater(); } } } QString MainWindow::activeSessionDir() const { if (!_pluggedController.isNull()) { if (Session *session = _pluggedController->session()) { // For new tabs to get the correct working directory, // force the updating of the currentWorkingDirectory. session->getDynamicTitle(); } return _pluggedController->currentDir(); } else { return QString(); } } void MainWindow::openUrls(const QList &urls) { Profile::Ptr defaultProfile = ProfileManager::instance()->defaultProfile(); for (const auto &url : urls) { if (url.isLocalFile()) { createSession(defaultProfile, url.path()); } else if (url.scheme() == QLatin1String("ssh")) { createSSHSession(defaultProfile, url); } } } void MainWindow::newTab() { Profile::Ptr defaultProfile = ProfileManager::instance()->defaultProfile(); createSession(defaultProfile, activeSessionDir()); } void MainWindow::cloneTab() { Q_ASSERT(_pluggedController); Session *session = _pluggedController->session(); Profile::Ptr profile = SessionManager::instance()->sessionProfile(session); if (profile) { createSession(profile, activeSessionDir()); } else { // something must be wrong: every session should be associated with profile Q_ASSERT(false); newTab(); } } Session *MainWindow::createSession(Profile::Ptr profile, const QString &directory) { if (!profile) { profile = ProfileManager::instance()->defaultProfile(); } Session *session = SessionManager::instance()->createSession(profile); if (!directory.isEmpty() && profile->startInCurrentSessionDir()) { session->setInitialWorkingDirectory(directory); } session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(_viewManager->managerId())); // create view before starting the session process so that the session // doesn't suffer a change in terminal size right after the session // starts. Some applications such as GNU Screen and Midnight Commander // don't like this happening auto newView = _viewManager->createView(session); _viewManager->activeContainer()->addView(newView); return session; } Session *MainWindow::createSSHSession(Profile::Ptr profile, const QUrl &url) { if (!profile) { profile = ProfileManager::instance()->defaultProfile(); } Session *session = SessionManager::instance()->createSession(profile); QString sshCommand = QStringLiteral("ssh "); if (url.port() > -1) { sshCommand += QStringLiteral("-p %1 ").arg(url.port()); } if (!url.userName().isEmpty()) { sshCommand += (url.userName() + QLatin1Char('@')); } if (!url.host().isEmpty()) { sshCommand += url.host(); } session->sendTextToTerminal(sshCommand, QLatin1Char('\r')); // create view before starting the session process so that the session // doesn't suffer a change in terminal size right after the session // starts. some applications such as GNU Screen and Midnight Commander // don't like this happening auto newView = _viewManager->createView(session); _viewManager->activeContainer()->addView(newView); return session; } void MainWindow::setFocus() { _viewManager->activeView()->setFocus(); } void MainWindow::newWindow() { Profile::Ptr defaultProfile = ProfileManager::instance()->defaultProfile(); emit newWindowRequest(defaultProfile, activeSessionDir()); } bool MainWindow::queryClose() { // Do not ask for confirmation during log out and power off // TODO: rework the dealing of this case to make it has its own confirmation // dialog. if (qApp->isSavingSession()) { return true; } // Check what processes are running, excluding the shell QStringList processesRunning; const auto uniqueSessions = QSet::fromList(_viewManager->sessions()); foreach (Session *session, uniqueSessions) { if ((session == nullptr) || !session->isForegroundProcessActive()) { continue; } const QString defaultProc = session->program().split(QLatin1Char('/')).last(); const QString currentProc = session->foregroundProcessName().split(QLatin1Char('/')).last(); if (currentProc.isEmpty()) { continue; } if (defaultProc != currentProc) { processesRunning.append(currentProc); } } // Get number of open tabs const int openTabs = _viewManager->viewProperties().count(); // If no processes running (except the shell) and no extra tabs, just close if (processesRunning.count() == 0 && openTabs < 2) { return true; } // NOTE: Some, if not all, of the below KWindowSystem calls are only // implemented under x11 (KDE4.8 kdelibs/kdeui/windowmanagement). // make sure the window is shown on current desktop and is not minimized KWindowSystem::setOnDesktop(winId(), KWindowSystem::currentDesktop()); if (isMinimized()) { KWindowSystem::unminimizeWindow(winId(), true); } int result; if (!processesRunning.isEmpty()) { result = KMessageBox::warningYesNoCancelList(this, i18ncp("@info", "There is a process running in this window. " "Do you still want to quit?", "There are %1 processes running in this window. " "Do you still want to quit?", processesRunning.count()), processesRunning, i18nc("@title", "Confirm Close"), KGuiItem(i18nc("@action:button", "Close &Window"), QStringLiteral("window-close")), KGuiItem(i18nc("@action:button", "Close Current &Tab"), QStringLiteral("tab-close")), KStandardGuiItem::cancel(), QStringLiteral("CloseAllTabs")); } else { result = KMessageBox::warningYesNoCancel(this, i18nc("@info", "There are %1 open tabs in this window. " "Do you still want to quit?", openTabs), i18nc("@title", "Confirm Close"), KGuiItem(i18nc("@action:button", "Close &Window"), QStringLiteral("window-close")), KGuiItem(i18nc("@action:button", "Close Current &Tab"), QStringLiteral("tab-close")), KStandardGuiItem::cancel(), QStringLiteral("CloseAllEmptyTabs")); } switch (result) { case KMessageBox::Yes: return true; case KMessageBox::No: if ((!_pluggedController.isNull()) && (!_pluggedController->session().isNull())) { disconnectController(_pluggedController); _pluggedController->session()->closeInNormalWay(); } return false; case KMessageBox::Cancel: return false; } return true; } void MainWindow::saveProperties(KConfigGroup &group) { _viewManager->saveSessions(group); } void MainWindow::readProperties(const KConfigGroup &group) { _viewManager->restoreSessions(group); } void MainWindow::saveGlobalProperties(KConfig *config) { SessionManager::instance()->saveSessions(config); } void MainWindow::readGlobalProperties(KConfig *config) { SessionManager::instance()->restoreSessions(config); } void MainWindow::syncActiveShortcuts(KActionCollection *dest, const KActionCollection *source) { foreach (QAction *qAction, source->actions()) { if (QAction *destQAction = dest->action(qAction->objectName())) { destQAction->setShortcut(qAction->shortcut()); } } } void MainWindow::showShortcutsDialog() { KShortcutsDialog dialog(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsDisallowed, this); // add actions from this window and the current session controller foreach (KXMLGUIClient *client, guiFactory()->clients()) { dialog.addCollection(client->actionCollection()); } if (dialog.configure()) { // sync shortcuts for non-session actions (defined in "konsoleui.rc") in other main windows foreach (QWidget *mainWindowWidget, QApplication::topLevelWidgets()) { auto *mainWindow = qobject_cast(mainWindowWidget); if ((mainWindow != nullptr) && mainWindow != this) { syncActiveShortcuts(mainWindow->actionCollection(), actionCollection()); } } // sync shortcuts for session actions (defined in "sessionui.rc") in other session controllers. // Controllers which are currently plugged in (ie. their actions are part of the current menu) // must be updated immediately via syncActiveShortcuts(). Other controllers will be updated // when they are plugged into a main window. foreach (SessionController *controller, SessionController::allControllers()) { controller->reloadXML(); if ((controller->factory() != nullptr) && controller != _pluggedController) { syncActiveShortcuts(controller->actionCollection(), _pluggedController->actionCollection()); } } } } void MainWindow::newFromProfile(const Profile::Ptr &profile) { createSession(profile, activeSessionDir()); } void MainWindow::showManageProfilesDialog() { showSettingsDialog(true); } 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() { setMenuBarInitialVisibility(KonsoleSettings::showMenuBarByDefault()); setRemoveWindowTitleBarAndFrame(KonsoleSettings::removeWindowTitleBarAndFrame()); if (KonsoleSettings::allowMenuAccelerators()) { restoreMenuAccelerators(); } else { removeMenuAccelerators(); } _viewManager->activeContainer()->setNavigationBehavior(KonsoleSettings::newTabBehavior()); setAutoSaveSettings(QStringLiteral("MainWindow"), KonsoleSettings::saveGeometryOnExit()); updateWindowCaption(); } void MainWindow::activateMenuBar() { const QList menuActions = menuBar()->actions(); if (menuActions.isEmpty()) { return; } // Show menubar if it is hidden at the moment if (menuBar()->isHidden()) { menuBar()->setVisible(true); _toggleMenuBarAction->setChecked(true); } // First menu action should be 'File' QAction *menuAction = menuActions.first(); // TODO: Handle when menubar is top level (MacOS) menuBar()->setActiveAction(menuAction); } void MainWindow::configureNotifications() { KNotifyConfigWidget::configure(this); } void MainWindow::setBlur(bool blur) { if (_pluggedController.isNull()) { return; } if (!_pluggedController->isKonsolePart()) { KWindowEffects::enableBlurBehind(winId(), blur); } } void MainWindow::setMenuBarInitialVisibility(bool visible) { _menuBarInitialVisibility = visible; } void MainWindow::setRemoveWindowTitleBarAndFrame(bool frameless) { // This is used to check if the window is in "opening" state // And avoid the visibility change when we change the window flag bool oldVisibility = isVisible(); if (frameless) { setWindowFlags(Qt::FramelessWindowHint); } else { setWindowFlags(Qt::Widget); } if (oldVisibility && !isVisible()) { setVisible(true); } } void MainWindow::showEvent(QShowEvent *event) { // Make sure the 'initial' visibility is applied only once. if (!_menuBarInitialVisibilityApplied) { // the initial visibility of menubar should be applied at this last // moment. Otherwise, the initial visibility will be determined by // what KMainWindow has automatically stored in konsolerc, but not by // what users has explicitly configured . menuBar()->setVisible(_menuBarInitialVisibility); _toggleMenuBarAction->setChecked(_menuBarInitialVisibility); _menuBarInitialVisibilityApplied = true; if (!KonsoleSettings::saveGeometryOnExit()) { resize(sizeHint()); } } // Call parent method KXmlGuiWindow::showEvent(event); } void MainWindow::triggerAction(const QString &name) const { if (auto action = actionCollection()->action(name)) { if (action->isEnabled()) { action->trigger(); } } } bool MainWindow::eventFilter(QObject *obj, QEvent *event) { if (!_pluggedController.isNull() && obj == _pluggedController->view()) { switch(event->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonDblClick: switch(static_cast(event)->button()) { case Qt::ForwardButton: triggerAction(QStringLiteral("next-view")); break; case Qt::BackButton: triggerAction(QStringLiteral("previous-view")); break; default: ; } default: ; } } return KXmlGuiWindow::eventFilter(obj, event); } bool MainWindow::focusNextPrevChild(bool) { // In stand-alone konsole, always disable implicit focus switching // through 'Tab' and 'Shift+Tab' // // Kpart is another different story return false; } diff --git a/src/settings/ConfigurationDialog.cpp b/src/settings/ConfigurationDialog.cpp new file mode 100644 index 00000000..b7879961 --- /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/ConfigurationDialog.h b/src/settings/ConfigurationDialog.h new file mode 100644 index 00000000..1f5c2742 --- /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/FileLocationSettings.cpp b/src/settings/FileLocationSettings.cpp deleted file mode 100644 index 65f454b8..00000000 --- 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 index c5dc3081..00000000 --- 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 index 3307be6d..f4c4234c 100644 --- a/src/settings/GeneralSettings.ui +++ b/src/settings/GeneralSettings.ui @@ -1,275 +1,312 @@ GeneralSettings 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.cpp b/src/settings/ProfileSettings.cpp index 8dc8df4b..7d810310 100644 --- a/src/settings/ProfileSettings.cpp +++ b/src/settings/ProfileSettings.cpp @@ -1,514 +1,545 @@ /* Copyright 2007-2008 by Robert Knight 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 "ProfileSettings.h" +#include // Qt #include #include #include +#include // KDE -#include #include #include #include // Konsole #include "EditProfileDialog.h" #include "ProfileManager.h" #include "Session.h" #include "TerminalDisplay.h" #include "SessionManager.h" #include "SessionController.h" using namespace Konsole; ProfileSettings::ProfileSettings(QWidget* aParent) : QWidget(aParent) , _sessionModel(new QStandardItemModel(this)) { 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); connect(editProfileButton, &QPushButton::clicked, this, &Konsole::ProfileSettings::editSelected); connect(deleteProfileButton, &QPushButton::clicked, this, &Konsole::ProfileSettings::deleteSelected); connect(setAsDefaultButton, &QPushButton::clicked, this, &Konsole::ProfileSettings::setSelectedAsDefault); } ProfileSettings::~ProfileSettings() = default; void ProfileSettings::slotAccepted() { ProfileManager::instance()->saveSettings(); deleteLater(); } void ProfileSettings::itemDataChanged(QStandardItem* item) { 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; } } return -1; } void ProfileSettings::removeItems(const Profile::Ptr &profile) { int row = rowForProfile(profile); if (row < 0) { return; } _sessionModel->removeRow(row); } void ProfileSettings::updateItems(const Profile::Ptr &profile) { const int row = rowForProfile(profile); if (row < 0) { return; } 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) { QStandardItem *item = _sessionModel->itemFromIndex(index); if (item->column() == ProfileNameColumn) { editSelected(); } } void ProfileSettings::addItems(const Profile::Ptr &profile) { if (profile->isHidden()) { return; } // each _sessionModel row has three items. 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); foreach(const Profile::Ptr& profile, profiles) { addItems(profile); } updateDefaultItem(); connect(_sessionModel, &QStandardItemModel::itemChanged, this, &Konsole::ProfileSettings::itemDataChanged); // listen for changes in the table selection and update the state of the form's buttons // accordingly. // // 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() { foreach(const Profile::Ptr & profile, selectedProfiles()) { if (profile != ProfileManager::instance()->defaultProfile()) { ProfileManager::instance()->deleteProfile(profile); } } } void ProfileSettings::setSelectedAsDefault() { ProfileManager::instance()->setDefaultProfile(currentProfile()); // do not allow the new default session type to be removed deleteProfileButton->setEnabled(false); setAsDefaultButton->setEnabled(false); // update font of new default item 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 // or the default if no profile is selected Profile::Ptr sourceProfile = currentProfile() ? currentProfile() : ProfileManager::instance()->defaultProfile(); Q_ASSERT(sourceProfile); 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")); // Consider https://blogs.kde.org/2009/03/26/how-crash-almost-every-qtkde-application-and-how-fix-it-0 before changing the below QPointer dialog = new EditProfileDialog(this); dialog.data()->setProfile(newProfile); dialog.data()->selectProfileName(); if (dialog.data()->exec() == QDialog::Accepted) { ProfileManager::instance()->addProfile(newProfile); ProfileManager::instance()->setFavorite(newProfile, true); ProfileManager::instance()->changeProfile(newProfile, newProfile->setProperties()); } delete dialog.data(); } void ProfileSettings::editSelected() { QList profiles(selectedProfiles()); foreach (Session* session, SessionManager::instance()->sessions()) { foreach (TerminalDisplay* terminal, session->views()) { // Searching for opened profiles if (terminal->sessionController()->profileDialogPointer() != nullptr) { foreach (const Profile::Ptr & profile, profiles) { if (profile->name() == terminal->sessionController()->profileDialogPointer()->lookupProfile()->name() && terminal->sessionController()->profileDialogPointer()->isVisible()) { // close opened edit dialog terminal->sessionController()->profileDialogPointer()->close(); } } } } } EditProfileDialog dialog(this); // the dialog will delete the profile group when it is destroyed ProfileGroup* group = new ProfileGroup; foreach (const Profile::Ptr & profile, profiles) { group->addProfile(profile); } group->updateValues(); dialog.setProfile(Profile::Ptr(group)); dialog.exec(); } 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 { if (!profile) { return false; } const QFileInfo fileInfo(profile->path()); if (!fileInfo.exists()) { return false; } const QFileInfo dirInfo(fileInfo.path()); return dirInfo.isWritable(); } void ProfileSettings::updateFavoriteStatus(const Profile::Ptr &profile, bool favorite) { Q_ASSERT(_sessionModel); 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&) { const auto* opt = qstyleoption_cast(&option); const QWidget* widget = opt != nullptr ? opt->widget : nullptr; QStyle* style = widget != nullptr ? widget->style() : QApplication::style(); 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); emit closeEditor(editor); } void ShortcutItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { _itemsBeingEdited.remove(index); if (!_modifiedEditors.contains(editor)) { return; } - QString shortcut = qobject_cast(editor)->keySequence().toString(); + QString shortcut = qobject_cast(editor)->keySequence().toString(); model->setData(index, shortcut, Qt::DisplayRole); _modifiedEditors.remove(editor); } QWidget* ShortcutItemDelegate::createEditor(QWidget* aParent, const QStyleOptionViewItem&, const QModelIndex& index) const { _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, const QModelIndex& index) const { if (_itemsBeingEdited.contains(index)) { StyledBackgroundPainter::drawBackground(painter, option, index); } else { QStyledItemDelegate::paint(painter, option, index); } } +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.h b/src/settings/ProfileSettings.h index ce6f7edd..10fd59d0 100644 --- a/src/settings/ProfileSettings.h +++ b/src/settings/ProfileSettings.h @@ -1,158 +1,164 @@ /* Copyright 2007-2008 by Robert Knight 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 PROFILESETTINGS_H #define PROFILESETTINGS_H // Qt #include #include +#include // KDE // Konsole #include "Profile.h" #include "ui_ProfileSettings.h" class QItemSelection; class QShowEvent; class QStandardItem; class QStandardItemModel; namespace Konsole { /** * A dialog which lists the available types of profiles and allows * the user to add new profiles, and remove or edit existing * profile types. */ class ProfileSettings : public QWidget, private Ui::ProfileSettings { Q_OBJECT - friend class FavoriteItemDelegate; friend class ShortcutItemDelegate; public: /** Constructs a new profile type with the specified parent. */ explicit ProfileSettings(QWidget *parent = nullptr); ~ProfileSettings() Q_DECL_OVERRIDE; /** * Specifies whether the shortcut editor should be show. * The shortcut editor allows shortcuts to be associated with * profiles. When a shortcut is changed, the dialog will call * SessionManager::instance()->setShortcut() to update the shortcut * associated with the profile. * * By default the editor is visible. */ void setShortcutEditorVisible(bool visible); protected: private Q_SLOTS: void slotAccepted(); void deleteSelected(); void setSelectedAsDefault(); void createProfile(); void editSelected(); - void moveUpSelected(); - void moveDownSelected(); void itemDataChanged(QStandardItem *item); // enables or disables Edit/Delete/Set as Default buttons when the // selection changes void tableSelectionChanged(const QItemSelection &); void updateFavoriteStatus(const Profile::Ptr &profile, bool favorite); void addItems(const Profile::Ptr&); void updateItems(const Profile::Ptr&); void removeItems(const Profile::Ptr&); // double clicking the profile name opens the edit profile dialog void doubleClicked(const QModelIndex &index); private: Profile::Ptr currentProfile() const; QList selectedProfiles() const; bool isProfileDeletable(Profile::Ptr profile) const; // updates the font of the items to match // 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 { public: static void drawBackground(QPainter *painter, const QStyleOptionViewItem &option, 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 { Q_OBJECT public: explicit ShortcutItemDelegate(QObject *parent = nullptr); void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, 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; mutable QSet _itemsBeingEdited; }; } #endif // MANAGEPROFILESDIALOG_H diff --git a/src/settings/ProfileSettings.ui b/src/settings/ProfileSettings.ui index b15188db..32e8012a 100644 --- a/src/settings/ProfileSettings.ui +++ b/src/settings/ProfileSettings.ui @@ -1,112 +1,144 @@ ProfileSettings 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 index b1906efb..d319b9f1 100644 --- a/src/settings/TabBarSettings.cpp +++ b/src/settings/TabBarSettings.cpp @@ -1,32 +1,42 @@ /* Copyright 2011 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 "TabBarSettings.h" using namespace Konsole; 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 index e93a38dd..ba2d4000 100644 --- a/src/settings/TabBarSettings.ui +++ b/src/settings/TabBarSettings.ui @@ -1,233 +1,568 @@ TabBarSettings 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/TemporaryFilesSettings.cpp b/src/settings/TemporaryFilesSettings.cpp new file mode 100644 index 00000000..a4872bf0 --- /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/FileLocationSettings.h b/src/settings/TemporaryFilesSettings.h similarity index 81% rename from src/settings/FileLocationSettings.h rename to src/settings/TemporaryFilesSettings.h index 93c59ea5..8d78aecd 100644 --- a/src/settings/FileLocationSettings.h +++ b/src/settings/TemporaryFilesSettings.h @@ -1,37 +1,37 @@ /* 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/. */ #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; }; } #endif diff --git a/src/settings/TemporaryFilesSettings.ui b/src/settings/TemporaryFilesSettings.ui new file mode 100644 index 00000000..a89958df --- /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 + + + + +