# HG changeset patch
# User John Donoghue <john.donoghue@ieee.org>
# Date 1367156719 14400
# Node ID 7f8db1942dc06b5c7590ab54b6c818b0338e24ed
# Parent  0eca6c5657c9cf08e1e137a04733ca870dd15604
Add Qt link uigetfile dialog implementation.

* libgui/src/octave-qt-link.cc, libgui/src/octave-qt-link.h,
  (octave_qt_link::do_file_dialog): New function.
  (make_filter_list): New function.

* libinterp/interpfcn/octave-link.cc
  (__octave_link_file_dialog__): New function.

* libinterp/interpfcn/octave-link.h:
  (octave_link::file_dialog): New function.
  (octave_link::do_file_dialog): New virtual function.


* scripts/plot/uigetfile.m: update to call octave_link file dialog if octave link is present.

* libgui/src/dialog.cc, libgui/src/dialog.h
  (class FileDialog): New class.
  (QUIWidgetCreator::QUIWidgetCreator): added initialization of new var path_name.
  (QUIWidgetCreator::signal_filedialog): New function.
  (QUIWidgetCreator::create_filedialog): New function.
  (QUIWidgetCreator::filedialog_finished): New function.
  (QUIWidgetCreator::get_dialog_path): New function.

* libgui/src/main-window.cc, libgui/src/main-window.h
  (main_window::connect_uiwidget_links): Added connect for handle_file_dialog.
  (main_window::handle_create_filedialog): New function.

diff -r 0eca6c5657c9 -r 7f8db1942dc0 libgui/src/dialog.cc
--- a/libgui/src/dialog.cc	Sun Apr 28 02:29:19 2013 -0400
+++ b/libgui/src/dialog.cc	Sun Apr 28 09:45:19 2013 -0400
@@ -31,6 +31,7 @@
 #include <QStringList>
 #include <QStringListModel>
 #include <QListView>
+#include <QFileInfo>
 // Could replace most of these with #include <QtGui>
 #include <QMessageBox>
 #include <QHBoxLayout>
@@ -45,7 +46,7 @@
 
 QUIWidgetCreator::QUIWidgetCreator (void)
   : QObject (), dialog_result (-1), dialog_button (),
-    string_list (new QStringList ()), list_index (new QIntList ())
+    string_list (new QStringList ()), list_index (new QIntList ()), path_name (new QString ())
 { }
 
 
@@ -53,6 +54,7 @@
 {
   delete string_list;
   delete list_index;
+  delete path_name;
 }
 
 
@@ -94,6 +96,19 @@
   waitcondition.wakeAll ();
 }
 
+void
+QUIWidgetCreator::filedialog_finished (const QStringList& files, const QString & path, const int filterindex)
+{
+  // Store the value so that builtin functions can retrieve.
+  *string_list = files;
+  dialog_result = filterindex;
+  *path_name = path;
+
+  // Wake up Octave process so that it continues.
+  waitcondition.wakeAll ();
+}
+
+
 
 MessageDialog::MessageDialog (const QString& message,
                               const QString& title,
@@ -386,7 +401,6 @@
   done (QDialog::Accepted);
 }
 
