Used type casenumber in GUI code where appropriate. Also, generally
[pspp-builds.git] / src / ui / gui / psppire-data-store.c
index 9e973ce349b21d3db4e514ed7a4c7ec3d576cd08..61fee9bc35c99ef032410c0c60e9d5e1b91a5945 100644 (file)
@@ -1,11 +1,9 @@
-/* psppire-data-store.c
-
-   PSPPIRE --- A Graphical User Interface for PSPP
+/* PSPPIRE - a graphical user interface for PSPP.
    Copyright (C) 2006  Free Software Foundation
 
    Copyright (C) 2006  Free Software Foundation
 
-   This program is free software; you can redistribute it and/or modify
+   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
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   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,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -14,9 +12,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    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, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA. */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
 #include <string.h>
 
 #include <config.h>
 #include <string.h>
@@ -25,8 +21,7 @@
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-#include <data/casefile.h>
-#include <data/case.h>
+#include <data/datasheet.h>
 #include <data/data-out.h>
 #include <data/variable.h>
 
 #include <data/data-out.h>
 #include <data/variable.h>
 
 #include <data/value-labels.h>
 #include <data/data-in.h>
 
 #include <data/value-labels.h>
 #include <data/data-in.h>
 
-#include <data/file-handle-def.h>
-#include <data/sys-file-writer.h>
-
-
 
 static void psppire_data_store_init            (PsppireDataStore      *data_store);
 static void psppire_data_store_class_init      (PsppireDataStoreClass *class);
 
 static void psppire_data_store_init            (PsppireDataStore      *data_store);
 static void psppire_data_store_class_init      (PsppireDataStoreClass *class);
@@ -58,13 +49,8 @@ static void psppire_data_store_sheet_row_init (GSheetRowIface *iface);
 
 static void psppire_data_store_finalize        (GObject           *object);
 
 
 static void psppire_data_store_finalize        (GObject           *object);
 
-static gchar *psppire_data_store_get_string (const GSheetModel *sheet_model, gint row, gint column);
-
-static gboolean psppire_data_store_set_string (GSheetModel *model,
-                                         const gchar *text, gint row, gint column);
-
 static gboolean psppire_data_store_clear_datum (GSheetModel *model,
 static gboolean psppire_data_store_clear_datum (GSheetModel *model,
-                                         gint row, gint column);
+                                         glong row, glong column);
 
 
 #define MIN_COLUMNS 10
 
 
 #define MIN_COLUMNS 10
@@ -77,7 +63,7 @@ static GObjectClass *parent_class = NULL;
 enum  {FONT_CHANGED,
        n_SIGNALS};
 
 enum  {FONT_CHANGED,
        n_SIGNALS};
 
-static guint signal[n_SIGNALS];
+static guint signal[n_SIGNALS];
 
 
 inline GType
 
 
 inline GType
@@ -152,9 +138,9 @@ psppire_data_store_class_init (PsppireDataStoreClass *class)
 
   object_class->finalize = psppire_data_store_finalize;
 
 
   object_class->finalize = psppire_data_store_finalize;
 
