Merge remote branch 'origin/master' into import-gui
authorJohn Darrington <john@darrington.wattle.id.au>
Sat, 30 Mar 2013 08:18:25 +0000 (09:18 +0100)
committerJohn Darrington <john@darrington.wattle.id.au>
Sat, 30 Mar 2013 08:18:25 +0000 (09:18 +0100)
src/data/casereader.c
src/data/ods-reader.c
src/ui/gui/automake.mk
src/ui/gui/page-assistant.c
src/ui/gui/page-file.c
src/ui/gui/page-sheet-spec.c [new file with mode: 0644]
src/ui/gui/page-sheet-spec.h [new file with mode: 0644]
src/ui/gui/text-data-import-dialog.c
src/ui/gui/text-data-import.ui

index c8050c6cde4c7b2a35d6d2b45aa752c3ecbee1e8..5695d7cfa8d7665be98ab8d8c4031b7a698fbb02 100644 (file)
@@ -1,4 +1,4 @@
-/* PSPP - a program for statistical analysis.
+/* pspp - a program for statistical analysis.
    Copyright (C) 2007, 2009, 2010, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -239,13 +239,12 @@ static casenumber
 casereader_count_cases__ (const struct casereader *reader,
                           casenumber max_cases)
 {
-  struct casereader *clone;
-  casenumber n_cases;
-
-  clone = casereader_clone (reader);
-  n_cases = casereader_advance (clone, max_cases);
-  casereader_destroy (clone);
-
+  struct casereader *clone = casereader_clone (reader);
+  casenumber n_cases = casereader_advance (clone, max_cases);
+#if (__GNUC__ == 4 ) && (__GNUC_MINOR__ == 4)
+  // volatile int x = 1;
+#endif
+  //  casereader_destroy (clone);
   return n_cases;
 }
 
index b3586b82ec8b7817d77f3f5dffcaf0bde6fd87f5..5363d40fe4e5df6ae3eafb134a1b9f6c9b5e0483 100644 (file)
@@ -100,31 +100,35 @@ enum reader_state
     STATE_CELL_CONTENT     /* Found a the text within a cell */
   };
 
-struct ods_reader
+struct state_data
 {
-  struct spreadsheet spreadsheet;
-  struct zip_reader *zreader;
   xmlTextReaderPtr xtr;
-  int ref_cnt;
-
+  int node_type;
   enum reader_state state;
   int row;
   int col;
-  int node_type;
   int current_sheet;
   xmlChar *current_sheet_name;
 
-  xmlChar *target_sheet_name;
-  int target_sheet_index;
+  int col_span;
+};
 
+struct ods_reader              /*  */
+{
+  struct spreadsheet spreadsheet;
+  struct zip_reader *zreader;
+  int ref_cnt;
+  int target_sheet_index;
+  xmlChar *target_sheet_name;
+  
+  struct state_data foo;
+  struct state_data rsd;
 
   int start_row;
   int start_col;
   int stop_row;
   int stop_col;
 
-  int col_span;
-
   struct sheet_detail *sheets;
   int n_allocated_sheets;
 
@@ -140,6 +144,7 @@ struct ods_reader
 void
 ods_destroy (struct spreadsheet *s)
 {
+#if 0
   struct ods_reader *r = (struct ods_reader *) s;
 
   if (--r->ref_cnt == 0)
@@ -155,38 +160,40 @@ ods_destroy (struct spreadsheet *s)
       free (r->sheets);
       free (r);
     }
+#endif
 }
 
 
 
 static bool
-reading_target_sheet (const struct ods_reader *r)
+reading_target_sheet (const struct ods_reader *r, const struct state_data *foo)
 {
   if (r->target_sheet_name != NULL)
     {
-      if ( 0 == xmlStrcmp (r->target_sheet_name, r->current_sheet_name))
+      if ( 0 == xmlStrcmp (r->target_sheet_name, foo->current_sheet_name))
        return true;
     }
   
-  if (r->target_sheet_index == r->current_sheet + 1)
+  if (r->target_sheet_index == foo->current_sheet + 1)
     return true;
 
   return false;
 }
 
 
