Merge branch 'master' into import-gui
authorJohn Darrington <john@darrington.wattle.id.au>
Thu, 9 May 2013 17:39:15 +0000 (19:39 +0200)
committerJohn Darrington <john@darrington.wattle.id.au>
Thu, 9 May 2013 17:39:15 +0000 (19:39 +0200)
Conflicts:
src/ui/gui/psppire-cell-renderer-button.c

src/data/casereader.c
src/data/gnumeric-reader.c
src/data/ods-reader.c
src/data/spreadsheet-reader.c
src/data/spreadsheet-reader.h
src/ui/gui/psppire-cell-renderer-button.c
tests/language/data-io/get-data-spreadsheet.at

index adb6b6a909b134e815836aa75cbf0b1263d79b68..c8050c6cde4c7b2a35d6d2b45aa752c3ecbee1e8 100644 (file)
@@ -242,19 +242,6 @@ casereader_count_cases__ (const struct casereader *reader,
   struct casereader *clone;
   casenumber n_cases;
 
-  /* This seems to avoid a bug in Gcc 4.4.5 where, upon
-     return from this function, the stack appeared corrupt,
-     and the program returned to the wrong address.  Oddly
-     the problem only manifested itself when used in conjunction
-     with the ODS reader, in code such as:
-
-     GET DATA /TYPE=ODS ....
-     LIST.
-  */
-#if (__GNUC__ == 4 ) && (__GNUC_MINOR__ == 4)
-  volatile int x = 1; x++;
-#endif
-
   clone = casereader_clone (reader);
   n_cases = casereader_advance (clone, max_cases);
   casereader_destroy (clone);
index 27ba9d4cd21811c76bb0c2340d269dea018063bd..a0a4766652d2c07f029f0e1cb163bc6f0bf70894 100644 (file)
@@ -48,6 +48,8 @@ gnumeric_open_reader (const struct spreadsheet_read_options *opts, struct dictio
 #include <libxml/xmlreader.h>
 #include <zlib.h>
 
+#include "data/format.h"
+#include "data/data-in.h"
 #include "data/case.h"
 #include "data/casereader-provider.h"
 #include "data/dictionary.h"
@@ -59,6 +61,25 @@ gnumeric_open_reader (const struct spreadsheet_read_options *opts, struct dictio
 
 #include "gl/xalloc.h"
 
+
+/* Shamelessly lifted from the Gnumeric sources:
+   https://git.gnome.org/browse/gnumeric/tree/src/value.h
+ */
+enum gnm_value_type
+{
+  VALUE_EMPTY   = 10,
+  VALUE_BOOLEAN = 20,
+  VALUE_INTEGER = 30, /* Note, this was removed from gnumeric in 2006 - old versions may of
+                        course still be around. New ones are supposed to use float.*/
+  VALUE_FLOAT   = 40,
+  VALUE_ERROR   = 50,
+  VALUE_STRING  = 60,
+  VALUE_CELLRANGE  = 70,
+  VALUE_ARRAY   = 80
+};
+
+
+
 static void gnm_file_casereader_destroy (struct casereader *, void *);
 
 static struct ccase *gnm_file_casereader_read (struct casereader *, void *);
@@ -147,6 +168,8 @@ struct gnumeric_reader
   struct dictionary *dict;
   struct ccase *first_case;
   bool used_first_case;
+
+  enum gnm_value_type vtype;
 };
 
 
@@ -203,7 +226,7 @@ gnumeric_get_sheet_range (struct spreadsheet *s, int n)
       process_node (gr, &gr->msd);
     }
 
-  return create_cell_ref (
+  return create_cell_range (
                          gr->sheets[n].start_col,
                          gr->sheets[n].start_row,
                          gr->sheets[n].stop_col,
@@ -429,7 +452,7 @@ process_node (struct gnumeric_reader *r, struct state_data *sd)
  */
 static void
 convert_xml_string_to_value (struct ccase *c, const struct variable *var,
-                            const xmlChar *xv)
+                            const xmlChar *xv, enum gnm_value_type type, int col, int row)
 {
   union value *v = case_data_rw (c, var);
 
@@ -437,7 +460,7 @@ convert_xml_string_to_value (struct ccase *c, const struct variable *var,
     value_set_missing (v, var_get_width (var));
   else if ( var_is_alpha (var))
     value_copy_str_rpad (v, var_get_width (var), xv, ' ');
-  else
+  else if (type == VALUE_FLOAT || type == VALUE_INTEGER)
     {
       const char *text = CHAR_CAST (const char *, xv);
       char *endptr;
@@ -447,6 +470,29 @@ convert_xml_string_to_value (struct ccase *c, const struct variable *var,
       if ( errno != 0 || endptr == text)
        v->f = SYSMIS;
     }
+  else
+    {
+      const char *text = CHAR_CAST (const char *, xv);
+
+      const struct fmt_spec *fmt = var_get_write_format (var);
+
+      char *m = data_in (ss_cstr (text), "UTF-8",
+                        fmt->type,
+                        v,
+                        var_get_width (var),
+                        "UTF-8");
+      
+      if (m)
+       {
+         char buf [FMT_STRING_LEN_MAX + 1];
+         char *cell = create_cell_ref (col, row);
+         
+         msg (MW, _("Cannot convert the value in the spreadsheet cell %s to format (%s): %s"), 
+              cell, fmt_to_string (fmt, buf), m);
+         free (cell);
+       }
+      free (m);
+    }
 }
 
 struct var_spec
@@ -454,6 +500,7 @@ struct var_spec
   char *name;
   int width;
   xmlChar *first_value;
+  int first_type;
 };
 
 
@@ -649,6 +696,7 @@ gnumeric_make_reader (struct spreadsheet *spreadsheet,
       n_cases --;
     }
 
+  int type = 0;
   /* Read in the first row of cells,
      including the headers if read_names was set */
   while (
@@ -657,9 +705,29 @@ gnumeric_make_reader (struct spreadsheet *spreadsheet,
         )
     {
       int idx;
+
+      if (r->rsd.state == STATE_CELL && r->rsd.node_type == XML_READER_TYPE_TEXT)
+       {
+         xmlChar *attr =
+           xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
+
+         type  =  _xmlchar_to_int (attr);
+
+         xmlFree (attr);
+       }
+
       process_node (r, &r->rsd);
 
-      if ( r->rsd.row > r->start_row ) break;
+      if ( r->rsd.row > r->start_row ) 
+       {
+         xmlChar *attr =
+           xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
+         
+         r->vtype  =  _xmlchar_to_int (attr);
+         
+         xmlFree (attr);
+         break;
+       }
 
       if ( r->rsd.col < r->start_col ||
           (r->stop_col != -1 && r->rsd.col > r->stop_col))
@@ -676,10 +744,13 @@ gnumeric_make_reader (struct spreadsheet *spreadsheet,
            var_spec [i].name = NULL;
            var_spec [i].width = -1;
            var_spec [i].first_value = NULL;
+           var_spec [i].first_type = -1;
          }
          n_var_specs =  idx + 1 ;
        }
 
+      var_spec [idx].first_type = type;
+
       if ( r->rsd.node_type == XML_READER_TYPE_TEXT )
        {
          xmlChar *value = xmlTextReaderValue (r->rsd.xtr);
@@ -767,9 +838,12 @@ gnumeric_make_reader (struct spreadsheet *spreadsheet,
        continue;
 
       var = dict_get_var (r->dict, x++);
-
+      
       convert_xml_string_to_value (r->first_case, var,
-                                  var_spec[i].first_value);
+                                  var_spec[i].first_value, 
+                                  var_spec[i].first_type,
+                                  r->rsd.col + i - 1,
+                                  r->rsd.row - 1);
     }
 
   for ( i = 0 ; i < n_var_specs ; ++i )
@@ -828,11 +902,22 @@ gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_)
   if (r->start_col == -1)
     r->start_col = r->rsd.min_col;
 
+
   while ((r->rsd.state == STATE_CELL || r->rsd.state == STATE_CELLS_START )
         && r->rsd.row == current_row && (ret = xmlTextReaderRead (r->rsd.xtr)))
     {
       process_node (r, &r->rsd);
 
+      if (r->rsd.state == STATE_CELL && r->rsd.node_type == XML_READER_TYPE_ELEMENT)
+       {
+         xmlChar *attr =
+           xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
+
+         r->vtype  = _xmlchar_to_int (attr);
+
+         xmlFree (attr);
+       }
+
       if ( r->rsd.col < r->start_col || (r->stop_col != -1 &&
                                     r->rsd.col > r->stop_col))
        continue;
@@ -843,17 +928,17 @@ gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_)
       if ( r->stop_row != -1 && r->rsd.row > r->stop_row)
        break;
 
+
       if ( r->rsd.node_type == XML_READER_TYPE_TEXT )
        {
          xmlChar *value = xmlTextReaderValue (r->rsd.xtr);
-
          const int idx = r->rsd.col - r->start_col;
-
          const struct variable *var = dict_get_var (r->dict, idx);
 
-         convert_xml_string_to_value (c, var, value);
+         convert_xml_string_to_value (c, var, value, r->vtype, 
+                                      r->rsd.col, r->rsd.row);
 
-         free (value);
+         xmlFree (value);
        }
     }
 
index a6ca1fbe81169002e0f96486dfd3b193287a4b63..8504c14cca545033de0d074a29f45659c47258c0 100644 (file)
@@ -243,7 +243,7 @@ ods_get_sheet_range (struct spreadsheet *s, int n)
       process_node (r, or);
     }
 
-  return create_cell_ref (
+  return create_cell_range (
                          r->sheets[n].start_col,
                          r->sheets[n].start_row,
                          r->sheets[n].stop_col,
@@ -477,7 +477,7 @@ xmv_to_width (const struct xml_value *xmv, int fallback)
  */
 static void
 convert_xml_to_value (struct ccase *c, const struct variable *var,
-                     const struct xml_value *xmv)
+                     const struct xml_value *xmv, int col, int row)
 {
   union value *v = case_data_rw (c, var);
 
@@ -503,12 +503,22 @@ convert_xml_to_value (struct ccase *c, const struct variable *var,
          const char *text = xmv->value ?
            CHAR_CAST (const char *, xmv->value) : CHAR_CAST (const char *, xmv->text);
 
-
-         free (data_in (ss_cstr (text), "UTF-8",
+         char *m = data_in (ss_cstr (text), "UTF-8",
                         fmt->type,
                         v,
                         var_get_width (var),
-                        "UTF-8"));
+                        "UTF-8");
+
+         if (m)
+           {
+             char buf [FMT_STRING_LEN_MAX + 1];
+             char *cell = create_cell_ref (col, row);
+
+             msg (MW, _("Cannot convert the value in the spreadsheet cell %s to format (%s): %s"), 
+                  cell, fmt_to_string (fmt, buf), m);
+             free (cell);
+           }
+         free (m);
        }
     }
 }
@@ -865,7 +875,9 @@ ods_make_reader (struct spreadsheet *spreadsheet,
     {
       const struct variable *var = dict_get_var (r->dict, i);
 
-      convert_xml_to_value (r->first_case, var,  &var_spec[i].firstval);
+      convert_xml_to_value (r->first_case, var,  &var_spec[i].firstval,
+                           r->rsd.col - n_var_specs + i,
+                           r->rsd.row - 1);
     }
 
   /* Read in the first row of data */
@@ -989,7 +1001,7 @@ ods_file_casereader_read (struct casereader *reader UNUSED, void *r_)
                break;
 
               var = dict_get_var (r->dict, idx);
-             convert_xml_to_value (c, var, xmv);
+             convert_xml_to_value (c, var, xmv, idx + r->start_col, r->rsd.row - 1);
            }
 
          xmlFree (xmv->text);
index fc1dfa8dd5dde8d4b980ef784bf2ebc2f507f023..02e5c2d3c04b18e3cc38dcce5359ac9fbbada59d 100644 (file)
@@ -169,25 +169,34 @@ int_to_ps26 (int i)
   return ret;
 }
 
