Mercurial > octave
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) |