Mercurial > octave
comparison libgui/src/m-editor/file-editor.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 74c18a1f357b |
comparison
equal
deleted
inserted
replaced
31646:c6d54dd31a7e | 31648:29d734430e5f |
---|---|
63 #include "pt-eval.h" | 63 #include "pt-eval.h" |
64 #include "utils.h" | 64 #include "utils.h" |
65 | 65 |
66 OCTAVE_BEGIN_NAMESPACE(octave) | 66 OCTAVE_BEGIN_NAMESPACE(octave) |
67 | 67 |
68 // Functions of the the reimplemented tab widget | 68 // Functions of the the reimplemented tab widget |
69 | 69 |
70 file_editor_tab_widget::file_editor_tab_widget (QWidget *p, file_editor *fe) | 70 file_editor_tab_widget::file_editor_tab_widget (QWidget *p, file_editor *fe) |
71 : QTabWidget (p) | 71 : QTabWidget (p) |
72 { | 72 { |
73 tab_bar *bar = new tab_bar (this); | 73 tab_bar *bar = new tab_bar (this); |
74 | 74 |
75 connect (bar, &tab_bar::close_current_tab_signal, | 75 connect (bar, &tab_bar::close_current_tab_signal, |
76 fe, &file_editor::request_close_file); | 76 fe, &file_editor::request_close_file); |
77 | 77 |
78 this->setTabBar (bar); | 78 this->setTabBar (bar); |
79 | 79 |
80 setTabsClosable (true); | 80 setTabsClosable (true); |
81 setUsesScrollButtons (true); | 81 setUsesScrollButtons (true); |
82 setMovable (true); | 82 setMovable (true); |
83 } | 83 } |
84 | 84 |
85 tab_bar *file_editor_tab_widget::get_tab_bar (void) const | 85 tab_bar *file_editor_tab_widget::get_tab_bar (void) const |
86 { | 86 { |
87 return qobject_cast<tab_bar *> (tabBar ()); | 87 return qobject_cast<tab_bar *> (tabBar ()); |
88 } | 88 } |
89 | 89 |
90 std::list<file_editor_tab *> | 90 std::list<file_editor_tab *> |
91 file_editor_tab_widget::tab_list (void) const | 91 file_editor_tab_widget::tab_list (void) const |
92 { | 92 { |
93 std::list<file_editor_tab *> retval; | 93 std::list<file_editor_tab *> retval; |
94 for (int i = 0; i < count (); i++) | 94 for (int i = 0; i < count (); i++) |
95 retval.push_back (static_cast<file_editor_tab *> (widget (i))); | 95 retval.push_back (static_cast<file_editor_tab *> (widget (i))); |
96 return retval; | 96 return retval; |
97 } | 97 } |
98 | 98 |
99 // File editor | 99 // File editor |
100 | 100 |
101 file_editor::file_editor (QWidget *p, base_qobject& oct_qobj) | 101 file_editor::file_editor (QWidget *p, base_qobject& oct_qobj) |
102 : file_editor_interface (p, oct_qobj) | 102 : file_editor_interface (p, oct_qobj) |
103 { | 103 { |
104 // Set current editing directory before construction because loaded | 104 // Set current editing directory before construction because loaded |
105 // files will change ced accordingly. | 105 // files will change ced accordingly. |
106 m_ced = QDir::currentPath (); | 106 m_ced = QDir::currentPath (); |
107 | 107 |
108 // Set actions that are later added by the main window to null, | 108 // Set actions that are later added by the main window to null, |
109 // preventing access to them when they are still undefined. | 109 // preventing access to them when they are still undefined. |
110 m_undo_action = nullptr; | 110 m_undo_action = nullptr; |
111 m_copy_action = nullptr; | 111 m_copy_action = nullptr; |
112 m_paste_action = nullptr; | 112 m_paste_action = nullptr; |
113 m_selectall_action = nullptr; | 113 m_selectall_action = nullptr; |
114 | 114 |
115 m_find_dialog = nullptr; | 115 m_find_dialog = nullptr; |
116 | 116 |
117 m_closed = false; | 117 m_closed = false; |
118 m_no_focus = false; | 118 m_no_focus = false; |
119 m_editor_ready = false; | 119 m_editor_ready = false; |
120 | 120 |
121 m_copy_action_enabled = false; | 121 m_copy_action_enabled = false; |
122 m_undo_action_enabled = false; | 122 m_undo_action_enabled = false; |
123 m_current_tab_modified = false; | 123 m_current_tab_modified = false; |
124 | 124 |
125 construct (); | 125 construct (); |
126 | 126 |
127 setVisible (false); | 127 setVisible (false); |
128 setAcceptDrops (true); | 128 setAcceptDrops (true); |
129 setFocusPolicy (Qt::StrongFocus); | 129 setFocusPolicy (Qt::StrongFocus); |
130 } | 130 } |
131 | 131 |
132 void file_editor::focusInEvent (QFocusEvent *e) | 132 void file_editor::focusInEvent (QFocusEvent *e) |
133 { | 133 { |
134 // The focus is transferred to the active tab and its edit | 134 // The focus is transferred to the active tab and its edit |
135 // area in this focus in event handler. This is to avoid | 135 // area in this focus in event handler. This is to avoid |
136 // using focus proxies with conflicts in the proxy change | 136 // using focus proxies with conflicts in the proxy change |
137 // presumably introduced by bug | 137 // presumably introduced by bug |
138 // https://bugreports.qt.io/browse/QTBUG-61092 | 138 // https://bugreports.qt.io/browse/QTBUG-61092 |
139 reset_focus (); // Make sure editor tab with edit area get focus | 139 reset_focus (); // Make sure editor tab with edit area get focus |
140 | 140 |
141 QDockWidget::focusInEvent (e); | 141 QDockWidget::focusInEvent (e); |
142 } | 142 } |
143 | 143 |
144 // insert global actions, that should also be displayed in the editor window, | 144 // insert global actions, that should also be displayed in the editor window, |
145 // into the editor's menu and/or toolbar | 145 // into the editor's menu and/or toolbar |
146 void file_editor::insert_global_actions (QList<QAction *> shared_actions) | 146 void file_editor::insert_global_actions (QList<QAction *> shared_actions) |
147 { | 147 { |
148 // actions/menus that have to be added to the toolbar or the menu | 148 // actions/menus that have to be added to the toolbar or the menu |
149 QAction *open_action = shared_actions.at (OPEN_ACTION); | 149 QAction *open_action = shared_actions.at (OPEN_ACTION); |
150 QAction *new_action = shared_actions.at (NEW_SCRIPT_ACTION); | 150 QAction *new_action = shared_actions.at (NEW_SCRIPT_ACTION); |
151 QAction *new_fcn_action = shared_actions.at (NEW_FUNCTION_ACTION); | 151 QAction *new_fcn_action = shared_actions.at (NEW_FUNCTION_ACTION); |
152 m_fileMenu->insertAction (m_mru_file_menu->menuAction (), open_action); | 152 m_fileMenu->insertAction (m_mru_file_menu->menuAction (), open_action); |
153 m_fileMenu->insertAction (open_action, new_fcn_action); | 153 m_fileMenu->insertAction (open_action, new_fcn_action); |
154 m_fileMenu->insertAction (new_fcn_action, new_action); | 154 m_fileMenu->insertAction (new_fcn_action, new_action); |
155 m_tool_bar->insertAction (m_popdown_mru_action, open_action); | 155 m_tool_bar->insertAction (m_popdown_mru_action, open_action); |
156 m_tool_bar->insertAction (open_action, new_action); | 156 m_tool_bar->insertAction (open_action, new_action); |
157 | 157 |
158 // actions that are additionally enabled/disabled later by the editor | 158 // actions that are additionally enabled/disabled later by the editor |
159 // undo | 159 // undo |
160 m_undo_action = shared_actions.at (UNDO_ACTION); | 160 m_undo_action = shared_actions.at (UNDO_ACTION); |
161 m_tool_bar->insertAction (m_redo_action, m_undo_action); | 161 m_tool_bar->insertAction (m_redo_action, m_undo_action); |
162 m_edit_menu->insertAction (m_redo_action, m_undo_action); | 162 m_edit_menu->insertAction (m_redo_action, m_undo_action); |
163 // select all | 163 // select all |
164 m_selectall_action = shared_actions.at (SELECTALL_ACTION); | 164 m_selectall_action = shared_actions.at (SELECTALL_ACTION); |
165 m_edit_menu->insertAction (m_find_action, m_selectall_action); | 165 m_edit_menu->insertAction (m_find_action, m_selectall_action); |
166 m_edit_menu->insertSeparator (m_find_action); | 166 m_edit_menu->insertSeparator (m_find_action); |
167 // paste | 167 // paste |
168 m_paste_action = shared_actions.at (PASTE_ACTION); | 168 m_paste_action = shared_actions.at (PASTE_ACTION); |
169 m_tool_bar->insertAction (m_find_action, m_paste_action); | 169 m_tool_bar->insertAction (m_find_action, m_paste_action); |
170 m_edit_menu->insertAction (m_selectall_action, m_paste_action); | 170 m_edit_menu->insertAction (m_selectall_action, m_paste_action); |
171 m_edit_menu->insertSeparator (m_selectall_action); | 171 m_edit_menu->insertSeparator (m_selectall_action); |
172 // copy | 172 // copy |
173 m_copy_action = shared_actions.at (COPY_ACTION); | 173 m_copy_action = shared_actions.at (COPY_ACTION); |
174 m_tool_bar->insertAction (m_paste_action, m_copy_action); | 174 m_tool_bar->insertAction (m_paste_action, m_copy_action); |
175 m_edit_menu->insertAction (m_paste_action, m_copy_action); | 175 m_edit_menu->insertAction (m_paste_action, m_copy_action); |
176 // find files | 176 // find files |
177 m_find_files_action = shared_actions.at (FIND_FILES_ACTION); | 177 m_find_files_action = shared_actions.at (FIND_FILES_ACTION); |
178 m_edit_menu->insertAction (m_find_action, m_find_files_action); | 178 m_edit_menu->insertAction (m_find_action, m_find_files_action); |
179 } | 179 } |
180 | 180 |
181 void file_editor::handle_enter_debug_mode (void) | 181 void file_editor::handle_enter_debug_mode (void) |
182 { | 182 { |
183 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | 183 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); |
184 gui_settings *settings = rmgr.get_settings (); | 184 gui_settings *settings = rmgr.get_settings (); |
185 QString sc_run = settings->sc_value (sc_edit_run_run_file); | 185 QString sc_run = settings->sc_value (sc_edit_run_run_file); |
186 QString sc_cont = settings->sc_value (sc_main_debug_continue); | 186 QString sc_cont = settings->sc_value (sc_main_debug_continue); |
187 | 187 |
188 if (sc_run == sc_cont) | 188 if (sc_run == sc_cont) |
189 m_run_action->setShortcut (QKeySequence ()); // prevent ambiguous shortcuts | 189 m_run_action->setShortcut (QKeySequence ()); // prevent ambiguous shortcuts |
190 | 190 |
191 m_run_action->setToolTip (tr ("Continue")); // update tool tip | 191 m_run_action->setToolTip (tr ("Continue")); // update tool tip |
192 | 192 |
193 emit enter_debug_mode_signal (); | 193 emit enter_debug_mode_signal (); |
194 } | 194 } |
195 | 195 |
196 void file_editor::handle_exit_debug_mode (void) | 196 void file_editor::handle_exit_debug_mode (void) |
197 { | 197 { |
198 shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); | 198 shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); |
199 scmgr.set_shortcut (m_run_action, sc_edit_run_run_file); | 199 scmgr.set_shortcut (m_run_action, sc_edit_run_run_file); |
200 m_run_action->setToolTip (tr ("Save File and Run")); // update tool tip | 200 m_run_action->setToolTip (tr ("Save File and Run")); // update tool tip |
201 | 201 |
202 emit exit_debug_mode_signal (); | 202 emit exit_debug_mode_signal (); |
203 } | 203 } |
204 | 204 |
205 void file_editor::check_actions (void) | 205 void file_editor::check_actions (void) |
206 { | 206 { |
207 // Do not include shared actions not only related to the editor | 207 // Do not include shared actions not only related to the editor |
208 bool have_tabs = m_tab_widget->count () > 0; | 208 bool have_tabs = m_tab_widget->count () > 0; |
209 | 209 |
210 m_edit_cmd_menu->setEnabled (have_tabs); | 210 m_edit_cmd_menu->setEnabled (have_tabs); |
211 m_edit_fmt_menu->setEnabled (have_tabs); | 211 m_edit_fmt_menu->setEnabled (have_tabs); |
212 m_edit_nav_menu->setEnabled (have_tabs); | 212 m_edit_nav_menu->setEnabled (have_tabs); |
213 | 213 |
214 m_comment_selection_action->setEnabled (have_tabs); | 214 m_comment_selection_action->setEnabled (have_tabs); |
215 m_uncomment_selection_action->setEnabled (have_tabs); | 215 m_uncomment_selection_action->setEnabled (have_tabs); |
216 m_comment_var_selection_action->setEnabled (have_tabs); | 216 m_comment_var_selection_action->setEnabled (have_tabs); |
217 m_indent_selection_action->setEnabled (have_tabs); | 217 m_indent_selection_action->setEnabled (have_tabs); |
218 m_unindent_selection_action->setEnabled (have_tabs); | 218 m_unindent_selection_action->setEnabled (have_tabs); |
219 m_smart_indent_line_or_selection_action->setEnabled (have_tabs); | 219 m_smart_indent_line_or_selection_action->setEnabled (have_tabs); |
220 | 220 |
221 m_context_help_action->setEnabled (have_tabs); | 221 m_context_help_action->setEnabled (have_tabs); |
222 m_context_doc_action->setEnabled (have_tabs); | 222 m_context_doc_action->setEnabled (have_tabs); |
223 | 223 |
224 m_view_editor_menu->setEnabled (have_tabs); | 224 m_view_editor_menu->setEnabled (have_tabs); |
225 m_zoom_in_action->setEnabled (have_tabs); | 225 m_zoom_in_action->setEnabled (have_tabs); |
226 m_zoom_out_action->setEnabled (have_tabs); | 226 m_zoom_out_action->setEnabled (have_tabs); |
227 m_zoom_normal_action->setEnabled (have_tabs); | 227 m_zoom_normal_action->setEnabled (have_tabs); |
228 | 228 |
229 m_find_action->setEnabled (have_tabs); | 229 m_find_action->setEnabled (have_tabs); |
230 m_find_next_action->setEnabled (have_tabs); | 230 m_find_next_action->setEnabled (have_tabs); |
231 m_find_previous_action->setEnabled (have_tabs); | 231 m_find_previous_action->setEnabled (have_tabs); |
232 m_print_action->setEnabled (have_tabs); | 232 m_print_action->setEnabled (have_tabs); |
233 | 233 |
234 m_run_action->setEnabled (have_tabs && m_is_octave_file); | 234 m_run_action->setEnabled (have_tabs && m_is_octave_file); |
235 | 235 |
236 m_toggle_breakpoint_action->setEnabled (have_tabs && m_is_octave_file); | 236 m_toggle_breakpoint_action->setEnabled (have_tabs && m_is_octave_file); |
237 m_next_breakpoint_action->setEnabled (have_tabs && m_is_octave_file); | 237 m_next_breakpoint_action->setEnabled (have_tabs && m_is_octave_file); |
238 m_previous_breakpoint_action->setEnabled (have_tabs && m_is_octave_file); | 238 m_previous_breakpoint_action->setEnabled (have_tabs && m_is_octave_file); |
239 m_remove_all_breakpoints_action->setEnabled (have_tabs && m_is_octave_file); | 239 m_remove_all_breakpoints_action->setEnabled (have_tabs && m_is_octave_file); |
240 | 240 |
241 m_edit_function_action->setEnabled (have_tabs); | 241 m_edit_function_action->setEnabled (have_tabs); |
242 m_save_action->setEnabled (have_tabs && m_current_tab_modified); | 242 m_save_action->setEnabled (have_tabs && m_current_tab_modified); |
243 m_save_as_action->setEnabled (have_tabs); | 243 m_save_as_action->setEnabled (have_tabs); |
244 m_close_action->setEnabled (have_tabs); | 244 m_close_action->setEnabled (have_tabs); |
245 m_close_all_action->setEnabled (have_tabs); | 245 m_close_all_action->setEnabled (have_tabs); |
246 m_close_others_action->setEnabled (have_tabs && m_tab_widget->count () > 1); | 246 m_close_others_action->setEnabled (have_tabs && m_tab_widget->count () > 1); |
247 m_sort_tabs_action->setEnabled (have_tabs && m_tab_widget->count () > 1); | 247 m_sort_tabs_action->setEnabled (have_tabs && m_tab_widget->count () > 1); |
248 | 248 |
249 emit editor_tabs_changed_signal (have_tabs, m_is_octave_file); | 249 emit editor_tabs_changed_signal (have_tabs, m_is_octave_file); |
250 } | 250 } |
251 | 251 |
252 // empty_script determines whether we have to create an empty script | 252 // empty_script determines whether we have to create an empty script |
253 // 1. At startup, when the editor has to be (really) visible | 253 // 1. At startup, when the editor has to be (really) visible |
254 // (Here we can not use the visibility changed signal) | 254 // (Here we can not use the visibility changed signal) |
255 // 2. When the editor becomes visible when octave is running | 255 // 2. When the editor becomes visible when octave is running |
256 void file_editor::empty_script (bool startup, bool visible) | 256 void file_editor::empty_script (bool startup, bool visible) |
257 { | 257 { |
258 | 258 |
259 if (startup) | 259 if (startup) |
260 m_editor_ready = true; | 260 m_editor_ready = true; |
261 else | 261 else |
262 { | 262 { |
263 if (! m_editor_ready) | 263 if (! m_editor_ready) |
264 return; // not yet ready but got visibility changed signals | 264 return; // not yet ready but got visibility changed signals |
265 } | 265 } |
266 | 266 |
267 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | 267 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); |
268 gui_settings *settings = rmgr.get_settings (); | 268 gui_settings *settings = rmgr.get_settings (); |
269 if (settings->value (global_use_custom_editor.key, | 269 if (settings->value (global_use_custom_editor.key, |
270 global_use_custom_editor.def).toBool ()) | 270 global_use_custom_editor.def).toBool ()) |
271 return; // do not open an empty script in the external editor | 271 return; // do not open an empty script in the external editor |
272 | 272 |
273 bool real_visible; | 273 bool real_visible; |
274 | 274 |
275 if (startup) | 275 if (startup) |
276 real_visible = isVisible (); | 276 real_visible = isVisible (); |
277 else | 277 else |
278 real_visible = visible; | 278 real_visible = visible; |
279 | 279 |
280 if (! real_visible || m_tab_widget->count () > 0) | 280 if (! real_visible || m_tab_widget->count () > 0) |
281 return; | |
282 | |
283 if (startup && ! isFloating ()) | |
284 { | |
285 // check if editor is really visible or hidden between tabbed widgets | |
286 QWidget *parent = parentWidget (); | |
287 | |
288 if (parent) | |
289 { | |
290 QList<QTabBar *> tab_list = parent->findChildren<QTabBar *>(); | |
291 | |
292 bool in_tab = false; | |
293 int i = 0; | |
294 while ((i < tab_list.count ()) && (! in_tab)) | |
295 { | |
296 QTabBar *tab = tab_list.at (i); | |
297 i++; | |
298 | |
299 int j = 0; | |
300 while ((j < tab->count ()) && (! in_tab)) | |
301 { | |
302 // check all tabs for the editor | |
303 if (tab->tabText (j) == windowTitle ()) | |
304 { | |
305 // editor is in this tab widget | |
306 in_tab = true; | |
307 int top = tab->currentIndex (); | |
308 if (! (top > -1 && tab->tabText (top) == windowTitle ())) | |
309 return; // not current tab -> not visible | |
310 } | |
311 j++; | |
312 } | |
313 } | |
314 } | |
315 } | |
316 | |
317 request_new_file (""); | |
318 } | |
319 | |
320 void file_editor::restore_session (gui_settings *settings) | |
321 { | |
322 //restore previous session | |
323 if (! settings->value (ed_restore_session).toBool ()) | |
324 return; | |
325 | |
326 // get the data from the settings file | |
327 QStringList sessionFileNames | |
328 = settings->value (ed_session_names).toStringList (); | |
329 | |
330 QStringList session_encodings | |
331 = settings->value (ed_session_enc).toStringList (); | |
332 | |
333 QStringList session_index | |
334 = settings->value (ed_session_ind).toStringList (); | |
335 | |
336 QStringList session_lines | |
337 = settings->value (ed_session_lines).toStringList (); | |
338 | |
339 QStringList session_bookmarks | |
340 = settings->value (ed_session_bookmarks).toStringList (); | |
341 | |
342 // fill a list of the struct and sort it (depending on index) | |
343 QList<session_data> s_data; | |
344 | |
345 bool do_encoding = (session_encodings.count () == sessionFileNames.count ()); | |
346 bool do_index = (session_index.count () == sessionFileNames.count ()); | |
347 bool do_lines = (session_lines.count () == sessionFileNames.count ()); | |
348 bool do_bookmarks = (session_bookmarks.count () == sessionFileNames.count ()); | |
349 | |
350 for (int n = 0; n < sessionFileNames.count (); ++n) | |
351 { | |
352 QFileInfo file = QFileInfo (sessionFileNames.at (n)); | |
353 if (! file.exists ()) | |
354 continue; | |
355 | |
356 session_data item = { 0, -1, sessionFileNames.at (n), | |
357 QString (), QString (), QString ()}; | |
358 if (do_lines) | |
359 item.line = session_lines.at (n).toInt (); | |
360 if (do_index) | |
361 item.index = session_index.at (n).toInt (); | |
362 if (do_encoding) | |
363 item.encoding = session_encodings.at (n); | |
364 if (do_bookmarks) | |
365 item.bookmarks = session_bookmarks.at (n); | |
366 | |
367 s_data << item; | |
368 } | |
369 | |
370 std::sort (s_data.begin (), s_data.end ()); | |
371 | |
372 // finally open the files with the desired encoding in the desired order | |
373 for (int n = 0; n < s_data.count (); ++n) | |
374 request_open_file (s_data.at (n).file_name, s_data.at (n).encoding, | |
375 s_data.at (n).line, false, false, true, "", -1, | |
376 s_data.at (n).bookmarks); | |
377 } | |
378 | |
379 void file_editor::activate (void) | |
380 { | |
381 if (m_no_focus) | |
382 return; // No focus for the editor if external open/close request | |
383 | |
384 octave_dock_widget::activate (); | |
385 | |
386 // set focus to current tab | |
387 reset_focus (); | |
388 } | |
389 | |
390 void file_editor::set_focus (QWidget *fet) | |
391 { | |
392 setFocus (); | |
393 | |
394 // set focus to desired tab | |
395 if (fet) | |
396 m_tab_widget->setCurrentWidget (fet); | |
397 } | |
398 | |
399 // function enabling/disabling the menu accelerators depending on the | |
400 // focus of the editor | |
401 void file_editor::enable_menu_shortcuts (bool enable) | |
402 { | |
403 // Hide or show the find dialog together with the focus of the | |
404 // editor widget depending on the overall visibility of the find dialog. | |
405 // Do not change internal visibility state. | |
406 if (m_find_dialog) | |
407 m_find_dialog->set_visible (enable); | |
408 | |
409 // Take care of the shortcuts | |
410 QHash<QMenu *, QStringList>::const_iterator i = m_hash_menu_text.constBegin (); | |
411 | |
412 while (i != m_hash_menu_text.constEnd ()) | |
413 { | |
414 i.key ()->setTitle (i.value ().at (! enable)); | |
415 ++i; | |
416 } | |
417 | |
418 // when editor loses focus, enable the actions, which are always active | |
419 // in the main window due to missing info on selected text and undo actions | |
420 if (m_copy_action && m_undo_action) | |
421 { | |
422 if (enable) | |
423 { | |
424 m_copy_action->setEnabled (m_copy_action_enabled); | |
425 m_undo_action->setEnabled (m_undo_action_enabled); | |
426 } | |
427 else | |
428 { | |
429 m_copy_action_enabled = m_copy_action->isEnabled (); | |
430 m_undo_action_enabled = m_undo_action->isEnabled (); | |
431 m_copy_action->setEnabled (true); | |
432 m_undo_action->setEnabled (true); | |
433 } | |
434 } | |
435 } | |
436 | |
437 // Save open files for restoring in next session | |
438 // (even if last session will not be restored next time) | |
439 // together with encoding and the tab index | |
440 void file_editor::save_session (void) | |
441 { | |
442 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
443 gui_settings *settings = rmgr.get_settings (); | |
444 | |
445 QStringList fetFileNames; | |
446 QStringList fet_encodings; | |
447 QStringList fet_index; | |
448 QStringList fet_lines; | |
449 QStringList fet_bookmarks; | |
450 | |
451 std::list<file_editor_tab *> editor_tab_lst = m_tab_widget->tab_list (); | |
452 | |
453 for (auto editor_tab : editor_tab_lst) | |
454 { | |
455 QString file_name = editor_tab->file_name (); | |
456 | |
457 // Don't append unnamed files. | |
458 | |
459 if (! file_name.isEmpty ()) | |
460 { | |
461 fetFileNames.append (file_name); | |
462 fet_encodings.append (editor_tab->encoding ()); | |
463 | |
464 QString index; | |
465 fet_index.append (index.setNum (m_tab_widget->indexOf (editor_tab))); | |
466 | |
467 int l, c; | |
468 editor_tab->qsci_edit_area ()->getCursorPosition (&l, &c); | |
469 fet_lines.append (index.setNum (l + 1)); | |
470 | |
471 fet_bookmarks.append (editor_tab->get_all_bookmarks ()); | |
472 } | |
473 } | |
474 | |
475 settings->setValue (ed_session_names.key, fetFileNames); | |
476 settings->setValue (ed_session_enc.key, fet_encodings); | |
477 settings->setValue (ed_session_ind.key, fet_index); | |
478 settings->setValue (ed_session_lines.key, fet_lines); | |
479 settings->setValue (ed_session_bookmarks.key, fet_bookmarks); | |
480 settings->sync (); | |
481 } | |
482 | |
483 bool file_editor::check_closing (void) | |
484 { | |
485 // When the application or the editor is closing and the user wants to | |
486 // close all files, in the latter case all editor tabs are checked whether | |
487 // they need to be saved. During these checks tabs are not closed since | |
488 // the user might cancel closing Octave during one of these saving dialogs. | |
489 // Therefore, saving the session for restoring at next start is not done | |
490 // before the application is definitely closing. | |
491 | |
492 // Save the session. Even is closing is cancelled, this would be | |
493 // overwritten by the next attempt to close the editor | |
494 save_session (); | |
495 | |
496 std::list<file_editor_tab *> fe_tab_lst = m_tab_widget->tab_list (); | |
497 m_number_of_tabs = fe_tab_lst.size (); | |
498 | |
499 for (auto fe_tab : fe_tab_lst) | |
500 { | |
501 // Wait for all editor tabs to have saved their files if required | |
502 | |
503 connect (fe_tab, &file_editor_tab::tab_ready_to_close, | |
504 this, &file_editor::handle_tab_ready_to_close, | |
505 Qt::UniqueConnection); | |
506 } | |
507 | |
508 m_closing_canceled = false; | |
509 | |
510 for (auto fe_tab : fe_tab_lst) | |
511 { | |
512 // If there was a cancellation, make the already saved/discarded tabs | |
513 // recover from the exit by removing the read-only state and by | |
514 // recovering the debugger breakpoints. Finally return false in order | |
515 // to cancel closing the application or the editor. | |
516 | |
517 if (fe_tab->check_file_modified (false) == QMessageBox::Cancel) | |
518 { | |
519 emit fetab_recover_from_exit (); | |
520 | |
521 m_closing_canceled = true; | |
522 | |
523 for (auto fet : fe_tab_lst) | |
524 disconnect (fet, &file_editor_tab::tab_ready_to_close, 0, 0); | |
525 | |
526 return false; | |
527 } | |
528 } | |
529 | |
530 return true; | |
531 } | |
532 | |
533 void file_editor::handle_tab_ready_to_close (void) | |
534 { | |
535 if (m_closing_canceled) | |
536 return; | |
537 | |
538 // FIXME: Why count down to zero here before doing anything? Why | |
539 // not remove and delete each tab that is ready to be closed, one | |
540 // per invocation? | |
541 | |
542 m_number_of_tabs--; | |
543 | |
544 if (m_number_of_tabs > 0) | |
545 return; | |
546 | |
547 // Here, the application or the editor will be closed -> store the session | |
548 | |
549 // Take care of the find dialog | |
550 if (m_find_dialog) | |
551 m_find_dialog->close (); | |
552 | |
553 // Finally close all the tabs and return indication that we can exit | |
554 // the application or close the editor. | |
555 // Closing and deleting the tabs makes the editor visible. In case it was | |
556 // hidden before, this state has to be restored afterwards. | |
557 bool vis = isVisible (); | |
558 | |
559 std::list<file_editor_tab *> editor_tab_lst = m_tab_widget->tab_list (); | |
560 for (auto editor_tab : editor_tab_lst) | |
561 editor_tab->deleteLater (); | |
562 | |
563 m_tab_widget->clear (); | |
564 | |
565 setVisible (vis); | |
566 } | |
567 | |
568 void file_editor::request_new_file (const QString& commands) | |
569 { | |
570 // Custom editor? If yes, we can only call the editor without passing | |
571 // some initial contents and even without being sure a new file is opened | |
572 if (call_custom_editor ()) | |
573 return; | |
574 | |
575 // New file isn't a file_editor_tab function since the file | |
576 // editor tab has yet to be created and there is no object to | |
577 // pass a signal to. Hence, functionality is here. | |
578 | |
579 file_editor_tab *fileEditorTab = make_file_editor_tab (m_ced); | |
580 add_file_editor_tab (fileEditorTab, ""); // new tab with empty title | |
581 fileEditorTab->new_file (commands); // title is updated here | |
582 activate (); // focus editor and new tab | |
583 } | |
584 | |
585 void file_editor::request_close_file (bool) | |
586 { | |
587 file_editor_tab *editor_tab | |
588 = static_cast<file_editor_tab *> (m_tab_widget->currentWidget ()); | |
589 editor_tab->conditional_close (); | |
590 } | |
591 | |
592 void file_editor::request_close_all_files (bool) | |
593 { | |
594 file_editor_tab *editor_tab; | |
595 | |
596 // loop over all tabs starting from last one otherwise deletion changes index | |
597 for (int index = m_tab_widget->count ()-1; index >= 0; index--) | |
598 { | |
599 editor_tab = static_cast<file_editor_tab *> (m_tab_widget->widget (index)); | |
600 editor_tab->conditional_close (); | |
601 } | |
602 } | |
603 | |
604 void file_editor::request_close_other_files (bool) | |
605 { | |
606 file_editor_tab *editor_tab; | |
607 QWidget *tabID = m_tab_widget->currentWidget (); | |
608 | |
609 // loop over all tabs starting from last one otherwise deletion changes index | |
610 for (int index = m_tab_widget->count ()-1; index >= 0; index--) | |
611 { | |
612 if (tabID != m_tab_widget->widget (index)) | |
613 { | |
614 editor_tab | |
615 = static_cast<file_editor_tab *> (m_tab_widget->widget (index)); | |
616 editor_tab->conditional_close (); | |
617 } | |
618 } | |
619 } | |
620 | |
621 void file_editor::copy_full_file_path (bool) | |
622 { | |
623 file_editor_tab *editor_tab | |
624 = static_cast<file_editor_tab *> (m_tab_widget->currentWidget ()); | |
625 | |
626 if (editor_tab) | |
627 QGuiApplication::clipboard ()->setText (editor_tab->file_name ()); | |
628 } | |
629 | |
630 // open a file from the mru list | |
631 void file_editor::request_mru_open_file (QAction *action) | |
632 { | |
633 if (action) | |
634 { | |
635 request_open_file (action->data ().toStringList ().at (0), | |
636 action->data ().toStringList ().at (1)); | |
637 } | |
638 } | |
639 | |
640 void file_editor::request_print_file (bool) | |
641 { | |
642 emit fetab_print_file (m_tab_widget->currentWidget ()); | |
643 } | |
644 | |
645 void file_editor::request_redo (bool) | |
646 { | |
647 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
648 QsciScintillaBase::SCI_REDO); | |
649 } | |
650 | |
651 void file_editor::request_cut (bool) | |
652 { | |
653 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
654 QsciScintillaBase::SCI_CUT); | |
655 } | |
656 | |
657 void file_editor::request_context_help (bool) | |
658 { | |
659 emit fetab_context_help (m_tab_widget->currentWidget (), false); | |
660 } | |
661 | |
662 void file_editor::request_context_doc (bool) | |
663 { | |
664 emit fetab_context_help (m_tab_widget->currentWidget (), true); | |
665 } | |
666 | |
667 void file_editor::request_context_edit (bool) | |
668 { | |
669 emit fetab_context_edit (m_tab_widget->currentWidget ()); | |
670 } | |
671 | |
672 void file_editor::request_save_file (bool) | |
673 { | |
674 emit fetab_save_file (m_tab_widget->currentWidget ()); | |
675 } | |
676 | |
677 void file_editor::request_save_file_as (bool) | |
678 { | |
679 emit fetab_save_file_as (m_tab_widget->currentWidget ()); | |
680 } | |
681 | |
682 void file_editor::request_run_file (bool) | |
683 { | |
684 emit interpreter_event | |
685 ([=] (interpreter& interp) | |
686 { | |
687 // INTERPRETER THREAD | |
688 | |
689 // Act as though this action was entered at the command propmt | |
690 // so that the interpreter will check for updated file time | |
691 // stamps. | |
692 Vlast_prompt_time.stamp (); | |
693 | |
694 tree_evaluator& tw = interp.get_evaluator (); | |
695 | |
696 if (tw.in_debug_repl ()) | |
697 emit request_dbcont_signal (); | |
698 else | |
699 emit fetab_run_file (m_tab_widget->currentWidget ()); | |
700 }); | |
701 } | |
702 | |
703 void file_editor::request_step_into_file () | |
704 { | |
705 emit fetab_run_file (m_tab_widget->currentWidget (), true); | |
706 } | |
707 | |
708 void file_editor::request_context_run (bool) | |
709 { | |
710 emit fetab_context_run (m_tab_widget->currentWidget ()); | |
711 } | |
712 | |
713 void file_editor::request_toggle_bookmark (bool) | |
714 { | |
715 emit fetab_toggle_bookmark (m_tab_widget->currentWidget ()); | |
716 } | |
717 | |
718 void file_editor::request_next_bookmark (bool) | |
719 { | |
720 emit fetab_next_bookmark (m_tab_widget->currentWidget ()); | |
721 } | |
722 | |
723 void file_editor::request_previous_bookmark (bool) | |
724 { | |
725 emit fetab_previous_bookmark (m_tab_widget->currentWidget ()); | |
726 } | |
727 | |
728 void file_editor::request_remove_bookmark (bool) | |
729 { | |
730 emit fetab_remove_bookmark (m_tab_widget->currentWidget ()); | |
731 } | |
732 | |
733 void file_editor::request_move_match_brace (bool) | |
734 { | |
735 emit fetab_move_match_brace (m_tab_widget->currentWidget (), false); | |
736 } | |
737 | |
738 void file_editor::request_sel_match_brace (bool) | |
739 { | |
740 emit fetab_move_match_brace (m_tab_widget->currentWidget (), true); | |
741 } | |
742 | |
743 // FIXME: What should this do with conditional breakpoints? | |
744 void file_editor::request_toggle_breakpoint (bool) | |
745 { | |
746 emit fetab_toggle_breakpoint (m_tab_widget->currentWidget ()); | |
747 } | |
748 | |
749 void file_editor::request_next_breakpoint (bool) | |
750 { | |
751 emit fetab_next_breakpoint (m_tab_widget->currentWidget ()); | |
752 } | |
753 | |
754 void file_editor::request_previous_breakpoint (bool) | |
755 { | |
756 emit fetab_previous_breakpoint (m_tab_widget->currentWidget ()); | |
757 } | |
758 | |
759 void file_editor::request_remove_breakpoint (bool) | |
760 { | |
761 emit fetab_remove_all_breakpoints (m_tab_widget->currentWidget ()); | |
762 } | |
763 | |
764 // slots for Edit->Commands actions | |
765 void file_editor::request_delete_start_word (bool) | |
766 { | |
767 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
768 QsciScintillaBase::SCI_DELWORDLEFT); | |
769 } | |
770 | |
771 void file_editor::request_delete_end_word (bool) | |
772 { | |
773 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
774 QsciScintillaBase::SCI_DELWORDRIGHT); | |
775 } | |
776 | |
777 void file_editor::request_delete_start_line (bool) | |
778 { | |
779 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
780 QsciScintillaBase::SCI_DELLINELEFT); | |
781 } | |
782 | |
783 void file_editor::request_delete_end_line (bool) | |
784 { | |
785 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
786 QsciScintillaBase::SCI_DELLINERIGHT); | |
787 } | |
788 | |
789 void file_editor::request_delete_line (bool) | |
790 { | |
791 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
792 QsciScintillaBase::SCI_LINEDELETE); | |
793 } | |
794 | |
795 void file_editor::request_copy_line (bool) | |
796 { | |
797 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
798 QsciScintillaBase::SCI_LINECOPY); | |
799 } | |
800 | |
801 void file_editor::request_cut_line (bool) | |
802 { | |
803 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
804 QsciScintillaBase::SCI_LINECUT); | |
805 } | |
806 | |
807 void file_editor::request_duplicate_selection (bool) | |
808 { | |
809 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
810 QsciScintillaBase::SCI_SELECTIONDUPLICATE); | |
811 } | |
812 | |
813 void file_editor::request_transpose_line (bool) | |
814 { | |
815 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
816 QsciScintillaBase::SCI_LINETRANSPOSE); | |
817 } | |
818 | |
819 void file_editor::request_comment_selected_text (bool) | |
820 { | |
821 emit fetab_comment_selected_text (m_tab_widget->currentWidget (), false); | |
822 } | |
823 | |
824 void file_editor::request_uncomment_selected_text (bool) | |
825 { | |
826 emit fetab_uncomment_selected_text (m_tab_widget->currentWidget ()); | |
827 } | |
828 | |
829 void file_editor::request_comment_var_selected_text (bool) | |
830 { | |
831 emit fetab_comment_selected_text (m_tab_widget->currentWidget (), true); | |
832 } | |
833 | |
834 // slots for Edit->Format actions | |
835 void file_editor::request_upper_case (bool) | |
836 { | |
837 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
838 QsciScintillaBase::SCI_UPPERCASE); | |
839 } | |
840 | |
841 void file_editor::request_lower_case (bool) | |
842 { | |
843 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
844 QsciScintillaBase::SCI_LOWERCASE); | |
845 } | |
846 | |
847 void file_editor::request_indent_selected_text (bool) | |
848 { | |
849 emit fetab_indent_selected_text (m_tab_widget->currentWidget ()); | |
850 } | |
851 | |
852 void file_editor::request_unindent_selected_text (bool) | |
853 { | |
854 emit fetab_unindent_selected_text (m_tab_widget->currentWidget ()); | |
855 } | |
856 | |
857 void file_editor::request_smart_indent_line_or_selected_text () | |
858 { | |
859 emit fetab_smart_indent_line_or_selected_text (m_tab_widget->currentWidget ()); | |
860 } | |
861 | |
862 void file_editor::request_conv_eol_windows (bool) | |
863 { | |
864 emit fetab_convert_eol (m_tab_widget->currentWidget (), | |
865 QsciScintilla::EolWindows); | |
866 } | |
867 void | |
868 file_editor::request_conv_eol_unix (bool) | |
869 { | |
870 emit fetab_convert_eol (m_tab_widget->currentWidget (), | |
871 QsciScintilla::EolUnix); | |
872 } | |
873 | |
874 void file_editor::request_conv_eol_mac (bool) | |
875 { | |
876 emit fetab_convert_eol (m_tab_widget->currentWidget (), | |
877 QsciScintilla::EolMac); | |
878 } | |
879 | |
880 // Slot for initially creating and showing the find dialog | |
881 void file_editor::request_find (bool) | |
882 { | |
883 // Create the dialog | |
884 find_create (); | |
885 | |
886 // Since find_create shows the dialog without activating the widget | |
887 // (which is reuqired in other cases) do this manually here | |
888 m_find_dialog->activateWindow (); | |
889 | |
890 // Initiate search text from possible selection and save the initial | |
891 // data from the dialog on the defined structure | |
892 m_find_dialog->init_search_text (); | |
893 } | |
894 | |
895 // This method creates the find dialog. | |
896 | |
897 void file_editor::find_create () | |
898 { | |
899 if (m_find_dialog) | |
900 m_find_dialog->close (); | |
901 | |
902 if (isFloating ()) | |
903 m_find_dialog = new find_dialog (m_octave_qobj, this, this); | |
904 else | |
905 m_find_dialog = new find_dialog (m_octave_qobj, this, parentWidget ()); | |
906 | |
907 // Add required actions | |
908 m_find_dialog->addAction (m_find_next_action); | |
909 m_find_dialog->addAction (m_find_previous_action); | |
910 | |
911 // Update edit area | |
912 file_editor_tab *fet | |
913 = static_cast<file_editor_tab *> (m_tab_widget->currentWidget ()); | |
914 m_find_dialog->update_edit_area (fet->qsci_edit_area ()); | |
915 | |
916 // Icon is the same as the editor | |
917 m_find_dialog->setWindowIcon (windowIcon ()); | |
918 | |
919 // Position: lower right of editor's position | |
920 int xp = x () + frameGeometry ().width (); | |
921 int yp = y () + frameGeometry ().height (); | |
922 | |
923 if (! isFloating ()) | |
924 { | |
925 // Fix position if editor is docked | |
926 | |
927 QWidget *parent = parentWidget (); | |
928 | |
929 if (parent) | |
930 { | |
931 xp = xp + parent->x (); | |
932 yp = yp + parent->y (); | |
933 } | |
934 } | |
935 | |
936 if (yp < 0) | |
937 yp = 0; | |
938 | |
939 // The size of the find dialog is considered in restore_settings | |
940 // since its size might change depending on the options | |
941 m_find_dialog->restore_settings (QPoint (xp, yp)); | |
942 | |
943 // Set visible | |
944 m_find_dialog->set_visible (true); | |
945 } | |
946 | |
947 void file_editor::request_find_next (bool) | |
948 { | |
949 if (m_find_dialog) | |
950 m_find_dialog->find_next (); | |
951 } | |
952 | |
953 void file_editor::request_find_previous (bool) | |
954 { | |
955 if (m_find_dialog) | |
956 m_find_dialog->find_prev (); | |
957 } | |
958 | |
959 void file_editor::request_goto_line (bool) | |
960 { | |
961 emit fetab_goto_line (m_tab_widget->currentWidget ()); | |
962 } | |
963 | |
964 void file_editor::request_completion (bool) | |
965 { | |
966 emit fetab_completion (m_tab_widget->currentWidget ()); | |
967 } | |
968 | |
969 void file_editor::handle_file_name_changed (const QString& fname, | |
970 const QString& tip, | |
971 bool modified) | |
972 { | |
973 QObject *fileEditorTab = sender (); | |
974 if (fileEditorTab) | |
975 { | |
976 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
977 | |
978 for (int i = 0; i < m_tab_widget->count (); i++) | |
979 { | |
980 if (m_tab_widget->widget (i) == fileEditorTab) | |
981 { | |
982 m_tab_widget->setTabText (i, fname); | |
983 m_tab_widget->setTabToolTip (i, tip); | |
984 | |
985 m_save_action->setEnabled (modified); | |
986 m_current_tab_modified = modified; | |
987 | |
988 if (modified) | |
989 m_tab_widget->setTabIcon (i, rmgr.icon ("document-save")); | |
990 else | |
991 m_tab_widget->setTabIcon (i, QIcon ()); | |
992 } | |
993 } | |
994 } | |
995 } | |
996 | |
997 void file_editor::handle_tab_close_request (int index) | |
998 { | |
999 file_editor_tab *editor_tab | |
1000 = static_cast<file_editor_tab *> (m_tab_widget->widget (index)); | |
1001 editor_tab->conditional_close (); | |
1002 } | |
1003 | |
1004 void | |
1005 file_editor::handle_tab_remove_request (void) | |
1006 { | |
1007 QObject *fileEditorTab = sender (); | |
1008 if (fileEditorTab) | |
1009 { | |
1010 for (int i = 0; i < m_tab_widget->count (); i++) | |
1011 { | |
1012 if (m_tab_widget->widget (i) == fileEditorTab) | |
1013 { | |
1014 m_tab_widget->removeTab (i); | |
1015 | |
1016 // Deleting the sender (even with deleteLater) seems a | |
1017 // bit strange. Is there a better way? | |
1018 fileEditorTab->deleteLater (); | |
1019 break; | |
1020 } | |
1021 } | |
1022 } | |
1023 check_actions (); | |
1024 | |
1025 activate (); // focus stays in editor when tab is closed | |
1026 | |
1027 } | |
1028 | |
1029 // context menu of edit area | |
1030 void file_editor::active_tab_changed (int index) | |
1031 { | |
1032 emit fetab_change_request (m_tab_widget->widget (index)); | |
1033 activate (); | |
1034 } | |
1035 | |
1036 void file_editor::handle_editor_state_changed (bool copy_available, | |
1037 bool is_octave_file, | |
1038 bool is_modified) | |
1039 { | |
1040 // In case there is some scenario where traffic could be coming from | |
1041 // all the file editor tabs, just process info from the current active tab. | |
1042 if (sender () == m_tab_widget->currentWidget ()) | |
1043 { | |
1044 m_save_action->setEnabled (is_modified); | |
1045 m_current_tab_modified = is_modified; | |
1046 | |
1047 if (m_copy_action) | |
1048 m_copy_action->setEnabled (copy_available); | |
1049 | |
1050 m_cut_action->setEnabled (copy_available); | |
1051 | |
1052 m_run_selection_action->setEnabled (copy_available); | |
1053 m_run_action->setEnabled (is_octave_file); | |
1054 m_is_octave_file = is_octave_file; | |
1055 | |
1056 emit editor_tabs_changed_signal (true, m_is_octave_file); | |
1057 } | |
1058 | |
1059 m_copy_action_enabled = m_copy_action->isEnabled (); | |
1060 m_undo_action_enabled = m_undo_action->isEnabled (); | |
1061 } | |
1062 | |
1063 void file_editor::handle_mru_add_file (const QString& file_name, | |
1064 const QString& encoding) | |
1065 { | |
1066 int index; | |
1067 while ((index = m_mru_files.indexOf (file_name)) >= 0) | |
1068 { | |
1069 m_mru_files.removeAt (index); | |
1070 m_mru_files_encodings.removeAt (index); | |
1071 } | |
1072 | |
1073 m_mru_files.prepend (file_name); | |
1074 m_mru_files_encodings.prepend (encoding); | |
1075 | |
1076 mru_menu_update (); | |
1077 } | |
1078 | |
1079 void file_editor::check_conflict_save (const QString& saveFileName, | |
1080 bool remove_on_success) | |
1081 { | |
1082 // Check whether this file is already open in the editor. | |
1083 file_editor_tab *tab = find_tab_widget (saveFileName); | |
1084 | |
1085 if (tab) | |
1086 { | |
1087 // Note: to overwrite the contents of some other file editor tab | |
1088 // with the same name requires identifying which file editor tab | |
1089 // that is (not too difficult) then closing that tab. Of course, | |
1090 // that could trigger another dialog box if the file editor tab | |
1091 // with the same name has modifications in it. This could become | |
1092 // somewhat confusing to the user. For now, opt to do nothing. | |
1093 | |
1094 // Create a NonModal message about error. | |
1095 QMessageBox *msgBox | |
1096 = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), | |
1097 tr ("File not saved! A file with the selected name\n%1\n" | |
1098 "is already open in the editor"). | |
1099 arg (saveFileName), | |
1100 QMessageBox::Ok, nullptr); | |
1101 | |
1102 msgBox->setWindowModality (Qt::NonModal); | |
1103 msgBox->setAttribute (Qt::WA_DeleteOnClose); | |
1104 msgBox->show (); | |
1105 | |
281 return; | 1106 return; |
282 | 1107 } |
283 if (startup && ! isFloating ()) | 1108 |
284 { | 1109 QObject *saveFileObject = sender (); |
285 // check if editor is really visible or hidden between tabbed widgets | 1110 QWidget *saveFileWidget = nullptr; |
286 QWidget *parent = parentWidget (); | 1111 |
287 | 1112 for (int i = 0; i < m_tab_widget->count (); i++) |
288 if (parent) | 1113 { |
289 { | 1114 if (m_tab_widget->widget (i) == saveFileObject) |
290 QList<QTabBar *> tab_list = parent->findChildren<QTabBar *>(); | 1115 { |
291 | 1116 saveFileWidget = m_tab_widget->widget (i); |
292 bool in_tab = false; | 1117 break; |
293 int i = 0; | 1118 } |
294 while ((i < tab_list.count ()) && (! in_tab)) | 1119 } |
295 { | 1120 if (! saveFileWidget) |
296 QTabBar *tab = tab_list.at (i); | 1121 { |
297 i++; | 1122 // Create a NonModal message about error. |
298 | 1123 QMessageBox *msgBox |
299 int j = 0; | 1124 = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), |
300 while ((j < tab->count ()) && (! in_tab)) | 1125 tr ("The associated file editor tab has disappeared."), |
301 { | 1126 QMessageBox::Ok, nullptr); |
302 // check all tabs for the editor | 1127 |
303 if (tab->tabText (j) == windowTitle ()) | 1128 msgBox->setWindowModality (Qt::NonModal); |
304 { | 1129 msgBox->setAttribute (Qt::WA_DeleteOnClose); |
305 // editor is in this tab widget | 1130 msgBox->show (); |
306 in_tab = true; | 1131 |
307 int top = tab->currentIndex (); | |
308 if (! (top > -1 && tab->tabText (top) == windowTitle ())) | |
309 return; // not current tab -> not visible | |
310 } | |
311 j++; | |
312 } | |
313 } | |
314 } | |
315 } | |
316 | |
317 request_new_file (""); | |
318 } | |
319 | |
320 void file_editor::restore_session (gui_settings *settings) | |
321 { | |
322 //restore previous session | |
323 if (! settings->value (ed_restore_session).toBool ()) | |
324 return; | 1132 return; |
325 | 1133 } |
326 // get the data from the settings file | 1134 |
327 QStringList sessionFileNames | 1135 // Can save without conflict, have the file editor tab do so. |
328 = settings->value (ed_session_names).toStringList (); | 1136 emit fetab_save_file (saveFileWidget, saveFileName, remove_on_success); |
329 | 1137 } |
330 QStringList session_encodings | 1138 |
331 = settings->value (ed_session_enc).toStringList (); | 1139 void file_editor::handle_insert_debugger_pointer_request (const QString& file, |
332 | 1140 int line) |
333 QStringList session_index | 1141 { |
334 = settings->value (ed_session_ind).toStringList (); | 1142 request_open_file (file, QString (), line, true); // default encoding |
335 | 1143 } |
336 QStringList session_lines | 1144 |
337 = settings->value (ed_session_lines).toStringList (); | 1145 void file_editor::handle_delete_debugger_pointer_request (const QString& file, |
338 | 1146 int line) |
339 QStringList session_bookmarks | 1147 { |
340 = settings->value (ed_session_bookmarks).toStringList (); | 1148 if (! file.isEmpty ()) |
341 | 1149 { |
342 // fill a list of the struct and sort it (depending on index) | 1150 // Check whether this file is already open in the editor. |
343 QList<session_data> s_data; | 1151 file_editor_tab *tab = find_tab_widget (file); |
344 | 1152 |
345 bool do_encoding = (session_encodings.count () == sessionFileNames.count ()); | 1153 if (tab) |
346 bool do_index = (session_index.count () == sessionFileNames.count ()); | 1154 { |
347 bool do_lines = (session_lines.count () == sessionFileNames.count ()); | 1155 m_tab_widget->setCurrentWidget (tab); |
348 bool do_bookmarks = (session_bookmarks.count () == sessionFileNames.count ()); | 1156 |
349 | 1157 if (line > 0) |
350 for (int n = 0; n < sessionFileNames.count (); ++n) | 1158 emit fetab_delete_debugger_pointer (tab, line); |
351 { | 1159 |
352 QFileInfo file = QFileInfo (sessionFileNames.at (n)); | 1160 emit fetab_set_focus (tab); |
353 if (! file.exists ()) | 1161 } |
354 continue; | 1162 } |
355 | 1163 } |
356 session_data item = { 0, -1, sessionFileNames.at (n), | 1164 |
357 QString (), QString (), QString ()}; | 1165 void file_editor::handle_update_breakpoint_marker_request (bool insert, |
358 if (do_lines) | 1166 const QString& file, |
359 item.line = session_lines.at (n).toInt (); | 1167 int line, |
360 if (do_index) | 1168 const QString& cond) |
361 item.index = session_index.at (n).toInt (); | 1169 { |
362 if (do_encoding) | 1170 request_open_file (file, QString (), line, false, true, insert, cond); |
363 item.encoding = session_encodings.at (n); | 1171 } |
364 if (do_bookmarks) | 1172 |
365 item.bookmarks = session_bookmarks.at (n); | 1173 void file_editor::handle_edit_file_request (const QString& file) |
366 | 1174 { |
367 s_data << item; | 1175 request_open_file (file); |
368 } | 1176 } |
369 | 1177 |
370 std::sort (s_data.begin (), s_data.end ()); | 1178 // Slot used for signals indicating that a file was changed/renamed or |
371 | 1179 // is going to be deleted/renamed |
372 // finally open the files with the desired encoding in the desired order | 1180 void file_editor::handle_file_remove (const QString& old_name, |
373 for (int n = 0; n < s_data.count (); ++n) | 1181 const QString& new_name) |
374 request_open_file (s_data.at (n).file_name, s_data.at (n).encoding, | 1182 { |
375 s_data.at (n).line, false, false, true, "", -1, | 1183 // Clear old list of file data and declare a structure for file data |
376 s_data.at (n).bookmarks); | 1184 m_tmp_closed_files.clear (); |
377 } | 1185 removed_file_data f_data; |
378 | 1186 |
379 void file_editor::activate (void) | 1187 // Preprocessing old name(s) |
380 { | 1188 QString old_name_clean = old_name.trimmed (); |
381 if (m_no_focus) | 1189 int s = old_name_clean.size (); |
382 return; // No focus for the editor if external open/close request | 1190 |
383 | 1191 if (s > 1 && old_name_clean.at (0) == QChar ('\"') |
384 octave_dock_widget::activate (); | 1192 && old_name_clean.at (s - 1) == QChar ('\"')) |
385 | 1193 old_name_clean = old_name_clean.mid (1, s - 2); |
386 // set focus to current tab | 1194 |
387 reset_focus (); | 1195 QStringList old_names = old_name_clean.split ("\" \""); |
388 } | 1196 |
389 | 1197 // Check if new name is a file or directory |
390 void file_editor::set_focus (QWidget *fet) | 1198 QFileInfo newf (new_name); |
391 { | 1199 bool new_is_dir = newf.isDir (); |
392 setFocus (); | 1200 |
393 | 1201 // Now loop over all old files/dirs (several files by movefile ()) |
394 // set focus to desired tab | 1202 for (int i = 0; i < old_names.count (); i++) |
395 if (fet) | 1203 { |
396 m_tab_widget->setCurrentWidget (fet); | 1204 // Check if old name is a file or directory |
397 } | 1205 QFileInfo old (old_names.at (i)); |
398 | 1206 |
399 // function enabling/disabling the menu accelerators depending on the | 1207 if (old.isDir ()) |
400 // focus of the editor | 1208 { |
401 void file_editor::enable_menu_shortcuts (bool enable) | 1209 // Call the function which handles directories and return |
402 { | 1210 handle_dir_remove (old_names.at (i), new_name); |
403 // Hide or show the find dialog together with the focus of the | 1211 } |
404 // editor widget depending on the overall visibility of the find dialog. | 1212 else |
405 // Do not change internal visibility state. | 1213 { |
406 if (m_find_dialog) | 1214 // It is a single file. Is it open? |
407 m_find_dialog->set_visible (enable); | 1215 file_editor_tab *editor_tab = find_tab_widget (old_names.at (i)); |
408 | 1216 |
409 // Take care of the shortcuts | 1217 if (editor_tab) |
410 QHash<QMenu *, QStringList>::const_iterator i = m_hash_menu_text.constBegin (); | 1218 { |
411 | 1219 |
412 while (i != m_hash_menu_text.constEnd ()) | 1220 editor_tab->enable_file_watcher (false); |
413 { | 1221 |
414 i.key ()->setTitle (i.value ().at (! enable)); | 1222 // For re-enabling tracking if error while removing/renaming |
415 ++i; | 1223 f_data.editor_tab = editor_tab; |
416 } | 1224 // For renaming into new file (if new_file is not empty) |
417 | 1225 if (new_is_dir) |
418 // when editor loses focus, enable the actions, which are always active | 1226 { |
419 // in the main window due to missing info on selected text and undo actions | 1227 std::string ndir = new_name.toStdString (); |
420 if (m_copy_action && m_undo_action) | 1228 std::string ofile = old.fileName ().toStdString (); |
421 { | 1229 f_data.new_file_name |
422 if (enable) | 1230 = QString::fromStdString (sys::env::make_absolute (ofile, ndir)); |
423 { | 1231 } |
424 m_copy_action->setEnabled (m_copy_action_enabled); | 1232 else |
425 m_undo_action->setEnabled (m_undo_action_enabled); | 1233 f_data.new_file_name = new_name; |
426 } | 1234 |
427 else | 1235 // Add file data to list |
428 { | 1236 m_tmp_closed_files << f_data; |
429 m_copy_action_enabled = m_copy_action->isEnabled (); | 1237 } |
430 m_undo_action_enabled = m_undo_action->isEnabled (); | 1238 } |
431 m_copy_action->setEnabled (true); | 1239 } |
432 m_undo_action->setEnabled (true); | 1240 } |
433 } | 1241 |
434 } | 1242 // Slot for signal indicating that a file was renamed |
435 } | 1243 void file_editor::handle_file_renamed (bool load_new) |
436 | 1244 { |
437 // Save open files for restoring in next session | 1245 m_no_focus = true; // Remember for not focussing editor |
438 // (even if last session will not be restored next time) | 1246 |
439 // together with encoding and the tab index | 1247 // Loop over all files that have to be handled. Start at the end of the |
440 void file_editor::save_session (void) | 1248 // list, otherwise the stored indexes are not correct. |
441 { | 1249 for (int i = m_tmp_closed_files.count () - 1; i >= 0; i--) |
442 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | 1250 { |
443 gui_settings *settings = rmgr.get_settings (); | 1251 if (load_new) |
444 | 1252 { |
445 QStringList fetFileNames; | 1253 // Close file (remove) or rename into new file (rename) |
446 QStringList fet_encodings; | 1254 if (m_tmp_closed_files.at (i).new_file_name.isEmpty ()) |
447 QStringList fet_index; | 1255 m_tmp_closed_files.at (i).editor_tab->file_has_changed (QString (), true); |
448 QStringList fet_lines; | 1256 else |
449 QStringList fet_bookmarks; | 1257 m_tmp_closed_files.at (i).editor_tab->set_file_name ( |
450 | 1258 m_tmp_closed_files.at (i).new_file_name); |
451 std::list<file_editor_tab *> editor_tab_lst = m_tab_widget->tab_list (); | 1259 } |
452 | 1260 else |
453 for (auto editor_tab : editor_tab_lst) | 1261 { |
454 { | 1262 // Something went wrong while renaming or removing: |
455 QString file_name = editor_tab->file_name (); | 1263 // Leave everything as it is but reactivate tracking |
456 | 1264 m_tmp_closed_files.at (i).editor_tab->enable_file_watcher (true); |
457 // Don't append unnamed files. | 1265 } |
458 | 1266 |
459 if (! file_name.isEmpty ()) | 1267 } |
460 { | 1268 |
461 fetFileNames.append (file_name); | 1269 m_no_focus = false; // Back to normal focus |
462 fet_encodings.append (editor_tab->encoding ()); | 1270 |
463 | 1271 // Clear the list of file data |
464 QString index; | 1272 m_tmp_closed_files.clear (); |
465 fet_index.append (index.setNum (m_tab_widget->indexOf (editor_tab))); | 1273 } |
466 | 1274 |
467 int l, c; | 1275 void file_editor::notice_settings (const gui_settings *settings) |
468 editor_tab->qsci_edit_area ()->getCursorPosition (&l, &c); | 1276 { |
469 fet_lines.append (index.setNum (l + 1)); | 1277 int size_idx = settings->value (global_icon_size).toInt (); |
470 | 1278 size_idx = (size_idx > 0) - (size_idx < 0) + 1; // Make valid index from 0 to 2 |
471 fet_bookmarks.append (editor_tab->get_all_bookmarks ()); | 1279 |
472 } | 1280 QStyle *st = style (); |
473 } | 1281 int icon_size = st->pixelMetric (global_icon_sizes[size_idx]); |
474 | 1282 m_tool_bar->setIconSize (QSize (icon_size, icon_size)); |
475 settings->setValue (ed_session_names.key, fetFileNames); | 1283 |
476 settings->setValue (ed_session_enc.key, fet_encodings); | 1284 // Tab position and rotation |
477 settings->setValue (ed_session_ind.key, fet_index); | 1285 QTabWidget::TabPosition pos |
478 settings->setValue (ed_session_lines.key, fet_lines); | 1286 = static_cast<QTabWidget::TabPosition> (settings->value (ed_tab_position).toInt ()); |
479 settings->setValue (ed_session_bookmarks.key, fet_bookmarks); | 1287 bool rotated = settings->value (ed_tabs_rotated).toBool (); |
480 settings->sync (); | 1288 |
481 } | 1289 m_tab_widget->setTabPosition (pos); |
482 | 1290 |
483 bool file_editor::check_closing (void) | 1291 if (rotated) |
484 { | 1292 m_tab_widget->setTabsClosable (false); // No close buttons |
485 // When the application or the editor is closing and the user wants to | 1293 // FIXME: close buttons can not be correctly placed in rotated tabs |
486 // close all files, in the latter case all editor tabs are checked whether | 1294 |
487 // they need to be saved. During these checks tabs are not closed since | 1295 // Get the tab bar and set the rotation |
488 // the user might cancel closing Octave during one of these saving dialogs. | 1296 int rotation = rotated; |
489 // Therefore, saving the session for restoring at next start is not done | 1297 if (pos == QTabWidget::West) |
490 // before the application is definitely closing. | 1298 rotation = -rotation; |
491 | 1299 |
492 // Save the session. Even is closing is cancelled, this would be | 1300 tab_bar *bar = m_tab_widget->get_tab_bar (); |
493 // overwritten by the next attempt to close the editor | 1301 bar->set_rotated (rotation); |
494 save_session (); | 1302 |
495 | 1303 // Get suitable height of a tab related to font and icon size |
496 std::list<file_editor_tab *> fe_tab_lst = m_tab_widget->tab_list (); | 1304 int height = 1.5*QFontMetrics (m_tab_widget->font ()).height (); |
497 m_number_of_tabs = fe_tab_lst.size (); | 1305 int is = 1.5*m_tab_widget->iconSize ().height (); |
498 | 1306 if (is > height) |
499 for (auto fe_tab : fe_tab_lst) | 1307 height = is; |
500 { | 1308 |
501 // Wait for all editor tabs to have saved their files if required | 1309 // Calculate possibly limited width and set the elide mode |
502 | 1310 int chars = settings->value (ed_tabs_max_width).toInt (); |
503 connect (fe_tab, &file_editor_tab::tab_ready_to_close, | 1311 int width = 9999; |
504 this, &file_editor::handle_tab_ready_to_close, | 1312 if (chars > 0) |
505 Qt::UniqueConnection); | 1313 width = chars * QFontMetrics (m_tab_widget->font ()).averageCharWidth (); |
506 } | 1314 |
507 | 1315 // Get tab bar size properties for style sheet depending on rotation |
508 m_closing_canceled = false; | 1316 QString width_str ("width"); |
509 | 1317 QString height_str ("height"); |
510 for (auto fe_tab : fe_tab_lst) | 1318 if ((pos == QTabWidget::West) || (pos == QTabWidget::East)) |
511 { | 1319 { |
512 // If there was a cancellation, make the already saved/discarded tabs | 1320 width_str = QString ("height"); |
513 // recover from the exit by removing the read-only state and by | 1321 height_str = QString ("width"); |
514 // recovering the debugger breakpoints. Finally return false in order | 1322 } |
515 // to cancel closing the application or the editor. | 1323 |
516 | 1324 QString style_sheet |
517 if (fe_tab->check_file_modified (false) == QMessageBox::Cancel) | 1325 = QString ("QTabBar::tab {max-" + height_str + ": %1px;\n" |
518 { | 1326 "max-" + width_str + ": %2px; }") |
519 emit fetab_recover_from_exit (); | 1327 .arg (height).arg (width); |
520 | 1328 |
521 m_closing_canceled = true; | 1329 #if defined (Q_OS_MAC) |
522 | 1330 // FIXME: This is a workaround for missing tab close buttons on MacOS |
523 for (auto fet : fe_tab_lst) | 1331 // in several Qt versions (https://bugreports.qt.io/browse/QTBUG-61092) |
524 disconnect (fet, &file_editor_tab::tab_ready_to_close, 0, 0); | 1332 if (! rotated) |
525 | 1333 { |
526 return false; | 1334 QString icon = global_icon_paths.at (ICON_THEME_OCTAVE) + "widget-close.png"; |
527 } | 1335 |
528 } | 1336 QString close_button_css_mac ( |
529 | 1337 "QTabBar::close-button" |
1338 " { image: url(" + icon + ");" | |
1339 " padding: 4px;" | |
1340 " subcontrol-position: bottom; }\n" | |
1341 "QTabBar::close-button:hover" | |
1342 " { background-color: #cccccc; }"); | |
1343 | |
1344 style_sheet = style_sheet + close_button_css_mac; | |
1345 } | |
1346 #endif | |
1347 | |
1348 m_tab_widget->setStyleSheet (style_sheet); | |
1349 | |
1350 bool show_it; | |
1351 show_it = settings->value (ed_show_line_numbers).toBool (); | |
1352 m_show_linenum_action->setChecked (show_it); | |
1353 show_it = settings->value (ed_show_white_space).toBool (); | |
1354 m_show_whitespace_action->setChecked (show_it); | |
1355 show_it = settings->value (ed_show_eol_chars).toBool (); | |
1356 m_show_eol_action->setChecked (show_it); | |
1357 show_it = settings->value (ed_show_indent_guides).toBool (); | |
1358 m_show_indguide_action->setChecked (show_it); | |
1359 show_it = settings->value (ed_long_line_marker).toBool (); | |
1360 m_show_longline_action->setChecked (show_it); | |
1361 | |
1362 show_it = settings->value (ed_show_toolbar).toBool (); | |
1363 m_show_toolbar_action->setChecked (show_it); | |
1364 m_tool_bar->setVisible (show_it); | |
1365 show_it = settings->value (ed_show_edit_status_bar).toBool (); | |
1366 m_show_statusbar_action->setChecked (show_it); | |
1367 show_it = settings->value (ed_show_hscroll_bar).toBool (); | |
1368 m_show_hscrollbar_action->setChecked (show_it); | |
1369 | |
1370 set_shortcuts (); | |
1371 | |
1372 // Find dialog with the same icon as the editor | |
1373 if (m_find_dialog) | |
1374 m_find_dialog->setWindowIcon (windowIcon ()); | |
1375 | |
1376 // Relay signal to file editor tabs. | |
1377 emit fetab_settings_changed (settings); | |
1378 } | |
1379 | |
1380 void file_editor::set_shortcuts (void) | |
1381 { | |
1382 // Shortcuts also available in the main window, as well as the related | |
1383 // shortcuts, are defined in main_window and added to the editor | |
1384 | |
1385 shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); | |
1386 | |
1387 // File menu | |
1388 scmgr.set_shortcut (m_edit_function_action, sc_edit_file_edit_function); | |
1389 scmgr.set_shortcut (m_save_action, sc_edit_file_save); | |
1390 scmgr.set_shortcut (m_save_as_action, sc_edit_file_save_as); | |
1391 scmgr.set_shortcut (m_close_action, sc_edit_file_close); | |
1392 scmgr.set_shortcut (m_close_all_action, sc_edit_file_close_all); | |
1393 scmgr.set_shortcut (m_close_others_action, sc_edit_file_close_other); | |
1394 scmgr.set_shortcut (m_print_action, sc_edit_file_print); | |
1395 | |
1396 // Edit menu | |
1397 scmgr.set_shortcut (m_redo_action, sc_edit_edit_redo); | |
1398 scmgr.set_shortcut (m_cut_action, sc_edit_edit_cut); | |
1399 scmgr.set_shortcut (m_find_action, sc_edit_edit_find_replace); | |
1400 scmgr.set_shortcut (m_find_next_action, sc_edit_edit_find_next); | |
1401 scmgr.set_shortcut (m_find_previous_action, sc_edit_edit_find_previous); | |
1402 | |
1403 scmgr.set_shortcut (m_delete_start_word_action, sc_edit_edit_delete_start_word); | |
1404 scmgr.set_shortcut (m_delete_end_word_action, sc_edit_edit_delete_end_word); | |
1405 scmgr.set_shortcut (m_delete_start_line_action, sc_edit_edit_delete_start_line); | |
1406 scmgr.set_shortcut (m_delete_end_line_action, sc_edit_edit_delete_end_line); | |
1407 scmgr.set_shortcut (m_delete_line_action, sc_edit_edit_delete_line); | |
1408 scmgr.set_shortcut (m_copy_line_action, sc_edit_edit_copy_line); | |
1409 scmgr.set_shortcut (m_cut_line_action, sc_edit_edit_cut_line); | |
1410 scmgr.set_shortcut (m_duplicate_selection_action, sc_edit_edit_duplicate_selection); | |
1411 scmgr.set_shortcut (m_transpose_line_action, sc_edit_edit_transpose_line); | |
1412 scmgr.set_shortcut (m_comment_selection_action, sc_edit_edit_comment_selection); | |
1413 scmgr.set_shortcut (m_uncomment_selection_action, sc_edit_edit_uncomment_selection); | |
1414 scmgr.set_shortcut (m_comment_var_selection_action, sc_edit_edit_comment_var_selection); | |
1415 | |
1416 scmgr.set_shortcut (m_upper_case_action, sc_edit_edit_upper_case); | |
1417 scmgr.set_shortcut (m_lower_case_action, sc_edit_edit_lower_case); | |
1418 scmgr.set_shortcut (m_indent_selection_action, sc_edit_edit_indent_selection); | |
1419 scmgr.set_shortcut (m_unindent_selection_action, sc_edit_edit_unindent_selection); | |
1420 scmgr.set_shortcut (m_smart_indent_line_or_selection_action, sc_edit_edit_smart_indent_line_or_selection); | |
1421 scmgr.set_shortcut (m_completion_action, sc_edit_edit_completion_list); | |
1422 scmgr.set_shortcut (m_goto_line_action, sc_edit_edit_goto_line); | |
1423 scmgr.set_shortcut (m_move_to_matching_brace, sc_edit_edit_move_to_brace); | |
1424 scmgr.set_shortcut (m_sel_to_matching_brace, sc_edit_edit_select_to_brace); | |
1425 scmgr.set_shortcut (m_toggle_bookmark_action, sc_edit_edit_toggle_bookmark); | |
1426 scmgr.set_shortcut (m_next_bookmark_action, sc_edit_edit_next_bookmark); | |
1427 scmgr.set_shortcut (m_previous_bookmark_action, sc_edit_edit_previous_bookmark); | |
1428 scmgr.set_shortcut (m_remove_bookmark_action, sc_edit_edit_remove_bookmark); | |
1429 scmgr.set_shortcut (m_preferences_action, sc_edit_edit_preferences); | |
1430 scmgr.set_shortcut (m_styles_preferences_action, sc_edit_edit_styles_preferences); | |
1431 | |
1432 scmgr.set_shortcut (m_conv_eol_windows_action, sc_edit_edit_conv_eol_winows); | |
1433 scmgr.set_shortcut (m_conv_eol_unix_action, sc_edit_edit_conv_eol_unix); | |
1434 scmgr.set_shortcut (m_conv_eol_mac_action, sc_edit_edit_conv_eol_mac); | |
1435 | |
1436 // View menu | |
1437 scmgr.set_shortcut (m_show_linenum_action, sc_edit_view_show_line_numbers); | |
1438 scmgr.set_shortcut (m_show_whitespace_action, sc_edit_view_show_white_spaces); | |
1439 scmgr.set_shortcut (m_show_eol_action, sc_edit_view_show_eol_chars); | |
1440 scmgr.set_shortcut (m_show_indguide_action, sc_edit_view_show_ind_guides); | |
1441 scmgr.set_shortcut (m_show_longline_action, sc_edit_view_show_long_line); | |
1442 scmgr.set_shortcut (m_show_toolbar_action, sc_edit_view_show_toolbar); | |
1443 scmgr.set_shortcut (m_show_statusbar_action, sc_edit_view_show_statusbar); | |
1444 scmgr.set_shortcut (m_show_hscrollbar_action, sc_edit_view_show_hscrollbar); | |
1445 scmgr.set_shortcut (m_zoom_in_action, sc_edit_view_zoom_in); | |
1446 scmgr.set_shortcut (m_zoom_out_action, sc_edit_view_zoom_out); | |
1447 scmgr.set_shortcut (m_zoom_normal_action, sc_edit_view_zoom_normal); | |
1448 scmgr.set_shortcut (m_sort_tabs_action, sc_edit_view_sort_tabs); | |
1449 | |
1450 // Debug menu | |
1451 scmgr.set_shortcut (m_toggle_breakpoint_action, sc_edit_debug_toggle_breakpoint); | |
1452 scmgr.set_shortcut (m_next_breakpoint_action, sc_edit_debug_next_breakpoint); | |
1453 scmgr.set_shortcut (m_previous_breakpoint_action, sc_edit_debug_previous_breakpoint); | |
1454 scmgr.set_shortcut (m_remove_all_breakpoints_action, sc_edit_debug_remove_breakpoints); | |
1455 | |
1456 // Run menu | |
1457 scmgr.set_shortcut (m_run_action, sc_edit_run_run_file); | |
1458 scmgr.set_shortcut (m_run_selection_action, sc_edit_run_run_selection); | |
1459 | |
1460 // Help menu | |
1461 scmgr.set_shortcut (m_context_help_action, sc_edit_help_help_keyword); | |
1462 scmgr.set_shortcut (m_context_doc_action, sc_edit_help_doc_keyword); | |
1463 | |
1464 // Tab navigation without menu entries | |
1465 scmgr.set_shortcut (m_switch_left_tab_action, sc_edit_tabs_switch_left_tab); | |
1466 scmgr.set_shortcut (m_switch_right_tab_action, sc_edit_tabs_switch_right_tab); | |
1467 scmgr.set_shortcut (m_move_tab_left_action, sc_edit_tabs_move_tab_left); | |
1468 scmgr.set_shortcut (m_move_tab_right_action, sc_edit_tabs_move_tab_right); | |
1469 | |
1470 } | |
1471 | |
1472 // This slot is a reimplementation of the virtual slot in octave_dock_widget. | |
1473 // We need this for creating an empty script when the editor has no open | |
1474 // files and is made visible. | |
1475 void file_editor::handle_visibility (bool visible) | |
1476 { | |
1477 octave_dock_widget::handle_visibility (visible); | |
1478 | |
1479 if (! m_editor_ready) | |
1480 return; | |
1481 | |
1482 if (m_closed && visible) | |
1483 { | |
1484 m_closed = false; | |
1485 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
1486 gui_settings *settings = rmgr.get_settings (); | |
1487 restore_session (settings); | |
1488 } | |
1489 | |
1490 empty_script (false, visible); | |
1491 } | |
1492 | |
1493 // This slot is a reimplementation of the virtual slot in octave_dock_widget. | |
1494 // We need this for updating the parent of the find dialog | |
1495 void file_editor::toplevel_change (bool) | |
1496 { | |
1497 if (m_find_dialog) | |
1498 { | |
1499 // close current dialog | |
1500 m_find_dialog->close (); | |
1501 | |
1502 // re-create dialog with the new parent (editor or main-win) | |
1503 find_create (); | |
1504 m_find_dialog->activateWindow (); | |
1505 } | |
1506 } | |
1507 | |
1508 void file_editor::update_octave_directory (const QString& dir) | |
1509 { | |
1510 m_ced = dir; | |
1511 emit fetab_set_directory (m_ced); // for save dialog | |
1512 } | |
1513 | |
1514 void file_editor::copyClipboard (void) | |
1515 { | |
1516 if (editor_tab_has_focus ()) | |
1517 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
1518 QsciScintillaBase::SCI_COPY); | |
1519 } | |
1520 | |
1521 void file_editor::pasteClipboard (void) | |
1522 { | |
1523 if (editor_tab_has_focus ()) | |
1524 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
1525 QsciScintillaBase::SCI_PASTE); | |
1526 } | |
1527 | |
1528 void file_editor::selectAll (void) | |
1529 { | |
1530 if (editor_tab_has_focus ()) | |
1531 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
1532 QsciScintillaBase::SCI_SELECTALL); | |
1533 } | |
1534 | |
1535 void file_editor::do_undo (void) | |
1536 { | |
1537 if (editor_tab_has_focus ()) | |
1538 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
1539 QsciScintillaBase::SCI_UNDO); | |
1540 } | |
1541 | |
1542 // Open a file, if not already open, and mark the current execution location | |
1543 // and/or a breakpoint with condition cond. | |
1544 void file_editor::request_open_file (const QString& openFileName, | |
1545 const QString& encoding, | |
1546 int line, bool debug_pointer, | |
1547 bool breakpoint_marker, bool insert, | |
1548 const QString& cond, int index, | |
1549 const QString& bookmarks) | |
1550 { | |
1551 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
1552 gui_settings *settings = rmgr.get_settings (); | |
1553 | |
1554 if (settings->value (global_use_custom_editor).toBool ()) | |
1555 { | |
1556 // Custom editor | |
1557 if (debug_pointer || breakpoint_marker) | |
1558 return; // Do not call custom editor during debugging | |
1559 | |
1560 if (call_custom_editor (openFileName, line)) | |
1561 return; // Custom editor called | |
1562 } | |
1563 | |
1564 bool show_dbg_file | |
1565 = settings->value (ed_show_dbg_file).toBool (); | |
1566 | |
1567 if (openFileName.isEmpty ()) | |
1568 { | |
1569 // This happens if edit is called without an argument | |
1570 // Open editor with empty edit area instead (as new file would do) | |
1571 request_new_file (""); | |
1572 } | |
1573 else | |
1574 { | |
1575 // Check whether this file is already open in the editor. | |
1576 file_editor_tab *tab = find_tab_widget (openFileName); | |
1577 | |
1578 if (tab) | |
1579 { | |
1580 m_tab_widget->setCurrentWidget (tab); | |
1581 | |
1582 if (line > 0) | |
1583 { | |
1584 if (insert) | |
1585 emit fetab_goto_line (tab, line); | |
1586 | |
1587 if (debug_pointer) | |
1588 emit fetab_insert_debugger_pointer (tab, line); | |
1589 | |
1590 if (breakpoint_marker) | |
1591 emit fetab_do_breakpoint_marker (insert, tab, line, cond); | |
1592 } | |
1593 | |
1594 if (show_dbg_file && ! ((breakpoint_marker || debug_pointer) | |
1595 && is_editor_console_tabbed ())) | |
1596 { | |
1597 emit fetab_set_focus (tab); | |
1598 activate (); | |
1599 } | |
1600 } | |
1601 else | |
1602 { | |
1603 if (! show_dbg_file && (breakpoint_marker || debug_pointer)) | |
1604 return; // Do not open a file for showing dbg markers | |
1605 | |
1606 if (breakpoint_marker && ! insert) | |
1607 return; // Never open a file when removing breakpoints | |
1608 | |
1609 file_editor_tab *fileEditorTab = nullptr; | |
1610 // Reuse <unnamed> tab if it hasn't yet been modified. | |
1611 bool reusing = false; | |
1612 tab = find_tab_widget (""); | |
1613 if (tab) | |
1614 { | |
1615 fileEditorTab = tab; | |
1616 if (fileEditorTab->qsci_edit_area ()->isModified ()) | |
1617 fileEditorTab = nullptr; | |
1618 else | |
1619 reusing = true; | |
1620 } | |
1621 | |
1622 // If <unnamed> was absent or modified, create a new tab. | |
1623 if (! fileEditorTab) | |
1624 fileEditorTab = make_file_editor_tab (); | |
1625 | |
1626 fileEditorTab->set_encoding (encoding); | |
1627 QString result = fileEditorTab->load_file (openFileName); | |
1628 if (result == "") | |
1629 { | |
1630 // Supply empty title then have the file_editor_tab update | |
1631 // with full or short name. | |
1632 if (! reusing) | |
1633 add_file_editor_tab (fileEditorTab, "", index); | |
1634 fileEditorTab->update_window_title (false); | |
1635 // file already loaded, add file to mru list here | |
1636 QFileInfo file_info = QFileInfo (openFileName); | |
1637 handle_mru_add_file (file_info.canonicalFilePath (), | |
1638 encoding); | |
1639 | |
1640 if (line > 0) | |
1641 { | |
1642 if (insert) | |
1643 emit fetab_goto_line (fileEditorTab, line); | |
1644 | |
1645 if (debug_pointer) | |
1646 emit fetab_insert_debugger_pointer (fileEditorTab, | |
1647 line); | |
1648 if (breakpoint_marker) | |
1649 emit fetab_do_breakpoint_marker (insert, fileEditorTab, | |
1650 line, cond); | |
1651 } | |
1652 } | |
1653 else | |
1654 { | |
1655 delete fileEditorTab; | |
1656 fileEditorTab = nullptr; | |
1657 | |
1658 if (QFile::exists (openFileName)) | |
1659 { | |
1660 // File not readable: | |
1661 // create a NonModal message about error. | |
1662 QMessageBox *msgBox | |
1663 = new QMessageBox (QMessageBox::Critical, | |
1664 tr ("Octave Editor"), | |
1665 tr ("Could not open file\n%1\nfor read: %2."). | |
1666 arg (openFileName).arg (result), | |
1667 QMessageBox::Ok, this); | |
1668 | |
1669 msgBox->setWindowModality (Qt::NonModal); | |
1670 msgBox->setAttribute (Qt::WA_DeleteOnClose); | |
1671 msgBox->show (); | |
1672 } | |
1673 else | |
1674 { | |
1675 // File does not exist, should it be created? | |
1676 bool create_file = true; | |
1677 QMessageBox *msgBox; | |
1678 | |
1679 if (! settings->value (ed_create_new_file).toBool ()) | |
1680 { | |
1681 msgBox = new QMessageBox (QMessageBox::Question, | |
1682 tr ("Octave Editor"), | |
1683 tr ("File\n%1\ndoes not exist. " | |
1684 "Do you want to create it?").arg (openFileName), | |
1685 QMessageBox::NoButton, nullptr); | |
1686 QPushButton *create_button = | |
1687 msgBox->addButton (tr ("Create"), QMessageBox::YesRole); | |
1688 msgBox->addButton (tr ("Cancel"), QMessageBox::RejectRole); | |
1689 msgBox->setDefaultButton (create_button); | |
1690 msgBox->exec (); | |
1691 | |
1692 QAbstractButton *clicked_button = msgBox->clickedButton (); | |
1693 if (clicked_button != create_button) | |
1694 create_file = false; | |
1695 | |
1696 delete msgBox; | |
1697 } | |
1698 | |
1699 if (create_file) | |
1700 { | |
1701 // create the file and call the editor again | |
1702 QFile file (openFileName); | |
1703 if (! file.open (QIODevice::WriteOnly)) | |
1704 { | |
1705 // error opening the file | |
1706 msgBox = new QMessageBox (QMessageBox::Critical, | |
1707 tr ("Octave Editor"), | |
1708 tr ("Could not open file\n%1\nfor write: %2."). | |
1709 arg (openFileName).arg (file.errorString ()), | |
1710 QMessageBox::Ok, this); | |
1711 | |
1712 msgBox->setWindowModality (Qt::NonModal); | |
1713 msgBox->setAttribute (Qt::WA_DeleteOnClose); | |
1714 msgBox->show (); | |
1715 } | |
1716 else | |
1717 { | |
1718 file.close (); | |
1719 request_open_file (openFileName); | |
1720 } | |
1721 } | |
1722 } | |
1723 } | |
1724 | |
1725 if (! bookmarks.isEmpty ()) | |
1726 { | |
1727 // Restore bookmarks | |
1728 for (const auto& bms : bookmarks.split (',')) | |
1729 { | |
1730 int bm = bms.toInt (); | |
1731 if (fileEditorTab) | |
1732 fileEditorTab->qsci_edit_area ()->markerAdd (bm, marker::bookmark); | |
1733 } | |
1734 } | |
1735 | |
1736 if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ())) | |
1737 { | |
1738 // update breakpoint pointers, really show editor | |
1739 // and the current editor tab | |
1740 if (fileEditorTab) | |
1741 fileEditorTab->update_breakpoints (); | |
1742 activate (); | |
1743 emit file_loaded_signal (); | |
1744 } | |
1745 } | |
1746 } | |
1747 } | |
1748 | |
1749 void file_editor::request_preferences (bool) | |
1750 { | |
1751 emit request_settings_dialog ("editor"); | |
1752 } | |
1753 | |
1754 void file_editor::request_styles_preferences (bool) | |
1755 { | |
1756 emit request_settings_dialog ("editor_styles"); | |
1757 } | |
1758 | |
1759 void file_editor::show_line_numbers (bool) | |
1760 { | |
1761 toggle_preference (ed_show_line_numbers); | |
1762 } | |
1763 | |
1764 void file_editor::show_white_space (bool) | |
1765 { | |
1766 toggle_preference (ed_show_white_space); | |
1767 } | |
1768 | |
1769 void file_editor::show_eol_chars (bool) | |
1770 { | |
1771 toggle_preference (ed_show_eol_chars); | |
1772 } | |
1773 | |
1774 void file_editor::show_indent_guides (bool) | |
1775 { | |
1776 toggle_preference (ed_show_indent_guides); | |
1777 } | |
1778 | |
1779 void file_editor::show_long_line (bool) | |
1780 { | |
1781 toggle_preference (ed_long_line_marker); | |
1782 } | |
1783 | |
1784 void file_editor::show_toolbar (bool) | |
1785 { | |
1786 toggle_preference (ed_show_toolbar); | |
1787 } | |
1788 | |
1789 void file_editor::show_statusbar (bool) | |
1790 { | |
1791 toggle_preference (ed_show_edit_status_bar); | |
1792 } | |
1793 | |
1794 void file_editor::show_hscrollbar (bool) | |
1795 { | |
1796 toggle_preference (ed_show_hscroll_bar); | |
1797 } | |
1798 | |
1799 void file_editor::zoom_in (bool) | |
1800 { | |
1801 emit fetab_zoom_in (m_tab_widget->currentWidget ()); | |
1802 } | |
1803 | |
1804 void file_editor::zoom_out (bool) | |
1805 { | |
1806 emit fetab_zoom_out (m_tab_widget->currentWidget ()); | |
1807 } | |
1808 | |
1809 void file_editor::zoom_normal (bool) | |
1810 { | |
1811 emit fetab_zoom_normal (m_tab_widget->currentWidget ()); | |
1812 } | |
1813 | |
1814 void file_editor::create_context_menu (QMenu *menu) | |
1815 { | |
1816 // remove all standard actions from scintilla | |
1817 QList<QAction *> all_actions = menu->actions (); | |
1818 | |
1819 for (auto *a : all_actions) | |
1820 menu->removeAction (a); | |
1821 | |
1822 // add editor's actions with icons and customized shortcuts | |
1823 menu->addAction (m_cut_action); | |
1824 menu->addAction (m_copy_action); | |
1825 menu->addAction (m_paste_action); | |
1826 menu->addSeparator (); | |
1827 menu->addAction (m_selectall_action); | |
1828 menu->addSeparator (); | |
1829 menu->addAction (m_find_files_action); | |
1830 menu->addAction (m_find_action); | |
1831 menu->addAction (m_find_next_action); | |
1832 menu->addAction (m_find_previous_action); | |
1833 menu->addSeparator (); | |
1834 menu->addMenu (m_edit_cmd_menu); | |
1835 menu->addMenu (m_edit_fmt_menu); | |
1836 menu->addMenu (m_edit_nav_menu); | |
1837 menu->addSeparator (); | |
1838 menu->addAction (m_run_selection_action); | |
1839 } | |
1840 | |
1841 void file_editor::edit_status_update (bool undo, bool redo) | |
1842 { | |
1843 if (m_undo_action) | |
1844 m_undo_action->setEnabled (undo); | |
1845 m_redo_action->setEnabled (redo); | |
1846 } | |
1847 | |
1848 // handler for the close event | |
1849 void file_editor::closeEvent (QCloseEvent *e) | |
1850 { | |
1851 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
1852 gui_settings *settings = rmgr.get_settings (); | |
1853 if (settings->value (ed_hiding_closes_files).toBool ()) | |
1854 { | |
1855 if (check_closing ()) | |
1856 { | |
1857 // All tabs are closed without cancelling, | |
1858 // store closing state for restoring session when shown again. | |
1859 // Editor is closing when session data is stored in preferences | |
1860 m_closed = true; | |
1861 e->ignore (); | |
1862 } | |
1863 else | |
1864 { | |
1865 e->ignore (); | |
1866 return; | |
1867 } | |
1868 } | |
1869 else | |
1870 e->accept (); | |
1871 | |
1872 octave_dock_widget::closeEvent (e); | |
1873 } | |
1874 | |
1875 void file_editor::dragEnterEvent (QDragEnterEvent *e) | |
1876 { | |
1877 if (e->mimeData ()->hasUrls ()) | |
1878 { | |
1879 e->acceptProposedAction (); | |
1880 } | |
1881 } | |
1882 | |
1883 void file_editor::dropEvent (QDropEvent *e) | |
1884 { | |
1885 if (e->mimeData ()->hasUrls ()) | |
1886 { | |
1887 for (const auto& url : e->mimeData ()->urls ()) | |
1888 request_open_file (url.toLocalFile ()); | |
1889 } | |
1890 } | |
1891 | |
1892 bool file_editor::is_editor_console_tabbed (void) | |
1893 { | |
1894 // FIXME: is there a way to do this job that doesn't require casting | |
1895 // the parent to a main_window object? | |
1896 | |
1897 main_window *w = dynamic_cast<main_window *> (parentWidget ()); | |
1898 | |
1899 if (w) | |
1900 { | |
1901 QList<QDockWidget *> w_list = w->tabifiedDockWidgets (this); | |
1902 QDockWidget *console = | |
1903 static_cast<QDockWidget *> (w->get_dock_widget_list ().at (0)); | |
1904 | |
1905 for (int i = 0; i < w_list.count (); i++) | |
1906 { | |
1907 if (w_list.at (i) == console) | |
1908 return true; | |
1909 } | |
1910 } | |
1911 | |
1912 return false; | |
1913 } | |
1914 | |
1915 void file_editor::construct (void) | |
1916 { | |
1917 QWidget *editor_widget = new QWidget (this); | |
1918 | |
1919 // FIXME: what was the intended purpose of this unused variable? | |
1920 // QStyle *editor_style = QApplication::style (); | |
1921 | |
1922 // Menu bar: do not set it native, required in macOS and Ubuntu Unity (Qt5) | |
1923 // for a visible menu bar in the editor widget. This property is ignored | |
1924 // on other platforms. | |
1925 m_menu_bar = new QMenuBar (editor_widget); | |
1926 m_menu_bar->setNativeMenuBar (false); | |
1927 | |
1928 m_tool_bar = new QToolBar (editor_widget); | |
1929 m_tool_bar->setMovable (true); | |
1930 | |
1931 m_tab_widget = new file_editor_tab_widget (editor_widget, this); | |
1932 | |
1933 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
1934 | |
1935 // the mru-list and an empty array of actions | |
1936 gui_settings *settings = rmgr.get_settings (); | |
1937 m_mru_files = settings->value (ed_mru_file_list).toStringList (); | |
1938 m_mru_files_encodings = settings->value (ed_mru_file_encodings) | |
1939 .toStringList (); | |
1940 | |
1941 if (m_mru_files_encodings.count () != m_mru_files.count ()) | |
1942 { | |
1943 // encodings don't have the same count -> do not use them! | |
1944 m_mru_files_encodings = QStringList (); | |
1945 for (int i = 0; i < m_mru_files.count (); i++) | |
1946 m_mru_files_encodings << QString (); | |
1947 } | |
1948 | |
1949 for (int i = 0; i < MaxMRUFiles; ++i) | |
1950 { | |
1951 m_mru_file_actions[i] = new QAction (this); | |
1952 m_mru_file_actions[i]->setVisible (false); | |
1953 } | |
1954 | |
1955 // menu bar | |
1956 | |
1957 // file menu | |
1958 | |
1959 m_fileMenu = add_menu (m_menu_bar, tr ("&File")); | |
1960 | |
1961 // new and open menus are inserted later by the main window | |
1962 m_mru_file_menu = new QMenu (tr ("&Recent Editor Files"), m_fileMenu); | |
1963 for (int i = 0; i < MaxMRUFiles; ++i) | |
1964 m_mru_file_menu->addAction (m_mru_file_actions[i]); | |
1965 m_fileMenu->addMenu (m_mru_file_menu); | |
1966 | |
1967 m_fileMenu->addSeparator (); | |
1968 | |
1969 m_edit_function_action | |
1970 = add_action (m_fileMenu, | |
1971 tr ("&Edit Function"), | |
1972 SLOT (request_context_edit (bool))); | |
1973 | |
1974 m_fileMenu->addSeparator (); | |
1975 | |
1976 m_save_action | |
1977 = add_action (m_fileMenu, rmgr.icon ("document-save"), | |
1978 tr ("&Save File"), SLOT (request_save_file (bool))); | |
1979 | |
1980 m_save_as_action | |
1981 = add_action (m_fileMenu, rmgr.icon ("document-save-as"), | |
1982 tr ("Save File &As..."), | |
1983 SLOT (request_save_file_as (bool))); | |
1984 | |
1985 m_fileMenu->addSeparator (); | |
1986 | |
1987 m_close_action | |
1988 = add_action (m_fileMenu, rmgr.icon ("window-close", false), | |
1989 tr ("&Close"), SLOT (request_close_file (bool))); | |
1990 | |
1991 m_close_all_action | |
1992 = add_action (m_fileMenu, rmgr.icon ("window-close", false), | |
1993 tr ("Close All"), SLOT (request_close_all_files (bool))); | |
1994 | |
1995 m_close_others_action | |
1996 = add_action (m_fileMenu, rmgr.icon ("window-close", false), | |
1997 tr ("Close Other Files"), | |
1998 SLOT (request_close_other_files (bool))); | |
1999 | |
2000 m_fileMenu->addSeparator (); | |
2001 | |
2002 m_print_action | |
2003 = add_action (m_fileMenu, rmgr.icon ("document-print"), | |
2004 tr ("Print..."), SLOT (request_print_file (bool))); | |
2005 | |
2006 // edit menu (undo, copy, paste and select all later via main window) | |
2007 | |
2008 m_edit_menu = add_menu (m_menu_bar, tr ("&Edit")); | |
2009 | |
2010 m_redo_action | |
2011 = add_action (m_edit_menu, rmgr.icon ("edit-redo"), | |
2012 tr ("&Redo"), SLOT (request_redo (bool))); | |
2013 m_redo_action->setEnabled (false); | |
2014 | |
2015 m_edit_menu->addSeparator (); | |
2016 | |
2017 m_cut_action | |
2018 = add_action (m_edit_menu, rmgr.icon ("edit-cut"), | |
2019 tr ("Cu&t"), SLOT (request_cut (bool))); | |
2020 m_cut_action->setEnabled (false); | |
2021 | |
2022 m_find_action | |
2023 = add_action (m_edit_menu, rmgr.icon ("edit-find-replace"), | |
2024 tr ("&Find and Replace..."), SLOT (request_find (bool))); | |
2025 | |
2026 m_find_next_action | |
2027 = add_action (m_edit_menu, tr ("Find &Next..."), | |
2028 SLOT (request_find_next (bool))); | |
2029 | |
2030 m_find_previous_action | |
2031 = add_action (m_edit_menu, tr ("Find &Previous..."), | |
2032 SLOT (request_find_previous (bool))); | |
2033 | |
2034 m_edit_menu->addSeparator (); | |
2035 | |
2036 m_edit_cmd_menu = m_edit_menu->addMenu (tr ("&Commands")); | |
2037 | |
2038 m_delete_line_action | |
2039 = add_action (m_edit_cmd_menu, tr ("Delete Line"), | |
2040 SLOT (request_delete_line (bool))); | |
2041 | |
2042 m_copy_line_action | |
2043 = add_action (m_edit_cmd_menu, tr ("Copy Line"), | |
2044 SLOT (request_copy_line (bool))); | |
2045 | |
2046 m_cut_line_action | |
2047 = add_action (m_edit_cmd_menu, tr ("Cut Line"), | |
2048 SLOT (request_cut_line (bool))); | |
2049 | |
2050 m_edit_cmd_menu->addSeparator (); | |
2051 | |
2052 m_delete_start_word_action | |
2053 = add_action (m_edit_cmd_menu, tr ("Delete to Start of Word"), | |
2054 SLOT (request_delete_start_word (bool))); | |
2055 | |
2056 m_delete_end_word_action | |
2057 = add_action (m_edit_cmd_menu, tr ("Delete to End of Word"), | |
2058 SLOT (request_delete_end_word (bool))); | |
2059 | |
2060 m_delete_start_line_action | |
2061 = add_action (m_edit_cmd_menu, tr ("Delete to Start of Line"), | |
2062 SLOT (request_delete_start_line (bool))); | |
2063 | |
2064 m_delete_end_line_action | |
2065 = add_action (m_edit_cmd_menu, tr ("Delete to End of Line"), | |
2066 SLOT (request_delete_end_line (bool))); | |
2067 | |
2068 m_edit_cmd_menu->addSeparator (); | |
2069 | |
2070 m_duplicate_selection_action | |
2071 = add_action (m_edit_cmd_menu, tr ("Duplicate Selection/Line"), | |
2072 SLOT (request_duplicate_selection (bool))); | |
2073 | |
2074 m_transpose_line_action | |
2075 = add_action (m_edit_cmd_menu, tr ("Transpose Line"), | |
2076 SLOT (request_transpose_line (bool))); | |
2077 | |
2078 m_edit_cmd_menu->addSeparator (); | |
2079 | |
2080 m_completion_action | |
2081 = add_action (m_edit_cmd_menu, tr ("&Show Completion List"), | |
2082 SLOT (request_completion (bool))); | |
2083 | |
2084 m_edit_fmt_menu = m_edit_menu->addMenu (tr ("&Format")); | |
2085 | |
2086 m_upper_case_action | |
2087 = add_action (m_edit_fmt_menu, tr ("&Uppercase Selection"), | |
2088 SLOT (request_upper_case (bool))); | |
2089 | |
2090 m_lower_case_action | |
2091 = add_action (m_edit_fmt_menu, tr ("&Lowercase Selection"), | |
2092 SLOT (request_lower_case (bool))); | |
2093 | |
2094 m_edit_fmt_menu->addSeparator (); | |
2095 | |
2096 m_comment_selection_action | |
2097 = add_action (m_edit_fmt_menu, tr ("&Comment"), | |
2098 SLOT (request_comment_selected_text (bool))); | |
2099 | |
2100 m_uncomment_selection_action | |
2101 = add_action (m_edit_fmt_menu, tr ("&Uncomment"), | |
2102 SLOT (request_uncomment_selected_text (bool))); | |
2103 | |
2104 m_comment_var_selection_action | |
2105 = add_action (m_edit_fmt_menu, tr ("Comment (Choosing String)"), | |
2106 SLOT (request_comment_var_selected_text (bool))); | |
2107 | |
2108 m_edit_fmt_menu->addSeparator (); | |
2109 | |
2110 m_indent_selection_action | |
2111 = add_action (m_edit_fmt_menu, tr ("&Indent Selection Rigidly"), | |
2112 SLOT (request_indent_selected_text (bool))); | |
2113 | |
2114 m_unindent_selection_action | |
2115 = add_action (m_edit_fmt_menu, tr ("&Unindent Selection Rigidly"), | |
2116 SLOT (request_unindent_selected_text (bool))); | |
2117 | |
2118 m_smart_indent_line_or_selection_action | |
2119 = add_action (m_edit_fmt_menu, tr ("Indent Code"), | |
2120 SLOT (request_smart_indent_line_or_selected_text (void))); | |
2121 | |
2122 m_edit_fmt_menu->addSeparator (); | |
2123 | |
2124 m_conv_eol_windows_action | |
2125 = add_action (m_edit_fmt_menu, | |
2126 tr ("Convert Line Endings to &Windows (CRLF)"), | |
2127 SLOT (request_conv_eol_windows (bool))); | |
2128 | |
2129 m_conv_eol_unix_action | |
2130 = add_action (m_edit_fmt_menu, tr ("Convert Line Endings to &Unix (LF)"), | |
2131 SLOT (request_conv_eol_unix (bool))); | |
2132 | |
2133 m_conv_eol_mac_action | |
2134 = add_action (m_edit_fmt_menu, | |
2135 tr ("Convert Line Endings to Legacy &Mac (CR)"), | |
2136 SLOT (request_conv_eol_mac (bool))); | |
2137 | |
2138 m_edit_nav_menu = m_edit_menu->addMenu (tr ("Navi&gation")); | |
2139 | |
2140 m_goto_line_action | |
2141 = add_action (m_edit_nav_menu, tr ("Go &to Line..."), | |
2142 SLOT (request_goto_line (bool))); | |
2143 | |
2144 m_edit_cmd_menu->addSeparator (); | |
2145 | |
2146 m_move_to_matching_brace | |
2147 = add_action (m_edit_nav_menu, tr ("Move to Matching Brace"), | |
2148 SLOT (request_move_match_brace (bool))); | |
2149 | |
2150 m_sel_to_matching_brace | |
2151 = add_action (m_edit_nav_menu, tr ("Select to Matching Brace"), | |
2152 SLOT (request_sel_match_brace (bool))); | |
2153 | |
2154 m_edit_nav_menu->addSeparator (); | |
2155 | |
2156 m_next_bookmark_action | |
2157 = add_action (m_edit_nav_menu, tr ("&Next Bookmark"), | |
2158 SLOT (request_next_bookmark (bool))); | |
2159 | |
2160 m_previous_bookmark_action | |
2161 = add_action (m_edit_nav_menu, tr ("Pre&vious Bookmark"), | |
2162 SLOT (request_previous_bookmark (bool))); | |
2163 | |
2164 m_toggle_bookmark_action | |
2165 = add_action (m_edit_nav_menu, tr ("Toggle &Bookmark"), | |
2166 SLOT (request_toggle_bookmark (bool))); | |
2167 | |
2168 m_remove_bookmark_action | |
2169 = add_action (m_edit_nav_menu, tr ("&Remove All Bookmarks"), | |
2170 SLOT (request_remove_bookmark (bool))); | |
2171 | |
2172 m_edit_menu->addSeparator (); | |
2173 | |
2174 m_preferences_action | |
2175 = add_action (m_edit_menu, rmgr.icon ("preferences-system"), | |
2176 tr ("&Preferences..."), | |
2177 SLOT (request_preferences (bool))); | |
2178 | |
2179 m_styles_preferences_action | |
2180 = add_action (m_edit_menu, rmgr.icon ("preferences-system"), | |
2181 tr ("&Styles Preferences..."), | |
2182 SLOT (request_styles_preferences (bool))); | |
2183 | |
2184 // view menu | |
2185 | |
2186 QMenu *view_menu = add_menu (m_menu_bar, tr ("&View")); | |
2187 | |
2188 m_view_editor_menu = view_menu->addMenu (tr ("&Editor")); | |
2189 | |
2190 m_show_linenum_action | |
2191 = add_action (m_view_editor_menu, tr ("Show &Line Numbers"), | |
2192 SLOT (show_line_numbers (bool))); | |
2193 m_show_linenum_action->setCheckable (true); | |
2194 | |
2195 m_show_whitespace_action | |
2196 = add_action (m_view_editor_menu, tr ("Show &Whitespace Characters"), | |
2197 SLOT (show_white_space (bool))); | |
2198 m_show_whitespace_action->setCheckable (true); | |
2199 | |
2200 m_show_eol_action | |
2201 = add_action (m_view_editor_menu, tr ("Show Line &Endings"), | |
2202 SLOT (show_eol_chars (bool))); | |
2203 m_show_eol_action->setCheckable (true); | |
2204 | |
2205 m_show_indguide_action | |
2206 = add_action (m_view_editor_menu, tr ("Show &Indentation Guides"), | |
2207 SLOT (show_indent_guides (bool))); | |
2208 m_show_indguide_action->setCheckable (true); | |
2209 | |
2210 m_show_longline_action | |
2211 = add_action (m_view_editor_menu, tr ("Show Long Line &Marker"), | |
2212 SLOT (show_long_line (bool))); | |
2213 m_show_longline_action->setCheckable (true); | |
2214 | |
2215 m_view_editor_menu->addSeparator (); | |
2216 | |
2217 m_show_toolbar_action | |
2218 = add_action (m_view_editor_menu, tr ("Show &Toolbar"), | |
2219 SLOT (show_toolbar (bool))); | |
2220 m_show_toolbar_action->setCheckable (true); | |
2221 | |
2222 m_show_statusbar_action | |
2223 = add_action (m_view_editor_menu, tr ("Show &Statusbar"), | |
2224 SLOT (show_statusbar (bool))); | |
2225 m_show_statusbar_action->setCheckable (true); | |
2226 | |
2227 m_show_hscrollbar_action | |
2228 = add_action (m_view_editor_menu, tr ("Show &Horizontal Scrollbar"), | |
2229 SLOT (show_hscrollbar (bool))); | |
2230 m_show_hscrollbar_action->setCheckable (true); | |
2231 | |
2232 view_menu->addSeparator (); | |
2233 | |
2234 m_zoom_in_action | |
2235 = add_action (view_menu, rmgr.icon ("view-zoom-in"), tr ("Zoom &In"), | |
2236 SLOT (zoom_in (bool))); | |
2237 | |
2238 m_zoom_out_action | |
2239 = add_action (view_menu, rmgr.icon ("view-zoom-out"), tr ("Zoom &Out"), | |
2240 SLOT (zoom_out (bool))); | |
2241 | |
2242 m_zoom_normal_action | |
2243 = add_action (view_menu, rmgr.icon ("view-zoom-original"), tr ("&Normal Size"), | |
2244 SLOT (zoom_normal (bool))); | |
2245 | |
2246 view_menu->addSeparator (); | |
2247 | |
2248 m_sort_tabs_action | |
2249 = add_action (view_menu, tr ("&Sort Tabs Alphabetically"), | |
2250 SLOT (sort_tabs_alph (void)), | |
2251 m_tab_widget->get_tab_bar ()); | |
2252 | |
2253 m_menu_bar->addMenu (view_menu); | |
2254 | |
2255 // debug menu | |
2256 | |
2257 m_debug_menu = add_menu (m_menu_bar, tr ("&Debug")); | |
2258 | |
2259 m_toggle_breakpoint_action | |
2260 = add_action (m_debug_menu, rmgr.icon ("bp-toggle"), | |
2261 tr ("Toggle &Breakpoint"), | |
2262 SLOT (request_toggle_breakpoint (bool))); | |
2263 | |
2264 m_next_breakpoint_action | |
2265 = add_action (m_debug_menu, rmgr.icon ("bp-next"), | |
2266 tr ("&Next Breakpoint"), | |
2267 SLOT (request_next_breakpoint (bool))); | |
2268 | |
2269 m_previous_breakpoint_action | |
2270 = add_action (m_debug_menu, rmgr.icon ("bp-prev"), | |
2271 tr ("Pre&vious Breakpoint"), | |
2272 SLOT (request_previous_breakpoint (bool))); | |
2273 | |
2274 m_remove_all_breakpoints_action | |
2275 = add_action (m_debug_menu, rmgr.icon ("bp-rm-all"), | |
2276 tr ("&Remove All Breakpoints"), | |
2277 SLOT (request_remove_breakpoint (bool))); | |
2278 | |
2279 m_debug_menu->addSeparator (); | |
2280 | |
2281 // The other debug actions will be added by the main window. | |
2282 | |
2283 // run menu | |
2284 | |
2285 QMenu *_run_menu = add_menu (m_menu_bar, tr ("&Run")); | |
2286 | |
2287 m_run_action | |
2288 = add_action (_run_menu, | |
2289 rmgr.icon ("system-run"), | |
2290 tr ("Save File and Run / Continue"), | |
2291 SLOT (request_run_file (bool))); | |
2292 | |
2293 m_run_selection_action | |
2294 = add_action (_run_menu, | |
2295 tr ("Run &Selection"), | |
2296 SLOT (request_context_run (bool))); | |
2297 m_run_selection_action->setEnabled (false); | |
2298 | |
2299 // help menu | |
2300 | |
2301 QMenu *_help_menu = add_menu (m_menu_bar, tr ("&Help")); | |
2302 | |
2303 m_context_help_action | |
2304 = add_action (_help_menu, | |
2305 tr ("&Help on Keyword"), | |
2306 SLOT (request_context_help (bool))); | |
2307 | |
2308 m_context_doc_action | |
2309 = add_action (_help_menu, | |
2310 tr ("&Documentation on Keyword"), | |
2311 SLOT (request_context_doc (bool))); | |
2312 | |
2313 // tab navigation (no menu, only actions; slots in tab_bar) | |
2314 | |
2315 m_switch_left_tab_action | |
2316 = add_action (nullptr, "", SLOT (switch_left_tab (void)), | |
2317 m_tab_widget->get_tab_bar ()); | |
2318 | |
2319 m_switch_right_tab_action | |
2320 = add_action (nullptr, "", SLOT (switch_right_tab (void)), | |
2321 m_tab_widget->get_tab_bar ()); | |
2322 | |
2323 m_move_tab_left_action | |
2324 = add_action (nullptr, "", SLOT (move_tab_left (void)), | |
2325 m_tab_widget->get_tab_bar ()); | |
2326 | |
2327 m_move_tab_right_action | |
2328 = add_action (nullptr, "", SLOT (move_tab_right (void)), | |
2329 m_tab_widget->get_tab_bar ()); | |
2330 | |
2331 // toolbar | |
2332 | |
2333 // popdown menu with mru files | |
2334 QToolButton *popdown_button = new QToolButton (); | |
2335 popdown_button->setToolTip (tr ("Recent Files")); | |
2336 popdown_button->setMenu (m_mru_file_menu); | |
2337 popdown_button->setPopupMode (QToolButton::InstantPopup); | |
2338 popdown_button->setArrowType (Qt::DownArrow); | |
2339 popdown_button->setToolButtonStyle (Qt::ToolButtonTextOnly); | |
2340 | |
2341 // new and open actions are inserted later from main window | |
2342 m_popdown_mru_action = m_tool_bar->addWidget (popdown_button); | |
2343 m_tool_bar->addAction (m_save_action); | |
2344 m_tool_bar->addAction (m_save_as_action); | |
2345 m_tool_bar->addAction (m_print_action); | |
2346 m_tool_bar->addSeparator (); | |
2347 // m_undo_action: later via main window | |
2348 m_tool_bar->addAction (m_redo_action); | |
2349 m_tool_bar->addSeparator (); | |
2350 m_tool_bar->addAction (m_cut_action); | |
2351 // m_copy_action: later via the main window | |
2352 // m_paste_action: later via the main window | |
2353 m_tool_bar->addAction (m_find_action); | |
2354 //m_tool_bar->addAction (m_find_next_action); | |
2355 //m_tool_bar->addAction (m_find_previous_action); | |
2356 m_tool_bar->addSeparator (); | |
2357 m_tool_bar->addAction (m_run_action); | |
2358 m_tool_bar->addSeparator (); | |
2359 m_tool_bar->addAction (m_toggle_breakpoint_action); | |
2360 m_tool_bar->addAction (m_previous_breakpoint_action); | |
2361 m_tool_bar->addAction (m_next_breakpoint_action); | |
2362 m_tool_bar->addAction (m_remove_all_breakpoints_action); | |
2363 | |
2364 // layout | |
2365 QVBoxLayout *vbox_layout = new QVBoxLayout (); | |
2366 vbox_layout->addWidget (m_menu_bar); | |
2367 vbox_layout->addWidget (m_tool_bar); | |
2368 vbox_layout->addWidget (m_tab_widget); | |
2369 vbox_layout->setMargin (0); | |
2370 vbox_layout->setSpacing (0); | |
2371 editor_widget->setLayout (vbox_layout); | |
2372 setWidget (editor_widget); | |
2373 | |
2374 // Create the basic context menu of the tab bar with editor actions. | |
2375 // Actions for selecting an tab are added when the menu is activated. | |
2376 tab_bar *bar = m_tab_widget->get_tab_bar (); | |
2377 QMenu *ctx_men = bar->get_context_menu (); | |
2378 ctx_men->addSeparator (); | |
2379 ctx_men->addAction (m_close_action); | |
2380 ctx_men->addAction (m_close_all_action); | |
2381 ctx_men->addAction (m_close_others_action); | |
2382 ctx_men->addSeparator (); | |
2383 ctx_men->addAction (m_sort_tabs_action); | |
2384 add_action (ctx_men, tr ("Copy Full File &Path"), | |
2385 SLOT (copy_full_file_path (bool)), this); | |
2386 | |
2387 // signals | |
2388 connect (m_mru_file_menu, &QMenu::triggered, | |
2389 this, &file_editor::request_mru_open_file); | |
2390 | |
2391 mru_menu_update (); | |
2392 | |
2393 connect (m_tab_widget, &file_editor_tab_widget::tabCloseRequested, | |
2394 this, &file_editor::handle_tab_close_request); | |
2395 | |
2396 connect (m_tab_widget, &file_editor_tab_widget::currentChanged, | |
2397 this, &file_editor::active_tab_changed); | |
2398 | |
2399 resize (500, 400); | |
2400 set_title (tr ("Editor")); | |
2401 | |
2402 check_actions (); | |
2403 } | |
2404 | |
2405 // Slot when autocompletion list was cancelled | |
2406 void file_editor::handle_autoc_cancelled (void) | |
2407 { | |
2408 // List was cancelled but somehow still active and blocking the | |
2409 // edit area from accepting shortcuts. Only after another keypress | |
2410 // shortcuts and lists are working againnas expected. This is | |
2411 // probably caused by qt bug https://bugreports.qt.io/browse/QTBUG-83720 | |
2412 // Hack: Accept the list, which is hidden but still active | |
2413 // and undo the text insertion, if any | |
2414 | |
2415 file_editor_tab *f = reset_focus (); | |
2416 octave_qscintilla *qsci = f->qsci_edit_area (); | |
2417 | |
2418 int line, col; | |
2419 qsci->getCursorPosition (&line, &col); | |
2420 int l1 = qsci->lineLength (line); // Current line length | |
2421 | |
2422 // Accept autocompletion | |
2423 qsci->SendScintilla (QsciScintillaBase::SCI_AUTOCCOMPLETE); | |
2424 | |
2425 // Was text inserted? If yes, undo | |
2426 if (qsci->text (line).length () - l1) | |
2427 qsci->undo (); | |
2428 } | |
2429 | |
2430 file_editor_tab *file_editor::reset_focus (void) | |
2431 { | |
2432 // Reset the focus of the tab and the related edit area | |
2433 file_editor_tab *f | |
2434 = static_cast<file_editor_tab *> (m_tab_widget->currentWidget ()); | |
2435 emit fetab_set_focus (f); | |
2436 return f; | |
2437 } | |
2438 | |
2439 file_editor_tab * | |
2440 file_editor::make_file_editor_tab (const QString& directory) | |
2441 { | |
2442 file_editor_tab *f = new file_editor_tab (m_octave_qobj, directory); | |
2443 | |
2444 // signals from the qscintilla edit area | |
2445 connect (f->qsci_edit_area (), &octave_qscintilla::status_update, | |
2446 this, &file_editor::edit_status_update); | |
2447 | |
2448 connect (f->qsci_edit_area (), &octave_qscintilla::create_context_menu_signal, | |
2449 this, &file_editor::create_context_menu); | |
2450 | |
2451 connect (f->qsci_edit_area (), | |
2452 SIGNAL (SCN_AUTOCCOMPLETED (const char *, int, int, int)), | |
2453 this, SLOT (reset_focus (void))); | |
2454 | |
2455 connect (f->qsci_edit_area (), SIGNAL (SCN_AUTOCCANCELLED (void)), | |
2456 this, SLOT (handle_autoc_cancelled (void))); | |
2457 | |
2458 // signals from the qscintilla edit area | |
2459 connect (this, &file_editor::enter_debug_mode_signal, | |
2460 f->qsci_edit_area (), &octave_qscintilla::handle_enter_debug_mode); | |
2461 | |
2462 connect (this, &file_editor::exit_debug_mode_signal, | |
2463 f->qsci_edit_area (), &octave_qscintilla::handle_exit_debug_mode); | |
2464 | |
2465 // Signals from the file editor_tab | |
2466 connect (f, &file_editor_tab::autoc_closed, | |
2467 this, &file_editor::reset_focus); | |
2468 | |
2469 connect (f, &file_editor_tab::file_name_changed, | |
2470 this, &file_editor::handle_file_name_changed); | |
2471 | |
2472 connect (f, &file_editor_tab::editor_state_changed, | |
2473 this, &file_editor::handle_editor_state_changed); | |
2474 | |
2475 connect (f, &file_editor_tab::tab_remove_request, | |
2476 this, &file_editor::handle_tab_remove_request); | |
2477 | |
2478 connect (f, &file_editor_tab::editor_check_conflict_save, | |
2479 this, &file_editor::check_conflict_save); | |
2480 | |
2481 connect (f, &file_editor_tab::mru_add_file, | |
2482 this, &file_editor::handle_mru_add_file); | |
2483 | |
2484 connect (f, &file_editor_tab::request_open_file, | |
2485 this, [=] (const QString& fname, const QString& encoding) { request_open_file (fname, encoding); }); | |
2486 | |
2487 connect (f, &file_editor_tab::edit_area_changed, | |
2488 this, &file_editor::edit_area_changed); | |
2489 | |
2490 connect (f, &file_editor_tab::set_focus_editor_signal, | |
2491 this, &file_editor::set_focus); | |
2492 | |
2493 // Signals from the file_editor or main-win non-trivial operations | |
2494 connect (this, &file_editor::fetab_settings_changed, | |
2495 f, [=] (const gui_settings *settings) { f->notice_settings (settings); }); | |
2496 | |
2497 connect (this, &file_editor::fetab_change_request, | |
2498 f, &file_editor_tab::change_editor_state); | |
2499 | |
2500 connect (this, QOverload<const QWidget *, const QString&, bool>::of (&file_editor::fetab_save_file), | |
2501 f, QOverload<const QWidget *, const QString&, bool>::of (&file_editor_tab::save_file)); | |
2502 | |
2503 // Signals from the file_editor trivial operations | |
2504 connect (this, &file_editor::fetab_recover_from_exit, | |
2505 f, &file_editor_tab::recover_from_exit); | |
2506 | |
2507 connect (this, &file_editor::fetab_set_directory, | |
2508 f, &file_editor_tab::set_current_directory); | |
2509 | |
2510 connect (this, &file_editor::fetab_zoom_in, | |
2511 f, &file_editor_tab::zoom_in); | |
2512 connect (this, &file_editor::fetab_zoom_out, | |
2513 f, &file_editor_tab::zoom_out); | |
2514 connect (this, &file_editor::fetab_zoom_normal, | |
2515 f, &file_editor_tab::zoom_normal); | |
2516 | |
2517 connect (this, &file_editor::fetab_context_help, | |
2518 f, &file_editor_tab::context_help); | |
2519 | |
2520 connect (this, &file_editor::fetab_context_edit, | |
2521 f, &file_editor_tab::context_edit); | |
2522 | |
2523 connect (this, QOverload<const QWidget *>::of (&file_editor::fetab_save_file), | |
2524 f, QOverload<const QWidget *>::of (&file_editor_tab::save_file)); | |
2525 | |
2526 connect (this, &file_editor::fetab_save_file_as, | |
2527 f, QOverload<const QWidget *>::of (&file_editor_tab::save_file_as)); | |
2528 | |
2529 connect (this, &file_editor::fetab_print_file, | |
2530 f, &file_editor_tab::print_file); | |
2531 | |
2532 connect (this, &file_editor::fetab_run_file, | |
2533 f, &file_editor_tab::run_file); | |
2534 | |
2535 connect (this, &file_editor::fetab_context_run, | |
2536 f, &file_editor_tab::context_run); | |
2537 | |
2538 connect (this, &file_editor::fetab_toggle_bookmark, | |
2539 f, &file_editor_tab::toggle_bookmark); | |
2540 | |
2541 connect (this, &file_editor::fetab_next_bookmark, | |
2542 f, &file_editor_tab::next_bookmark); | |
2543 | |
2544 connect (this, &file_editor::fetab_previous_bookmark, | |
2545 f, &file_editor_tab::previous_bookmark); | |
2546 | |
2547 connect (this, &file_editor::fetab_remove_bookmark, | |
2548 f, &file_editor_tab::remove_bookmark); | |
2549 | |
2550 connect (this, &file_editor::fetab_toggle_breakpoint, | |
2551 f, &file_editor_tab::toggle_breakpoint); | |
2552 | |
2553 connect (this, &file_editor::fetab_next_breakpoint, | |
2554 f, &file_editor_tab::next_breakpoint); | |
2555 | |
2556 connect (this, &file_editor::fetab_previous_breakpoint, | |
2557 f, &file_editor_tab::previous_breakpoint); | |
2558 | |
2559 connect (this, &file_editor::fetab_remove_all_breakpoints, | |
2560 f, &file_editor_tab::remove_all_breakpoints); | |
2561 | |
2562 connect (this, &file_editor::fetab_scintilla_command, | |
2563 f, &file_editor_tab::scintilla_command); | |
2564 | |
2565 connect (this, &file_editor::fetab_comment_selected_text, | |
2566 f, &file_editor_tab::comment_selected_text); | |
2567 | |
2568 connect (this, &file_editor::fetab_uncomment_selected_text, | |
2569 f, &file_editor_tab::uncomment_selected_text); | |
2570 | |
2571 connect (this, &file_editor::fetab_indent_selected_text, | |
2572 f, &file_editor_tab::indent_selected_text); | |
2573 | |
2574 connect (this, &file_editor::fetab_unindent_selected_text, | |
2575 f, &file_editor_tab::unindent_selected_text); | |
2576 | |
2577 connect (this, &file_editor::fetab_smart_indent_line_or_selected_text, | |
2578 f, &file_editor_tab::smart_indent_line_or_selected_text); | |
2579 | |
2580 connect (this, &file_editor::fetab_convert_eol, | |
2581 f, &file_editor_tab::convert_eol); | |
2582 | |
2583 connect (this, &file_editor::fetab_goto_line, | |
2584 f, &file_editor_tab::goto_line); | |
2585 | |
2586 connect (this, &file_editor::fetab_move_match_brace, | |
2587 f, &file_editor_tab::move_match_brace); | |
2588 | |
2589 connect (this, &file_editor::fetab_completion, | |
2590 f, &file_editor_tab::show_auto_completion); | |
2591 | |
2592 connect (this, &file_editor::fetab_set_focus, | |
2593 f, &file_editor_tab::set_focus); | |
2594 | |
2595 connect (this, &file_editor::fetab_insert_debugger_pointer, | |
2596 f, &file_editor_tab::insert_debugger_pointer); | |
2597 | |
2598 connect (this, &file_editor::fetab_delete_debugger_pointer, | |
2599 f, &file_editor_tab::delete_debugger_pointer); | |
2600 | |
2601 connect (this, &file_editor::fetab_do_breakpoint_marker, | |
2602 f, &file_editor_tab::do_breakpoint_marker); | |
2603 | |
2604 connect (this, &file_editor::update_gui_lexer_signal, | |
2605 f, &file_editor_tab::update_lexer_settings); | |
2606 | |
2607 // Convert other signals from the edit area and tab to editor signals. | |
2608 | |
2609 connect (f->qsci_edit_area (), &octave_qscintilla::execute_command_in_terminal_signal, | |
2610 this, &file_editor::execute_command_in_terminal_signal); | |
2611 | |
2612 connect (f->qsci_edit_area (), &octave_qscintilla::focus_console_after_command_signal, | |
2613 this, &file_editor::focus_console_after_command_signal); | |
2614 | |
2615 connect (f, &file_editor_tab::run_file_signal, | |
2616 this, &file_editor::run_file_signal); | |
2617 | |
2618 connect (f, &file_editor_tab::edit_mfile_request, | |
2619 this, &file_editor::edit_mfile_request); | |
2620 | |
2621 connect (f, &file_editor_tab::debug_quit_signal, | |
2622 this, &file_editor::debug_quit_signal); | |
2623 | |
2624 // Any interpreter_event signal from a file_editor_tab_widget is | |
2625 // handled the same as for the parent main_window object. | |
2626 | |
2627 connect (f, QOverload<const fcn_callback&>::of (&file_editor_tab::interpreter_event), | |
2628 this, QOverload<const fcn_callback&>::of (&file_editor::interpreter_event)); | |
2629 | |
2630 connect (f, QOverload<const meth_callback&>::of (&file_editor_tab::interpreter_event), | |
2631 this, QOverload<const meth_callback&>::of (&file_editor::interpreter_event)); | |
2632 | |
2633 return f; | |
2634 } | |
2635 | |
2636 void file_editor::add_file_editor_tab (file_editor_tab *f, const QString& fn, | |
2637 int index) | |
2638 { | |
2639 if (index == -1) | |
2640 m_tab_widget->addTab (f, fn); | |
2641 else | |
2642 m_tab_widget->insertTab (index, f, fn); | |
2643 | |
2644 m_tab_widget->setCurrentWidget (f); | |
2645 | |
2646 check_actions (); | |
2647 } | |
2648 | |
2649 void file_editor::mru_menu_update (void) | |
2650 { | |
2651 int num_files = qMin (m_mru_files.size (), int (MaxMRUFiles)); | |
2652 | |
2653 // configure and show active actions of mru-menu | |
2654 for (int i = 0; i < num_files; ++i) | |
2655 { | |
2656 QString text = QString ("&%1 %2"). | |
2657 arg ((i+1) % int (MaxMRUFiles)).arg (m_mru_files.at (i)); | |
2658 m_mru_file_actions[i]->setText (text); | |
2659 | |
2660 QStringList action_data; | |
2661 action_data << m_mru_files.at (i) << m_mru_files_encodings.at (i); | |
2662 m_mru_file_actions[i]->setData (action_data); | |
2663 | |
2664 m_mru_file_actions[i]->setVisible (true); | |
2665 } | |
2666 | |
2667 // hide unused mru-menu entries | |
2668 for (int j = num_files; j < MaxMRUFiles; ++j) | |
2669 m_mru_file_actions[j]->setVisible (false); | |
2670 | |
2671 // delete entries in string-list beyond MaxMRUFiles | |
2672 while (m_mru_files.size () > MaxMRUFiles) | |
2673 { | |
2674 m_mru_files.removeLast (); | |
2675 m_mru_files_encodings.removeLast (); | |
2676 } | |
2677 | |
2678 // save actual mru-list in settings | |
2679 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
2680 gui_settings *settings = rmgr.get_settings (); | |
2681 | |
2682 settings->setValue (ed_mru_file_list.key, m_mru_files); | |
2683 settings->setValue (ed_mru_file_encodings.key, m_mru_files_encodings); | |
2684 settings->sync (); | |
2685 } | |
2686 | |
2687 bool file_editor::call_custom_editor (const QString& file_name, int line) | |
2688 { | |
2689 // Check if the user wants to use a custom file editor. | |
2690 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
2691 gui_settings *settings = rmgr.get_settings (); | |
2692 | |
2693 if (settings->value (global_use_custom_editor.key, | |
2694 global_use_custom_editor.def).toBool ()) | |
2695 { | |
2696 // use the external editor interface for handling the call | |
2697 emit request_open_file_external (file_name, line); | |
2698 | |
2699 if (line < 0 && ! file_name.isEmpty ()) | |
2700 handle_mru_add_file (QFileInfo (file_name).canonicalFilePath (), | |
2701 QString ()); | |
2702 | |
2703 return true; | |
2704 } | |
2705 | |
2706 return false; | |
2707 } | |
2708 | |
2709 void file_editor::toggle_preference (const gui_pref& preference) | |
2710 { | |
2711 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
2712 gui_settings *settings = rmgr.get_settings (); | |
2713 | |
2714 bool old = settings->value (preference).toBool (); | |
2715 settings->setValue (preference.key, ! old); | |
2716 notice_settings (settings); | |
2717 } | |
2718 | |
2719 // Function for closing the files in a removed directory | |
2720 void file_editor::handle_dir_remove (const QString& old_name, | |
2721 const QString& new_name) | |
2722 { | |
2723 QDir old_dir (old_name); | |
2724 removed_file_data f_data; | |
2725 | |
2726 std::list<file_editor_tab *> editor_tab_lst = m_tab_widget->tab_list (); | |
2727 | |
2728 for (auto editor_tab : editor_tab_lst) | |
2729 { | |
2730 QString file_name = editor_tab->file_name (); | |
2731 | |
2732 if (file_name.isEmpty ()) | |
2733 continue; // Nothing to do, no valid file name | |
2734 | |
2735 // Get abs. file path and its path relative to the removed directory | |
2736 QString rel_path_to_file = old_dir.relativeFilePath (file_name); | |
2737 QString abs_path_to_file = old_dir.absoluteFilePath (file_name); | |
2738 | |
2739 // Test whether the file is located within the directory that will | |
2740 // be removed. For this, two conditions must be met: | |
2741 // 1. The path of the file rel. to the dir is not equal to the | |
2742 // its absolute one. | |
2743 // If both are equal, then there is no relative path and removed | |
2744 // directory and file are on different drives (e.g. on windows) | |
2745 // 2. The (real) relative path does not start with "../", i.e., | |
2746 // the file can be reached from the directory by descending only | |
2747 if ((rel_path_to_file != abs_path_to_file) | |
2748 && (rel_path_to_file.left (3) != QString ("../"))) | |
2749 { | |
2750 // The currently considered file is included in the | |
2751 // removed/renamed diectory: remeber it | |
2752 if (editor_tab) | |
2753 { | |
2754 editor_tab->enable_file_watcher (false); | |
2755 f_data.editor_tab = editor_tab; | |
2756 | |
2757 // Add the new file path and the encoding for later reloading | |
2758 // if new_name is given | |
2759 if (! new_name.isEmpty ()) | |
2760 { | |
2761 QDir new_dir (new_name); | |
2762 QString append_to_new_dir; | |
2763 if (new_dir.exists ()) | |
2764 { | |
2765 // The new directory already exists (movefile was used). | |
2766 // This means, we have to add the name (not the path) | |
2767 // of the old dir and the relative path to the file | |
2768 // to new dir. | |
2769 append_to_new_dir | |
2770 = old_dir.dirName () + "/" + rel_path_to_file; | |
2771 } | |
2772 else | |
2773 append_to_new_dir = rel_path_to_file; | |
2774 | |
2775 f_data.new_file_name | |
2776 = new_dir.absoluteFilePath (append_to_new_dir); | |
2777 } | |
2778 else | |
2779 f_data.new_file_name = ""; // no new name, just removing this file | |
2780 | |
2781 // Store data in list for later reloading | |
2782 m_tmp_closed_files << f_data; | |
2783 } | |
2784 } | |
2785 } | |
2786 } | |
2787 | |
2788 bool file_editor::editor_tab_has_focus (void) | |
2789 { | |
2790 QWidget *foc_w = focusWidget (); | |
2791 if (foc_w && foc_w->inherits ("octave::octave_qscintilla")) | |
530 return true; | 2792 return true; |
531 } | 2793 return false; |
532 | 2794 } |
533 void file_editor::handle_tab_ready_to_close (void) | 2795 |
534 { | 2796 // Check whether this file is already open in the editor. |
535 if (m_closing_canceled) | 2797 file_editor_tab *file_editor::find_tab_widget (const QString& file) |
536 return; | 2798 { |
537 | 2799 std::string std_file = file.toStdString (); |
538 // FIXME: Why count down to zero here before doing anything? Why | 2800 |
539 // not remove and delete each tab that is ready to be closed, one | 2801 std::list<file_editor_tab *> fe_tab_lst = m_tab_widget->tab_list (); |
540 // per invocation? | 2802 |
541 | 2803 for (auto fe_tab : fe_tab_lst) |
542 m_number_of_tabs--; | 2804 { |
543 | 2805 QString tab_file = fe_tab->file_name (); |
544 if (m_number_of_tabs > 0) | 2806 |
545 return; | 2807 // We check file == tab_file because |
546 | 2808 // |
547 // Here, the application or the editor will be closed -> store the session | 2809 // same_file ("", "") |
548 | 2810 // |
549 // Take care of the find dialog | 2811 // is false |
550 if (m_find_dialog) | 2812 |
551 m_find_dialog->close (); | 2813 if (same_file (std_file, tab_file.toStdString ()) || file == tab_file) |
552 | 2814 return fe_tab; |
553 // Finally close all the tabs and return indication that we can exit | 2815 } |
554 // the application or close the editor. | 2816 |
555 // Closing and deleting the tabs makes the editor visible. In case it was | 2817 return nullptr; |
556 // hidden before, this state has to be restored afterwards. | 2818 } |
557 bool vis = isVisible (); | 2819 |
558 | 2820 QAction * file_editor::add_action (QMenu *menu, const QString& text, |
559 std::list<file_editor_tab *> editor_tab_lst = m_tab_widget->tab_list (); | 2821 const char *member, |
560 for (auto editor_tab : editor_tab_lst) | 2822 QWidget *receiver) |
561 editor_tab->deleteLater (); | 2823 { |
562 | 2824 return add_action (menu, QIcon (), text, member, receiver); |
563 m_tab_widget->clear (); | 2825 } |
564 | 2826 |
565 setVisible (vis); | 2827 QAction * file_editor::add_action (QMenu *menu, const QIcon& icon, |
566 } | 2828 const QString& text, const char *member, |
567 | 2829 QWidget *receiver) |
568 void file_editor::request_new_file (const QString& commands) | 2830 { |
569 { | 2831 QAction *a; |
570 // Custom editor? If yes, we can only call the editor without passing | 2832 QWidget *r = this; |
571 // some initial contents and even without being sure a new file is opened | 2833 |
572 if (call_custom_editor ()) | 2834 if (receiver != nullptr) |
573 return; | 2835 r = receiver; |
574 | 2836 |
575 // New file isn't a file_editor_tab function since the file | 2837 if (menu) |
576 // editor tab has yet to be created and there is no object to | 2838 a = menu->addAction (icon, text, r, member); |
577 // pass a signal to. Hence, functionality is here. | 2839 else |
578 | 2840 { |
579 file_editor_tab *fileEditorTab = make_file_editor_tab (m_ced); | 2841 a = new QAction (this); |
580 add_file_editor_tab (fileEditorTab, ""); // new tab with empty title | 2842 connect (a, SIGNAL (triggered ()), r, member); |
581 fileEditorTab->new_file (commands); // title is updated here | 2843 } |
582 activate (); // focus editor and new tab | 2844 |
583 } | 2845 addAction (a); // important for shortcut context |
584 | 2846 a->setShortcutContext (Qt::WidgetWithChildrenShortcut); |
585 void file_editor::request_close_file (bool) | 2847 |
586 { | 2848 return a; |
587 file_editor_tab *editor_tab | 2849 } |
588 = static_cast<file_editor_tab *> (m_tab_widget->currentWidget ()); | 2850 |
589 editor_tab->conditional_close (); | 2851 QMenu* file_editor::add_menu (QMenuBar *p, QString name) |
590 } | 2852 { |
591 | 2853 QMenu *menu = p->addMenu (name); |
592 void file_editor::request_close_all_files (bool) | 2854 |
593 { | 2855 QString base_name = name; // get a copy |
594 file_editor_tab *editor_tab; | 2856 // replace intended '&' ("&&") by a temp. string |
595 | 2857 base_name.replace ("&&", "___octave_amp_replacement___"); |
596 // loop over all tabs starting from last one otherwise deletion changes index | 2858 // remove single '&' (shortcut) |
597 for (int index = m_tab_widget->count ()-1; index >= 0; index--) | 2859 base_name.remove ("&"); |
598 { | 2860 // restore intended '&' |
599 editor_tab = static_cast<file_editor_tab *> (m_tab_widget->widget (index)); | 2861 base_name.replace ("___octave_amp_replacement___", "&&"); |
600 editor_tab->conditional_close (); | 2862 |
601 } | 2863 // remember names with and without shortcut |
602 } | 2864 m_hash_menu_text[menu] = QStringList () << name << base_name; |
603 | 2865 |
604 void file_editor::request_close_other_files (bool) | 2866 return menu; |
605 { | 2867 } |
606 file_editor_tab *editor_tab; | 2868 |
607 QWidget *tabID = m_tab_widget->currentWidget (); | 2869 OCTAVE_END_NAMESPACE(octave) |
608 | 2870 |
609 // loop over all tabs starting from last one otherwise deletion changes index | |
610 for (int index = m_tab_widget->count ()-1; index >= 0; index--) | |
611 { | |
612 if (tabID != m_tab_widget->widget (index)) | |
613 { | |
614 editor_tab | |
615 = static_cast<file_editor_tab *> (m_tab_widget->widget (index)); | |
616 editor_tab->conditional_close (); | |
617 } | |
618 } | |
619 } | |
620 | |
621 void file_editor::copy_full_file_path (bool) | |
622 { | |
623 file_editor_tab *editor_tab | |
624 = static_cast<file_editor_tab *> (m_tab_widget->currentWidget ()); | |
625 | |
626 if (editor_tab) | |
627 QGuiApplication::clipboard ()->setText (editor_tab->file_name ()); | |
628 } | |
629 | |
630 // open a file from the mru list | |
631 void file_editor::request_mru_open_file (QAction *action) | |
632 { | |
633 if (action) | |
634 { | |
635 request_open_file (action->data ().toStringList ().at (0), | |
636 action->data ().toStringList ().at (1)); | |
637 } | |
638 } | |
639 | |
640 void file_editor::request_print_file (bool) | |
641 { | |
642 emit fetab_print_file (m_tab_widget->currentWidget ()); | |
643 } | |
644 | |
645 void file_editor::request_redo (bool) | |
646 { | |
647 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
648 QsciScintillaBase::SCI_REDO); | |
649 } | |
650 | |
651 void file_editor::request_cut (bool) | |
652 { | |
653 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
654 QsciScintillaBase::SCI_CUT); | |
655 } | |
656 | |
657 void file_editor::request_context_help (bool) | |
658 { | |
659 emit fetab_context_help (m_tab_widget->currentWidget (), false); | |
660 } | |
661 | |
662 void file_editor::request_context_doc (bool) | |
663 { | |
664 emit fetab_context_help (m_tab_widget->currentWidget (), true); | |
665 } | |
666 | |
667 void file_editor::request_context_edit (bool) | |
668 { | |
669 emit fetab_context_edit (m_tab_widget->currentWidget ()); | |
670 } | |
671 | |
672 void file_editor::request_save_file (bool) | |
673 { | |
674 emit fetab_save_file (m_tab_widget->currentWidget ()); | |
675 } | |
676 | |
677 void file_editor::request_save_file_as (bool) | |
678 { | |
679 emit fetab_save_file_as (m_tab_widget->currentWidget ()); | |
680 } | |
681 | |
682 void file_editor::request_run_file (bool) | |
683 { | |
684 emit interpreter_event | |
685 ([=] (interpreter& interp) | |
686 { | |
687 // INTERPRETER THREAD | |
688 | |
689 // Act as though this action was entered at the command propmt | |
690 // so that the interpreter will check for updated file time | |
691 // stamps. | |
692 Vlast_prompt_time.stamp (); | |
693 | |
694 tree_evaluator& tw = interp.get_evaluator (); | |
695 | |
696 if (tw.in_debug_repl ()) | |
697 emit request_dbcont_signal (); | |
698 else | |
699 emit fetab_run_file (m_tab_widget->currentWidget ()); | |
700 }); | |
701 } | |
702 | |
703 void file_editor::request_step_into_file () | |
704 { | |
705 emit fetab_run_file (m_tab_widget->currentWidget (), true); | |
706 } | |
707 | |
708 void file_editor::request_context_run (bool) | |
709 { | |
710 emit fetab_context_run (m_tab_widget->currentWidget ()); | |
711 } | |
712 | |
713 void file_editor::request_toggle_bookmark (bool) | |
714 { | |
715 emit fetab_toggle_bookmark (m_tab_widget->currentWidget ()); | |
716 } | |
717 | |
718 void file_editor::request_next_bookmark (bool) | |
719 { | |
720 emit fetab_next_bookmark (m_tab_widget->currentWidget ()); | |
721 } | |
722 | |
723 void file_editor::request_previous_bookmark (bool) | |
724 { | |
725 emit fetab_previous_bookmark (m_tab_widget->currentWidget ()); | |
726 } | |
727 | |
728 void file_editor::request_remove_bookmark (bool) | |
729 { | |
730 emit fetab_remove_bookmark (m_tab_widget->currentWidget ()); | |
731 } | |
732 | |
733 void file_editor::request_move_match_brace (bool) | |
734 { | |
735 emit fetab_move_match_brace (m_tab_widget->currentWidget (), false); | |
736 } | |
737 | |
738 void file_editor::request_sel_match_brace (bool) | |
739 { | |
740 emit fetab_move_match_brace (m_tab_widget->currentWidget (), true); | |
741 } | |
742 | |
743 // FIXME: What should this do with conditional breakpoints? | |
744 void file_editor::request_toggle_breakpoint (bool) | |
745 { | |
746 emit fetab_toggle_breakpoint (m_tab_widget->currentWidget ()); | |
747 } | |
748 | |
749 void file_editor::request_next_breakpoint (bool) | |
750 { | |
751 emit fetab_next_breakpoint (m_tab_widget->currentWidget ()); | |
752 } | |
753 | |
754 void file_editor::request_previous_breakpoint (bool) | |
755 { | |
756 emit fetab_previous_breakpoint (m_tab_widget->currentWidget ()); | |
757 } | |
758 | |
759 void file_editor::request_remove_breakpoint (bool) | |
760 { | |
761 emit fetab_remove_all_breakpoints (m_tab_widget->currentWidget ()); | |
762 } | |
763 | |
764 // slots for Edit->Commands actions | |
765 void file_editor::request_delete_start_word (bool) | |
766 { | |
767 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
768 QsciScintillaBase::SCI_DELWORDLEFT); | |
769 } | |
770 | |
771 void file_editor::request_delete_end_word (bool) | |
772 { | |
773 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
774 QsciScintillaBase::SCI_DELWORDRIGHT); | |
775 } | |
776 | |
777 void file_editor::request_delete_start_line (bool) | |
778 { | |
779 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
780 QsciScintillaBase::SCI_DELLINELEFT); | |
781 } | |
782 | |
783 void file_editor::request_delete_end_line (bool) | |
784 { | |
785 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
786 QsciScintillaBase::SCI_DELLINERIGHT); | |
787 } | |
788 | |
789 void file_editor::request_delete_line (bool) | |
790 { | |
791 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
792 QsciScintillaBase::SCI_LINEDELETE); | |
793 } | |
794 | |
795 void file_editor::request_copy_line (bool) | |
796 { | |
797 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
798 QsciScintillaBase::SCI_LINECOPY); | |
799 } | |
800 | |
801 void file_editor::request_cut_line (bool) | |
802 { | |
803 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
804 QsciScintillaBase::SCI_LINECUT); | |
805 } | |
806 | |
807 void file_editor::request_duplicate_selection (bool) | |
808 { | |
809 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
810 QsciScintillaBase::SCI_SELECTIONDUPLICATE); | |
811 } | |
812 | |
813 void file_editor::request_transpose_line (bool) | |
814 { | |
815 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
816 QsciScintillaBase::SCI_LINETRANSPOSE); | |
817 } | |
818 | |
819 void file_editor::request_comment_selected_text (bool) | |
820 { | |
821 emit fetab_comment_selected_text (m_tab_widget->currentWidget (), false); | |
822 } | |
823 | |
824 void file_editor::request_uncomment_selected_text (bool) | |
825 { | |
826 emit fetab_uncomment_selected_text (m_tab_widget->currentWidget ()); | |
827 } | |
828 | |
829 void file_editor::request_comment_var_selected_text (bool) | |
830 { | |
831 emit fetab_comment_selected_text (m_tab_widget->currentWidget (), true); | |
832 } | |
833 | |
834 // slots for Edit->Format actions | |
835 void file_editor::request_upper_case (bool) | |
836 { | |
837 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
838 QsciScintillaBase::SCI_UPPERCASE); | |
839 } | |
840 | |
841 void file_editor::request_lower_case (bool) | |
842 { | |
843 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
844 QsciScintillaBase::SCI_LOWERCASE); | |
845 } | |
846 | |
847 void file_editor::request_indent_selected_text (bool) | |
848 { | |
849 emit fetab_indent_selected_text (m_tab_widget->currentWidget ()); | |
850 } | |
851 | |
852 void file_editor::request_unindent_selected_text (bool) | |
853 { | |
854 emit fetab_unindent_selected_text (m_tab_widget->currentWidget ()); | |
855 } | |
856 | |
857 void file_editor::request_smart_indent_line_or_selected_text () | |
858 { | |
859 emit fetab_smart_indent_line_or_selected_text (m_tab_widget->currentWidget ()); | |
860 } | |
861 | |
862 void file_editor::request_conv_eol_windows (bool) | |
863 { | |
864 emit fetab_convert_eol (m_tab_widget->currentWidget (), | |
865 QsciScintilla::EolWindows); | |
866 } | |
867 void | |
868 file_editor::request_conv_eol_unix (bool) | |
869 { | |
870 emit fetab_convert_eol (m_tab_widget->currentWidget (), | |
871 QsciScintilla::EolUnix); | |
872 } | |
873 | |
874 void file_editor::request_conv_eol_mac (bool) | |
875 { | |
876 emit fetab_convert_eol (m_tab_widget->currentWidget (), | |
877 QsciScintilla::EolMac); | |
878 } | |
879 | |
880 // Slot for initially creating and showing the find dialog | |
881 void file_editor::request_find (bool) | |
882 { | |
883 // Create the dialog | |
884 find_create (); | |
885 | |
886 // Since find_create shows the dialog without activating the widget | |
887 // (which is reuqired in other cases) do this manually here | |
888 m_find_dialog->activateWindow (); | |
889 | |
890 // Initiate search text from possible selection and save the initial | |
891 // data from the dialog on the defined structure | |
892 m_find_dialog->init_search_text (); | |
893 } | |
894 | |
895 // This method creates the find dialog. | |
896 | |
897 void file_editor::find_create () | |
898 { | |
899 if (m_find_dialog) | |
900 m_find_dialog->close (); | |
901 | |
902 if (isFloating ()) | |
903 m_find_dialog = new find_dialog (m_octave_qobj, this, this); | |
904 else | |
905 m_find_dialog = new find_dialog (m_octave_qobj, this, parentWidget ()); | |
906 | |
907 // Add required actions | |
908 m_find_dialog->addAction (m_find_next_action); | |
909 m_find_dialog->addAction (m_find_previous_action); | |
910 | |
911 // Update edit area | |
912 file_editor_tab *fet | |
913 = static_cast<file_editor_tab *> (m_tab_widget->currentWidget ()); | |
914 m_find_dialog->update_edit_area (fet->qsci_edit_area ()); | |
915 | |
916 // Icon is the same as the editor | |
917 m_find_dialog->setWindowIcon (windowIcon ()); | |
918 | |
919 // Position: lower right of editor's position | |
920 int xp = x () + frameGeometry ().width (); | |
921 int yp = y () + frameGeometry ().height (); | |
922 | |
923 if (! isFloating ()) | |
924 { | |
925 // Fix position if editor is docked | |
926 | |
927 QWidget *parent = parentWidget (); | |
928 | |
929 if (parent) | |
930 { | |
931 xp = xp + parent->x (); | |
932 yp = yp + parent->y (); | |
933 } | |
934 } | |
935 | |
936 if (yp < 0) | |
937 yp = 0; | |
938 | |
939 // The size of the find dialog is considered in restore_settings | |
940 // since its size might change depending on the options | |
941 m_find_dialog->restore_settings (QPoint (xp, yp)); | |
942 | |
943 // Set visible | |
944 m_find_dialog->set_visible (true); | |
945 } | |
946 | |
947 void file_editor::request_find_next (bool) | |
948 { | |
949 if (m_find_dialog) | |
950 m_find_dialog->find_next (); | |
951 } | |
952 | |
953 void file_editor::request_find_previous (bool) | |
954 { | |
955 if (m_find_dialog) | |
956 m_find_dialog->find_prev (); | |
957 } | |
958 | |
959 void file_editor::request_goto_line (bool) | |
960 { | |
961 emit fetab_goto_line (m_tab_widget->currentWidget ()); | |
962 } | |
963 | |
964 void file_editor::request_completion (bool) | |
965 { | |
966 emit fetab_completion (m_tab_widget->currentWidget ()); | |
967 } | |
968 | |
969 void file_editor::handle_file_name_changed (const QString& fname, | |
970 const QString& tip, | |
971 bool modified) | |
972 { | |
973 QObject *fileEditorTab = sender (); | |
974 if (fileEditorTab) | |
975 { | |
976 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
977 | |
978 for (int i = 0; i < m_tab_widget->count (); i++) | |
979 { | |
980 if (m_tab_widget->widget (i) == fileEditorTab) | |
981 { | |
982 m_tab_widget->setTabText (i, fname); | |
983 m_tab_widget->setTabToolTip (i, tip); | |
984 | |
985 m_save_action->setEnabled (modified); | |
986 m_current_tab_modified = modified; | |
987 | |
988 if (modified) | |
989 m_tab_widget->setTabIcon (i, rmgr.icon ("document-save")); | |
990 else | |
991 m_tab_widget->setTabIcon (i, QIcon ()); | |
992 } | |
993 } | |
994 } | |
995 } | |
996 | |
997 void file_editor::handle_tab_close_request (int index) | |
998 { | |
999 file_editor_tab *editor_tab | |
1000 = static_cast<file_editor_tab *> (m_tab_widget->widget (index)); | |
1001 editor_tab->conditional_close (); | |
1002 } | |
1003 | |
1004 void | |
1005 file_editor::handle_tab_remove_request (void) | |
1006 { | |
1007 QObject *fileEditorTab = sender (); | |
1008 if (fileEditorTab) | |
1009 { | |
1010 for (int i = 0; i < m_tab_widget->count (); i++) | |
1011 { | |
1012 if (m_tab_widget->widget (i) == fileEditorTab) | |
1013 { | |
1014 m_tab_widget->removeTab (i); | |
1015 | |
1016 // Deleting the sender (even with deleteLater) seems a | |
1017 // bit strange. Is there a better way? | |
1018 fileEditorTab->deleteLater (); | |
1019 break; | |
1020 } | |
1021 } | |
1022 } | |
1023 check_actions (); | |
1024 | |
1025 activate (); // focus stays in editor when tab is closed | |
1026 | |
1027 } | |
1028 | |
1029 // context menu of edit area | |
1030 void file_editor::active_tab_changed (int index) | |
1031 { | |
1032 emit fetab_change_request (m_tab_widget->widget (index)); | |
1033 activate (); | |
1034 } | |
1035 | |
1036 void file_editor::handle_editor_state_changed (bool copy_available, | |
1037 bool is_octave_file, | |
1038 bool is_modified) | |
1039 { | |
1040 // In case there is some scenario where traffic could be coming from | |
1041 // all the file editor tabs, just process info from the current active tab. | |
1042 if (sender () == m_tab_widget->currentWidget ()) | |
1043 { | |
1044 m_save_action->setEnabled (is_modified); | |
1045 m_current_tab_modified = is_modified; | |
1046 | |
1047 if (m_copy_action) | |
1048 m_copy_action->setEnabled (copy_available); | |
1049 | |
1050 m_cut_action->setEnabled (copy_available); | |
1051 | |
1052 m_run_selection_action->setEnabled (copy_available); | |
1053 m_run_action->setEnabled (is_octave_file); | |
1054 m_is_octave_file = is_octave_file; | |
1055 | |
1056 emit editor_tabs_changed_signal (true, m_is_octave_file); | |
1057 } | |
1058 | |
1059 m_copy_action_enabled = m_copy_action->isEnabled (); | |
1060 m_undo_action_enabled = m_undo_action->isEnabled (); | |
1061 } | |
1062 | |
1063 void file_editor::handle_mru_add_file (const QString& file_name, | |
1064 const QString& encoding) | |
1065 { | |
1066 int index; | |
1067 while ((index = m_mru_files.indexOf (file_name)) >= 0) | |
1068 { | |
1069 m_mru_files.removeAt (index); | |
1070 m_mru_files_encodings.removeAt (index); | |
1071 } | |
1072 | |
1073 m_mru_files.prepend (file_name); | |
1074 m_mru_files_encodings.prepend (encoding); | |
1075 | |
1076 mru_menu_update (); | |
1077 } | |
1078 | |
1079 void file_editor::check_conflict_save (const QString& saveFileName, | |
1080 bool remove_on_success) | |
1081 { | |
1082 // Check whether this file is already open in the editor. | |
1083 file_editor_tab *tab = find_tab_widget (saveFileName); | |
1084 | |
1085 if (tab) | |
1086 { | |
1087 // Note: to overwrite the contents of some other file editor tab | |
1088 // with the same name requires identifying which file editor tab | |
1089 // that is (not too difficult) then closing that tab. Of course, | |
1090 // that could trigger another dialog box if the file editor tab | |
1091 // with the same name has modifications in it. This could become | |
1092 // somewhat confusing to the user. For now, opt to do nothing. | |
1093 | |
1094 // Create a NonModal message about error. | |
1095 QMessageBox *msgBox | |
1096 = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), | |
1097 tr ("File not saved! A file with the selected name\n%1\n" | |
1098 "is already open in the editor"). | |
1099 arg (saveFileName), | |
1100 QMessageBox::Ok, nullptr); | |
1101 | |
1102 msgBox->setWindowModality (Qt::NonModal); | |
1103 msgBox->setAttribute (Qt::WA_DeleteOnClose); | |
1104 msgBox->show (); | |
1105 | |
1106 return; | |
1107 } | |
1108 | |
1109 QObject *saveFileObject = sender (); | |
1110 QWidget *saveFileWidget = nullptr; | |
1111 | |
1112 for (int i = 0; i < m_tab_widget->count (); i++) | |
1113 { | |
1114 if (m_tab_widget->widget (i) == saveFileObject) | |
1115 { | |
1116 saveFileWidget = m_tab_widget->widget (i); | |
1117 break; | |
1118 } | |
1119 } | |
1120 if (! saveFileWidget) | |
1121 { | |
1122 // Create a NonModal message about error. | |
1123 QMessageBox *msgBox | |
1124 = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), | |
1125 tr ("The associated file editor tab has disappeared."), | |
1126 QMessageBox::Ok, nullptr); | |
1127 | |
1128 msgBox->setWindowModality (Qt::NonModal); | |
1129 msgBox->setAttribute (Qt::WA_DeleteOnClose); | |
1130 msgBox->show (); | |
1131 | |
1132 return; | |
1133 } | |
1134 | |
1135 // Can save without conflict, have the file editor tab do so. | |
1136 emit fetab_save_file (saveFileWidget, saveFileName, remove_on_success); | |
1137 } | |
1138 | |
1139 void file_editor::handle_insert_debugger_pointer_request (const QString& file, | |
1140 int line) | |
1141 { | |
1142 request_open_file (file, QString (), line, true); // default encoding | |
1143 } | |
1144 | |
1145 void file_editor::handle_delete_debugger_pointer_request (const QString& file, | |
1146 int line) | |
1147 { | |
1148 if (! file.isEmpty ()) | |
1149 { | |
1150 // Check whether this file is already open in the editor. | |
1151 file_editor_tab *tab = find_tab_widget (file); | |
1152 | |
1153 if (tab) | |
1154 { | |
1155 m_tab_widget->setCurrentWidget (tab); | |
1156 | |
1157 if (line > 0) | |
1158 emit fetab_delete_debugger_pointer (tab, line); | |
1159 | |
1160 emit fetab_set_focus (tab); | |
1161 } | |
1162 } | |
1163 } | |
1164 | |
1165 void file_editor::handle_update_breakpoint_marker_request (bool insert, | |
1166 const QString& file, | |
1167 int line, | |
1168 const QString& cond) | |
1169 { | |
1170 request_open_file (file, QString (), line, false, true, insert, cond); | |
1171 } | |
1172 | |
1173 void file_editor::handle_edit_file_request (const QString& file) | |
1174 { | |
1175 request_open_file (file); | |
1176 } | |
1177 | |
1178 // Slot used for signals indicating that a file was changed/renamed or | |
1179 // is going to be deleted/renamed | |
1180 void file_editor::handle_file_remove (const QString& old_name, | |
1181 const QString& new_name) | |
1182 { | |
1183 // Clear old list of file data and declare a structure for file data | |
1184 m_tmp_closed_files.clear (); | |
1185 removed_file_data f_data; | |
1186 | |
1187 // Preprocessing old name(s) | |
1188 QString old_name_clean = old_name.trimmed (); | |
1189 int s = old_name_clean.size (); | |
1190 | |
1191 if (s > 1 && old_name_clean.at (0) == QChar ('\"') | |
1192 && old_name_clean.at (s - 1) == QChar ('\"')) | |
1193 old_name_clean = old_name_clean.mid (1, s - 2); | |
1194 | |
1195 QStringList old_names = old_name_clean.split ("\" \""); | |
1196 | |
1197 // Check if new name is a file or directory | |
1198 QFileInfo newf (new_name); | |
1199 bool new_is_dir = newf.isDir (); | |
1200 | |
1201 // Now loop over all old files/dirs (several files by movefile ()) | |
1202 for (int i = 0; i < old_names.count (); i++) | |
1203 { | |
1204 // Check if old name is a file or directory | |
1205 QFileInfo old (old_names.at (i)); | |
1206 | |
1207 if (old.isDir ()) | |
1208 { | |
1209 // Call the function which handles directories and return | |
1210 handle_dir_remove (old_names.at (i), new_name); | |
1211 } | |
1212 else | |
1213 { | |
1214 // It is a single file. Is it open? | |
1215 file_editor_tab *editor_tab = find_tab_widget (old_names.at (i)); | |
1216 | |
1217 if (editor_tab) | |
1218 { | |
1219 | |
1220 editor_tab->enable_file_watcher (false); | |
1221 | |
1222 // For re-enabling tracking if error while removing/renaming | |
1223 f_data.editor_tab = editor_tab; | |
1224 // For renaming into new file (if new_file is not empty) | |
1225 if (new_is_dir) | |
1226 { | |
1227 std::string ndir = new_name.toStdString (); | |
1228 std::string ofile = old.fileName ().toStdString (); | |
1229 f_data.new_file_name | |
1230 = QString::fromStdString (sys::env::make_absolute (ofile, ndir)); | |
1231 } | |
1232 else | |
1233 f_data.new_file_name = new_name; | |
1234 | |
1235 // Add file data to list | |
1236 m_tmp_closed_files << f_data; | |
1237 } | |
1238 } | |
1239 } | |
1240 } | |
1241 | |
1242 // Slot for signal indicating that a file was renamed | |
1243 void file_editor::handle_file_renamed (bool load_new) | |
1244 { | |
1245 m_no_focus = true; // Remember for not focussing editor | |
1246 | |
1247 // Loop over all files that have to be handled. Start at the end of the | |
1248 // list, otherwise the stored indexes are not correct. | |
1249 for (int i = m_tmp_closed_files.count () - 1; i >= 0; i--) | |
1250 { | |
1251 if (load_new) | |
1252 { | |
1253 // Close file (remove) or rename into new file (rename) | |
1254 if (m_tmp_closed_files.at (i).new_file_name.isEmpty ()) | |
1255 m_tmp_closed_files.at (i).editor_tab->file_has_changed (QString (), true); | |
1256 else | |
1257 m_tmp_closed_files.at (i).editor_tab->set_file_name ( | |
1258 m_tmp_closed_files.at (i).new_file_name); | |
1259 } | |
1260 else | |
1261 { | |
1262 // Something went wrong while renaming or removing: | |
1263 // Leave everything as it is but reactivate tracking | |
1264 m_tmp_closed_files.at (i).editor_tab->enable_file_watcher (true); | |
1265 } | |
1266 | |
1267 } | |
1268 | |
1269 m_no_focus = false; // Back to normal focus | |
1270 | |
1271 // Clear the list of file data | |
1272 m_tmp_closed_files.clear (); | |
1273 } | |
1274 | |
1275 void file_editor::notice_settings (const gui_settings *settings) | |
1276 { | |
1277 int size_idx = settings->value (global_icon_size).toInt (); | |
1278 size_idx = (size_idx > 0) - (size_idx < 0) + 1; // Make valid index from 0 to 2 | |
1279 | |
1280 QStyle *st = style (); | |
1281 int icon_size = st->pixelMetric (global_icon_sizes[size_idx]); | |
1282 m_tool_bar->setIconSize (QSize (icon_size, icon_size)); | |
1283 | |
1284 // Tab position and rotation | |
1285 QTabWidget::TabPosition pos | |
1286 = static_cast<QTabWidget::TabPosition> (settings->value (ed_tab_position).toInt ()); | |
1287 bool rotated = settings->value (ed_tabs_rotated).toBool (); | |
1288 | |
1289 m_tab_widget->setTabPosition (pos); | |
1290 | |
1291 if (rotated) | |
1292 m_tab_widget->setTabsClosable (false); // No close buttons | |
1293 // FIXME: close buttons can not be correctly placed in rotated tabs | |
1294 | |
1295 // Get the tab bar and set the rotation | |
1296 int rotation = rotated; | |
1297 if (pos == QTabWidget::West) | |
1298 rotation = -rotation; | |
1299 | |
1300 tab_bar *bar = m_tab_widget->get_tab_bar (); | |
1301 bar->set_rotated (rotation); | |
1302 | |
1303 // Get suitable height of a tab related to font and icon size | |
1304 int height = 1.5*QFontMetrics (m_tab_widget->font ()).height (); | |
1305 int is = 1.5*m_tab_widget->iconSize ().height (); | |
1306 if (is > height) | |
1307 height = is; | |
1308 | |
1309 // Calculate possibly limited width and set the elide mode | |
1310 int chars = settings->value (ed_tabs_max_width).toInt (); | |
1311 int width = 9999; | |
1312 if (chars > 0) | |
1313 width = chars * QFontMetrics (m_tab_widget->font ()).averageCharWidth (); | |
1314 | |
1315 // Get tab bar size properties for style sheet depending on rotation | |
1316 QString width_str ("width"); | |
1317 QString height_str ("height"); | |
1318 if ((pos == QTabWidget::West) || (pos == QTabWidget::East)) | |
1319 { | |
1320 width_str = QString ("height"); | |
1321 height_str = QString ("width"); | |
1322 } | |
1323 | |
1324 QString style_sheet | |
1325 = QString ("QTabBar::tab {max-" + height_str + ": %1px;\n" | |
1326 "max-" + width_str + ": %2px; }") | |
1327 .arg (height).arg (width); | |
1328 | |
1329 #if defined (Q_OS_MAC) | |
1330 // FIXME: This is a workaround for missing tab close buttons on MacOS | |
1331 // in several Qt versions (https://bugreports.qt.io/browse/QTBUG-61092) | |
1332 if (! rotated) | |
1333 { | |
1334 QString icon = global_icon_paths.at (ICON_THEME_OCTAVE) + "widget-close.png"; | |
1335 | |
1336 QString close_button_css_mac ( | |
1337 "QTabBar::close-button" | |
1338 " { image: url(" + icon + ");" | |
1339 " padding: 4px;" | |
1340 " subcontrol-position: bottom; }\n" | |
1341 "QTabBar::close-button:hover" | |
1342 " { background-color: #cccccc; }"); | |
1343 | |
1344 style_sheet = style_sheet + close_button_css_mac; | |
1345 } | |
1346 #endif | 2871 #endif |
1347 | |
1348 m_tab_widget->setStyleSheet (style_sheet); | |
1349 | |
1350 bool show_it; | |
1351 show_it = settings->value (ed_show_line_numbers).toBool (); | |
1352 m_show_linenum_action->setChecked (show_it); | |
1353 show_it = settings->value (ed_show_white_space).toBool (); | |
1354 m_show_whitespace_action->setChecked (show_it); | |
1355 show_it = settings->value (ed_show_eol_chars).toBool (); | |
1356 m_show_eol_action->setChecked (show_it); | |
1357 show_it = settings->value (ed_show_indent_guides).toBool (); | |
1358 m_show_indguide_action->setChecked (show_it); | |
1359 show_it = settings->value (ed_long_line_marker).toBool (); | |
1360 m_show_longline_action->setChecked (show_it); | |
1361 | |
1362 show_it = settings->value (ed_show_toolbar).toBool (); | |
1363 m_show_toolbar_action->setChecked (show_it); | |
1364 m_tool_bar->setVisible (show_it); | |
1365 show_it = settings->value (ed_show_edit_status_bar).toBool (); | |
1366 m_show_statusbar_action->setChecked (show_it); | |
1367 show_it = settings->value (ed_show_hscroll_bar).toBool (); | |
1368 m_show_hscrollbar_action->setChecked (show_it); | |
1369 | |
1370 set_shortcuts (); | |
1371 | |
1372 // Find dialog with the same icon as the editor | |
1373 if (m_find_dialog) | |
1374 m_find_dialog->setWindowIcon (windowIcon ()); | |
1375 | |
1376 // Relay signal to file editor tabs. | |
1377 emit fetab_settings_changed (settings); | |
1378 } | |
1379 | |
1380 void file_editor::set_shortcuts (void) | |
1381 { | |
1382 // Shortcuts also available in the main window, as well as the related | |
1383 // shortcuts, are defined in main_window and added to the editor | |
1384 | |
1385 shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager (); | |
1386 | |
1387 // File menu | |
1388 scmgr.set_shortcut (m_edit_function_action, sc_edit_file_edit_function); | |
1389 scmgr.set_shortcut (m_save_action, sc_edit_file_save); | |
1390 scmgr.set_shortcut (m_save_as_action, sc_edit_file_save_as); | |
1391 scmgr.set_shortcut (m_close_action, sc_edit_file_close); | |
1392 scmgr.set_shortcut (m_close_all_action, sc_edit_file_close_all); | |
1393 scmgr.set_shortcut (m_close_others_action, sc_edit_file_close_other); | |
1394 scmgr.set_shortcut (m_print_action, sc_edit_file_print); | |
1395 | |
1396 // Edit menu | |
1397 scmgr.set_shortcut (m_redo_action, sc_edit_edit_redo); | |
1398 scmgr.set_shortcut (m_cut_action, sc_edit_edit_cut); | |
1399 scmgr.set_shortcut (m_find_action, sc_edit_edit_find_replace); | |
1400 scmgr.set_shortcut (m_find_next_action, sc_edit_edit_find_next); | |
1401 scmgr.set_shortcut (m_find_previous_action, sc_edit_edit_find_previous); | |
1402 | |
1403 scmgr.set_shortcut (m_delete_start_word_action, sc_edit_edit_delete_start_word); | |
1404 scmgr.set_shortcut (m_delete_end_word_action, sc_edit_edit_delete_end_word); | |
1405 scmgr.set_shortcut (m_delete_start_line_action, sc_edit_edit_delete_start_line); | |
1406 scmgr.set_shortcut (m_delete_end_line_action, sc_edit_edit_delete_end_line); | |
1407 scmgr.set_shortcut (m_delete_line_action, sc_edit_edit_delete_line); | |
1408 scmgr.set_shortcut (m_copy_line_action, sc_edit_edit_copy_line); | |
1409 scmgr.set_shortcut (m_cut_line_action, sc_edit_edit_cut_line); | |
1410 scmgr.set_shortcut (m_duplicate_selection_action, sc_edit_edit_duplicate_selection); | |
1411 scmgr.set_shortcut (m_transpose_line_action, sc_edit_edit_transpose_line); | |
1412 scmgr.set_shortcut (m_comment_selection_action, sc_edit_edit_comment_selection); | |
1413 scmgr.set_shortcut (m_uncomment_selection_action, sc_edit_edit_uncomment_selection); | |
1414 scmgr.set_shortcut (m_comment_var_selection_action, sc_edit_edit_comment_var_selection); | |
1415 | |
1416 scmgr.set_shortcut (m_upper_case_action, sc_edit_edit_upper_case); | |
1417 scmgr.set_shortcut (m_lower_case_action, sc_edit_edit_lower_case); | |
1418 scmgr.set_shortcut (m_indent_selection_action, sc_edit_edit_indent_selection); | |
1419 scmgr.set_shortcut (m_unindent_selection_action, sc_edit_edit_unindent_selection); | |
1420 scmgr.set_shortcut (m_smart_indent_line_or_selection_action, sc_edit_edit_smart_indent_line_or_selection); | |
1421 scmgr.set_shortcut (m_completion_action, sc_edit_edit_completion_list); | |
1422 scmgr.set_shortcut (m_goto_line_action, sc_edit_edit_goto_line); | |
1423 scmgr.set_shortcut (m_move_to_matching_brace, sc_edit_edit_move_to_brace); | |
1424 scmgr.set_shortcut (m_sel_to_matching_brace, sc_edit_edit_select_to_brace); | |
1425 scmgr.set_shortcut (m_toggle_bookmark_action, sc_edit_edit_toggle_bookmark); | |
1426 scmgr.set_shortcut (m_next_bookmark_action, sc_edit_edit_next_bookmark); | |
1427 scmgr.set_shortcut (m_previous_bookmark_action, sc_edit_edit_previous_bookmark); | |
1428 scmgr.set_shortcut (m_remove_bookmark_action, sc_edit_edit_remove_bookmark); | |
1429 scmgr.set_shortcut (m_preferences_action, sc_edit_edit_preferences); | |
1430 scmgr.set_shortcut (m_styles_preferences_action, sc_edit_edit_styles_preferences); | |
1431 | |
1432 scmgr.set_shortcut (m_conv_eol_windows_action, sc_edit_edit_conv_eol_winows); | |
1433 scmgr.set_shortcut (m_conv_eol_unix_action, sc_edit_edit_conv_eol_unix); | |
1434 scmgr.set_shortcut (m_conv_eol_mac_action, sc_edit_edit_conv_eol_mac); | |
1435 | |
1436 // View menu | |
1437 scmgr.set_shortcut (m_show_linenum_action, sc_edit_view_show_line_numbers); | |
1438 scmgr.set_shortcut (m_show_whitespace_action, sc_edit_view_show_white_spaces); | |
1439 scmgr.set_shortcut (m_show_eol_action, sc_edit_view_show_eol_chars); | |
1440 scmgr.set_shortcut (m_show_indguide_action, sc_edit_view_show_ind_guides); | |
1441 scmgr.set_shortcut (m_show_longline_action, sc_edit_view_show_long_line); | |
1442 scmgr.set_shortcut (m_show_toolbar_action, sc_edit_view_show_toolbar); | |
1443 scmgr.set_shortcut (m_show_statusbar_action, sc_edit_view_show_statusbar); | |
1444 scmgr.set_shortcut (m_show_hscrollbar_action, sc_edit_view_show_hscrollbar); | |
1445 scmgr.set_shortcut (m_zoom_in_action, sc_edit_view_zoom_in); | |
1446 scmgr.set_shortcut (m_zoom_out_action, sc_edit_view_zoom_out); | |
1447 scmgr.set_shortcut (m_zoom_normal_action, sc_edit_view_zoom_normal); | |
1448 scmgr.set_shortcut (m_sort_tabs_action, sc_edit_view_sort_tabs); | |
1449 | |
1450 // Debug menu | |
1451 scmgr.set_shortcut (m_toggle_breakpoint_action, sc_edit_debug_toggle_breakpoint); | |
1452 scmgr.set_shortcut (m_next_breakpoint_action, sc_edit_debug_next_breakpoint); | |
1453 scmgr.set_shortcut (m_previous_breakpoint_action, sc_edit_debug_previous_breakpoint); | |
1454 scmgr.set_shortcut (m_remove_all_breakpoints_action, sc_edit_debug_remove_breakpoints); | |
1455 | |
1456 // Run menu | |
1457 scmgr.set_shortcut (m_run_action, sc_edit_run_run_file); | |
1458 scmgr.set_shortcut (m_run_selection_action, sc_edit_run_run_selection); | |
1459 | |
1460 // Help menu | |
1461 scmgr.set_shortcut (m_context_help_action, sc_edit_help_help_keyword); | |
1462 scmgr.set_shortcut (m_context_doc_action, sc_edit_help_doc_keyword); | |
1463 | |
1464 // Tab navigation without menu entries | |
1465 scmgr.set_shortcut (m_switch_left_tab_action, sc_edit_tabs_switch_left_tab); | |
1466 scmgr.set_shortcut (m_switch_right_tab_action, sc_edit_tabs_switch_right_tab); | |
1467 scmgr.set_shortcut (m_move_tab_left_action, sc_edit_tabs_move_tab_left); | |
1468 scmgr.set_shortcut (m_move_tab_right_action, sc_edit_tabs_move_tab_right); | |
1469 | |
1470 } | |
1471 | |
1472 // This slot is a reimplementation of the virtual slot in octave_dock_widget. | |
1473 // We need this for creating an empty script when the editor has no open | |
1474 // files and is made visible. | |
1475 void file_editor::handle_visibility (bool visible) | |
1476 { | |
1477 octave_dock_widget::handle_visibility (visible); | |
1478 | |
1479 if (! m_editor_ready) | |
1480 return; | |
1481 | |
1482 if (m_closed && visible) | |
1483 { | |
1484 m_closed = false; | |
1485 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
1486 gui_settings *settings = rmgr.get_settings (); | |
1487 restore_session (settings); | |
1488 } | |
1489 | |
1490 empty_script (false, visible); | |
1491 } | |
1492 | |
1493 // This slot is a reimplementation of the virtual slot in octave_dock_widget. | |
1494 // We need this for updating the parent of the find dialog | |
1495 void file_editor::toplevel_change (bool) | |
1496 { | |
1497 if (m_find_dialog) | |
1498 { | |
1499 // close current dialog | |
1500 m_find_dialog->close (); | |
1501 | |
1502 // re-create dialog with the new parent (editor or main-win) | |
1503 find_create (); | |
1504 m_find_dialog->activateWindow (); | |
1505 } | |
1506 } | |
1507 | |
1508 void file_editor::update_octave_directory (const QString& dir) | |
1509 { | |
1510 m_ced = dir; | |
1511 emit fetab_set_directory (m_ced); // for save dialog | |
1512 } | |
1513 | |
1514 void file_editor::copyClipboard (void) | |
1515 { | |
1516 if (editor_tab_has_focus ()) | |
1517 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
1518 QsciScintillaBase::SCI_COPY); | |
1519 } | |
1520 | |
1521 void file_editor::pasteClipboard (void) | |
1522 { | |
1523 if (editor_tab_has_focus ()) | |
1524 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
1525 QsciScintillaBase::SCI_PASTE); | |
1526 } | |
1527 | |
1528 void file_editor::selectAll (void) | |
1529 { | |
1530 if (editor_tab_has_focus ()) | |
1531 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
1532 QsciScintillaBase::SCI_SELECTALL); | |
1533 } | |
1534 | |
1535 void file_editor::do_undo (void) | |
1536 { | |
1537 if (editor_tab_has_focus ()) | |
1538 emit fetab_scintilla_command (m_tab_widget->currentWidget (), | |
1539 QsciScintillaBase::SCI_UNDO); | |
1540 } | |
1541 | |
1542 // Open a file, if not already open, and mark the current execution location | |
1543 // and/or a breakpoint with condition cond. | |
1544 void file_editor::request_open_file (const QString& openFileName, | |
1545 const QString& encoding, | |
1546 int line, bool debug_pointer, | |
1547 bool breakpoint_marker, bool insert, | |
1548 const QString& cond, int index, | |
1549 const QString& bookmarks) | |
1550 { | |
1551 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
1552 gui_settings *settings = rmgr.get_settings (); | |
1553 | |
1554 if (settings->value (global_use_custom_editor).toBool ()) | |
1555 { | |
1556 // Custom editor | |
1557 if (debug_pointer || breakpoint_marker) | |
1558 return; // Do not call custom editor during debugging | |
1559 | |
1560 if (call_custom_editor (openFileName, line)) | |
1561 return; // Custom editor called | |
1562 } | |
1563 | |
1564 bool show_dbg_file | |
1565 = settings->value (ed_show_dbg_file).toBool (); | |
1566 | |
1567 if (openFileName.isEmpty ()) | |
1568 { | |
1569 // This happens if edit is called without an argument | |
1570 // Open editor with empty edit area instead (as new file would do) | |
1571 request_new_file (""); | |
1572 } | |
1573 else | |
1574 { | |
1575 // Check whether this file is already open in the editor. | |
1576 file_editor_tab *tab = find_tab_widget (openFileName); | |
1577 | |
1578 if (tab) | |
1579 { | |
1580 m_tab_widget->setCurrentWidget (tab); | |
1581 | |
1582 if (line > 0) | |
1583 { | |
1584 if (insert) | |
1585 emit fetab_goto_line (tab, line); | |
1586 | |
1587 if (debug_pointer) | |
1588 emit fetab_insert_debugger_pointer (tab, line); | |
1589 | |
1590 if (breakpoint_marker) | |
1591 emit fetab_do_breakpoint_marker (insert, tab, line, cond); | |
1592 } | |
1593 | |
1594 if (show_dbg_file && ! ((breakpoint_marker || debug_pointer) | |
1595 && is_editor_console_tabbed ())) | |
1596 { | |
1597 emit fetab_set_focus (tab); | |
1598 activate (); | |
1599 } | |
1600 } | |
1601 else | |
1602 { | |
1603 if (! show_dbg_file && (breakpoint_marker || debug_pointer)) | |
1604 return; // Do not open a file for showing dbg markers | |
1605 | |
1606 if (breakpoint_marker && ! insert) | |
1607 return; // Never open a file when removing breakpoints | |
1608 | |
1609 file_editor_tab *fileEditorTab = nullptr; | |
1610 // Reuse <unnamed> tab if it hasn't yet been modified. | |
1611 bool reusing = false; | |
1612 tab = find_tab_widget (""); | |
1613 if (tab) | |
1614 { | |
1615 fileEditorTab = tab; | |
1616 if (fileEditorTab->qsci_edit_area ()->isModified ()) | |
1617 fileEditorTab = nullptr; | |
1618 else | |
1619 reusing = true; | |
1620 } | |
1621 | |
1622 // If <unnamed> was absent or modified, create a new tab. | |
1623 if (! fileEditorTab) | |
1624 fileEditorTab = make_file_editor_tab (); | |
1625 | |
1626 fileEditorTab->set_encoding (encoding); | |
1627 QString result = fileEditorTab->load_file (openFileName); | |
1628 if (result == "") | |
1629 { | |
1630 // Supply empty title then have the file_editor_tab update | |
1631 // with full or short name. | |
1632 if (! reusing) | |
1633 add_file_editor_tab (fileEditorTab, "", index); | |
1634 fileEditorTab->update_window_title (false); | |
1635 // file already loaded, add file to mru list here | |
1636 QFileInfo file_info = QFileInfo (openFileName); | |
1637 handle_mru_add_file (file_info.canonicalFilePath (), | |
1638 encoding); | |
1639 | |
1640 if (line > 0) | |
1641 { | |
1642 if (insert) | |
1643 emit fetab_goto_line (fileEditorTab, line); | |
1644 | |
1645 if (debug_pointer) | |
1646 emit fetab_insert_debugger_pointer (fileEditorTab, | |
1647 line); | |
1648 if (breakpoint_marker) | |
1649 emit fetab_do_breakpoint_marker (insert, fileEditorTab, | |
1650 line, cond); | |
1651 } | |
1652 } | |
1653 else | |
1654 { | |
1655 delete fileEditorTab; | |
1656 fileEditorTab = nullptr; | |
1657 | |
1658 if (QFile::exists (openFileName)) | |
1659 { | |
1660 // File not readable: | |
1661 // create a NonModal message about error. | |
1662 QMessageBox *msgBox | |
1663 = new QMessageBox (QMessageBox::Critical, | |
1664 tr ("Octave Editor"), | |
1665 tr ("Could not open file\n%1\nfor read: %2."). | |
1666 arg (openFileName).arg (result), | |
1667 QMessageBox::Ok, this); | |
1668 | |
1669 msgBox->setWindowModality (Qt::NonModal); | |
1670 msgBox->setAttribute (Qt::WA_DeleteOnClose); | |
1671 msgBox->show (); | |
1672 } | |
1673 else | |
1674 { | |
1675 // File does not exist, should it be created? | |
1676 bool create_file = true; | |
1677 QMessageBox *msgBox; | |
1678 | |
1679 if (! settings->value (ed_create_new_file).toBool ()) | |
1680 { | |
1681 msgBox = new QMessageBox (QMessageBox::Question, | |
1682 tr ("Octave Editor"), | |
1683 tr ("File\n%1\ndoes not exist. " | |
1684 "Do you want to create it?").arg (openFileName), | |
1685 QMessageBox::NoButton, nullptr); | |
1686 QPushButton *create_button = | |
1687 msgBox->addButton (tr ("Create"), QMessageBox::YesRole); | |
1688 msgBox->addButton (tr ("Cancel"), QMessageBox::RejectRole); | |
1689 msgBox->setDefaultButton (create_button); | |
1690 msgBox->exec (); | |
1691 | |
1692 QAbstractButton *clicked_button = msgBox->clickedButton (); | |
1693 if (clicked_button != create_button) | |
1694 create_file = false; | |
1695 | |
1696 delete msgBox; | |
1697 } | |
1698 | |
1699 if (create_file) | |
1700 { | |
1701 // create the file and call the editor again | |
1702 QFile file (openFileName); | |
1703 if (! file.open (QIODevice::WriteOnly)) | |
1704 { | |
1705 // error opening the file | |
1706 msgBox = new QMessageBox (QMessageBox::Critical, | |
1707 tr ("Octave Editor"), | |
1708 tr ("Could not open file\n%1\nfor write: %2."). | |
1709 arg (openFileName).arg (file.errorString ()), | |
1710 QMessageBox::Ok, this); | |
1711 | |
1712 msgBox->setWindowModality (Qt::NonModal); | |
1713 msgBox->setAttribute (Qt::WA_DeleteOnClose); | |
1714 msgBox->show (); | |
1715 } | |
1716 else | |
1717 { | |
1718 file.close (); | |
1719 request_open_file (openFileName); | |
1720 } | |
1721 } | |
1722 } | |
1723 } | |
1724 | |
1725 if (! bookmarks.isEmpty ()) | |
1726 { | |
1727 // Restore bookmarks | |
1728 for (const auto& bms : bookmarks.split (',')) | |
1729 { | |
1730 int bm = bms.toInt (); | |
1731 if (fileEditorTab) | |
1732 fileEditorTab->qsci_edit_area ()->markerAdd (bm, marker::bookmark); | |
1733 } | |
1734 } | |
1735 | |
1736 if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ())) | |
1737 { | |
1738 // update breakpoint pointers, really show editor | |
1739 // and the current editor tab | |
1740 if (fileEditorTab) | |
1741 fileEditorTab->update_breakpoints (); | |
1742 activate (); | |
1743 emit file_loaded_signal (); | |
1744 } | |
1745 } | |
1746 } | |
1747 } | |
1748 | |
1749 void file_editor::request_preferences (bool) | |
1750 { | |
1751 emit request_settings_dialog ("editor"); | |
1752 } | |
1753 | |
1754 void file_editor::request_styles_preferences (bool) | |
1755 { | |
1756 emit request_settings_dialog ("editor_styles"); | |
1757 } | |
1758 | |
1759 void file_editor::show_line_numbers (bool) | |
1760 { | |
1761 toggle_preference (ed_show_line_numbers); | |
1762 } | |
1763 | |
1764 void file_editor::show_white_space (bool) | |
1765 { | |
1766 toggle_preference (ed_show_white_space); | |
1767 } | |
1768 | |
1769 void file_editor::show_eol_chars (bool) | |
1770 { | |
1771 toggle_preference (ed_show_eol_chars); | |
1772 } | |
1773 | |
1774 void file_editor::show_indent_guides (bool) | |
1775 { | |
1776 toggle_preference (ed_show_indent_guides); | |
1777 } | |
1778 | |
1779 void file_editor::show_long_line (bool) | |
1780 { | |
1781 toggle_preference (ed_long_line_marker); | |
1782 } | |
1783 | |
1784 void file_editor::show_toolbar (bool) | |
1785 { | |
1786 toggle_preference (ed_show_toolbar); | |
1787 } | |
1788 | |
1789 void file_editor::show_statusbar (bool) | |
1790 { | |
1791 toggle_preference (ed_show_edit_status_bar); | |
1792 } | |
1793 | |
1794 void file_editor::show_hscrollbar (bool) | |
1795 { | |
1796 toggle_preference (ed_show_hscroll_bar); | |
1797 } | |
1798 | |
1799 void file_editor::zoom_in (bool) | |
1800 { | |
1801 emit fetab_zoom_in (m_tab_widget->currentWidget ()); | |
1802 } | |
1803 | |
1804 void file_editor::zoom_out (bool) | |
1805 { | |
1806 emit fetab_zoom_out (m_tab_widget->currentWidget ()); | |
1807 } | |
1808 | |
1809 void file_editor::zoom_normal (bool) | |
1810 { | |
1811 emit fetab_zoom_normal (m_tab_widget->currentWidget ()); | |
1812 } | |
1813 | |
1814 void file_editor::create_context_menu (QMenu *menu) | |
1815 { | |
1816 // remove all standard actions from scintilla | |
1817 QList<QAction *> all_actions = menu->actions (); | |
1818 | |
1819 for (auto *a : all_actions) | |
1820 menu->removeAction (a); | |
1821 | |
1822 // add editor's actions with icons and customized shortcuts | |
1823 menu->addAction (m_cut_action); | |
1824 menu->addAction (m_copy_action); | |
1825 menu->addAction (m_paste_action); | |
1826 menu->addSeparator (); | |
1827 menu->addAction (m_selectall_action); | |
1828 menu->addSeparator (); | |
1829 menu->addAction (m_find_files_action); | |
1830 menu->addAction (m_find_action); | |
1831 menu->addAction (m_find_next_action); | |
1832 menu->addAction (m_find_previous_action); | |
1833 menu->addSeparator (); | |
1834 menu->addMenu (m_edit_cmd_menu); | |
1835 menu->addMenu (m_edit_fmt_menu); | |
1836 menu->addMenu (m_edit_nav_menu); | |
1837 menu->addSeparator (); | |
1838 menu->addAction (m_run_selection_action); | |
1839 } | |
1840 | |
1841 void file_editor::edit_status_update (bool undo, bool redo) | |
1842 { | |
1843 if (m_undo_action) | |
1844 m_undo_action->setEnabled (undo); | |
1845 m_redo_action->setEnabled (redo); | |
1846 } | |
1847 | |
1848 // handler for the close event | |
1849 void file_editor::closeEvent (QCloseEvent *e) | |
1850 { | |
1851 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
1852 gui_settings *settings = rmgr.get_settings (); | |
1853 if (settings->value (ed_hiding_closes_files).toBool ()) | |
1854 { | |
1855 if (check_closing ()) | |
1856 { | |
1857 // All tabs are closed without cancelling, | |
1858 // store closing state for restoring session when shown again. | |
1859 // Editor is closing when session data is stored in preferences | |
1860 m_closed = true; | |
1861 e->ignore (); | |
1862 } | |
1863 else | |
1864 { | |
1865 e->ignore (); | |
1866 return; | |
1867 } | |
1868 } | |
1869 else | |
1870 e->accept (); | |
1871 | |
1872 octave_dock_widget::closeEvent (e); | |
1873 } | |
1874 | |
1875 void file_editor::dragEnterEvent (QDragEnterEvent *e) | |
1876 { | |
1877 if (e->mimeData ()->hasUrls ()) | |
1878 { | |
1879 e->acceptProposedAction (); | |
1880 } | |
1881 } | |
1882 | |
1883 void file_editor::dropEvent (QDropEvent *e) | |
1884 { | |
1885 if (e->mimeData ()->hasUrls ()) | |
1886 { | |
1887 for (const auto& url : e->mimeData ()->urls ()) | |
1888 request_open_file (url.toLocalFile ()); | |
1889 } | |
1890 } | |
1891 | |
1892 bool file_editor::is_editor_console_tabbed (void) | |
1893 { | |
1894 // FIXME: is there a way to do this job that doesn't require casting | |
1895 // the parent to a main_window object? | |
1896 | |
1897 main_window *w = dynamic_cast<main_window *> (parentWidget ()); | |
1898 | |
1899 if (w) | |
1900 { | |
1901 QList<QDockWidget *> w_list = w->tabifiedDockWidgets (this); | |
1902 QDockWidget *console = | |
1903 static_cast<QDockWidget *> (w->get_dock_widget_list ().at (0)); | |
1904 | |
1905 for (int i = 0; i < w_list.count (); i++) | |
1906 { | |
1907 if (w_list.at (i) == console) | |
1908 return true; | |
1909 } | |
1910 } | |
1911 | |
1912 return false; | |
1913 } | |
1914 | |
1915 void file_editor::construct (void) | |
1916 { | |
1917 QWidget *editor_widget = new QWidget (this); | |
1918 | |
1919 // FIXME: what was the intended purpose of this unused variable? | |
1920 // QStyle *editor_style = QApplication::style (); | |
1921 | |
1922 // Menu bar: do not set it native, required in macOS and Ubuntu Unity (Qt5) | |
1923 // for a visible menu bar in the editor widget. This property is ignored | |
1924 // on other platforms. | |
1925 m_menu_bar = new QMenuBar (editor_widget); | |
1926 m_menu_bar->setNativeMenuBar (false); | |
1927 | |
1928 m_tool_bar = new QToolBar (editor_widget); | |
1929 m_tool_bar->setMovable (true); | |
1930 | |
1931 m_tab_widget = new file_editor_tab_widget (editor_widget, this); | |
1932 | |
1933 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
1934 | |
1935 // the mru-list and an empty array of actions | |
1936 gui_settings *settings = rmgr.get_settings (); | |
1937 m_mru_files = settings->value (ed_mru_file_list).toStringList (); | |
1938 m_mru_files_encodings = settings->value (ed_mru_file_encodings) | |
1939 .toStringList (); | |
1940 | |
1941 if (m_mru_files_encodings.count () != m_mru_files.count ()) | |
1942 { | |
1943 // encodings don't have the same count -> do not use them! | |
1944 m_mru_files_encodings = QStringList (); | |
1945 for (int i = 0; i < m_mru_files.count (); i++) | |
1946 m_mru_files_encodings << QString (); | |
1947 } | |
1948 | |
1949 for (int i = 0; i < MaxMRUFiles; ++i) | |
1950 { | |
1951 m_mru_file_actions[i] = new QAction (this); | |
1952 m_mru_file_actions[i]->setVisible (false); | |
1953 } | |
1954 | |
1955 // menu bar | |
1956 | |
1957 // file menu | |
1958 | |
1959 m_fileMenu = add_menu (m_menu_bar, tr ("&File")); | |
1960 | |
1961 // new and open menus are inserted later by the main window | |
1962 m_mru_file_menu = new QMenu (tr ("&Recent Editor Files"), m_fileMenu); | |
1963 for (int i = 0; i < MaxMRUFiles; ++i) | |
1964 m_mru_file_menu->addAction (m_mru_file_actions[i]); | |
1965 m_fileMenu->addMenu (m_mru_file_menu); | |
1966 | |
1967 m_fileMenu->addSeparator (); | |
1968 | |
1969 m_edit_function_action | |
1970 = add_action (m_fileMenu, | |
1971 tr ("&Edit Function"), | |
1972 SLOT (request_context_edit (bool))); | |
1973 | |
1974 m_fileMenu->addSeparator (); | |
1975 | |
1976 m_save_action | |
1977 = add_action (m_fileMenu, rmgr.icon ("document-save"), | |
1978 tr ("&Save File"), SLOT (request_save_file (bool))); | |
1979 | |
1980 m_save_as_action | |
1981 = add_action (m_fileMenu, rmgr.icon ("document-save-as"), | |
1982 tr ("Save File &As..."), | |
1983 SLOT (request_save_file_as (bool))); | |
1984 | |
1985 m_fileMenu->addSeparator (); | |
1986 | |
1987 m_close_action | |
1988 = add_action (m_fileMenu, rmgr.icon ("window-close", false), | |
1989 tr ("&Close"), SLOT (request_close_file (bool))); | |
1990 | |
1991 m_close_all_action | |
1992 = add_action (m_fileMenu, rmgr.icon ("window-close", false), | |
1993 tr ("Close All"), SLOT (request_close_all_files (bool))); | |
1994 | |
1995 m_close_others_action | |
1996 = add_action (m_fileMenu, rmgr.icon ("window-close", false), | |
1997 tr ("Close Other Files"), | |
1998 SLOT (request_close_other_files (bool))); | |
1999 | |
2000 m_fileMenu->addSeparator (); | |
2001 | |
2002 m_print_action | |
2003 = add_action (m_fileMenu, rmgr.icon ("document-print"), | |
2004 tr ("Print..."), SLOT (request_print_file (bool))); | |
2005 | |
2006 // edit menu (undo, copy, paste and select all later via main window) | |
2007 | |
2008 m_edit_menu = add_menu (m_menu_bar, tr ("&Edit")); | |
2009 | |
2010 m_redo_action | |
2011 = add_action (m_edit_menu, rmgr.icon ("edit-redo"), | |
2012 tr ("&Redo"), SLOT (request_redo (bool))); | |
2013 m_redo_action->setEnabled (false); | |
2014 | |
2015 m_edit_menu->addSeparator (); | |
2016 | |
2017 m_cut_action | |
2018 = add_action (m_edit_menu, rmgr.icon ("edit-cut"), | |
2019 tr ("Cu&t"), SLOT (request_cut (bool))); | |
2020 m_cut_action->setEnabled (false); | |
2021 | |
2022 m_find_action | |
2023 = add_action (m_edit_menu, rmgr.icon ("edit-find-replace"), | |
2024 tr ("&Find and Replace..."), SLOT (request_find (bool))); | |
2025 | |
2026 m_find_next_action | |
2027 = add_action (m_edit_menu, tr ("Find &Next..."), | |
2028 SLOT (request_find_next (bool))); | |
2029 | |
2030 m_find_previous_action | |
2031 = add_action (m_edit_menu, tr ("Find &Previous..."), | |
2032 SLOT (request_find_previous (bool))); | |
2033 | |
2034 m_edit_menu->addSeparator (); | |
2035 | |
2036 m_edit_cmd_menu = m_edit_menu->addMenu (tr ("&Commands")); | |
2037 | |
2038 m_delete_line_action | |
2039 = add_action (m_edit_cmd_menu, tr ("Delete Line"), | |
2040 SLOT (request_delete_line (bool))); | |
2041 | |
2042 m_copy_line_action | |
2043 = add_action (m_edit_cmd_menu, tr ("Copy Line"), | |
2044 SLOT (request_copy_line (bool))); | |
2045 | |
2046 m_cut_line_action | |
2047 = add_action (m_edit_cmd_menu, tr ("Cut Line"), | |
2048 SLOT (request_cut_line (bool))); | |
2049 | |
2050 m_edit_cmd_menu->addSeparator (); | |
2051 | |
2052 m_delete_start_word_action | |
2053 = add_action (m_edit_cmd_menu, tr ("Delete to Start of Word"), | |
2054 SLOT (request_delete_start_word (bool))); | |
2055 | |
2056 m_delete_end_word_action | |
2057 = add_action (m_edit_cmd_menu, tr ("Delete to End of Word"), | |
2058 SLOT (request_delete_end_word (bool))); | |
2059 | |
2060 m_delete_start_line_action | |
2061 = add_action (m_edit_cmd_menu, tr ("Delete to Start of Line"), | |
2062 SLOT (request_delete_start_line (bool))); | |
2063 | |
2064 m_delete_end_line_action | |
2065 = add_action (m_edit_cmd_menu, tr ("Delete to End of Line"), | |
2066 SLOT (request_delete_end_line (bool))); | |
2067 | |
2068 m_edit_cmd_menu->addSeparator (); | |
2069 | |
2070 m_duplicate_selection_action | |
2071 = add_action (m_edit_cmd_menu, tr ("Duplicate Selection/Line"), | |
2072 SLOT (request_duplicate_selection (bool))); | |
2073 | |
2074 m_transpose_line_action | |
2075 = add_action (m_edit_cmd_menu, tr ("Transpose Line"), | |
2076 SLOT (request_transpose_line (bool))); | |
2077 | |
2078 m_edit_cmd_menu->addSeparator (); | |
2079 | |
2080 m_completion_action | |
2081 = add_action (m_edit_cmd_menu, tr ("&Show Completion List"), | |
2082 SLOT (request_completion (bool))); | |
2083 | |
2084 m_edit_fmt_menu = m_edit_menu->addMenu (tr ("&Format")); | |
2085 | |
2086 m_upper_case_action | |
2087 = add_action (m_edit_fmt_menu, tr ("&Uppercase Selection"), | |
2088 SLOT (request_upper_case (bool))); | |
2089 | |
2090 m_lower_case_action | |
2091 = add_action (m_edit_fmt_menu, tr ("&Lowercase Selection"), | |
2092 SLOT (request_lower_case (bool))); | |
2093 | |
2094 m_edit_fmt_menu->addSeparator (); | |
2095 | |
2096 m_comment_selection_action | |
2097 = add_action (m_edit_fmt_menu, tr ("&Comment"), | |
2098 SLOT (request_comment_selected_text (bool))); | |
2099 | |
2100 m_uncomment_selection_action | |
2101 = add_action (m_edit_fmt_menu, tr ("&Uncomment"), | |
2102 SLOT (request_uncomment_selected_text (bool))); | |
2103 | |
2104 m_comment_var_selection_action | |
2105 = add_action (m_edit_fmt_menu, tr ("Comment (Choosing String)"), | |
2106 SLOT (request_comment_var_selected_text (bool))); | |
2107 | |
2108 m_edit_fmt_menu->addSeparator (); | |
2109 | |
2110 m_indent_selection_action | |
2111 = add_action (m_edit_fmt_menu, tr ("&Indent Selection Rigidly"), | |
2112 SLOT (request_indent_selected_text (bool))); | |
2113 | |
2114 m_unindent_selection_action | |
2115 = add_action (m_edit_fmt_menu, tr ("&Unindent Selection Rigidly"), | |
2116 SLOT (request_unindent_selected_text (bool))); | |
2117 | |
2118 m_smart_indent_line_or_selection_action | |
2119 = add_action (m_edit_fmt_menu, tr ("Indent Code"), | |
2120 SLOT (request_smart_indent_line_or_selected_text (void))); | |
2121 | |
2122 m_edit_fmt_menu->addSeparator (); | |
2123 | |
2124 m_conv_eol_windows_action | |
2125 = add_action (m_edit_fmt_menu, | |
2126 tr ("Convert Line Endings to &Windows (CRLF)"), | |
2127 SLOT (request_conv_eol_windows (bool))); | |
2128 | |
2129 m_conv_eol_unix_action | |
2130 = add_action (m_edit_fmt_menu, tr ("Convert Line Endings to &Unix (LF)"), | |
2131 SLOT (request_conv_eol_unix (bool))); | |
2132 | |
2133 m_conv_eol_mac_action | |
2134 = add_action (m_edit_fmt_menu, | |
2135 tr ("Convert Line Endings to Legacy &Mac (CR)"), | |
2136 SLOT (request_conv_eol_mac (bool))); | |
2137 | |
2138 m_edit_nav_menu = m_edit_menu->addMenu (tr ("Navi&gation")); | |
2139 | |
2140 m_goto_line_action | |
2141 = add_action (m_edit_nav_menu, tr ("Go &to Line..."), | |
2142 SLOT (request_goto_line (bool))); | |
2143 | |
2144 m_edit_cmd_menu->addSeparator (); | |
2145 | |
2146 m_move_to_matching_brace | |
2147 = add_action (m_edit_nav_menu, tr ("Move to Matching Brace"), | |
2148 SLOT (request_move_match_brace (bool))); | |
2149 | |
2150 m_sel_to_matching_brace | |
2151 = add_action (m_edit_nav_menu, tr ("Select to Matching Brace"), | |
2152 SLOT (request_sel_match_brace (bool))); | |
2153 | |
2154 m_edit_nav_menu->addSeparator (); | |
2155 | |
2156 m_next_bookmark_action | |
2157 = add_action (m_edit_nav_menu, tr ("&Next Bookmark"), | |
2158 SLOT (request_next_bookmark (bool))); | |
2159 | |
2160 m_previous_bookmark_action | |
2161 = add_action (m_edit_nav_menu, tr ("Pre&vious Bookmark"), | |
2162 SLOT (request_previous_bookmark (bool))); | |
2163 | |
2164 m_toggle_bookmark_action | |
2165 = add_action (m_edit_nav_menu, tr ("Toggle &Bookmark"), | |
2166 SLOT (request_toggle_bookmark (bool))); | |
2167 | |
2168 m_remove_bookmark_action | |
2169 = add_action (m_edit_nav_menu, tr ("&Remove All Bookmarks"), | |
2170 SLOT (request_remove_bookmark (bool))); | |
2171 | |
2172 m_edit_menu->addSeparator (); | |
2173 | |
2174 m_preferences_action | |
2175 = add_action (m_edit_menu, rmgr.icon ("preferences-system"), | |
2176 tr ("&Preferences..."), | |
2177 SLOT (request_preferences (bool))); | |
2178 | |
2179 m_styles_preferences_action | |
2180 = add_action (m_edit_menu, rmgr.icon ("preferences-system"), | |
2181 tr ("&Styles Preferences..."), | |
2182 SLOT (request_styles_preferences (bool))); | |
2183 | |
2184 // view menu | |
2185 | |
2186 QMenu *view_menu = add_menu (m_menu_bar, tr ("&View")); | |
2187 | |
2188 m_view_editor_menu = view_menu->addMenu (tr ("&Editor")); | |
2189 | |
2190 m_show_linenum_action | |
2191 = add_action (m_view_editor_menu, tr ("Show &Line Numbers"), | |
2192 SLOT (show_line_numbers (bool))); | |
2193 m_show_linenum_action->setCheckable (true); | |
2194 | |
2195 m_show_whitespace_action | |
2196 = add_action (m_view_editor_menu, tr ("Show &Whitespace Characters"), | |
2197 SLOT (show_white_space (bool))); | |
2198 m_show_whitespace_action->setCheckable (true); | |
2199 | |
2200 m_show_eol_action | |
2201 = add_action (m_view_editor_menu, tr ("Show Line &Endings"), | |
2202 SLOT (show_eol_chars (bool))); | |
2203 m_show_eol_action->setCheckable (true); | |
2204 | |
2205 m_show_indguide_action | |
2206 = add_action (m_view_editor_menu, tr ("Show &Indentation Guides"), | |
2207 SLOT (show_indent_guides (bool))); | |
2208 m_show_indguide_action->setCheckable (true); | |
2209 | |
2210 m_show_longline_action | |
2211 = add_action (m_view_editor_menu, tr ("Show Long Line &Marker"), | |
2212 SLOT (show_long_line (bool))); | |
2213 m_show_longline_action->setCheckable (true); | |
2214 | |
2215 m_view_editor_menu->addSeparator (); | |
2216 | |
2217 m_show_toolbar_action | |
2218 = add_action (m_view_editor_menu, tr ("Show &Toolbar"), | |
2219 SLOT (show_toolbar (bool))); | |
2220 m_show_toolbar_action->setCheckable (true); | |
2221 | |
2222 m_show_statusbar_action | |
2223 = add_action (m_view_editor_menu, tr ("Show &Statusbar"), | |
2224 SLOT (show_statusbar (bool))); | |
2225 m_show_statusbar_action->setCheckable (true); | |
2226 | |
2227 m_show_hscrollbar_action | |
2228 = add_action (m_view_editor_menu, tr ("Show &Horizontal Scrollbar"), | |
2229 SLOT (show_hscrollbar (bool))); | |
2230 m_show_hscrollbar_action->setCheckable (true); | |
2231 | |
2232 view_menu->addSeparator (); | |
2233 | |
2234 m_zoom_in_action | |
2235 = add_action (view_menu, rmgr.icon ("view-zoom-in"), tr ("Zoom &In"), | |
2236 SLOT (zoom_in (bool))); | |
2237 | |
2238 m_zoom_out_action | |
2239 = add_action (view_menu, rmgr.icon ("view-zoom-out"), tr ("Zoom &Out"), | |
2240 SLOT (zoom_out (bool))); | |
2241 | |
2242 m_zoom_normal_action | |
2243 = add_action (view_menu, rmgr.icon ("view-zoom-original"), tr ("&Normal Size"), | |
2244 SLOT (zoom_normal (bool))); | |
2245 | |
2246 view_menu->addSeparator (); | |
2247 | |
2248 m_sort_tabs_action | |
2249 = add_action (view_menu, tr ("&Sort Tabs Alphabetically"), | |
2250 SLOT (sort_tabs_alph (void)), | |
2251 m_tab_widget->get_tab_bar ()); | |
2252 | |
2253 m_menu_bar->addMenu (view_menu); | |
2254 | |
2255 // debug menu | |
2256 | |
2257 m_debug_menu = add_menu (m_menu_bar, tr ("&Debug")); | |
2258 | |
2259 m_toggle_breakpoint_action | |
2260 = add_action (m_debug_menu, rmgr.icon ("bp-toggle"), | |
2261 tr ("Toggle &Breakpoint"), | |
2262 SLOT (request_toggle_breakpoint (bool))); | |
2263 | |
2264 m_next_breakpoint_action | |
2265 = add_action (m_debug_menu, rmgr.icon ("bp-next"), | |
2266 tr ("&Next Breakpoint"), | |
2267 SLOT (request_next_breakpoint (bool))); | |
2268 | |
2269 m_previous_breakpoint_action | |
2270 = add_action (m_debug_menu, rmgr.icon ("bp-prev"), | |
2271 tr ("Pre&vious Breakpoint"), | |
2272 SLOT (request_previous_breakpoint (bool))); | |
2273 | |
2274 m_remove_all_breakpoints_action | |
2275 = add_action (m_debug_menu, rmgr.icon ("bp-rm-all"), | |
2276 tr ("&Remove All Breakpoints"), | |
2277 SLOT (request_remove_breakpoint (bool))); | |
2278 | |
2279 m_debug_menu->addSeparator (); | |
2280 | |
2281 // The other debug actions will be added by the main window. | |
2282 | |
2283 // run menu | |
2284 | |
2285 QMenu *_run_menu = add_menu (m_menu_bar, tr ("&Run")); | |
2286 | |
2287 m_run_action | |
2288 = add_action (_run_menu, | |
2289 rmgr.icon ("system-run"), | |
2290 tr ("Save File and Run / Continue"), | |
2291 SLOT (request_run_file (bool))); | |
2292 | |
2293 m_run_selection_action | |
2294 = add_action (_run_menu, | |
2295 tr ("Run &Selection"), | |
2296 SLOT (request_context_run (bool))); | |
2297 m_run_selection_action->setEnabled (false); | |
2298 | |
2299 // help menu | |
2300 | |
2301 QMenu *_help_menu = add_menu (m_menu_bar, tr ("&Help")); | |
2302 | |
2303 m_context_help_action | |
2304 = add_action (_help_menu, | |
2305 tr ("&Help on Keyword"), | |
2306 SLOT (request_context_help (bool))); | |
2307 | |
2308 m_context_doc_action | |
2309 = add_action (_help_menu, | |
2310 tr ("&Documentation on Keyword"), | |
2311 SLOT (request_context_doc (bool))); | |
2312 | |
2313 // tab navigation (no menu, only actions; slots in tab_bar) | |
2314 | |
2315 m_switch_left_tab_action | |
2316 = add_action (nullptr, "", SLOT (switch_left_tab (void)), | |
2317 m_tab_widget->get_tab_bar ()); | |
2318 | |
2319 m_switch_right_tab_action | |
2320 = add_action (nullptr, "", SLOT (switch_right_tab (void)), | |
2321 m_tab_widget->get_tab_bar ()); | |
2322 | |
2323 m_move_tab_left_action | |
2324 = add_action (nullptr, "", SLOT (move_tab_left (void)), | |
2325 m_tab_widget->get_tab_bar ()); | |
2326 | |
2327 m_move_tab_right_action | |
2328 = add_action (nullptr, "", SLOT (move_tab_right (void)), | |
2329 m_tab_widget->get_tab_bar ()); | |
2330 | |
2331 // toolbar | |
2332 | |
2333 // popdown menu with mru files | |
2334 QToolButton *popdown_button = new QToolButton (); | |
2335 popdown_button->setToolTip (tr ("Recent Files")); | |
2336 popdown_button->setMenu (m_mru_file_menu); | |
2337 popdown_button->setPopupMode (QToolButton::InstantPopup); | |
2338 popdown_button->setArrowType (Qt::DownArrow); | |
2339 popdown_button->setToolButtonStyle (Qt::ToolButtonTextOnly); | |
2340 | |
2341 // new and open actions are inserted later from main window | |
2342 m_popdown_mru_action = m_tool_bar->addWidget (popdown_button); | |
2343 m_tool_bar->addAction (m_save_action); | |
2344 m_tool_bar->addAction (m_save_as_action); | |
2345 m_tool_bar->addAction (m_print_action); | |
2346 m_tool_bar->addSeparator (); | |
2347 // m_undo_action: later via main window | |
2348 m_tool_bar->addAction (m_redo_action); | |
2349 m_tool_bar->addSeparator (); | |
2350 m_tool_bar->addAction (m_cut_action); | |
2351 // m_copy_action: later via the main window | |
2352 // m_paste_action: later via the main window | |
2353 m_tool_bar->addAction (m_find_action); | |
2354 //m_tool_bar->addAction (m_find_next_action); | |
2355 //m_tool_bar->addAction (m_find_previous_action); | |
2356 m_tool_bar->addSeparator (); | |
2357 m_tool_bar->addAction (m_run_action); | |
2358 m_tool_bar->addSeparator (); | |
2359 m_tool_bar->addAction (m_toggle_breakpoint_action); | |
2360 m_tool_bar->addAction (m_previous_breakpoint_action); | |
2361 m_tool_bar->addAction (m_next_breakpoint_action); | |
2362 m_tool_bar->addAction (m_remove_all_breakpoints_action); | |
2363 | |
2364 // layout | |
2365 QVBoxLayout *vbox_layout = new QVBoxLayout (); | |
2366 vbox_layout->addWidget (m_menu_bar); | |
2367 vbox_layout->addWidget (m_tool_bar); | |
2368 vbox_layout->addWidget (m_tab_widget); | |
2369 vbox_layout->setMargin (0); | |
2370 vbox_layout->setSpacing (0); | |
2371 editor_widget->setLayout (vbox_layout); | |
2372 setWidget (editor_widget); | |
2373 | |
2374 // Create the basic context menu of the tab bar with editor actions. | |
2375 // Actions for selecting an tab are added when the menu is activated. | |
2376 tab_bar *bar = m_tab_widget->get_tab_bar (); | |
2377 QMenu *ctx_men = bar->get_context_menu (); | |
2378 ctx_men->addSeparator (); | |
2379 ctx_men->addAction (m_close_action); | |
2380 ctx_men->addAction (m_close_all_action); | |
2381 ctx_men->addAction (m_close_others_action); | |
2382 ctx_men->addSeparator (); | |
2383 ctx_men->addAction (m_sort_tabs_action); | |
2384 add_action (ctx_men, tr ("Copy Full File &Path"), | |
2385 SLOT (copy_full_file_path (bool)), this); | |
2386 | |
2387 // signals | |
2388 connect (m_mru_file_menu, &QMenu::triggered, | |
2389 this, &file_editor::request_mru_open_file); | |
2390 | |
2391 mru_menu_update (); | |
2392 | |
2393 connect (m_tab_widget, &file_editor_tab_widget::tabCloseRequested, | |
2394 this, &file_editor::handle_tab_close_request); | |
2395 | |
2396 connect (m_tab_widget, &file_editor_tab_widget::currentChanged, | |
2397 this, &file_editor::active_tab_changed); | |
2398 | |
2399 resize (500, 400); | |
2400 set_title (tr ("Editor")); | |
2401 | |
2402 check_actions (); | |
2403 } | |
2404 | |
2405 // Slot when autocompletion list was cancelled | |
2406 void file_editor::handle_autoc_cancelled (void) | |
2407 { | |
2408 // List was cancelled but somehow still active and blocking the | |
2409 // edit area from accepting shortcuts. Only after another keypress | |
2410 // shortcuts and lists are working againnas expected. This is | |
2411 // probably caused by qt bug https://bugreports.qt.io/browse/QTBUG-83720 | |
2412 // Hack: Accept the list, which is hidden but still active | |
2413 // and undo the text insertion, if any | |
2414 | |
2415 file_editor_tab *f = reset_focus (); | |
2416 octave_qscintilla *qsci = f->qsci_edit_area (); | |
2417 | |
2418 int line, col; | |
2419 qsci->getCursorPosition (&line, &col); | |
2420 int l1 = qsci->lineLength (line); // Current line length | |
2421 | |
2422 // Accept autocompletion | |
2423 qsci->SendScintilla (QsciScintillaBase::SCI_AUTOCCOMPLETE); | |
2424 | |
2425 // Was text inserted? If yes, undo | |
2426 if (qsci->text (line).length () - l1) | |
2427 qsci->undo (); | |
2428 } | |
2429 | |
2430 file_editor_tab *file_editor::reset_focus (void) | |
2431 { | |
2432 // Reset the focus of the tab and the related edit area | |
2433 file_editor_tab *f | |
2434 = static_cast<file_editor_tab *> (m_tab_widget->currentWidget ()); | |
2435 emit fetab_set_focus (f); | |
2436 return f; | |
2437 } | |
2438 | |
2439 file_editor_tab * | |
2440 file_editor::make_file_editor_tab (const QString& directory) | |
2441 { | |
2442 file_editor_tab *f = new file_editor_tab (m_octave_qobj, directory); | |
2443 | |
2444 // signals from the qscintilla edit area | |
2445 connect (f->qsci_edit_area (), &octave_qscintilla::status_update, | |
2446 this, &file_editor::edit_status_update); | |
2447 | |
2448 connect (f->qsci_edit_area (), &octave_qscintilla::create_context_menu_signal, | |
2449 this, &file_editor::create_context_menu); | |
2450 | |
2451 connect (f->qsci_edit_area (), | |
2452 SIGNAL (SCN_AUTOCCOMPLETED (const char *, int, int, int)), | |
2453 this, SLOT (reset_focus (void))); | |
2454 | |
2455 connect (f->qsci_edit_area (), SIGNAL (SCN_AUTOCCANCELLED (void)), | |
2456 this, SLOT (handle_autoc_cancelled (void))); | |
2457 | |
2458 // signals from the qscintilla edit area | |
2459 connect (this, &file_editor::enter_debug_mode_signal, | |
2460 f->qsci_edit_area (), &octave_qscintilla::handle_enter_debug_mode); | |
2461 | |
2462 connect (this, &file_editor::exit_debug_mode_signal, | |
2463 f->qsci_edit_area (), &octave_qscintilla::handle_exit_debug_mode); | |
2464 | |
2465 // Signals from the file editor_tab | |
2466 connect (f, &file_editor_tab::autoc_closed, | |
2467 this, &file_editor::reset_focus); | |
2468 | |
2469 connect (f, &file_editor_tab::file_name_changed, | |
2470 this, &file_editor::handle_file_name_changed); | |
2471 | |
2472 connect (f, &file_editor_tab::editor_state_changed, | |
2473 this, &file_editor::handle_editor_state_changed); | |
2474 | |
2475 connect (f, &file_editor_tab::tab_remove_request, | |
2476 this, &file_editor::handle_tab_remove_request); | |
2477 | |
2478 connect (f, &file_editor_tab::editor_check_conflict_save, | |
2479 this, &file_editor::check_conflict_save); | |
2480 | |
2481 connect (f, &file_editor_tab::mru_add_file, | |
2482 this, &file_editor::handle_mru_add_file); | |
2483 | |
2484 connect (f, &file_editor_tab::request_open_file, | |
2485 this, [=] (const QString& fname, const QString& encoding) { request_open_file (fname, encoding); }); | |
2486 | |
2487 connect (f, &file_editor_tab::edit_area_changed, | |
2488 this, &file_editor::edit_area_changed); | |
2489 | |
2490 connect (f, &file_editor_tab::set_focus_editor_signal, | |
2491 this, &file_editor::set_focus); | |
2492 | |
2493 // Signals from the file_editor or main-win non-trivial operations | |
2494 connect (this, &file_editor::fetab_settings_changed, | |
2495 f, [=] (const gui_settings *settings) { f->notice_settings (settings); }); | |
2496 | |
2497 connect (this, &file_editor::fetab_change_request, | |
2498 f, &file_editor_tab::change_editor_state); | |
2499 | |
2500 connect (this, QOverload<const QWidget *, const QString&, bool>::of (&file_editor::fetab_save_file), | |
2501 f, QOverload<const QWidget *, const QString&, bool>::of (&file_editor_tab::save_file)); | |
2502 | |
2503 // Signals from the file_editor trivial operations | |
2504 connect (this, &file_editor::fetab_recover_from_exit, | |
2505 f, &file_editor_tab::recover_from_exit); | |
2506 | |
2507 connect (this, &file_editor::fetab_set_directory, | |
2508 f, &file_editor_tab::set_current_directory); | |
2509 | |
2510 connect (this, &file_editor::fetab_zoom_in, | |
2511 f, &file_editor_tab::zoom_in); | |
2512 connect (this, &file_editor::fetab_zoom_out, | |
2513 f, &file_editor_tab::zoom_out); | |
2514 connect (this, &file_editor::fetab_zoom_normal, | |
2515 f, &file_editor_tab::zoom_normal); | |
2516 | |
2517 connect (this, &file_editor::fetab_context_help, | |
2518 f, &file_editor_tab::context_help); | |
2519 | |
2520 connect (this, &file_editor::fetab_context_edit, | |
2521 f, &file_editor_tab::context_edit); | |
2522 | |
2523 connect (this, QOverload<const QWidget *>::of (&file_editor::fetab_save_file), | |
2524 f, QOverload<const QWidget *>::of (&file_editor_tab::save_file)); | |
2525 | |
2526 connect (this, &file_editor::fetab_save_file_as, | |
2527 f, QOverload<const QWidget *>::of (&file_editor_tab::save_file_as)); | |
2528 | |
2529 connect (this, &file_editor::fetab_print_file, | |
2530 f, &file_editor_tab::print_file); | |
2531 | |
2532 connect (this, &file_editor::fetab_run_file, | |
2533 f, &file_editor_tab::run_file); | |
2534 | |
2535 connect (this, &file_editor::fetab_context_run, | |
2536 f, &file_editor_tab::context_run); | |
2537 | |
2538 connect (this, &file_editor::fetab_toggle_bookmark, | |
2539 f, &file_editor_tab::toggle_bookmark); | |
2540 | |
2541 connect (this, &file_editor::fetab_next_bookmark, | |
2542 f, &file_editor_tab::next_bookmark); | |
2543 | |
2544 connect (this, &file_editor::fetab_previous_bookmark, | |
2545 f, &file_editor_tab::previous_bookmark); | |
2546 | |
2547 connect (this, &file_editor::fetab_remove_bookmark, | |
2548 f, &file_editor_tab::remove_bookmark); | |
2549 | |
2550 connect (this, &file_editor::fetab_toggle_breakpoint, | |
2551 f, &file_editor_tab::toggle_breakpoint); | |
2552 | |
2553 connect (this, &file_editor::fetab_next_breakpoint, | |
2554 f, &file_editor_tab::next_breakpoint); | |
2555 | |
2556 connect (this, &file_editor::fetab_previous_breakpoint, | |
2557 f, &file_editor_tab::previous_breakpoint); | |
2558 | |
2559 connect (this, &file_editor::fetab_remove_all_breakpoints, | |
2560 f, &file_editor_tab::remove_all_breakpoints); | |
2561 | |
2562 connect (this, &file_editor::fetab_scintilla_command, | |
2563 f, &file_editor_tab::scintilla_command); | |
2564 | |
2565 connect (this, &file_editor::fetab_comment_selected_text, | |
2566 f, &file_editor_tab::comment_selected_text); | |
2567 | |
2568 connect (this, &file_editor::fetab_uncomment_selected_text, | |
2569 f, &file_editor_tab::uncomment_selected_text); | |
2570 | |
2571 connect (this, &file_editor::fetab_indent_selected_text, | |
2572 f, &file_editor_tab::indent_selected_text); | |
2573 | |
2574 connect (this, &file_editor::fetab_unindent_selected_text, | |
2575 f, &file_editor_tab::unindent_selected_text); | |
2576 | |
2577 connect (this, &file_editor::fetab_smart_indent_line_or_selected_text, | |
2578 f, &file_editor_tab::smart_indent_line_or_selected_text); | |
2579 | |
2580 connect (this, &file_editor::fetab_convert_eol, | |
2581 f, &file_editor_tab::convert_eol); | |
2582 | |
2583 connect (this, &file_editor::fetab_goto_line, | |
2584 f, &file_editor_tab::goto_line); | |
2585 | |
2586 connect (this, &file_editor::fetab_move_match_brace, | |
2587 f, &file_editor_tab::move_match_brace); | |
2588 | |
2589 connect (this, &file_editor::fetab_completion, | |
2590 f, &file_editor_tab::show_auto_completion); | |
2591 | |
2592 connect (this, &file_editor::fetab_set_focus, | |
2593 f, &file_editor_tab::set_focus); | |
2594 | |
2595 connect (this, &file_editor::fetab_insert_debugger_pointer, | |
2596 f, &file_editor_tab::insert_debugger_pointer); | |
2597 | |
2598 connect (this, &file_editor::fetab_delete_debugger_pointer, | |
2599 f, &file_editor_tab::delete_debugger_pointer); | |
2600 | |
2601 connect (this, &file_editor::fetab_do_breakpoint_marker, | |
2602 f, &file_editor_tab::do_breakpoint_marker); | |
2603 | |
2604 connect (this, &file_editor::update_gui_lexer_signal, | |
2605 f, &file_editor_tab::update_lexer_settings); | |
2606 | |
2607 // Convert other signals from the edit area and tab to editor signals. | |
2608 | |
2609 connect (f->qsci_edit_area (), &octave_qscintilla::execute_command_in_terminal_signal, | |
2610 this, &file_editor::execute_command_in_terminal_signal); | |
2611 | |
2612 connect (f->qsci_edit_area (), &octave_qscintilla::focus_console_after_command_signal, | |
2613 this, &file_editor::focus_console_after_command_signal); | |
2614 | |
2615 connect (f, &file_editor_tab::run_file_signal, | |
2616 this, &file_editor::run_file_signal); | |
2617 | |
2618 connect (f, &file_editor_tab::edit_mfile_request, | |
2619 this, &file_editor::edit_mfile_request); | |
2620 | |
2621 connect (f, &file_editor_tab::debug_quit_signal, | |
2622 this, &file_editor::debug_quit_signal); | |
2623 | |
2624 // Any interpreter_event signal from a file_editor_tab_widget is | |
2625 // handled the same as for the parent main_window object. | |
2626 | |
2627 connect (f, QOverload<const fcn_callback&>::of (&file_editor_tab::interpreter_event), | |
2628 this, QOverload<const fcn_callback&>::of (&file_editor::interpreter_event)); | |
2629 | |
2630 connect (f, QOverload<const meth_callback&>::of (&file_editor_tab::interpreter_event), | |
2631 this, QOverload<const meth_callback&>::of (&file_editor::interpreter_event)); | |
2632 | |
2633 return f; | |
2634 } | |
2635 | |
2636 void file_editor::add_file_editor_tab (file_editor_tab *f, const QString& fn, | |
2637 int index) | |
2638 { | |
2639 if (index == -1) | |
2640 m_tab_widget->addTab (f, fn); | |
2641 else | |
2642 m_tab_widget->insertTab (index, f, fn); | |
2643 | |
2644 m_tab_widget->setCurrentWidget (f); | |
2645 | |
2646 check_actions (); | |
2647 } | |
2648 | |
2649 void file_editor::mru_menu_update (void) | |
2650 { | |
2651 int num_files = qMin (m_mru_files.size (), int (MaxMRUFiles)); | |
2652 | |
2653 // configure and show active actions of mru-menu | |
2654 for (int i = 0; i < num_files; ++i) | |
2655 { | |
2656 QString text = QString ("&%1 %2"). | |
2657 arg ((i+1) % int (MaxMRUFiles)).arg (m_mru_files.at (i)); | |
2658 m_mru_file_actions[i]->setText (text); | |
2659 | |
2660 QStringList action_data; | |
2661 action_data << m_mru_files.at (i) << m_mru_files_encodings.at (i); | |
2662 m_mru_file_actions[i]->setData (action_data); | |
2663 | |
2664 m_mru_file_actions[i]->setVisible (true); | |
2665 } | |
2666 | |
2667 // hide unused mru-menu entries | |
2668 for (int j = num_files; j < MaxMRUFiles; ++j) | |
2669 m_mru_file_actions[j]->setVisible (false); | |
2670 | |
2671 // delete entries in string-list beyond MaxMRUFiles | |
2672 while (m_mru_files.size () > MaxMRUFiles) | |
2673 { | |
2674 m_mru_files.removeLast (); | |
2675 m_mru_files_encodings.removeLast (); | |
2676 } | |
2677 | |
2678 // save actual mru-list in settings | |
2679 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
2680 gui_settings *settings = rmgr.get_settings (); | |
2681 | |
2682 settings->setValue (ed_mru_file_list.key, m_mru_files); | |
2683 settings->setValue (ed_mru_file_encodings.key, m_mru_files_encodings); | |
2684 settings->sync (); | |
2685 } | |
2686 | |
2687 bool file_editor::call_custom_editor (const QString& file_name, int line) | |
2688 { | |
2689 // Check if the user wants to use a custom file editor. | |
2690 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
2691 gui_settings *settings = rmgr.get_settings (); | |
2692 | |
2693 if (settings->value (global_use_custom_editor.key, | |
2694 global_use_custom_editor.def).toBool ()) | |
2695 { | |
2696 // use the external editor interface for handling the call | |
2697 emit request_open_file_external (file_name, line); | |
2698 | |
2699 if (line < 0 && ! file_name.isEmpty ()) | |
2700 handle_mru_add_file (QFileInfo (file_name).canonicalFilePath (), | |
2701 QString ()); | |
2702 | |
2703 return true; | |
2704 } | |
2705 | |
2706 return false; | |
2707 } | |
2708 | |
2709 void file_editor::toggle_preference (const gui_pref& preference) | |
2710 { | |
2711 resource_manager& rmgr = m_octave_qobj.get_resource_manager (); | |
2712 gui_settings *settings = rmgr.get_settings (); | |
2713 | |
2714 bool old = settings->value (preference).toBool (); | |
2715 settings->setValue (preference.key, ! old); | |
2716 notice_settings (settings); | |
2717 } | |
2718 | |
2719 // Function for closing the files in a removed directory | |
2720 void file_editor::handle_dir_remove (const QString& old_name, | |
2721 const QString& new_name) | |
2722 { | |
2723 QDir old_dir (old_name); | |
2724 removed_file_data f_data; | |
2725 | |
2726 std::list<file_editor_tab *> editor_tab_lst = m_tab_widget->tab_list (); | |
2727 | |
2728 for (auto editor_tab : editor_tab_lst) | |
2729 { | |
2730 QString file_name = editor_tab->file_name (); | |
2731 | |
2732 if (file_name.isEmpty ()) | |
2733 continue; // Nothing to do, no valid file name | |
2734 | |
2735 // Get abs. file path and its path relative to the removed directory | |
2736 QString rel_path_to_file = old_dir.relativeFilePath (file_name); | |
2737 QString abs_path_to_file = old_dir.absoluteFilePath (file_name); | |
2738 | |
2739 // Test whether the file is located within the directory that will | |
2740 // be removed. For this, two conditions must be met: | |
2741 // 1. The path of the file rel. to the dir is not equal to the | |
2742 // its absolute one. | |
2743 // If both are equal, then there is no relative path and removed | |
2744 // directory and file are on different drives (e.g. on windows) | |
2745 // 2. The (real) relative path does not start with "../", i.e., | |
2746 // the file can be reached from the directory by descending only | |
2747 if ((rel_path_to_file != abs_path_to_file) | |
2748 && (rel_path_to_file.left (3) != QString ("../"))) | |
2749 { | |
2750 // The currently considered file is included in the | |
2751 // removed/renamed diectory: remeber it | |
2752 if (editor_tab) | |
2753 { | |
2754 editor_tab->enable_file_watcher (false); | |
2755 f_data.editor_tab = editor_tab; | |
2756 | |
2757 // Add the new file path and the encoding for later reloading | |
2758 // if new_name is given | |
2759 if (! new_name.isEmpty ()) | |
2760 { | |
2761 QDir new_dir (new_name); | |
2762 QString append_to_new_dir; | |
2763 if (new_dir.exists ()) | |
2764 { | |
2765 // The new directory already exists (movefile was used). | |
2766 // This means, we have to add the name (not the path) | |
2767 // of the old dir and the relative path to the file | |
2768 // to new dir. | |
2769 append_to_new_dir | |
2770 = old_dir.dirName () + "/" + rel_path_to_file; | |
2771 } | |
2772 else | |
2773 append_to_new_dir = rel_path_to_file; | |
2774 | |
2775 f_data.new_file_name | |
2776 = new_dir.absoluteFilePath (append_to_new_dir); | |
2777 } | |
2778 else | |
2779 f_data.new_file_name = ""; // no new name, just removing this file | |
2780 | |
2781 // Store data in list for later reloading | |
2782 m_tmp_closed_files << f_data; | |
2783 } | |
2784 } | |
2785 } | |
2786 } | |
2787 | |
2788 bool file_editor::editor_tab_has_focus (void) | |
2789 { | |
2790 QWidget *foc_w = focusWidget (); | |
2791 if (foc_w && foc_w->inherits ("octave::octave_qscintilla")) | |
2792 return true; | |
2793 return false; | |
2794 } | |
2795 | |
2796 // Check whether this file is already open in the editor. | |
2797 file_editor_tab *file_editor::find_tab_widget (const QString& file) | |
2798 { | |
2799 std::string std_file = file.toStdString (); | |
2800 | |
2801 std::list<file_editor_tab *> fe_tab_lst = m_tab_widget->tab_list (); | |
2802 | |
2803 for (auto fe_tab : fe_tab_lst) | |
2804 { | |
2805 QString tab_file = fe_tab->file_name (); | |
2806 | |
2807 // We check file == tab_file because | |
2808 // | |
2809 // same_file ("", "") | |
2810 // | |
2811 // is false | |
2812 | |
2813 if (same_file (std_file, tab_file.toStdString ()) || file == tab_file) | |
2814 return fe_tab; | |
2815 } | |
2816 | |
2817 return nullptr; | |
2818 } | |
2819 | |
2820 QAction * file_editor::add_action (QMenu *menu, const QString& text, | |
2821 const char *member, | |
2822 QWidget *receiver) | |
2823 { | |
2824 return add_action (menu, QIcon (), text, member, receiver); | |
2825 } | |
2826 | |
2827 QAction * file_editor::add_action (QMenu *menu, const QIcon& icon, | |
2828 const QString& text, const char *member, | |
2829 QWidget *receiver) | |
2830 { | |
2831 QAction *a; | |
2832 QWidget *r = this; | |
2833 | |
2834 if (receiver != nullptr) | |
2835 r = receiver; | |
2836 | |
2837 if (menu) | |
2838 a = menu->addAction (icon, text, r, member); | |
2839 else | |
2840 { | |
2841 a = new QAction (this); | |
2842 connect (a, SIGNAL (triggered ()), r, member); | |
2843 } | |
2844 | |
2845 addAction (a); // important for shortcut context | |
2846 a->setShortcutContext (Qt::WidgetWithChildrenShortcut); | |
2847 | |
2848 return a; | |
2849 } | |
2850 | |
2851 QMenu* file_editor::add_menu (QMenuBar *p, QString name) | |
2852 { | |
2853 QMenu *menu = p->addMenu (name); | |
2854 | |
2855 QString base_name = name; // get a copy | |
2856 // replace intended '&' ("&&") by a temp. string | |
2857 base_name.replace ("&&", "___octave_amp_replacement___"); | |
2858 // remove single '&' (shortcut) | |
2859 base_name.remove ("&"); | |
2860 // restore intended '&' | |
2861 base_name.replace ("___octave_amp_replacement___", "&&"); | |
2862 | |
2863 // remember names with and without shortcut | |
2864 m_hash_menu_text[menu] = QStringList () << name << base_name; | |
2865 | |
2866 return menu; | |
2867 } | |
2868 | |
2869 OCTAVE_END_NAMESPACE(octave) | |
2870 | |
2871 #endif |