Mercurial > hg > octave-jordi
view libgui/src/m-editor/file-editor.cc @ 20994:aab7a3c7168e
edit a file from an error message in the terminal (bug #35619)
* QTerminal.cc (handleCustomContextMenuRequested): move slot for the context
menu from header file, detect an error location by regular expressions;
(edit_file): slot context menu entry for editing a file in an error message
* QTerminal.h: new signal for editing a file from an error message,
slot handleCustomContextMenuRequested moved into QTerminal.cc, new edit
action in the context menu, new slot for context menu entry, connect
new edit signal to related slot in the main window
* file-editor-tab.cc (handle_context_menu_edit): only keep searching for an
embedded function, move the rest of the search into the editor, called
via a new signal;
(goto_line): center the new line in all cases
* file-editor-tab.h: new signal for editing an m-file
* file-editor.cc (handle_edit_mfile_request): partly moved from file-editor-tab;
(construct): connect new signals from file-editor-tab and from main window
to the new slot for searching and editing an m-file
* file-editor.h: new slot for searching and editing an m-file
* main-window.cc (edit_mfile): new slot for editing an m-file, just emitting
the signal for the editor
* main-window.h: new slot and new signal for editing an m-file
author | Torsten <ttl@justmail.de> |
---|---|
date | Mon, 28 Dec 2015 16:44:10 +0100 |
parents | 73e92fca3c78 |
children | 1c91ff4cf9ec |
line wrap: on
line source
/* Copyright (C) 2011-2015 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/>. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #ifdef HAVE_QSCINTILLA #include "file-editor.h" #include "resource-manager.h" #include "shortcut-manager.h" #include <QVBoxLayout> #include <QApplication> #include <QFile> #include <QFont> #include <QFileDialog> #include <QMessageBox> #include <QStyle> #include <QTextStream> #include <QTabBar> #include <QProcess> #include <QInputDialog> #include <Qsci/qscicommandset.h> #include "octave-link.h" #include "utils.h" #include "main-window.h" #include <oct-map.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 = 0; _copy_action = 0; _paste_action = 0; _selectall_action = 0; construct (); setVisible (false); setAcceptDrops(true); _file_encoding = QString (); // for selecting an encoding in open dialog } file_editor::~file_editor (void) { if (_mru_file_menu) delete _mru_file_menu; } bool file_editor::check_closing (void) { // Save open files for restoring in next session; this only is possible QSettings *settings = resource_manager::get_settings (); // Have all file editor tabs signal what their filenames are. editor_tab_map.clear (); emit fetab_file_name_query (0); // 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; // over all open tabs 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 (); // Save all tabs with confirmation. file_editor_tab::reset_cancel (); emit fetab_check_modified_file (); // Close all tabs if there was no cancellation. if (file_editor_tab::was_cancelled ()) return false; for (int i = 0; i < _tab_widget->count (); i++) { delete _tab_widget->widget (i); _tab_widget->removeTab (i); } return true; } void file_editor::focus (void) { octave_dock_widget::focus (); // set focus to current tab QWidget *fileEditorTab = _tab_widget->currentWidget (); if (fileEditorTab) emit fetab_set_focus (fileEditorTab); } 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 } } void file_editor::request_new_script (const QString& commands) { request_new_file (commands); } void file_editor::request_new_function (bool) { bool ok; // get the name of the new function QString new_name = QInputDialog::getText (this, tr ("New Function"), tr ("New function name:\n"), QLineEdit::Normal, "", &ok); if (ok && new_name.length () > 0) { // append suffix if it not already exists if (new_name.rightRef (2) != ".m") new_name.append (".m"); // check whether new files are created without prompt QSettings *settings = resource_manager::get_settings (); if (! settings->value ("editor/create_new_file",false).toBool ()) { // no, so enable this settings and wait for end of new file loading settings->setValue ("editor/create_new_file",true); connect (this, SIGNAL (file_loaded_signal ()), this, SLOT (restore_create_file_setting ())); } // start the edit command emit execute_command_in_terminal_signal ("edit " + new_name); } } void file_editor::restore_create_file_setting () { // restore the new files creation setting QSettings *settings = resource_manager::get_settings (); settings->setValue ("editor/create_new_file",false); disconnect (this, SIGNAL (file_loaded_signal ()), this, SLOT (restore_create_file_setting ())); } void file_editor::request_open_file (void) { // Open 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. // Create a NonModal message. QFileDialog *fileDialog = new QFileDialog (this); fileDialog->setNameFilter (tr ("Octave Files (*.m);;All Files (*)")); // Giving trouble under KDE (problem is related to Qt signal handling on unix, // see https://bugs.kde.org/show_bug.cgi?id=260719 , // it had/has no effect on Windows, though) fileDialog->setOption(QFileDialog::DontUseNativeDialog, true); // define a new grid layout with the extra elements QGridLayout *extra = new QGridLayout (fileDialog); QFrame *separator = new QFrame (fileDialog); separator->setFrameShape (QFrame::HLine); // horizontal line as separator separator->setFrameStyle (QFrame::Sunken); // combo box for encoding QLabel *label_enc = new QLabel (tr ("File Encoding:")); QComboBox *combo_enc = new QComboBox (); resource_manager::combo_encoding (combo_enc); _file_encoding = QString (); // default, no special encoding // track changes in the combo boxes connect (combo_enc, SIGNAL (currentIndexChanged (QString)), this, SLOT (handle_combo_enc_current_index (QString))); // build the extra grid layout extra->addWidget (separator,0,0,1,3); extra->addWidget (label_enc,1,0); extra->addWidget (combo_enc,1,1); extra->addItem (new QSpacerItem (1,20,QSizePolicy::Expanding, QSizePolicy::Fixed), 1,2); // and add the extra grid layout to the dialog's layout QGridLayout *dialog_layout = dynamic_cast<QGridLayout*> (fileDialog->layout ()); dialog_layout->addLayout (extra,dialog_layout->rowCount (),0, 1,dialog_layout->columnCount ()); fileDialog->setAcceptMode (QFileDialog::AcceptOpen); fileDialog->setViewMode (QFileDialog::Detail); fileDialog->setFileMode (QFileDialog::ExistingFiles); fileDialog->setDirectory (ced); connect (fileDialog, SIGNAL (filesSelected (const QStringList&)), this, SLOT (request_open_files (const QStringList&))); fileDialog->setWindowModality (Qt::NonModal); fileDialog->setAttribute (Qt::WA_DeleteOnClose); fileDialog->show (); } void file_editor::handle_combo_enc_current_index (QString new_encoding) { _file_encoding = new_encoding; } // Check whether this file is already open in the editor. QWidget * file_editor::find_tab_widget (const QString& file) const { QWidget *retval = 0; 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 ())) { 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 ()) { if (line > -1) // check for a specific line (debugging) return true; // yes: do ont open a file in external editor QString editor = settings->value ("customFileEditor").toString (); editor.replace ("%f", file_name); editor.replace ("%l", QString::number (line)); bool started_ok = QProcess::startDetached (editor); if (started_ok != true) { QMessageBox *msgBox = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), tr ("Could not start custom file editor\n%1"). arg (editor), QMessageBox::Ok, this); msgBox->setWindowModality (Qt::NonModal); msgBox->setAttribute (Qt::WA_DeleteOnClose); msgBox->show (); } 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; } // The following slot is called after files have been selected in the // open file dialog, possibly with a new selected encoding stored in // _file_encoding void file_editor::request_open_files (const QStringList& open_file_names) { for (int i = 0; i < open_file_names.count (); i++) request_open_file (open_file_names.at (i), _file_encoding); } void file_editor::request_open_file (const QString& openFileName, const QString& encoding, int line, bool debug_pointer, bool breakpoint_marker, bool insert) { 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 { // Have all file editor tabs signal what their filenames are. editor_tab_map.clear (); emit fetab_file_name_query (0); // 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); } if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ())) { emit fetab_set_focus (tab); focus (); } } else { file_editor_tab *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. 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); } } 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,0); 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) { // Have all file editor tabs signal what their filenames are. editor_tab_map.clear (); emit fetab_file_name_query (0); // 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, 0); msgBox->setWindowModality (Qt::NonModal); msgBox->setAttribute (Qt::WA_DeleteOnClose); msgBox->show (); return; } QObject *saveFileObject = sender (); QWidget *saveFileWidget = 0; 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, 0); 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_edit_mfile_request (const QString& fname, const QString& ffile, const QString& curr_dir, int line) { // Is it a regular function within the search path? (Call __which__) octave_value_list fct = F__which__ (ovl (fname.toStdString ()),0); octave_map map = fct(0).map_value (); QString type = QString::fromStdString ( map.contents ("type").data ()[0].string_value ()); QString name = QString::fromStdString ( map.contents ("name").data ()[0].string_value ()); QString message = QString (); QString filename = QString (); if (type == QString("built-in function")) { // built in function: can't edit message = tr ("%1 is a built-in function"); } else if (type.isEmpty ()) { // function not known to octave -> try directory of edited file // get directory QDir dir; if (ffile.isEmpty ()) { if (curr_dir.isEmpty ()) dir = QDir (ced); else dir = QDir (curr_dir); } else dir = QDir (QFileInfo (ffile).canonicalPath ()); // function not known to octave -> try directory of edited file QFileInfo file = QFileInfo (dir, fname + ".m"); if (file.exists ()) { filename = file.canonicalFilePath (); // local file exists } else { // local file does not exist -> try private directory file = QFileInfo (ffile); file = QFileInfo (QDir (file.canonicalPath () + "/private"), fname + ".m"); if (file.exists ()) { filename = file.canonicalFilePath (); // private function exists } else { message = tr ("Can not find function %1"); // no file found } } } if (! message.isEmpty ()) { QMessageBox *msgBox = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"), message.arg (name), QMessageBox::Ok, this); msgBox->setWindowModality (Qt::NonModal); msgBox->setAttribute (Qt::WA_DeleteOnClose); msgBox->show (); return; } if ( filename.isEmpty ()) filename = QString::fromStdString ( map.contents ("file").data ()[0].string_value ()); if (! filename.endsWith (".m")) filename.append (".m"); request_open_file (filename, QString (), line); // default encoding } 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 ()) { // Have all file editor tabs signal what their filenames are. editor_tab_map.clear (); emit fetab_file_name_query (0); // 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) { request_open_file (file, QString (), line, false, true, insert); } void file_editor::handle_edit_file_request (const QString& file) { request_open_file (file); } 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 ()); } 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 ()); } 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::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); 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); _undo_action->setEnabled (false); // copy _copy_action = shared_actions.at (COPY_ACTION); _tool_bar->insertAction (_cut_action,_copy_action); _edit_menu->insertAction (_cut_action,_copy_action); _copy_action->setEnabled (false); // 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); _paste_action->setEnabled (false); // 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 tab_widget (editor_widget); _tab_widget->setTabsClosable (true); #ifdef 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))); _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 (); _previous_bookmark_action = add_action (_edit_nav_menu, QIcon (), tr ("Pre&vious Bookmark"), SLOT (request_previous_bookmark (bool))); _next_bookmark_action = add_action (_edit_nav_menu, QIcon (), tr ("&Next Bookmark"), SLOT (request_next_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); _show_toolbar_action = add_action (_view_editor_menu, QIcon (), tr ("Show &Toolbar"), SLOT (show_toolbar (bool))); _show_toolbar_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 (0, QIcon (), "", SLOT (switch_left_tab ())); _switch_right_tab_action = add_action (0, QIcon (), "", SLOT (switch_right_tab ())); _move_tab_left_action = add_action (0, QIcon (), "", SLOT (move_tab_left ())); _move_tab_right_action = add_action (0, 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->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); // signals connect (this, SIGNAL (request_settings_dialog (const QString&)), main_win (), SLOT (process_settings_dialog_request (const QString&))); connect (main_win (), SIGNAL (new_file_signal (const QString&)), this, SLOT (request_new_file (const QString&))); connect (main_win (), SIGNAL (open_file_signal (const QString&)), this, SLOT (request_open_file (const QString&))); connect (main_win (), SIGNAL (edit_mfile_request (const QString&, const QString&, const QString&, int)), this, SLOT (handle_edit_mfile_request (const QString&, const QString&, const QString&, int))); 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))); connect (this, SIGNAL (execute_command_in_terminal_signal (const QString&)), main_win (), SLOT (execute_command_in_terminal (const QString&))); resize (500, 400); setWindowIcon (QIcon (":/actions/icons/logo.png")); set_title (tr ("Editor")); restore_session (settings); 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)), this, SLOT (edit_mfile_request (const QString&, const QString&, const QString&, int))); // 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))); // Signals from the file_editor trivial operations 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*)), f, SLOT (find (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)), f, SLOT (do_breakpoint_marker (bool, const QWidget*, int))); _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 (_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 (_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); _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) { 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 ()); } } } // 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 () { #ifdef HAVE_QTABWIDGET_SETMOVABLE switch_tab (-1, true); #endif } void file_editor::move_tab_right () { #ifdef 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) { #ifdef 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); } #endif