# HG changeset patch
# User Torsten <mttl@mailbox.org>
# Date 1491890423 -7200
#      Tue Apr 11 08:00:23 2017 +0200
# Node ID 4e981842222fa711c7e034a14d4cd9f265811ee3
# Parent  c319e6d737f266fc1a0bd5e654eb6a58b9448d73
improve opening files from gui when built without qscintilla (bug #39179)

* external-editor-interface.cc/h: new class with an interface for an external
  editor, which is used by preference or if qscintilla is not available;
  (external_editor_interface): ctor, connect a signal for opening the settings;
  (external_editor): check for an external editor being set in the settings;
  (call_custom_editor): call the custom editor;
  (request_open_file, request_open_file, handle_edit_file_request):
  slots for the various ways for opening a file

* file-editor-interface.h: moved request_new_function and
  removed request_open_file into the main window

* file-editor.cc: include external-editor-interface.h;
  (file_editor): file encoding tracked in main window;
  (request_new_function): moved into main window;
  (request_open_file (void)): moved to main window;
  (request_open_files): moved to main window;
  (handle_combo_enc_current_index): moved to main window;
  (restore_create_file_setting): moved into main window;
  (request_new_script): moved into main window;
  (restore_create_file_setting): moved into main window;
  (call_custom_editor): use external_editor_interface;
  (handle_edit_mfile_request): moved into main window;
  (construct): moved some signal connection into the main window;
  (add_file_editor_tab): update signal connection to moved slots;

* file-editor.h: moved request_new_function, handle_edit_mfile_request,
  request_open_file (void), request_open_files, handle_combo_enc_current_index,
  and class variable _file_encodinginto the main window;

* main-window.cc (main_window): initialize _file_encoding to empty string,
  set external editor interface and store active editor for connecting signals;
  (~main_window): delete external_editor_interface;
  (edit_mfile): directly use slot handle_edit_mfile_request moved here;
  (handle_edit_mfile_request): moved from editor to here;
  (request_new_function): moved from editor to here;
  (request_open_file): moved from file editor to here;
  (set_file_encoding): moved from file editor to here, old name was
  handle_combo_enc_current_index;
  (request_open_files): moved from file editor to here;
  (restore_create_file_setting): moved from editor to here;
  (construct_octave_qt_link): connect signals to slots in editor or external
  editor interface;
  (construct_file_menu): connect signals to slots in editor or external
  editor interface, slot for opening files now in main window
  (construct_new_menu): connect signals to slots in editor, external
  editor interface, or to slots moved here;

* main-window.h: update signals according to moved slots, namely
  request_new_function, request_new_script, handle_edit_mfile_request,
  restore_create_file_setting, moved request_open_file, set_file_encoding,
  request_open_files, and class variable _file_encoding to here

* module.mk: added new files external-editor-interface.cc/h

diff -r c319e6d737f2 -r 4e981842222f libgui/src/external-editor-interface.cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/external-editor-interface.cc	Tue Apr 11 08:00:23 2017 +0200
@@ -0,0 +1,119 @@
+/*
+
+Copyright (C) 2017 Torsten
+
+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
+
+#include <QSettings>
+#include <QMessageBox>
+#include <QProcess>
+
+#include "external-editor-interface.h"
+#include "resource-manager.h"
+
+external_editor_interface::external_editor_interface (QWidget *p)
+    : QWidget (p)
+{ };
+
+// Get and verify the settings of the external editor program
+QString
+external_editor_interface::external_editor ()
+{
+  QSettings *settings = resource_manager::get_settings ();
+  QString editor = settings->value ("customFileEditor").toString ();
+
+  // check the settings (avoid an empty string)
+  if (editor.trimmed ().isEmpty ())
+    {
+      QMessageBox *msgBox = new QMessageBox (QMessageBox::Warning,
+                              tr ("Octave Editor"),
+                              tr ("There is no custom editor configured yet.\n"
+                                  "Do you want to open the preferences?"),
+                              QMessageBox::No | QMessageBox::Yes);
+      msgBox->setDefaultButton (QMessageBox::Yes);
+      msgBox->setAttribute (Qt::WA_DeleteOnClose);
+      int button = msgBox->exec ();
+
+      if (button == QMessageBox::Yes)
+        emit request_settings_dialog ("editor");
+    }
+
+  return editor;
+}
+
+// Calling the external editor
+bool
+external_editor_interface::call_custom_editor (const QString& file, int line)
+{
+  if (line > -1)  // check for a specific line (debugging)
+    return true;  // yes: do not open a file in external editor
+
+  QString editor = external_editor ();
+  if (editor.isEmpty ())
+    return true;
+
+  // replace macros
+  editor.replace ("%f", file);
+  editor.replace ("%l", QString::number (line));
+
+  // start the process and check for success
+  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);
+
+      msgBox->setWindowModality (Qt::NonModal);
+      msgBox->setAttribute (Qt::WA_DeleteOnClose);
+      msgBox->show ();
+    }
+
+  return started_ok;
+}
+
+
+// Slots for the several signals for invoking the editor
+
+void
+external_editor_interface::request_new_file (const QString&)
+{
+  call_custom_editor ();
+}
+
+void
+external_editor_interface::request_open_file (const QString& file_name,
+                const QString&, int line, bool, bool, bool, const QString&)
+{
+  call_custom_editor (file_name, line);
+}
+
+void
+external_editor_interface::handle_edit_file_request (const QString& file)
+{
+  call_custom_editor (file);
+}
+
diff -r c319e6d737f2 -r 4e981842222f libgui/src/external-editor-interface.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/external-editor-interface.h	Tue Apr 11 08:00:23 2017 +0200
@@ -0,0 +1,61 @@
+/*
+
+Copyright (C) 2017 Torsten
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU Genera*_*)
+* l 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 (octave_external_editor_interface_h)
+#define octave_external_editor_interface_h 1
+
+#include <QWidget>
+#include <QString>
+
+class external_editor_interface : public QWidget
+{
+
+  Q_OBJECT
+
+public:
+
+  external_editor_interface (QWidget *main_win);
+  ~external_editor_interface () { };
+
+signals:
+
+  void request_settings_dialog (const QString&);
+
+public slots:
+
+  bool call_custom_editor (const QString& file = QString (), int line = -1);
+  void request_open_file (const QString& fileName,
+                          const QString& encoding = QString (),
+                          int line = -1, bool debug_pointer = false,
+                          bool breakpoint_marker = false, bool insert = true,
+                          const QString& cond = "");
+  void request_new_file (const QString&);
+  void handle_edit_file_request (const QString& file);
+
+private:
+
+  QString external_editor ();
+
+};
+
+#endif
diff -r c319e6d737f2 -r 4e981842222f libgui/src/m-editor/file-editor-interface.h
--- a/libgui/src/m-editor/file-editor-interface.h	Mon Apr 10 07:02:42 2017 +0200
+++ b/libgui/src/m-editor/file-editor-interface.h	Tue Apr 11 08:00:23 2017 +0200
@@ -68,9 +68,6 @@ public:
 
 public slots:
   virtual void request_new_file (const QString& command = QString ()) = 0;
-  virtual void request_new_script (const QString& command = QString ()) = 0;
-  virtual void request_new_function (bool) = 0;
-  virtual void request_open_file () = 0;
   virtual void request_open_file (const QString& openFileName,
                                   const QString& encoding = QString (),
                                   int line = -1,
diff -r c319e6d737f2 -r 4e981842222f libgui/src/m-editor/file-editor.cc
--- a/libgui/src/m-editor/file-editor.cc	Mon Apr 10 07:02:42 2017 +0200
+++ b/libgui/src/m-editor/file-editor.cc	Tue Apr 11 08:00:23 2017 +0200
@@ -34,7 +34,6 @@ along with Octave; see the file COPYING.
 #include <QFile>
 #include <QFileDialog>
 #include <QFont>
-#include <QInputDialog>
 #include <QMessageBox>
 #include <QMimeData>
 #include <QProcess>
@@ -72,8 +71,6 @@ file_editor::file_editor (QWidget *p)
 
   setVisible (false);
   setAcceptDrops (true);
-
-  _file_encoding = QString ();  // for selecting an encoding in open dialog
 }
 
 file_editor::~file_editor (void)
@@ -228,111 +225,6 @@ file_editor::request_new_file (const QSt
     }
 }
 
-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
@@ -363,28 +255,8 @@ file_editor::call_custom_editor (const Q
 
   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 ();
-        }
+      // 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 (),
@@ -413,16 +285,6 @@ file_editor::is_editor_console_tabbed ()
   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);
-}
-
 // Open a file, if not already open, and mark the current execution location
 // and/or a breakpoint with condition cond.
 void
@@ -678,92 +540,6 @@ file_editor::check_conflict_save (const 
 }
 
 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)
 {
@@ -1908,17 +1684,6 @@ file_editor::construct (void)
            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 *)));
 
@@ -2032,7 +1797,7 @@ file_editor::add_file_editor_tab (file_e
 
   connect (f, SIGNAL (edit_mfile_request (const QString&, const QString&,
                                           const QString&, int)),
-           this, SLOT (handle_edit_mfile_request (const QString&,
+           main_win (), SLOT (handle_edit_mfile_request (const QString&,
                                                   const QString&,
                                                   const QString&, int)));
 
diff -r c319e6d737f2 -r 4e981842222f libgui/src/m-editor/file-editor.h
--- a/libgui/src/m-editor/file-editor.h	Mon Apr 10 07:02:42 2017 +0200
+++ b/libgui/src/m-editor/file-editor.h	Tue Apr 11 08:00:23 2017 +0200
@@ -195,6 +195,7 @@ signals:
 
   void request_settings_dialog (const QString&);
   void execute_command_in_terminal_signal (const QString&);
+  void request_open_file_external (const QString& file_name, int line);
   void file_loaded_signal ();
 
 public slots:
@@ -205,9 +206,6 @@ public slots:
   bool check_closing (void);
 
   void request_new_file (const QString& commands);
-  void request_new_script (const QString& commands);
-  void request_new_function (bool triggered = true);
-  void request_open_file (void);
   void request_close_file (bool);
   void request_close_all_files (bool);
   void request_close_other_files (bool);
@@ -279,8 +277,6 @@ public slots:
   void handle_update_breakpoint_marker_request (bool insert,
                                                 const QString& file, int line,
                                                 const QString& cond);
-  void handle_edit_mfile_request (const QString& name, const QString& file,
-                                  const QString& curr_dir, int line);
 
   void handle_edit_file_request (const QString& file);
 
@@ -302,7 +298,6 @@ protected slots:
 
 private slots:
 
-  void request_open_files (const QStringList&);
   void request_open_file (const QString& fileName,
                           const QString& encoding = QString (),
                           int line = -1, bool debug_pointer = false,
@@ -310,9 +305,6 @@ private slots:
                           const QString& cond = "");
   void request_preferences (bool);
   void request_styles_preferences (bool);
-  void restore_create_file_setting ();
-
-  void handle_combo_enc_current_index (QString new_encoding);
 
   void show_line_numbers (bool);
   void show_white_space (bool);
@@ -472,8 +464,6 @@ private:
 
   bool _closed;
 
-  QString _file_encoding;
-
   enum { MaxMRUFiles = 10 };
   QMenu *_mru_file_menu;
   QAction *_mru_file_actions[MaxMRUFiles];
diff -r c319e6d737f2 -r 4e981842222f libgui/src/main-window.cc
--- a/libgui/src/main-window.cc	Mon Apr 10 07:02:42 2017 +0200
+++ b/libgui/src/main-window.cc	Tue Apr 11 08:00:23 2017 +0200
@@ -27,6 +27,7 @@ along with Octave; see the file COPYING.
 
 #include <QKeySequence>
 #include <QApplication>
+#include <QInputDialog>
 #include <QLabel>
 #include <QMenuBar>
 #include <QMenu>
@@ -64,6 +65,7 @@ along with Octave; see the file COPYING.
 #include "symtab.h"
 #include "version.h"
 #include "utils.h"
+#include <oct-map.h>
 
 static file_editor_interface *
 create_default_editor (QWidget *p)
@@ -145,7 +147,8 @@ main_window::main_window (QWidget *p, oc
     _clipboard (QApplication::clipboard ()),
     _prevent_readline_conflicts (true),
     _suppress_dbg_location (true),
-    _start_gui (app_context && app_context->start_gui_p ())
+    _start_gui (app_context && app_context->start_gui_p ()),
+    _file_encoding (QString ())
 {
   if (_start_gui)
     {
@@ -159,6 +162,11 @@ main_window::main_window (QWidget *p, oc
       workspace_window = new workspace_view (this);
     }
 
+  _external_editor = new external_editor_interface (this);
+  _active_editor = editor_window;  // for connecting signals
+  if (! editor_window)
+    _active_editor = _external_editor;
+
   QSettings *settings = resource_manager::get_settings ();
 
   bool connect_to_web = true;
@@ -201,6 +209,7 @@ main_window::~main_window (void)
   // to its original pipe to capture error messages at exit.
 
   delete editor_window;     // first one for dialogs of modified editor-tabs
+  delete _external_editor;
   delete command_window;
   delete workspace_window;
   delete doc_browser_window;
@@ -308,11 +317,11 @@ main_window::open_file (const QString& f
 {
   emit open_file_signal (file_name);
 }
+
 void
-
 main_window::edit_mfile (const QString& name, int line)
 {
-  emit edit_mfile_request (name, QString (), QString (), line);
+  handle_edit_mfile_request (name, QString (), QString (), line);
 }
 
 void
@@ -1390,7 +1399,237 @@ main_window::handle_create_filedialog (c
   file_dialog->show ();
 }
 
+
+//
+// Functions related to file editing
+//
+// These are moved from editor to here for also using them when octave
+// is built without qscintilla
+//
+void
+main_window::request_open_file (void)
+{
+  // Open file isn't a file_editor_tab or editor function since the file
+  // might be opened in an external editor. Hence, functionality is here.
+
+  QSettings *settings = resource_manager::get_settings ();
+  bool is_internal = editor_window
+                && ! settings->value ("useCustomFileEditor",false).toBool ();
+
+  // Create a NonModal message.
+  QWidget *p = this;
+  if (is_internal)
+    p = editor_window;
+  QFileDialog *fileDialog = new QFileDialog (p);
+  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);
+
+  if (is_internal)
+    {
+      // combo box for encoding, only when using the internal editor
+      QLabel *label_enc = new QLabel (tr ("File Encoding:"));
+      QComboBox *combo_enc = new QComboBox ();
+      resource_manager::combo_encoding (combo_enc);
+      _file_encoding = QString ();  // default
+
+      // track changes in the combo boxes
+      connect (combo_enc, SIGNAL (currentIndexChanged (QString)),
+               this, SLOT (set_file_encoding (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 (_current_directory_combo_box->itemText (0));
+
+  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
+main_window::set_file_encoding (const QString& new_encoding)
+{
+  _file_encoding = new_encoding;
+}
+
+// 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
+main_window::request_open_files (const QStringList& open_file_names)
+{
+  for (int i = 0; i < open_file_names.count (); i++)
+    emit open_file_signal (open_file_names.at (i), _file_encoding, -1);
+}
+
+void
+main_window::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 (_current_directory_combo_box->itemText (0));
+          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");
+
+  emit open_file_signal (filename, QString (), line);  // default encoding
+}
+
+// Create a new script
+void
+main_window::request_new_script (const QString& commands)
+{
+  emit new_file_signal (commands);
+}
+
+// Create a new function and open it
+void
+main_window::request_new_function (bool)
+{
+  bool ok;
+  // Get the name of the new function: Parent of the input dialog is the
+  // editor window or the main window. The latter is chosen, if a custom
+  // editor is used or qscintilla is not available
+  QWidget *p = editor_window;
+  QSettings *settings = resource_manager::get_settings ();
+  if (! p || settings->value ("useCustomFileEditor",false).toBool ())
+    p = this;
+  QString new_name = QInputDialog::getText (p, 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 (editor_window, SIGNAL (file_loaded_signal ()),
+                   this, SLOT (restore_create_file_setting ()));
+        }
+      // start the edit command
+      execute_command_in_terminal ("edit " + new_name);
+    }
+}
+
+void
+main_window::restore_create_file_setting ()
+{
+  // restore the new files creation setting
+  QSettings *settings = resource_manager::get_settings ();
+  settings->setValue ("editor/create_new_file",false);
+  disconnect (editor_window, SIGNAL (file_loaded_signal ()),
+              this, SLOT (restore_create_file_setting ()));
+}
+
+
+//
 // Main subroutine of the constructor
+//
 void
 main_window::construct (void)
 {
@@ -1466,6 +1705,15 @@ main_window::construct (void)
       connect (this, SIGNAL (editor_focus_changed (bool)),
                editor_window, SLOT (enable_menu_shortcuts (bool)));
 
+      connect (editor_window,
+               SIGNAL (request_open_file_external (const QString&, int)),
+               _external_editor,
+               SLOT (call_custom_editor (const QString&, int)));
+
+      connect (_external_editor,
+               SIGNAL (request_settings_dialog (const QString&)),
+               this, SLOT (process_settings_dialog_request (const QString&)));
+
       connect (file_browser_window, SIGNAL (load_file_signal (const QString&)),
                this, SLOT (handle_load_workspace_request (const QString&)));
 
@@ -1646,12 +1894,10 @@ main_window::construct_octave_qt_link (v
                SIGNAL (show_preferences_signal (void)),
                this, SLOT (process_settings_dialog_request ()));
 
-#if defined (HAVE_QSCINTILLA)
       connect (_octave_qt_link,
                SIGNAL (edit_file_signal (const QString&)),
-               editor_window,
+               _active_editor,
                SLOT (handle_edit_file_request (const QString&)));
-#endif
 
       connect (_octave_qt_link,
                SIGNAL (insert_debugger_pointer_signal (const QString&, int)),
@@ -1794,10 +2040,8 @@ main_window::construct_file_menu (QMenuB
   _exit_action = file_menu->addAction (tr ("Exit"));
   _exit_action->setShortcutContext (Qt::ApplicationShortcut);
 
-#if defined (HAVE_QSCINTILLA)
   connect (_open_action, SIGNAL (triggered ()),
-           editor_window, SLOT (request_open_file ()));
-#endif
+           this, SLOT (request_open_file ()));
 
   connect (_load_workspace_action, SIGNAL (triggered ()),
            this, SLOT (handle_load_workspace_request ()));
@@ -1826,13 +2070,18 @@ main_window::construct_new_menu (QMenu *
   _new_figure_action = new_menu->addAction (tr ("New Figure"));
   _new_figure_action->setEnabled (true);
 
-#if defined (HAVE_QSCINTILLA)
   connect (_new_script_action, SIGNAL (triggered ()),
-           editor_window, SLOT (request_new_script ()));
-
+           this, SLOT (request_new_script ()));
   connect (_new_function_action, SIGNAL (triggered ()),
-           editor_window, SLOT (request_new_function ()));
-#endif
+           this, SLOT (request_new_function ()));
+  connect (this, SIGNAL (new_file_signal (const QString&)),
+           _active_editor, SLOT (request_new_file (const QString&)));
+  connect (this, SIGNAL (open_file_signal (const QString&)),
+           _active_editor, SLOT (request_open_file (const QString&)));
+  connect (this,
+           SIGNAL (open_file_signal (const QString&, const QString&, int)),
+           _active_editor,
+           SLOT (request_open_file (const QString&, const QString&, int)));
 
   connect (_new_figure_action, SIGNAL (triggered ()),
            this, SLOT (handle_new_figure_request ()));
diff -r c319e6d737f2 -r 4e981842222f libgui/src/main-window.h
--- a/libgui/src/main-window.h	Mon Apr 10 07:02:42 2017 +0200
+++ b/libgui/src/main-window.h	Tue Apr 11 08:00:23 2017 +0200
@@ -40,6 +40,7 @@ along with Octave; see the file COPYING.
 
 // Editor includes
 #include "file-editor-interface.h"
+#include "external-editor-interface.h"
 
 // QTerminal includes
 #include "QTerminal.h"
@@ -124,7 +125,7 @@ signals:
   void init_terminal_size_signal (void);
   void new_file_signal (const QString&);
   void open_file_signal (const QString&);
-  void edit_mfile_request (const QString&, const QString&, const QString&, int);
+  void open_file_signal (const QString& file, const QString& enc, int line);
 
   void show_doc_signal (const QString&);
 
@@ -195,6 +196,12 @@ public slots:
   void debug_step_out (void);
   void debug_quit (void);
 
+  void request_open_file (void);
+  void request_new_script (const QString& commands = QString ());
+  void request_new_function (bool triggered = true);
+  void handle_edit_mfile_request (const QString& name, const QString& file,
+                                  const QString& curr_dir, int line);
+
   void handle_insert_debugger_pointer_request (const QString& file, int line);
   void handle_delete_debugger_pointer_request (const QString& file, int line);
   void handle_update_breakpoint_marker_request (bool insert,
@@ -261,6 +268,9 @@ public slots:
 private slots:
 
   void disable_menu_shortcuts (bool disable);
+  void restore_create_file_setting ();
+  void set_file_encoding (const QString& new_encoding);
+  void request_open_files (const QStringList& open_file_names);
 
 protected:
   void closeEvent (QCloseEvent * closeEvent);
@@ -345,6 +355,9 @@ private:
   file_editor_interface *editor_window;
   workspace_view *workspace_window;
 
+  external_editor_interface *_external_editor;
+  QWidget *_active_editor;
+
   QList<octave_dock_widget *> dock_widget_list ();
 
   octave_dock_widget *_active_dock;
@@ -439,6 +452,8 @@ private:
   bool _prevent_readline_conflicts;
   bool _suppress_dbg_location;
   bool _start_gui;
+
+  QString _file_encoding;
 };
 
 class news_reader : public QObject
diff -r c319e6d737f2 -r 4e981842222f libgui/src/module.mk
--- a/libgui/src/module.mk	Mon Apr 10 07:02:42 2017 +0200
+++ b/libgui/src/module.mk	Tue Apr 11 08:00:23 2017 +0200
@@ -98,6 +98,7 @@ DIRSTAMP_FILES += \
 endif
 
 OCTAVE_GUI_SRC_MOC = \
+  libgui/src/moc-external-editor-interface.cc \
   libgui/src/moc-dialog.cc \
   libgui/src/moc-documentation-dock-widget.cc \
   libgui/src/moc-files-dock-widget.cc \
@@ -143,6 +144,7 @@ noinst_HEADERS += \
   libgui/src/dialog.h \
   libgui/src/octave-dock-widget.h \
   libgui/src/documentation-dock-widget.h \
+  libgui/src/external-editor-interface.h \
   libgui/src/files-dock-widget.h \
   libgui/src/history-dock-widget.h \
   libgui/src/liboctgui-build-info.h \
@@ -174,6 +176,7 @@ noinst_HEADERS += \
 libgui_src_libgui_src_la_SOURCES = \
   libgui/src/dialog.cc \
   libgui/src/documentation-dock-widget.cc \
+  libgui/src/external-editor-interface.cc \
   libgui/src/files-dock-widget.cc \
   libgui/src/history-dock-widget.cc \
   libgui/src/m-editor/file-editor-tab.cc \