-
 void
 InputDialog::buttonCancel_clicked (void)
 {
@@ -403,3 +417,66 @@
 {
   buttonCancel_clicked ();
 }
+
+FileDialog::FileDialog (const QStringList &filters,
+                        const QString& title,
+                        const QString& filename,
+                        const QString &dirname,
+                        bool multiselect)
+  : QFileDialog()
+{
+  // Create a NonModal message.
+  setWindowModality (Qt::NonModal);
+
+  setWindowTitle (title.isEmpty () ? " " : title);
+  setDirectory (dirname);
+
+  if (multiselect)
+    setFileMode (QFileDialog::ExistingFiles);
+  else
+    setFileMode (QFileDialog::ExistingFile);
+
+  setNameFilters (filters);
+  setAcceptMode (QFileDialog::AcceptOpen);
+  selectFile (filename);
+  
+  connect (this, SIGNAL (finish_input (const QStringList&, const QString &, const int)),
+           &uiwidget_creator,
+           SLOT (filedialog_finished (const QStringList&, const QString &, const int)));
+}
+
+void
+FileDialog::reject (void)
+{
+  QStringList empty;
+  emit finish_input (empty, "", 0);
+  done (QDialog::Rejected);
+
+}
+
+void FileDialog::accept(void)
+{
+  QStringList string_result;
+  QString path;
+  int idx = 1;
+
+  string_result = selectedFiles();
+
+  // matlab expects just the file name, whereas the file dialog gave us
+  // pull path names, so fix it
+  for(int i=0;i<string_result.size ();i++)
+    {
+      string_result[i] = QFileInfo (string_result[i]).fileName ();
+    }
+
+
+  path = directory ().absolutePath ();
+
+  QStringList filters = nameFilters ();
+  idx = filters.indexOf( selectedNameFilter ()) + 1;
+  
+  // send the selected info
+  emit finish_input (string_result, path, idx);
+  done (QDialog::Accepted);
+}
+
diff -r 0eca6c5657c9 -r 7f8db1942dc0 libgui/src/dialog.h
--- a/libgui/src/dialog.h	Sun Apr 28 02:29:19 2013 -0400
+++ b/libgui/src/dialog.h	Sun Apr 28 09:45:19 2013 -0400
@@ -32,6 +32,7 @@
 #include <QDialog>
 #include <QMessageBox>
 #include <QLineEdit>
+#include <QFileDialog>
 
 // Defined for purposes of sending QList<int> as part of signal.
 typedef QList<int> QIntList;
@@ -102,7 +103,17 @@
   };
 
   const QStringList *get_string_list (void) { return string_list; }
-  
+
+  bool signal_filedialog (const QStringList &filters, const QString &title, 
+                          const QString &filename, const QString &dirname, 
+                          bool multiselect)
+  {
+    emit create_filedialog (filters, title, filename, dirname, multiselect);
+    return true;
+  }
+
+  const QString * get_dialog_path(void) { return path_name; }
+
   void wait (void)
   {
     // Wait while the user is responding to message box.
@@ -122,6 +133,11 @@
                            const QFloatList&, const QFloatList&,
                            const QStringList&);
 
+  void create_filedialog (const QStringList &filters,
+                          const QString &title,
+                          const QString &filename,
+                          const QString &dirname,
+                          bool multiselect);
 public slots:
 
   void dialog_button_clicked (QAbstractButton *button);
@@ -131,6 +147,8 @@
 
   void input_finished (const QStringList& input, const int button_pressed);
 
+  void filedialog_finished (const QStringList& files, const QString &path, const int filterindex);
+
 private:
 
   int dialog_result;
@@ -141,6 +159,8 @@
   QStringList *string_list;
   QIntList *list_index;
 
+  QString * path_name;
+
   // GUI objects cannot be accessed in the non-GUI thread.  However,
   // signals can be sent to slots across threads with proper
   // synchronization.  Hence, the use of QWaitCondition.
@@ -227,4 +247,24 @@
   void reject (void);
 };
 
+class FileDialog : public QFileDialog
+{
+  Q_OBJECT
+
+public:
+
+  explicit FileDialog (const QStringList &filters,
+                       const QString& title, const QString& filename, 
+                       const QString& dirname, bool multiselect);
+
+signals:
+
+  void finish_input (const QStringList&, const QString &, const int);
+
+private slots:
+  void reject();
+  void accept();
+
+};
+
 #endif
diff -r 0eca6c5657c9 -r 7f8db1942dc0 libgui/src/main-window.cc
--- a/libgui/src/main-window.cc	Sun Apr 28 02:29:19 2013 -0400
+++ b/libgui/src/main-window.cc	Sun Apr 28 09:45:19 2013 -0400
@@ -651,6 +651,11 @@
            SLOT (handle_create_inputlayout (const QStringList&, const QString&,
                                             const QFloatList&, const QFloatList&,
                                             const QStringList&)));