+
 char *
-create_cell_ref (int col0, int row0, int coli, int rowi)
+create_cell_ref (int col0, int row0)
 {
   char *cs0 ;
-  char *csi ;
   char *s ;
 
   if ( col0 < 0) return NULL;
-  if ( rowi < 0) return NULL;
-  if ( coli < 0) return NULL;
   if ( row0 < 0) return NULL;
 
   cs0 =  int_to_ps26 (col0);
-  csi =  int_to_ps26 (coli);
-  s =  c_xasprintf ("%s%d:%s%d",
-                        cs0, row0 + 1,
-                        csi, rowi + 1);
+  s =  c_xasprintf ("%s%d", cs0, row0 + 1);
+
   free (cs0);
-  free (csi);
+
+  return s;
+}
+
+char *
+create_cell_range (int col0, int row0, int coli, int rowi)
+{
+  char *s0 = create_cell_ref (col0, row0);
+  char *si = create_cell_ref (coli, rowi);
+
+  char *s =  c_xasprintf ("%s:%s", s0, si);
+
+  free (s0);
+  free (si);
 
   return s;
 }
index 9a46b35e9eb6a255e78403e9cfa242f6c133a754..e9656ab12d2751818abf4abf0ae2d483106b210d 100644 (file)
@@ -77,7 +77,8 @@ const char * spreadsheet_get_sheet_name (struct spreadsheet *s, int n);
 char * spreadsheet_get_sheet_range (struct spreadsheet *s, int n);
 
 