-  signal[FONT_CHANGED] =
+  signal[FONT_CHANGED] =
     g_signal_new ("font_changed",
     g_signal_new ("font_changed",
-                 G_TYPE_FROM_CLASS(class),
+                 G_TYPE_FROM_CLASS (class),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL,
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL,
@@ -165,22 +151,27 @@ psppire_data_store_class_init (PsppireDataStoreClass *class)
 
 
 
 
 
 
-static gint
+static glong
 psppire_data_store_get_var_count (const GSheetModel *model)
 {
 psppire_data_store_get_var_count (const GSheetModel *model)
 {
-  const PsppireDataStore *store = PSPPIRE_DATA_STORE(model);
+  const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
 
   return psppire_dict_get_var_cnt (store->dict);
 }
 
 
   return psppire_dict_get_var_cnt (store->dict);
 }
 
-static gint
-psppire_data_store_get_case_count (const GSheetModel *model)
+casenumber
+psppire_data_store_get_case_count (PsppireDataStore *store)
 {
 {
-  const PsppireDataStore *store = PSPPIRE_DATA_STORE(model);
-
   return psppire_case_file_get_case_count (store->case_file);
 }
 
   return psppire_case_file_get_case_count (store->case_file);
 }
 
+static glong
+psppire_data_store_get_case_count_from_model (const GSheetModel *model)
+{
+  const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
+
+  return psppire_case_file_get_case_count (store->case_file);
+}
 
 static void
 psppire_data_store_init (PsppireDataStore *data_store)
 
 static void
 psppire_data_store_init (PsppireDataStore *data_store)
@@ -192,20 +183,39 @@ psppire_data_store_init (PsppireDataStore *data_store)
 
 const PangoFontDescription *
 psppire_data_store_get_font_desc (const GSheetModel *model,
 
 const PangoFontDescription *
 psppire_data_store_get_font_desc (const GSheetModel *model,
-                             gint row, gint column)
+                             glong row, glong column)
 {
 {
-  PsppireDataStore *store = PSPPIRE_DATA_STORE(model);
+  PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
 
   return store->font_desc;
 }
 
 
   return store->font_desc;
 }
 
+static inline gchar *
+psppire_data_store_get_string_wrapper (const GSheetModel *model, glong row,
+                                      glong column)
+{
+  return psppire_data_store_get_string (PSPPIRE_DATA_STORE (model), row, column);
+}
+
+
+static inline gboolean
+psppire_data_store_set_string_wrapper (GSheetModel *model,
+                                      const gchar *text,
+                                      glong row, glong column)
+{
+  return psppire_data_store_set_string (PSPPIRE_DATA_STORE (model), text,
+                                       row, column);
+}
+
+
+
 
 static void
 psppire_data_store_sheet_model_init (GSheetModelIface *iface)
 {
   iface->free_strings = TRUE;
 
 static void
 psppire_data_store_sheet_model_init (GSheetModelIface *iface)
 {
   iface->free_strings = TRUE;
-  iface->get_string = psppire_data_store_get_string;
-  iface->set_string = psppire_data_store_set_string;
+  iface->get_string = psppire_data_store_get_string_wrapper;
+  iface->set_string = psppire_data_store_set_string_wrapper;
   iface->clear_datum = psppire_data_store_clear_datum;
   iface->is_editable = NULL;
   iface->is_visible = NULL;
   iface->clear_datum = psppire_data_store_clear_datum;
   iface->is_editable = NULL;
   iface->is_visible = NULL;
@@ -214,7 +224,7 @@ psppire_data_store_sheet_model_init (GSheetModelIface *iface)
   iface->get_font_desc = psppire_data_store_get_font_desc;
   iface->get_cell_border = NULL;
   iface->get_column_count = psppire_data_store_get_var_count;
   iface->get_font_desc = psppire_data_store_get_font_desc;
   iface->get_cell_border = NULL;
   iface->get_column_count = psppire_data_store_get_var_count;
-  iface->get_row_count = psppire_data_store_get_case_count;
+  iface->get_row_count = psppire_data_store_get_case_count_from_model;
 }
 
 static
 }
 
 static
@@ -225,35 +235,36 @@ gboolean always_true ()
 
 
 static void
 
 
 static void
-delete_cases_callback (GtkWidget *w, gint first, gint n_cases, gpointer data)
+delete_cases_callback (GtkWidget *w,
+        casenumber first, casenumber n_cases, gpointer data)
 {
   PsppireDataStore *store  ;
 
   g_return_if_fail (data);
 
 {
   PsppireDataStore *store  ;
 
   g_return_if_fail (data);
 
-  store  = PSPPIRE_DATA_STORE(data);
+  store  = PSPPIRE_DATA_STORE (data);
 
   g_assert (first >= 0);
 
 
   g_assert (first >= 0);
 
-  g_sheet_model_rows_deleted (G_SHEET_MODEL(store), first, n_cases);
+  g_sheet_model_rows_deleted (G_SHEET_MODEL (store), first, n_cases);
 }
 
 
 static void
 }
 
 
 static void
-insert_case_callback (GtkWidget *w, gint casenum, gpointer data)
+insert_case_callback (GtkWidget *w, casenumber casenum, gpointer data)
 {
   PsppireDataStore *store  ;
 
   g_return_if_fail (data);
 
 {
   PsppireDataStore *store  ;
 
   g_return_if_fail (data);
 
-  store  = PSPPIRE_DATA_STORE(data);
+  store  = PSPPIRE_DATA_STORE (data);
 
 
-  g_sheet_model_range_changed (G_SHEET_MODEL(store),
+  g_sheet_model_range_changed (G_SHEET_MODEL (store),
                               casenum, -1,
                               psppire_case_file_get_case_count (store->case_file),
                               -1);
 
                               casenum, -1,
                               psppire_case_file_get_case_count (store->case_file),
                               -1);
 
-  g_sheet_model_rows_inserted (G_SHEET_MODEL(store), casenum, 1);
+  g_sheet_model_rows_inserted (G_SHEET_MODEL (store), casenum, 1);
 }
 
 
 }
 
 
@@ -263,9 +274,9 @@ changed_case_callback (GtkWidget *w, gint casenum, gpointer data)
   PsppireDataStore *store  ;
   g_return_if_fail (data);
 
   PsppireDataStore *store  ;
   g_return_if_fail (data);
 
-  store  = PSPPIRE_DATA_STORE(data);
+  store  = PSPPIRE_DATA_STORE (data);
 
 
-  g_sheet_model_range_changed (G_SHEET_MODEL(store),
+  g_sheet_model_range_changed (G_SHEET_MODEL (store),
                                 casenum, -1,
                                 casenum, -1);
 }
                                 casenum, -1,
                                 casenum, -1);
 }
