1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 2014-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if defined (HAVE_CONFIG_H) 27 # include "config.h" 28 #endif 29 30 #include <QAction> 31 #include <QApplication> 32 #include <QCheckBox> 33 #include <QDebug> 34 #include <QDialogButtonBox> 35 #include <QFileDialog> 36 #include <QGridLayout> 37 #include <QHeaderView> 38 #include <QKeySequence> 39 #include <QLineEdit> 40 #include <QMessageBox> 41 #include <QPushButton> 42 #include <QVBoxLayout> 43 #include <QtCore> 44 45 #include "octave-qobject.h" 46 #include "shortcut-manager.h" 47 #include "gui-preferences-global.h" 48 #include "gui-preferences-sc.h" 49 #include "error.h" 50 51 namespace octave 52 { 53 // enter_shortcut: 54 // class derived from QLineEdit for directly entering key sequences which 55 enter_shortcut(QWidget * p)56 enter_shortcut::enter_shortcut (QWidget *p) : QLineEdit (p) 57 { 58 m_direct_shortcut = true; // the shortcut is directly entered 59 m_shift_modifier = false; // the shift modifier is not added 60 } 61 62 // new keyPressEvent keyPressEvent(QKeyEvent * e)63 void enter_shortcut::keyPressEvent (QKeyEvent *e) 64 { 65 if (! m_direct_shortcut) 66 { 67 QLineEdit::keyPressEvent (e); 68 return; 69 } 70 71 if (e->type () == QEvent::KeyPress) 72 { 73 int key = e->key (); 74 75 if (key == Qt::Key_unknown || key == 0) 76 return; 77 78 #if defined (HAVE_QGUIAPPLICATION) 79 Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers (); //e->modifiers (); 80 #else 81 Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers (); //e->modifiers (); 82 #endif 83 84 if (m_shift_modifier || (modifiers & Qt::ShiftModifier)) 85 key += Qt::SHIFT; 86 if (modifiers & Qt::ControlModifier) 87 key += Qt::CTRL; 88 if (modifiers & Qt::AltModifier) 89 key += Qt::ALT; 90 if (modifiers & Qt::MetaModifier) 91 key += Qt::META; 92 93 setText (QKeySequence (key).toString ()); 94 } 95 } 96 97 // slot for checkbox whether the shortcut is directly entered or not handle_direct_shortcut(int state)98 void enter_shortcut::handle_direct_shortcut (int state) 99 { 100 if (state) 101 m_direct_shortcut = true; // the shortcut is directly entered 102 else 103 m_direct_shortcut = false; // the shortcut has to be written as text 104 } 105 106 // slot for checkbox whether the shift modifier should be added handle_shift_modifier(int state)107 void enter_shortcut::handle_shift_modifier (int state) 108 { 109 if (state) 110 m_shift_modifier = true; // the shortcut is directly entered 111 else 112 m_shift_modifier = false; // the shortcut has to be written as text 113 } 114 115 shortcut_manager(base_qobject & oct_qobj)116 shortcut_manager::shortcut_manager (base_qobject& oct_qobj) 117 : m_octave_qobj (oct_qobj) 118 { 119 setObjectName ("Shortcut_Manager"); 120 121 // Mac: don't let Qt interpret CMD key ("Meta" in Qt terminology) as Ctrl 122 #if defined (Q_OS_MAC) 123 QCoreApplication::setAttribute (Qt::AA_MacDontSwapCtrlAndMeta, true); 124 #endif 125 } 126 init_data(void)127 void shortcut_manager::init_data (void) 128 { 129 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 130 gui_settings *settings = rmgr.get_settings (); 131 132 settings->setValue (sc_main_ctrld.key, false); // reset use fo ctrl-d 133 134 // actions not related to specific menus or widgets 135 136 // dock widgets 137 init (tr ("Undock/Dock Widget"), sc_dock_widget_dock); 138 init (tr ("Close Widget"), sc_dock_widget_close); 139 140 // actions of the main window 141 142 // file 143 init (tr ("New File"), sc_main_file_new_file); 144 init (tr ("New Function"), sc_main_file_new_function); 145 init (tr ("New Figure"), sc_main_file_new_figure); 146 init (tr ("Open File"), sc_main_file_open_file); 147 init (tr ("Load Workspace"), sc_main_file_load_workspace); 148 init (tr ("Save Workspace As"), sc_main_file_save_workspace); 149 init (tr ("Exit Octave"), sc_main_file_exit); 150 151 // edit 152 init (tr ("Copy"), sc_main_edit_copy); 153 init (tr ("Paste"), sc_main_edit_paste); 154 init (tr ("Undo"), sc_main_edit_undo); 155 init (tr ("Select All"), sc_main_edit_select_all); 156 init (tr ("Clear Clipboard"), sc_main_edit_clear_clipboard); 157 init (tr ("Find in Files"), sc_main_edit_find_in_files); 158 init (tr ("Clear Command Window"), sc_main_edit_clear_command_window); 159 init (tr ("Clear Command History"), sc_main_edit_clear_history); 160 init (tr ("Clear Workspace"), sc_main_edit_clear_workspace); 161 init (tr ("Set Path"), sc_main_edit_set_path); 162 init (tr ("Preferences"), sc_main_edit_preferences); 163 164 // debug 165 init (tr ("Step"), sc_main_debug_step_over); 166 init (tr ("Step Into"), sc_main_debug_step_into); 167 init (tr ("Step Out"), sc_main_debug_step_out); 168 init (tr ("Continue"), sc_main_debug_continue); 169 init (tr ("Quit Debug Mode"), sc_main_debug_quit); 170 171 // window 172 init (tr ("Show Command Window"), sc_main_window_show_command); 173 init (tr ("Show Command History"), sc_main_window_show_history); 174 init (tr ("Show File Browser"), sc_main_window_show_file_browser); 175 init (tr ("Show Workspace"), sc_main_window_show_workspace); 176 init (tr ("Show Editor"), sc_main_window_show_editor); 177 init (tr ("Show Documentation"), sc_main_window_show_doc); 178 init (tr ("Show Variable Editor"), sc_main_window_show_variable_editor); 179 init (tr ("Command Window"), sc_main_window_command); 180 init (tr ("Command History"), sc_main_window_history); 181 init (tr ("File Browser"), sc_main_window_file_browser); 182 init (tr ("Workspace"), sc_main_window_workspace); 183 init (tr ("Editor"), sc_main_window_editor); 184 init (tr ("Documentation"), sc_main_window_doc); 185 init (tr ("Variable Editor"), sc_main_window_variable_editor); 186 init (tr ("Previous Widget"), sc_main_window_previous_dock); 187 init (tr ("Reset Default Window Layout"), sc_main_window_reset); 188 189 // help 190 init (tr ("Show Ondisk Documentation"), sc_main_help_ondisk_doc); 191 init (tr ("Show Online Documentation"), sc_main_help_online_doc); 192 init (tr ("Report Bug"), sc_main_help_report_bug); 193 init (tr ("Octave Packages"), sc_main_help_packages); 194 init (tr ("Contribute to Octave"), sc_main_help_contribute); 195 init (tr ("Octave Developer Resources"), sc_main_help_developer); 196 init (tr ("About Octave"), sc_main_help_about); 197 198 // news 199 init (tr ("Release Notes"), sc_main_news_release_notes); 200 init (tr ("Community News"), sc_main_news_community_news); 201 202 // Tab handling 203 // The following shortcuts are moved into a separate tab. The key names 204 // are not changed, to preserve compatibility with older versions. 205 init (tr ("Close Tab"), sc_edit_file_close); 206 init (tr ("Close All Tabs"), sc_edit_file_close_all); 207 init (tr ("Close Other Tabs"), sc_edit_file_close_other); 208 init (tr ("Switch to Left Tab"), sc_edit_tabs_switch_left_tab); 209 init (tr ("Switch to Right Tab"), sc_edit_tabs_switch_right_tab); 210 init (tr ("Move Tab Left"), sc_edit_tabs_move_tab_left); 211 init (tr ("Move Tab Right"), sc_edit_tabs_move_tab_right); 212 213 // Zooming 214 init (tr ("Zoom In"), sc_edit_view_zoom_in); 215 init (tr ("Zoom Out"), sc_edit_view_zoom_out); 216 #if defined (Q_OS_MAC) 217 init (tr ("Zoom Normal"), sc_edit_view_zoom_normal); 218 #else 219 init (tr ("Zoom Normal"), sc_edit_view_zoom_normal); 220 #endif 221 222 // actions of the editor 223 224 // file 225 init (tr ("Edit Function"), sc_edit_file_edit_function); 226 init (tr ("Save File"), sc_edit_file_save); 227 init (tr ("Save File As"), sc_edit_file_save_as); 228 init (tr ("Print"), sc_edit_file_print); 229 230 // edit 231 init (tr ("Redo"), sc_edit_edit_redo); 232 init (tr ("Cut"), sc_edit_edit_cut); 233 init (tr ("Find and Replace"), sc_edit_edit_find_replace); 234 init (tr ("Find Next"), sc_edit_edit_find_next); 235 init (tr ("Find Previous"), sc_edit_edit_find_previous); 236 init (tr ("Delete to Start of Word"), sc_edit_edit_delete_start_word); 237 init (tr ("Delete to End of Word"), sc_edit_edit_delete_end_word); 238 init (tr ("Delete to Start of Line"), sc_edit_edit_delete_start_line); 239 init (tr ("Delete to End of Line"), sc_edit_edit_delete_end_line); 240 init (tr ("Delete Line"), sc_edit_edit_delete_line); 241 init (tr ("Copy Line"), sc_edit_edit_copy_line); 242 init (tr ("Cut Line"), sc_edit_edit_cut_line); 243 init (tr ("Duplicate Selection/Line"), sc_edit_edit_duplicate_selection); 244 init (tr ("Transpose Line"), sc_edit_edit_transpose_line); 245 init (tr ("Show Completion List"), sc_edit_edit_completion_list); 246 247 init (tr ("Comment Selection"), sc_edit_edit_comment_selection); 248 init (tr ("Uncomment Selection"), sc_edit_edit_uncomment_selection); 249 init (tr ("Comment Selection (Choosing String)"), sc_edit_edit_comment_var_selection); 250 init (tr ("Uppercase Selection"), sc_edit_edit_upper_case); 251 init (tr ("Lowercase Selection"), sc_edit_edit_lower_case); 252 253 #if defined (Q_OS_MAC) 254 init (tr ("Indent Selection Rigidly"), sc_edit_edit_indent_selection); 255 init (tr ("Unindent Selection Rigidly"), sc_edit_edit_unindent_selection); 256 #else 257 init (tr ("Indent Selection Rigidly"), sc_edit_edit_indent_selection); 258 init (tr ("Unindent Selection Rigidly"), sc_edit_edit_unindent_selection); 259 #endif 260 init (tr ("Indent Code"), sc_edit_edit_smart_indent_line_or_selection); 261 262 init (tr ("Convert Line Endings to Windows"), sc_edit_edit_conv_eol_winows); 263 init (tr ("Convert Line Endings to Unix"), sc_edit_edit_conv_eol_unix); 264 init (tr ("Convert Line Endings to Mac"), sc_edit_edit_conv_eol_mac); 265 266 init (tr ("Goto Line"), sc_edit_edit_goto_line); 267 init (tr ("Move to Matching Brace"), sc_edit_edit_move_to_brace); 268 init (tr ("Select to Matching Brace"), sc_edit_edit_select_to_brace); 269 init (tr ("Toggle Bookmark"), sc_edit_edit_toggle_bookmark); 270 init (tr ("Next Bookmark"), sc_edit_edit_next_bookmark); 271 init (tr ("Previous Bookmark"), sc_edit_edit_previous_bookmark); 272 init (tr ("Remove All Bookmark"), sc_edit_edit_remove_bookmark); 273 274 init (tr ("Preferences"), sc_edit_edit_preferences); 275 init (tr ("Styles Preferences"), sc_edit_edit_styles_preferences); 276 277 // view 278 init (tr ("Show Line Numbers"), sc_edit_view_show_line_numbers); 279 init (tr ("Show Whitespace Characters"), sc_edit_view_show_white_spaces); 280 init (tr ("Show Line Endings"), sc_edit_view_show_eol_chars); 281 init (tr ("Show Indentation Guides"), sc_edit_view_show_ind_guides); 282 init (tr ("Show Long Line Marker"), sc_edit_view_show_long_line); 283 init (tr ("Show Toolbar"), sc_edit_view_show_toolbar); 284 init (tr ("Show Statusbar"), sc_edit_view_show_statusbar); 285 init (tr ("Show Horizontal Scrollbar"), sc_edit_view_show_hscrollbar); 286 init (tr ("Sort Tabs Alphabetically"), sc_edit_view_sort_tabs); 287 288 // debug 289 init (tr ("Toggle Breakpoint"), sc_edit_debug_toggle_breakpoint); 290 init (tr ("Next Breakpoint"), sc_edit_debug_next_breakpoint); 291 init (tr ("Previous Breakpoint"), sc_edit_debug_previous_breakpoint); 292 init (tr ("Remove All Breakpoints"), sc_edit_debug_remove_breakpoints); 293 294 // run 295 init (tr ("Run File"), sc_edit_run_run_file); 296 init (tr ("Run Selection"), sc_edit_run_run_selection); 297 298 // help 299 init (tr ("Help on Keyword"), sc_edit_help_help_keyword); 300 init (tr ("Document on Keyword"), sc_edit_help_doc_keyword); 301 302 303 // Documentation browser 304 init (tr ("Go to Homepage"), sc_doc_go_home); 305 init (tr ("Go Back one Page"), sc_doc_go_back); 306 init (tr ("Go Forward one Page"), sc_doc_go_next); 307 } 308 309 // write one or all actual shortcut set(s) into a settings file write_shortcuts(gui_settings * settings,bool closing)310 void shortcut_manager::write_shortcuts (gui_settings *settings, 311 bool closing) 312 { 313 bool sc_ctrld = false; 314 315 QString sc_main = sc_main_file.mid (0, sc_main_file.indexOf ('_') + 1); 316 317 for (int i = 0; i < m_sc.count (); i++) // loop over all shortcuts 318 { 319 settings->setValue (sc_group + "/" + m_sc.at (i).m_settings_key, 320 m_sc.at (i).m_actual_sc.toString ()); 321 // special: check main-window for Ctrl-D (Terminal) 322 if (m_sc.at (i).m_settings_key.startsWith (sc_main) 323 && m_sc.at (i).m_actual_sc == QKeySequence (Qt::ControlModifier+Qt::Key_D)) 324 sc_ctrld = true; 325 } 326 327 settings->setValue (sc_main_ctrld.key, sc_ctrld); 328 329 if (closing) 330 { 331 delete m_dialog; // the dialog for key sequences can be removed now 332 m_dialog = nullptr; // make sure it is zero again 333 } 334 335 settings->sync (); // sync the settings file 336 } 337 set_shortcut(QAction * action,const sc_pref & scpref)338 void shortcut_manager::set_shortcut (QAction *action, const sc_pref& scpref) 339 { 340 int index; 341 342 index = m_action_hash[scpref.key] - 1; 343 344 if (index > -1 && index < m_sc.count ()) 345 { 346 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 347 gui_settings *settings = rmgr.get_settings (); 348 action->setShortcut (QKeySequence (settings->sc_value (scpref))); 349 } 350 else 351 qDebug () << "Key: " << scpref.key << " not found in m_action_hash"; 352 } 353 shortcut(QShortcut * sc,const sc_pref & scpref)354 void shortcut_manager::shortcut (QShortcut *sc, const sc_pref& scpref) 355 { 356 int index; 357 358 index = m_action_hash[scpref.key] - 1; 359 360 if (index > -1 && index < m_sc.count ()) 361 { 362 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 363 gui_settings *settings = rmgr.get_settings (); 364 sc->setKey (QKeySequence (settings->sc_value (scpref))); 365 } 366 else 367 qDebug () << "Key: " << scpref.key << " not found in m_action_hash"; 368 } 369 fill_treewidget(QTreeWidget * tree_view)370 void shortcut_manager::fill_treewidget (QTreeWidget *tree_view) 371 { 372 m_dialog = nullptr; 373 m_level_hash.clear (); 374 375 #if defined (HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE) 376 tree_view->header ()->setSectionResizeMode (QHeaderView::ResizeToContents); 377 #else 378 tree_view->header ()->setResizeMode (QHeaderView::ResizeToContents); 379 #endif 380 381 QTreeWidgetItem *main = new QTreeWidgetItem (tree_view); 382 main->setText (0, tr ("Global")); 383 main->setExpanded (true); 384 QTreeWidgetItem *main_file = new QTreeWidgetItem (main); 385 main_file->setText (0, tr ("File Menu")); 386 QTreeWidgetItem *main_edit = new QTreeWidgetItem (main); 387 main_edit->setText (0, tr ("Edit Menu")); 388 QTreeWidgetItem *main_debug = new QTreeWidgetItem (main); 389 main_debug->setText (0, tr ("Debug Menu")); 390 QTreeWidgetItem *main_window = new QTreeWidgetItem (main); 391 main_window->setText (0, tr ("Window Menu")); 392 QTreeWidgetItem *main_help = new QTreeWidgetItem (main); 393 main_help->setText (0, tr ("Help Menu")); 394 QTreeWidgetItem *main_news = new QTreeWidgetItem (main); 395 main_news->setText (0, tr ("News Menu")); 396 QTreeWidgetItem *main_dock_widgets = new QTreeWidgetItem (main); 397 main_dock_widgets->setText (0, tr ("Handling of Dock Widgets")); 398 QTreeWidgetItem *main_tabs = new QTreeWidgetItem (main); 399 main_tabs->setText (0, tr ("Tab Handling in Dock Widgets")); 400 QTreeWidgetItem *main_find = new QTreeWidgetItem (main); 401 main_find->setText (0, tr ("Find & Replace in Dock Widgets")); 402 QTreeWidgetItem *main_zoom = new QTreeWidgetItem (main); 403 main_zoom->setText (0, tr ("Zooming in Editor and Documentation")); 404 405 m_level_hash[sc_main_file] = main_file; 406 m_level_hash[sc_main_edit] = main_edit; 407 m_level_hash[sc_main_debug] = main_debug; 408 m_level_hash[sc_main_window] = main_window; 409 m_level_hash[sc_main_help] = main_help; 410 m_level_hash[sc_main_news] = main_news; 411 m_level_hash[sc_dock_widget] = main_dock_widgets; 412 m_level_hash[sc_edit_tabs] = main_tabs; 413 m_level_hash[sc_edit_find] = main_find; 414 m_level_hash[sc_edit_zoom] = main_zoom; 415 416 QTreeWidgetItem *editor = new QTreeWidgetItem (tree_view); 417 editor->setText (0, tr ("Editor")); 418 editor->setExpanded (true); 419 QTreeWidgetItem *editor_file = new QTreeWidgetItem (editor); 420 editor_file->setText (0, tr ("File Menu")); 421 QTreeWidgetItem *editor_edit = new QTreeWidgetItem (editor); 422 editor_edit->setText (0, tr ("Edit Menu")); 423 QTreeWidgetItem *editor_view = new QTreeWidgetItem (editor); 424 editor_view->setText (0, tr ("View Menu")); 425 QTreeWidgetItem *editor_debug = new QTreeWidgetItem (editor); 426 editor_debug->setText (0, tr ("Debug Menu")); 427 QTreeWidgetItem *editor_run = new QTreeWidgetItem (editor); 428 editor_run->setText (0, tr ("Run Menu")); 429 QTreeWidgetItem *editor_help = new QTreeWidgetItem (editor); 430 editor_help->setText (0, tr ("Help Menu")); 431 432 m_level_hash[sc_edit_file] = editor_file; 433 m_level_hash[sc_edit_edit] = editor_edit; 434 m_level_hash[sc_edit_view] = editor_view; 435 m_level_hash[sc_edit_debug] = editor_debug; 436 m_level_hash[sc_edit_run] = editor_run; 437 m_level_hash[sc_edit_help] = editor_help; 438 439 QTreeWidgetItem *doc = new QTreeWidgetItem (tree_view); 440 doc->setText (0, tr ("Documentation Viewer")); 441 doc->setExpanded (true); 442 443 QTreeWidgetItem *doc_browser = new QTreeWidgetItem (doc); 444 doc_browser->setText (0, tr ("Browser")); 445 446 m_level_hash[sc_doc] = doc_browser; 447 448 connect (tree_view, SIGNAL (itemDoubleClicked (QTreeWidgetItem*, int)), 449 this, SLOT (handle_double_clicked (QTreeWidgetItem*, int))); 450 451 for (int i = 0; i < m_sc.count (); i++) 452 { 453 shortcut_t sc = m_sc.at (i); 454 455 QTreeWidgetItem *section = m_level_hash[sc.m_settings_key.section (':',0,0)]; 456 457 // handle sections which have changed and do not correspond to the 458 // previously defined keyname 459 if (section == editor_file) 460 { 461 // Closing tabs now in global tab handling section 462 if (sc.m_settings_key.contains (sc_edit_file_cl)) 463 section = main_tabs; 464 } 465 if (section == editor_edit) 466 { 467 // Find & replace now in global file & replace handling section 468 if (sc.m_settings_key.contains (sc_edit_edit_find)) 469 section = main_find; 470 } 471 if (section == editor_view) 472 { 473 // Zooming now in global zoom handling section 474 if (sc.m_settings_key.contains (sc_edit_view_zoom)) 475 section = main_zoom; 476 } 477 478 QTreeWidgetItem *tree_item = new QTreeWidgetItem (section); 479 480 // set a slightly transparent foreground for default columns 481 QColor fg = QColor (tree_item->foreground (1).color ()); 482 fg.setAlpha (128); 483 tree_item->setForeground (1, QBrush (fg)); 484 485 // write the shortcuts 486 tree_item->setText (0, sc.m_description); 487 tree_item->setText (1, sc.m_default_sc.toString ()); 488 tree_item->setText (2, sc.m_actual_sc.toString ()); 489 490 m_item_index_hash[tree_item] = i + 1; // index+1 to avoid 0 491 m_index_item_hash[i] = tree_item; 492 } 493 } 494 495 // import or export of shortcut sets, 496 // called from settings dialog when related buttons are clicked; 497 // returns true on success, false otherwise 498 bool import_export(int action)499 shortcut_manager::import_export (int action) 500 { 501 // ask to save the current shortcuts, maybe abort import 502 if (action == OSC_DEFAULT || action == OSC_IMPORT) 503 { 504 if (! overwrite_all_shortcuts ()) 505 return false; 506 } 507 508 // get the filename to read or write the shortcuts, 509 // the default extension is .osc (octave shortcuts) 510 if (action != OSC_DEFAULT) 511 { 512 QString file; 513 514 // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved. 515 int opts = 0; // No options by default. 516 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 517 gui_settings *settings = rmgr.get_settings (); 518 if (! settings->value (global_use_native_dialogs).toBool ()) 519 opts = QFileDialog::DontUseNativeDialog; 520 521 if (action == OSC_IMPORT) 522 file = QFileDialog::getOpenFileName (this, 523 tr ("Import shortcuts from file..."), QString (), 524 tr ("Octave Shortcut Files (*.osc);;All Files (*)"), 525 nullptr, QFileDialog::Option (opts)); 526 else if (action == OSC_EXPORT) 527 file = QFileDialog::getSaveFileName (this, 528 tr ("Export shortcuts to file..."), QString (), 529 tr ("Octave Shortcut Files (*.osc);;All Files (*)"), 530 nullptr, QFileDialog::Option (opts)); 531 532 if (file.isEmpty ()) 533 return false; 534 535 gui_settings osc_settings (file, QSettings::IniFormat); 536 537 if (osc_settings.status () != QSettings::NoError) 538 { 539 qWarning () << tr ("Failed to open %1 as Octave shortcut file") 540 .arg (file); 541 return false; 542 } 543 else 544 { 545 if (action == OSC_IMPORT) 546 import_shortcuts (&osc_settings); // import (special action) 547 else if (action == OSC_EXPORT) 548 write_shortcuts (&osc_settings, false); // export, (save settings) 549 } 550 } 551 else 552 { 553 import_shortcuts (nullptr); 554 } 555 556 return true; 557 } 558 handle_double_clicked(QTreeWidgetItem * item,int col)559 void shortcut_manager::handle_double_clicked (QTreeWidgetItem *item, int col) 560 { 561 if (col != 2) 562 return; 563 564 int i = m_item_index_hash[item]; 565 if (i == 0) 566 return; // top-level-item clicked 567 568 shortcut_dialog (i-1); // correct to index starting at 0 569 } 570 shortcut_dialog_finished(int result)571 void shortcut_manager::shortcut_dialog_finished (int result) 572 { 573 if (result == QDialog::Rejected) 574 return; 575 576 // check for duplicate 577 int double_index = m_shortcut_hash[m_edit_actual->text ()] - 1; 578 579 if (double_index >= 0 && double_index != m_handled_index) 580 { 581 int ret = QMessageBox::warning (this, tr ("Double Shortcut"), 582 tr ("The chosen shortcut\n \"%1\"\n" 583 "is already used for the action\n \"%2\".\n" 584 "Do you want to use the shortcut anyhow removing it " 585 "from the previous action?") 586 .arg (m_edit_actual->text ()) 587 .arg (m_sc.at (double_index).m_description), 588 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); 589 590 if (ret == QMessageBox::Yes) 591 { 592 shortcut_t double_shortcut = m_sc.at (double_index); 593 double_shortcut.m_actual_sc = QKeySequence (); 594 m_sc.replace (double_index, double_shortcut); 595 m_index_item_hash[double_index]->setText (2, QString ()); 596 } 597 else 598 return; 599 } 600 601 shortcut_t shortcut = m_sc.at (m_handled_index); 602 if (! shortcut.m_actual_sc.isEmpty ()) 603 m_shortcut_hash.remove (shortcut.m_actual_sc.toString ()); 604 shortcut.m_actual_sc = m_edit_actual->text (); 605 m_sc.replace (m_handled_index, shortcut); 606 607 m_index_item_hash[m_handled_index]->setText (2, shortcut.m_actual_sc.toString ()); 608 609 if (! shortcut.m_actual_sc.isEmpty ()) 610 m_shortcut_hash[shortcut.m_actual_sc.toString ()] = m_handled_index + 1; 611 } 612 shortcut_dialog_set_default(void)613 void shortcut_manager::shortcut_dialog_set_default (void) 614 { 615 m_edit_actual->setText (m_label_default->text ()); 616 } 617 init(const QString & description,const sc_pref & sc)618 void shortcut_manager::init (const QString& description, const sc_pref& sc) 619 { 620 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 621 gui_settings *settings = rmgr.get_settings (); 622 623 QKeySequence actual = QKeySequence (settings->sc_value (sc)); 624 625 // append the new shortcut to the list 626 shortcut_t shortcut_info; 627 shortcut_info.m_description = description; 628 shortcut_info.m_settings_key = sc.key; 629 shortcut_info.m_actual_sc = actual; 630 shortcut_info.m_default_sc = settings->sc_def_value (sc); 631 m_sc << shortcut_info; 632 633 // insert shortcut in order to check for duplicates later 634 if (! actual.isEmpty ()) 635 m_shortcut_hash[actual.toString ()] = m_sc.count (); 636 m_action_hash[sc.key] = m_sc.count (); 637 638 // check whether ctrl+d is used from main window, i.e. is a global shortcut 639 QString main_group_prefix 640 = sc_main_file.mid (0, sc_main_file.indexOf ('_') + 1); 641 if (sc.key.startsWith (main_group_prefix) 642 && actual == QKeySequence (Qt::ControlModifier+Qt::Key_D)) 643 settings->setValue (sc_main_ctrld.key, true); 644 } 645 shortcut_dialog(int index)646 void shortcut_manager::shortcut_dialog (int index) 647 { 648 if (! m_dialog) 649 { 650 m_dialog = new QDialog (this); 651 652 m_dialog->setWindowTitle (tr ("Enter new Shortcut")); 653 654 QVBoxLayout *box = new QVBoxLayout (m_dialog); 655 box->setSpacing (2); 656 box->setContentsMargins (12, 12, 12, 12); 657 658 QLabel *help = new QLabel (tr ("Apply the desired shortcut or click " 659 "on the right button to reset the " 660 "shortcut to its default.")); 661 help->setWordWrap (true); 662 box->addWidget (help); 663 664 QCheckBox *direct 665 = new QCheckBox (tr ("Enter shortcut directly by performing it")); 666 667 QCheckBox *shift 668 = new QCheckBox (tr ("Add Shift modifier\n" 669 "(allows to enter number keys)")); 670 671 shift->setStyleSheet 672 ("QCheckBox::indicator { subcontrol-position: left top; }"); 673 674 connect (direct, SIGNAL (clicked (bool)), 675 shift, SLOT (setEnabled (bool))); 676 677 direct->setCheckState (Qt::Checked); 678 679 box->addWidget (direct); 680 box->addWidget (shift); 681 682 box->addSpacing (15); 683 684 QGridLayout *grid = new QGridLayout (); 685 686 QLabel *actual = new QLabel (tr ("Actual shortcut")); 687 m_edit_actual = new enter_shortcut (m_dialog); 688 m_edit_actual->setAlignment (Qt::AlignHCenter); 689 grid->addWidget (actual, 0, 0); 690 grid->addWidget (m_edit_actual, 0, 1); 691 692 QLabel *def = new QLabel (tr ("Default shortcut")); 693 m_label_default = new QLabel (m_dialog); 694 m_label_default->setAlignment (Qt::AlignHCenter); 695 grid->addWidget (def, 1, 0); 696 grid->addWidget (m_label_default, 1, 1); 697 698 QPushButton *set_default = new QPushButton (tr ("Set to default")); 699 grid->addWidget (set_default, 0, 2); 700 connect (set_default, SIGNAL (clicked ()), 701 this, SLOT (shortcut_dialog_set_default ())); 702 703 box->addLayout (grid); 704 705 box->addSpacing (18); 706 707 QDialogButtonBox *button_box = new QDialogButtonBox (QDialogButtonBox::Ok 708 | QDialogButtonBox::Cancel); 709 QList<QAbstractButton *> buttons = button_box->buttons (); 710 for (int i = 0; i < buttons.count (); i++) 711 buttons.at (i)->setShortcut (QKeySequence ()); 712 connect (button_box, SIGNAL (accepted ()), m_dialog, SLOT (accept ())); 713 connect (button_box, SIGNAL (rejected ()), m_dialog, SLOT (reject ())); 714 box->addWidget (button_box); 715 716 m_dialog->setLayout (box); 717 718 connect (direct, SIGNAL (stateChanged (int)), 719 m_edit_actual, SLOT (handle_direct_shortcut (int))); 720 connect (shift, SIGNAL (stateChanged (int)), 721 m_edit_actual, SLOT (handle_shift_modifier (int))); 722 connect (m_dialog, SIGNAL (finished (int)), 723 this, SLOT (shortcut_dialog_finished (int))); 724 725 } 726 727 m_edit_actual->setText (m_sc.at (index).m_actual_sc.toString ()); 728 m_label_default->setText (m_sc.at (index).m_default_sc.toString ()); 729 m_handled_index = index; 730 731 m_edit_actual->setFocus (); 732 m_dialog->setFocusProxy (m_edit_actual); 733 m_dialog->exec (); 734 } 735 736 // import a shortcut set from a given settings file or reset to 737 // the defaults (settings = 0) and refresh the tree view import_shortcuts(gui_settings * settings)738 void shortcut_manager::import_shortcuts (gui_settings *settings) 739 { 740 for (int i = 0; i < m_sc.count (); i++) 741 { 742 // update the list of all shortcuts 743 shortcut_t sc = m_sc.at (i); // make a copy 744 745 if (settings) 746 sc.m_actual_sc = QKeySequence ( // get new shortcut from settings 747 settings->value (sc_group + sc.m_settings_key,sc.m_actual_sc). 748 toString ()); // and use the old one as default 749 else 750 sc.m_actual_sc = QKeySequence (sc.m_default_sc); // get default shortcut 751 752 m_sc.replace (i,sc); // replace the old with the new one 753 754 // update the tree view 755 QTreeWidgetItem *tree_item = m_index_item_hash[i]; // get related tree item 756 tree_item->setText (2, sc.m_actual_sc.toString ()); // display new shortcut 757 } 758 } 759 760 // ask the user whether to save the current shortcut set; 761 // returns true to proceed with import action, false to abort it overwrite_all_shortcuts(void)762 bool shortcut_manager::overwrite_all_shortcuts (void) 763 { 764 QMessageBox msg_box; 765 msg_box.setWindowTitle (tr ("Overwriting Shortcuts")); 766 msg_box.setIcon (QMessageBox::Warning); 767 msg_box.setText (tr ("You are about to overwrite all shortcuts.\n" 768 "Would you like to save the current shortcut set or cancel the action?")); 769 msg_box.setStandardButtons (QMessageBox::Save | QMessageBox::Cancel); 770 QPushButton *discard = msg_box.addButton (tr ("Don't save"), 771 QMessageBox::DestructiveRole); 772 msg_box.setDefaultButton (QMessageBox::Save); 773 774 int ret = msg_box.exec (); 775 776 if (msg_box.clickedButton () == discard) 777 return true; // do not save and go ahead 778 779 if (ret == QMessageBox::Save) 780 { 781 if (import_export (OSC_EXPORT)) 782 return true; // go ahead 783 } 784 785 return false; // abort the import 786 } 787 } 788