changeset 16557:04fb96f4bea1

allow double-click in file browser to load data files * files-dock-widget.cc (files_dock_widget::display_directory): If file looks like Octave data file, load it instead of opening with editor. * ls-mat-ascii.h, ls-mat-ascii.cc (get_lines_and_columns): New option to supress error messages. New option to check for numeric values. (looks_like_mat_ascii_file): New function. * load-save.h load-save.cc (is_octave_data_file): New function. (get_file_format): Don't return LS_MAT_ASCII unless the file really looks like it is a numeric data file.
author John W. Eaton <jwe@octave.org>
date Tue, 23 Apr 2013 12:57:16 -0400
parents 03a28487fa9d
children ce65326ecd6c
files libgui/src/files-dock-widget.cc libinterp/interp-core/ls-mat-ascii.cc libinterp/interp-core/ls-mat-ascii.h libinterp/interpfcn/load-save.cc libinterp/interpfcn/load-save.h
diffstat 5 files changed, 92 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/files-dock-widget.cc
+++ b/libgui/src/files-dock-widget.cc
@@ -41,6 +41,8 @@
 #include <QMessageBox>
 #include <QToolButton>
 
+#include "load-save.h"
+
 files_dock_widget::files_dock_widget (QWidget *p)
   : octave_dock_widget (p)
 {
@@ -280,8 +282,15 @@
         }
       else
         {
-          if (QFile::exists (fileInfo.absoluteFilePath ()))
-            emit open_file (fileInfo.absoluteFilePath ());
+          QString abs_fname = fileInfo.absoluteFilePath ();
+
+          if (QFile::exists (abs_fname))
+            {
+              if (is_octave_data_file (abs_fname.toStdString ()))
+                emit load_file_signal (abs_fname);
+              else
+                emit open_file (fileInfo.absoluteFilePath ());
+            }
         }
     }
 }
--- a/libinterp/interp-core/ls-mat-ascii.cc
+++ b/libinterp/interp-core/ls-mat-ascii.cc
@@ -107,7 +107,10 @@
 }
 
 static void
-get_lines_and_columns (std::istream& is, const std::string& filename, octave_idx_type& nr, octave_idx_type& nc)
+get_lines_and_columns (std::istream& is, 
+                       octave_idx_type& nr, octave_idx_type& nc,
+                       const std::string& filename = std::string (),
+                       bool quiet = false, bool check_numeric = false)
 {
   std::streampos pos = is.tellg ();
 
@@ -147,6 +150,25 @@
 
           if (end != std::string::npos)
             {
+              if (check_numeric)
+                {
+                  std::istringstream tmp_stream (buf.substr (beg, end-beg));
+
+                  octave_read_double (tmp_stream);
+
+                  if (tmp_stream.fail ())
+                    {
+                      if (! quiet)
+                        error ("load: %s: non-numeric data found near line %d",
+                               filename.c_str (), file_line_number);
+
+                      nr = 0;
+                      nc = 0;
+
+                      goto done;
+                    }
+                }
+
               beg = buf.find_first_not_of (", \t", end);
 
               if (beg == std::string::npos || (buf[beg] == '\r' &&
@@ -172,14 +194,24 @@
           else if (nc == tmp_nc)
             nr++;
           else
-            error ("load: %s: inconsistent number of columns near line %d",
-                   filename.c_str (), file_line_number);
+            {
+              if (! quiet)
+                error ("load: %s: inconsistent number of columns near line %d",
+                       filename.c_str (), file_line_number);
+
+              nr = 0;
+              nc = 0;
+
+              goto done;
+            }
         }
     }
 
-  if (nr == 0 || nc == 0)
+  if (! quiet && (nr == 0 || nc == 0))
     error ("load: file '%s' seems to be empty!", filename.c_str ());
 
+ done:
+
   is.clear ();
   is.seekg (pos);
 }
@@ -233,7 +265,7 @@
 
       int total_count = 0;
 
-      get_lines_and_columns (is, filename, nr, nc);
+      get_lines_and_columns (is, nr, nc, filename);
 
       octave_quit ();
 
@@ -376,3 +408,23 @@
 
   return (os && success);
 }
