# HG changeset patch # User John Donoghue # 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 --git a/libgui/src/dialog.cc b/libgui/src/dialog.cc --- a/libgui/src/dialog.cc +++ b/libgui/src/dialog.cc @@ -31,6 +31,7 @@ #include #include #include +#include // Could replace most of these with #include #include #include @@ -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 #include #include +#include // Defined for purposes of sending QList as part of signal. typedef QList 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 --git a/libgui/src/main-window.cc b/libgui/src/main-window.cc --- a/libgui/src/main-window.cc +++ b/libgui/src/main-window.cc @@ -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 --git a/libgui/src/main-window.h b/libgui/src/main-window.h --- a/libgui/src/main-window.h +++ b/libgui/src/main-window.h @@ -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 --git a/libgui/src/octave-qt-link.cc b/libgui/src/octave-qt-link.cc --- a/libgui/src/octave-qt-link.cc +++ b/libgui/src/octave-qt-link.cc @@ -128,6 +128,37 @@ return retval; } +static QStringList +make_filter_list (const std::list< std::pair >& 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 >::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, int> octave_qt_link::do_list_dialog (const std::list& list, @@ -188,6 +219,39 @@ return retval; } +std::list +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 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 --git a/libgui/src/octave-qt-link.h b/libgui/src/octave-qt-link.h --- a/libgui/src/octave-qt-link.h +++ b/libgui/src/octave-qt-link.h @@ -84,6 +84,13 @@ const std::list& nc, const std::list& defaults); + std::list + 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 --git a/libinterp/interpfcn/octave-link.cc b/libinterp/interpfcn/octave-link.cc --- a/libinterp/interpfcn/octave-link.cc +++ b/libinterp/interpfcn/octave-link.cc @@ -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 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 > 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 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::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::iterator it = items_lst.begin (); + for (int idx=0;idx (); } + static std::list + 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 (); + } + + 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& nc, const std::list& defaults) = 0; + virtual std::list + 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 --git a/scripts/plot/uigetfile.m b/scripts/plot/uigetfile.m --- a/scripts/plot/uigetfile.m +++ b/scripts/plot/uigetfile.m @@ -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