-char *create_cell_ref (int col0, int row0, int coli, int rowi);
+char * create_cell_ref (int col0, int row0);
+char *create_cell_range (int col0, int row0, int coli, int rowi);
 
 void spreadsheet_destroy (struct spreadsheet *);
 
index 8b9e9076dcd3f61abe9806e3263f309fe5af78cd..d4071cd71e0bac5cf9cf3a30cf7e2ec9dcdb8f3a 100644 (file)
@@ -340,7 +340,17 @@ psppire_cell_renderer_button_press_event (GtkButton      *button,
       /* Allow right-click events to propagate upward in the widget hierarchy.
          Otherwise right-click menus, that trigger on a button-press-event on
          the containing PsppSheetView, will pop up if the button is rendered as
-         a facade but not if the button widget exists.  */
+         a facade but not if the button widget exists.
+
+         We have to translate the event's data by hand to be relative to the
+         parent window, because the normal GObject signal propagation mechanism
+         won't do it for us.  (This might be a hint that we're doing this
+         wrong.) */
+      gint x, y;
+
+      gdk_window_get_position (event->window, &x, &y);
+      event->x += x;
+      event->y += y;
       g_signal_stop_emission_by_name (button, "button-press-event");
       return FALSE;
     }
index 28b9686c863b4b64efba5bc8b3bf3967633f8a8a..3ca0d8b93608f1c458e75ae1e1b029db48a966ed 100644 (file)
@@ -87,8 +87,7 @@ GET DATA /TYPE=$1 /FILE='testsheet' /SHEET=index 3.
 DISPLAY VARIABLES.
 LIST.
 ])
-AT_CHECK([pspp -o pspp.csv get-data.sps])
-AT_CHECK([cat pspp.csv], [0], [dnl
+AT_CHECK([pspp -O format=csv get-data.sps], [0], [dnl
 Variable,Description,,Position
 name,Format: A8,,1
 ,Measure: Nominal,,
@@ -103,6 +102,8 @@ height,Format: F8.2,,3
 ,Display Alignment: Right,,
 ,Display Width: 8,,
 
+warning: Cannot convert the value in the spreadsheet cell C4 to format (F8.2): Field contents are not numeric.
+
 Table: Data List
 name,id,height
 fred    ,.00,23.40