Mercurial > octave
view libgui/src/m-editor/file-editor.cc @ 23920:0b971884080c
reload editor files when removing was not successful (bug #43922)
* files-dock-widget.cc (contextmenu_rename): emit the signal for reloading
the files from their new location with the state of the renaming allowing
to reload the files from the old locations,
(contextmenu_delete): emit the signal for reloading files if the removing
was not successful allowing to reload the not removed files,
* files-dock-widget.h: signal file_renamed_signal with boolean parameter
* file-editor.cc (handle_file_remove): clear list of temporary closed files
right at the beginning of this method, if an editor file is going to be
removed or renamed, store the old file name at first in the file list,
then the new file name (or an empty string) and finally the encoding;
(handle_dir_remove): clear the closed file list at the beginning, store
name of old file, new file (or empty string) and encoding into the list
is a file is affected by renaming or removing the directory;
(handle_file_renamed): new boolean parameter, which decides whether the old
or the new file is loaded into the editor
* file-editor.h: boolean parameter for handle_file_renamed; list of temporarily
closed files contains old name, new name, and encoding
* main-window.cc (construct): update signal connection due to new boolean
parameter
author | Torsten <mttl@mailbox.org> |
---|---|
date | Tue, 15 Aug 2017 22:00:06 +0200 |
parents | 1e54d9aba433 |
children | 387be1a6c3dc |
line wrap: on
line source
/* Copyright (C) 2011-2017 Jacob Dawid This file is part of Octave. Octave is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octave; see the file COPYING. If not, see <http://www.gnu.org/licenses/>. */ #if defined (HAVE_CONFIG_H) # include "config.h" #endif #if defined (HAVE_QSCINTILLA) #include "file-editor.h" #include "resource-manager.h" #include "shortcut-manager.h" #include <QApplication> #include <QFile> #include <QFileDialog> #include <QFont> #include <QMessageBox> #include <QMimeData> #include <QProcess> #include <QStyle> #include <QTabBar> #include <QTextStream> #include <QVBoxLayout> #include <Qsci/qscicommandset.h> #include "main-window.h" #include "oct-map.h" #include "octave-link.h" #include "utils.h" file_editor::file_editor (QWidget *p) : file_editor_interface (p) { // Set current editing directory before construct because loaded // files will change ced accordingly. ced = QDir::currentPath (); // set action that are later added by the main window to null, // preventing access to them when they are still undefined _undo_action = nullptr; _copy_action = nullptr; _paste_action = nullptr; _selectall_action = nullptr; _closed = false; _no_focus = false; construct (); // actions that should also be available in the find dialog _fetab_actions << _find_next_action; _fetab_actions << _find_previous_action; setVisible (false); setAcceptDrops (true); } file_editor::~file_editor (void) { if (_mru_file_menu) delete _mru_file_menu; } bool file_editor::check_closing (void) { // When the application or the editor is closing and the user wants to close // all files in the latter case all editor tabs are checked whether // they need to be saved. During these ckecked the tabs are not closed // since the user might cancel closing octave during one of these saving // dialogs. Therefore, saving the session for restoring at next start // is not done before the application is definitely closing // Have all file editor tabs signal what their filenames are. editor_tab_map.clear (); emit fetab_file_name_query (nullptr); // Save all tabs with confirmation. file_editor_tab::reset_cancel (); emit fetab_check_modified_file (); // If there was a cancellation, make the already saved/discarded tabs // recovering from the exit by removing the read-only state and by // recovering the debugger breakpoints. Finally return false in order to // cancel closing the application or the editor if (file_editor_tab::was_cancelled ()) { emit fetab_recover_from_exit (); return false; } // Here, the application or the editor will be closed -> store the session // Save open files for restoring in next session; this only is possible QSettings *settings = resource_manager::get_settings (); // save filenames (even if last session will not be restored next time) // together with encoding and the tab index QStringList fetFileNames; QStringList fet_encodings; QStringList fet_index; // save all open tabs before they are definitely closed for (editor_tab_map_const_iterator p = editor_tab_map.begin (); p != editor_tab_map.end (); p++) { QString file_name = p->first; // get file name of tab if (! file_name.isEmpty ()) // do not append unnamed files { fetFileNames.append (file_name); fet_encodings.append (editor_tab_map[file_name].encoding); QString index; fet_index.append (index.setNum (_tab_widget->indexOf (editor_tab_map[file_name].fet_ID))); } } settings->setValue ("editor/savedSessionTabs", fetFileNames); settings->setValue ("editor/saved_session_encodings", fet_encodings); settings->setValue ("editor/saved_session_tab_index", fet_index); settings->sync (); // Finally close all the tabs and return indication that we can exit // the application or close the editor for (int i = _tab_widget->count () - 1; i >= 0; i--) { // backwards loop since _tab_widget->count () changes during the loop delete _tab_widget->widget (i); _tab_widget->removeTab (i); } return true; } void file_editor::focus (void) { if (_no_focus) return; // No focus for the editor if external open/close request octave_dock_widget::focus (); // set focus to current tab QWidget *fileEditorTab = _tab_widget->currentWidget (); if (fileEditorTab) emit fetab_set_focus (fileEditorTab); } void file_editor::set_focus (QWidget *fet) { octave_dock_widget::focus (); // set focus to desired tab if (fet) _tab_widget->setCurrentWidget (fet); } void file_editor::update_octave_directory (const QString& dir) { ced = dir; emit fetab_set_directory (ced); // for save dialog } QMenu * file_editor::debug_menu (void) { return _debug_menu; } QToolBar * file_editor::toolbar (void) { return _tool_bar; } void file_editor::handle_enter_debug_mode (void) { _run_action->setEnabled (false); _run_action->setShortcut (QKeySequence ()); } void file_editor::handle_exit_debug_mode (void) { _run_action->setEnabled (true); shortcut_manager::set_shortcut (_run_action, "editor_run:run_file"); } void file_editor::request_new_file (const QString& commands) { // Custom editor? If yes, we can only call the editor without passing // some initial contents and even without being sure a new file is opened if (call_custom_editor ()) return; // New file isn't a file_editor_tab function since the file // editor tab has yet to be created and there is no object to // pass a signal to. Hence, functionality is here. file_editor_tab *fileEditorTab = new file_editor_tab (ced); if (fileEditorTab) { add_file_editor_tab (fileEditorTab, ""); // new tab with empty title fileEditorTab->new_file (commands); // title is updated here focus (); // focus editor and new tab } } // Check whether this file is already open in the editor. QWidget * file_editor::find_tab_widget (const QString& file) { // Have all file editor tabs signal what their filenames are. editor_tab_map.clear (); emit fetab_file_name_query (nullptr); // Check all tabs for the given file name QWidget *retval = nullptr; for (editor_tab_map_const_iterator p = editor_tab_map.begin (); p != editor_tab_map.end (); p++) { QString tab_file = p->first; if (same_file (file.toStdString (), tab_file.toStdString ()) || file == tab_file) // needed as same_file ("","") is false. { retval = p->second.fet_ID; break; } } return retval; } bool file_editor::call_custom_editor (const QString& file_name, int line) { // Check if the user wants to use a custom file editor. QSettings *settings = resource_manager::get_settings (); if (settings->value ("useCustomFileEditor",false).toBool ()) { // use the external editor interface for handling the call emit request_open_file_external (file_name, line); if (line < 0 && ! file_name.isEmpty ()) handle_mru_add_file (QFileInfo (file_name).canonicalFilePath (), QString ()); return true; } return false; } bool file_editor::is_editor_console_tabbed () { main_window *w = static_cast<main_window *>(main_win ()); QList<QDockWidget *> w_list = w->tabifiedDockWidgets (this); QDockWidget *console = static_cast<QDockWidget *> (w->get_dock_widget_list ().at (0)); for (int i = 0; i < w_list.count (); i++) { if (w_list.at (i) == console) return true; } return false; } // Open a file, if not already open, and mark the current execution location // and/or a breakpoint with condition cond. void file_editor::request_open_file (const QString& openFileName, const QString& encoding, int line, bool debug_pointer, bool breakpoint_marker, bool insert, const QString& cond) { if (call_custom_editor (openFileName, line)) return; // custom editor called if (openFileName.isEmpty ()) { // This happens if edit is calles without an argument // Open eitor with empty edit area instead (as new file would do) request_new_file (""); } else { // Check whether this file is already open in the editor. QWidget *tab = find_tab_widget (openFileName); if (tab) { _tab_widget->setCurrentWidget (tab); if (line > 0) { emit fetab_goto_line (tab, line); if (debug_pointer) emit fetab_insert_debugger_pointer (tab, line); if (breakpoint_marker) emit fetab_do_breakpoint_marker (insert, tab, line, cond); } if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ())) { emit fetab_set_focus (tab); focus (); } } else { file_editor_tab *fileEditorTab = nullptr; // Reuse <unnamed> tab if it hasn't yet been modified. bool reusing = false; tab = find_tab_widget (""); if (tab) { fileEditorTab = static_cast<file_editor_tab *>(tab); if (fileEditorTab->qsci_edit_area ()->isModified ()) fileEditorTab = nullptr; else reusing = true; } // If <unnamed> was absent or modified, create a new tab. if (! fileEditorTab) fileEditorTab = new file_editor_tab (); if (fileEditorTab) { fileEditorTab->set_encoding (encoding); QString result = fileEditorTab->load_file (openFileName); if (result == "") { // Supply empty title then have the file_editor_tab update // with full or short name. if (! reusing) add_file_editor_tab (fileEditorTab, ""); fileEditorTab->update_window_title (false); // file already loaded, add file to mru list here QFileInfo file_info = QFileInfo (openFileName); handle_mru_add_file (file_info.canonicalFilePath (), encoding); if (line > 0) { emit fetab_goto_line (fileEditorTab, line); if (debug_pointer) emit fetab_insert_debugger_pointer (fileEditorTab, line); if (breakpoint_marker) emit fetab_do_breakpoint_marker (insert, fileEditorTab, line, cond); } } else { delete fileEditorTab; if (QFile::exists (openFileName)) { // File not readable: // create a NonModal message about error. QMessageBox *msgBox = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), tr ("Could not open file\n%1\nfor read: %2."). arg (openFileName).arg (result), QMessageBox::Ok, this); msgBox->setWindowModality (Qt::NonModal); msgBox->setAttribute (Qt::WA_DeleteOnClose); msgBox->show (); } else { // File does not exist, should it be created? bool create_file = true; QMessageBox *msgBox; QSettings *settings = resource_manager::get_settings (); if (! settings->value ("editor/create_new_file", false).toBool ()) { msgBox = new QMessageBox (QMessageBox::Question, tr ("Octave Editor"), tr ("File\n%1\ndoes not exist. " "Do you want to create it?").arg (openFileName), QMessageBox::NoButton,nullptr); QPushButton *create_button = msgBox->addButton (tr ("Create"), QMessageBox::YesRole); msgBox->addButton (tr ("Cancel"), QMessageBox::RejectRole); msgBox->setDefaultButton (create_button); msgBox->exec (); QAbstractButton *clicked_button = msgBox->clickedButton (); if (clicked_button != create_button) create_file = false; delete msgBox; } if (create_file) { // create the file and call the editor again QFile file (openFileName); if (! file.open (QIODevice::WriteOnly)) { // error opening the file msgBox = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), tr ("Could not open file\n%1\nfor write: %2."). arg (openFileName).arg (file.errorString ()), QMessageBox::Ok, this); msgBox->setWindowModality (Qt::NonModal); msgBox->setAttribute (Qt::WA_DeleteOnClose); msgBox->show (); } else { file.close (); request_open_file (openFileName); } } } } } if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ())) { // really show editor and the current editor tab focus (); emit file_loaded_signal (); } } } } // open a file from the mru list void file_editor::request_mru_open_file (QAction *action) { if (action) { request_open_file (action->data ().toStringList ().at (0), action->data ().toStringList ().at (1)); } } void file_editor::check_conflict_save (const QString& saveFileName, bool remove_on_success) { // Check whether this file is already open in the editor. QWidget *tab = find_tab_widget (saveFileName); if (tab) { // Note: to overwrite the contents of some other file editor tab // with the same name requires identifying which file editor tab // that is (not too difficult) then close that tab. Of course, // that could trigger another dialog box if the file editor tab // with the same name has modifications in it. This could become // somewhat confusing to the user. For now, opt to do nothing. // Create a NonModal message about error. QMessageBox *msgBox = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), tr ("File not saved! A file with the selected name\n%1\n" "is already open in the editor"). arg (saveFileName), QMessageBox::Ok, nullptr); msgBox->setWindowModality (Qt::NonModal); msgBox->setAttribute (Qt::WA_DeleteOnClose); msgBox->show (); return; } QObject *saveFileObject = sender (); QWidget *saveFileWidget = nullptr; for (int i = 0; i < _tab_widget->count (); i++) { if (_tab_widget->widget (i) == saveFileObject) { saveFileWidget = _tab_widget->widget (i); break; } } if (! saveFileWidget) { // Create a NonModal message about error. QMessageBox *msgBox = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), tr ("The associated file editor tab has disappeared."), QMessageBox::Ok, nullptr); msgBox->setWindowModality (Qt::NonModal); msgBox->setAttribute (Qt::WA_DeleteOnClose); msgBox->show (); return; } // Can save without conflict, have the file editor tab do so. emit fetab_save_file (saveFileWidget, saveFileName, remove_on_success); } void file_editor::handle_insert_debugger_pointer_request (const QString& file, int line) { request_open_file (file, QString (), line, true); // default encoding } void file_editor::handle_delete_debugger_pointer_request (const QString& file, int line) { if (! file.isEmpty ()) { // Check whether this file is already open in the editor. QWidget *tab = find_tab_widget (file); if (tab) { _tab_widget->setCurrentWidget (tab); if (line > 0) emit fetab_delete_debugger_pointer (tab, line); emit fetab_set_focus (tab); } } } void file_editor::handle_update_breakpoint_marker_request (bool insert, const QString& file, int line, const QString& cond) { request_open_file (file, QString (), line, false, true, insert, cond); } void file_editor::handle_edit_file_request (const QString& file) { request_open_file (file); } // Slot used for signals indicating that a file was changed/rename or // is going to be deleted/renamed void file_editor::handle_file_remove (const QString& old_name, const QString& new_name) { // Clear old lsit of files to reload _tmp_closed_files.clear (); // Check if old name is a file or directory QFileInfo old (old_name); if (old.isDir ()) { // Call the function which handles directories and return handle_dir_remove (old_name, new_name); return; } // Is old file open? file_editor_tab *editor_tab = static_cast<file_editor_tab *> (find_tab_widget (old_name)); if (editor_tab) { // Yes, close it silently _no_focus = true; // Remember for not focussing editor editor_tab->file_has_changed (QString (), true); // Close the tab _no_focus = false; // Back to normal _tmp_closed_files << old_name; // for reloading if error removing if (! new_name.isEmpty ()) _tmp_closed_files << new_name; // store new name else _tmp_closed_files << ""; // no new name, just removing this file // Get and store the related encoding for (editor_tab_map_const_iterator p = editor_tab_map.begin (); p != editor_tab_map.end (); p++) { if (editor_tab == p->second.fet_ID) { _tmp_closed_files << p->second.encoding; break; } } } } // Function for closing the files in a removed directory void file_editor::handle_dir_remove (const QString& old_name, const QString& new_name) { QDir old_dir (old_name); // Have all file editor tabs signal what their filenames are. editor_tab_map.clear (); emit fetab_file_name_query (nullptr); // Loop over all open files and pick those within old_dir for (editor_tab_map_const_iterator p = editor_tab_map.begin (); p != editor_tab_map.end (); p++) { QString rel_path_to_file = old_dir.relativeFilePath (p->first); if (rel_path_to_file.left (3) != QString ("../")) { // We directly go down from old_dir to reach our file: Our // file is included in the removed/renamed diectory. // Thus delete it. _no_focus = true; // Remember for not focussing editor file_editor_tab *editor_tab = static_cast<file_editor_tab *> (p->second.fet_ID); editor_tab->file_has_changed (QString (), true); // Close _no_focus = false; // Back to normal // Store file for possible later reload _tmp_closed_files << p->first; // Add the new file path and the encoding for later reloading // if new_name is given if (! new_name.isEmpty ()) { QDir new_dir (new_name); _tmp_closed_files << new_dir.absoluteFilePath (rel_path_to_file); } else _tmp_closed_files << ""; // no new name, just removing this file _tmp_closed_files << p->second.encoding; // store the encoding } } } // Slot for signal indicating that a file was renamed void file_editor::handle_file_renamed (bool load_new) { _no_focus = true; // Remember for not focussing editor for (int i = 0; i < _tmp_closed_files.count (); i = i + 3) { if (! _tmp_closed_files.at (i + load_new).isEmpty ()) request_open_file (_tmp_closed_files.at (i + load_new), _tmp_closed_files.at (i+2)); } _no_focus = false; // Back to normal focus } void file_editor::do_undo () { if (editor_tab_has_focus ()) emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_UNDO); } void file_editor::request_redo (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_REDO); } void file_editor::copyClipboard () { if (editor_tab_has_focus ()) emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_COPY); } void file_editor::request_cut (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_CUT); } void file_editor::pasteClipboard () { if (editor_tab_has_focus ()) emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_PASTE); } void file_editor::selectAll () { if (editor_tab_has_focus ()) emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_SELECTALL); } void file_editor::request_context_help (bool) { emit fetab_context_help (_tab_widget->currentWidget (), false); } void file_editor::request_context_doc (bool) { emit fetab_context_help (_tab_widget->currentWidget (), true); } void file_editor::request_context_edit (bool) { emit fetab_context_edit (_tab_widget->currentWidget ()); } void file_editor::request_save_file (bool) { emit fetab_save_file (_tab_widget->currentWidget ()); } void file_editor::request_save_file_as (bool) { emit fetab_save_file_as (_tab_widget->currentWidget ()); } void file_editor::request_print_file (bool) { emit fetab_print_file (_tab_widget->currentWidget ()); } void file_editor::request_run_file (bool) { emit fetab_run_file (_tab_widget->currentWidget ()); } void file_editor::request_context_run (bool) { emit fetab_context_run (_tab_widget->currentWidget ()); } void file_editor::request_toggle_bookmark (bool) { emit fetab_toggle_bookmark (_tab_widget->currentWidget ()); } void file_editor::request_next_bookmark (bool) { emit fetab_next_bookmark (_tab_widget->currentWidget ()); } void file_editor::request_previous_bookmark (bool) { emit fetab_previous_bookmark (_tab_widget->currentWidget ()); } void file_editor::request_remove_bookmark (bool) { emit fetab_remove_bookmark (_tab_widget->currentWidget ()); } // FIXME: What should this do with conditional breakpoints? void file_editor::request_toggle_breakpoint (bool) { emit fetab_toggle_breakpoint (_tab_widget->currentWidget ()); } void file_editor::request_next_breakpoint (bool) { emit fetab_next_breakpoint (_tab_widget->currentWidget ()); } void file_editor::request_previous_breakpoint (bool) { emit fetab_previous_breakpoint (_tab_widget->currentWidget ()); } void file_editor::request_remove_breakpoint (bool) { emit fetab_remove_all_breakpoints (_tab_widget->currentWidget ()); } // slots for Edit->Commands actions void file_editor::request_delete_start_word (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_DELWORDLEFT); } void file_editor::request_delete_end_word (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_DELWORDRIGHT); } void file_editor::request_delete_start_line (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_DELLINELEFT); } void file_editor::request_delete_end_line (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_DELLINERIGHT); } void file_editor::request_delete_line (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_LINEDELETE); } void file_editor::request_copy_line (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_LINECOPY); } void file_editor::request_cut_line (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_LINECUT); } void file_editor::request_duplicate_selection (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_SELECTIONDUPLICATE); } void file_editor::request_transpose_line (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_LINETRANSPOSE); } void file_editor::request_comment_selected_text (bool) { emit fetab_comment_selected_text (_tab_widget->currentWidget ()); } void file_editor::request_uncomment_selected_text (bool) { emit fetab_uncomment_selected_text (_tab_widget->currentWidget ()); } // slots for Edit->Format actions void file_editor::request_upper_case (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_UPPERCASE); } void file_editor::request_lower_case (bool) { emit fetab_scintilla_command (_tab_widget->currentWidget (), QsciScintillaBase::SCI_LOWERCASE); } void file_editor::request_indent_selected_text (bool) { emit fetab_indent_selected_text (_tab_widget->currentWidget ()); } void file_editor::request_unindent_selected_text (bool) { emit fetab_unindent_selected_text (_tab_widget->currentWidget ()); } void file_editor::request_conv_eol_windows (bool) { emit fetab_convert_eol (_tab_widget->currentWidget (), QsciScintilla::EolWindows); } void file_editor::request_conv_eol_unix (bool) { emit fetab_convert_eol (_tab_widget->currentWidget (), QsciScintilla::EolUnix); } void file_editor::request_conv_eol_mac (bool) { emit fetab_convert_eol (_tab_widget->currentWidget (), QsciScintilla::EolMac); } void file_editor::request_find (bool) { emit fetab_find (_tab_widget->currentWidget (), _fetab_actions); } void file_editor::request_find_next (bool) { emit fetab_find_next (_tab_widget->currentWidget ()); } void file_editor::request_find_previous (bool) { emit fetab_find_previous (_tab_widget->currentWidget ()); } void file_editor::request_goto_line (bool) { emit fetab_goto_line (_tab_widget->currentWidget ()); } void file_editor::request_move_match_brace (bool) { emit fetab_move_match_brace (_tab_widget->currentWidget (), false); } void file_editor::request_sel_match_brace (bool) { emit fetab_move_match_brace (_tab_widget->currentWidget (), true); } void file_editor::request_completion (bool) { emit fetab_completion (_tab_widget->currentWidget ()); } void file_editor::handle_mru_add_file (const QString& file_name, const QString& encoding) { int index; while ((index = _mru_files.indexOf (file_name)) >= 0) { _mru_files.removeAt (index); _mru_files_encodings.removeAt (index); } _mru_files.prepend (file_name); _mru_files_encodings.prepend (encoding); mru_menu_update (); } void file_editor::mru_menu_update (void) { int num_files = qMin (_mru_files.size (), int (MaxMRUFiles)); // configure and show active actions of mru-menu for (int i = 0; i < num_files; ++i) { QString text = tr ("&%1 %2"). arg ((i+1) % int (MaxMRUFiles)).arg (_mru_files.at (i)); _mru_file_actions[i]->setText (text); QStringList action_data; action_data << _mru_files.at (i) << _mru_files_encodings.at (i); _mru_file_actions[i]->setData (action_data); _mru_file_actions[i]->setVisible (true); } // hide unused mru-menu entries for (int j = num_files; j < MaxMRUFiles; ++j) _mru_file_actions[j]->setVisible (false); // delete entries in string-list beyond MaxMRUFiles while (_mru_files.size () > MaxMRUFiles) { _mru_files.removeLast (); _mru_files_encodings.removeLast (); } // save actual mru-list in settings QSettings *settings = resource_manager::get_settings (); settings->setValue ("editor/mru_file_list", _mru_files); settings->setValue ("editor/mru_file_encodings", _mru_files_encodings); settings->sync (); } void file_editor::handle_file_name_changed (const QString& fname, const QString& tip) { QObject *fileEditorTab = sender (); if (fileEditorTab) { for (int i = 0; i < _tab_widget->count (); i++) { if (_tab_widget->widget (i) == fileEditorTab) { _tab_widget->setTabText (i, fname); _tab_widget->setTabToolTip (i, tip); } } } } void file_editor::request_close_file (bool) { file_editor_tab *editor_tab = static_cast<file_editor_tab *> (_tab_widget->currentWidget ()); editor_tab->conditional_close (); } void file_editor::request_close_all_files (bool) { file_editor_tab *editor_tab; // loop over all tabs starting from last one otherwise deletion changes index for (int index = _tab_widget->count ()-1; index >= 0; index--) { editor_tab = static_cast<file_editor_tab *> (_tab_widget->widget (index)); editor_tab->conditional_close (); } } void file_editor::request_close_other_files (bool) { file_editor_tab *editor_tab; QWidget *tabID = _tab_widget->currentWidget (); // loop over all tabs starting from last one otherwise deletion changes index for (int index = _tab_widget->count ()-1; index >= 0; index--) { if (tabID != _tab_widget->widget (index)) { editor_tab = static_cast<file_editor_tab *> (_tab_widget->widget (index)); editor_tab->conditional_close (); } } } void file_editor::handle_tab_close_request (int index) { file_editor_tab *editor_tab = static_cast<file_editor_tab *> (_tab_widget->widget (index)); editor_tab->conditional_close (); } void file_editor::handle_tab_remove_request (void) { QObject *fileEditorTab = sender (); if (fileEditorTab) { for (int i = 0; i < _tab_widget->count (); i++) { if (_tab_widget->widget (i) == fileEditorTab) { _tab_widget->removeTab (i); // Deleting sender is dodgy, but works because the signal // is the last item in the sender's routines. delete fileEditorTab; break; } } } check_actions (); focus (); // focus stays in editor when tab is closed } void file_editor::handle_add_filename_to_list (const QString& fileName, const QString& encoding, QWidget *ID) { // Should we allow multiple tabs for a single file? editor_tab_map[fileName].fet_ID = ID; editor_tab_map[fileName].encoding = encoding; } // context menu of edit area void file_editor::active_tab_changed (int index) { emit fetab_change_request (_tab_widget->widget (index)); } void file_editor::create_context_menu (QMenu *menu) { // remove all standard actions from scintilla QList<QAction *> all_actions = menu->actions (); QAction *a; foreach (a, all_actions) menu->removeAction (a); // add editor's actions with icons and customized shortcuts menu->addAction (_undo_action); menu->addAction (_redo_action); menu->addSeparator (); menu->addAction (_cut_action); menu->addAction (_copy_action); menu->addAction (_paste_action); menu->addSeparator (); menu->addAction (_selectall_action); menu->addSeparator (); menu->addAction (_run_selection_action); } void file_editor::toggle_preference (const QString& preference, bool def) { QSettings *settings = resource_manager::get_settings (); bool old = settings->value (preference,def).toBool (); settings->setValue (preference,! old); notice_settings (settings); } void file_editor::show_line_numbers (bool) { toggle_preference ("editor/showLineNumbers",true); } void file_editor::show_white_space (bool) { toggle_preference ("editor/show_white_space",false); } void file_editor::show_eol_chars (bool) { toggle_preference ("editor/show_eol_chars",false); } void file_editor::show_indent_guides (bool) { toggle_preference ("editor/show_indent_guides",false); } void file_editor::show_long_line (bool) { toggle_preference ("editor/long_line_marker",true); } void file_editor::show_toolbar (bool) { toggle_preference ("editor/show_toolbar",true); } void file_editor::show_statusbar (bool) { toggle_preference ("editor/show_edit_status_bar",true); } void file_editor::show_hscrollbar (bool) { toggle_preference ("editor/show_hscroll_bar",true); } void file_editor::zoom_in (bool) { emit fetab_zoom_in (_tab_widget->currentWidget ()); } void file_editor::zoom_out (bool) { emit fetab_zoom_out (_tab_widget->currentWidget ()); } void file_editor::zoom_normal (bool) { emit fetab_zoom_normal (_tab_widget->currentWidget ()); } void file_editor::edit_status_update (bool undo, bool redo) { if (_undo_action) _undo_action->setEnabled (undo); _redo_action->setEnabled (redo); } void file_editor::handle_editor_state_changed (bool copy_available, bool is_octave_file) { // In case there is some scenario where traffic could be coming from // all the file editor tabs, just process info from the current active tab. if (sender () == _tab_widget->currentWidget ()) { if (_copy_action) _copy_action->setEnabled (copy_available); _cut_action->setEnabled (copy_available); _run_selection_action->setEnabled (copy_available); _run_action->setEnabled (is_octave_file); setFocusProxy (_tab_widget->currentWidget ()); } } void file_editor::notice_settings (const QSettings *settings) { int icon_size_settings = settings->value ("toolbar_icon_size",0).toInt (); QStyle *st = style (); int icon_size = st->pixelMetric (QStyle::PM_ToolBarIconSize); if (icon_size_settings == 1) icon_size = st->pixelMetric (QStyle::PM_LargeIconSize); else if (icon_size_settings == -1) icon_size = st->pixelMetric (QStyle::PM_SmallIconSize); _tool_bar->setIconSize (QSize (icon_size,icon_size)); int tab_width_min = settings->value ("editor/notebook_tab_width_min", 160) .toInt (); int tab_width_max = settings->value ("editor/notebook_tab_width_max", 300) .toInt (); if (settings->value ("editor/longWindowTitle", false).toBool ()) { QString style_sheet = QString ("QTabBar::tab " "{min-width: %1px; max-width: %2px;}") .arg (tab_width_min).arg (tab_width_max); _tab_widget->setElideMode (Qt::ElideLeft); _tab_widget->setStyleSheet (style_sheet); } else _tab_widget->setElideMode (Qt::ElideNone); _tab_widget->setUsesScrollButtons (true); bool show_it; show_it = settings->value ("editor/showLineNumbers",true).toBool (); _show_linenum_action->setChecked (show_it); show_it = settings->value ("editor/show_white_space",false).toBool (); _show_whitespace_action->setChecked (show_it); show_it = settings->value ("editor/show_eol_chars",false).toBool (); _show_eol_action->setChecked (show_it); show_it = settings->value ("editor/show_indent_guides",false).toBool (); _show_indguide_action->setChecked (show_it); show_it = settings->value ("editor/long_line_marker",true).toBool (); _show_longline_action->setChecked (show_it); show_it = settings->value ("editor/show_toolbar",true).toBool (); _show_toolbar_action->setChecked (show_it); _tool_bar->setVisible (show_it); show_it = settings->value ("editor/show_edit_status_bar",true).toBool (); _show_statusbar_action->setChecked (show_it); show_it = settings->value ("editor/show_hscroll_bar",true).toBool (); _show_hscrollbar_action->setChecked (show_it); set_shortcuts (); // Relay signal to file editor tabs. emit fetab_settings_changed (settings); } void file_editor::request_preferences (bool) { emit request_settings_dialog ("editor"); } void file_editor::request_styles_preferences (bool) { emit request_settings_dialog ("editor_styles"); } // insert global actions, that should also be displayed in the editor window, // into the editor's menu and/or toolbar void file_editor::insert_global_actions (QList<QAction*> shared_actions) { // actions/menus that have to be added to the toolbar or the menu QAction *open_action = shared_actions.at (OPEN_ACTION); QAction *new_action = shared_actions.at (NEW_SCRIPT_ACTION); QAction *new_fcn_action = shared_actions.at (NEW_FUNCTION_ACTION); _fileMenu->insertAction (_mru_file_menu->menuAction (), open_action); _fileMenu->insertAction (open_action, new_fcn_action); _fileMenu->insertAction (new_fcn_action, new_action); _tool_bar->insertAction (_popdown_mru_action, open_action); _tool_bar->insertAction (open_action, new_action); // actions that are additionally enabled/disabled later by the editor // undo _undo_action = shared_actions.at (UNDO_ACTION); _tool_bar->insertAction (_redo_action,_undo_action); _edit_menu->insertAction (_redo_action,_undo_action); // copy _copy_action = shared_actions.at (COPY_ACTION); _tool_bar->insertAction (_cut_action,_copy_action); _edit_menu->insertAction (_cut_action,_copy_action); // select all _selectall_action = shared_actions.at (SELECTALL_ACTION); _edit_menu->insertAction (_find_action,_selectall_action); _edit_menu->insertSeparator (_find_action); // paste _paste_action = shared_actions.at (PASTE_ACTION); _tool_bar->insertAction (_find_action,_paste_action); _edit_menu->insertAction (_selectall_action,_paste_action); _edit_menu->insertSeparator (_selectall_action); // find files _find_files_action = shared_actions.at (FIND_FILES_ACTION); _edit_menu->insertAction (_find_action, _find_files_action); } QAction* file_editor::add_action (QMenu *menu, const QIcon& icon, const QString& text, const char *member) { QAction *a; if (menu) a = menu->addAction (icon, text, this, member); else { a = new QAction (this); connect (a, SIGNAL (triggered ()), this, member); } addAction (a); // important for shortcut context a->setShortcutContext (Qt::WidgetWithChildrenShortcut); return a; } // function enabling/disabling the menu accelerators depending on the // focus of the editor void file_editor::enable_menu_shortcuts (bool enable) { QHash<QMenu*, QStringList>::const_iterator i = _hash_menu_text.constBegin (); while (i != _hash_menu_text.constEnd ()) { i.key ()->setTitle (i.value ().at (! enable)); ++i; } // when editor loses focus, enable the actions, which are always active // in the main window due to missing info on selected text and undo actions if (! enable && _copy_action && _undo_action) { _copy_action->setEnabled (true); _undo_action->setEnabled (true); } } QMenu* file_editor::m_add_menu (QMenuBar *p, QString name) { QMenu *menu = p->addMenu (name); QString base_name = name; // get a copy // replace intended '&' ("&&") by a temp. string base_name.replace ("&&", "___octave_amp_replacement___"); // remove single '&' (shortcut) base_name.remove ("&"); // restore intended '&' base_name.replace ("___octave_amp_replacement___", "&&"); // remember names with and without shortcut _hash_menu_text[menu] = QStringList () << name << base_name; return menu; } void file_editor::construct (void) { QWidget *editor_widget = new QWidget (this); // FIXME: what was the intended purpose of this unused variable? // QStyle *editor_style = QApplication::style (); _menu_bar = new QMenuBar (editor_widget); #if defined (Q_OS_MAC) _menu_bar->setNativeMenuBar (false); #endif _tool_bar = new QToolBar (editor_widget); _tool_bar->setMovable (true); _tab_widget = new file_editor_tab_widget (editor_widget); _tab_widget->setTabsClosable (true); #if defined (HAVE_QTABWIDGET_SETMOVABLE) _tab_widget->setMovable (true); #endif // the mru-list and an empty array of actions QSettings *settings = resource_manager::get_settings (); _mru_files = settings->value ("editor/mru_file_list").toStringList (); _mru_files_encodings = settings->value ("editor/mru_file_encodings") .toStringList (); if (_mru_files_encodings.count () != _mru_files.count ()) { // encodings don't have the same count -> do not use them! _mru_files_encodings = QStringList (); for (int i = 0; i < _mru_files.count (); i++) _mru_files_encodings << QString (); } for (int i = 0; i < MaxMRUFiles; ++i) { _mru_file_actions[i] = new QAction (this); _mru_file_actions[i]->setVisible (false); } // menu bar // file menu _fileMenu = m_add_menu (_menu_bar, tr ("&File")); // new and open menus are inserted later by the main window _mru_file_menu = new QMenu (tr ("&Recent Editor Files"), _fileMenu); for (int i = 0; i < MaxMRUFiles; ++i) _mru_file_menu->addAction (_mru_file_actions[i]); _fileMenu->addMenu (_mru_file_menu); _fileMenu->addSeparator (); _edit_function_action = add_action (_fileMenu, QIcon (), tr ("&Edit Function"), SLOT (request_context_edit (bool))); _fileMenu->addSeparator (); _save_action = add_action (_fileMenu, resource_manager::icon ("document-save"), tr ("&Save File"), SLOT (request_save_file (bool))); _save_as_action = add_action (_fileMenu, resource_manager::icon ("document-save-as"), tr ("Save File &As..."), SLOT (request_save_file_as (bool))); _fileMenu->addSeparator (); _close_action = add_action (_fileMenu, resource_manager::icon ("window-close",false), tr ("&Close"), SLOT (request_close_file (bool))); _close_all_action = add_action (_fileMenu, resource_manager::icon ("window-close",false), tr ("Close All"), SLOT (request_close_all_files (bool))); _close_others_action = add_action (_fileMenu, resource_manager::icon ("window-close",false), tr ("Close Other Files"), SLOT (request_close_other_files (bool))); _fileMenu->addSeparator (); _print_action = add_action (_fileMenu, resource_manager::icon ("document-print"), tr ("Print..."), SLOT (request_print_file (bool))); // edit menu (undo, copy, paste and select all later via main window) _edit_menu = m_add_menu (_menu_bar, tr ("&Edit")); _redo_action = add_action (_edit_menu, resource_manager::icon ("edit-redo"), tr ("&Redo"), SLOT (request_redo (bool))); _redo_action->setEnabled (false); _edit_menu->addSeparator (); _cut_action = add_action (_edit_menu, resource_manager::icon ("edit-cut"), tr ("Cu&t"), SLOT (request_cut (bool))); _cut_action->setEnabled (false); _find_action = add_action (_edit_menu, resource_manager::icon ("edit-find-replace"), tr ("&Find and Replace..."), SLOT (request_find (bool))); _find_next_action = add_action (_edit_menu, QIcon (), tr ("Find &Next..."), SLOT (request_find_next (bool))); _find_previous_action = add_action (_edit_menu, QIcon (), tr ("Find &Previous..."), SLOT (request_find_previous (bool))); _edit_menu->addSeparator (); _edit_cmd_menu = _edit_menu->addMenu (tr ("&Commands")); _delete_line_action = add_action (_edit_cmd_menu, QIcon (), tr ("Delete Line"), SLOT (request_delete_line (bool))); _copy_line_action = add_action (_edit_cmd_menu, QIcon (), tr ("Copy Line"), SLOT (request_copy_line (bool))); _cut_line_action = add_action (_edit_cmd_menu, QIcon (), tr ("Cut Line"), SLOT (request_cut_line (bool))); _edit_cmd_menu->addSeparator (); _delete_start_word_action = add_action (_edit_cmd_menu, QIcon (), tr ("Delete to Start of Word"), SLOT (request_delete_start_word (bool))); _delete_end_word_action = add_action (_edit_cmd_menu, QIcon (), tr ("Delete to End of Word"), SLOT (request_delete_end_word (bool))); _delete_start_line_action = add_action (_edit_cmd_menu, QIcon (), tr ("Delete to Start of Line"), SLOT (request_delete_start_line (bool))); _delete_end_line_action = add_action (_edit_cmd_menu, QIcon (), tr ("Delete to End of Line"), SLOT (request_delete_end_line (bool))); _edit_cmd_menu->addSeparator (); _duplicate_selection_action = add_action (_edit_cmd_menu, QIcon (), tr ("Duplicate Selection/Line"), SLOT (request_duplicate_selection (bool))); _transpose_line_action = add_action (_edit_cmd_menu, QIcon (), tr ("Transpose Line"), SLOT (request_transpose_line (bool))); _edit_cmd_menu->addSeparator (); _completion_action = add_action (_edit_cmd_menu, QIcon (), tr ("&Show Completion List"), SLOT (request_completion (bool))); _edit_fmt_menu = _edit_menu->addMenu (tr ("&Format")); _upper_case_action = add_action (_edit_fmt_menu, QIcon (), tr ("&Uppercase Selection"), SLOT (request_upper_case (bool))); _lower_case_action = add_action (_edit_fmt_menu, QIcon (), tr ("&Lowercase Selection"), SLOT (request_lower_case (bool))); _edit_fmt_menu->addSeparator (); _comment_selection_action = add_action (_edit_fmt_menu, QIcon (), tr ("&Comment"), SLOT (request_comment_selected_text (bool))); _uncomment_selection_action = add_action (_edit_fmt_menu, QIcon (), tr ("&Uncomment"), SLOT (request_uncomment_selected_text (bool))); _edit_fmt_menu->addSeparator (); _indent_selection_action = add_action (_edit_fmt_menu, QIcon (), tr ("&Indent"), SLOT (request_indent_selected_text (bool))); _unindent_selection_action = add_action (_edit_fmt_menu, QIcon (), tr ("&Unindent"), SLOT (request_unindent_selected_text (bool))); _edit_fmt_menu->addSeparator (); _conv_eol_windows_action = add_action (_edit_fmt_menu, QIcon (), tr ("Convert Line Endings to &Windows (CRLF)"), SLOT (request_conv_eol_windows (bool))); _conv_eol_unix_action = add_action (_edit_fmt_menu, QIcon (), tr ("Convert Line Endings to &Unix (LF)"), SLOT (request_conv_eol_unix (bool))); _conv_eol_mac_action = add_action (_edit_fmt_menu, QIcon (), tr ("Convert Line Endings to &Mac (CR)"), SLOT (request_conv_eol_mac (bool))); _edit_nav_menu = _edit_menu->addMenu (tr ("Navi&gation")); _goto_line_action = add_action (_edit_nav_menu, QIcon (), tr ("Go &to Line..."), SLOT (request_goto_line (bool))); _edit_cmd_menu->addSeparator (); _move_to_matching_brace = add_action (_edit_nav_menu, QIcon (), tr ("Move to Matching Brace"), SLOT (request_move_match_brace (bool))); _sel_to_matching_brace = add_action (_edit_nav_menu, QIcon (), tr ("Select to Matching Brace"), SLOT (request_sel_match_brace (bool))); _edit_nav_menu->addSeparator (); _next_bookmark_action = add_action (_edit_nav_menu, QIcon (), tr ("&Next Bookmark"), SLOT (request_next_bookmark (bool))); _previous_bookmark_action = add_action (_edit_nav_menu, QIcon (), tr ("Pre&vious Bookmark"), SLOT (request_previous_bookmark (bool))); _toggle_bookmark_action = add_action (_edit_nav_menu, QIcon (), tr ("Toggle &Bookmark"), SLOT (request_toggle_bookmark (bool))); _remove_bookmark_action = add_action (_edit_nav_menu, QIcon (), tr ("&Remove All Bookmarks"), SLOT (request_remove_bookmark (bool))); _edit_menu->addSeparator (); _preferences_action = add_action (_edit_menu, resource_manager::icon ("preferences-system"), tr ("&Preferences..."), SLOT (request_preferences (bool))); _styles_preferences_action = add_action (_edit_menu, resource_manager::icon ("preferences-system"), tr ("&Styles Preferences..."), SLOT (request_styles_preferences (bool))); // view menu QMenu *view_menu = m_add_menu (_menu_bar, tr ("&View")); _view_editor_menu = view_menu->addMenu (tr ("&Editor")); _show_linenum_action = add_action (_view_editor_menu, QIcon (), tr ("Show &Line Numbers"), SLOT (show_line_numbers (bool))); _show_linenum_action->setCheckable (true); _show_whitespace_action = add_action (_view_editor_menu, QIcon (), tr ("Show &Whitespace Characters"), SLOT (show_white_space (bool))); _show_whitespace_action->setCheckable (true); _show_eol_action = add_action (_view_editor_menu, QIcon (), tr ("Show Line &Endings"), SLOT (show_eol_chars (bool))); _show_eol_action->setCheckable (true); _show_indguide_action = add_action (_view_editor_menu, QIcon (), tr ("Show &Indentation Guides"), SLOT (show_indent_guides (bool))); _show_indguide_action->setCheckable (true); _show_longline_action = add_action (_view_editor_menu, QIcon (), tr ("Show Long Line &Marker"), SLOT (show_long_line (bool))); _show_longline_action->setCheckable (true); _view_editor_menu->addSeparator (); _show_toolbar_action = add_action (_view_editor_menu, QIcon (), tr ("Show &Toolbar"), SLOT (show_toolbar (bool))); _show_toolbar_action->setCheckable (true); _show_statusbar_action = add_action (_view_editor_menu, QIcon (), tr ("Show &Statusbar"), SLOT (show_statusbar (bool))); _show_statusbar_action->setCheckable (true); _show_hscrollbar_action = add_action (_view_editor_menu, QIcon (), tr ("Show &Horizontal Scrollbar"), SLOT (show_hscrollbar (bool))); _show_hscrollbar_action->setCheckable (true); view_menu->addSeparator (); _zoom_in_action = add_action (view_menu, resource_manager::icon ("zoom-in"), tr ("Zoom &In"), SLOT (zoom_in (bool))); _zoom_out_action = add_action (view_menu, resource_manager::icon ("zoom-out"), tr ("Zoom &Out"), SLOT (zoom_out (bool))); _zoom_normal_action = add_action (view_menu, QIcon (), tr ("&Normal Size"), SLOT (zoom_normal (bool))); _menu_bar->addMenu (view_menu); // debug menu _debug_menu = m_add_menu (_menu_bar, tr ("&Debug")); _toggle_breakpoint_action = add_action (_debug_menu, resource_manager::icon ("bp-toggle"), tr ("Toggle &Breakpoint"), SLOT (request_toggle_breakpoint (bool))); _next_breakpoint_action = add_action (_debug_menu, resource_manager::icon ("bp-next"), tr ("&Next Breakpoint"), SLOT (request_next_breakpoint (bool))); _previous_breakpoint_action = add_action (_debug_menu, resource_manager::icon ("bp-prev"), tr ("Pre&vious Breakpoint"), SLOT (request_previous_breakpoint (bool))); _remove_all_breakpoints_action = add_action (_debug_menu, resource_manager::icon ("bp-rm-all"), tr ("&Remove All Breakpoints"), SLOT (request_remove_breakpoint (bool))); _debug_menu->addSeparator (); // The other debug actions will be added by the main window. // run menu QMenu *_run_menu = m_add_menu (_menu_bar, tr ("&Run")); _run_action = add_action (_run_menu, resource_manager::icon ("system-run"), tr ("Save File and Run"), SLOT (request_run_file (bool))); _run_selection_action = add_action (_run_menu, QIcon (), tr ("Run &Selection"), SLOT (request_context_run (bool))); _run_selection_action->setEnabled (false); // help menu QMenu *_help_menu = m_add_menu (_menu_bar, tr ("&Help")); _context_help_action = add_action (_help_menu, QIcon (), tr ("&Help on Keyword"), SLOT (request_context_help (bool))); _context_doc_action = add_action (_help_menu, QIcon (), tr ("&Documentation on Keyword"), SLOT (request_context_doc (bool))); // tab navigation (no menu, only actions) _switch_left_tab_action = add_action (nullptr, QIcon (), "", SLOT (switch_left_tab ())); _switch_right_tab_action = add_action (nullptr, QIcon (), "", SLOT (switch_right_tab ())); _move_tab_left_action = add_action (nullptr, QIcon (), "", SLOT (move_tab_left ())); _move_tab_right_action = add_action (nullptr, QIcon (), "", SLOT (move_tab_right ())); // toolbar // popdown menu with mru files QToolButton *popdown_button = new QToolButton (); popdown_button->setToolTip (tr ("Recent Files")); popdown_button->setMenu (_mru_file_menu); popdown_button->setPopupMode (QToolButton::InstantPopup); popdown_button->setToolButtonStyle (Qt::ToolButtonTextOnly); // new and open actions are inserted later from main window _popdown_mru_action = _tool_bar->addWidget (popdown_button); _tool_bar->addAction (_save_action); _tool_bar->addAction (_save_as_action); _tool_bar->addAction (_print_action); _tool_bar->addSeparator (); // _undo_action: later via main window _tool_bar->addAction (_redo_action); // _copy_action: later via the main window _tool_bar->addAction (_cut_action); // _paste_action: later via the main window _tool_bar->addAction (_find_action); //_tool_bar->addAction (_find_next_action); //_tool_bar->addAction (_find_previous_action); _tool_bar->addSeparator (); _tool_bar->addAction (_run_action); _tool_bar->addSeparator (); _tool_bar->addAction (_toggle_breakpoint_action); _tool_bar->addAction (_previous_breakpoint_action); _tool_bar->addAction (_next_breakpoint_action); _tool_bar->addAction (_remove_all_breakpoints_action); // layout QVBoxLayout *vbox_layout = new QVBoxLayout (); vbox_layout->addWidget (_menu_bar); vbox_layout->addWidget (_tool_bar); vbox_layout->addWidget (_tab_widget); vbox_layout->setMargin (0); editor_widget->setLayout (vbox_layout); setWidget (editor_widget); // create the context menu of the tab bar file_editor_tab_bar *bar = static_cast<file_editor_tab_bar *>(_tab_widget->tabBar ()); QList<QAction *> tab_bar_actions; tab_bar_actions.append (_close_action); tab_bar_actions.append (_close_all_action); tab_bar_actions.append (_close_others_action); bar->create_context_menu (&tab_bar_actions); // signals connect (this, SIGNAL (execute_command_in_terminal_signal (const QString&)), main_win (), SLOT (execute_command_in_terminal (const QString&))); connect (this, SIGNAL (request_settings_dialog (const QString&)), main_win (), SLOT (process_settings_dialog_request (const QString&))); connect (_mru_file_menu, SIGNAL (triggered (QAction *)), this, SLOT (request_mru_open_file (QAction *))); mru_menu_update (); connect (_tab_widget, SIGNAL (tabCloseRequested (int)), this, SLOT (handle_tab_close_request (int))); connect (_tab_widget, SIGNAL (currentChanged (int)), this, SLOT (active_tab_changed (int))); resize (500, 400); setWindowIcon (QIcon (":/actions/icons/logo.png")); set_title (tr ("Editor")); check_actions (); } void file_editor::restore_session (QSettings *settings) { //restore previous session if (! settings->value ("editor/restoreSession", true).toBool ()) return; // get the data from the settings file QStringList sessionFileNames = settings->value ("editor/savedSessionTabs", QStringList ()).toStringList (); QStringList session_encodings = settings->value ("editor/saved_session_encodings", QStringList ()).toStringList (); QStringList session_index = settings->value ("editor/saved_session_tab_index", QStringList ()).toStringList (); // fill a list of the struct and sort it (depending on index) QList<session_data> s_data; bool do_encoding = (session_encodings.count () == sessionFileNames.count ()); bool do_index = (session_index.count () == sessionFileNames.count ()); for (int n = 0; n < sessionFileNames.count (); ++n) { QFileInfo file = QFileInfo (sessionFileNames.at (n)); if (! file.exists ()) continue; session_data item = { QString (), sessionFileNames.at (n), QString ()}; if (do_index) item.index = session_index.at (n); if (do_encoding) item.encoding = session_encodings.at (n); s_data << item; } qSort (s_data); // finally open the file with the desired encoding in the desired order for (int n = 0; n < s_data.count (); ++n) request_open_file (s_data.at (n).file_name, s_data.at (n).encoding); } void file_editor::add_file_editor_tab (file_editor_tab *f, const QString& fn) { _tab_widget->addTab (f, fn); // signals from the qscintilla edit area connect (f->qsci_edit_area (), SIGNAL (status_update (bool, bool)), this, SLOT (edit_status_update (bool, bool))); connect (f->qsci_edit_area (), SIGNAL (show_doc_signal (const QString&)), main_win (), SLOT (handle_show_doc (const QString&))); connect (f->qsci_edit_area (), SIGNAL (create_context_menu_signal (QMenu *)), this, SLOT (create_context_menu (QMenu *))); connect (f->qsci_edit_area (), SIGNAL (execute_command_in_terminal_signal (const QString&)), main_win (), SLOT (execute_command_in_terminal (const QString&))); // Signals from the file editor_tab connect (f, SIGNAL (file_name_changed (const QString&, const QString&)), this, SLOT (handle_file_name_changed (const QString&, const QString&))); connect (f, SIGNAL (editor_state_changed (bool, bool)), this, SLOT (handle_editor_state_changed (bool, bool))); connect (f, SIGNAL (tab_remove_request ()), this, SLOT (handle_tab_remove_request ())); connect (f, SIGNAL (add_filename_to_list (const QString&, const QString&, QWidget*)), this, SLOT (handle_add_filename_to_list (const QString&, const QString&, QWidget*))); connect (f, SIGNAL (editor_check_conflict_save (const QString&, bool)), this, SLOT (check_conflict_save (const QString&, bool))); connect (f, SIGNAL (mru_add_file (const QString&, const QString&)), this, SLOT (handle_mru_add_file (const QString&, const QString&))); connect (f, SIGNAL (run_file_signal (const QFileInfo&)), main_win (), SLOT (run_file_in_terminal (const QFileInfo&))); connect (f, SIGNAL (request_open_file (const QString&)), this, SLOT (request_open_file (const QString&))); connect (f, SIGNAL (edit_mfile_request (const QString&, const QString&, const QString&, int)), main_win (), SLOT (handle_edit_mfile_request (const QString&, const QString&, const QString&, int))); connect (f, SIGNAL (set_focus_editor_signal (QWidget*)), this, SLOT (set_focus (QWidget*))); // Signals from the file_editor non-trivial operations connect (this, SIGNAL (fetab_settings_changed (const QSettings *)), f, SLOT (notice_settings (const QSettings *))); connect (this, SIGNAL (fetab_change_request (const QWidget*)), f, SLOT (change_editor_state (const QWidget*))); connect (this, SIGNAL (fetab_file_name_query (const QWidget*)), f, SLOT (file_name_query (const QWidget*))); connect (this, SIGNAL (fetab_save_file (const QWidget*, const QString&, bool)), f, SLOT (save_file (const QWidget*, const QString&, bool))); connect (this, SIGNAL (fetab_check_modified_file (void)), f, SLOT (check_modified_file (void))); connect (f, SIGNAL (execute_command_in_terminal_signal (const QString&)), main_win (), SLOT (execute_command_in_terminal (const QString&))); // Signals from the file_editor trivial operations connect (this, SIGNAL (fetab_recover_from_exit (void)), f, SLOT (recover_from_exit (void))); connect (this, SIGNAL (fetab_set_directory (const QString&)), f, SLOT (set_current_directory (const QString&))); connect (this, SIGNAL (fetab_zoom_in (const QWidget*)), f, SLOT (zoom_in (const QWidget*))); connect (this, SIGNAL (fetab_zoom_out (const QWidget*)), f, SLOT (zoom_out (const QWidget*))); connect (this, SIGNAL (fetab_zoom_normal (const QWidget*)), f, SLOT (zoom_normal (const QWidget*))); connect (this, SIGNAL (fetab_context_help (const QWidget*, bool)), f, SLOT (context_help (const QWidget*, bool))); connect (this, SIGNAL (fetab_context_edit (const QWidget*)), f, SLOT (context_edit (const QWidget*))); connect (this, SIGNAL (fetab_save_file (const QWidget*)), f, SLOT (save_file (const QWidget*))); connect (this, SIGNAL (fetab_save_file_as (const QWidget*)), f, SLOT (save_file_as (const QWidget*))); connect (this, SIGNAL (fetab_print_file (const QWidget*)), f, SLOT (print_file (const QWidget*))); connect (this, SIGNAL (fetab_run_file (const QWidget*)), f, SLOT (run_file (const QWidget*))); connect (this, SIGNAL (fetab_context_run (const QWidget*)), f, SLOT (context_run (const QWidget*))); connect (this, SIGNAL (fetab_toggle_bookmark (const QWidget*)), f, SLOT (toggle_bookmark (const QWidget*))); connect (this, SIGNAL (fetab_next_bookmark (const QWidget*)), f, SLOT (next_bookmark (const QWidget*))); connect (this, SIGNAL (fetab_previous_bookmark (const QWidget*)), f, SLOT (previous_bookmark (const QWidget*))); connect (this, SIGNAL (fetab_remove_bookmark (const QWidget*)), f, SLOT (remove_bookmark (const QWidget*))); connect (this, SIGNAL (fetab_toggle_breakpoint (const QWidget*)), f, SLOT (toggle_breakpoint (const QWidget*))); connect (this, SIGNAL (fetab_next_breakpoint (const QWidget*)), f, SLOT (next_breakpoint (const QWidget*))); connect (this, SIGNAL (fetab_previous_breakpoint (const QWidget*)), f, SLOT (previous_breakpoint (const QWidget*))); connect (this, SIGNAL (fetab_remove_all_breakpoints (const QWidget*)), f, SLOT (remove_all_breakpoints (const QWidget*))); connect (this, SIGNAL (fetab_scintilla_command (const QWidget *, unsigned int)), f, SLOT (scintilla_command (const QWidget *, unsigned int))); connect (this, SIGNAL (fetab_comment_selected_text (const QWidget*)), f, SLOT (comment_selected_text (const QWidget*))); connect (this, SIGNAL (fetab_uncomment_selected_text (const QWidget*)), f, SLOT (uncomment_selected_text (const QWidget*))); connect (this, SIGNAL (fetab_indent_selected_text (const QWidget*)), f, SLOT (indent_selected_text (const QWidget*))); connect (this, SIGNAL (fetab_unindent_selected_text (const QWidget*)), f, SLOT (unindent_selected_text (const QWidget*))); connect (this, SIGNAL (fetab_convert_eol (const QWidget*, QsciScintilla::EolMode)), f, SLOT (convert_eol (const QWidget*, QsciScintilla::EolMode))); connect (this, SIGNAL (fetab_find (const QWidget*, QList<QAction *>)), f, SLOT (find (const QWidget*, QList<QAction *>))); connect (this, SIGNAL (fetab_find_next (const QWidget*)), f, SLOT (find_next (const QWidget*))); connect (this, SIGNAL (fetab_find_previous (const QWidget*)), f, SLOT (find_previous (const QWidget*))); connect (this, SIGNAL (fetab_goto_line (const QWidget*, int)), f, SLOT (goto_line (const QWidget*, int))); connect (this, SIGNAL (fetab_move_match_brace (const QWidget*, bool)), f, SLOT (move_match_brace (const QWidget*, bool))); connect (this, SIGNAL (fetab_completion (const QWidget*)), f, SLOT (show_auto_completion (const QWidget*))); connect (this, SIGNAL (fetab_set_focus (const QWidget*)), f, SLOT (set_focus (const QWidget*))); connect (this, SIGNAL (fetab_insert_debugger_pointer (const QWidget*, int)), f, SLOT (insert_debugger_pointer (const QWidget*, int))); connect (this, SIGNAL (fetab_delete_debugger_pointer (const QWidget*, int)), f, SLOT (delete_debugger_pointer (const QWidget*, int))); connect (this, SIGNAL (fetab_do_breakpoint_marker (bool, const QWidget*, int, const QString&)), f, SLOT (do_breakpoint_marker (bool, const QWidget*, int, const QString&))); _tab_widget->setCurrentWidget (f); check_actions (); } bool file_editor::editor_tab_has_focus () { QWidget *foc_w = focusWidget (); if (foc_w && foc_w->inherits ("octave_qscintilla")) return true; return false; } void file_editor::set_shortcuts () { // Shortcuts also available in the main window, as well as the realted // ahotcuts, are defined in main_window and added to the editor // File menu shortcut_manager::set_shortcut (_edit_function_action, "editor_file:edit_function"); shortcut_manager::set_shortcut (_save_action, "editor_file:save"); shortcut_manager::set_shortcut (_save_as_action, "editor_file:save_as"); shortcut_manager::set_shortcut (_close_action, "editor_file:close"); shortcut_manager::set_shortcut (_close_all_action, "editor_file:close_all"); shortcut_manager::set_shortcut (_close_others_action, "editor_file:close_other"); shortcut_manager::set_shortcut (_print_action, "editor_file:print"); // Edit menu shortcut_manager::set_shortcut (_redo_action, "editor_edit:redo"); shortcut_manager::set_shortcut (_cut_action, "editor_edit:cut"); shortcut_manager::set_shortcut (_find_action, "editor_edit:find_replace"); shortcut_manager::set_shortcut (_find_next_action, "editor_edit:find_next"); shortcut_manager::set_shortcut (_find_previous_action, "editor_edit:find_previous"); shortcut_manager::set_shortcut (_delete_start_word_action, "editor_edit:delete_start_word"); shortcut_manager::set_shortcut (_delete_end_word_action, "editor_edit:delete_end_word"); shortcut_manager::set_shortcut (_delete_start_line_action, "editor_edit:delete_start_line"); shortcut_manager::set_shortcut (_delete_end_line_action, "editor_edit:delete_end_line"); shortcut_manager::set_shortcut (_delete_line_action, "editor_edit:delete_line"); shortcut_manager::set_shortcut (_copy_line_action, "editor_edit:copy_line"); shortcut_manager::set_shortcut (_cut_line_action, "editor_edit:cut_line"); shortcut_manager::set_shortcut (_duplicate_selection_action, "editor_edit:duplicate_selection"); shortcut_manager::set_shortcut (_transpose_line_action, "editor_edit:transpose_line"); shortcut_manager::set_shortcut (_comment_selection_action, "editor_edit:comment_selection"); shortcut_manager::set_shortcut (_uncomment_selection_action, "editor_edit:uncomment_selection"); shortcut_manager::set_shortcut (_upper_case_action, "editor_edit:upper_case"); shortcut_manager::set_shortcut (_lower_case_action, "editor_edit:lower_case"); shortcut_manager::set_shortcut (_indent_selection_action, "editor_edit:indent_selection"); shortcut_manager::set_shortcut (_unindent_selection_action, "editor_edit:unindent_selection"); shortcut_manager::set_shortcut (_completion_action, "editor_edit:completion_list"); shortcut_manager::set_shortcut (_goto_line_action, "editor_edit:goto_line"); shortcut_manager::set_shortcut (_move_to_matching_brace, "editor_edit:move_to_brace"); shortcut_manager::set_shortcut (_sel_to_matching_brace, "editor_edit:select_to_brace"); shortcut_manager::set_shortcut (_toggle_bookmark_action, "editor_edit:toggle_bookmark"); shortcut_manager::set_shortcut (_next_bookmark_action, "editor_edit:next_bookmark"); shortcut_manager::set_shortcut (_previous_bookmark_action, "editor_edit:previous_bookmark"); shortcut_manager::set_shortcut (_remove_bookmark_action, "editor_edit:remove_bookmark"); shortcut_manager::set_shortcut (_preferences_action, "editor_edit:preferences"); shortcut_manager::set_shortcut (_styles_preferences_action, "editor_edit:styles_preferences"); shortcut_manager::set_shortcut (_conv_eol_windows_action, "editor_edit:conv_eol_winows"); shortcut_manager::set_shortcut (_conv_eol_unix_action, "editor_edit:conv_eol_unix"); shortcut_manager::set_shortcut (_conv_eol_mac_action, "editor_edit:conv_eol_mac"); // View menu shortcut_manager::set_shortcut (_show_linenum_action, "editor_view:show_line_numbers"); shortcut_manager::set_shortcut (_show_whitespace_action, "editor_view:show_white_spaces"); shortcut_manager::set_shortcut (_show_eol_action, "editor_view:show_eol_chars"); shortcut_manager::set_shortcut (_show_indguide_action, "editor_view:show_ind_guides"); shortcut_manager::set_shortcut (_show_longline_action, "editor_view:show_long_line"); shortcut_manager::set_shortcut (_show_toolbar_action, "editor_view:show_toolbar"); shortcut_manager::set_shortcut (_show_statusbar_action, "editor_view:show_statusbar"); shortcut_manager::set_shortcut (_show_hscrollbar_action, "editor_view:show_hscrollbar"); shortcut_manager::set_shortcut (_zoom_in_action, "editor_view:zoom_in"); shortcut_manager::set_shortcut (_zoom_out_action, "editor_view:zoom_out"); shortcut_manager::set_shortcut (_zoom_normal_action, "editor_view:zoom_normal"); // Debug menu shortcut_manager::set_shortcut (_toggle_breakpoint_action, "editor_debug:toggle_breakpoint"); shortcut_manager::set_shortcut (_next_breakpoint_action, "editor_debug:next_breakpoint"); shortcut_manager::set_shortcut (_previous_breakpoint_action, "editor_debug:previous_breakpoint"); shortcut_manager::set_shortcut (_remove_all_breakpoints_action, "editor_debug:remove_breakpoints"); // Run menu shortcut_manager::set_shortcut (_run_action, "editor_run:run_file"); shortcut_manager::set_shortcut (_run_selection_action, "editor_run:run_selection"); // Help menu shortcut_manager::set_shortcut (_context_help_action, "editor_help:help_keyword"); shortcut_manager::set_shortcut (_context_doc_action, "editor_help:doc_keyword"); // Tab navigation without menu entries shortcut_manager::set_shortcut (_switch_left_tab_action, "editor_tabs:switch_left_tab"); shortcut_manager::set_shortcut (_switch_right_tab_action, "editor_tabs:switch_right_tab"); shortcut_manager::set_shortcut (_move_tab_left_action, "editor_tabs:move_tab_left"); shortcut_manager::set_shortcut (_move_tab_right_action, "editor_tabs:move_tab_right"); } void file_editor::check_actions () { bool have_tabs = _tab_widget->count () > 0; _edit_cmd_menu->setEnabled (have_tabs); _edit_fmt_menu->setEnabled (have_tabs); _edit_nav_menu->setEnabled (have_tabs); _comment_selection_action->setEnabled (have_tabs); _uncomment_selection_action->setEnabled (have_tabs); _indent_selection_action->setEnabled (have_tabs); _unindent_selection_action->setEnabled (have_tabs); _context_help_action->setEnabled (have_tabs); _context_doc_action->setEnabled (have_tabs); _view_editor_menu->setEnabled (have_tabs); _zoom_in_action->setEnabled (have_tabs); _zoom_out_action->setEnabled (have_tabs); _zoom_normal_action->setEnabled (have_tabs); _find_action->setEnabled (have_tabs); _find_next_action->setEnabled (have_tabs); _find_previous_action->setEnabled (have_tabs); _print_action->setEnabled (have_tabs); _run_action->setEnabled (have_tabs); _edit_function_action->setEnabled (have_tabs); _save_action->setEnabled (have_tabs); _save_as_action->setEnabled (have_tabs); _close_action->setEnabled (have_tabs); _close_all_action->setEnabled (have_tabs); _close_others_action->setEnabled (have_tabs && _tab_widget->count () > 1); } // empty_script determines whether we have to create an empty script // 1. At startup, when the editor has to be (really) visible // (Here we can not use the visibility changed signal) // 2. When the editor becomes visible when octave is running void file_editor::empty_script (bool startup, bool visible) { QSettings *settings = resource_manager::get_settings (); if (settings->value ("useCustomFileEditor",false).toBool ()) return; // do not open an empty script in the external editor bool real_visible; if (startup) real_visible = isVisible (); else real_visible = visible; if (! real_visible || _tab_widget->count () > 0) return; if (startup && ! isFloating ()) { // check is editor is really visible or hidden between tabbed widgets QList<QTabBar *> tab_list = main_win ()->findChildren<QTabBar *>(); bool in_tab = false; int i = 0; while ((i < tab_list.count ()) && (! in_tab)) { QTabBar *tab = tab_list.at (i); i++; int j = 0; while ((j < tab->count ()) && (! in_tab)) { // check all tabs for the editor if (tab->tabText (j) == windowTitle ()) { // editor is in this tab widget in_tab = true; int top = tab->currentIndex (); if (top > -1 && tab->tabText (top) == windowTitle ()) real_visible = true; // and is the current tab else return; // not current tab -> not visible } j++; } } } request_new_file (""); } // This slot is a reimplementation of the virtual slot in octave_dock_widget. // We need this for creating an empty script when the editor has no open files // and is made visible void file_editor::handle_visibility (bool visible) { if (_closed && visible) { _closed = false; QSettings *settings = resource_manager::get_settings (); restore_session (settings); } empty_script (false, visible); if (visible && ! isFloating ()) focus (); } void file_editor::dragEnterEvent (QDragEnterEvent *e) { if (e->mimeData ()->hasUrls ()) { e->acceptProposedAction (); } } void file_editor::dropEvent (QDropEvent *e) { if (e->mimeData ()->hasUrls ()) { foreach (QUrl url, e->mimeData ()->urls ()) request_open_file (url.toLocalFile ()); } } // handler for the close event void file_editor::closeEvent (QCloseEvent *e) { QSettings *settings = resource_manager::get_settings (); if (settings->value ("editor/hiding_closes_files",false).toBool ()) { if (check_closing ()) { // all tabs are closed without cancelling, // store closing state for restoring session when shown again _closed = true; e->accept (); } else e->ignore (); } else e->accept (); } // slots for tab navigation void file_editor::switch_left_tab () { switch_tab (-1); } void file_editor::switch_right_tab () { switch_tab (1); } void file_editor::move_tab_left () { #if defined (HAVE_QTABWIDGET_SETMOVABLE) switch_tab (-1, true); #endif } void file_editor::move_tab_right () { #if defined (HAVE_QTABWIDGET_SETMOVABLE) switch_tab (1, true); #endif } void file_editor::switch_tab (int direction, bool movetab) { int tabs = _tab_widget->count (); if (tabs < 2) return; int old_pos = _tab_widget->currentIndex (); int new_pos = _tab_widget->currentIndex () + direction; if (new_pos < 0 || new_pos >= tabs) new_pos = new_pos - direction*tabs; if (movetab) { #if defined (HAVE_QTABWIDGET_SETMOVABLE) _tab_widget->tabBar ()->moveTab (old_pos, new_pos); _tab_widget->setCurrentIndex (old_pos); _tab_widget->setCurrentIndex (new_pos); focus (); #endif } else _tab_widget->setCurrentIndex (new_pos); } // // Functions of the the reimplemented tab bar // file_editor_tab_bar::file_editor_tab_bar (QWidget *p) : QTabBar (p) { _context_menu = new QMenu (this); } file_editor_tab_bar::~file_editor_tab_bar () { delete _context_menu; } // Create the context menu and fill it with actions from the editor void file_editor_tab_bar::create_context_menu (QList<QAction*> *actions) { for (int i = 0; i < actions->count (); i++) _context_menu->addAction (actions->at (i)); } // Reimplement mouse event for filtering out the desired mouse clicks void file_editor_tab_bar::mousePressEvent (QMouseEvent *me) { QPoint click_pos; int clicked_idx = -1; // detect the tab where the click occured for (int i = 0; i < count (); i++) { click_pos = mapToGlobal (me->pos ()); if (tabRect (i).contains (mapFromGlobal (click_pos))) { clicked_idx = i; break; } } // If a tab was clicked if (clicked_idx >= 0) { int current_idx = currentIndex (); // detect the mouse click if ((me->type () == QEvent::MouseButtonDblClick && me->button() == Qt::LeftButton) || (me->type () != QEvent::MouseButtonDblClick && me->button() == Qt::MidButton)) { // Middle click or double click -> close the tab // Make the clicked tab the current one and close it setCurrentIndex (clicked_idx); emit close_current_tab_signal (true); // Was the closed tab before or after the previously current tab? // According to the result, use previous index or reduce it by one if (current_idx - clicked_idx > 0) setCurrentIndex (current_idx - 1); else if (current_idx - clicked_idx < 0) setCurrentIndex (current_idx); } else if (me->type () != QEvent::MouseButtonDblClick && me->button() == Qt::RightButton) { // Right click, show context menu setCurrentIndex (clicked_idx); if (! _context_menu->exec (click_pos)) { // No action selected, back to previous tab setCurrentIndex (current_idx); } else { // Was the possibly only closed tab before or after the // previously current tab? According to the result, use previous // index or reduce it by one. Also prevent using a too large // if other or all files were closed. int new_idx = count () - 1; if (new_idx > 0) { if (current_idx - clicked_idx > 0) new_idx = current_idx - 1; else if (current_idx - clicked_idx < 0) new_idx = current_idx; } if (new_idx >= 0) setCurrentIndex (new_idx); } } else { // regular handling of the mouse event QTabBar::mousePressEvent (me); } } else { // regular handling of the mouse event QTabBar::mousePressEvent (me); } } // // Functions of the the reimplemented tab widget // file_editor_tab_widget::file_editor_tab_widget (QWidget *p) : QTabWidget (p) { file_editor_tab_bar *bar; bar = new file_editor_tab_bar (this); connect (bar, SIGNAL (close_current_tab_signal (bool)), p->parent (), SLOT (request_close_file (bool))); this->setTabBar(bar); } file_editor_tab_widget::~file_editor_tab_widget () { } QTabBar* file_editor_tab_widget::tabBar () const { return (QTabWidget::tabBar ()); } #endif