@@ -278,14 +289,33 @@ delete_variables_callback (GObject *obj, gint var_num, gint n_vars, gpointer dat
 
   g_return_if_fail (data);
 
 
   g_return_if_fail (data);
 
-  store  = PSPPIRE_DATA_STORE(data);
+  store  = PSPPIRE_DATA_STORE (data);
 
 
-  g_sheet_model_columns_deleted (G_SHEET_MODEL(store), var_num, n_vars);
+  g_sheet_model_columns_deleted (G_SHEET_MODEL (store), var_num, n_vars);
 
 
-  g_sheet_column_columns_changed (G_SHEET_COLUMN(store),
+  g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
                                   var_num, -1);
 }
 
                                   var_num, -1);
 }
 
+
+static void
+variable_changed_callback (GObject *obj, gint var_num, gpointer data)
+{
+  PsppireDataStore *store;
+
+  g_return_if_fail (data);
+
+  store  = PSPPIRE_DATA_STORE (data);
+
+  g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
+                                 var_num, 1);
+
+
+  g_sheet_model_range_changed (G_SHEET_MODEL (store),
+                              -1, var_num,
+                              -1, var_num);
+}
+
 static void
 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
 {
 static void
 insert_variable_callback (GObject *obj, gint var_num, gpointer data)
 {
@@ -294,12 +324,14 @@ insert_variable_callback (GObject *obj, gint var_num, gpointer data)
 
   g_return_if_fail (data);
 
 
   g_return_if_fail (data);
 
-  store  = PSPPIRE_DATA_STORE(data);
+  store  = PSPPIRE_DATA_STORE (data);
 
   if ( var_num > 0 )
     {
 
   if ( var_num > 0 )
     {
-      struct variable *variable;
-      variable = psppire_dict_get_variable (store->dict, var_num);
+      struct variable *variable =
+       psppire_dict_get_variable (store->dict, var_num);
+
+      g_assert (variable != NULL);
 
       posn = var_get_case_index (variable);
     }
 
       posn = var_get_case_index (variable);
     }
@@ -310,10 +342,10 @@ insert_variable_callback (GObject *obj, gint var_num, gpointer data)
 
   psppire_case_file_insert_values (store->case_file, 1, posn);
 
 
   psppire_case_file_insert_values (store->case_file, 1, posn);
 
-  g_sheet_column_columns_changed (G_SHEET_COLUMN(store),
+  g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
                                  var_num, 1);
 
                                  var_num, 1);
 
-  g_sheet_model_columns_inserted (G_SHEET_MODEL(store), var_num, 1);
+  g_sheet_model_columns_inserted (G_SHEET_MODEL (store), var_num, 1);
 }
 
 
 }
 
 