-static void process_node (struct ods_reader *r);
+static void process_node (struct ods_reader *or, struct state_data *r);
 
 
 const char *
 ods_get_sheet_name (struct spreadsheet *s, int n)
 {
-  struct ods_reader *or = (struct ods_reader *) s;
-  
+  struct ods_reader *r = (struct ods_reader *) s;
+  struct state_data *or = &r->foo;
+
   assert (n < s->n_sheets);
 
   while ( 
-         (or->n_allocated_sheets <= n)
+         (r->n_allocated_sheets <= n)
          || or->state != STATE_SPREADSHEET
          )
     {
@@ -194,22 +201,23 @@ ods_get_sheet_name (struct spreadsheet *s, int n)
       if ( ret != 1)
        break;
 
-      process_node (or);
+      process_node (r, or);
     }
 
-  return or->sheets[n].name;
+  return r->sheets[n].name;
 }
 
 char *
 ods_get_sheet_range (struct spreadsheet *s, int n)
 {
-  struct ods_reader *or = (struct ods_reader *) s;
+  struct ods_reader *r = (struct ods_reader *) s;
+  struct state_data *or = &r->foo;
   
   assert (n < s->n_sheets);
 
   while ( 
-         (or->n_allocated_sheets <= n)
-         || (or->sheets[n].stop_row == -1) 
+         (r->n_allocated_sheets <= n)
+         || (r->sheets[n].stop_row == -1) 
          || or->state != STATE_SPREADSHEET
          )
     {
@@ -217,20 +225,21 @@ ods_get_sheet_range (struct spreadsheet *s, int n)
       if ( ret != 1)
        break;
 
-      process_node (or);
+      process_node (r, or);
     }
 
   return create_cell_ref (
-                         or->sheets[n].start_col,
-                         or->sheets[n].start_row,
-                         or->sheets[n].stop_col,
-                         or->sheets[n].stop_row);
+                         r->sheets[n].start_col,
+                         r->sheets[n].start_row,
+                         r->sheets[n].stop_col,
+                         r->sheets[n].stop_row);
 }
 
 
 static void
 ods_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
 {
+#if 0
   struct ods_reader *r = r_;
   if ( r == NULL)
     return ;
@@ -253,6 +262,7 @@ ods_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
   xmlFree (r->target_sheet_name);
 
   ods_destroy (&r->spreadsheet);
+#endif
 }
 
 
@@ -260,7 +270,7 @@ ods_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
 
 
 static void
-process_node (struct ods_reader *r)
+process_node (struct ods_reader *or, struct state_data *r)
 {
   xmlChar *name = xmlTextReaderName (r->xtr);
   if (name == NULL)
@@ -290,15 +300,15 @@ process_node (struct ods_reader *r)
 
          ++r->current_sheet;
 
-         if (r->current_sheet >= r->n_allocated_sheets)
+         if (r->current_sheet >= or->n_allocated_sheets)
            {
-             assert (r->current_sheet == r->n_allocated_sheets);
-             r->sheets = xrealloc (r->sheets, sizeof (*r->sheets) * ++r->n_allocated_sheets);
-             r->sheets[r->n_allocated_sheets - 1].start_col = -1;
-             r->sheets[r->n_allocated_sheets - 1].stop_col = -1;
-             r->sheets[r->n_allocated_sheets - 1].start_row = -1;
-             r->sheets[r->n_allocated_sheets - 1].stop_row = -1;
-             r->sheets[r->n_allocated_sheets - 1].name = CHAR_CAST (char *, xmlStrdup (r->current_sheet_name));
+             assert (r->current_sheet == or->n_allocated_sheets);
+             or->sheets = xrealloc (or->sheets, sizeof (*or->sheets) * ++or->n_allocated_sheets);
+             or->sheets[or->n_allocated_sheets - 1].start_col = -1;
+             or->sheets[or->n_allocated_sheets - 1].stop_col = -1;
+             or->sheets[or->n_allocated_sheets - 1].start_row = -1;
+             or->sheets[or->n_allocated_sheets - 1].stop_row = -1;
+             or->sheets[or->n_allocated_sheets - 1].name = CHAR_CAST (char *, xmlStrdup (r->current_sheet_name));
            }
 
          r->col = 0;
@@ -379,22 +389,22 @@ process_node (struct ods_reader *r)
       break;
     case STATE_CELL_CONTENT:
       assert (r->current_sheet >= 0);
-      assert (r->current_sheet < r->n_allocated_sheets);
+      assert (r->current_sheet < or->n_allocated_sheets);
 
-      if (r->sheets[r->current_sheet].start_row == -1)
-       r->sheets[r->current_sheet].start_row = r->row - 1;
+      if (or->sheets[r->current_sheet].start_row == -1)
+       or->sheets[r->current_sheet].start_row = r->row - 1;
 
       if ( 
-         (r->sheets[r->current_sheet].start_col == -1)
+         (or->sheets[r->current_sheet].start_col == -1)
          ||
-         (r->sheets[r->current_sheet].start_col >= r->col - 1)
+         (or->sheets[r->current_sheet].start_col >= r->col - 1)
           )
-       r->sheets[r->current_sheet].start_col = r->col - 1;
+       or->sheets[r->current_sheet].start_col = r->col - 1;
 
-      r->sheets[r->current_sheet].stop_row = r->row - 1;
+      or->sheets[r->current_sheet].stop_row = r->row - 1;
 
-      if ( r->sheets[r->current_sheet].stop_col <  r->col - 1)
-       r->sheets[r->current_sheet].stop_col = r->col - 1;
+      if ( or->sheets[r->current_sheet].stop_col <  r->col - 1)
+       or->sheets[r->current_sheet].stop_col = r->col - 1;
 
       if (XML_READER_TYPE_END_ELEMENT  == r->node_type)
        r->state = STATE_CELL;
@@ -480,11 +490,11 @@ convert_xml_to_value (struct ccase *c, const struct variable *var,
            CHAR_CAST (const char *, xmv->value) : CHAR_CAST (const char *, xmv->text);
 
 
-         free (data_in (ss_cstr (text), "UTF-8",
+         data_in (ss_cstr (text), "UTF-8",
                         fmt->type,
                         v,
                         var_get_width (var),
-                        "UTF-8"));
+                        "UTF-8");
        }
     }
 }