+
+bool
+looks_like_mat_ascii_file (const std::string& filename)
+{
+  bool retval = false;
+
+  std::ifstream is (filename.c_str ());
+
+  if (is)
+    {
+      int nr = 0;
+      int nc = 0;
+
+      get_lines_and_columns (is, nr, nc, filename, true, true);
+
+      retval = (nr != 0 && nc != 0);
+    }
+
+  return retval;
+}
--- a/libinterp/interp-core/ls-mat-ascii.h
+++ b/libinterp/interp-core/ls-mat-ascii.h
@@ -31,4 +31,6 @@
 save_mat_ascii_data (std::ostream& os, const octave_value& val_arg,
                      int precision, bool tabs = false);
 
+extern bool looks_like_mat_ascii_file (const std::string& filename);
+
 #endif
--- a/libinterp/interpfcn/load-save.cc
+++ b/libinterp/interpfcn/load-save.cc
@@ -242,7 +242,8 @@
 
       int32_t mopt, nr, nc, imag, len;
 
-      int err = read_mat_file_header (file, swap, mopt, nr, nc, imag, len, 1);
+      int err = read_mat_file_header (file, swap, mopt, nr, nc, imag, len,
+                                      true);
 
       if (! err)
         retval = LS_MAT_BINARY;
@@ -277,7 +278,7 @@
 
 static load_save_format
 get_file_format (const std::string& fname, const std::string& orig_fname,
-                 bool &use_zlib)
+                 bool &use_zlib, bool quiet = false)
 {
   load_save_format retval = LS_UNKNOWN;
 
@@ -309,19 +310,16 @@
         }
 #endif
 
-      if (retval == LS_UNKNOWN)
-        {
-          // Try reading the file as numbers only, determining the
-          // number of rows and columns from the data.  We don't
-          // even bother to check to see if the first item in the
-          // file is a number, so that get_complete_line() can
-          // skip any comments that might appear at the top of the
-          // file.
+      // FIXME -- looks_like_mat_ascii_file does not check to see
+      // whether the file contains numbers.  It just skips comments and
+      // checks for the same number of words on each line.  We may need
+      // a better check here.  The best way to do that might be just
+      // to try to read the file and see if it works.
 
-          retval = LS_MAT_ASCII;
-        }
+      if (retval == LS_UNKNOWN && looks_like_mat_ascii_file (fname))
+        retval = LS_MAT_ASCII;
     }
-  else
+  else if (! quiet)
     gripe_file_open ("load", orig_fname);
 
   return retval;
@@ -537,6 +535,12 @@
   return fname;
 }
 
+bool
+is_octave_data_file (const std::string& fname)
+{
+  bool use_zlib = false;
+  return get_file_format (fname, fname, use_zlib, true) != LS_UNKNOWN;
+}
 
 DEFUN (load, args, nargout,
   "-*- texinfo -*-\n\
--- a/libinterp/interpfcn/load-save.h
+++ b/libinterp/interpfcn/load-save.h
@@ -26,6 +26,9 @@
 #include <iosfwd>
 #include <string>
 
+#include "mach-info.h"
+#include "symtab.h"
+
 class octave_value;
 
 // FIXME: maybe MAT5 and MAT7 should be options to MAT_BINARY.
@@ -80,6 +83,8 @@
          bool list_only, bool swap, bool verbose,
          const string_vector& argv, int argv_idx, int argc, int nargout);
 
+extern bool is_octave_data_file (const std::string& file);
+
 extern void
 do_save (std::ostream& os, const symbol_table::symbol_record& sr,
          load_save_format fmt, bool save_as_floats);