@@ -325,7 +357,7 @@ dict_size_change_callback (GObject *obj,
 
   g_return_if_fail (data);
 
 
   g_return_if_fail (data);
 
-  store  = PSPPIRE_DATA_STORE(data);
+  store  = PSPPIRE_DATA_STORE (data);
 
   psppire_case_file_insert_values (store->case_file, adjustment, posn);
 }
 
   psppire_case_file_insert_values (store->case_file, adjustment, posn);
 }
@@ -348,64 +380,71 @@ psppire_data_store_new (PsppireDict *dict)
 
   psppire_data_store_set_dictionary (retval, dict);
 
 
   psppire_data_store_set_dictionary (retval, dict);
 
-
   return retval;
 }
 
 
   return retval;
 }
 
 
-
-/**
- * psppire_data_store_replace_set_dictionary:
- * @data_store: The variable store
- * @dict: The dictionary to set
- *
- * If a dictionary is already associated with the data-store, then it will be
- * destroyed.
- **/
 void
 void
-psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
+psppire_data_store_set_case_file (PsppireDataStore *data_store,
+                                 PsppireCaseFile *cf)
 {
 {
-  gint var_cnt = psppire_dict_get_next_value_idx (dict);
-
-  data_store->dict = dict;
-
   if ( data_store->case_file)
     {
       g_object_unref (data_store->case_file);
   if ( data_store->case_file)
     {
       g_object_unref (data_store->case_file);
-      data_store->case_file = 0;
     }
 
     }
 
-  data_store->case_file = psppire_case_file_new (var_cnt);
+  data_store->case_file = cf;
 
   g_signal_connect (data_store->case_file, "cases-deleted",
 
   g_signal_connect (data_store->case_file, "cases-deleted",
-                  G_CALLBACK(delete_cases_callback),
+                  G_CALLBACK (delete_cases_callback),
                   data_store);
 
   g_signal_connect (data_store->case_file, "case-inserted",
                   data_store);
 
   g_signal_connect (data_store->case_file, "case-inserted",
-                  G_CALLBACK(insert_case_callback),
+                  G_CALLBACK (insert_case_callback),
                   data_store);
 
 
   g_signal_connect (data_store->case_file, "case-changed",
                   data_store);
 
 
   g_signal_connect (data_store->case_file, "case-changed",
-                  G_CALLBACK(changed_case_callback),
+                  G_CALLBACK (changed_case_callback),
                   data_store);
                   data_store);
+}
+
+
+
+/**
+ * psppire_data_store_replace_set_dictionary:
+ * @data_store: The variable store
+ * @dict: The dictionary to set
+ *
+ * If a dictionary is already associated with the data-store, then it will be
+ * destroyed.
+ **/
+void
+psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *dict)
+{
+  data_store->dict = dict;
 
   g_signal_connect (dict, "variable-inserted",
 
   g_signal_connect (dict, "variable-inserted",
-                  G_CALLBACK(insert_variable_callback),
+                  G_CALLBACK (insert_variable_callback),
                   data_store);
 
   g_signal_connect (dict, "variables-deleted",
                   data_store);
 
   g_signal_connect (dict, "variables-deleted",
-                  G_CALLBACK(delete_variables_callback),
+                  G_CALLBACK (delete_variables_callback),
                   data_store);
 
                   data_store);
 
+  g_signal_connect (dict, "variable-changed",
+                  G_CALLBACK (variable_changed_callback),
+                  data_store);
+
+
   g_signal_connect (dict, "dict-size-changed",
   g_signal_connect (dict, "dict-size-changed",
-                   G_CALLBACK(dict_size_change_callback),
+                   G_CALLBACK (dict_size_change_callback),
                    data_store);
 
   /* The entire model has changed */
                    data_store);
 
   /* The entire model has changed */
-  g_sheet_model_range_changed (G_SHEET_MODEL(data_store), -1, -1, -1, -1);
+  g_sheet_model_range_changed (G_SHEET_MODEL (data_store), -1, -1, -1, -1);
 
 
-  g_sheet_column_columns_changed (G_SHEET_COLUMN(data_store), 0, -1);
+  g_sheet_column_columns_changed (G_SHEET_COLUMN (data_store), 0, -1);
 }
 
 static void
 }
 
 static void