@@ -543,38 +553,31 @@ ods_error_handler (void *ctx, const char *mesg,
 }
 
 
-static bool
+static xmlTextReaderPtr
 init_reader (struct ods_reader *r, bool report_errors)
 {
   struct zip_member *content = zip_member_open (r->zreader, "content.xml");
   xmlTextReaderPtr xtr;
 
   if ( content == NULL)
-    return false;
-
-  if (r->xtr)
-    xmlFreeTextReader (r->xtr);
+    return NULL;
 
   zip_member_ref (content);
   xtr = xmlReaderForIO ((xmlInputReadCallback) zip_member_read,
-                       (xmlInputCloseCallback) zip_member_finish,
+                       (xmlInputCloseCallback) NULL,
                        content,   NULL, NULL,
                        report_errors ? 0 : (XML_PARSE_NOERROR | XML_PARSE_NOWARNING) );
 
   if ( xtr == NULL)
     return false;
 
-  r->xtr = xtr;
+
   r->spreadsheet.type = SPREADSHEET_ODS;
-  r->row = 0;
-  r->col = 0;
-  r->current_sheet = 0;
-  r->state = STATE_INIT;
 
   if (report_errors) 
     xmlTextReaderSetErrorHandler (xtr, ods_error_handler, r);
 
-  return true;
+  return xtr;
 }
 
 
@@ -585,6 +588,7 @@ ods_probe (const char *filename, bool report_errors)
   struct string errs = DS_EMPTY_INITIALIZER;
   int sheet_count;
   struct zip_reader *zr = zip_reader_create (filename, &errs);
