1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 2011-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 <utility> 31 32 #include <QAction> 33 #include <QApplication> 34 #include <QClipboard> 35 #include <QDateTime> 36 #include <QDebug> 37 #include <QDesktopServices> 38 #include <QDesktopWidget> 39 #include <QFileDialog> 40 #include <QIcon> 41 #include <QInputDialog> 42 #include <QKeySequence> 43 #include <QLabel> 44 #include <QMenu> 45 #include <QMenuBar> 46 #include <QMessageBox> 47 #include <QStyle> 48 #include <QStyleFactory> 49 #include <QStyleFactory> 50 #include <QTextBrowser> 51 #include <QTextCodec> 52 #include <QTextStream> 53 #include <QThread> 54 #include <QTimer> 55 #include <QToolBar> 56 57 #if defined (HAVE_QSCINTILLA) 58 # include "file-editor.h" 59 #endif 60 #include "gui-preferences-cs.h" 61 #include "gui-preferences-dw.h" 62 #include "gui-preferences-ed.h" 63 #include "gui-preferences-global.h" 64 #include "gui-preferences-mw.h" 65 #include "gui-preferences-nr.h" 66 #include "gui-preferences-sc.h" 67 #include "gui-settings.h" 68 #include "interpreter-qobject.h" 69 #include "main-window.h" 70 #include "news-reader.h" 71 #include "octave-qobject.h" 72 #include "settings-dialog.h" 73 #include "shortcut-manager.h" 74 #include "welcome-wizard.h" 75 76 #include "Array.h" 77 #include "cmd-edit.h" 78 #include "oct-env.h" 79 #include "url-transfer.h" 80 81 #include "builtin-defun-decls.h" 82 #include "defaults.h" 83 #include "defun.h" 84 #include "interpreter-private.h" 85 #include "interpreter.h" 86 #include "load-path.h" 87 #include "oct-map.h" 88 #include "octave.h" 89 #include "parse.h" 90 #include "syminfo.h" 91 #include "symscope.h" 92 #include "utils.h" 93 #include "version.h" 94 95 namespace octave 96 { 97 static file_editor_interface * create_default_editor(QWidget * p,base_qobject & oct_qobj)98 create_default_editor (QWidget *p, base_qobject& oct_qobj) 99 { 100 #if defined (HAVE_QSCINTILLA) 101 return new file_editor (p, oct_qobj); 102 #else 103 octave_unused_parameter (p); 104 octave_unused_parameter (oct_qobj); 105 106 return 0; 107 #endif 108 } 109 main_window(base_qobject & oct_qobj)110 main_window::main_window (base_qobject& oct_qobj) 111 : QMainWindow (), m_octave_qobj (oct_qobj), 112 m_workspace_model (nullptr), 113 m_status_bar (nullptr), m_command_window (nullptr), 114 m_history_window (nullptr), m_file_browser_window (nullptr), 115 m_doc_browser_window (nullptr), m_editor_window (nullptr), 116 m_workspace_window (nullptr), m_variable_editor_window (nullptr), 117 m_external_editor (new external_editor_interface (this, m_octave_qobj)), 118 m_active_editor (m_external_editor), m_settings_dlg (nullptr), 119 m_find_files_dlg (nullptr), m_set_path_dlg (nullptr), 120 m_release_notes_window (nullptr), m_community_news_window (nullptr), 121 m_clipboard (QApplication::clipboard ()), 122 m_prevent_readline_conflicts (true), m_suppress_dbg_location (true), 123 m_closing (false), m_file_encoding (QString ()) 124 { 125 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 126 127 if (rmgr.is_first_run ()) 128 { 129 // Before wizard. 130 m_octave_qobj.config_translators (); 131 132 welcome_wizard welcomeWizard (m_octave_qobj); 133 134 if (welcomeWizard.exec () == QDialog::Rejected) 135 exit (1); 136 137 // Install settings file. 138 rmgr.reload_settings (); 139 } 140 else 141 { 142 // Get settings file. 143 rmgr.reload_settings (); 144 145 // After settings. 146 m_octave_qobj.config_translators (); 147 } 148 149 rmgr.update_network_settings (); 150 151 // We provide specific terminal capabilities, so ensure that 152 // TERM is always set appropriately. 153 154 #if defined (OCTAVE_USE_WINDOWS_API) 155 sys::env::putenv ("TERM", "cygwin"); 156 #else 157 sys::env::putenv ("TERM", "xterm"); 158 #endif 159 160 // FIXME: can we do this job when creating the shortcut manager? 161 // A quick look shows that it may require some coordination with the 162 // resource manager. Startup is complicated, but maybe we can make 163 // it simpler? 164 shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); 165 scmgr.init_data (); 166 167 construct_central_widget (); 168 169 m_workspace_model = new workspace_model (m_octave_qobj); 170 m_status_bar = new QStatusBar (); 171 m_command_window = new terminal_dock_widget (this, m_octave_qobj); 172 m_history_window = new history_dock_widget (this, m_octave_qobj); 173 m_file_browser_window = new files_dock_widget (this, m_octave_qobj); 174 m_doc_browser_window = new documentation_dock_widget (this, m_octave_qobj); 175 m_editor_window = create_default_editor (this, m_octave_qobj); 176 m_variable_editor_window = new variable_editor (this, m_octave_qobj); 177 m_workspace_window = new workspace_view (this, m_octave_qobj); 178 179 m_previous_dock = m_command_window; 180 181 // Set active editor depending on editor window. If the latter is 182 // not initialized (qscintilla not present), use the external editor. 183 if (m_editor_window) 184 m_active_editor = m_editor_window; 185 else 186 m_active_editor = m_external_editor; 187 188 #if defined (HAVE_QGUIAPPLICATION_SETDESKTOPFILENAME) 189 QGuiApplication::setDesktopFileName ("org.octave.Octave.desktop"); 190 #endif 191 192 QApplication *qapp = m_octave_qobj.qapplication (); 193 194 m_default_style = qapp->style ()->objectName (); 195 196 gui_settings *settings = rmgr.get_settings (); 197 198 bool connect_to_web = true; 199 QDateTime last_checked; 200 int serial = 0; 201 m_active_dock = nullptr; 202 203 if (settings) 204 { 205 connect_to_web 206 = settings->value (nr_allow_connection).toBool (); 207 208 last_checked 209 = settings->value (nr_last_time).toDateTime (); 210 211 serial = settings->value (nr_last_news).toInt (); 212 m_default_encoding = settings->value (ed_default_enc).toString (); 213 } 214 215 QDateTime current = QDateTime::currentDateTime (); 216 QDateTime one_day_ago = current.addDays (-1); 217 218 if (connect_to_web 219 && (! last_checked.isValid () || one_day_ago > last_checked)) 220 load_and_display_community_news (serial); 221 222 construct_octave_qt_link (); 223 224 // We have to set up all our windows, before we finally launch 225 // octave. 226 227 construct (); 228 229 read_settings (); 230 231 init_terminal_size (); 232 233 // Connect signals for changes in visibility now before window is 234 // shown. 235 236 connect_visibility_changed (); 237 238 focus_command_window (); 239 } 240 ~main_window(void)241 main_window::~main_window (void) 242 { 243 // Destroy the terminal first so that STDERR stream is redirected back 244 // to its original pipe to capture error messages at exit. 245 246 delete m_editor_window; // first one for dialogs of modified editor-tabs 247 delete m_external_editor; 248 delete m_command_window; 249 delete m_workspace_window; 250 delete m_doc_browser_window; 251 delete m_file_browser_window; 252 delete m_history_window; 253 delete m_status_bar; 254 delete m_workspace_model; 255 delete m_variable_editor_window; 256 257 delete m_find_files_dlg; 258 delete m_release_notes_window; 259 delete m_community_news_window; 260 } 261 command_window_has_focus(void) const262 bool main_window::command_window_has_focus (void) const 263 { 264 return m_command_window->has_focus (); 265 } 266 focus_command_window(void)267 void main_window::focus_command_window (void) 268 { 269 m_command_window->activate (); 270 } 271 focus_window(const QString & win_name)272 void main_window::focus_window (const QString& win_name) 273 { 274 if (win_name == "command") 275 m_command_window->activate (); 276 else if (win_name == "history") 277 m_history_window->activate (); 278 else if (win_name == "workspace") 279 m_workspace_window->activate (); 280 else if (win_name == "filebrowser") 281 m_file_browser_window->activate (); 282 } 283 confirm_shutdown(void)284 bool main_window::confirm_shutdown (void) 285 { 286 bool closenow = true; 287 288 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 289 gui_settings *settings = rmgr.get_settings (); 290 291 if (settings->value (global_prompt_to_exit.key, 292 global_prompt_to_exit.def).toBool ()) 293 { 294 int ans = QMessageBox::question (this, tr ("Octave"), 295 tr ("Are you sure you want to exit Octave?"), 296 (QMessageBox::Ok 297 | QMessageBox::Cancel), 298 QMessageBox::Ok); 299 300 if (ans != QMessageBox::Ok) 301 closenow = false; 302 } 303 304 #if defined (HAVE_QSCINTILLA) 305 if (closenow) 306 closenow = m_editor_window->check_closing (); 307 #endif 308 309 return closenow; 310 } 311 312 // catch focus changes and determine the active dock widget focus_changed(QWidget *,QWidget * new_widget)313 void main_window::focus_changed (QWidget *, QWidget *new_widget) 314 { 315 // If there is no new widget (e.g., when pressing <alt> and the global 316 // menu gets active), we can return immediately 317 if (! new_widget) 318 return; 319 320 octave_dock_widget *dock = nullptr; 321 QWidget *w_new = new_widget; // get a copy of new focus widget 322 QWidget *start = w_new; // Save it as start of our search 323 int count = 0; // fallback to prevent endless loop 324 325 QList<octave_dock_widget *> w_list = dock_widget_list (); 326 327 while (w_new && w_new != m_main_tool_bar && count < 100) 328 { 329 // Go through all dock widgets and check whether the current widget 330 // with focus is a child of one of them. 331 for (auto w : w_list) 332 { 333 if (w->isAncestorOf (w_new)) 334 dock = w; 335 } 336 337 if (dock) 338 break; 339 340 // If not yet found (in case w_new is not a child of its dock widget), 341 // test next widget in the focus chain 342 w_new = qobject_cast<QWidget *> (w_new->previousInFocusChain ()); 343 344 // Measures preventing an endless loop 345 if (w_new == start) 346 break; // We have arrived where we began ==> exit loop 347 count++; // Limited number of trials 348 } 349 350 // editor needs extra handling 351 octave_dock_widget *edit_dock_widget 352 = static_cast<octave_dock_widget *> (m_editor_window); 353 // if new dock has focus, emit signal and store active focus 354 // except editor changes to a dialog (dock=0) 355 if ((dock || m_active_dock != edit_dock_widget) && (dock != m_active_dock)) 356 { 357 // signal to all dock widgets for updating the style 358 emit active_dock_changed (m_active_dock, dock); 359 360 if (dock) 361 { 362 QList<QDockWidget *> tabbed = tabifiedDockWidgets (dock); 363 if (tabbed.contains (m_active_dock)) 364 dock->set_predecessor_widget (m_active_dock); 365 } 366 367 if (edit_dock_widget == dock) 368 emit editor_focus_changed (true); 369 else if (edit_dock_widget == m_active_dock) 370 emit editor_focus_changed (false); 371 372 if (m_active_dock) 373 m_previous_dock = m_active_dock; 374 m_active_dock = dock; 375 } 376 } 377 request_reload_settings(void)378 void main_window::request_reload_settings (void) 379 { 380 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 381 gui_settings *settings = rmgr.get_settings (); 382 383 if (settings) 384 emit settings_changed (settings); 385 } 386 report_status_message(const QString & statusMessage)387 void main_window::report_status_message (const QString& statusMessage) 388 { 389 m_status_bar->showMessage (statusMessage, 1000); 390 } 391 handle_save_workspace_request(void)392 void main_window::handle_save_workspace_request (void) 393 { 394 // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved. 395 int opts = 0; // No options by default. 396 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 397 gui_settings *settings = rmgr.get_settings (); 398 if (! settings->value (global_use_native_dialogs).toBool ()) 399 opts = QFileDialog::DontUseNativeDialog; 400 401 QString file 402 = QFileDialog::getSaveFileName (this, tr ("Save Workspace As"), ".", 403 nullptr, nullptr, QFileDialog::Option (opts)); 404 405 if (! file.isEmpty ()) 406 { 407 emit interpreter_event 408 ([file] (interpreter& interp) 409 { 410 // INTERPRETER THREAD 411 412 Fsave (interp, ovl (file.toStdString ())); 413 }); 414 } 415 } 416 handle_load_workspace_request(const QString & file_arg)417 void main_window::handle_load_workspace_request (const QString& file_arg) 418 { 419 // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved. 420 int opts = 0; // No options by default. 421 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 422 gui_settings *settings = rmgr.get_settings (); 423 if (! settings->value (global_use_native_dialogs).toBool ()) 424 opts = QFileDialog::DontUseNativeDialog; 425 426 QString file = file_arg; 427 428 if (file.isEmpty ()) 429 file = QFileDialog::getOpenFileName (this, tr ("Load Workspace"), ".", 430 nullptr, nullptr, QFileDialog::Option (opts)); 431 432 if (! file.isEmpty ()) 433 { 434 emit interpreter_event 435 ([file] (interpreter& interp) 436 { 437 // INTERPRETER THREAD 438 439 Fload (interp, ovl (file.toStdString ())); 440 441 tree_evaluator& tw = interp.get_evaluator (); 442 443 event_manager& xevmgr = interp.get_event_manager (); 444 445 xevmgr.set_workspace (true, tw.get_symbol_info ()); 446 }); 447 } 448 } 449 handle_open_any_request(const QString & file_arg)450 void main_window::handle_open_any_request (const QString& file_arg) 451 { 452 if (! file_arg.isEmpty ()) 453 { 454 std::string file = file_arg.toStdString (); 455 456 emit interpreter_event 457 ([file] (interpreter& interp) 458 { 459 // INTERPRETER THREAD 460 461 interp.feval ("open", ovl (file)); 462 463 // Update the workspace since open.m may have loaded new 464 // variables. 465 tree_evaluator& tw = interp.get_evaluator (); 466 467 event_manager& xevmgr = interp.get_event_manager (); 468 469 xevmgr.set_workspace (true, tw.get_symbol_info ()); 470 }); 471 } 472 } 473 handle_clear_workspace_request(void)474 void main_window::handle_clear_workspace_request (void) 475 { 476 emit interpreter_event 477 ([] (interpreter& interp) 478 { 479 // INTERPRETER THREAD 480 481 Fclear (interp); 482 }); 483 } 484 handle_clear_command_window_request(void)485 void main_window::handle_clear_command_window_request (void) 486 { 487 emit interpreter_event 488 ([] (void) 489 { 490 // INTERPRETER THREAD 491 492 command_editor::kill_full_line (); 493 command_editor::clear_screen (); 494 }); 495 } 496 handle_clear_history_request(void)497 void main_window::handle_clear_history_request (void) 498 { 499 emit interpreter_event 500 ([] (interpreter& interp) 501 { 502 // INTERPRETER THREAD 503 504 history_system& history_sys = interp.get_history_system (); 505 506 history_sys.do_history (ovl ("-c")); 507 }); 508 } 509 handle_undo_request(void)510 void main_window::handle_undo_request (void) 511 { 512 if (command_window_has_focus ()) 513 { 514 emit interpreter_event 515 ([] (void) 516 { 517 // INTERPRETER THREAD 518 519 command_editor::undo (); 520 command_editor::redisplay (); 521 }); 522 } 523 else 524 emit undo_signal (); 525 } 526 handle_rename_variable_request(const QString & old_name_arg,const QString & new_name_arg)527 void main_window::handle_rename_variable_request (const QString& old_name_arg, 528 const QString& new_name_arg) 529 530 { 531 std::string old_name = old_name_arg.toStdString (); 532 std::string new_name = new_name_arg.toStdString (); 533 534 emit interpreter_event 535 ([old_name, new_name] (interpreter& interp) 536 { 537 // INTERPRETER THREAD 538 539 symbol_scope scope = interp.get_current_scope (); 540 541 if (scope) 542 { 543 scope.rename (old_name, new_name); 544 545 tree_evaluator& tw = interp.get_evaluator (); 546 547 event_manager& xevmgr = interp.get_event_manager (); 548 549 xevmgr.set_workspace (true, tw.get_symbol_info ()); 550 } 551 552 // FIXME: if this action fails, do we need a way to display that info 553 // in the GUI? 554 }); 555 } 556 modify_path(const octave_value_list & dir_list,bool rm,bool subdirs)557 void main_window::modify_path (const octave_value_list& dir_list, 558 bool rm, bool subdirs) 559 { 560 emit interpreter_event 561 ([dir_list, rm, subdirs, this] (interpreter& interp) 562 { 563 // INTERPRETER THREAD 564 565 octave_value_list paths = ovl (); 566 567 if (subdirs) 568 { 569 // Loop over all directories in order to get all subdirs 570 for (octave_idx_type i = 0; i < dir_list.length (); i++) 571 paths.append (Fgenpath (dir_list(i))); 572 } 573 else 574 paths = dir_list; 575 576 if (rm) 577 Frmpath (interp, paths); 578 else 579 Faddpath (interp, paths); 580 }); 581 } 582 new_file(const QString & commands)583 void main_window::new_file (const QString& commands) 584 { 585 emit new_file_signal (commands); 586 } 587 open_file(const QString & file_name,int line)588 void main_window::open_file (const QString& file_name, int line) 589 { 590 if (line < 0) 591 emit open_file_signal (file_name); 592 else 593 emit open_file_signal (file_name, QString (), line); 594 } 595 edit_mfile(const QString & name,int line)596 void main_window::edit_mfile (const QString& name, int line) 597 { 598 handle_edit_mfile_request (name, QString (), QString (), line); 599 } 600 file_remove_proxy(const QString & o,const QString & n)601 void main_window::file_remove_proxy (const QString& o, const QString& n) 602 { 603 interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj (); 604 605 qt_interpreter_events *qt_link = interp_qobj->qt_link (); 606 607 // Wait for worker to suspend 608 qt_link->lock (); 609 610 // Close the file if opened 611 #if defined (HAVE_QSCINTILLA) 612 m_editor_window->handle_file_remove (o, n); 613 #else 614 octave_unused_parameter (o); 615 octave_unused_parameter (n); 616 #endif 617 618 // We are done: Unlock and wake the worker thread 619 qt_link->unlock (); 620 qt_link->wake_all (); 621 } 622 open_online_documentation_page(void)623 void main_window::open_online_documentation_page (void) 624 { 625 QDesktopServices::openUrl 626 (QUrl ("https://octave.org/doc/interpreter/index.html")); 627 } 628 display_release_notes(void)629 void main_window::display_release_notes (void) 630 { 631 if (! m_release_notes_window) 632 { 633 std::string news_file = config::oct_etc_dir () + "/NEWS"; 634 635 QString news; 636 637 QFile *file = new QFile (QString::fromStdString (news_file)); 638 if (file->open (QFile::ReadOnly)) 639 { 640 QTextStream *stream = new QTextStream (file); 641 news = stream->readAll (); 642 if (! news.isEmpty ()) 643 { 644 // Convert '<', '>' which would be interpreted as HTML 645 news.replace ("<", "<"); 646 news.replace (">", ">"); 647 // Add HTML tags for pre-formatted text 648 news.prepend ("<pre>"); 649 news.append ("</pre>"); 650 } 651 else 652 news = (tr ("The release notes file '%1' is empty.") 653 . arg (QString::fromStdString (news_file))); 654 } 655 else 656 news = (tr ("The release notes file '%1' cannot be read.") 657 . arg (QString::fromStdString (news_file))); 658 659 m_release_notes_window = new QWidget; 660 661 QTextBrowser *browser = new QTextBrowser (m_release_notes_window); 662 browser->setText (news); 663 664 QVBoxLayout *vlayout = new QVBoxLayout; 665 vlayout->addWidget (browser); 666 667 m_release_notes_window->setLayout (vlayout); 668 m_release_notes_window->setWindowTitle (tr ("Octave Release Notes")); 669 670 browser->document ()->adjustSize (); 671 672 int win_x, win_y; 673 get_screen_geometry (&win_x, &win_y); 674 675 m_release_notes_window->resize (win_x*2/5, win_y*2/3); 676 m_release_notes_window->move (20, 20); // move to the top left corner 677 } 678 679 if (! m_release_notes_window->isVisible ()) 680 m_release_notes_window->show (); 681 else if (m_release_notes_window->isMinimized ()) 682 m_release_notes_window->showNormal (); 683 684 m_release_notes_window->setWindowIcon (QIcon (m_release_notes_icon)); 685 686 m_release_notes_window->raise (); 687 m_release_notes_window->activateWindow (); 688 } 689 load_and_display_community_news(int serial)690 void main_window::load_and_display_community_news (int serial) 691 { 692 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 693 gui_settings *settings = rmgr.get_settings (); 694 695 bool connect_to_web 696 = (settings 697 ? settings->value (nr_allow_connection).toBool () 698 : true); 699 700 QString base_url = "https://octave.org"; 701 QString page = "community-news.html"; 702 703 QThread *worker_thread = new QThread; 704 705 news_reader *reader = new news_reader (m_octave_qobj, base_url, page, 706 serial, connect_to_web); 707 708 reader->moveToThread (worker_thread); 709 710 connect (reader, SIGNAL (display_news_signal (const QString&)), 711 this, SLOT (display_community_news (const QString&))); 712 713 connect (worker_thread, SIGNAL (started (void)), 714 reader, SLOT (process (void))); 715 716 connect (reader, SIGNAL (finished (void)), worker_thread, SLOT (quit (void))); 717 718 connect (reader, SIGNAL (finished (void)), reader, SLOT (deleteLater (void))); 719 720 connect (worker_thread, SIGNAL (finished (void)), 721 worker_thread, SLOT (deleteLater (void))); 722 723 worker_thread->start (); 724 } 725 display_community_news(const QString & news)726 void main_window::display_community_news (const QString& news) 727 { 728 if (! m_community_news_window) 729 { 730 m_community_news_window = new QWidget; 731 732 QTextBrowser *browser = new QTextBrowser (m_community_news_window); 733 734 browser->setHtml (news); 735 browser->setObjectName ("OctaveNews"); 736 browser->setOpenExternalLinks (true); 737 738 QVBoxLayout *vlayout = new QVBoxLayout; 739 740 vlayout->addWidget (browser); 741 742 m_community_news_window->setLayout (vlayout); 743 m_community_news_window->setWindowTitle (tr ("Octave Community News")); 744 745 int win_x, win_y; 746 get_screen_geometry (&win_x, &win_y); 747 748 m_community_news_window->resize (win_x/2, win_y/2); 749 m_community_news_window->move ((win_x - m_community_news_window->width ())/2, 750 (win_y - m_community_news_window->height ())/2); 751 } 752 else 753 { 754 // Window already exists, just update the browser contents 755 QTextBrowser *browser 756 757 = m_community_news_window->findChild<QTextBrowser *>("OctaveNews" 758 #if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS) 759 , Qt::FindDirectChildrenOnly 760 #endif 761 ); 762 if (browser) 763 browser->setHtml (news); 764 } 765 766 if (! m_community_news_window->isVisible ()) 767 m_community_news_window->show (); 768 else if (m_community_news_window->isMinimized ()) 769 m_community_news_window->showNormal (); 770 771 // same icon as release notes 772 m_community_news_window->setWindowIcon (QIcon (m_release_notes_icon)); 773 774 m_community_news_window->raise (); 775 m_community_news_window->activateWindow (); 776 } 777 open_bug_tracker_page(void)778 void main_window::open_bug_tracker_page (void) 779 { 780 QDesktopServices::openUrl (QUrl ("https://octave.org/bugs.html")); 781 } 782 open_octave_packages_page(void)783 void main_window::open_octave_packages_page (void) 784 { 785 QDesktopServices::openUrl (QUrl ("https://octave.org/packages.html")); 786 } 787 open_contribute_page(void)788 void main_window::open_contribute_page (void) 789 { 790 QDesktopServices::openUrl (QUrl ("https://octave.org/contribute.html")); 791 } 792 open_donate_page(void)793 void main_window::open_donate_page (void) 794 { 795 QDesktopServices::openUrl (QUrl ("https://octave.org/donate.html")); 796 } 797 process_settings_dialog_request(const QString & desired_tab)798 void main_window::process_settings_dialog_request (const QString& desired_tab) 799 { 800 if (m_settings_dlg) // m_settings_dlg is a guarded pointer! 801 { 802 // here the dialog is still open and called once again 803 if (! desired_tab.isEmpty ()) 804 m_settings_dlg->show_tab (desired_tab); 805 return; 806 } 807 808 m_settings_dlg = new settings_dialog (this, m_octave_qobj, desired_tab); 809 810 connect (m_settings_dlg, SIGNAL (apply_new_settings (void)), 811 this, SLOT (request_reload_settings (void))); 812 813 m_settings_dlg->setModal (false); 814 m_settings_dlg->setAttribute (Qt::WA_DeleteOnClose); 815 m_settings_dlg->show (); 816 } 817 show_about_octave(void)818 void main_window::show_about_octave (void) 819 { 820 std::string message 821 = octave_name_version_copyright_copying_warranty_and_bugs (true); 822 823 QMessageBox::about (this, tr ("About Octave"), 824 QString::fromStdString (message)); 825 } 826 notice_settings(const gui_settings * settings,bool update_by_worker)827 void main_window::notice_settings (const gui_settings *settings, 828 bool update_by_worker) 829 { 830 if (! settings) 831 return; 832 833 // Get desired style from preferences or take the default one if 834 // the desired one is not found 835 QString preferred_style = settings->value (global_style).toString (); 836 837 if (preferred_style == global_style.def.toString ()) 838 preferred_style = m_default_style; 839 840 QStyle *new_style = QStyleFactory::create (preferred_style); 841 if (new_style) 842 { 843 QApplication *qapp = m_octave_qobj.qapplication (); 844 845 qapp->setStyle (new_style); 846 } 847 848 // the widget's icons (when floating) 849 QString icon_set 850 = settings->value (dw_icon_set).toString (); 851 852 int count = 0; 853 int icon_set_found = 0; // default 854 855 while (! dw_icon_set_names[count].name.isEmpty ()) 856 { 857 // while not end of data 858 if (dw_icon_set_names[count].name == icon_set) 859 { 860 // data of desired icon set found 861 icon_set_found = count; 862 break; 863 } 864 count++; 865 } 866 867 QString icon; 868 for (auto *widget : dock_widget_list ()) 869 { 870 QString name = widget->objectName (); 871 if (! name.isEmpty ()) 872 { 873 // if child has a name 874 icon = dw_icon_set_names[icon_set_found].path; // prefix | octave-logo 875 if (dw_icon_set_names[icon_set_found].name != "NONE") 876 icon += name + ".png"; // add widget name and ext. 877 widget->setWindowIcon (QIcon (icon)); 878 } 879 } 880 if (dw_icon_set_names[icon_set_found].name != "NONE") 881 m_release_notes_icon = dw_icon_set_names[icon_set_found].path 882 + "ReleaseWidget.png"; 883 else 884 m_release_notes_icon = ":/actions/icons/logo.png"; 885 886 int size_idx = settings->value (global_icon_size).toInt (); 887 size_idx = (size_idx > 0) - (size_idx < 0) + 1; // Make valid index from 0 to 2 888 889 QStyle *st = style (); 890 int icon_size = st->pixelMetric (global_icon_sizes[size_idx]); 891 m_main_tool_bar->setIconSize (QSize (icon_size,icon_size)); 892 893 if (settings->value (global_status_bar.key, global_status_bar.def).toBool ()) 894 m_status_bar->show (); 895 else 896 m_status_bar->hide (); 897 898 m_prevent_readline_conflicts 899 = settings->value (sc_prevent_rl_conflicts.key, 900 sc_prevent_rl_conflicts.def).toBool (); 901 902 m_suppress_dbg_location 903 = ! settings->value (cs_dbg_location).toBool (); 904 905 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 906 rmgr.update_network_settings (); 907 908 emit active_dock_changed (nullptr, m_active_dock); // update dock widget styles 909 910 configure_shortcuts (); 911 set_global_shortcuts (m_active_dock == m_command_window); 912 disable_menu_shortcuts (m_active_dock == m_editor_window); 913 914 // Check whether some octave internal preferences have to be updated 915 QString new_default_encoding 916 = settings->value (ed_default_enc).toString (); 917 // Do not update internal pref only if a) this update was not initiated 918 // by the worker and b) the pref has really changes 919 if (! update_by_worker && (new_default_encoding != m_default_encoding)) 920 update_default_encoding (new_default_encoding); 921 922 // Set cursor blinking depending on the settings 923 // Cursor blinking: consider old terminal related setting if not yet set 924 // TODO: This pref. can be deprecated / removed if Qt adds support for 925 // getting the cursor blink preferences from all OS environments 926 bool cursor_blinking; 927 928 if (settings->contains (global_cursor_blinking.key)) 929 cursor_blinking = settings->value (global_cursor_blinking).toBool (); 930 else 931 cursor_blinking = settings->value (cs_cursor_blinking).toBool (); 932 933 if (cursor_blinking) 934 QApplication::setCursorFlashTime (1000); // 1000 ms flash time 935 else 936 QApplication::setCursorFlashTime (0); // no flashing 937 938 } 939 prepare_to_exit(void)940 void main_window::prepare_to_exit (void) 941 { 942 // Find files dialog is constructed dynamically, not at time of main_window 943 // construction. Connecting it to qApp aboutToQuit signal would have 944 // caused it to run after gui_settings is deleted. 945 if (m_find_files_dlg) 946 m_find_files_dlg->save_settings (); 947 948 if (m_set_path_dlg) 949 m_set_path_dlg->save_settings (); 950 951 write_settings (); 952 } 953 go_to_previous_widget(void)954 void main_window::go_to_previous_widget (void) 955 { 956 m_previous_dock->activate (); 957 } 958 update_octave_directory(const QString & dir)959 void main_window::update_octave_directory (const QString& dir) 960 { 961 // Remove existing entry, if any, then add new directory at top and 962 // mark it as the current directory. Finally, update the file list 963 // widget. 964 965 int index = m_current_directory_combo_box->findText (dir); 966 967 if (index >= 0) 968 m_current_directory_combo_box->removeItem (index); 969 970 m_current_directory_combo_box->insertItem (0, dir); 971 m_current_directory_combo_box->setCurrentIndex (0); 972 } 973 browse_for_directory(void)974 void main_window::browse_for_directory (void) 975 { 976 // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved. 977 int opts = QFileDialog::ShowDirsOnly; 978 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 979 gui_settings *settings = rmgr.get_settings (); 980 if (! settings->value (global_use_native_dialogs).toBool ()) 981 opts = QFileDialog::DontUseNativeDialog; 982 983 QString dir 984 = QFileDialog::getExistingDirectory (this, tr ("Browse directories"), nullptr, 985 QFileDialog::Option (opts)); 986 987 set_current_working_directory (dir); 988 989 // FIXME: on Windows systems, the command window freezes after the 990 // previous actions. Forcing the focus appears to unstick it. 991 992 focus_command_window (); 993 } 994 set_current_working_directory(const QString & dir)995 void main_window::set_current_working_directory (const QString& dir) 996 { 997 // Change to dir if it is an existing directory. 998 999 QString xdir = (dir.isEmpty () ? "." : dir); 1000 1001 QFileInfo fileInfo (xdir); 1002 1003 if (fileInfo.exists () && fileInfo.isDir ()) 1004 { 1005 emit interpreter_event 1006 ([xdir] (interpreter& interp) 1007 { 1008 // INTERPRETER THREAD 1009 1010 interp.chdir (xdir.toStdString ()); 1011 }); 1012 } 1013 } 1014 change_directory_up(void)1015 void main_window::change_directory_up (void) 1016 { 1017 set_current_working_directory (".."); 1018 } 1019 1020 // Slot that is called if return is pressed in the line edit of the 1021 // combobox to change to a new directory or a directory that is already 1022 // in the drop down list. 1023 accept_directory_line_edit(void)1024 void main_window::accept_directory_line_edit (void) 1025 { 1026 // Get new directory name, and change to it if it is new. Otherwise, 1027 // the combo box will trigger the "activated" signal to change to the 1028 // directory. 1029 1030 QString dir = m_current_directory_combo_box->currentText (); 1031 1032 int index = m_current_directory_combo_box->findText (dir); 1033 1034 if (index < 0) 1035 set_current_working_directory (dir); 1036 } 1037 execute_command_in_terminal(const QString & command)1038 void main_window::execute_command_in_terminal (const QString& command) 1039 { 1040 emit interpreter_event 1041 ([command] (void) 1042 { 1043 // INTERPRETER THREAD 1044 1045 std::string pending_input = command_editor::get_current_line (); 1046 1047 command_editor::set_initial_input (pending_input); 1048 command_editor::replace_line (command.toStdString ()); 1049 command_editor::redisplay (); 1050 command_editor::interrupt_event_loop (); 1051 command_editor::accept_line (); 1052 }); 1053 1054 focus_console_after_command (); 1055 } 1056 run_file_in_terminal(const QFileInfo & info)1057 void main_window::run_file_in_terminal (const QFileInfo& info) 1058 { 1059 emit interpreter_event 1060 ([info] (interpreter& interp) 1061 { 1062 // INTERPRETER THREAD 1063 1064 QString function_name = info.fileName (); 1065 function_name.chop (info.suffix ().length () + 1); 1066 std::string file_path = info.absoluteFilePath ().toStdString (); 1067 1068 std::string pending_input = command_editor::get_current_line (); 1069 1070 if (valid_identifier (function_name.toStdString ())) 1071 { 1072 // Valid identifier: call as function with possibility to 1073 // debug. 1074 1075 load_path& lp = interp.get_load_path (); 1076 1077 std::string path = info.absolutePath ().toStdString (); 1078 1079 if (lp.contains_file_in_dir (file_path, path)) 1080 command_editor::replace_line (function_name.toStdString ()); 1081 } 1082 else 1083 { 1084 // No valid identifier: use equivalent of Fsource (), no 1085 // debug possible. 1086 1087 interp.source_file (file_path); 1088 1089 command_editor::replace_line (""); 1090 } 1091 1092 command_editor::set_initial_input (pending_input); 1093 command_editor::redisplay (); 1094 command_editor::interrupt_event_loop (); 1095 command_editor::accept_line (); 1096 }); 1097 1098 focus_console_after_command (); 1099 } 1100 handle_new_figure_request(void)1101 void main_window::handle_new_figure_request (void) 1102 { 1103 emit interpreter_event 1104 ([] (interpreter& interp) 1105 { 1106 // INTERPRETER THREAD 1107 1108 Fbuiltin (interp, ovl ("figure")); 1109 Fdrawnow (interp); 1110 }); 1111 } 1112 handle_enter_debugger(void)1113 void main_window::handle_enter_debugger (void) 1114 { 1115 setWindowTitle ("Octave (Debugging)"); 1116 1117 m_debug_continue->setEnabled (true); 1118 m_debug_step_into->setEnabled (true); 1119 m_debug_step_over->setEnabled (true); 1120 m_debug_step_out->setEnabled (true); 1121 m_debug_quit->setEnabled (true); 1122 1123 #if defined (HAVE_QSCINTILLA) 1124 m_editor_window->handle_enter_debug_mode (); 1125 #endif 1126 } 1127 handle_exit_debugger(void)1128 void main_window::handle_exit_debugger (void) 1129 { 1130 setWindowTitle ("Octave"); 1131 1132 m_debug_continue->setEnabled (false); 1133 m_debug_step_into->setEnabled (false); 1134 m_debug_step_over->setEnabled (m_editor_has_tabs); 1135 m_debug_step_out->setEnabled (false); 1136 m_debug_quit->setEnabled (false); 1137 1138 #if defined (HAVE_QSCINTILLA) 1139 m_editor_window->handle_exit_debug_mode (); 1140 #endif 1141 } 1142 debug_continue(void)1143 void main_window::debug_continue (void) 1144 { 1145 emit interpreter_event 1146 ([this] (interpreter& interp) 1147 { 1148 // INTERPRETER THREAD 1149 1150 F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location)); 1151 Fdbcont (interp); 1152 1153 command_editor::interrupt (true); 1154 }); 1155 } 1156 debug_step_into(void)1157 void main_window::debug_step_into (void) 1158 { 1159 emit interpreter_event 1160 ([this] (interpreter& interp) 1161 { 1162 // INTERPRETER THREAD 1163 1164 F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location)); 1165 Fdbstep (interp, ovl ("in")); 1166 1167 command_editor::interrupt (true); 1168 }); 1169 } 1170 debug_step_over(void)1171 void main_window::debug_step_over (void) 1172 { 1173 if (m_debug_quit->isEnabled ()) 1174 { 1175 // We are in debug mode, just call dbstep. 1176 1177 emit interpreter_event 1178 ([this] (interpreter& interp) 1179 { 1180 // INTERPRETER THREAD 1181 1182 F__db_next_breakpoint_quiet__ (interp, 1183 ovl (m_suppress_dbg_location)); 1184 Fdbstep (interp); 1185 1186 command_editor::interrupt (true); 1187 }); 1188 } 1189 else 1190 { 1191 // Not in debug mode: "step into" the current editor file 1192 emit step_into_file_signal (); 1193 } 1194 } 1195 debug_step_out(void)1196 void main_window::debug_step_out (void) 1197 { 1198 emit interpreter_event 1199 ([this] (interpreter& interp) 1200 { 1201 // INTERPRETER THREAD 1202 1203 F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location)); 1204 Fdbstep (interp, ovl ("out")); 1205 1206 command_editor::interrupt (true); 1207 }); 1208 } 1209 debug_quit(void)1210 void main_window::debug_quit (void) 1211 { 1212 emit interpreter_event 1213 ([] (interpreter& interp) 1214 { 1215 // INTERPRETER THREAD 1216 1217 Fdbquit (interp); 1218 1219 command_editor::interrupt (true); 1220 }); 1221 } 1222 1223 // 1224 // Functions related to file editing 1225 // 1226 // These are moved from editor to here for also using them when octave 1227 // is built without qscintilla 1228 // request_open_file(void)1229 void main_window::request_open_file (void) 1230 { 1231 // Open file isn't a file_editor_tab or editor function since the file 1232 // might be opened in an external editor. Hence, functionality is here. 1233 1234 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 1235 gui_settings *settings = rmgr.get_settings (); 1236 bool is_internal = m_editor_window 1237 && ! settings->value (global_use_custom_editor.key, 1238 global_use_custom_editor.def).toBool (); 1239 1240 // Create a NonModal message. 1241 QWidget *p = this; 1242 if (is_internal) 1243 p = m_editor_window; 1244 QFileDialog *fileDialog = new QFileDialog (p); 1245 fileDialog->setNameFilter (tr ("Octave Files (*.m);;All Files (*)")); 1246 1247 fileDialog->setAcceptMode (QFileDialog::AcceptOpen); 1248 fileDialog->setViewMode (QFileDialog::Detail); 1249 fileDialog->setFileMode (QFileDialog::ExistingFiles); 1250 fileDialog->setDirectory (m_current_directory_combo_box->itemText (0)); 1251 1252 // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved. 1253 if (! settings->value (global_use_native_dialogs).toBool ()) 1254 fileDialog->setOption(QFileDialog::DontUseNativeDialog); 1255 1256 connect (fileDialog, SIGNAL (filesSelected (const QStringList&)), 1257 this, SLOT (request_open_files (const QStringList&))); 1258 1259 fileDialog->setWindowModality (Qt::NonModal); 1260 fileDialog->setAttribute (Qt::WA_DeleteOnClose); 1261 fileDialog->show (); 1262 } 1263 1264 // Create a new script request_new_script(const QString & commands)1265 void main_window::request_new_script (const QString& commands) 1266 { 1267 emit new_file_signal (commands); 1268 } 1269 1270 // Create a new function and open it request_new_function(bool)1271 void main_window::request_new_function (bool) 1272 { 1273 bool ok; 1274 // Get the name of the new function: Parent of the input dialog is the 1275 // editor window or the main window. The latter is chosen, if a custom 1276 // editor is used or qscintilla is not available 1277 QWidget *p = m_editor_window; 1278 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 1279 gui_settings *settings = rmgr.get_settings (); 1280 if (! p || settings->value (global_use_custom_editor.key, 1281 global_use_custom_editor.def).toBool ()) 1282 p = this; 1283 QString new_name = QInputDialog::getText (p, tr ("New Function"), 1284 tr ("New function name:\n"), QLineEdit::Normal, "", &ok); 1285 1286 if (ok && new_name.length () > 0) 1287 { 1288 // append suffix if it does not already exist 1289 if (new_name.rightRef (2) != ".m") 1290 new_name.append (".m"); 1291 // check whether new files are created without prompt 1292 if (! settings->value (ed_create_new_file).toBool ()) 1293 { 1294 // no, so enable this settings and wait for end of new file loading 1295 settings->setValue (ed_create_new_file.key, true); 1296 connect (m_editor_window, SIGNAL (file_loaded_signal (void)), 1297 this, SLOT (restore_create_file_setting (void))); 1298 } 1299 // start the edit command 1300 execute_command_in_terminal ("edit " + new_name); 1301 } 1302 } 1303 handle_edit_mfile_request(const QString & fname,const QString & ffile,const QString & curr_dir,int line)1304 void main_window::handle_edit_mfile_request (const QString& fname, 1305 const QString& ffile, 1306 const QString& curr_dir, 1307 int line) 1308 { 1309 emit interpreter_event 1310 ([this, fname, ffile, curr_dir, line] (interpreter& interp) 1311 { 1312 // INTERPRETER THREAD 1313 1314 // Split possible subfunctions 1315 QStringList fcn_list = fname.split ('>'); 1316 QString fcn_name = fcn_list.at (0) + ".m"; 1317 1318 // FIXME: could use symbol_exist directly, but we may also want 1319 // to fix that to be a member function in the interpreter 1320 // class? 1321 1322 // Is it a regular function within the search path? (Call Fexist) 1323 octave_value_list fct = Fexist (interp, ovl (fname.toStdString ()),0); 1324 int type = fct (0).int_value (); 1325 1326 QString message = QString (); 1327 QString filename = QString (); 1328 1329 switch (type) 1330 { 1331 case 3: 1332 case 5: 1333 case 103: 1334 message = tr ("%1 is a built-in, compiled or inline\n" 1335 "function and can not be edited."); 1336 break; 1337 1338 case 2: 1339 // FIXME: could use a load_path function directly. 1340 octave_value_list file_path 1341 = Ffile_in_loadpath (interp, ovl (fcn_name.toStdString ()), 0); 1342 if (file_path.length () > 0) 1343 filename = QString::fromStdString (file_path (0).string_value ()); 1344 break; 1345 } 1346 1347 if (filename.isEmpty () && message.isEmpty ()) 1348 { 1349 // No error so far, but function still not known 1350 // -> try directory of edited file 1351 // get directory 1352 QDir dir; 1353 if (ffile.isEmpty ()) 1354 { 1355 if (curr_dir.isEmpty ()) 1356 dir = QDir (m_current_directory_combo_box->itemText (0)); 1357 else 1358 dir = QDir (curr_dir); 1359 } 1360 else 1361 dir = QDir (QFileInfo (ffile).canonicalPath ()); 1362 1363 QFileInfo file = QFileInfo (dir, fcn_name); 1364 if (file.exists ()) 1365 filename = file.canonicalFilePath (); // local file exists 1366 else 1367 { 1368 // local file does not exist -> try private directory 1369 file = QFileInfo (ffile); 1370 file = QFileInfo (QDir (file.canonicalPath () + "/private"), 1371 fcn_name); 1372 if (file.exists ()) 1373 filename = file.canonicalFilePath (); // private function exists 1374 else 1375 message = tr ("Can not find function %1"); // no file found 1376 1377 } 1378 } 1379 1380 if (! message.isEmpty ()) 1381 { 1382 emit warning_function_not_found_signal (message.arg (fname)); 1383 return; 1384 } 1385 1386 if (! filename.endsWith (".m")) 1387 filename.append (".m"); 1388 1389 // default encoding 1390 emit open_file_signal (filename, QString (), line); 1391 }); 1392 } 1393 warning_function_not_found(const QString & message)1394 void main_window::warning_function_not_found (const QString& message) 1395 { 1396 QMessageBox *msgBox = new QMessageBox (QMessageBox::Critical, 1397 tr ("Octave Editor"), 1398 message, QMessageBox::Ok, this); 1399 msgBox->setWindowModality (Qt::NonModal); 1400 msgBox->setAttribute (Qt::WA_DeleteOnClose); 1401 msgBox->show (); 1402 } 1403 handle_insert_debugger_pointer_request(const QString & file,int line)1404 void main_window::handle_insert_debugger_pointer_request (const QString& file, 1405 int line) 1406 { 1407 bool cmd_focus = command_window_has_focus (); 1408 1409 emit insert_debugger_pointer_signal (file, line); 1410 1411 if (cmd_focus) 1412 focus_command_window (); 1413 } 1414 handle_delete_debugger_pointer_request(const QString & file,int line)1415 void main_window::handle_delete_debugger_pointer_request (const QString& file, 1416 int line) 1417 { 1418 bool cmd_focus = command_window_has_focus (); 1419 1420 emit delete_debugger_pointer_signal (file, line); 1421 1422 if (cmd_focus) 1423 focus_command_window (); 1424 } 1425 handle_update_breakpoint_marker_request(bool insert,const QString & file,int line,const QString & cond)1426 void main_window::handle_update_breakpoint_marker_request (bool insert, 1427 const QString& file, 1428 int line, 1429 const QString& cond) 1430 { 1431 bool cmd_focus = command_window_has_focus (); 1432 1433 emit update_breakpoint_marker_signal (insert, file, line, cond); 1434 1435 if (cmd_focus) 1436 focus_command_window (); 1437 } 1438 read_settings(void)1439 void main_window::read_settings (void) 1440 { 1441 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 1442 gui_settings *settings = rmgr.get_settings (); 1443 1444 if (! settings) 1445 { 1446 qDebug ("Error: gui_settings pointer from resource manager is NULL."); 1447 return; 1448 } 1449 1450 set_window_layout (settings); 1451 1452 // restore the list of the last directories 1453 QStringList curr_dirs = settings->value (mw_dir_list).toStringList (); 1454 for (int i=0; i < curr_dirs.size (); i++) 1455 { 1456 m_current_directory_combo_box->addItem (curr_dirs.at (i)); 1457 } 1458 emit settings_changed (settings); 1459 } 1460 init_terminal_size(void)1461 void main_window::init_terminal_size (void) 1462 { 1463 emit init_terminal_size_signal (); 1464 } 1465 set_window_layout(gui_settings * settings)1466 void main_window::set_window_layout (gui_settings *settings) 1467 { 1468 // For resetting from some inconsistent state, first reset layout 1469 // without saving or showing it 1470 do_reset_windows (true, false); 1471 1472 // Restore main window state and geometry from settings file or, in case 1473 // of an error (no pref values yet), from the default layout. 1474 if (! restoreGeometry (settings->value (mw_geometry).toByteArray ())) 1475 { 1476 do_reset_windows (true); 1477 return; 1478 } 1479 1480 if (isMaximized()) 1481 { 1482 setGeometry( QApplication::desktop ()->availableGeometry (this)); 1483 } 1484 1485 if (! restoreState (settings->value (mw_state).toByteArray ())) 1486 { 1487 do_reset_windows (true); 1488 return; 1489 } 1490 1491 // Restore the geometry of all dock-widgets 1492 for (auto *widget : dock_widget_list ()) 1493 { 1494 QString name = widget->objectName (); 1495 1496 if (! name.isEmpty ()) 1497 { 1498 bool floating = false; 1499 bool visible = true; 1500 1501 floating = settings->value 1502 (dw_is_floating.key.arg (name), dw_is_floating.def).toBool (); 1503 visible = settings->value 1504 (dw_is_visible.key.arg (name), dw_is_visible.def).toBool (); 1505 1506 // If floating, make window from widget. 1507 if (floating) 1508 { 1509 widget->make_window (); 1510 1511 if (visible) 1512 { 1513 if (settings->value (dw_is_minimized.key.arg (name), 1514 dw_is_minimized.def).toBool ()) 1515 widget->showMinimized (); 1516 else 1517 widget->setVisible (true); 1518 } 1519 else 1520 widget->setVisible (false); 1521 } 1522 else // not floating 1523 { 1524 if (! widget->parent ()) // should not be floating but is 1525 widget->make_widget (false); // no docking, just reparent 1526 1527 widget->make_widget (); 1528 widget->setVisible (visible); // not floating -> show 1529 } 1530 } 1531 } 1532 1533 show (); 1534 } 1535 write_settings(void)1536 void main_window::write_settings (void) 1537 { 1538 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 1539 gui_settings *settings = rmgr.get_settings (); 1540 if (! settings) 1541 { 1542 qDebug ("Error: gui_settings pointer from resource manager is NULL."); 1543 return; 1544 } 1545 1546 settings->setValue (mw_geometry.key, saveGeometry ()); 1547 settings->setValue (mw_state.key, saveState ()); 1548 // write the list of recently used directories 1549 QStringList curr_dirs; 1550 for (int i=0; i<m_current_directory_combo_box->count (); i++) 1551 { 1552 curr_dirs.append (m_current_directory_combo_box->itemText (i)); 1553 } 1554 settings->setValue (mw_dir_list.key, curr_dirs); 1555 settings->sync (); 1556 } 1557 1558 // Connecting the signals emitted when the visibility of a widget changes. 1559 // This has to be done after the window is shown (see octave-gui.cc) connect_visibility_changed(void)1560 void main_window::connect_visibility_changed (void) 1561 { 1562 for (auto *widget : dock_widget_list ()) 1563 widget->connect_visibility_changed (); 1564 1565 #if defined (HAVE_QSCINTILLA) 1566 m_editor_window->enable_menu_shortcuts (false); 1567 #endif 1568 } 1569 copyClipboard(void)1570 void main_window::copyClipboard (void) 1571 { 1572 if (m_current_directory_combo_box->hasFocus ()) 1573 { 1574 QLineEdit *edit = m_current_directory_combo_box->lineEdit (); 1575 if (edit && edit->hasSelectedText ()) 1576 { 1577 QClipboard *clipboard = QApplication::clipboard (); 1578 clipboard->setText (edit->selectedText ()); 1579 } 1580 } 1581 else 1582 emit copyClipboard_signal (); 1583 } 1584 pasteClipboard(void)1585 void main_window::pasteClipboard (void) 1586 { 1587 if (m_current_directory_combo_box->hasFocus ()) 1588 { 1589 QLineEdit *edit = m_current_directory_combo_box->lineEdit (); 1590 QClipboard *clipboard = QApplication::clipboard (); 1591 QString str = clipboard->text (); 1592 if (edit && str.length () > 0) 1593 { 1594 edit->insert (str); 1595 } 1596 } 1597 else 1598 emit pasteClipboard_signal (); 1599 } 1600 selectAll(void)1601 void main_window::selectAll (void) 1602 { 1603 if (m_current_directory_combo_box->hasFocus ()) 1604 { 1605 QLineEdit *edit = m_current_directory_combo_box->lineEdit (); 1606 if (edit) 1607 { 1608 edit->selectAll (); 1609 } 1610 } 1611 else 1612 emit selectAll_signal (); 1613 } 1614 handle_show_doc(const QString & file)1615 void main_window::handle_show_doc (const QString& file) 1616 { 1617 m_doc_browser_window->setVisible (true); 1618 emit show_doc_signal (file); 1619 } 1620 handle_register_doc(const QString & file)1621 void main_window::handle_register_doc (const QString& file) 1622 { 1623 emit register_doc_signal (file); 1624 } 1625 handle_unregister_doc(const QString & file)1626 void main_window::handle_unregister_doc (const QString& file) 1627 { 1628 emit unregister_doc_signal (file); 1629 } 1630 handle_octave_ready(void)1631 void main_window::handle_octave_ready (void) 1632 { 1633 // actions after the startup files are executed 1634 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 1635 gui_settings *settings = rmgr.get_settings (); 1636 1637 QDir startup_dir = QDir (); // current octave dir after startup 1638 1639 if (settings) 1640 { 1641 if (settings->value (global_restore_ov_dir).toBool ()) 1642 { 1643 // restore last dir from previous session 1644 QStringList curr_dirs 1645 = settings->value (mw_dir_list).toStringList (); 1646 if (curr_dirs.length () > 0) 1647 startup_dir = QDir (curr_dirs.at (0)); // last dir prev. session 1648 } 1649 else if (! settings->value (global_ov_startup_dir).toString ().isEmpty ()) 1650 { 1651 // do not restore but there is a startup dir configured 1652 startup_dir 1653 = QDir (settings->value (global_ov_startup_dir).toString ()); 1654 } 1655 1656 update_default_encoding (settings->value (ed_default_enc).toString ()); 1657 } 1658 1659 if (! startup_dir.exists ()) 1660 { 1661 // the configured startup dir does not exist, take actual one 1662 startup_dir = QDir (); 1663 } 1664 1665 set_current_working_directory (startup_dir.absolutePath ()); 1666 1667 if (m_editor_window) 1668 { 1669 #if defined (HAVE_QSCINTILLA) 1670 // Octave ready, determine whether to create an empty script. 1671 // This can not be done when the editor is created because all functions 1672 // must be known for the lexer's auto completion information 1673 m_editor_window->empty_script (true, false); 1674 m_editor_window->restore_session (settings); 1675 #endif 1676 } 1677 1678 focus_command_window (); // make sure that the command window has focus 1679 } 1680 handle_set_path_dialog_request(void)1681 void main_window::handle_set_path_dialog_request (void) 1682 { 1683 if (m_set_path_dlg) // m_set_path_dlg is a guarded pointer! 1684 return; 1685 1686 m_set_path_dlg = new set_path_dialog (this, m_octave_qobj); 1687 1688 m_set_path_dlg->setModal (false); 1689 m_set_path_dlg->setAttribute (Qt::WA_DeleteOnClose); 1690 m_set_path_dlg->show (); 1691 1692 // Any interpreter_event signal from a set_path_dialog object is 1693 // handled the same as for the main_window object. 1694 1695 connect (m_set_path_dlg, SIGNAL (interpreter_event (const fcn_callback&)), 1696 this, SIGNAL (interpreter_event (const fcn_callback&))); 1697 1698 connect (m_set_path_dlg, SIGNAL (interpreter_event (const meth_callback&)), 1699 this, SIGNAL (interpreter_event (const meth_callback&))); 1700 1701 connect (m_set_path_dlg, 1702 SIGNAL (modify_path_signal (const octave_value_list&, bool, bool)), 1703 this, SLOT (modify_path (const octave_value_list&, bool, bool))); 1704 1705 interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj (); 1706 1707 qt_interpreter_events *qt_link = interp_qobj->qt_link (); 1708 1709 connect (qt_link, SIGNAL (update_path_dialog_signal (void)), 1710 m_set_path_dlg, SLOT (update_model (void))); 1711 1712 // Now that all the signal connections are in place for the dialog 1713 // we can set the initial value of the path in the model. 1714 1715 m_set_path_dlg->update_model (); 1716 } 1717 find_files(const QString & start_dir)1718 void main_window::find_files (const QString& start_dir) 1719 { 1720 1721 if (! m_find_files_dlg) 1722 { 1723 m_find_files_dlg = new find_files_dialog (this, m_octave_qobj); 1724 1725 connect (m_find_files_dlg, SIGNAL (finished (int)), 1726 this, SLOT (find_files_finished (int))); 1727 1728 connect (m_find_files_dlg, SIGNAL (dir_selected (const QString &)), 1729 m_file_browser_window, 1730 SLOT (set_current_directory (const QString&))); 1731 1732 connect (m_find_files_dlg, SIGNAL (file_selected (const QString &)), 1733 this, SLOT (open_file (const QString &))); 1734 1735 m_find_files_dlg->setWindowModality (Qt::NonModal); 1736 } 1737 1738 if (! m_find_files_dlg->isVisible ()) 1739 { 1740 m_find_files_dlg->show (); 1741 } 1742 1743 m_find_files_dlg->set_search_dir (start_dir); 1744 1745 m_find_files_dlg->activateWindow (); 1746 1747 } 1748 set_global_shortcuts(bool set_shortcuts)1749 void main_window::set_global_shortcuts (bool set_shortcuts) 1750 { 1751 // this slot is called when the terminal gets/loses focus 1752 1753 // return if the user doesn't want to use readline shortcuts 1754 if (! m_prevent_readline_conflicts) 1755 return; 1756 1757 if (set_shortcuts) 1758 { 1759 // terminal loses focus: set the global shortcuts 1760 configure_shortcuts (); 1761 } 1762 else 1763 { 1764 // terminal gets focus: disable some shortcuts 1765 QKeySequence no_key = QKeySequence (); 1766 1767 // file menu 1768 m_open_action->setShortcut (no_key); 1769 m_new_script_action->setShortcut (no_key); 1770 m_new_function_action->setShortcut (no_key); 1771 m_new_figure_action->setShortcut (no_key); 1772 m_load_workspace_action->setShortcut (no_key); 1773 m_save_workspace_action->setShortcut (no_key); 1774 m_preferences_action->setShortcut (no_key); 1775 m_set_path_action->setShortcut (no_key); 1776 m_exit_action->setShortcut (no_key); 1777 1778 // edit menu 1779 m_select_all_action->setShortcut (no_key); 1780 m_clear_clipboard_action->setShortcut (no_key); 1781 m_find_files_action->setShortcut (no_key); 1782 m_clear_command_history_action->setShortcut (no_key); 1783 m_clear_command_window_action->setShortcut (no_key); 1784 m_clear_workspace_action->setShortcut (no_key); 1785 1786 // window menu 1787 m_reset_windows_action->setShortcut (no_key); 1788 1789 // help menu 1790 m_ondisk_doc_action->setShortcut (no_key); 1791 m_online_doc_action->setShortcut (no_key); 1792 m_report_bug_action->setShortcut (no_key); 1793 m_octave_packages_action->setShortcut (no_key); 1794 m_contribute_action->setShortcut (no_key); 1795 m_developer_action->setShortcut (no_key); 1796 m_about_octave_action->setShortcut (no_key); 1797 1798 // news menu 1799 m_release_notes_action->setShortcut (no_key); 1800 m_current_news_action->setShortcut (no_key); 1801 } 1802 } 1803 set_screen_size(int ht,int wd)1804 void main_window::set_screen_size (int ht, int wd) 1805 { 1806 emit interpreter_event 1807 ([ht, wd] (void) 1808 { 1809 // INTERPRETER THREAD 1810 1811 command_editor::set_screen_size (ht, wd); 1812 }); 1813 } 1814 clipboard_has_changed(void)1815 void main_window::clipboard_has_changed (void) 1816 { 1817 if (m_clipboard->text ().isEmpty ()) 1818 { 1819 m_paste_action->setEnabled (false); 1820 m_clear_clipboard_action->setEnabled (false); 1821 } 1822 else 1823 { 1824 m_paste_action->setEnabled (true); 1825 m_clear_clipboard_action->setEnabled (true); 1826 } 1827 } 1828 clear_clipboard(void)1829 void main_window::clear_clipboard (void) 1830 { 1831 m_clipboard->clear (QClipboard::Clipboard); 1832 } 1833 disable_menu_shortcuts(bool disable)1834 void main_window::disable_menu_shortcuts (bool disable) 1835 { 1836 QHash<QMenu*, QStringList>::const_iterator i = m_hash_menu_text.constBegin (); 1837 1838 while (i != m_hash_menu_text.constEnd ()) 1839 { 1840 i.key ()->setTitle (i.value ().at (disable)); 1841 ++i; 1842 } 1843 } 1844 restore_create_file_setting(void)1845 void main_window::restore_create_file_setting (void) 1846 { 1847 // restore the new files creation setting 1848 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 1849 gui_settings *settings = rmgr.get_settings (); 1850 settings->setValue (ed_create_new_file.key, false); 1851 disconnect (m_editor_window, SIGNAL (file_loaded_signal (void)), 1852 this, SLOT (restore_create_file_setting (void))); 1853 } 1854 set_file_encoding(const QString & new_encoding)1855 void main_window::set_file_encoding (const QString& new_encoding) 1856 { 1857 m_file_encoding = new_encoding; 1858 } 1859 1860 // The following slot is called after files have been selected in the 1861 // open file dialog, possibly with a new selected encoding stored in 1862 // m_file_encoding request_open_files(const QStringList & open_file_names)1863 void main_window::request_open_files (const QStringList& open_file_names) 1864 { 1865 for (int i = 0; i < open_file_names.count (); i++) 1866 emit open_file_signal (open_file_names.at (i), m_file_encoding, -1); 1867 } 1868 edit_variable(const QString & expr,const octave_value & val)1869 void main_window::edit_variable (const QString &expr, const octave_value& val) 1870 { 1871 m_variable_editor_window->edit_variable (expr, val); 1872 1873 if (! m_variable_editor_window->isVisible ()) 1874 { 1875 m_variable_editor_window->show (); 1876 m_variable_editor_window->raise (); 1877 } 1878 1879 } 1880 refresh_variable_editor(void)1881 void main_window::refresh_variable_editor (void) 1882 { 1883 m_variable_editor_window->refresh (); 1884 } 1885 handle_variable_editor_update(void)1886 void main_window::handle_variable_editor_update (void) 1887 { 1888 // Called when the variable editor emits the updated signal. The size 1889 // of a variable may have changed, so we refresh the workspace in the 1890 // interpreter. That will eventually cause the workspace view in the 1891 // GUI to be updated. 1892 1893 emit interpreter_event 1894 ([] (interpreter& interp) 1895 { 1896 // INTERPRETER THREAD 1897 1898 tree_evaluator& tw = interp.get_evaluator (); 1899 1900 event_manager& xevmgr = interp.get_event_manager (); 1901 1902 xevmgr.set_workspace (true, tw.get_symbol_info (), false); 1903 }); 1904 } 1905 closeEvent(QCloseEvent * e)1906 void main_window::closeEvent (QCloseEvent *e) 1907 { 1908 if (confirm_shutdown ()) 1909 { 1910 // FIXME: Instead of ignoring the event and posting an 1911 // interpreter event, should we just accept the event and 1912 // shutdown and clean up the interprter as part of closing the 1913 // GUI? Going that route might make it easier to close the GUI 1914 // without having to stop the interpreter, for example, if the 1915 // GUI is started from the interpreter command line. 1916 1917 e->ignore (); 1918 1919 emit interpreter_event 1920 ([] (interpreter& interp) 1921 { 1922 // INTERPRETER THREAD 1923 1924 interp.quit (0, false, false); 1925 }); 1926 } 1927 else 1928 e->ignore (); 1929 } 1930 construct_central_widget(void)1931 void main_window::construct_central_widget (void) 1932 { 1933 // Create and set the central widget. QMainWindow takes ownership of 1934 // the widget (pointer) so there is no need to delete the object upon 1935 // destroying this main_window. 1936 1937 QWidget *dummyWidget = new QWidget (); 1938 dummyWidget->setObjectName ("CentralDummyWidget"); 1939 dummyWidget->resize (10, 10); 1940 dummyWidget->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); 1941 dummyWidget->hide (); 1942 setCentralWidget (dummyWidget); 1943 } 1944 1945 // Main subroutine of the constructor 1946 construct(void)1947 void main_window::construct (void) 1948 { 1949 setWindowIcon (QIcon (":/actions/icons/logo.png")); 1950 1951 m_workspace_window->setModel (m_workspace_model); 1952 1953 connect (m_workspace_model, SIGNAL (model_changed (void)), 1954 m_workspace_window, SLOT (handle_model_changed (void))); 1955 1956 interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj (); 1957 1958 qt_interpreter_events *qt_link = interp_qobj->qt_link (); 1959 1960 connect (qt_link, 1961 SIGNAL (edit_variable_signal (const QString&, 1962 const octave_value&)), 1963 this, 1964 SLOT (edit_variable (const QString&, const octave_value&))); 1965 1966 connect (qt_link, SIGNAL (refresh_variable_editor_signal (void)), 1967 this, SLOT (refresh_variable_editor (void))); 1968 1969 connect (m_workspace_window, 1970 SIGNAL (rename_variable_signal (const QString&, const QString&)), 1971 this, 1972 SLOT (handle_rename_variable_request (const QString&, 1973 const QString&))); 1974 1975 connect (m_variable_editor_window, SIGNAL (updated (void)), 1976 this, SLOT (handle_variable_editor_update (void))); 1977 1978 construct_menu_bar (); 1979 1980 construct_tool_bar (); 1981 1982 // Order is important. Deleting gui_settings must be last. 1983 connect (qApp, SIGNAL (aboutToQuit (void)), 1984 m_command_window, SLOT (save_settings (void))); 1985 1986 connect (qApp, SIGNAL (aboutToQuit (void)), 1987 m_history_window, SLOT (save_settings (void))); 1988 1989 connect (qApp, SIGNAL (aboutToQuit (void)), 1990 m_file_browser_window, SLOT (save_settings (void))); 1991 1992 connect (qApp, SIGNAL (aboutToQuit (void)), 1993 m_doc_browser_window, SLOT (save_settings (void))); 1994 1995 connect (qApp, SIGNAL (aboutToQuit (void)), 1996 m_workspace_window, SLOT (save_settings (void))); 1997 1998 connect (qApp, SIGNAL (aboutToQuit (void)), 1999 m_editor_window, SLOT (save_settings (void))); 2000 2001 connect (qApp, SIGNAL (aboutToQuit (void)), 2002 m_variable_editor_window, SLOT (save_settings (void))); 2003 2004 connect (qApp, SIGNAL (aboutToQuit (void)), 2005 this, SLOT (prepare_to_exit (void))); 2006 2007 connect (qApp, SIGNAL (focusChanged (QWidget*, QWidget*)), 2008 this, SLOT (focus_changed (QWidget*, QWidget*))); 2009 2010 connect (this, SIGNAL (settings_changed (const gui_settings *)), 2011 this, SLOT (notice_settings (const gui_settings *))); 2012 2013 connect (this, SIGNAL (editor_focus_changed (bool)), 2014 this, SLOT (disable_menu_shortcuts (bool))); 2015 2016 connect (this, SIGNAL (editor_focus_changed (bool)), 2017 m_editor_window, SLOT (enable_menu_shortcuts (bool))); 2018 2019 connect (this, SIGNAL (step_into_file_signal (void)), 2020 m_editor_window, SLOT (request_step_into_file (void))); 2021 2022 connect (m_editor_window, SIGNAL (editor_tabs_changed_signal (bool)), 2023 this, SLOT (editor_tabs_changed (bool))); 2024 2025 connect (m_editor_window, 2026 SIGNAL (request_open_file_external (const QString&, int)), 2027 m_external_editor, 2028 SLOT (call_custom_editor (const QString&, int))); 2029 2030 connect (m_external_editor, 2031 SIGNAL (request_settings_dialog (const QString&)), 2032 this, SLOT (process_settings_dialog_request (const QString&))); 2033 2034 connect (m_file_browser_window, SIGNAL (load_file_signal (const QString&)), 2035 this, SLOT (handle_load_workspace_request (const QString&))); 2036 2037 connect (m_file_browser_window, SIGNAL (open_any_signal (const QString&)), 2038 this, SLOT (handle_open_any_request (const QString&))); 2039 2040 connect (m_file_browser_window, SIGNAL (find_files_signal (const QString&)), 2041 this, SLOT (find_files (const QString&))); 2042 2043 // Connections for signals from the interpreter thread where the slot 2044 // should be executed by the gui thread 2045 2046 connect (this, SIGNAL (warning_function_not_found_signal (const QString&)), 2047 this, SLOT (warning_function_not_found (const QString&))); 2048 2049 setWindowTitle ("Octave"); 2050 2051 setStatusBar (m_status_bar); 2052 2053 #if defined (HAVE_QSCINTILLA) 2054 connect (this, 2055 SIGNAL (insert_debugger_pointer_signal (const QString&, int)), 2056 m_editor_window, 2057 SLOT (handle_insert_debugger_pointer_request (const QString&, 2058 int))); 2059 2060 connect (this, 2061 SIGNAL (delete_debugger_pointer_signal (const QString&, int)), 2062 m_editor_window, 2063 SLOT (handle_delete_debugger_pointer_request (const QString&, 2064 int))); 2065 2066 connect (this, 2067 SIGNAL (update_breakpoint_marker_signal (bool, const QString&, 2068 int, const QString&)), 2069 m_editor_window, 2070 SLOT (handle_update_breakpoint_marker_request (bool, 2071 const QString&, 2072 int, 2073 const QString&))); 2074 2075 // Signals for removing/renaming files/dirs in the file browser 2076 connect (m_file_browser_window, 2077 SIGNAL (file_remove_signal (const QString&, const QString&)), 2078 m_editor_window, 2079 SLOT (handle_file_remove (const QString&, const QString&))); 2080 2081 connect (m_file_browser_window, SIGNAL (file_renamed_signal (bool)), 2082 m_editor_window, SLOT (handle_file_renamed (bool))); 2083 2084 // Signals for removing/renaming files/dirs in the terminal window 2085 connect (qt_link, SIGNAL (file_renamed_signal (bool)), 2086 m_editor_window, SLOT (handle_file_renamed (bool))); 2087 #endif 2088 2089 // Signals for removing/renaming files/dirs in the temrinal window 2090 connect (qt_link, 2091 SIGNAL (file_remove_signal (const QString&, const QString&)), 2092 this, SLOT (file_remove_proxy (const QString&, const QString&))); 2093 2094 connect (this, SIGNAL (interpreter_event (const fcn_callback&)), 2095 &m_octave_qobj, SLOT (interpreter_event (const fcn_callback&))); 2096 2097 connect (this, SIGNAL (interpreter_event (const meth_callback&)), 2098 &m_octave_qobj, SLOT (interpreter_event (const meth_callback&))); 2099 2100 configure_shortcuts (); 2101 } 2102 construct_octave_qt_link(void)2103 void main_window::construct_octave_qt_link (void) 2104 { 2105 interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj (); 2106 2107 qt_interpreter_events *qt_link = interp_qobj->qt_link (); 2108 2109 connect (qt_link, SIGNAL (settings_changed (const gui_settings *, bool)), 2110 this, SLOT (notice_settings (const gui_settings *, bool))); 2111 2112 connect (qt_link, SIGNAL (apply_new_settings (void)), 2113 this, SLOT (request_reload_settings (void))); 2114 2115 connect (qt_link, 2116 SIGNAL (set_workspace_signal (bool, bool, const symbol_info_list&)), 2117 m_workspace_model, 2118 SLOT (set_workspace (bool, bool, const symbol_info_list&))); 2119 2120 connect (qt_link, SIGNAL (clear_workspace_signal (void)), 2121 m_workspace_model, SLOT (clear_workspace (void))); 2122 2123 connect (qt_link, SIGNAL (directory_changed_signal (QString)), 2124 this, SLOT (update_octave_directory (QString))); 2125 2126 connect (qt_link, SIGNAL (directory_changed_signal (QString)), 2127 m_file_browser_window, SLOT (update_octave_directory (QString))); 2128 2129 connect (qt_link, SIGNAL (directory_changed_signal (QString)), 2130 m_editor_window, SLOT (update_octave_directory (QString))); 2131 2132 connect (qt_link, 2133 SIGNAL (execute_command_in_terminal_signal (QString)), 2134 this, SLOT (execute_command_in_terminal (QString))); 2135 2136 connect (qt_link, 2137 SIGNAL (set_history_signal (const QStringList&)), 2138 m_history_window, SLOT (set_history (const QStringList&))); 2139 2140 connect (qt_link, 2141 SIGNAL (append_history_signal (const QString&)), 2142 m_history_window, SLOT (append_history (const QString&))); 2143 2144 connect (qt_link, 2145 SIGNAL (clear_history_signal (void)), 2146 m_history_window, SLOT (clear_history (void))); 2147 2148 connect (qt_link, SIGNAL (enter_debugger_signal (void)), 2149 this, SLOT (handle_enter_debugger (void))); 2150 2151 connect (qt_link, SIGNAL (exit_debugger_signal (void)), 2152 this, SLOT (handle_exit_debugger (void))); 2153 2154 connect (qt_link, 2155 SIGNAL (show_preferences_signal (void)), 2156 this, SLOT (process_settings_dialog_request (void))); 2157 2158 connect (qt_link, 2159 SIGNAL (edit_file_signal (const QString&)), 2160 m_active_editor, 2161 SLOT (handle_edit_file_request (const QString&))); 2162 2163 connect (qt_link, 2164 SIGNAL (insert_debugger_pointer_signal (const QString&, int)), 2165 this, 2166 SLOT (handle_insert_debugger_pointer_request (const QString&, 2167 int))); 2168 2169 connect (qt_link, 2170 SIGNAL (delete_debugger_pointer_signal (const QString&, int)), 2171 this, 2172 SLOT (handle_delete_debugger_pointer_request (const QString&, 2173 int))); 2174 2175 connect (qt_link, 2176 SIGNAL (update_breakpoint_marker_signal (bool, const QString&, 2177 int, const QString&)), 2178 this, 2179 SLOT (handle_update_breakpoint_marker_request (bool, const QString&, 2180 int, const QString&))); 2181 2182 connect (qt_link, 2183 SIGNAL (show_doc_signal (const QString &)), 2184 this, SLOT (handle_show_doc (const QString &))); 2185 2186 connect (qt_link, 2187 SIGNAL (register_doc_signal (const QString &)), 2188 this, SLOT (handle_register_doc (const QString &))); 2189 2190 connect (qt_link, 2191 SIGNAL (unregister_doc_signal (const QString &)), 2192 this, SLOT (handle_unregister_doc (const QString &))); 2193 } 2194 add_action(QMenu * menu,const QIcon & icon,const QString & text,const char * member,const QWidget * receiver)2195 QAction* main_window::add_action (QMenu *menu, const QIcon& icon, 2196 const QString& text, const char *member, 2197 const QWidget *receiver) 2198 { 2199 QAction *a; 2200 2201 if (receiver) 2202 a = menu->addAction (icon, text, receiver, member); 2203 else 2204 a = menu->addAction (icon, text, this, member); 2205 2206 addAction (a); // important for shortcut context 2207 a->setShortcutContext (Qt::ApplicationShortcut); 2208 return a; 2209 } 2210 m_add_menu(QMenuBar * p,QString name)2211 QMenu* main_window::m_add_menu (QMenuBar *p, QString name) 2212 { 2213 QMenu *menu = p->addMenu (name); 2214 2215 QString base_name = name; // get a copy 2216 // replace intended '&' ("&&") by a temp. string 2217 base_name.replace ("&&", "___octave_amp_replacement___"); 2218 // remove single '&' (shortcut) 2219 base_name.remove ("&"); 2220 // restore intended '&' 2221 base_name.replace ("___octave_amp_replacement___", "&&"); 2222 2223 // remember names with and without shortcut 2224 m_hash_menu_text[menu] = QStringList () << name << base_name; 2225 2226 return menu; 2227 } 2228 construct_menu_bar(void)2229 void main_window::construct_menu_bar (void) 2230 { 2231 QMenuBar *menu_bar = menuBar (); 2232 2233 construct_file_menu (menu_bar); 2234 2235 construct_edit_menu (menu_bar); 2236 2237 construct_debug_menu (menu_bar); 2238 2239 construct_window_menu (menu_bar); 2240 2241 construct_help_menu (menu_bar); 2242 2243 construct_news_menu (menu_bar); 2244 2245 #if defined (HAVE_QSCINTILLA) 2246 // call the editor to add actions which should also be available in the 2247 // editor's menu and tool bar 2248 QList<QAction*> shared_actions; 2249 shared_actions << m_new_script_action 2250 << m_new_function_action 2251 << m_open_action 2252 << m_find_files_action 2253 << m_undo_action 2254 << m_copy_action 2255 << m_paste_action 2256 <<m_select_all_action; 2257 m_editor_window->insert_global_actions (shared_actions); 2258 #endif 2259 } 2260 construct_file_menu(QMenuBar * p)2261 void main_window::construct_file_menu (QMenuBar *p) 2262 { 2263 QMenu *file_menu = m_add_menu (p, tr ("&File")); 2264 2265 construct_new_menu (file_menu); 2266 2267 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 2268 m_open_action 2269 = file_menu->addAction (rmgr.icon ("document-open"), tr ("Open...")); 2270 m_open_action->setShortcutContext (Qt::ApplicationShortcut); 2271 m_open_action->setToolTip (tr ("Open an existing file in editor")); 2272 2273 #if defined (HAVE_QSCINTILLA) 2274 file_menu->addMenu (m_editor_window->get_mru_menu ()); 2275 #endif 2276 2277 file_menu->addSeparator (); 2278 2279 m_load_workspace_action 2280 = file_menu->addAction (tr ("Load Workspace...")); 2281 2282 m_save_workspace_action 2283 = file_menu->addAction (tr ("Save Workspace As...")); 2284 2285 file_menu->addSeparator (); 2286 2287 m_exit_action = file_menu->addAction (tr ("Exit")); 2288 m_exit_action->setMenuRole (QAction::QuitRole); 2289 m_exit_action->setShortcutContext (Qt::ApplicationShortcut); 2290 2291 connect (m_open_action, SIGNAL (triggered (void)), 2292 this, SLOT (request_open_file (void))); 2293 2294 connect (m_load_workspace_action, SIGNAL (triggered (void)), 2295 this, SLOT (handle_load_workspace_request (void))); 2296 2297 connect (m_save_workspace_action, SIGNAL (triggered (void)), 2298 this, SLOT (handle_save_workspace_request (void))); 2299 2300 connect (m_exit_action, SIGNAL (triggered (void)), 2301 this, SLOT (close (void))); 2302 } 2303 construct_new_menu(QMenu * p)2304 void main_window::construct_new_menu (QMenu *p) 2305 { 2306 QMenu *new_menu = p->addMenu (tr ("New")); 2307 2308 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 2309 m_new_script_action 2310 = new_menu->addAction (rmgr.icon ("document-new"), tr ("New Script")); 2311 m_new_script_action->setShortcutContext (Qt::ApplicationShortcut); 2312 2313 m_new_function_action = new_menu->addAction (tr ("New Function...")); 2314 m_new_function_action->setEnabled (true); 2315 m_new_function_action->setShortcutContext (Qt::ApplicationShortcut); 2316 2317 m_new_figure_action = new_menu->addAction (tr ("New Figure")); 2318 m_new_figure_action->setEnabled (true); 2319 2320 connect (m_new_script_action, SIGNAL (triggered (void)), 2321 this, SLOT (request_new_script (void))); 2322 2323 connect (m_new_function_action, SIGNAL (triggered (void)), 2324 this, SLOT (request_new_function (void))); 2325 2326 connect (this, SIGNAL (new_file_signal (const QString&)), 2327 m_active_editor, SLOT (request_new_file (const QString&))); 2328 2329 connect (this, SIGNAL (open_file_signal (const QString&)), 2330 m_active_editor, SLOT (request_open_file (const QString&))); 2331 2332 connect (this, 2333 SIGNAL (open_file_signal (const QString&, const QString&, int)), 2334 m_active_editor, 2335 SLOT (request_open_file (const QString&, const QString&, int))); 2336 2337 connect (m_new_figure_action, SIGNAL (triggered (void)), 2338 this, SLOT (handle_new_figure_request (void))); 2339 } 2340 construct_edit_menu(QMenuBar * p)2341 void main_window::construct_edit_menu (QMenuBar *p) 2342 { 2343 QMenu *edit_menu = m_add_menu (p, tr ("&Edit")); 2344 2345 QKeySequence ctrl_shift = Qt::ControlModifier + Qt::ShiftModifier; 2346 2347 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 2348 m_undo_action 2349 = edit_menu->addAction (rmgr.icon ("edit-undo"), tr ("Undo")); 2350 m_undo_action->setShortcutContext (Qt::ApplicationShortcut); 2351 2352 edit_menu->addSeparator (); 2353 2354 m_copy_action 2355 = edit_menu->addAction (rmgr.icon ("edit-copy"), tr ("Copy"), this, 2356 SLOT (copyClipboard (void))); 2357 m_copy_action->setShortcutContext (Qt::ApplicationShortcut); 2358 2359 m_paste_action 2360 = edit_menu->addAction (rmgr.icon ("edit-paste"), tr ("Paste"), this, 2361 SLOT (pasteClipboard (void))); 2362 m_paste_action->setShortcutContext (Qt::ApplicationShortcut); 2363 2364 m_select_all_action 2365 = edit_menu->addAction (tr ("Select All"), this, SLOT (selectAll (void))); 2366 m_select_all_action->setShortcutContext (Qt::ApplicationShortcut); 2367 2368 m_clear_clipboard_action 2369 = edit_menu->addAction (tr ("Clear Clipboard"), this, 2370 SLOT (clear_clipboard (void))); 2371 2372 edit_menu->addSeparator (); 2373 2374 m_find_files_action 2375 = edit_menu->addAction (rmgr.icon ("edit-find"), tr ("Find Files...")); 2376 2377 edit_menu->addSeparator (); 2378 2379 m_clear_command_window_action 2380 = edit_menu->addAction (tr ("Clear Command Window")); 2381 2382 m_clear_command_history_action 2383 = edit_menu->addAction (tr ("Clear Command History")); 2384 2385 m_clear_workspace_action 2386 = edit_menu->addAction (tr ("Clear Workspace")); 2387 2388 edit_menu->addSeparator (); 2389 2390 m_set_path_action 2391 = edit_menu->addAction (tr ("Set Path")); 2392 2393 m_preferences_action 2394 = edit_menu->addAction (rmgr.icon ("preferences-system"), 2395 tr ("Preferences...")); 2396 2397 connect (m_find_files_action, SIGNAL (triggered (void)), 2398 this, SLOT (find_files (void))); 2399 2400 connect (m_clear_command_window_action, SIGNAL (triggered (void)), 2401 this, SLOT (handle_clear_command_window_request (void))); 2402 2403 connect (m_clear_command_history_action, SIGNAL (triggered (void)), 2404 this, SLOT (handle_clear_history_request (void))); 2405 2406 connect (m_clear_workspace_action, SIGNAL (triggered (void)), 2407 this, SLOT (handle_clear_workspace_request (void))); 2408 2409 connect (m_clipboard, SIGNAL (dataChanged (void)), 2410 this, SLOT (clipboard_has_changed (void))); 2411 clipboard_has_changed (); 2412 #if defined (Q_OS_WIN32) 2413 // Always enable paste action (unreliable clipboard signals in windows) 2414 // FIXME: This has to be removed, when the clipboard signals in windows 2415 // are working again 2416 m_paste_action->setEnabled (true); 2417 m_clear_clipboard_action->setEnabled (true); 2418 #endif 2419 2420 connect (m_preferences_action, SIGNAL (triggered (void)), 2421 this, SLOT (process_settings_dialog_request (void))); 2422 2423 connect (m_set_path_action, SIGNAL (triggered (void)), 2424 this, SLOT (handle_set_path_dialog_request (void))); 2425 2426 } 2427 construct_debug_menu_item(const char * icon,const QString & item,const char * member)2428 QAction * main_window::construct_debug_menu_item (const char *icon, 2429 const QString& item, 2430 const char *member) 2431 { 2432 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 2433 QAction *action = add_action (m_debug_menu, rmgr.icon (QString (icon)), 2434 item, member); 2435 2436 action->setEnabled (false); 2437 2438 #if defined (HAVE_QSCINTILLA) 2439 m_editor_window->debug_menu ()->addAction (action); 2440 m_editor_window->toolbar ()->addAction (action); 2441 #endif 2442 2443 return action; 2444 } 2445 construct_debug_menu(QMenuBar * p)2446 void main_window::construct_debug_menu (QMenuBar *p) 2447 { 2448 m_debug_menu = m_add_menu (p, tr ("De&bug")); 2449 2450 m_debug_step_over 2451 = construct_debug_menu_item ("db-step", tr ("Step"), 2452 SLOT (debug_step_over (void))); 2453 2454 m_debug_step_into 2455 = construct_debug_menu_item ("db-step-in", tr ("Step In"), 2456 SLOT (debug_step_into (void))); 2457 2458 m_debug_step_out 2459 = construct_debug_menu_item ("db-step-out", tr ("Step Out"), 2460 SLOT (debug_step_out (void))); 2461 2462 m_debug_continue 2463 = construct_debug_menu_item ("db-cont", tr ("Continue"), 2464 SLOT (debug_continue (void))); 2465 2466 m_debug_menu->addSeparator (); 2467 #if defined (HAVE_QSCINTILLA) 2468 m_editor_window->debug_menu ()->addSeparator (); 2469 #endif 2470 2471 m_debug_quit 2472 = construct_debug_menu_item ("db-stop", tr ("Quit Debug Mode"), 2473 SLOT (debug_quit (void))); 2474 } 2475 editor_tabs_changed(bool have_tabs)2476 void main_window::editor_tabs_changed (bool have_tabs) 2477 { 2478 // Set state of actions which depend on the existence of editor tabs 2479 m_editor_has_tabs = have_tabs; 2480 m_debug_step_over->setEnabled (have_tabs); 2481 } 2482 construct_window_menu_item(QMenu * p,const QString & item,bool checkable,QWidget * widget)2483 QAction * main_window::construct_window_menu_item (QMenu *p, 2484 const QString& item, 2485 bool checkable, 2486 QWidget *widget) 2487 { 2488 QAction *action = p->addAction (QIcon (), item); 2489 2490 addAction (action); // important for shortcut context 2491 action->setCheckable (checkable); 2492 action->setShortcutContext (Qt::ApplicationShortcut); 2493 2494 if (widget) // might be zero for m_editor_window 2495 { 2496 if (checkable) 2497 { 2498 // action for visibility of dock widget 2499 connect (action, SIGNAL (toggled (bool)), 2500 widget, SLOT (setVisible (bool))); 2501 2502 connect (widget, SIGNAL (active_changed (bool)), 2503 action, SLOT (setChecked (bool))); 2504 } 2505 else 2506 { 2507 // action for focus of dock widget 2508 connect (action, SIGNAL (triggered (void)), widget, SLOT (activate (void))); 2509 } 2510 } 2511 else 2512 { 2513 action->setEnabled (false); 2514 } 2515 2516 return action; 2517 } 2518 construct_window_menu(QMenuBar * p)2519 void main_window::construct_window_menu (QMenuBar *p) 2520 { 2521 QMenu *window_menu = m_add_menu (p, tr ("&Window")); 2522 2523 m_show_command_window_action = construct_window_menu_item 2524 (window_menu, tr ("Show Command Window"), true, m_command_window); 2525 2526 m_show_history_action = construct_window_menu_item 2527 (window_menu, tr ("Show Command History"), true, m_history_window); 2528 2529 m_show_file_browser_action = construct_window_menu_item 2530 (window_menu, tr ("Show File Browser"), true, m_file_browser_window); 2531 2532 m_show_workspace_action = construct_window_menu_item 2533 (window_menu, tr ("Show Workspace"), true, m_workspace_window); 2534 2535 m_show_editor_action = construct_window_menu_item 2536 (window_menu, tr ("Show Editor"), true, m_editor_window); 2537 2538 m_show_documentation_action = construct_window_menu_item 2539 (window_menu, tr ("Show Documentation"), true, m_doc_browser_window); 2540 2541 m_show_variable_editor_action = construct_window_menu_item 2542 (window_menu, tr ("Show Variable Editor"), true, m_variable_editor_window); 2543 2544 window_menu->addSeparator (); 2545 2546 m_command_window_action = construct_window_menu_item 2547 (window_menu, tr ("Command Window"), false, m_command_window); 2548 2549 m_history_action = construct_window_menu_item 2550 (window_menu, tr ("Command History"), false, m_history_window); 2551 2552 m_file_browser_action = construct_window_menu_item 2553 (window_menu, tr ("File Browser"), false, m_file_browser_window); 2554 2555 m_workspace_action = construct_window_menu_item 2556 (window_menu, tr ("Workspace"), false, m_workspace_window); 2557 2558 m_editor_action = construct_window_menu_item 2559 (window_menu, tr ("Editor"), false, m_editor_window); 2560 2561 m_documentation_action = construct_window_menu_item 2562 (window_menu, tr ("Documentation"), false, m_doc_browser_window); 2563 2564 m_variable_editor_action = construct_window_menu_item 2565 (window_menu, tr ("Variable Editor"), false, m_variable_editor_window); 2566 2567 window_menu->addSeparator (); 2568 2569 m_previous_dock_action = add_action (window_menu, QIcon (), 2570 tr ("Previous Widget"), SLOT (go_to_previous_widget (void))); 2571 2572 window_menu->addSeparator (); 2573 2574 m_reset_windows_action = add_action (window_menu, QIcon (), 2575 tr ("Reset Default Window Layout"), SLOT (reset_windows (void))); 2576 } 2577 construct_help_menu(QMenuBar * p)2578 void main_window::construct_help_menu (QMenuBar *p) 2579 { 2580 QMenu *help_menu = m_add_menu (p, tr ("&Help")); 2581 2582 construct_documentation_menu (help_menu); 2583 2584 help_menu->addSeparator (); 2585 2586 m_report_bug_action = add_action (help_menu, QIcon (), 2587 tr ("Report Bug"), SLOT (open_bug_tracker_page ())); 2588 2589 m_octave_packages_action = add_action (help_menu, QIcon (), 2590 tr ("Octave Packages"), SLOT (open_octave_packages_page ())); 2591 2592 m_contribute_action = add_action (help_menu, QIcon (), 2593 tr ("Contribute"), SLOT (open_contribute_page ())); 2594 2595 m_developer_action = add_action (help_menu, QIcon (), 2596 tr ("Donate to Octave"), SLOT (open_donate_page ())); 2597 2598 help_menu->addSeparator (); 2599 2600 m_about_octave_action = add_action (help_menu, QIcon (), 2601 tr ("About Octave"), SLOT (show_about_octave ())); 2602 } 2603 construct_documentation_menu(QMenu * p)2604 void main_window::construct_documentation_menu (QMenu *p) 2605 { 2606 QMenu *doc_menu = p->addMenu (tr ("Documentation")); 2607 2608 m_ondisk_doc_action = add_action (doc_menu, QIcon (), 2609 tr ("On Disk"), SLOT (activate ()), m_doc_browser_window); 2610 2611 m_online_doc_action = add_action (doc_menu, QIcon (), 2612 tr ("Online"), SLOT (open_online_documentation_page ())); 2613 } 2614 construct_news_menu(QMenuBar * p)2615 void main_window::construct_news_menu (QMenuBar *p) 2616 { 2617 QMenu *news_menu = m_add_menu (p, tr ("&News")); 2618 2619 m_release_notes_action = add_action (news_menu, QIcon (), 2620 tr ("Release Notes"), SLOT (display_release_notes ())); 2621 2622 m_current_news_action = add_action (news_menu, QIcon (), 2623 tr ("Community News"), SLOT (load_and_display_community_news ())); 2624 } 2625 construct_tool_bar(void)2626 void main_window::construct_tool_bar (void) 2627 { 2628 m_main_tool_bar = addToolBar (tr ("Toolbar")); 2629 m_main_tool_bar->setStyleSheet (m_main_tool_bar->styleSheet () 2630 + global_toolbar_style); 2631 2632 m_main_tool_bar->setObjectName ("MainToolBar"); 2633 m_main_tool_bar->addAction (m_new_script_action); 2634 m_main_tool_bar->addAction (m_open_action); 2635 2636 m_main_tool_bar->addSeparator (); 2637 2638 m_main_tool_bar->addAction (m_copy_action); 2639 m_main_tool_bar->addAction (m_paste_action); 2640 m_main_tool_bar->addAction (m_undo_action); 2641 2642 m_main_tool_bar->addSeparator (); 2643 2644 m_current_directory_combo_box = new QComboBox (this); 2645 QFontMetrics fm = m_current_directory_combo_box->fontMetrics (); 2646 m_current_directory_combo_box->setFixedWidth (48*fm.averageCharWidth ()); 2647 m_current_directory_combo_box->setEditable (true); 2648 m_current_directory_combo_box->setInsertPolicy (QComboBox::NoInsert); 2649 m_current_directory_combo_box->setToolTip (tr ("Enter directory name")); 2650 m_current_directory_combo_box->setMaxVisibleItems (current_directory_max_visible); 2651 m_current_directory_combo_box->setMaxCount (current_directory_max_count); 2652 QSizePolicy sizePol (QSizePolicy::Preferred, QSizePolicy::Preferred); 2653 m_current_directory_combo_box->setSizePolicy (sizePol); 2654 2655 // addWidget takes ownership of the objects so there is no 2656 // need to delete these upon destroying this main_window. 2657 m_main_tool_bar->addWidget (new QLabel (tr ("Current Directory: "))); 2658 m_main_tool_bar->addWidget (m_current_directory_combo_box); 2659 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 2660 QAction *current_dir_up 2661 = m_main_tool_bar->addAction (rmgr.icon ("go-up"), 2662 tr ("One directory up")); 2663 QAction *current_dir_search 2664 = m_main_tool_bar->addAction (rmgr.icon ("folder"), 2665 tr ("Browse directories")); 2666 2667 connect (m_current_directory_combo_box, SIGNAL (activated (QString)), 2668 this, SLOT (set_current_working_directory (QString))); 2669 2670 connect (m_current_directory_combo_box->lineEdit (), SIGNAL (returnPressed (void)), 2671 this, SLOT (accept_directory_line_edit (void))); 2672 2673 connect (current_dir_search, SIGNAL (triggered (void)), 2674 this, SLOT (browse_for_directory (void))); 2675 2676 connect (current_dir_up, SIGNAL (triggered (void)), 2677 this, SLOT (change_directory_up (void))); 2678 2679 connect (m_undo_action, SIGNAL (triggered (void)), 2680 this, SLOT (handle_undo_request (void))); 2681 } 2682 focus_console_after_command(void)2683 void main_window::focus_console_after_command (void) 2684 { 2685 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 2686 gui_settings *settings = rmgr.get_settings (); 2687 if (settings->value (cs_focus_cmd).toBool ()) 2688 focus_command_window (); 2689 } 2690 configure_shortcuts(void)2691 void main_window::configure_shortcuts (void) 2692 { 2693 shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); 2694 2695 // file menu 2696 scmgr.set_shortcut (m_open_action, sc_main_file_open_file); 2697 scmgr.set_shortcut (m_new_script_action, sc_main_file_new_file); 2698 scmgr.set_shortcut (m_new_function_action, sc_main_file_new_function); 2699 scmgr.set_shortcut (m_new_figure_action, sc_main_file_new_figure); 2700 scmgr.set_shortcut (m_load_workspace_action, sc_main_file_load_workspace); 2701 scmgr.set_shortcut (m_save_workspace_action, sc_main_file_save_workspace); 2702 scmgr.set_shortcut (m_exit_action, sc_main_file_exit); 2703 2704 // edit menu 2705 scmgr.set_shortcut (m_copy_action, sc_main_edit_copy); 2706 scmgr.set_shortcut (m_paste_action, sc_main_edit_paste); 2707 scmgr.set_shortcut (m_undo_action, sc_main_edit_undo); 2708 scmgr.set_shortcut (m_select_all_action, sc_main_edit_select_all); 2709 scmgr.set_shortcut (m_clear_clipboard_action, sc_main_edit_clear_clipboard); 2710 scmgr.set_shortcut (m_find_files_action, sc_main_edit_find_in_files); 2711 scmgr.set_shortcut (m_clear_command_history_action, sc_main_edit_clear_history); 2712 scmgr.set_shortcut (m_clear_command_window_action, sc_main_edit_clear_command_window); 2713 scmgr.set_shortcut (m_clear_workspace_action, sc_main_edit_clear_workspace); 2714 scmgr.set_shortcut (m_set_path_action, sc_main_edit_set_path); 2715 scmgr.set_shortcut (m_preferences_action, sc_main_edit_preferences); 2716 2717 // debug menu 2718 scmgr.set_shortcut (m_debug_step_over, sc_main_debug_step_over); 2719 scmgr.set_shortcut (m_debug_step_into, sc_main_debug_step_into); 2720 scmgr.set_shortcut (m_debug_step_out, sc_main_debug_step_out); 2721 scmgr.set_shortcut (m_debug_continue, sc_main_debug_continue); 2722 scmgr.set_shortcut (m_debug_quit, sc_main_debug_quit); 2723 2724 // window menu 2725 scmgr.set_shortcut (m_show_command_window_action, sc_main_window_show_command); 2726 scmgr.set_shortcut (m_show_history_action, sc_main_window_show_history); 2727 scmgr.set_shortcut (m_show_workspace_action, sc_main_window_show_workspace); 2728 scmgr.set_shortcut (m_show_file_browser_action, sc_main_window_show_file_browser); 2729 scmgr.set_shortcut (m_show_editor_action, sc_main_window_show_editor); 2730 scmgr.set_shortcut (m_show_documentation_action, sc_main_window_show_doc); 2731 scmgr.set_shortcut (m_show_variable_editor_action, sc_main_window_show_variable_editor); 2732 scmgr.set_shortcut (m_command_window_action, sc_main_window_command); 2733 scmgr.set_shortcut (m_history_action, sc_main_window_history); 2734 scmgr.set_shortcut (m_workspace_action, sc_main_window_workspace); 2735 scmgr.set_shortcut (m_file_browser_action, sc_main_window_file_browser); 2736 scmgr.set_shortcut (m_editor_action, sc_main_window_editor); 2737 scmgr.set_shortcut (m_documentation_action, sc_main_window_doc); 2738 scmgr.set_shortcut (m_variable_editor_action, sc_main_window_variable_editor); 2739 scmgr.set_shortcut (m_previous_dock_action, sc_main_window_previous_dock); 2740 scmgr.set_shortcut (m_reset_windows_action, sc_main_window_reset); 2741 2742 // help menu 2743 scmgr.set_shortcut (m_ondisk_doc_action, sc_main_help_ondisk_doc); 2744 scmgr.set_shortcut (m_online_doc_action, sc_main_help_online_doc); 2745 scmgr.set_shortcut (m_report_bug_action, sc_main_help_report_bug); 2746 scmgr.set_shortcut (m_octave_packages_action, sc_main_help_packages); 2747 scmgr.set_shortcut (m_contribute_action, sc_main_help_contribute); 2748 scmgr.set_shortcut (m_developer_action, sc_main_help_developer); 2749 scmgr.set_shortcut (m_about_octave_action, sc_main_help_about); 2750 2751 // news menu 2752 scmgr.set_shortcut (m_release_notes_action, sc_main_news_release_notes); 2753 scmgr.set_shortcut (m_current_news_action, sc_main_news_community_news); 2754 } 2755 dock_widget_list(void)2756 QList<octave_dock_widget *> main_window::dock_widget_list (void) 2757 { 2758 QList<octave_dock_widget *> list = QList<octave_dock_widget *> (); 2759 list.append (static_cast<octave_dock_widget *> (m_command_window)); 2760 list.append (static_cast<octave_dock_widget *> (m_history_window)); 2761 list.append (static_cast<octave_dock_widget *> (m_file_browser_window)); 2762 list.append (static_cast<octave_dock_widget *> (m_doc_browser_window)); 2763 #if defined (HAVE_QSCINTILLA) 2764 list.append (static_cast<octave_dock_widget *> (m_editor_window)); 2765 #endif 2766 list.append (static_cast<octave_dock_widget *> (m_workspace_window)); 2767 list.append (static_cast<octave_dock_widget *> (m_variable_editor_window)); 2768 return list; 2769 } 2770 update_default_encoding(const QString & default_encoding)2771 void main_window::update_default_encoding (const QString& default_encoding) 2772 { 2773 m_default_encoding = default_encoding; 2774 std::string mfile_encoding = m_default_encoding.toStdString (); 2775 if (m_default_encoding.startsWith ("SYSTEM", Qt::CaseInsensitive)) 2776 mfile_encoding = "SYSTEM"; 2777 2778 emit interpreter_event 2779 ([mfile_encoding] (interpreter& interp) 2780 { 2781 // INTERPRETER THREAD 2782 2783 F__mfile_encoding__ (interp, ovl (mfile_encoding)); 2784 }); 2785 } 2786 2787 // Get size of screen where the main window is located get_screen_geometry(int * width,int * height)2788 void main_window::get_screen_geometry (int *width, int *height) 2789 { 2790 QRect screen_geometry 2791 = QApplication::desktop ()->availableGeometry (this); 2792 2793 *width = screen_geometry.width (); 2794 *height = screen_geometry.height (); 2795 } 2796 resize_dock(QDockWidget * dw,int width,int height)2797 void main_window::resize_dock (QDockWidget *dw, int width, int height) 2798 { 2799 #if defined (HAVE_QMAINWINDOW_RESIZEDOCKS) 2800 // resizeDockWidget was added to Qt in Qt 5.6 2801 if (width >= 0) 2802 resizeDocks ({dw},{width},Qt::Horizontal); 2803 if (height >= 0) 2804 resizeDocks ({dw},{height},Qt::Vertical); 2805 #else 2806 // This replacement of resizeDockWidget is not very reliable. 2807 // But even if Qt4 is not yet 2808 QSize s = dw->widget ()->size (); 2809 if (width >= 0) 2810 s.setWidth (width); 2811 if (height >= 0) 2812 s.setHeight (height); 2813 dw->widget ()->resize (s); 2814 dw->adjustSize (); 2815 #endif 2816 } 2817 2818 // The default main window size relative to the desktop size set_default_geometry()2819 void main_window::set_default_geometry () 2820 { 2821 int win_x, win_y; 2822 get_screen_geometry (&win_x, &win_y); 2823 2824 move (0, 0); 2825 resize (2*win_x/3, 7*win_y/8); 2826 } 2827 reset_windows(void)2828 void main_window::reset_windows (void) 2829 { 2830 // Slot for resetting the window layout to the default one 2831 hide (); 2832 showNormal (); // Unmaximize 2833 do_reset_windows (false); // Add all widgets 2834 // Re-add after giving time: This seems to be a reliable way to 2835 // reset the main window's layout 2836 QTimer::singleShot (250, this, SLOT (do_reset_windows (void))); 2837 } 2838 2839 // Create the default layout of the main window. Do not use 2840 // restoreState () and restoreGeometry () with default values since 2841 // this might lead to problems when the Qt version changes do_reset_windows(bool show,bool save)2842 void main_window::do_reset_windows (bool show, bool save) 2843 { 2844 // Set main window default geometry and store its width for 2845 // later resizing the command window 2846 set_default_geometry (); 2847 int win_x = geometry ().width (); 2848 2849 // Resize command window, the important one in the default layout 2850 resize_dock (m_command_window, 7*win_x/8, -1); 2851 2852 // See Octave bug #53409 and https://bugreports.qt.io/browse/QTBUG-55357 2853 #if (QT_VERSION < 0x050601) || (QT_VERSION >= 0x050701) 2854 setDockOptions (QMainWindow::AnimatedDocks 2855 | QMainWindow::AllowNestedDocks 2856 | QMainWindow::AllowTabbedDocks); 2857 #else 2858 setDockNestingEnabled (true); 2859 #endif 2860 2861 // Add the dock widgets and show them 2862 addDockWidget (Qt::LeftDockWidgetArea, m_file_browser_window); 2863 addDockWidget (Qt::LeftDockWidgetArea, m_workspace_window); 2864 addDockWidget (Qt::LeftDockWidgetArea, m_history_window); 2865 2866 addDockWidget (Qt::RightDockWidgetArea, m_command_window); 2867 2868 addDockWidget (Qt::RightDockWidgetArea, m_doc_browser_window); 2869 tabifyDockWidget (m_command_window, m_doc_browser_window); 2870 2871 addDockWidget (Qt::RightDockWidgetArea, m_variable_editor_window); 2872 tabifyDockWidget (m_command_window, m_variable_editor_window); 2873 2874 #if defined (HAVE_QSCINTILLA) 2875 addDockWidget (Qt::RightDockWidgetArea, m_editor_window); 2876 tabifyDockWidget (m_command_window, m_editor_window); 2877 #endif 2878 2879 // Resize command window, the important one in the default layout 2880 resize_dock (m_command_window, 2*win_x/3, -1); 2881 2882 // Show main wibdow, save state and geometry of main window and 2883 // all dock widgets 2884 if (show) 2885 { 2886 // Show all dock widgets 2887 for (auto *widget : dock_widget_list ()) 2888 widget->show (); 2889 2890 // Show main window and store size and state 2891 showNormal (); 2892 2893 if (save) 2894 { 2895 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); 2896 gui_settings *settings = rmgr.get_settings (); 2897 2898 settings->setValue (mw_geometry.key, saveGeometry ()); 2899 settings->setValue (mw_state.key, saveState ()); 2900 } 2901 2902 focus_command_window (); 2903 } 2904 } 2905 } 2906