+
+  connect (&uiwidget_creator,
+           SIGNAL (create_filedialog (const QStringList &,const QString&, const QString&, const QString&, bool)),
+           this,
+           SLOT (handle_create_filedialog (const QStringList &,const QString&, const QString&,const QString&, bool)));
 }
 
 // Create a message dialog with specified string, buttons and decorative
@@ -707,6 +712,19 @@
   input_dialog->show ();
 }
 
+void
+main_window::handle_create_filedialog (const QStringList &filters,
+                                       const QString& title, 
+                                       const QString& filename, 
+                                       const QString &dirname,
+                                       bool multiselect)
+{
+  FileDialog * file_dialog = new FileDialog(filters, title, 
+                                            filename, dirname, multiselect);
+  file_dialog->setAttribute (Qt::WA_DeleteOnClose);
+  file_dialog->show ();
+}
+
 // Main subroutine of the constructor
 void
 main_window::construct (void)
diff -r 0eca6c5657c9 -r 7f8db1942dc0 libgui/src/main-window.h
--- a/libgui/src/main-window.h	Sun Apr 28 02:29:19 2013 -0400
+++ b/libgui/src/main-window.h	Sun Apr 28 09:45:19 2013 -0400
@@ -157,6 +157,11 @@
                                   const QFloatList&, const QFloatList&,
                                   const QStringList&);
 
+  void handle_create_filedialog (const QStringList &filters, 
+                                 const QString& title, const QString& filename, 
+                                 const QString &dirname,
+                                 bool multiselect);
+
   // find files dialog 
   void find_files(const QString &startdir=QDir::currentPath());
   void find_files_finished(int);
diff -r 0eca6c5657c9 -r 7f8db1942dc0 libgui/src/octave-qt-link.cc
--- a/libgui/src/octave-qt-link.cc	Sun Apr 28 02:29:19 2013 -0400
+++ b/libgui/src/octave-qt-link.cc	Sun Apr 28 09:45:19 2013 -0400
@@ -128,6 +128,37 @@
   return retval;
 }
 
+static QStringList
+make_filter_list (const std::list< std::pair<std::string, std::string> >& lst)
+{
+  QStringList retval;
+
+  // we have pairs of data, first being the list of extensions exta;exb;extc etc
+  // second the name to use as filter name (optional).
+  // Qt wants a a list of filters in the format of 'FilterName (spacfe separated exts)'
+
+  for (std::list< std::pair<std::string,std::string> >::const_iterator it = lst.begin ();
+       it != lst.end (); it++)
+    {
+      QString ext = QString::fromStdString ((*it).first);
+      QString name = QString::fromStdString ((*it).second);
+
+      // strip out (exts) from name (if any)
+      name.replace(QRegExp("\\(.*\\)"), "");
+      // replace ';' with spaces in ext list
+      ext.replace(";"," ");
+
+      if (name.length() == 0)
+        {
+           // no name field - so need build one from teh extendiions
+           name = ext.toUpper() + " Files";
+        }
+
+      retval.append (name + " (" + ext + ")");
+    }
+
+  return retval;
+}
 
 std::pair<std::list<int>, int>
 octave_qt_link::do_list_dialog (const std::list<std::string>& list,
@@ -188,6 +219,39 @@
   return retval;
 }
 
