comparison libgui/src/main-window.cc @ 31648:29d734430e5f stable

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