Mercurial > octave
changeset 31696:8fed04d0607c
eliminate shortcut_manager class and revamp shortcut handling
* settings-dialog.ui: Use a custom type for the
* shortcuts-tree-widget.h, shortcuts-tree-widget.cc: New files.
(shortcuts_tree_widget): New class to use for editing and displaying
shortcuts in the settings dialog. Adapt constructor from
shortcut_manager::fill_treewidget function.
(enter_shortcut): Move here from shortcut-manager.h and
shortcut-manager.cc.
(tree_widget_shortcut_item): New class to use for items in the
shortcuts_tree_widget class in place of QTreeWidgetItem.
(shortcut_edit_dialog): New class to use for shortcut editing dialog
in place of a simple QDialog. Allows for capturing edited values in
the dialog object.
* gui-preferences-sc.h, gui-preferences-sc.cc (sc_group):
Drop trailing "/" from definition and move here from
gui-preferences.h. Update code that prepends sc_group to a settings key.
(get_shortcut_section): New function.
* gui-preferences.h, gui-preferences.cc
(sc_pref::def_value, sc_pref::def_text): New functions.
(all_shortcut_preferences::value, all_shortcut_preferences::keys): New
static funtions.
(all_shortcut_preferences::do_value,
all_shortcut_preferences::do_keys): New helper functions.
* gui-settings.cc (gui_settings::sc_def_value):
Simply call sc_pref::def_value.
* settings-dialog.h, settings-dialog.cc (class settings_dialog):
Eliminate use of base_qobject and shortcut_manager.
(settings_dialog::import_shortcut_set): Get file name here. Call
shortcuts_tree_widget::import_shortcuts instead of
shortcut_manager::import_export.
(settings_dialog::export_shortcut_set): Get file name here. Call
shortcuts_tree_widget::export_shortcuts instead of
shortcut_manager::import_export.
(settings_dialog::default_shortcut_set): Check whether to overwrite
shortcuts here. Call shortcuts_tree_widget::set_default_shortcuts
instead of shortcut_manager::import_export.
(settings_dialog::write_changed_settings): Eliminate CLOSING
argument. Call shortcuts_tree_widget::write_settings instead of
shortcut_manager::write_shortcuts.
(settings_dialog::get_shortcuts_file_name): New function to prompt
user for file name.
(settings_dialog::overwrite_all_shortcuts): New function to ask user
whether replacing shortcuts is OK.
(import_export_action): Move enum decl here from shortcut-manager.h.
* main-window.cc (main_window::process_settings_dialog_request):
Eliminate m_octave_qobj in call to settings_dialog ctor.
(main_window::main_window): Don't call shortcut_manager::init_data.
* terminal-dock-widget.h, terminal-dock-widget.cc
(terminal_dock_widget::init_control_d_shortcut_behavior): New function.
(terminal_dock_widget::terminal_dock_widget): Use it instead of
performing same action in shortcut_manager::init.
* octave-qobject.h, octave-qobject.cc
(base_qobject::m_shortcut_manager): Delete data member.
(base_qobject::get_shortcut_manager): Delete.
(base_qobject::base_qobject): Don't call shortcut_manager::init_data.
* shortcut-manager.h, shortcut-manager.cc: Delete. Eliminates the now
unnecessary shortcut_manager class.
* libgui/src/module.mk: Update.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Mon, 26 Dec 2022 17:29:59 -0500 |
parents | 5749674b826e |
children | dd904ce6f53f |
files | libgui/src/documentation.cc libgui/src/gui-preferences-sc.cc libgui/src/gui-preferences-sc.h libgui/src/gui-preferences.cc libgui/src/gui-preferences.h libgui/src/gui-settings.cc libgui/src/main-window.cc libgui/src/module.mk libgui/src/octave-qobject.cc libgui/src/octave-qobject.h libgui/src/settings-dialog.cc libgui/src/settings-dialog.h libgui/src/settings-dialog.ui libgui/src/shortcut-manager.cc libgui/src/shortcut-manager.h libgui/src/shortcuts-tree-widget.cc libgui/src/shortcuts-tree-widget.h libgui/src/terminal-dock-widget.cc libgui/src/terminal-dock-widget.h |
diffstat | 19 files changed, 1145 insertions(+), 1015 deletions(-) [+] |
line wrap: on
line diff
--- a/libgui/src/documentation.cc Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/documentation.cc Mon Dec 26 17:29:59 2022 -0500 @@ -51,6 +51,7 @@ #include <QTimer> #include <QWheelEvent> #include <QVBoxLayout> +#include <QWheelEvent> #include "documentation.h" #include "documentation-bookmarks.h"
--- a/libgui/src/gui-preferences-sc.cc Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/gui-preferences-sc.cc Mon Dec 26 17:29:59 2022 -0500 @@ -216,3 +216,13 @@ sc_pref sc_doc_go_back (QCoreApplication::translate ("shortcuts", "Go Back one Page"), sc_doc + ":go_back", QKeySequence::Back); sc_pref sc_doc_go_next (QCoreApplication::translate ("shortcuts", "Go Forward one Page"), sc_doc + ":go_next", QKeySequence::Forward); sc_pref sc_doc_bookmark (QCoreApplication::translate ("shortcuts", "Bookmark this Page"), sc_doc + ":bookmark", CTRL + Qt::Key_D); + +QString get_shortcut_section (const QString& key) +{ + QString section; + + if (key.contains (':')) + section = key.section (':', 0, 0, QString::SectionSkipEmpty); + + return section; +}
--- a/libgui/src/gui-preferences-sc.h Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/gui-preferences-sc.h Mon Dec 26 17:29:59 2022 -0500 @@ -27,6 +27,7 @@ #define octave_gui_preferences_sc_h 1 #include <QSet> +#include <QString> #include "gui-preferences.h" @@ -57,8 +58,10 @@ const Qt::KeyboardModifiers CTRL_SHIFT = CTRL | Qt::ShiftModifier; const Qt::KeyboardModifiers CTRL_ALT = CTRL | Qt::AltModifier; +const QString sc_group ("shortcuts"); + // Shortcuts not related to specific Menus - + // Dock widgets const QString sc_dock_widget ("dock_widget"); extern sc_pref sc_dock_widget_dock; @@ -270,4 +273,6 @@ const gui_pref sc_prevent_rl_conflicts_menu ("shortcuts/prevent_readline_conflicts_menu", QVariant (false)); +extern QString get_shortcut_section (const QString& key); + #endif
--- a/libgui/src/gui-preferences.cc Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/gui-preferences.cc Mon Dec 26 17:29:59 2022 -0500 @@ -54,6 +54,23 @@ all_shortcut_preferences::insert (settings_key, *this); } +QKeySequence sc_pref::def_value (void) const +{ + QKeySequence key_seq = QKeySequence (); + + if (m_def) + key_seq = QKeySequence (m_def); + else if (m_def_std != QKeySequence::UnknownKey) + key_seq = QKeySequence (m_def_std); + + return key_seq; +} + +QString sc_pref::def_text (void) const +{ + return def_value ().toString (); +} + all_shortcut_preferences *all_shortcut_preferences::s_instance = nullptr; void all_shortcut_preferences::insert (const QString& settings_key, @@ -64,12 +81,37 @@ s_instance->do_insert (settings_key, scpref); } +const sc_pref all_shortcut_preferences::value (const QString& settings_key) +{ + ensure_instance (); + + return s_instance->do_value (settings_key); +} + +QStringList all_shortcut_preferences::keys (void) +{ + ensure_instance (); + + return s_instance->do_keys (); +} + void all_shortcut_preferences::do_insert (const QString& settings_key, const sc_pref& scpref) { m_hash.insert (settings_key, scpref); } +const sc_pref +all_shortcut_preferences::do_value (const QString& settings_key) const +{ + return m_hash.value (settings_key); +} + +QStringList all_shortcut_preferences::do_keys (void) const +{ + return m_hash.keys (); +} + void all_shortcut_preferences::ensure_instance (void) { if (! s_instance)
--- a/libgui/src/gui-preferences.h Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/gui-preferences.h Mon Dec 26 17:29:59 2022 -0500 @@ -58,8 +58,6 @@ // combination of Qt:Keys (resutling in an unsigend int, when added) // or as one of the predefined standard key sequences. -const QString sc_group ("shortcuts/"); // group name is handled separately - class sc_pref { public: @@ -93,6 +91,10 @@ QKeySequence::StandardKey def_std (void) const { return m_def_std; } + QKeySequence def_value (void) const; + + QString def_text (void) const; + private: // Description of the shortcut. @@ -128,6 +130,10 @@ static void insert (const QString& settings_key, const sc_pref& scpref); + static const sc_pref value (const QString& settings_key); + + static QStringList keys (void); + private: // Map from shortcut identifier (settings key) to sc_pref object. @@ -135,6 +141,10 @@ void do_insert (const QString& settings_key, const sc_pref& scpref); + const sc_pref do_value (const QString& settings_key) const; + + QStringList do_keys (void) const; + static void ensure_instance (void); // Map from shortcut identifier (settings key) to sc_pref object.
--- a/libgui/src/gui-settings.cc Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/gui-settings.cc Mon Dec 26 17:29:59 2022 -0500 @@ -45,6 +45,7 @@ #include "gui-preferences-cs.h" #include "gui-preferences-ed.h" +#include "gui-preferences-sc.h" #include "gui-preferences-global.h" #include "gui-settings.h" @@ -122,23 +123,13 @@ // Get the value from the settings where the key sequences are stored // as strings - return value (sc_group + scpref.settings_key (), + return value (sc_group + "/" + scpref.settings_key (), key_seq.toString ()).toString (); } QKeySequence gui_settings::sc_def_value (const sc_pref& scpref) const { - QKeySequence key_seq = QKeySequence (); - - // Check, which of the elements for the default value in the sc_pref - // structure has a valid value and take this as default. If both - // elements are not valid, leave the key sequence empty - if (scpref.def ()) - key_seq = QKeySequence (scpref.def ()); - else if (scpref.def_std () != QKeySequence::UnknownKey) - key_seq = QKeySequence (scpref.def_std ()); - - return key_seq; + return scpref.def_value (); } void gui_settings::set_shortcut (QAction *action, const sc_pref& scpref,
--- a/libgui/src/main-window.cc Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/main-window.cc Mon Dec 26 17:29:59 2022 -0500 @@ -75,7 +75,6 @@ #include "octave-qobject.h" #include "octave-qtutils.h" #include "settings-dialog.h" -#include "shortcut-manager.h" #include "welcome-wizard.h" #include "cmd-edit.h" @@ -150,13 +149,6 @@ sys::env::putenv ("TERM", "xterm"); #endif - // FIXME: can we do this job when creating the shortcut manager? - // A quick look shows that it may require some coordination with the - // resource manager. Startup is complicated, but maybe we can make - // it simpler? - shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); - scmgr.init_data (); - construct_central_widget (); m_status_bar = new QStatusBar (this); @@ -875,7 +867,7 @@ return; } - m_settings_dlg = new settings_dialog (this, m_octave_qobj, desired_tab); + m_settings_dlg = new settings_dialog (this, desired_tab); connect (m_settings_dlg, &settings_dialog::apply_new_settings, this, &main_window::request_reload_settings);
--- a/libgui/src/module.mk Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/module.mk Mon Dec 26 17:29:59 2022 -0500 @@ -301,7 +301,7 @@ %reldir%/moc-color-picker.cc \ %reldir%/moc-tab-bar.cc \ %reldir%/moc-qt-interpreter-events.cc \ - %reldir%/moc-shortcut-manager.cc \ + %reldir%/moc-shortcuts-tree-widget.cc \ %reldir%/moc-welcome-wizard.cc \ %reldir%/moc-workspace-model.cc \ %reldir%/moc-workspace-view.cc \ @@ -383,7 +383,7 @@ %reldir%/qt-utils.h \ %reldir%/release-notes.h \ %reldir%/settings-dialog.h \ - %reldir%/shortcut-manager.h \ + %reldir%/shortcuts-tree-widget.h \ %reldir%/tab-bar.h \ %reldir%/terminal-dock-widget.h \ %reldir%/color-picker.h \ @@ -430,7 +430,7 @@ %reldir%/qt-application.cc \ %reldir%/release-notes.cc \ %reldir%/settings-dialog.cc \ - %reldir%/shortcut-manager.cc \ + %reldir%/shortcuts-tree-widget.cc \ %reldir%/tab-bar.cc \ %reldir%/terminal-dock-widget.cc \ %reldir%/color-picker.cc \
--- a/libgui/src/octave-qobject.cc Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/octave-qobject.cc Mon Dec 26 17:29:59 2022 -0500 @@ -54,7 +54,6 @@ #include "qt-application.h" #include "qt-interpreter-events.h" #include "release-notes.h" -#include "shortcut-manager.h" #include "terminal-dock-widget.h" #include "variable-editor.h" #include "workspace-model.h" @@ -174,7 +173,6 @@ m_argc (m_app_context.sys_argc ()), m_argv (m_app_context.sys_argv ()), m_qapplication (new octave_qapplication (m_argc, m_argv)), - m_shortcut_manager (), m_qt_tr (new QTranslator ()), m_gui_tr (new QTranslator ()), m_qsci_tr (new QTranslator ()), @@ -193,8 +191,7 @@ m_variable_editor_widget (), m_main_window (nullptr) { - std::string show_gui_msgs = - sys::env::getenv ("OCTAVE_SHOW_GUI_MESSAGES"); + std::string show_gui_msgs = sys::env::getenv ("OCTAVE_SHOW_GUI_MESSAGES"); // Installing our handler suppresses the messages. @@ -210,11 +207,14 @@ qRegisterMetaType<octave_value_list> ("octave_value_list"); -// Bug #55940 (Disable App Nap on Mac) + // Bug #55940 (Disable App Nap on Mac) #if defined (Q_OS_MAC) // Mac App Nap feature causes pause() and sleep() to misbehave. // Disable it for the entire program run. disable_app_nap (); + + // Don't let Qt interpret CMD key ("Meta" in Qt terminology) as Ctrl. + QCoreApplication::setAttribute (Qt::AA_MacDontSwapCtrlAndMeta, true); #endif // Force left-to-right alignment (see bug #46204) @@ -313,9 +313,6 @@ settings.config_icon_theme (); - // Initilize the shortcut-manager - m_shortcut_manager.init_data (); - m_qapplication->setQuitOnLastWindowClosed (false); } }
--- a/libgui/src/octave-qobject.h Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/octave-qobject.h Mon Dec 26 17:29:59 2022 -0500 @@ -36,7 +36,6 @@ #include <QStringList> #include "interpreter-qobject.h" -#include "shortcut-manager.h" OCTAVE_BEGIN_NAMESPACE(octave) @@ -136,11 +135,6 @@ return m_main_window; } - shortcut_manager& get_shortcut_manager (void) - { - return m_shortcut_manager; - } - std::shared_ptr<qt_interpreter_events> get_qt_interpreter_events (void) { return m_qt_interpreter_events; @@ -263,8 +257,6 @@ octave_qapplication *m_qapplication; - shortcut_manager m_shortcut_manager; - QTranslator *m_qt_tr; QTranslator *m_gui_tr; QTranslator *m_qsci_tr;
--- a/libgui/src/settings-dialog.cc Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/settings-dialog.cc Mon Dec 26 17:29:59 2022 -0500 @@ -65,17 +65,16 @@ #include "gui-preferences-all.h" #include "gui-settings.h" -#include "octave-qobject.h" #include "octave-qtutils.h" #include "settings-dialog.h" +#include "shortcuts-tree-widget.h" #include "variable-editor.h" #include "workspace-model.h" OCTAVE_BEGIN_NAMESPACE(octave) - settings_dialog::settings_dialog (QWidget *p, base_qobject& oct_qobj, - const QString& desired_tab) - : QDialog (p), Ui::settings_dialog (), m_octave_qobj (oct_qobj) + settings_dialog::settings_dialog (QWidget *p, const QString& desired_tab) + : QDialog (p), Ui::settings_dialog () { setupUi (this); @@ -421,8 +420,6 @@ // shortcuts - shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); - cb_prevent_readline_conflicts->setChecked ( settings.value (sc_prevent_rl_conflicts.key, sc_prevent_rl_conflicts.def).toBool ()); @@ -430,10 +427,9 @@ settings.value (sc_prevent_rl_conflicts_menu.key, sc_prevent_rl_conflicts_menu.def).toBool ()); - // initialize the tree view with all shortcut data - scmgr.fill_treewidget (shortcuts_treewidget); + // connect the buttons for import/export of the shortcut sets + // FIXME: Should there also be a button to discard changes? - // connect the buttons for import/export of the shortcut sets connect (btn_import_shortcut_set, &QPushButton::clicked, this, &settings_dialog::import_shortcut_set); @@ -553,7 +549,7 @@ if (button_role == QDialogButtonBox::ApplyRole || button_role == QDialogButtonBox::AcceptRole) { - write_changed_settings (button_role == QDialogButtonBox::AcceptRole); + write_changed_settings (); emit apply_new_settings (); } @@ -616,25 +612,58 @@ // slots for import/export of shortcut sets + // Prompt for file name and import shortcuts from it. Importing will + // change values in tree view but does not apply values to + // gui_settings_object so that the user may choose to apply or cancel + // the action. + void settings_dialog::import_shortcut_set (void) { - shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); + if (! overwrite_all_shortcuts ()) + return; + + QString file = get_shortcuts_file_name (OSC_IMPORT); + + gui_settings osc_settings (file, QSettings::IniFormat); - scmgr.import_export (shortcut_manager::OSC_IMPORT); + if (osc_settings.status () == QSettings::NoError) + shortcuts_treewidget->import_shortcuts (osc_settings); + else + qWarning () << (tr ("Failed to open %1 as Octave shortcut file") + .arg (file)); } + // Prompt for file name and export shortcuts to it. + + // FIXME: Should exported settings values come from the gui_settings + // object or the tree view? If modified values in the tree view have + // not been applied, should we offer to apply them first? Offer a + // choice to save current application settings or the modified values + // in the dialog? + void settings_dialog::export_shortcut_set (void) { - shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); + QString file = get_shortcuts_file_name (OSC_EXPORT); + + gui_settings osc_settings (file, QSettings::IniFormat); - scmgr.import_export (shortcut_manager::OSC_EXPORT); + if (osc_settings.status () == QSettings::NoError) + shortcuts_treewidget->export_shortcuts (osc_settings); + else + qWarning () << (tr ("Failed to open %1 as Octave shortcut file") + .arg (file)); } + // Reset the tree view to default values. Does not apply values to + // gui_settings object so that the user may choose to apply or cancel + // the action. + void settings_dialog::default_shortcut_set (void) { - shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); + if (! overwrite_all_shortcuts ()) + return; - scmgr.import_export (shortcut_manager::OSC_DEFAULT); + shortcuts_treewidget->set_default_shortcuts (); } void settings_dialog::update_editor_lexers (int def) @@ -1017,7 +1046,7 @@ #endif - void settings_dialog::write_changed_settings (bool closing) + void settings_dialog::write_changed_settings (void) { gui_settings settings; @@ -1241,8 +1270,7 @@ settings.setValue (sc_prevent_rl_conflicts.key, cb_prevent_readline_conflicts->isChecked ()); settings.setValue (sc_prevent_rl_conflicts_menu.key, cb_prevent_readline_conflicts_menu->isChecked ()); - shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); - scmgr.write_shortcuts (settings, closing); + shortcuts_treewidget->write_settings (); settings.sync (); } @@ -1610,4 +1638,90 @@ settings.sync (); } + QString settings_dialog::get_shortcuts_file_name (import_export_action action) + { + QString file; + + // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved. + int opts = 0; // No options by default. + + gui_settings settings; + + if (! settings.value (global_use_native_dialogs).toBool ()) + opts = QFileDialog::DontUseNativeDialog; + + if (action == OSC_IMPORT) + file = QFileDialog::getOpenFileName + (this, tr ("Import shortcuts from file..."), QString (), + tr ("Octave Shortcut Files (*.osc);;All Files (*)"), + nullptr, QFileDialog::Option (opts)); + + else + file = QFileDialog::getSaveFileName + (this, tr ("Export shortcuts to file..."), QString (), + tr ("Octave Shortcut Files (*.osc);;All Files (*)"), + nullptr, QFileDialog::Option (opts)); + + return file; + } + + // Ask whether to overwrite current shortcuts with settings from an + // imported file. Optionally allow current shortcuts to be saved to a + // file. + + // FIXME: If the tree view contains changes that have not yet been + // saved to the application settings object, should we + // + // * allow the user to choose whether to + // - cancel the operation (X) + // - save the modified settings (X) + // - save the current application settings (XX) + // + // * unconditionally display an error dialog and cancel the + // export operation + // + // (X) - already an option, but not based on whether the tree view + // contains unsaved changes + // (XX) - already possible (cancel operation, cancel settings + // dialog, re-open settings dialog and export changes). + + bool settings_dialog::overwrite_all_shortcuts (void) + { + QMessageBox msg_box; + + msg_box.setWindowTitle (tr ("Overwriting Shortcuts")); + msg_box.setIcon (QMessageBox::Warning); + msg_box.setText (tr ("You are about to overwrite all shortcuts.\n" + "Would you like to save the current shortcut set or cancel the action?")); + msg_box.setStandardButtons (QMessageBox::Save | QMessageBox::Cancel); + + QPushButton *discard + = msg_box.addButton (tr ("Don't save"), QMessageBox::DestructiveRole); + + msg_box.setDefaultButton (QMessageBox::Save); + + int ret = msg_box.exec (); + + if (msg_box.clickedButton () == discard) + return true; + + if (ret == QMessageBox::Save) + { + QString file = get_shortcuts_file_name (OSC_EXPORT); + + gui_settings osc_settings (file, QSettings::IniFormat); + + if (osc_settings.status () == QSettings::NoError) + { + shortcuts_treewidget->export_shortcuts (osc_settings); + return true; + } + else + qWarning () << (tr ("Failed to open %1 as Octave shortcut file") + .arg (file)); + } + + return false; + } + OCTAVE_END_NAMESPACE(octave)
--- a/libgui/src/settings-dialog.h Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/settings-dialog.h Mon Dec 26 17:29:59 2022 -0500 @@ -39,15 +39,15 @@ OCTAVE_BEGIN_NAMESPACE(octave) - class base_qobject; - // Ui::settings_dialog is a generated class. class settings_dialog : public QDialog, private Ui::settings_dialog { - Q_OBJECT public: + Q_OBJECT - explicit settings_dialog (QWidget *parent, base_qobject& octave_qobj, + public: + + explicit settings_dialog (QWidget *parent, const QString& desired_tab = QString ()); ~settings_dialog (void) = default; @@ -82,13 +82,19 @@ private: + enum import_export_action + { + OSC_IMPORT, + OSC_EXPORT + }; + #if defined (HAVE_QSCINTILLA) void update_lexer (QsciLexer *lexer, int mode, int def = 0); void get_lexer_settings (QsciLexer *lexer); void write_lexer_settings (QsciLexer *lexer); #endif - void write_changed_settings (bool closing); + void write_changed_settings (void); void read_workspace_colors (void); void write_workspace_colors (void); @@ -99,7 +105,9 @@ void read_varedit_colors (void); void write_varedit_colors (void); - base_qobject& m_octave_qobj; + QString get_shortcuts_file_name (import_export_action action); + + bool overwrite_all_shortcuts (void); color_picker *m_widget_title_bg_color; color_picker *m_widget_title_bg_color_active;
--- a/libgui/src/settings-dialog.ui Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/settings-dialog.ui Mon Dec 26 17:29:59 2022 -0500 @@ -2681,7 +2681,7 @@ <number>0</number> </property> <item> - <widget class="QTreeWidget" name="shortcuts_treewidget"> + <widget class="octave::shortcuts_tree_widget" name="shortcuts_treewidget"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> @@ -2959,6 +2959,13 @@ </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>octave::shortcuts_tree_widget</class> + <extends>QTreeWidget</extends> + <header>shortcuts-tree-widget.h</header> + </customwidget> + </customwidgets> <resources/> <connections> <connection>
--- a/libgui/src/shortcut-manager.cc Sun Dec 25 20:37:53 2022 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,778 +0,0 @@ -//////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2014-2022 The Octave Project Developers -// -// See the file COPYRIGHT.md in the top-level directory of this -// distribution or <https://octave.org/copyright/>. -// -// This file is part of Octave. -// -// Octave 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 3 of the License, or -// (at your option) any later version. -// -// Octave 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 Octave; see the file COPYING. If not, see -// <https://www.gnu.org/licenses/>. -// -//////////////////////////////////////////////////////////////////////// - -#if defined (HAVE_CONFIG_H) -# include "config.h" -#endif - -#include <QAction> -#include <QApplication> -#include <QCheckBox> -#include <QDialogButtonBox> -#include <QFileDialog> -#include <QGridLayout> -#include <QHeaderView> -#include <QKeySequence> -#include <QLineEdit> -#include <QMessageBox> -#include <QPushButton> -#include <QVBoxLayout> -#include <QtCore> - -#include "shortcut-manager.h" -#include "gui-preferences-global.h" -#include "gui-preferences-sc.h" -#include "gui-settings.h" -#include "error.h" - -OCTAVE_BEGIN_NAMESPACE(octave) - - // enter_shortcut: - // class derived from QLineEdit for directly entering key sequences which - - enter_shortcut::enter_shortcut (QWidget *p) : QLineEdit (p) - { - m_direct_shortcut = true; // the shortcut is directly entered - m_shift_modifier = false; // the shift modifier is not added - } - - // new keyPressEvent - void enter_shortcut::keyPressEvent (QKeyEvent *e) - { - if (! m_direct_shortcut) - { - QLineEdit::keyPressEvent (e); - return; - } - - if (e->type () == QEvent::KeyPress) - { - int key = e->key (); - - if (key == Qt::Key_unknown || key == 0) - return; - - Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers (); //e->modifiers (); - - if (m_shift_modifier || (modifiers & Qt::ShiftModifier)) - key += Qt::SHIFT; - if (modifiers & Qt::ControlModifier) - key += Qt::CTRL; - if (modifiers & Qt::AltModifier) - key += Qt::ALT; - if (modifiers & Qt::MetaModifier) - key += Qt::META; - - setText (QKeySequence (key).toString ()); - } - } - - // slot for checkbox whether the shortcut is directly entered or not - void enter_shortcut::handle_direct_shortcut (int state) - { - if (state) - m_direct_shortcut = true; // the shortcut is directly entered - else - m_direct_shortcut = false; // the shortcut has to be written as text - } - - // slot for checkbox whether the shift modifier should be added - void enter_shortcut::handle_shift_modifier (int state) - { - if (state) - m_shift_modifier = true; // the shortcut is directly entered - else - m_shift_modifier = false; // the shortcut has to be written as text - } - - shortcut_manager::shortcut_manager (void) - { - setObjectName ("Shortcut_Manager"); - - // Mac: don't let Qt interpret CMD key ("Meta" in Qt terminology) as Ctrl -#if defined (Q_OS_MAC) - QCoreApplication::setAttribute (Qt::AA_MacDontSwapCtrlAndMeta, true); -#endif - } - - void shortcut_manager::init_data (void) - { - gui_settings settings; - - settings.setValue (sc_main_ctrld.key, false); // reset use fo ctrl-d - - // actions not related to specific menus or widgets - - // dock widgets - init (tr ("Undock/Dock Widget"), sc_dock_widget_dock); - init (tr ("Close Widget"), sc_dock_widget_close); - - // actions of the main window - - // file - init (tr ("New File"), sc_main_file_new_file); - init (tr ("New Function"), sc_main_file_new_function); - init (tr ("New Figure"), sc_main_file_new_figure); - init (tr ("Open File"), sc_main_file_open_file); - init (tr ("Load Workspace"), sc_main_file_load_workspace); - init (tr ("Save Workspace As"), sc_main_file_save_workspace); - init (tr ("Exit Octave"), sc_main_file_exit); - - // edit - init (tr ("Copy"), sc_main_edit_copy); - init (tr ("Paste"), sc_main_edit_paste); - init (tr ("Undo"), sc_main_edit_undo); - init (tr ("Select All"), sc_main_edit_select_all); - init (tr ("Clear Clipboard"), sc_main_edit_clear_clipboard); - init (tr ("Find in Files"), sc_main_edit_find_in_files); - init (tr ("Clear Command Window"), sc_main_edit_clear_command_window); - init (tr ("Clear Command History"), sc_main_edit_clear_history); - init (tr ("Clear Workspace"), sc_main_edit_clear_workspace); - init (tr ("Set Path"), sc_main_edit_set_path); - init (tr ("Preferences"), sc_main_edit_preferences); - - // debug - init (tr ("Step"), sc_main_debug_step_over); - init (tr ("Step Into"), sc_main_debug_step_into); - init (tr ("Step Out"), sc_main_debug_step_out); - init (tr ("Continue"), sc_main_debug_continue); - init (tr ("Quit Debug Mode"), sc_main_debug_quit); - - // tools - init (tr ("Start/Stop Profiler Session"), sc_main_tools_start_profiler); - init (tr ("Resume Profiler Session"), sc_main_tools_resume_profiler); - init (tr ("Show Profile Data"), sc_main_tools_show_profiler); - - // window - init (tr ("Show Command Window"), sc_main_window_show_command); - init (tr ("Show Command History"), sc_main_window_show_history); - init (tr ("Show File Browser"), sc_main_window_show_file_browser); - init (tr ("Show Workspace"), sc_main_window_show_workspace); - init (tr ("Show Editor"), sc_main_window_show_editor); - init (tr ("Show Documentation"), sc_main_window_show_doc); - init (tr ("Show Variable Editor"), sc_main_window_show_variable_editor); - init (tr ("Command Window"), sc_main_window_command); - init (tr ("Command History"), sc_main_window_history); - init (tr ("File Browser"), sc_main_window_file_browser); - init (tr ("Workspace"), sc_main_window_workspace); - init (tr ("Editor"), sc_main_window_editor); - init (tr ("Documentation"), sc_main_window_doc); - init (tr ("Variable Editor"), sc_main_window_variable_editor); - init (tr ("Previous Widget"), sc_main_window_previous_dock); - init (tr ("Reset Default Window Layout"), sc_main_window_reset); - - // help - init (tr ("Show On-disk Documentation"), sc_main_help_ondisk_doc); - init (tr ("Show Online Documentation"), sc_main_help_online_doc); - init (tr ("Report Bug"), sc_main_help_report_bug); - init (tr ("Octave Packages"), sc_main_help_packages); - init (tr ("Contribute to Octave"), sc_main_help_contribute); - init (tr ("Octave Developer Resources"), sc_main_help_developer); - init (tr ("About Octave"), sc_main_help_about); - - // news - init (tr ("Release Notes"), sc_main_news_release_notes); - init (tr ("Community News"), sc_main_news_community_news); - - // Tab handling - // The following shortcuts are moved into a separate tab. The key names - // are not changed, to preserve compatibility with older versions. - init (tr ("Close Tab"), sc_edit_file_close); - init (tr ("Close All Tabs"), sc_edit_file_close_all); - init (tr ("Close Other Tabs"), sc_edit_file_close_other); - init (tr ("Switch to Left Tab"), sc_edit_tabs_switch_left_tab); - init (tr ("Switch to Right Tab"), sc_edit_tabs_switch_right_tab); - init (tr ("Move Tab Left"), sc_edit_tabs_move_tab_left); - init (tr ("Move Tab Right"), sc_edit_tabs_move_tab_right); - - // Zooming - init (tr ("Zoom In"), sc_edit_view_zoom_in); - init (tr ("Zoom Out"), sc_edit_view_zoom_out); -#if defined (Q_OS_MAC) - init (tr ("Zoom Normal"), sc_edit_view_zoom_normal); -#else - init (tr ("Zoom Normal"), sc_edit_view_zoom_normal); -#endif - - // actions of the editor - - // file - init (tr ("Edit Function"), sc_edit_file_edit_function); - init (tr ("Save File"), sc_edit_file_save); - init (tr ("Save File As"), sc_edit_file_save_as); - init (tr ("Print"), sc_edit_file_print); - - // edit - init (tr ("Redo"), sc_edit_edit_redo); - init (tr ("Cut"), sc_edit_edit_cut); - init (tr ("Find and Replace"), sc_edit_edit_find_replace); - init (tr ("Find Next"), sc_edit_edit_find_next); - init (tr ("Find Previous"), sc_edit_edit_find_previous); - init (tr ("Delete to Start of Word"), sc_edit_edit_delete_start_word); - init (tr ("Delete to End of Word"), sc_edit_edit_delete_end_word); - init (tr ("Delete to Start of Line"), sc_edit_edit_delete_start_line); - init (tr ("Delete to End of Line"), sc_edit_edit_delete_end_line); - init (tr ("Delete Line"), sc_edit_edit_delete_line); - init (tr ("Copy Line"), sc_edit_edit_copy_line); - init (tr ("Cut Line"), sc_edit_edit_cut_line); - init (tr ("Duplicate Selection/Line"), sc_edit_edit_duplicate_selection); - init (tr ("Transpose Line"), sc_edit_edit_transpose_line); - init (tr ("Show Completion List"), sc_edit_edit_completion_list); - - init (tr ("Comment Selection"), sc_edit_edit_comment_selection); - init (tr ("Uncomment Selection"), sc_edit_edit_uncomment_selection); - init (tr ("Comment Selection (Choosing String)"), sc_edit_edit_comment_var_selection); - init (tr ("Uppercase Selection"), sc_edit_edit_upper_case); - init (tr ("Lowercase Selection"), sc_edit_edit_lower_case); - -#if defined (Q_OS_MAC) - init (tr ("Indent Selection Rigidly"), sc_edit_edit_indent_selection); - init (tr ("Unindent Selection Rigidly"), sc_edit_edit_unindent_selection); -#else - init (tr ("Indent Selection Rigidly"), sc_edit_edit_indent_selection); - init (tr ("Unindent Selection Rigidly"), sc_edit_edit_unindent_selection); -#endif - init (tr ("Indent Code"), sc_edit_edit_smart_indent_line_or_selection); - - init (tr ("Convert Line Endings to Windows"), sc_edit_edit_conv_eol_winows); - init (tr ("Convert Line Endings to Unix"), sc_edit_edit_conv_eol_unix); - init (tr ("Convert Line Endings to Mac"), sc_edit_edit_conv_eol_mac); - - init (tr ("Goto Line"), sc_edit_edit_goto_line); - init (tr ("Move to Matching Brace"), sc_edit_edit_move_to_brace); - init (tr ("Select to Matching Brace"), sc_edit_edit_select_to_brace); - init (tr ("Toggle Bookmark"), sc_edit_edit_toggle_bookmark); - init (tr ("Next Bookmark"), sc_edit_edit_next_bookmark); - init (tr ("Previous Bookmark"), sc_edit_edit_previous_bookmark); - init (tr ("Remove All Bookmark"), sc_edit_edit_remove_bookmark); - - init (tr ("Preferences"), sc_edit_edit_preferences); - init (tr ("Styles Preferences"), sc_edit_edit_styles_preferences); - - // view - init (tr ("Show Line Numbers"), sc_edit_view_show_line_numbers); - init (tr ("Show Whitespace Characters"), sc_edit_view_show_white_spaces); - init (tr ("Show Line Endings"), sc_edit_view_show_eol_chars); - init (tr ("Show Indentation Guides"), sc_edit_view_show_ind_guides); - init (tr ("Show Long Line Marker"), sc_edit_view_show_long_line); - init (tr ("Show Toolbar"), sc_edit_view_show_toolbar); - init (tr ("Show Statusbar"), sc_edit_view_show_statusbar); - init (tr ("Show Horizontal Scrollbar"), sc_edit_view_show_hscrollbar); - init (tr ("Sort Tabs Alphabetically"), sc_edit_view_sort_tabs); - - // debug - init (tr ("Toggle Breakpoint"), sc_edit_debug_toggle_breakpoint); - init (tr ("Next Breakpoint"), sc_edit_debug_next_breakpoint); - init (tr ("Previous Breakpoint"), sc_edit_debug_previous_breakpoint); - init (tr ("Remove All Breakpoints"), sc_edit_debug_remove_breakpoints); - - // run - init (tr ("Run File"), sc_edit_run_run_file); - init (tr ("Run Selection"), sc_edit_run_run_selection); - - // help - init (tr ("Help on Keyword"), sc_edit_help_help_keyword); - init (tr ("Document on Keyword"), sc_edit_help_doc_keyword); - - // Documentation browser - init (tr ("Go to Homepage"), sc_doc_go_home); - init (tr ("Go Back one Page"), sc_doc_go_back); - init (tr ("Go Forward one Page"), sc_doc_go_next); - init (tr ("Bookmark this Page"), sc_doc_bookmark); - } - - // write one or all actual shortcut set(s) into a settings file - void shortcut_manager::write_shortcuts (gui_settings& settings, - bool closing) - { - bool sc_ctrld = false; - - QString sc_main = sc_main_file.mid (0, sc_main_file.indexOf ('_') + 1); - - for (int i = 0; i < m_sc.count (); i++) // loop over all shortcuts - { - settings.setValue (sc_group + "/" + m_sc.at (i).m_settings_key, - m_sc.at (i).m_actual_sc.toString ()); - // special: check main-window for Ctrl-D (Terminal) - if (m_sc.at (i).m_settings_key.startsWith (sc_main) - && m_sc.at (i).m_actual_sc == QKeySequence (Qt::ControlModifier+Qt::Key_D)) - sc_ctrld = true; - } - - settings.setValue (sc_main_ctrld.key, sc_ctrld); - - if (closing) - { - delete m_dialog; // the dialog for key sequences can be removed now - m_dialog = nullptr; // make sure it is zero again - } - - settings.sync (); // sync the settings file - } - - void shortcut_manager::fill_treewidget (QTreeWidget *tree_view) - { - m_dialog = nullptr; - - QHash <QString, QTreeWidgetItem *> level_hash; - - tree_view->header ()->setSectionResizeMode (QHeaderView::ResizeToContents); - - QTreeWidgetItem *main = new QTreeWidgetItem (tree_view); - main->setText (0, tr ("Global")); - main->setExpanded (true); - QTreeWidgetItem *main_file = new QTreeWidgetItem (main); - main_file->setText (0, tr ("File Menu")); - QTreeWidgetItem *main_edit = new QTreeWidgetItem (main); - main_edit->setText (0, tr ("Edit Menu")); - QTreeWidgetItem *main_debug = new QTreeWidgetItem (main); - main_debug->setText (0, tr ("Debug Menu")); - QTreeWidgetItem *main_tools = new QTreeWidgetItem (main); - main_tools->setText (0, tr ("Tools Menu")); - QTreeWidgetItem *main_window = new QTreeWidgetItem (main); - main_window->setText (0, tr ("Window Menu")); - QTreeWidgetItem *main_help = new QTreeWidgetItem (main); - main_help->setText (0, tr ("Help Menu")); - QTreeWidgetItem *main_news = new QTreeWidgetItem (main); - main_news->setText (0, tr ("News Menu")); - QTreeWidgetItem *main_dock_widgets = new QTreeWidgetItem (main); - main_dock_widgets->setText (0, tr ("Handling of Dock Widgets")); - QTreeWidgetItem *main_tabs = new QTreeWidgetItem (main); - main_tabs->setText (0, tr ("Tab Handling in Dock Widgets")); - QTreeWidgetItem *main_find = new QTreeWidgetItem (main); - main_find->setText (0, tr ("Find & Replace in Dock Widgets")); - QTreeWidgetItem *main_zoom = new QTreeWidgetItem (main); - main_zoom->setText (0, tr ("Zooming in Editor and Documentation")); - - level_hash[sc_main_file] = main_file; - level_hash[sc_main_edit] = main_edit; - level_hash[sc_main_debug] = main_debug; - level_hash[sc_main_tools] = main_tools; - level_hash[sc_main_window] = main_window; - level_hash[sc_main_help] = main_help; - level_hash[sc_main_news] = main_news; - level_hash[sc_dock_widget] = main_dock_widgets; - level_hash[sc_edit_tabs] = main_tabs; - level_hash[sc_edit_find] = main_find; - level_hash[sc_edit_zoom] = main_zoom; - - QTreeWidgetItem *editor = new QTreeWidgetItem (tree_view); - editor->setText (0, tr ("Editor")); - editor->setExpanded (true); - QTreeWidgetItem *editor_file = new QTreeWidgetItem (editor); - editor_file->setText (0, tr ("File Menu")); - QTreeWidgetItem *editor_edit = new QTreeWidgetItem (editor); - editor_edit->setText (0, tr ("Edit Menu")); - QTreeWidgetItem *editor_view = new QTreeWidgetItem (editor); - editor_view->setText (0, tr ("View Menu")); - QTreeWidgetItem *editor_debug = new QTreeWidgetItem (editor); - editor_debug->setText (0, tr ("Debug Menu")); - QTreeWidgetItem *editor_run = new QTreeWidgetItem (editor); - editor_run->setText (0, tr ("Run Menu")); - QTreeWidgetItem *editor_help = new QTreeWidgetItem (editor); - editor_help->setText (0, tr ("Help Menu")); - - level_hash[sc_edit_file] = editor_file; - level_hash[sc_edit_edit] = editor_edit; - level_hash[sc_edit_view] = editor_view; - level_hash[sc_edit_debug] = editor_debug; - level_hash[sc_edit_run] = editor_run; - level_hash[sc_edit_help] = editor_help; - - QTreeWidgetItem *doc = new QTreeWidgetItem (tree_view); - doc->setText (0, tr ("Documentation Viewer")); - doc->setExpanded (true); - - QTreeWidgetItem *doc_browser = new QTreeWidgetItem (doc); - doc_browser->setText (0, tr ("Browser")); - - level_hash[sc_doc] = doc_browser; - - connect (tree_view, &QTreeWidget::itemDoubleClicked, - this, &shortcut_manager::handle_double_clicked); - - for (int i = 0; i < m_sc.count (); i++) - { - shortcut_t sc = m_sc.at (i); - - QTreeWidgetItem *section = level_hash[sc.m_settings_key.section (':', 0, 0)]; - - // handle sections which have changed and do not correspond to the - // previously defined keyname - if (section == editor_file) - { - // Closing tabs now in global tab handling section - if (sc.m_settings_key.contains (sc_edit_file_cl)) - section = main_tabs; - } - if (section == editor_edit) - { - // Find & replace now in global file & replace handling section - if (sc.m_settings_key.contains (sc_edit_edit_find)) - section = main_find; - } - if (section == editor_view) - { - // Zooming now in global zoom handling section - if (sc.m_settings_key.contains (sc_edit_view_zoom)) - section = main_zoom; - } - - QTreeWidgetItem *tree_item = new QTreeWidgetItem (section); - - // set a slightly transparent foreground for default columns - QColor fg = QColor (tree_item->foreground (1).color ()); - fg.setAlpha (128); - tree_item->setForeground (1, QBrush (fg)); - - // write the shortcuts - tree_item->setText (0, sc.m_description); - tree_item->setText (1, sc.m_default_sc.toString ()); - tree_item->setText (2, sc.m_actual_sc.toString ()); - - m_item_index_hash[tree_item] = i + 1; // index+1 to avoid 0 - m_index_item_hash[i] = tree_item; - } - } - - // import or export of shortcut sets, - // called from settings dialog when related buttons are clicked; - // returns true on success, false otherwise - bool - shortcut_manager::import_export (int action) - { - // ask to save the current shortcuts, maybe abort import - if (action == OSC_DEFAULT || action == OSC_IMPORT) - { - if (! overwrite_all_shortcuts ()) - return false; - } - - // get the filename to read or write the shortcuts, - // the default extension is .osc (octave shortcuts) - if (action != OSC_DEFAULT) - { - QString file; - - // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved. - int opts = 0; // No options by default. - - gui_settings settings; - - if (! settings.value (global_use_native_dialogs).toBool ()) - opts = QFileDialog::DontUseNativeDialog; - - if (action == OSC_IMPORT) - file = QFileDialog::getOpenFileName (this, - tr ("Import shortcuts from file..."), QString (), - tr ("Octave Shortcut Files (*.osc);;All Files (*)"), - nullptr, QFileDialog::Option (opts)); - else if (action == OSC_EXPORT) - file = QFileDialog::getSaveFileName (this, - tr ("Export shortcuts to file..."), QString (), - tr ("Octave Shortcut Files (*.osc);;All Files (*)"), - nullptr, QFileDialog::Option (opts)); - - if (file.isEmpty ()) - return false; - - gui_settings osc_settings (file, QSettings::IniFormat); - - if (osc_settings.status () != QSettings::NoError) - { - qWarning () << tr ("Failed to open %1 as Octave shortcut file") - .arg (file); - return false; - } - else - { - if (action == OSC_IMPORT) - import_shortcuts (osc_settings); // import (special action) - else if (action == OSC_EXPORT) - write_shortcuts (osc_settings, false); // export, (save settings) - } - } - else - reset_default_shortcuts (); - - return true; - } - - void shortcut_manager::handle_double_clicked (QTreeWidgetItem *item, int col) - { - if (col != 2) - return; - - int i = m_item_index_hash[item]; - if (i == 0) - return; // top-level-item clicked - - shortcut_dialog (i-1); // correct to index starting at 0 - } - - void shortcut_manager::shortcut_dialog_finished (int result) - { - if (result == QDialog::Rejected) - return; - - // check for duplicate - int double_index = m_shortcut_hash[m_edit_actual->text ()] - 1; - - if (double_index >= 0 && double_index != m_handled_index) - { - int ret = QMessageBox::warning (this, tr ("Double Shortcut"), - tr ("The chosen shortcut\n \"%1\"\n" - "is already used for the action\n \"%2\".\n" - "Do you want to use the shortcut anyhow removing it " - "from the previous action?") - .arg (m_edit_actual->text ()) - .arg (m_sc.at (double_index).m_description), - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - - if (ret == QMessageBox::Yes) - { - shortcut_t double_shortcut = m_sc.at (double_index); - double_shortcut.m_actual_sc = QKeySequence (); - m_sc.replace (double_index, double_shortcut); - m_index_item_hash[double_index]->setText (2, QString ()); - } - else - return; - } - - shortcut_t shortcut = m_sc.at (m_handled_index); - if (! shortcut.m_actual_sc.isEmpty ()) - m_shortcut_hash.remove (shortcut.m_actual_sc.toString ()); - shortcut.m_actual_sc = m_edit_actual->text (); - m_sc.replace (m_handled_index, shortcut); - - m_index_item_hash[m_handled_index]->setText (2, shortcut.m_actual_sc.toString ()); - - if (! shortcut.m_actual_sc.isEmpty ()) - m_shortcut_hash[shortcut.m_actual_sc.toString ()] = m_handled_index + 1; - } - - void shortcut_manager::shortcut_dialog_set_default (void) - { - m_edit_actual->setText (m_label_default->text ()); - } - - void shortcut_manager::init (const QString& description, const sc_pref& sc) - { - gui_settings settings; - - QKeySequence actual = QKeySequence (settings.sc_value (sc)); - - // append the new shortcut to the list - shortcut_t shortcut_info; - shortcut_info.m_description = description; - shortcut_info.m_settings_key = sc.settings_key (); - shortcut_info.m_actual_sc = actual; - shortcut_info.m_default_sc = settings.sc_def_value (sc); - m_sc << shortcut_info; - - // insert shortcut in order to check for duplicates later - if (! actual.isEmpty ()) - m_shortcut_hash[actual.toString ()] = m_sc.count (); - - // check whether ctrl+d is used from main window, i.e. is a global shortcut - QString main_group_prefix - = sc_main_file.mid (0, sc_main_file.indexOf ('_') + 1); - if (sc.settings_key ().startsWith (main_group_prefix) - && actual == QKeySequence (Qt::ControlModifier+Qt::Key_D)) - settings.setValue (sc_main_ctrld.key, true); - } - - void shortcut_manager::shortcut_dialog (int index) - { - if (! m_dialog) - { - m_dialog = new QDialog (this); - - m_dialog->setWindowTitle (tr ("Enter new Shortcut")); - - QVBoxLayout *box = new QVBoxLayout (m_dialog); - box->setSpacing (2); - box->setContentsMargins (12, 12, 12, 12); - - QLabel *help = new QLabel (tr ("Apply the desired shortcut or click " - "on the right button to reset the " - "shortcut to its default.")); - help->setWordWrap (true); - box->addWidget (help); - - QCheckBox *direct - = new QCheckBox (tr ("Enter shortcut directly by performing it")); - - QCheckBox *shift - = new QCheckBox (tr ("Add Shift modifier\n" - "(allows one to enter number keys)")); - - shift->setStyleSheet - ("QCheckBox::indicator { subcontrol-position: left top; }"); - - connect (direct, &QCheckBox::clicked, shift, &QCheckBox::setEnabled); - - direct->setCheckState (Qt::Checked); - - box->addWidget (direct); - box->addWidget (shift); - - box->addSpacing (15); - - QGridLayout *grid = new QGridLayout (); - - QLabel *actual = new QLabel (tr ("Actual shortcut")); - m_edit_actual = new enter_shortcut (m_dialog); - m_edit_actual->setAlignment (Qt::AlignHCenter); - grid->addWidget (actual, 0, 0); - grid->addWidget (m_edit_actual, 0, 1); - - QLabel *def = new QLabel (tr ("Default shortcut")); - m_label_default = new QLabel (m_dialog); - m_label_default->setAlignment (Qt::AlignHCenter); - grid->addWidget (def, 1, 0); - grid->addWidget (m_label_default, 1, 1); - - QPushButton *set_default = new QPushButton (tr ("Set to default")); - grid->addWidget (set_default, 0, 2); - connect (set_default, &QPushButton::clicked, - this, &shortcut_manager::shortcut_dialog_set_default); - - box->addLayout (grid); - - box->addSpacing (18); - - QDialogButtonBox *button_box = new QDialogButtonBox (QDialogButtonBox::Ok - | QDialogButtonBox::Cancel); - QList<QAbstractButton *> buttons = button_box->buttons (); - for (int i = 0; i < buttons.count (); i++) - buttons.at (i)->setShortcut (QKeySequence ()); - connect (button_box, &QDialogButtonBox::accepted, - m_dialog, &QDialog::accept); - connect (button_box, &QDialogButtonBox::rejected, - m_dialog, &QDialog::reject); - box->addWidget (button_box); - - m_dialog->setLayout (box); - - connect (direct, &QCheckBox::stateChanged, - m_edit_actual, &enter_shortcut::handle_direct_shortcut); - connect (shift, &QCheckBox::stateChanged, - m_edit_actual, &enter_shortcut::handle_shift_modifier); - connect (m_dialog, &QDialog::finished, - this, &shortcut_manager::shortcut_dialog_finished); - - } - - m_edit_actual->setText (m_sc.at (index).m_actual_sc.toString ()); - m_label_default->setText (m_sc.at (index).m_default_sc.toString ()); - m_handled_index = index; - - m_edit_actual->setFocus (); - m_dialog->setFocusProxy (m_edit_actual); - m_dialog->exec (); - } - - // import a shortcut set from a given settings file and refresh the - // tree view - void shortcut_manager::import_shortcuts (gui_settings& settings) - { - for (int i = 0; i < m_sc.count (); i++) - { - // update the list of all shortcuts - - // make a copy - shortcut_t sc = m_sc.at (i); - - // get new shortcut from settings and use the old one as default - sc.m_actual_sc = QKeySequence (settings.value (sc_group + sc.m_settings_key, sc.m_actual_sc).toString ()); - - // replace the old with the new one - m_sc.replace (i, sc); - - // update the tree view - // get related tree item - QTreeWidgetItem *tree_item = m_index_item_hash[i]; - - // display new shortcut - tree_item->setText (2, sc.m_actual_sc.toString ()); - } - } - - // reset to the defaults and refresh the tree view - void shortcut_manager::reset_default_shortcuts (void) - { - for (int i = 0; i < m_sc.count (); i++) - { - // update the list of all shortcuts - - // make a copy - shortcut_t sc = m_sc.at (i); - - // get default shortcut - sc.m_actual_sc = QKeySequence (sc.m_default_sc); - - // replace the old with the new one - m_sc.replace (i, sc); - - // update the tree view - // get related tree item - QTreeWidgetItem *tree_item = m_index_item_hash[i]; - - // display new shortcut - tree_item->setText (2, sc.m_actual_sc.toString ()); - } - } - - // ask the user whether to save the current shortcut set; - // returns true to proceed with import action, false to abort it - bool shortcut_manager::overwrite_all_shortcuts (void) - { - QMessageBox msg_box; - msg_box.setWindowTitle (tr ("Overwriting Shortcuts")); - msg_box.setIcon (QMessageBox::Warning); - msg_box.setText (tr ("You are about to overwrite all shortcuts.\n" - "Would you like to save the current shortcut set or cancel the action?")); - msg_box.setStandardButtons (QMessageBox::Save | QMessageBox::Cancel); - QPushButton *discard = msg_box.addButton (tr ("Don't save"), - QMessageBox::DestructiveRole); - msg_box.setDefaultButton (QMessageBox::Save); - - int ret = msg_box.exec (); - - if (msg_box.clickedButton () == discard) - return true; // do not save and go ahead - - if (ret == QMessageBox::Save) - { - if (import_export (OSC_EXPORT)) - return true; // go ahead - } - - return false; // abort the import - } - -OCTAVE_END_NAMESPACE(octave)
--- a/libgui/src/shortcut-manager.h Sun Dec 25 20:37:53 2022 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -//////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2014-2022 The Octave Project Developers -// -// See the file COPYRIGHT.md in the top-level directory of this -// distribution or <https://octave.org/copyright/>. -// -// This file is part of Octave. -// -// Octave 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 3 of the License, or -// (at your option) any later version. -// -// Octave 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 Octave; see the file COPYING. If not, see -// <https://www.gnu.org/licenses/>. -// -//////////////////////////////////////////////////////////////////////// - -#if ! defined (octave_shortcut_manager_h) -#define octave_shortcut_manager_h 1 - -#include <QKeyEvent> -#include <QLabel> -#include <QLineEdit> -#include <QShortcut> -#include <QTreeWidget> -#include <QWidget> - -#include "gui-preferences.h" - -OCTAVE_BEGIN_NAMESPACE(octave) - - class enter_shortcut : public QLineEdit - { - Q_OBJECT - - public: - - enter_shortcut (QWidget *p = nullptr); - - ~enter_shortcut (void) = default; - - virtual void keyPressEvent (QKeyEvent *e); - - public slots: - - void handle_direct_shortcut (int); - void handle_shift_modifier (int); - - private: - - bool m_direct_shortcut; - bool m_shift_modifier; - - }; - - class gui_settings; - - class shortcut_manager : public QWidget - { - Q_OBJECT - - public: - - enum - { - OSC_IMPORT = 0, - OSC_EXPORT = 1, - OSC_DEFAULT = 2 - }; - - shortcut_manager (void); - - // No copying! - - shortcut_manager (const shortcut_manager&) = delete; - - shortcut_manager& operator = (const shortcut_manager&) = delete; - - ~shortcut_manager (void) = default; - - void init_data (void); - - void write_shortcuts (gui_settings& settings, bool closing); - - void fill_treewidget (QTreeWidget *tree_view); - - bool import_export (int action); - - protected slots: - - void handle_double_clicked (QTreeWidgetItem *, int); - void shortcut_dialog_finished (int); - void shortcut_dialog_set_default (); - - private: - - void init (const QString&, const sc_pref& scpref); - void shortcut_dialog (int); - void import_shortcuts (gui_settings& settings); - void reset_default_shortcuts (void); - bool overwrite_all_shortcuts (void); - - class shortcut_t - { - public: - - shortcut_t (void) - : m_tree_item (nullptr), m_description (), m_settings_key (), - m_actual_sc (QKeySequence ()), m_default_sc (QKeySequence ()) - { } - - shortcut_t (const shortcut_t& x) - : m_tree_item (x.m_tree_item), m_description (x.m_description), - m_settings_key (x.m_settings_key) - { - m_actual_sc = x.m_actual_sc; - m_default_sc = x.m_default_sc; - } - - shortcut_t& operator = (const shortcut_t& x) - { - if (&x != this) - { - m_tree_item = x.m_tree_item; - m_description = x.m_description; - m_settings_key = x.m_settings_key; - - m_actual_sc = QKeySequence (); - m_default_sc = QKeySequence (); - - m_actual_sc = x.m_actual_sc; - m_default_sc = x.m_default_sc; - } - - return *this; - } - - ~shortcut_t (void) = default; - - QTreeWidgetItem *m_tree_item; - QString m_description; - QString m_settings_key; - QKeySequence m_actual_sc; - QKeySequence m_default_sc; - }; - - QList<shortcut_t> m_sc; - QHash<QString, int> m_shortcut_hash; - QHash<int, QTreeWidgetItem *> m_index_item_hash; - QHash<QTreeWidgetItem *, int> m_item_index_hash; - - QDialog *m_dialog; - enter_shortcut *m_edit_actual; - QLabel *m_label_default; - int m_handled_index; - }; - -OCTAVE_END_NAMESPACE(octave) - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgui/src/shortcuts-tree-widget.cc Mon Dec 26 17:29:59 2022 -0500 @@ -0,0 +1,708 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2014-2022 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or <https://octave.org/copyright/>. +// +// This file is part of Octave. +// +// Octave 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 3 of the License, or +// (at your option) any later version. +// +// Octave 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 Octave; see the file COPYING. If not, see +// <https://www.gnu.org/licenses/>. +// +//////////////////////////////////////////////////////////////////////// + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#include <QApplication> +#include <QDialog> +#include <QDialogButtonBox> +#include <QGridLayout> +#include <QHeaderView> +#include <QKeyEvent> +#include <QLabel> +#include <QMessageBox> +#include <QPushButton> +#include <QVBoxLayout> + +#include "gui-preferences-sc.h" +#include "gui-settings.h" +#include "shortcuts-tree-widget.h" + +OCTAVE_BEGIN_NAMESPACE(octave) + +// enter_shortcut: +// class derived from QLineEdit for directly entering key sequences which + +enter_shortcut::enter_shortcut (QWidget *p) : QLineEdit (p) +{ + m_direct_shortcut = true; // the shortcut is directly entered + m_shift_modifier = false; // the shift modifier is not added +} + +// new keyPressEvent +void enter_shortcut::keyPressEvent (QKeyEvent *e) +{ + if (! m_direct_shortcut) + { + QLineEdit::keyPressEvent (e); + return; + } + + if (e->type () == QEvent::KeyPress) + { + int key = e->key (); + + if (key == Qt::Key_unknown || key == 0) + return; + + Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers (); //e->modifiers (); + + if (m_shift_modifier || (modifiers & Qt::ShiftModifier)) + key += Qt::SHIFT; + if (modifiers & Qt::ControlModifier) + key += Qt::CTRL; + if (modifiers & Qt::AltModifier) + key += Qt::ALT; + if (modifiers & Qt::MetaModifier) + key += Qt::META; + + setText (QKeySequence (key).toString ()); + } +} + +// slot for checkbox whether the shortcut is directly entered or not +void enter_shortcut::handle_direct_shortcut (int state) +{ + if (state) + m_direct_shortcut = true; // the shortcut is directly entered + else + m_direct_shortcut = false; // the shortcut has to be written as text +} + +// slot for checkbox whether the shift modifier should be added +void enter_shortcut::handle_shift_modifier (int state) +{ + if (state) + m_shift_modifier = true; // the shortcut is directly entered + else + m_shift_modifier = false; // the shortcut has to be written as text +} + +tree_widget_shortcut_item::tree_widget_shortcut_item +(QTreeWidgetItem *parent, const sc_pref& scpref, const QString& actual_text) + : QTreeWidgetItem (parent), m_settings_key (scpref.settings_key ()) +{ + // set a slightly transparent foreground for default columns + QColor fg = QColor (foreground (DEFAULT_COLUMN).color ()); + fg.setAlpha (128); + setForeground (DEFAULT_COLUMN, QBrush (fg)); + + // write the shortcuts + set_description (scpref.description ()); + set_default_text (scpref.def_text ()); + set_actual_text (actual_text); +} + +QString tree_widget_shortcut_item::settings_key (void) const +{ + return m_settings_key; +} + +QString tree_widget_shortcut_item::description (void) const +{ + return text (DESCRIPTION_COLUMN); +} + +void tree_widget_shortcut_item::set_description (const QString& text) +{ + setText (DESCRIPTION_COLUMN, text); +} + +QString tree_widget_shortcut_item::default_text (void) const +{ + return text (DEFAULT_COLUMN); +} + +void tree_widget_shortcut_item::set_default_text (const QString& text) +{ + setText (DEFAULT_COLUMN, text); +} + +QString tree_widget_shortcut_item::actual_text (void) const +{ + return text (ACTUAL_COLUMN); +} + +void tree_widget_shortcut_item::set_actual_text (const QString& text) +{ + setText (ACTUAL_COLUMN, text); +} + +shortcut_edit_dialog::shortcut_edit_dialog + (tree_widget_shortcut_item *shortcut_item, QWidget *parent) + : QDialog (parent), m_shortcut_item (shortcut_item), + m_settings_key (shortcut_item->settings_key ()) +{ + setAttribute (Qt::WA_DeleteOnClose); + + setWindowTitle (tr ("Enter new Shortcut")); + + QVBoxLayout *box = new QVBoxLayout (this); + + box->setSpacing (2); + box->setContentsMargins (12, 12, 12, 12); + + QLabel *help = new QLabel (tr ("Apply the desired shortcut or click " + "on the right button to reset the " + "shortcut to its default. (%1)") + .arg (m_settings_key)); + + help->setWordWrap (true); + + box->addWidget (help); + + QCheckBox *direct + = new QCheckBox (tr ("Enter shortcut directly by performing it")); + + QCheckBox *shift + = new QCheckBox (tr ("Add Shift modifier\n" + "(allows one to enter number keys)")); + + shift->setStyleSheet + ("QCheckBox::indicator { subcontrol-position: left top; }"); + + connect (direct, &QCheckBox::clicked, shift, &QCheckBox::setEnabled); + + direct->setCheckState (Qt::Checked); + + box->addWidget (direct); + box->addWidget (shift); + + box->addSpacing (15); + + QGridLayout *grid = new QGridLayout (); + + QLabel *actual = new QLabel (tr ("Actual shortcut")); + + m_edit_actual = new enter_shortcut (this); + m_edit_actual->setAlignment (Qt::AlignHCenter); + + grid->addWidget (actual, 0, 0); + grid->addWidget (m_edit_actual, 0, 1); + + QLabel *def = new QLabel (tr ("Default shortcut")); + + QLabel *label_default = new QLabel (this); + label_default->setAlignment (Qt::AlignHCenter); + + grid->addWidget (def, 1, 0); + grid->addWidget (label_default, 1, 1); + + QPushButton *set_default = new QPushButton (tr ("Set to default")); + + connect (set_default, &QPushButton::clicked, + this, &shortcut_edit_dialog::set_default_shortcut); + + grid->addWidget (set_default, 0, 2); + + box->addLayout (grid); + box->addSpacing (18); + + QDialogButtonBox *button_box = new QDialogButtonBox (QDialogButtonBox::Ok + | QDialogButtonBox::Cancel); + QList<QAbstractButton *> buttons = button_box->buttons (); + for (int i = 0; i < buttons.count (); i++) + buttons.at (i)->setShortcut (QKeySequence ()); + + connect (button_box, &QDialogButtonBox::accepted, + this, &QDialog::accept); + + connect (button_box, &QDialogButtonBox::rejected, + this, &QDialog::reject); + + box->addWidget (button_box); + + setLayout (box); + + connect (direct, &QCheckBox::stateChanged, + m_edit_actual, &enter_shortcut::handle_direct_shortcut); + + connect (shift, &QCheckBox::stateChanged, + m_edit_actual, &enter_shortcut::handle_shift_modifier); + + connect (this, &QDialog::finished, + this, &shortcut_edit_dialog::finished); + + gui_settings settings; + + const sc_pref scpref = all_shortcut_preferences::value (m_settings_key); + + QString actual_text = settings.sc_value (scpref); + + m_default_text = scpref.def_text (); + + m_edit_actual->setText (actual_text); + label_default->setText (m_default_text); + + m_edit_actual->setFocus (); + + setFocusProxy (m_edit_actual); +} + +void shortcut_edit_dialog::finished (int result) +{ + if (result == QDialog::Rejected) + return; + + // Check whether the chosen shortcut is already in use either in the + // current context (section of the shortcut settings) or as a global + // (main_) shortcut. This job might have been easier if we had + // organized the sections as child groups instead of using a colon in + // the settings key to separate the section from the shortcut name. + + // Note that m_settings_key doesn't begin with the sc_group prefix. + + QString my_section = get_shortcut_section (m_settings_key); + QString actual_text = m_edit_actual->text (); + + bool conflict = false; + QString other_settings_key; + + gui_settings settings; + + settings.beginGroup (sc_group); + const QStringList shortcut_settings_keys = settings.allKeys (); + settings.endGroup (); + + for (const auto& settings_key : shortcut_settings_keys) + { + if (settings_key == m_settings_key) + continue; + + QString section = get_shortcut_section (settings_key); + + if (section == my_section || section.startsWith ("main_")) + { + QString shortcut_text + = settings.value (sc_group + "/" + settings_key).toString (); + + if (shortcut_text == actual_text) + { + other_settings_key = settings_key; + conflict = true; + } + } + } + + if (conflict) + { + // We only need the description of the other shortcut, not the + // complete sc_pref info. + + const sc_pref other_scpref + = all_shortcut_preferences::value (other_settings_key); + + int ret = QMessageBox::warning (this, tr ("Double Shortcut"), + tr ("The chosen shortcut\n \"%1\"\n" + "is already used for the action\n \"%2\".\n" + "Do you want to use the shortcut and remove it " + "from the previous action?") + .arg (actual_text) + .arg (other_scpref.description ()), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + + if (ret == QMessageBox::Yes) + emit set_shortcut (other_settings_key, ""); + else + return; + } + + m_shortcut_item->set_actual_text (actual_text); +} + +void shortcut_edit_dialog::set_default_shortcut (void) +{ + // Just remove user-set value so that the default will be used. + m_edit_actual->setText (""); +} + +shortcuts_tree_widget::shortcuts_tree_widget (QWidget *parent) + : QTreeWidget (parent) +{ + QHash <QString, QTreeWidgetItem *> level_hash; + + header ()->setSectionResizeMode (QHeaderView::ResizeToContents); + + int dsc_col = tree_widget_shortcut_item::DESCRIPTION_COLUMN; + + QTreeWidgetItem *main = new QTreeWidgetItem (this); + main->setText (dsc_col, tr ("Global")); + main->setExpanded (true); + + QTreeWidgetItem *main_file = new QTreeWidgetItem (main); + main_file->setText (dsc_col, tr ("File Menu")); + + QTreeWidgetItem *main_edit = new QTreeWidgetItem (main); + main_edit->setText (dsc_col, tr ("Edit Menu")); + + QTreeWidgetItem *main_debug = new QTreeWidgetItem (main); + main_debug->setText (dsc_col, tr ("Debug Menu")); + + QTreeWidgetItem *main_tools = new QTreeWidgetItem (main); + main_tools->setText (dsc_col, tr ("Tools Menu")); + + QTreeWidgetItem *main_window = new QTreeWidgetItem (main); + main_window->setText (dsc_col, tr ("Window Menu")); + + QTreeWidgetItem *main_help = new QTreeWidgetItem (main); + main_help->setText (dsc_col, tr ("Help Menu")); + + QTreeWidgetItem *main_news = new QTreeWidgetItem (main); + main_news->setText (dsc_col, tr ("News Menu")); + + QTreeWidgetItem *main_dock_widgets = new QTreeWidgetItem (main); + main_dock_widgets->setText (dsc_col, tr ("Handling of Dock Widgets")); + + QTreeWidgetItem *main_tabs = new QTreeWidgetItem (main); + main_tabs->setText (dsc_col, tr ("Tab Handling in Dock Widgets")); + + QTreeWidgetItem *main_find = new QTreeWidgetItem (main); + main_find->setText (dsc_col, tr ("Find & Replace in Dock Widgets")); + + QTreeWidgetItem *main_zoom = new QTreeWidgetItem (main); + main_zoom->setText (dsc_col, tr ("Zooming in Editor and Documentation")); + + level_hash[sc_main_file] = main_file; + level_hash[sc_main_edit] = main_edit; + level_hash[sc_main_debug] = main_debug; + level_hash[sc_main_tools] = main_tools; + level_hash[sc_main_window] = main_window; + level_hash[sc_main_help] = main_help; + level_hash[sc_main_news] = main_news; + level_hash[sc_dock_widget] = main_dock_widgets; + level_hash[sc_edit_tabs] = main_tabs; + level_hash[sc_edit_find] = main_find; + level_hash[sc_edit_zoom] = main_zoom; + + QTreeWidgetItem *editor = new QTreeWidgetItem (this); + editor->setText (dsc_col, tr ("Editor")); + editor->setExpanded (true); + + QTreeWidgetItem *editor_file = new QTreeWidgetItem (editor); + editor_file->setText (dsc_col, tr ("File Menu")); + + QTreeWidgetItem *editor_edit = new QTreeWidgetItem (editor); + editor_edit->setText (dsc_col, tr ("Edit Menu")); + + QTreeWidgetItem *editor_view = new QTreeWidgetItem (editor); + editor_view->setText (dsc_col, tr ("View Menu")); + + QTreeWidgetItem *editor_debug = new QTreeWidgetItem (editor); + editor_debug->setText (dsc_col, tr ("Debug Menu")); + + QTreeWidgetItem *editor_run = new QTreeWidgetItem (editor); + editor_run->setText (dsc_col, tr ("Run Menu")); + + QTreeWidgetItem *editor_help = new QTreeWidgetItem (editor); + editor_help->setText (dsc_col, tr ("Help Menu")); + + level_hash[sc_edit_file] = editor_file; + level_hash[sc_edit_edit] = editor_edit; + level_hash[sc_edit_view] = editor_view; + level_hash[sc_edit_debug] = editor_debug; + level_hash[sc_edit_run] = editor_run; + level_hash[sc_edit_help] = editor_help; + + QTreeWidgetItem *doc = new QTreeWidgetItem (this); + doc->setText (dsc_col, tr ("Documentation Viewer")); + doc->setExpanded (true); + + QTreeWidgetItem *doc_browser = new QTreeWidgetItem (doc); + doc_browser->setText (dsc_col, tr ("Browser")); + + level_hash[sc_doc] = doc_browser; + + connect (this, &QTreeWidget::itemDoubleClicked, + this, &shortcuts_tree_widget::edit_selection); + + const QList<QString> shortcut_settings_keys + = all_shortcut_preferences::keys (); + + gui_settings settings; + + settings.beginGroup (sc_group); + + for (const auto& settings_key : shortcut_settings_keys) + { + QTreeWidgetItem *section = level_hash[settings_key.section (':', 0, 0)]; + + // handle sections which have changed and do not correspond to the + // previously defined keyname + if (section == editor_file) + { + // Closing tabs now in global tab handling section + if (settings_key.contains (sc_edit_file_cl)) + section = main_tabs; + } + else if (section == editor_edit) + { + // Find & replace now in global file & replace handling section + if (settings_key.contains (sc_edit_edit_find)) + section = main_find; + } + else if (section == editor_view) + { + // Zooming now in global zoom handling section + if (settings_key.contains (sc_edit_view_zoom)) + section = main_zoom; + } + + // We don't want to apply default value here. + QString actual_text = settings.value (settings_key).toString (); + + const sc_pref scpref = all_shortcut_preferences::value (settings_key); + + // Inserts itself in the tree widget in SECTION. The parent + // object will delete it. + new tree_widget_shortcut_item (section, scpref, actual_text); + } + + settings.endGroup (); +} + +void +shortcuts_tree_widget::edit_selection (QTreeWidgetItem *item, int col) +{ + if (col != 2) + return; + + tree_widget_shortcut_item *shortcut_item + = dynamic_cast<tree_widget_shortcut_item *> (item); + + if (! shortcut_item) + return; // top-level-item clicked + + shortcut_edit_dialog *dialog + = new shortcut_edit_dialog (shortcut_item); + + connect (dialog, &shortcut_edit_dialog::set_shortcut, + this, &shortcuts_tree_widget::update_widget_value); + + dialog->show (); +} + +void shortcuts_tree_widget::update_widget_value (const QString& settings_key, + const QString& sc_text) +{ + tree_widget_shortcut_item *item = get_item (settings_key); + + if (item) + item->set_actual_text (sc_text); +} + +tree_widget_shortcut_item * +shortcuts_tree_widget::get_item (const QString& settings_key) +{ + // There aren't many shortcuts so iterating over all of them to find + // an individual item isn't a big performance issue. If we had many + // more items we could use a QHash <settings_key, sc_pref> data member. + + tree_widget_shortcut_item *item = nullptr; + + QTreeWidgetItemIterator it (this, QTreeWidgetItemIterator::NoChildren); + while (*it) + { + tree_widget_shortcut_item *shortcut_item + = dynamic_cast<tree_widget_shortcut_item *> (*it); + + if (settings_key == shortcut_item->settings_key ()) + { + item = shortcut_item; + break; + } + + it++; + } + + // FIXME: Should it be an error to not find a match? + + if (! item) + qWarning () << (tr ("item %1 not found in shortcut settings dialog") + .arg (settings_key)); + + return item; +} + +void shortcuts_tree_widget::update_settings_value (gui_settings& settings, + const QString& settings_key) +{ + tree_widget_shortcut_item *item = get_item (settings_key); + + if (item) + settings.setValue (settings_key, item->actual_text ()); +} + +// Refresh the tree view with values from the settings object. + +void shortcuts_tree_widget::import_shortcuts (gui_settings& settings) +{ + settings.beginGroup (sc_group); + + const QStringList shortcut_settings_keys = settings.allKeys (); + + for (const auto& settings_key : shortcut_settings_keys) + { + QString sc_text = settings.value (settings_key).toString (); + + update_widget_value (settings_key, sc_text); + } + + settings.endGroup (); + + bool sc_ctrld = false; + + QTreeWidgetItemIterator it (this, QTreeWidgetItemIterator::NoChildren); + while (*it) + { + tree_widget_shortcut_item *shortcut_item + = dynamic_cast<tree_widget_shortcut_item *> (*it); + + if (! shortcut_item) + continue; + + QString settings_key = shortcut_item->settings_key (); + QString sc_text = shortcut_item->actual_text (); + + if (sc_text.isEmpty ()) + sc_text = shortcut_item->default_text (); + + QString section = get_shortcut_section (settings_key); + + // special: check main-window for Ctrl-D (Terminal) + if (section.startsWith ("main_") + && QKeySequence (sc_text) == QKeySequence (Qt::ControlModifier+Qt::Key_D)) + + sc_ctrld = true; + + it++; + } + + settings.setValue (sc_main_ctrld.key, sc_ctrld); + + settings.sync (); +} + +// Export all shortcuts from the tree view to the settings object. + +void shortcuts_tree_widget::export_shortcuts (gui_settings& settings) +{ + settings.beginGroup (sc_group); + + bool sc_ctrld = false; + + QTreeWidgetItemIterator it (this, QTreeWidgetItemIterator::NoChildren); + while (*it) + { + tree_widget_shortcut_item *shortcut_item + = dynamic_cast<tree_widget_shortcut_item *> (*it); + + if (! shortcut_item) + continue; + + QString settings_key = shortcut_item->settings_key (); + QString sc_text = shortcut_item->actual_text (); + + if (sc_text.isEmpty ()) + sc_text = shortcut_item->default_text (); + else + settings.setValue (settings_key, sc_text); + + QString section = get_shortcut_section (settings_key); + + // special: check main-window for Ctrl-D (Terminal) + if (section.startsWith ("main_") + && QKeySequence (sc_text) == QKeySequence (Qt::ControlModifier+Qt::Key_D)) + + sc_ctrld = true; + + it++; + } + + settings.endGroup (); + + settings.setValue (sc_main_ctrld.key, sc_ctrld); + + settings.sync (); +} + +// Clear all user-defined settings from the tree widget and the +// application settings. + +void shortcuts_tree_widget::set_default_shortcuts (void) +{ + gui_settings settings; + + settings.beginGroup (sc_group); + + settings.remove (""); + + settings.endGroup (); + + bool sc_ctrld = false; + + QTreeWidgetItemIterator it (this, QTreeWidgetItemIterator::NoChildren); + while (*it) + { + tree_widget_shortcut_item *shortcut_item + = dynamic_cast<tree_widget_shortcut_item *> (*it); + + if (! shortcut_item) + continue; + + QString settings_key = shortcut_item->settings_key (); + + shortcut_item->set_actual_text (""); + + QString sc_text = shortcut_item->default_text (); + + QString section = get_shortcut_section (settings_key); + + // special: check main-window for Ctrl-D (Terminal) + if (section.startsWith ("main_") + && QKeySequence (sc_text) == QKeySequence (Qt::ControlModifier+Qt::Key_D)) + + sc_ctrld = true; + + it++; + } + + settings.setValue (sc_main_ctrld.key, sc_ctrld); + + settings.sync (); +} + +// For each key found in application settings object, transfer +// corresponding setting to the application settings object. + +void shortcuts_tree_widget::write_settings (void) +{ + gui_settings settings; + + export_shortcuts (settings); +} + +OCTAVE_END_NAMESPACE(octave)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgui/src/shortcuts-tree-widget.h Mon Dec 26 17:29:59 2022 -0500 @@ -0,0 +1,158 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2014-2022 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or <https://octave.org/copyright/>. +// +// This file is part of Octave. +// +// Octave 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 3 of the License, or +// (at your option) any later version. +// +// Octave 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 Octave; see the file COPYING. If not, see +// <https://www.gnu.org/licenses/>. +// +//////////////////////////////////////////////////////////////////////// + +#if ! defined (octave_shortcuts_tree_widget_h) +#define octave_shortcuts_tree_widget_h 1 + +#include <QCheckBox> +#include <QDialog> +#include <QKeyEvent> +#include <QLineEdit> +#include <QString> +#include <QTreeWidget> +#include <QtCore> + +#include "gui-preferences.h" +#include "gui-settings.h" + +OCTAVE_BEGIN_NAMESPACE(octave) + +class enter_shortcut : public QLineEdit +{ + Q_OBJECT + +public: + + enter_shortcut (QWidget *p = nullptr); + + ~enter_shortcut (void) = default; + + virtual void keyPressEvent (QKeyEvent *e); + +public slots: + + void handle_direct_shortcut (int); + void handle_shift_modifier (int); + +private: + + bool m_direct_shortcut; + bool m_shift_modifier; +}; + +class tree_widget_shortcut_item : public QTreeWidgetItem +{ +public: + + enum + { + DESCRIPTION_COLUMN = 0, + DEFAULT_COLUMN, + ACTUAL_COLUMN + }; + + tree_widget_shortcut_item (QTreeWidgetItem *parent, const sc_pref& scpref, + const QString& actual_text); + + QString settings_key (void) const; + + QString description (void) const; + void set_description (const QString& text); + + QString default_text (void) const; + void set_default_text (const QString& text); + + QString actual_text (void) const; + void set_actual_text (const QString& text); + +private: + + QString m_settings_key; +}; + +class shortcut_edit_dialog : public QDialog +{ + Q_OBJECT + +public: + + shortcut_edit_dialog (tree_widget_shortcut_item *shortcut_item, + QWidget *parent = nullptr); + +public slots: + + void finished (int result); + + void set_default_shortcut (void); + +signals: + + void set_shortcut (const QString& settings_key, + const QString& settings_value); + +private: + + tree_widget_shortcut_item *m_shortcut_item; + + enter_shortcut *m_edit_actual; + + QString m_settings_key; + QString m_default_text; +}; + +class shortcuts_tree_widget : public QTreeWidget +{ + Q_OBJECT + +public: + + shortcuts_tree_widget (QWidget *parent); + + void import_shortcuts (gui_settings& settings); + + void export_shortcuts (gui_settings& settings); + + void set_default_shortcuts (void); + + void write_settings (void); + +public slots: + + void edit_selection (QTreeWidgetItem *item, int col); + + void update_widget_value (const QString& settings_key, + const QString& sc_text); + +private: + + tree_widget_shortcut_item * get_item (const QString& settings_key); + + void update_settings_value (gui_settings& settings, + const QString& settings_key); +}; + +OCTAVE_END_NAMESPACE(octave) + +#endif
--- a/libgui/src/terminal-dock-widget.cc Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/terminal-dock-widget.cc Mon Dec 26 17:29:59 2022 -0500 @@ -39,6 +39,8 @@ #include "gui-preferences-cs.h" #include "gui-preferences-global.h" +#include "gui-preferences-sc.h" +#include "gui-settings.h" #include "octave-qobject.h" #include "terminal-dock-widget.h" @@ -50,6 +52,8 @@ : octave_dock_widget ("TerminalDockWidget", p, oct_qobj), m_experimental_terminal_widget (oct_qobj.experimental_terminal_widget ()) { + init_control_d_shortcut_behavior (); + // FIXME: we could do this in a better way, but improving it doesn't // matter much if we will eventually be removing the old terminal. if (m_experimental_terminal_widget) @@ -168,4 +172,39 @@ } } + void terminal_dock_widget::init_control_d_shortcut_behavior (void) + { + gui_settings settings; + + // Reset use of Ctrl-D. Do this before the call to beginGroup + // because sc_main_ctrld.key already begins with the sc_group + // prefix. + settings.setValue (sc_main_ctrld.key, false); + + settings.beginGroup (sc_group); + const QStringList shortcut_settings_keys = settings.allKeys (); + settings.endGroup (); + + for (const auto& settings_key : shortcut_settings_keys) + { + // Check whether Ctrl+D is used from main window, i.e. is a + // global shortcut. + + QString section = get_shortcut_section (settings_key); + + if (section.startsWith ("main_")) + { + sc_pref scpref = all_shortcut_preferences::value (settings_key); + + QKeySequence actual = QKeySequence (settings.sc_value (scpref)); + + if (actual == QKeySequence (Qt::ControlModifier+Qt::Key_D)) + { + settings.setValue (sc_main_ctrld.key, true); + break; + } + } + } + } + OCTAVE_END_NAMESPACE(octave)
--- a/libgui/src/terminal-dock-widget.h Sun Dec 25 20:37:53 2022 -0500 +++ b/libgui/src/terminal-dock-widget.h Mon Dec 26 17:29:59 2022 -0500 @@ -51,6 +51,8 @@ void init_command_prompt (); + void init_control_d_shortcut_behavior (); + // FIXME: The next two functions could be eliminated (or combined) // if we had a common interface for the old and new terminal // widgets.