+std::list<std::string>
+octave_qt_link::do_file_dialog (const std::list< std::pair< std::string, std::string > > filter,
+                                const std::string& title,
+                                const std::string& filename,
+                                const std::string& dirname,
+                                bool multiselect)
+{
+  std::list<std::string> retval;
+
+  uiwidget_creator.signal_filedialog ( make_filter_list (filter),
+                                       QString::fromStdString (title),
+                                       QString::fromStdString (filename),
+                                       QString::fromStdString (dirname),
+                                       multiselect);
+
+  // Wait while the user is responding to dialog.
+  uiwidget_creator.wait ();
+
+  // add all the file dialog result to a string list
+  const QStringList *inputLine = uiwidget_creator.get_string_list ();
+
+  for (QStringList::const_iterator it = inputLine->begin ();
+       it != inputLine->end (); it++)
+    {
+      retval.push_back (it->toStdString ());
+    }
+
+  retval.push_back (uiwidget_creator.get_dialog_path ()->toStdString ());
+  retval.push_back ((QString ("%1").arg (uiwidget_creator.get_dialog_result ())).toStdString ());
+
+  return retval;
+}
+
 int
 octave_qt_link::do_debug_cd_or_addpath_error (const std::string& file,
                                               const std::string& dir,
diff -r 0eca6c5657c9 -r 7f8db1942dc0 libgui/src/octave-qt-link.h
--- a/libgui/src/octave-qt-link.h	Sun Apr 28 02:29:19 2013 -0400
+++ b/libgui/src/octave-qt-link.h	Sun Apr 28 09:45:19 2013 -0400
@@ -84,6 +84,13 @@
                    const std::list<float>& nc,
                    const std::list<std::string>& defaults);
 
+  std::list<std::string>
+  do_file_dialog (const std::list< std::pair< std::string, std::string > > filter,
+                  const std::string& title, 
+                  const std::string &filename,
+                  const std::string &pathname,
+                  bool multiselect);
+
   int
   do_debug_cd_or_addpath_error (const std::string& file,
                                 const std::string& dir,
@@ -114,6 +121,7 @@
   void do_set_default_prompts (std::string& ps1, std::string& ps2,
                                std::string& ps4);
 
+
 private:
 
   // No copying!
diff -r 0eca6c5657c9 -r 7f8db1942dc0 libinterp/interpfcn/octave-link.cc
--- a/libinterp/interpfcn/octave-link.cc	Sun Apr 28 02:29:19 2013 -0400
+++ b/libinterp/interpfcn/octave-link.cc	Sun Apr 28 09:45:19 2013 -0400
@@ -193,6 +193,82 @@
   return retval;
 }
 
+DEFUN (__octave_link_file_dialog__, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} __octave_link_file_dialog__ (@var{filterlist}, @var{title}, @var{filename}, @var{size} @var{multiselect}, @var{pathname})\n\
+Undocumented internal function.\n\
+@end deftypefn")
+{
+  octave_value_list retval(3, octave_value (0));
+
+  if (args.length () == 6)
+    {
+
+      const Array<std::string> flist = args (0).cellstr_value ();
+      std::string title = args (1).string_value ();
+      std::string filename = args (2).string_value ();
+      Matrix pos = args (3).matrix_value ();
+      std::string multi_on = args (4).string_value (); // on, off
+      std::string pathname = args (5).string_value ();
+
+      octave_idx_type nel = flist.numel ();
+      std::list< std::pair<std::string, std::string> > filter_lst;
+
+      for(octave_idx_type i = 0; i < flist.rows (); i++)
+        {
+          filter_lst.push_back ( std::make_pair (flist.elem (i,0), flist.columns ()>1 ? flist.elem (i, 1) : "" ) );
+        }
+
+      if (! error_state)
+        {
+
+          flush_octave_stdout ();
+
+          std::list<std::string> items_lst
+            = octave_link::file_dialog (filter_lst, title, filename, pathname, multi_on == "on" ? true : false);
+
+          nel = items_lst.size ();
+
+          // if 3, then is filename, dolder and selected index,
+          if (items_lst.size () <= 3)
+            {
+             int idx = 0;
+             for (std::list<std::string>::iterator it = items_lst.begin ();
+                  it != items_lst.end (); it++)
+               {
+                 retval (idx++) = *(it);
+
+                 if (idx == 1 && retval (0).string_value ().length () == 0)
+                   retval (0) = 0;
+                 if(idx == 3) retval (2) = atoi (retval (2).string_value ().c_str ());
+               }
+            }
+          else
+            {
+              // multiple files
+              nel = items_lst.size ();
+              Cell items (dim_vector (1, nel));
+
+              std::list<std::string>::iterator it = items_lst.begin ();
+              for (int idx=0;idx<items_lst.size ()-2;idx++)
+                {
+                  items.xelem (idx) = *it;
+                  it++;
+                }
+              retval (0) = items;
+              retval (1) = *it;
+              it++;
+              retval (2) = atoi ((*it).c_str ());
+            }
+
+        }
+      else
+        error ("invalid arguments");
+
+    }
+  return retval;
+}
+
 DEFUN (__octave_link_list_dialog__, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} __octave_link_list_dialog__ (@var{list}, @var{mode}, @var{size}, @var{intial}, @var{name}, @var{prompt}, @var{ok_string}, @var{cancel_string})\n\