+  xmlTextReaderPtr xtr;
 
   if (zr == NULL)
     {
@@ -602,10 +606,17 @@ ods_probe (const char *filename, bool report_errors)
   r->zreader = zr;
   r->ref_cnt = 1;
 
-  if (! init_reader (r, report_errors))
+  xtr = init_reader (r, report_errors);
+  if (xtr == NULL)
     {
       goto error;
     }
+  r->foo.xtr = xtr;
+  r->foo.row = 0;
+  r->foo.col = 0;
+  r->foo.current_sheet = 0;
+  r->foo.state = STATE_INIT;
+
 
   r->spreadsheet.n_sheets = sheet_count;
   r->n_allocated_sheets = 0;
@@ -634,6 +645,7 @@ ods_make_reader (struct spreadsheet *spreadsheet,
   int i;
   struct var_spec *var_spec = NULL;
   int n_var_specs = 0;
+  xmlTextReaderPtr xtr;
 
   struct ods_reader *r = (struct ods_reader *) spreadsheet;
   xmlChar *val_string = NULL;
@@ -643,9 +655,17 @@ ods_make_reader (struct spreadsheet *spreadsheet,
   ds_init_empty (&r->ods_errs);
   ++r->ref_cnt;
 
-  if ( !init_reader (r, true))
+  xtr = init_reader (r, true);
+  if ( xtr == NULL)
     goto error;
 
+  r->rsd.xtr = xtr;
+  r->rsd.row = 0;
+  r->rsd.col = 0;
+  r->rsd.current_sheet = 0;
+  r->rsd.state = STATE_INIT;
+
+
   if (opts->cell_range)
     {
       if ( ! convert_cell_ref (opts->cell_range,
@@ -665,20 +685,17 @@ ods_make_reader (struct spreadsheet *spreadsheet,
       r->stop_row = -1;
     }
 
-  r->state = STATE_INIT;
   r->target_sheet_name = xmlStrdup (BAD_CAST opts->sheet_name);
   r->target_sheet_index = opts->sheet_index;
-  r->row = r->col = 0;
-
 
   /* Advance to the start of the cells for the target sheet */
-  while ( ! reading_target_sheet (r)  
-         || r->state != STATE_ROW || r->row <= r->start_row )
+  while ( ! reading_target_sheet (r, &r->rsd)  
+         || r->rsd.state != STATE_ROW || r->rsd.row <= r->start_row )
     {
-      if (1 != (ret = xmlTextReaderRead (r->xtr)))
+      if (1 != (ret = xmlTextReaderRead (r->rsd.xtr)))
           break;
 
-      process_node (r);
+      process_node (r, &r->rsd);
     }
 
   if (ret < 1)
@@ -690,17 +707,17 @@ ods_make_reader (struct spreadsheet *spreadsheet,
 
   if ( opts->read_names)
     {
-      while (1 == (ret = xmlTextReaderRead (r->xtr)))
+      while (1 == (ret = xmlTextReaderRead (r->rsd.xtr)))
        {
          int idx;
 
-         process_node (r);
+         process_node (r, &r->rsd);
 
          /* If the row is finished then stop for now */
-         if (r->state == STATE_TABLE && r->row > r->start_row)
+         if (r->rsd.state == STATE_TABLE && r->rsd.row > r->start_row)
            break;
 
-         idx = r->col - r->start_col -1 ;
+         idx = r->rsd.col - r->start_col -1 ;
 
          if ( idx < 0)
            continue;
@@ -708,11 +725,11 @@ ods_make_reader (struct spreadsheet *spreadsheet,
          if (r->stop_col != -1 && idx > r->stop_col - r->start_col)
            continue;
 
-         if (r->state == STATE_CELL_CONTENT 
+         if (r->rsd.state == STATE_CELL_CONTENT 
              &&
-             XML_READER_TYPE_TEXT  == r->node_type)
+             XML_READER_TYPE_TEXT  == r->rsd.node_type)
            {
-             xmlChar *value = xmlTextReaderValue (r->xtr);
+             xmlChar *value = xmlTextReaderValue (r->rsd.xtr);
 
              if ( idx >= n_var_specs)
                {
@@ -736,35 +753,35 @@ ods_make_reader (struct spreadsheet *spreadsheet,
     }
 
   /* Read in the first row of data */
-  while (1 == xmlTextReaderRead (r->xtr))
+  while (1 == xmlTextReaderRead (r->rsd.xtr))
     {
       int idx;
-      process_node (r);
+      process_node (r, &r->rsd);
 
-      if ( ! reading_target_sheet (r) )
+      if ( ! reading_target_sheet (r, &r->rsd) )
        break;
 
       /* If the row is finished then stop for now */
-      if (r->state == STATE_TABLE &&
-         r->row > r->start_row + (opts->read_names ? 1 : 0))
+      if (r->rsd.state == STATE_TABLE &&
+         r->rsd.row > r->start_row + (opts->read_names ? 1 : 0))
        break;
 
-      idx = r->col - r->start_col - 1;
+      idx = r->rsd.col - r->start_col - 1;
       if (idx < 0)
        continue;
 
       if (r->stop_col != -1 && idx > r->stop_col - r->start_col)
        continue;
 
-      if ( r->state == STATE_CELL &&
-          XML_READER_TYPE_ELEMENT  == r->node_type)
+      if ( r->rsd.state == STATE_CELL &&
+          XML_READER_TYPE_ELEMENT  == r->rsd.node_type)
        {
-         type = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value-type"));
-         val_string = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value"));
+         type = xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("office:value-type"));
+         val_string = xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("office:value"));
        }
 
-      if ( r->state == STATE_CELL_CONTENT &&
-          XML_READER_TYPE_TEXT  == r->node_type)
+      if ( r->rsd.state == STATE_CELL_CONTENT &&
+          XML_READER_TYPE_TEXT  == r->rsd.node_type)
        {
          if (idx >= n_var_specs)
            {
@@ -778,7 +795,7 @@ ods_make_reader (struct spreadsheet *spreadsheet,
            }
 
          var_spec [idx].firstval.type = type;
-         var_spec [idx].firstval.text = xmlTextReaderValue (r->xtr);
+         var_spec [idx].firstval.text = xmlTextReaderValue (r->rsd.xtr);
          var_spec [idx].firstval.value = val_string;
 
          val_string = NULL;
@@ -789,7 +806,7 @@ ods_make_reader (struct spreadsheet *spreadsheet,
 
   /* Create the dictionary and populate it */
   r->spreadsheet.dict = r->dict = dict_create (
-    CHAR_CAST (const char *, xmlTextReaderConstEncoding (r->xtr)));
+    CHAR_CAST (const char *, xmlTextReaderConstEncoding (r->rsd.xtr)));
 
   for (i = 0; i < n_var_specs ; ++i )
     {
@@ -836,11 +853,11 @@ ods_make_reader (struct spreadsheet *spreadsheet,
     }
 
   /* Read in the first row of data */
-  while (1 == xmlTextReaderRead (r->xtr))
+  while (1 == xmlTextReaderRead (r->rsd.xtr))
     {
-      process_node (r);
+      process_node (r, &r->rsd);
 
-      if (r->state == STATE_ROW)
+      if (r->rsd.state == STATE_ROW)
        break;
     }
 
@@ -888,8 +905,6 @@ static struct ccase *
 ods_file_casereader_read (struct casereader *reader UNUSED, void *r_)
 {
   struct ccase *c = NULL;
-  xmlChar *val_string = NULL;
-  xmlChar *type = NULL;
   struct ods_reader *r = r_;
 
   if (!r->used_first_case)
@@ -900,17 +915,17 @@ ods_file_casereader_read (struct casereader *reader UNUSED, void *r_)
 
 
   /* Advance to the start of a row. (If there is one) */
-  while (r->state != STATE_ROW 
-        && 1 == xmlTextReaderRead (r->xtr)
+  while (r->rsd.state != STATE_ROW 
+        && 1 == xmlTextReaderRead (r->rsd.xtr)
         )
     {
-      process_node (r);
+      process_node (r, &r->rsd);
     }
 
 
-  if ( ! reading_target_sheet (r)  
-       ||  r->state < STATE_TABLE
-       ||  (r->stop_row != -1 && r->row > r->stop_row + 1)
+  if ( ! reading_target_sheet (r, &r->rsd)  
+       ||  r->rsd.state < STATE_TABLE
+       ||  (r->stop_row != -1 && r->rsd.row > r->stop_row + 1)
        )
     {
       return NULL;
@@ -919,34 +934,37 @@ ods_file_casereader_read (struct casereader *reader UNUSED, void *r_)
   c = case_create (r->proto);
   case_set_missing (c);
   
-  while (1 == xmlTextReaderRead (r->xtr))
+  xmlChar *val_string = NULL;
+  xmlChar *type = NULL;
+
+  while (1 == xmlTextReaderRead (r->rsd.xtr))
     {
-      process_node (r);
+      process_node (r, &r->rsd);
 
-      if ( r->stop_row != -1 && r->row > r->stop_row + 1)
+      if ( r->stop_row != -1 && r->rsd.row > r->stop_row + 1)
        break;
 
-      if (r->state == STATE_CELL &&
-          r->node_type == XML_READER_TYPE_ELEMENT)
+      if (r->rsd.state == STATE_CELL &&
+          r->rsd.node_type == XML_READER_TYPE_ELEMENT)
        {
-         type = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value-type"));
-         val_string = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value"));
+         type = xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("office:value-type"));
+         val_string = xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("office:value"));
        }
 
-      if (r->state == STATE_CELL_CONTENT && 
-          r->node_type == XML_READER_TYPE_TEXT)
+      if (r->rsd.state == STATE_CELL_CONTENT && 
+          r->rsd.node_type == XML_READER_TYPE_TEXT)
        {
          int col;
          struct xml_value *xmv = xzalloc (sizeof *xmv);
-         xmv->text = xmlTextReaderValue (r->xtr);
+         xmv->text = xmlTextReaderValue (r->rsd.xtr);
          xmv->value = val_string;       
          xmv->type = type;
          val_string = NULL;
 
-         for (col = 0; col < r->col_span; ++col)
+         for (col = 0; col < r->rsd.col_span; ++col)
            {
              const struct variable *var;
-             const int idx = r->col - col - r->start_col - 1;
+             const int idx = r->rsd.col - col - r->start_col - 1;
              if (idx < 0)
                continue;
              if (r->stop_col != -1 && idx > r->stop_col - r->start_col )
@@ -963,7 +981,7 @@ ods_file_casereader_read (struct casereader *reader UNUSED, void *r_)
          xmlFree (xmv->type);
          free (xmv);
        }
-      if ( r->state <= STATE_TABLE)
+      if ( r->rsd.state <= STATE_TABLE)
        break;
     }
 
index e29e30bb711a337605c2974d73c428b656eff061..941a7fea1c2690b36840188c13d19f3933ee7ed7 100644 (file)
@@ -328,6 +328,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/page-formats.h \
        src/ui/gui/page-separators.c \
        src/ui/gui/page-separators.h \
+       src/ui/gui/page-sheet-spec.c \
+       src/ui/gui/page-sheet-spec.h \
        src/ui/gui/text-data-import-dialog.c \
        src/ui/gui/text-data-import-dialog.h \
        src/ui/gui/transpose-dialog.c \
index 88314734e2d82845a82d965b3c859d3657d8d3b0..cad23763de75dcbb99834074ee6d4e40d9e26374 100644 (file)
@@ -160,10 +160,12 @@ on_prepare (GtkAssistant *assistant, GtkWidget *page,
   if ( ia->spreadsheet) 
     {
       if (pn == 0)
-      {
-      }
+       {
+         prepare_sheet_spec_page (ia);
+        }
       else if (pn == 1)
        {
+         post_sheet_spec_page (ia);
          prepare_formats_page (ia);
        }
     }
@@ -230,6 +232,8 @@ on_reset (GtkButton *button, struct import_assistant *ia)
     reset_separators_page (ia);
   else if (page == assist_get_page ((struct assist_page *) ia->formats))
     reset_formats_page (ia);
+  else if (page == assist_get_page ((struct assist_page *) ia->sheet_spec))
+    reset_sheet_spec_page (ia);
 }
 
 /* Causes the assistant to close, returning RESPONSE for
index 2dd9f9ca1616670dec965af3311feb392dc11260..84b7928a27645689afc37a04a6268edbb1de33ff 100644 (file)
@@ -230,6 +230,21 @@ choose_file (GtkWindow *parent_window, gchar **encodingp)
   gtk_file_filter_add_mime_type (filter, "text/tab-separated-values");
   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
 
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("Gnumeric Spreadsheet Files"));
+  gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("OpenDocument Spreadsheet Files"));
+  gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("All Spreadsheet Files"));
+  gtk_file_filter_add_mime_type (filter, "application/x-gnumeric");
+  gtk_file_filter_add_mime_type (filter, "application/vnd.oasis.opendocument.spreadsheet");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
 
   gtk_file_chooser_set_extra_widget (
     GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
diff --git a/src/ui/gui/page-sheet-spec.c b/src/ui/gui/page-sheet-spec.c
new file mode 100644 (file)
index 0000000..3d92bfe
--- /dev/null
@@ -0,0 +1,305 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2013  Free Software Foundation
+
+   This program 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.
+
+   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "page-sheet-spec.h"
+
+#include "ui/gui/text-data-import-dialog.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <gtk-contrib/psppire-sheet.h>
+#include <gtk/gtk.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "data/data-in.h"
+#include "data/data-out.h"
+#include "data/format-guesser.h"
+#include "data/value-labels.h"
+#include "data/gnumeric-reader.h"
+#include "data/ods-reader.h"
+#include "data/spreadsheet-reader.h"
+#include "language/data-io/data-parser.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/i18n.h"
+#include "libpspp/line-reader.h"
+#include "libpspp/message.h"
+#include "ui/gui/checkbox-treeview.h"
+#include "ui/gui/dialog-common.h"
+#include "ui/gui/executor.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/builder-wrapper.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dialog.h"
+#include "ui/gui/psppire-encoding-selector.h"
+#include "ui/gui/psppire-empty-list-store.h"
+#include "ui/gui/psppire-var-sheet.h"
+#include "ui/gui/psppire-var-store.h"
+#include "ui/gui/psppire-scanf.h"
+#include "ui/syntax-gen.h"
+
+#include "ui/gui/psppire-spreadsheet-model.h"
+
+#include <data/casereader.h>
+
+#include "gl/error.h"
+#include "gl/intprops.h"
+#include "gl/xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+struct import_assistant;
+
+/* The "sheet-spec" page of the assistant. */
+
+/* The sheet_spec page of the assistant (only relevant for spreadsheet imports). */
+struct sheet_spec_page
+  {
+    GtkWidget *page;
+    struct casereader *reader;
+    struct dictionary *dict;
+    
+    struct spreadsheet_read_options opts;
+  };
+
+
+char *
+sheet_spec_gen_syntax (const struct import_assistant *ia)
+{
+  const struct sheet_spec_page *ssp = ia->sheet_spec;
+  GtkBuilder *builder = ia->asst.builder;
+  GtkWidget *range_entry = get_widget_assert (builder, "cell-range-entry");
+  const gchar *range = gtk_entry_get_text (GTK_ENTRY (range_entry));
+
+  struct string s = DS_EMPTY_INITIALIZER;
+
+  syntax_gen_pspp (&s,
+                  "GET DATA"
+                  "\n  /TYPE=%ss"
+                  "\n  /FILE=%sq"
+                  "\n  /SHEET=index %d"
+                  "\n  /READNAMES=%ss",
+                  (ia->spreadsheet->type == SPREADSHEET_GNUMERIC) ? "GNM" : "ODS",
+                  ia->file.file_name,                   
+                  ssp->opts.sheet_index,
+                  ssp->opts.read_names ? "ON" : "OFF");
+
+
+  if (range && 0 != strcmp ("", range))
+    {
+      syntax_gen_pspp (&s,
+                      "\n  /CELLRANGE=RANGE %sq", range);
+    }
+  else
+    {
+      syntax_gen_pspp (&s,
+                      "\n  /CELLRANGE=FULL");
+    }
+
+
+  syntax_gen_pspp (&s, ".");
+
+  
+  return ds_cstr (&s);
+}
+
+
+static void 
+on_sheet_combo_changed (GtkComboBox *cb, struct import_assistant *ia)
+{
+  GtkTreeIter iter;
+  gchar *range = NULL;
+  GtkTreeModel *model = gtk_combo_box_get_model (cb);
+  GtkBuilder *builder = ia->asst.builder;
+  GtkWidget *range_entry = get_widget_assert (builder, "cell-range-entry");
+
+  gtk_combo_box_get_active_iter (cb, &iter);
+  gtk_tree_model_get (model, &iter, PSPPIRE_SPREADSHEET_MODEL_COL_RANGE, &range, -1);
+  gtk_entry_set_text (GTK_ENTRY (range_entry), range ?  range : "");
+  g_free (range);
+}
+
+/* Initializes IA's sheet_spec substructure. */
+struct sheet_spec_page *
+sheet_spec_page_create (struct import_assistant *ia)
+{
+  GtkBuilder *builder = ia->asst.builder;
+  struct sheet_spec_page *p = xzalloc (sizeof (*p));
+
+  GtkWidget *combo_box = get_widget_assert (builder, "sheet-entry");
+  GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
+                                 "text", 0,
+                                 NULL);
+
+  g_signal_connect (combo_box, "changed", G_CALLBACK (on_sheet_combo_changed), ia);
+
+  add_page_to_assistant (ia, get_widget_assert (builder, "Sheet"),
+                        GTK_ASSISTANT_PAGE_INTRO);
+
+  return p;
+}
+
+/* Prepares IA's sheet_spec page. */
+void
+prepare_sheet_spec_page (struct import_assistant *ia)
+{
+  GtkBuilder *builder = ia->asst.builder;
+  GtkWidget *sheet_entry = get_widget_assert (builder, "sheet-entry");
+
+  gtk_combo_box_set_model (GTK_COMBO_BOX (sheet_entry), 
+                          psppire_spreadsheet_model_new (ia->spreadsheet));
+
+  gtk_combo_box_set_active (GTK_COMBO_BOX (sheet_entry), 0);
+}
+
+
+/* Resets IA's sheet_spec page to its initial state. */
+void
+reset_sheet_spec_page (struct import_assistant *ia)
+{
+  printf ("%s\n", __FUNCTION__);
+}
+
+/* Called when the Forward button is clicked, 
+   but before displaying the new page.
+*/
+void
+post_sheet_spec_page (struct import_assistant *ia)
+{
+  int row_start = -1;
+  int row_stop = -1;
+  int col_start = -1;
+  int col_stop = -1;
+
+  GtkBuilder *builder = ia->asst.builder;
+
+  struct sheet_spec_page *ssp = ia->sheet_spec;
+  struct casereader *creader = NULL;
+  struct dictionary *dict = NULL;
+
+  GtkWidget *readnames_checkbox = get_widget_assert (builder, "readnames-checkbox");
+  GtkWidget *range_entry = get_widget_assert (builder, "cell-range-entry");
+  const gchar *range = gtk_entry_get_text (GTK_ENTRY (range_entry));
+  GtkWidget *combo_box = get_widget_assert (builder, "sheet-entry");
+
+  gint num = gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box));
+  
+  ssp->opts.sheet_name = NULL;
+  ssp->opts.cell_range = NULL;
+  ssp->opts.sheet_index = num + 1;
+
+  if ( convert_cell_ref (range, &col_start, &row_start, &col_stop, &row_stop))
+    {
+      ssp->opts.cell_range = range;
+    }
+
+  ssp->opts.read_names = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (readnames_checkbox));
+  ssp->opts.asw = -1;
+
+  switch (ia->spreadsheet->type)
+    {
+    case SPREADSHEET_ODS:
+    case SPREADSHEET_GNUMERIC:
+      {
+       creader = spreadsheet_make_reader (ia->spreadsheet, &ssp->opts);
+       dict = ia->spreadsheet->dict;
+      }
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+  ssp->dict = dict;
+  ssp->reader = creader;
+
+  if (creader && dict)
+    {
+      update_assistant (ia);
+    }
+  else
+    {
+      GtkWidget * dialog = gtk_message_dialog_new (NULL,
+                             GTK_DIALOG_MODAL,
+                             GTK_MESSAGE_ERROR,
+                             GTK_BUTTONS_CLOSE,
+                             _("An error occurred reading the spreadsheet file."));
+
+      gtk_dialog_run (GTK_DIALOG (dialog));
+      gtk_widget_destroy (dialog);
+    }
+}
+
+
+/*
+  Update IA according to the contents of DICT and CREADER.
+  CREADER will be destroyed by this function.
+*/
+void 
+update_assistant (struct import_assistant *ia)
+{
+  struct sheet_spec_page *ssp = ia->sheet_spec;
+  int rows = 0;
+
+  if (ssp->dict)
+    {
+      struct ccase *c;
+      int col;
+
+      ia->column_cnt = dict_get_var_cnt (ssp->dict);
+      ia->columns = xcalloc (ia->column_cnt, sizeof (*ia->columns));
+      for (col = 0; col < ia->column_cnt ; ++col)
+       {
+         const struct variable *var = dict_get_var (ssp->dict, col);
+         ia->columns[col].name = xstrdup (var_get_name (var));
+         ia->columns[col].contents = NULL;
+       }
+
+      for (; (c = casereader_read (ssp->reader)) != NULL; case_unref (c))
+       {
+         rows++;
+         for (col = 0; col < ia->column_cnt ; ++col)
+           {
+             char *ss;
+             const struct variable *var = dict_get_var (ssp->dict, col);
+             
+             ia->columns[col].contents = xrealloc (ia->columns[col].contents,
+                                                   sizeof (struct substring) * rows);
+             
+             ss = data_out (case_data (c, var), dict_get_encoding (ssp->dict), 
+                            var_get_print_format (var));
+             
+             ia->columns[col].contents[rows - 1] = ss_cstr (ss);
+           }
+         
+         if (rows > MAX_PREVIEW_LINES)
+           {
+             case_unref (c);
+             break;
+           }
+       }
+    }
+  
+  ia->file.line_cnt = rows;
+}
diff --git a/src/ui/gui/page-sheet-spec.h b/src/ui/gui/page-sheet-spec.h
new file mode 100644 (file)
index 0000000..7a4e801
--- /dev/null
@@ -0,0 +1,30 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2013  Free Software Foundation
+
+   This program 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.
+
+   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef PAGE_SHEET_SPEC
+#define PAGE_SHEET_SPEC 1
+
+
+struct sheet_spec_page ;
+struct import_assistant;
+
+/* Initializes IA's sheet_spec substructure. */
+struct sheet_spec_page *sheet_spec_page_create (struct import_assistant *ia);
+
+char *sheet_spec_gen_syntax (const struct import_assistant *ia);
+
+
+#endif
index 20bac652ccab69c153e753e2f4684b0922e4114a..d24a23242d7a03810de1fff1545cbd679d82767d 100644 (file)
@@ -19,6 +19,7 @@
 #include "ui/gui/text-data-import-dialog.h"
 
 #include "page-intro.h"
+#include "page-sheet-spec.h"
 #include "page-first-line.h"
 #include "page-separators.h"
 #include "page-formats.h"
@@ -77,6 +78,7 @@ text_data_import_assistant (PsppireDataWindow *dw)
 {
   GtkWindow *parent_window = GTK_WINDOW (dw);
   struct import_assistant *ia = init_assistant (parent_window);
+  struct sheet_spec_page *ssp ;
 
   if (!init_file (ia, parent_window))
     {
@@ -84,7 +86,13 @@ text_data_import_assistant (PsppireDataWindow *dw)
       return;
     }
 
+  ssp = ia->sheet_spec;
 
+  if (ia->spreadsheet)
+    {
+      ia->sheet_spec = sheet_spec_page_create (ia);
+    }
+  else
     {
       ia->intro = intro_page_create (ia);
       ia->first_line = first_line_page_create (ia);
@@ -123,6 +131,7 @@ text_data_import_assistant (PsppireDataWindow *dw)
       break;
     }
 
+  if (ssp) 
     {
       destroy_formats_page (ia);
       destroy_separators_page (ia);
@@ -223,6 +232,7 @@ generate_syntax (const struct import_assistant *ia)
 {
   struct string s = DS_EMPTY_INITIALIZER;
 
+  if (ia->spreadsheet == NULL)
     {
       syntax_gen_pspp (&s,
                       "GET DATA"
@@ -232,7 +242,6 @@ generate_syntax (const struct import_assistant *ia)
       if (ia->file.encoding && strcmp (ia->file.encoding, "Auto"))
        syntax_gen_pspp (&s, "  /ENCODING=%sq\n", ia->file.encoding);
 
-
       intro_append_syntax (ia->intro, &s);
 
 
@@ -245,7 +254,11 @@ generate_syntax (const struct import_assistant *ia)
       formats_append_syntax (ia, &s);
       apply_dict (ia->dict, &s);
     }
-
+  else
+    {
+      return sheet_spec_gen_syntax (ia);
+    }
+  
   return ds_cstr (&s);
 }
 
index d8a33d118a39beec98546e09147e42308a6b5ae6..a7a393ea115c251407f77b19e22010805a5ce624 100644 (file)
@@ -653,17 +653,140 @@ The selected file contains N lines of text.  Only the first M of these will be s
       </object>
     </child>
   </object>
-  <object class="GtkAdjustment" id="adjustment1">
-    <property name="value">100</property>
-    <property name="lower">1</property>
-    <property name="upper">100</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">10</property>
-  </object>
-  <object class="GtkAdjustment" id="adjustment2">
-    <property name="value">1000</property>
-    <property name="upper">100000000</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">10</property>
+  <object class="GtkWindow" id="Sheet">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Importing Spreadsheet Data</property>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkLabel" id="intro-label1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="label" translatable="yes">Enter below the sheet number and the cell range which you wish to import.</property>
+            <property name="wrap">True</property>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkAlignment" id="alignment4">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="xscale">0</property>
+            <child>
+              <object class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment7">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkTable" id="table3">
+                        <property name="visible">True</property>
+                        <property name="n_rows">3</property>
+                        <property name="n_columns">2</property>
+                        <child>
+                          <object class="GtkEntry" id="cell-range-entry">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="invisible_char">&#x25CF;</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                            <property name="y_options"></property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkComboBox" id="sheet-entry">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                           <property name="active">0</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="y_options"></property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="cell-range-label">
+                            <property name="visible">True</property>
+                            <property name="xalign">1</property>
+                            <property name="label" translatable="yes">_Cells: </property>
+                            <property name="use_underline">True</property>
+                            <property name="mnemonic_widget">cell-range-entry</property>
+                          </object>
+                          <packing>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options"></property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="sheet-label">
+                            <property name="visible">True</property>
+                            <property name="xalign">1</property>
+                            <property name="label" translatable="yes">_Sheet Index: </property>
+                            <property name="use_underline">True</property>
+                            <property name="mnemonic_widget">sheet-entry</property>
+                          </object>
+                          <packing>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options"></property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="readnames-checkbox">
+                            <property name="label" translatable="yes">Use first row as _variable names</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="image_position">right</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Cells to Import&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
   </object>
 </interface>