@@ -420,7 +459,7 @@ psppire_data_store_finalize (GObject *object)
 
 /* Insert a blank case before POSN */
 gboolean
 
 /* Insert a blank case before POSN */
 gboolean
-psppire_data_store_insert_new_case (PsppireDataStore *ds, gint posn)
+psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
 {
   gboolean result;
   gint val_cnt, v;
 {
   gboolean result;
   gint val_cnt, v;
@@ -429,7 +468,7 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, gint posn)
 
 
   /* Opportunity for optimisation exists here when creating a blank case */
 
 
   /* Opportunity for optimisation exists here when creating a blank case */
-  val_cnt = casefile_get_value_cnt (ds->case_file->flexifile) ;
+  val_cnt = datasheet_get_column_cnt (ds->case_file->datasheet) ;
 
   case_create (&cc, val_cnt);
 
 
   case_create (&cc, val_cnt);
 
@@ -452,16 +491,15 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, gint posn)
 }
 
 
 }
 
 
-static gchar *
-psppire_data_store_get_string (const GSheetModel *model, gint row, gint column)
+gchar *
+psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
 {
   gint idx;
   char *text;
   const struct fmt_spec *fp ;
   const struct variable *pv ;
 {
   gint idx;
   char *text;
   const struct fmt_spec *fp ;
   const struct variable *pv ;
-  const union value *v ;
+  union value *v ;
   GString *s;
   GString *s;
-  PsppireDataStore *store = PSPPIRE_DATA_STORE(model);
 
   g_return_val_if_fail (store->dict, NULL);
   g_return_val_if_fail (store->case_file, NULL);
 
   g_return_val_if_fail (store->dict, NULL);
   g_return_val_if_fail (store->case_file, NULL);
@@ -474,21 +512,25 @@ psppire_data_store_get_string (const GSheetModel *model, gint row, gint column)
 
   pv = psppire_dict_get_variable (store->dict, column);
 
 
   pv = psppire_dict_get_variable (store->dict, column);
 
+  g_assert (pv);
+
   idx = var_get_case_index (pv);
 
   idx = var_get_case_index (pv);
 
-  v = psppire_case_file_get_value (store->case_file, row, idx);
+  g_assert (idx >= 0);
+
+  v = psppire_case_file_get_value (store->case_file, row, idx, NULL,
+                                   var_get_width (pv));
 
   g_return_val_if_fail (v, NULL);
 
   if ( store->show_labels)
     {
 
   g_return_val_if_fail (v, NULL);
 
   if ( store->show_labels)
     {
-      const struct val_labs * vl = var_get_value_labels (pv);
-
-      const gchar *label;
-      if ( (label = val_labs_find (vl, *v)) )
-       {
+      const gchar *label = var_lookup_value_label (pv, v);
+      if (label)
+        {
+          free (v);
          return pspp_locale_to_utf8 (label, -1, 0);
          return pspp_locale_to_utf8 (label, -1, 0);
-       }
+        }
     }
 
   fp = var_get_write_format (pv);
     }
 
   fp = var_get_write_format (pv);
@@ -510,16 +552,16 @@ psppire_data_store_get_string (const GSheetModel *model, gint row, gint column)
 
   g_strchomp (text);
 
 
   g_strchomp (text);
 
+  free (v);
   return text;
 }
 
 
 static gboolean
 psppire_data_store_clear_datum (GSheetModel *model,
   return text;
 }
 
 
 static gboolean
 psppire_data_store_clear_datum (GSheetModel *model,
-                                         gint row, gint col)
-
+                                         glong row, glong col)
 {
 {
-  PsppireDataStore *store = PSPPIRE_DATA_STORE(model);
+  PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
 
   union value v;
   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
 
   union value v;
   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
@@ -542,12 +584,10 @@ psppire_data_store_clear_datum (GSheetModel *model,
    to ROW, COL with  the value TEXT.
    Returns true if anything was updated, false otherwise.
 */
    to ROW, COL with  the value TEXT.
    Returns true if anything was updated, false otherwise.
 */
-static gboolean
-psppire_data_store_set_string (GSheetModel *model,
-                         const gchar *text, gint row, gint col)
+gboolean
+psppire_data_store_set_string (PsppireDataStore *store,
+                              const gchar *text, glong row, glong col)
 {
 {
-  PsppireDataStore *store = PSPPIRE_DATA_STORE(model);
-
   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
   g_return_val_if_fail (pv, FALSE);
 
   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
   g_return_val_if_fail (pv, FALSE);
 
@@ -585,10 +625,10 @@ psppire_data_store_set_font (PsppireDataStore *store,
 #if 0
   store->width_of_m = calc_m_width (fd);
 #endif
 #if 0
   store->width_of_m = calc_m_width (fd);
 #endif
-  g_signal_emit (store, signal[FONT_CHANGED], 0);
+  g_signal_emit (store, signal[FONT_CHANGED], 0);
 
 
 
 
-  g_sheet_model_range_changed (G_SHEET_MODEL(store),
+  g_sheet_model_range_changed (G_SHEET_MODEL (store),
                                 -1, -1, -1, -1);
 }
 
                                 -1, -1, -1, -1);
 }
 
@@ -601,81 +641,51 @@ psppire_data_store_show_labels (PsppireDataStore *store, gboolean show_labels)
 
   store->show_labels = show_labels;
 
 
   store->show_labels = show_labels;
 
-  g_sheet_model_range_changed (G_SHEET_MODEL(store),
+  g_sheet_model_range_changed (G_SHEET_MODEL (store),
                                 -1, -1, -1, -1);
 }
 
 
                                 -1, -1, -1, -1);
 }
 
 
-
-/* FIXME: There's no reason to actually have this function.
-   It should be done by a procedure */
 void
 void
-psppire_data_store_create_system_file (PsppireDataStore *store,
-                             struct file_handle *handle)
+psppire_data_store_clear (PsppireDataStore *data_store)
 {
 {
-  gint i, var_cnt;
-  const struct sfm_write_options wo = {
-    true, /* writeable */
-    false, /* dont compress */
-    3 /* version */
-  };
-
-  struct sfm_writer *writer ;
-
-  g_assert (handle);
-
-  writer = sfm_open_writer (handle, store->dict->dict, wo);
-
-  if ( ! writer)
-    return;
-
-
-  var_cnt = psppire_data_store_get_var_count (G_SHEET_MODEL(store));
-
-  for (i = 0 ; i < psppire_case_file_get_case_count (store->case_file); ++i )
-    {
-      struct ccase c;
-
-      case_create (&c, var_cnt);
-      psppire_case_file_get_case (store->case_file, i, &c);
-      sfm_write_case (writer, &c);
-
-      case_destroy (&c);
-    }
+  psppire_case_file_clear (data_store->case_file);
 
 
-  sfm_close_writer (writer);
+  psppire_dict_clear (data_store->dict);
 }
 
 
 
 }
 
 
 
-void
-psppire_data_store_clear (PsppireDataStore *data_store)
+/* Return a casereader made from this datastore */
+struct casereader *
+psppire_data_store_get_reader (PsppireDataStore *ds)
 {
 {
-  psppire_case_file_clear (data_store->case_file);
+  struct casereader *reader ;
 
 
-  psppire_dict_clear (data_store->dict);
-}
+  reader = psppire_case_file_make_reader (ds->case_file);
 
 
+  return reader;
+}
 
 
 
 /* Column related funcs */
 
 
 
 
 /* Column related funcs */
 
-static gint
+static glong
 geometry_get_column_count (const GSheetColumn *geom)
 {
 geometry_get_column_count (const GSheetColumn *geom)
 {
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE(geom);
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
 
 
-  return MAX(MIN_COLUMNS, psppire_dict_get_var_cnt (ds->dict));
+  return MAX (MIN_COLUMNS, psppire_dict_get_var_cnt (ds->dict));
 }
 
 
 
 static gint
 }
 
 
 
 static gint
-geometry_get_width (const GSheetColumn *geom, gint unit)
+geometry_get_width (const GSheetColumn *geom, glong unit)
 {
   const struct variable *pv ;
 {
   const struct variable *pv ;
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE(geom);
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
 
   if ( unit >= psppire_dict_get_var_cnt (ds->dict) )
     return ds->width_of_m * 8 ;
 
   if ( unit >= psppire_dict_get_var_cnt (ds->dict) )
     return ds->width_of_m * 8 ;
@@ -689,9 +699,9 @@ geometry_get_width (const GSheetColumn *geom, gint unit)
 }
 
 static void
 }
 
 static void
-geometry_set_width (GSheetColumn *geom, gint unit, gint width)
+geometry_set_width (GSheetColumn *geom, glong unit, gint width)
 {
 {
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE(geom);
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
 
   struct variable *pv = psppire_dict_get_variable (ds->dict, unit);
 
 
   struct variable *pv = psppire_dict_get_variable (ds->dict, unit);
 
@@ -701,9 +711,9 @@ geometry_set_width (GSheetColumn *geom, gint unit, gint width)
 
 
 static GtkJustification
 
 
 static GtkJustification
-geometry_get_justification (const GSheetColumn *geom, gint unit)
+geometry_get_justification (const GSheetColumn *geom, glong unit)
 {
 {
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE(geom);
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
   const struct variable *pv ;
 
 
   const struct variable *pv ;
 
 
@@ -721,11 +731,11 @@ geometry_get_justification (const GSheetColumn *geom, gint unit)
 static const gchar null_var_name[]=N_("var");
 
 static gchar *
 static const gchar null_var_name[]=N_("var");
 
 static gchar *
-geometry_get_column_button_label (const GSheetColumn *geom, gint unit)
+geometry_get_column_button_label (const GSheetColumn *geom, glong unit)
 {
   gchar *text;
   struct variable *pv ;
 {
   gchar *text;
   struct variable *pv ;
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE(geom);
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
 
   if ( unit >= psppire_dict_get_var_cnt (ds->dict) )
     return g_locale_to_utf8 (null_var_name, -1, 0, 0, 0);
 
   if ( unit >= psppire_dict_get_var_cnt (ds->dict) )
     return g_locale_to_utf8 (null_var_name, -1, 0, 0, 0);
@@ -738,10 +748,31 @@ geometry_get_column_button_label (const GSheetColumn *geom, gint unit)
 }
 
 
 }
 
 
+static gchar *
+geometry_get_column_subtitle (const GSheetColumn *geom, glong unit)
+{
+  gchar *text;
+  const struct variable *v ;
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
+
+  if ( unit >= psppire_dict_get_var_cnt (ds->dict) )
+    return NULL;
+
+  v = psppire_dict_get_variable (ds->dict, unit);
+
+  if ( ! var_has_label (v))
+    return NULL;
+
+  text =  pspp_locale_to_utf8 (var_get_label (v), -1, 0);
+
+  return text;
+}
+
+
 static gboolean
 static gboolean
-geometry_get_sensitivity (const GSheetColumn *geom, gint unit)
+geometry_get_sensitivity (const GSheetColumn *geom, glong unit)
 {
 {
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE(geom);
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
 
   return (unit < psppire_dict_get_var_cnt (ds->dict));
 }
 
   return (unit < psppire_dict_get_var_cnt (ds->dict));
 }
@@ -757,31 +788,32 @@ psppire_data_store_sheet_column_init (GSheetColumnIface *iface)
   iface->get_sensitivity = geometry_get_sensitivity;
   iface->get_justification = geometry_get_justification;
   iface->get_button_label = geometry_get_column_button_label;
   iface->get_sensitivity = geometry_get_sensitivity;
   iface->get_justification = geometry_get_justification;
   iface->get_button_label = geometry_get_column_button_label;
+  iface->get_subtitle = geometry_get_column_subtitle;
 }
 
 
 /* Row related funcs */
 
 }
 
 
 /* Row related funcs */
 
-static gint
+static glong
 geometry_get_row_count (const GSheetRow *geom, gpointer data)
 {
 geometry_get_row_count (const GSheetRow *geom, gpointer data)
 {
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE(geom);
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
 
   return TRAILING_ROWS + psppire_case_file_get_case_count (ds->case_file);
 }
 
 
 static gint
 
   return TRAILING_ROWS + psppire_case_file_get_case_count (ds->case_file);
 }
 
 
 static gint
-geometry_get_height (const GSheetRow *geom, gint unit, gpointer data)
+geometry_get_height (const GSheetRow *geom, glong unit, gpointer data)
 {
   return 25;
 }
 
 
 static gboolean
 {
   return 25;
 }
 
 
 static gboolean
-geometry_get_row_sensitivity (const GSheetRow *geom, gint unit, gpointer data)
+geometry_get_row_sensitivity (const GSheetRow *geom, glong unit, gpointer data)
 {
 {
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE(geom);
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
 
 
   return (unit < psppire_case_file_get_case_count (ds->case_file));
 
 
   return (unit < psppire_case_file_get_case_count (ds->case_file));
@@ -789,17 +821,17 @@ geometry_get_row_sensitivity (const GSheetRow *geom, gint unit, gpointer data)
 
 
 static gchar *
 
 
 static gchar *
-geometry_get_row_button_label (const GSheetRow *geom, gint unit, gpointer data)
+geometry_get_row_button_label (const GSheetRow *geom, glong unit, gpointer data)
 {
   gchar *text;
   gchar *s;
 {
   gchar *text;
   gchar *s;
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE(geom);
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (geom);
 
   if ( unit >
        TRAILING_ROWS + psppire_case_file_get_case_count (ds->case_file))
     return 0;
 
 
   if ( unit >
        TRAILING_ROWS + psppire_case_file_get_case_count (ds->case_file))
     return 0;
 
-  s = g_strdup_printf (_("%d"), unit);
+  s = g_strdup_printf (_("%ld"), unit + FIRST_CASE_NUMBER);
 
   text =  pspp_locale_to_utf8 (s, -1, 0);
 
 
   text =  pspp_locale_to_utf8 (s, -1, 0);