diff -r 0eca6c5657c9 -r 7f8db1942dc0 libinterp/interpfcn/octave-link.h
--- a/libinterp/interpfcn/octave-link.h	Sun Apr 28 02:29:19 2013 -0400
+++ b/libinterp/interpfcn/octave-link.h	Sun Apr 28 09:45:19 2013 -0400
@@ -179,6 +179,19 @@
       : std::list<std::string> ();
   }
 
+  static std::list<std::string>
+  file_dialog ( const std::list< std::pair< std::string, std::string > > filter,
+                const std::string& title,
+                const std::string& filename,
+                const std::string& dirname,
+                bool multiselect)
+  {
+    return enabled ()
+      ? instance->do_file_dialog (filter, title, filename, dirname, multiselect)
+      : std::list<std::string> ();
+  }
+
+
   static int debug_cd_or_addpath_error (const std::string& file,
                                         const std::string& dir,
                                         bool addpath_option)
@@ -370,6 +383,13 @@
                    const std::list<float>& nc,
                    const std::list<std::string>& defaults) = 0;
 
+  virtual std::list<std::string>
+  do_file_dialog (const std::list< std::pair< std::string, std::string > > filter,
+                  const std::string& title,
+                  const std::string& filename,
+                  const std::string& dirname,
+                  bool multiselect) = 0;
+
   virtual int
   do_debug_cd_or_addpath_error (const std::string& file,
                                 const std::string& dir,
diff -r 0eca6c5657c9 -r 7f8db1942dc0 scripts/plot/uigetfile.m
--- a/scripts/plot/uigetfile.m	Sun Apr 28 02:29:19 2013 -0400
+++ b/scripts/plot/uigetfile.m	Sun Apr 28 09:45:19 2013 -0400
@@ -65,19 +65,21 @@
 
 function [retfile, retpath, retindex] = uigetfile (varargin)
 
-  defaulttoolkit = get (0, "defaultfigure__graphics_toolkit__");
-  funcname = ["__uigetfile_", defaulttoolkit, "__"];
-  functype = exist (funcname);
-  if (! __is_function__ (funcname))
-    funcname = "__uigetfile_fltk__";
+  if (! __octave_link_enabled__ ())
+    defaulttoolkit = get (0, "defaultfigure__graphics_toolkit__");
+    funcname = ["__uigetfile_", defaulttoolkit, "__"];
+    functype = exist (funcname);
     if (! __is_function__ (funcname))
-      error ("uigetfile: fltk graphics toolkit required");
-    elseif (! strcmp (defaulttoolkit, "gnuplot"))
-      warning ("uigetfile: no implementation for toolkit '%s', using 'fltk' instead",
+      funcname = "__uigetfile_fltk__";
+      if (! __is_function__ (funcname))
+        error ("uigetfile: fltk graphics toolkit required");
+      elseif (! strcmp (defaulttoolkit, "gnuplot"))
+        warning ("uigetfile: no implementation for toolkit '%s', using 'fltk' instead",
                defaulttoolkit);
+      endif
     endif
   endif
-
+  
   if (nargin > 7)
     error ("uigetfile: number of input arguments must be less than eight");
   endif
@@ -183,7 +185,11 @@
     endfor
   endif
 
-  [retfile, retpath, retindex] = feval (funcname, outargs{:});
+  if (__octave_link_enabled__ ())
+    [retfile, retpath, retindex] = __octave_link_file_dialog__ (outargs{:});
+  else
+    [retfile, retpath, retindex] = feval (funcname, outargs{:});
+  endif
 
 endfunction
 
