Change license from GPLv2+ to GPLv3+.
[pspp-builds.git] / src / ui / gui / psppire-var-store.c
index 1aefb8f98bdfdce96f6640b0417d6da4288dac65..8cbba37ddbb7882e9ef587f540f645d5e6ba9856 100644 (file)
@@ -1,12 +1,9 @@
-/* psppire-var-store.c
-   PSPPIRE --- A Graphical User Interface for PSPP
+/* PSPPIRE - a graphical user interface for PSPP.
    Copyright (C) 2006  Free Software Foundation
-   Written by John Darrington
 
-   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
-   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,
    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 <stdlib.h>
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+
 
 #include <gobject/gvaluecollector.h>
 
 #include <gtksheet/gsheetmodel.h>
 
-#include "psppire-variable.h"
 #include "psppire-var-store.h"
 #include "var-sheet.h"
+#include "helper.h"
 
 #include <data/dictionary.h>
 #include <data/variable.h>
 #include "missing-val-dialog.h"
 #include <data/value-labels.h>
 
-#define _(A) A
-#define N_(A) A
+#include "var-display.h"
 
+#define TRAILING_ROWS 40
 
 static void         psppire_var_store_init            (PsppireVarStore      *var_store);
 static void         psppire_var_store_class_init      (PsppireVarStoreClass *class);
 static void         psppire_var_store_sheet_model_init (GSheetModelIface *iface);
 static void         psppire_var_store_finalize        (GObject           *object);
 
-static const gchar *const psppire_var_store_get_string(GSheetModel *sheet_model, gint row, gint column);
 
-static gboolean  psppire_var_store_clear(GSheetModel *model,  gint row, gint col);
+gchar * missing_values_to_string (const struct variable *pv, GError **err);
+
+
+static gchar *psppire_var_store_get_string (const GSheetModel *sheet_model, gint row, gint column);
 
+static gboolean  psppire_var_store_clear (GSheetModel *model,  gint row, gint col);
 
-static gboolean psppire_var_store_set_string(GSheetModel *model, 
+
+static gboolean psppire_var_store_set_string (GSheetModel *model,
                                          const gchar *text, gint row, gint column);
 
+static gint psppire_var_store_get_row_count (const GSheetModel * model);
+
+static gchar *text_for_column (const struct variable *pv, gint c, GError **err);
+
+
+static void psppire_var_store_sheet_row_init (GSheetRowIface *iface);
 
-static const gchar *const text_for_column(const struct PsppireVariable *pv, gint c);
 
 
 static GObjectClass *parent_class = NULL;
@@ -89,12 +98,24 @@ psppire_var_store_get_type (void)
        NULL
       };
 
-      var_store_type = g_type_register_static (G_TYPE_OBJECT, "PsppireVarStore",
-                                               &var_store_info, 0);
+      static const GInterfaceInfo sheet_row_info =
+      {
+       (GInterfaceInitFunc) psppire_var_store_sheet_row_init,
+       NULL,
+       NULL
+      };
+
+      var_store_type = g_type_register_static (G_TYPE_OBJECT, "PsppireVarStore", &var_store_info, 0);
 
       g_type_add_interface_static (var_store_type,
                                   G_TYPE_SHEET_MODEL,
                                   &sheet_model_info);
+
+      g_type_add_interface_static (var_store_type,
+                                  G_TYPE_SHEET_ROW,
+                                  &sheet_row_info);
+
+
     }
 
   return var_store_type;
@@ -115,9 +136,9 @@ psppire_var_store_class_init (PsppireVarStoreClass *class)
 static void
 psppire_var_store_init (PsppireVarStore *var_store)
 {
-  GdkColormap *colormap = gdk_colormap_get_system();
+  GdkColormap *colormap = gdk_colormap_get_system ();
 
-  g_assert(gdk_color_parse("gray", &var_store->disabled));
+  g_assert (gdk_color_parse ("gray", &var_store->disabled));
 
   gdk_colormap_alloc_color (colormap, &var_store->disabled, FALSE, TRUE);
 
@@ -125,35 +146,35 @@ psppire_var_store_init (PsppireVarStore *var_store)
 }
 
 static gboolean
-psppire_var_store_item_editable(PsppireVarStore *var_store, gint row, gint column)
+psppire_var_store_item_editable (PsppireVarStore *var_store, gint row, gint column)
 {
   const struct fmt_spec *write_spec ;
 
-  struct PsppireVariable *pv = psppire_var_store_get_variable(var_store, row);
+  struct variable *pv = psppire_var_store_get_var (var_store, row);
 
-  if ( !pv ) 
+  if ( !pv )
     return TRUE;
 
-  if ( ALPHA == psppire_variable_get_type(pv) && column == COL_DECIMALS ) 
+  if ( var_is_alpha (pv) && column == COL_DECIMALS )
     return FALSE;
 
-  write_spec = psppire_variable_get_write_spec(pv);
+  write_spec = var_get_print_format (pv);
 
-  switch ( write_spec->type ) 
+  switch ( write_spec->type )
     {
-    case FMT_DATE:     
-    case FMT_EDATE:    
-    case FMT_SDATE:    
-    case FMT_ADATE:    
-    case FMT_JDATE:    
-    case FMT_QYR:      
-    case FMT_MOYR:     
-    case FMT_WKYR:     
-    case FMT_DATETIME: 
-    case FMT_TIME:     
-    case FMT_DTIME:    
-    case FMT_WKDAY:    
-    case FMT_MONTH:    
+    case FMT_DATE:
+    case FMT_EDATE:
+    case FMT_SDATE:
+    case FMT_ADATE:
+    case FMT_JDATE:
+    case FMT_QYR:
+    case FMT_MOYR:
+    case FMT_WKYR:
+    case FMT_DATETIME:
+    case FMT_TIME:
+    case FMT_DTIME:
+    case FMT_WKDAY:
+    case FMT_MONTH:
       if ( column == COL_DECIMALS || column == COL_WIDTH)
        return FALSE;
       break;
@@ -164,32 +185,39 @@ psppire_var_store_item_editable(PsppireVarStore *var_store, gint row, gint colum
   return TRUE;
 }
 
+
+struct variable *
+psppire_var_store_get_var (PsppireVarStore *store, gint row)
+{
+  return psppire_dict_get_variable (store->dict, row);
+}
+
 static gboolean
-psppire_var_store_is_editable(GSheetModel *model, gint row, gint column)
+psppire_var_store_is_editable (const GSheetModel *model, gint row, gint column)
 {
-  PsppireVarStore *store = PSPPIRE_VAR_STORE(model);
-  return psppire_var_store_item_editable(store, row, column);
+  PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
+  return psppire_var_store_item_editable (store, row, column);
 }
 
 
 static const GdkColor *
-psppire_var_store_get_foreground(GSheetModel *model, gint row, gint column)
+psppire_var_store_get_foreground (const GSheetModel *model, gint row, gint column)
 {
-  PsppireVarStore *store = PSPPIRE_VAR_STORE(model);
+  PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
 
-  if ( ! psppire_var_store_item_editable(store, row, column) ) 
+  if ( ! psppire_var_store_item_editable (store, row, column) )
     return &store->disabled;
-  
+
   return NULL;
 }
 
 
 const PangoFontDescription *
-psppire_var_store_get_font_desc(GSheetModel *model,
+psppire_var_store_get_font_desc (const GSheetModel *model,
                              gint row, gint column)
 {
-  PsppireVarStore *store = PSPPIRE_VAR_STORE(model);
-  
+  PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
+
   return store->font_desc;
 }
 
@@ -198,6 +226,8 @@ psppire_var_store_get_font_desc(GSheetModel *model,
 static void
 psppire_var_store_sheet_model_init (GSheetModelIface *iface)
 {
+  iface->get_row_count = psppire_var_store_get_row_count;
+  iface->free_strings = TRUE;
   iface->get_string = psppire_var_store_get_string;
   iface->set_string = psppire_var_store_set_string;
   iface->clear_datum = psppire_var_store_clear;
@@ -225,34 +255,35 @@ psppire_var_store_new (PsppireDict *dict)
 
   retval = g_object_new (GTK_TYPE_VAR_STORE, NULL);
 
-  psppire_var_store_set_dictionary(retval, dict);
+  psppire_var_store_set_dictionary (retval, dict);
 
   return retval;
 }
 
-static void 
-var_change_callback(GtkWidget *w, gint n, gpointer data)
+static void
+var_change_callback (GtkWidget *w, gint n, gpointer data)
 {
-  GSheetModel *model = G_SHEET_MODEL(data);
+  GSheetModel *model = G_SHEET_MODEL (data);
+
   g_sheet_model_range_changed (model,
                                 n, 0, n, n_COLS);
 }
 
 
-static void 
-var_delete_callback(GtkWidget *w, gint first, gint n, gpointer data)
+static void
+var_delete_callback (GtkWidget *w, gint first, gint n, gpointer data)
 {
-  GSheetModel *model = G_SHEET_MODEL(data);
-  
+  GSheetModel *model = G_SHEET_MODEL (data);
+
   g_sheet_model_rows_deleted (model, first, n);
 }
 
 
 
-static void 
-var_insert_callback(GtkWidget *w, gint row, gpointer data)
+static void
+var_insert_callback (GtkWidget *w, gint row, gpointer data)
 {
-  GSheetModel *model = G_SHEET_MODEL(data);
+  GSheetModel *model = G_SHEET_MODEL (data);
 
   g_sheet_model_rows_inserted (model, row, 1);
 }
@@ -268,24 +299,24 @@ var_insert_callback(GtkWidget *w, gint row, gpointer data)
  * destroyed.
  **/
 void
-psppire_var_store_set_dictionary(PsppireVarStore *var_store, PsppireDict *dict)
+psppire_var_store_set_dictionary (PsppireVarStore *var_store, PsppireDict *dict)
 {
-  if ( var_store->dict ) g_object_unref(var_store->dict);
+  if ( var_store->dict ) g_object_unref (var_store->dict);
 
   var_store->dict = dict;
 
-  g_signal_connect(dict, "variable-changed", G_CALLBACK(var_change_callback), 
+  g_signal_connect (dict, "variable-changed", G_CALLBACK (var_change_callback),
                   var_store);
 
-  g_signal_connect(dict, "variables-deleted", G_CALLBACK(var_delete_callback), 
+  g_signal_connect (dict, "variables-deleted", G_CALLBACK (var_delete_callback),
                   var_store);
 
-  g_signal_connect(dict, "variable-inserted", G_CALLBACK(var_insert_callback), 
+  g_signal_connect (dict, "variable-inserted", G_CALLBACK (var_insert_callback),
                   var_store);
 
 
   /* The entire model has changed */
-  g_sheet_model_range_changed (G_SHEET_MODEL(var_store), -1, -1, -1, -1);
+  g_sheet_model_range_changed (G_SHEET_MODEL (var_store), -1, -1, -1, -1);
 }
 
 static void
@@ -295,61 +326,45 @@ psppire_var_store_finalize (GObject *object)
   (* parent_class->finalize) (object);
 }
 
-static const gchar *const 
-psppire_var_store_get_string(GSheetModel *model, gint row, gint column)
+static gchar *
+psppire_var_store_get_string (const GSheetModel *model, gint row, gint column)
 {
-  const gchar *s ;
+  PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
 
-  PsppireVarStore *store = PSPPIRE_VAR_STORE(model);
+  struct variable *pv;
 
-  struct PsppireVariable *pv;
-
-  if ( row >= psppire_dict_get_var_cnt(store->dict))
+  if ( row >= psppire_dict_get_var_cnt (store->dict))
     return 0;
-  
+
   pv = psppire_dict_get_variable (store->dict, row);
-  
-  s = text_for_column(pv, column);
 
-  return s;
+  return text_for_column (pv, column, 0);
 }
 
 
-struct PsppireVariable *
-psppire_var_store_get_variable(PsppireVarStore *store, gint row)
-{
-  g_return_val_if_fail(store, NULL);
-  g_return_val_if_fail(store->dict, NULL);
-
-  if ( row >= psppire_dict_get_var_cnt(store->dict))
-    return 0;
-
-  return psppire_dict_get_variable (store->dict, row);
-}
-
-/* Clears that part of the variable store, if possible, which corresponds 
+/* Clears that part of the variable store, if possible, which corresponds
    to ROW, COL.
    Returns true if anything was updated, false otherwise.
 */
-static gboolean 
-psppire_var_store_clear(GSheetModel *model,  gint row, gint col)
+static gboolean
+psppire_var_store_clear (GSheetModel *model,  gint row, gint col)
 {
-  struct PsppireVariable *pv ;
+  struct variable *pv ;
 
-  PsppireVarStore *var_store = PSPPIRE_VAR_STORE(model);
+  PsppireVarStore *var_store = PSPPIRE_VAR_STORE (model);
 
-  if ( row >= psppire_dict_get_var_cnt(var_store->dict))
+  if ( row >= psppire_dict_get_var_cnt (var_store->dict))
       return FALSE;
 
-  pv = psppire_var_store_get_variable(var_store, row);
+  pv = psppire_var_store_get_var (var_store, row);
 
-  if ( !pv ) 
+  if ( !pv )
     return FALSE;
 
   switch (col)
     {
     case COL_LABEL:
-      psppire_variable_set_label(pv, 0);
+      var_set_label (pv, 0);
       return TRUE;
       break;
     }
@@ -357,44 +372,80 @@ psppire_var_store_clear(GSheetModel *model,  gint row, gint col)
   return FALSE;
 }
 
-/* Attempts to update that part of the variable store which corresponds 
+/* Attempts to update that part of the variable store which corresponds
    to ROW, COL with  the value TEXT.
    Returns true if anything was updated, false otherwise.
 */
-static gboolean 
-psppire_var_store_set_string(GSheetModel *model, 
+static gboolean
+psppire_var_store_set_string (GSheetModel *model,
                          const gchar *text, gint row, gint col)
 {
-  struct PsppireVariable *pv ;
+  struct variable *pv ;
 
-  PsppireVarStore *var_store = PSPPIRE_VAR_STORE(model);
+  PsppireVarStore *var_store = PSPPIRE_VAR_STORE (model);
 
-  if ( row >= psppire_dict_get_var_cnt(var_store->dict))
+  if ( row >= psppire_dict_get_var_cnt (var_store->dict))
       return FALSE;
 
-  pv = psppire_var_store_get_variable(var_store, row);
-  if ( !pv ) 
+  pv = psppire_var_store_get_var (var_store, row);
+
+  if ( !pv )
     return FALSE;
 
   switch (col)
     {
     case COL_NAME:
-      return psppire_variable_set_name(pv, text);
+      return psppire_dict_rename_var (var_store->dict, pv, text);
       break;
     case COL_COLUMNS:
       if ( ! text) return FALSE;
-      return psppire_variable_set_columns(pv, atoi(text));
+      var_set_display_width (pv, atoi (text));
+      return TRUE;
       break;
     case COL_WIDTH:
-      if ( ! text) return FALSE;
-      return psppire_variable_set_width(pv, atoi(text));
+      {
+       int width = atoi (text);
+       if ( ! text) return FALSE;
+       if ( var_is_alpha (pv))
+           var_set_width (pv, width);
+       else
+         {
+           struct fmt_spec fmt ;
+           fmt = *var_get_write_format (pv);
+           if ( width < fmt_min_output_width (fmt.type)
+                ||
+                width > fmt_max_output_width (fmt.type))
+             return FALSE;
+
+           fmt.w = width;
+           fmt.d = MIN (fmt_max_output_decimals (fmt.type, width), fmt.d);
+
+           var_set_both_formats (pv, &fmt);
+         }
+
+       return TRUE;
+      }
       break;
     case COL_DECIMALS:
-      if ( ! text) return FALSE;
-      return psppire_variable_set_decimals(pv, atoi(text));
+      {
+       int decimals;
+       struct fmt_spec fmt;
+       if ( ! text) return FALSE;
+       decimals = atoi (text);
+       fmt = *var_get_write_format (pv);
+       if ( decimals >
+            fmt_max_output_decimals (fmt.type,
+                                     fmt.w
+                                     ))
+         return FALSE;
+
+       fmt.d = decimals;
+       var_set_both_formats (pv, &fmt);
+       return TRUE;
+      }
       break;
     case COL_LABEL:
-      psppire_variable_set_label(pv, text);
+      var_set_label (pv, text);
       return TRUE;
       break;
     case COL_TYPE:
@@ -406,7 +457,7 @@ psppire_var_store_set_string(GSheetModel *model,
       return FALSE;
       break;
     default:
-      g_assert_not_reached();
+      g_assert_not_reached ();
       return FALSE;
     }
 
@@ -414,198 +465,166 @@ psppire_var_store_set_string(GSheetModel *model,
 }
 
 
-#define MAX_CELL_TEXT_LEN 255
+const static gchar none[] = N_("None");
 
-static const gchar *const
-text_for_column(const struct PsppireVariable *pv, gint c)
+static  gchar *
+text_for_column (const struct variable *pv, gint c, GError **err)
 {
-  static gchar buf[MAX_CELL_TEXT_LEN];
-
-  static gchar none[]=_("None");
-
-  static const gchar *const type_label[] = 
+  static const gchar *const type_label[] =
     {
-      _("Numeric"),
-      _("Comma"),
-      _("Dot"),
-      _("Scientific"),
-      _("Date"),
-      _("Dollar"),
-      _("Custom"),
-      _("String")
+      N_("Numeric"),
+      N_("Comma"),
+      N_("Dot"),
+      N_("Scientific"),
+      N_("Date"),
+      N_("Dollar"),
+      N_("Custom"),
+      N_("String")
     };
-  enum {VT_NUMERIC, VT_COMMA, VT_DOT, VT_SCIENTIFIC, VT_DATE, VT_DOLLAR, 
+  enum {VT_NUMERIC, VT_COMMA, VT_DOT, VT_SCIENTIFIC, VT_DATE, VT_DOLLAR,
        VT_CUSTOM, VT_STRING};
 
-  const struct fmt_spec *write_spec = psppire_variable_get_write_spec(pv);
+  const struct fmt_spec *write_spec = var_get_write_format (pv);
 
   switch (c)
     {
     case COL_NAME:
-      return psppire_variable_get_name(pv);
+      return pspp_locale_to_utf8 ( var_get_name (pv), -1, err);
       break;
     case COL_TYPE:
       {
-       switch ( write_spec->type ) 
+       switch ( write_spec->type )
          {
          case FMT_F:
-           return type_label[VT_NUMERIC];
+           return g_locale_to_utf8 (gettext (type_label[VT_NUMERIC]), -1, 0, 0, err);
            break;
          case FMT_COMMA:
-           return type_label[VT_COMMA];
+           return g_locale_to_utf8 (gettext (type_label[VT_COMMA]), -1, 0, 0, err);
            break;
          case FMT_DOT:
-           return type_label[VT_DOT];
+           return g_locale_to_utf8 (gettext (type_label[VT_DOT]), -1, 0, 0, err);
            break;
          case FMT_E:
-           return type_label[VT_SCIENTIFIC];
+           return g_locale_to_utf8 (gettext (type_label[VT_SCIENTIFIC]), -1, 0, 0, err);
            break;
-         case FMT_DATE:        
-         case FMT_EDATE:       
-         case FMT_SDATE:       
-         case FMT_ADATE:       
-         case FMT_JDATE:       
-         case FMT_QYR: 
-         case FMT_MOYR:        
-         case FMT_WKYR:        
-         case FMT_DATETIME:    
-         case FMT_TIME:        
-         case FMT_DTIME:       
-         case FMT_WKDAY:       
-         case FMT_MONTH:       
-           return type_label[VT_DATE];
+         case FMT_DATE:
+         case FMT_EDATE:
+         case FMT_SDATE:
+         case FMT_ADATE:
+         case FMT_JDATE:
+         case FMT_QYR:
+         case FMT_MOYR:
+         case FMT_WKYR:
+         case FMT_DATETIME:
+         case FMT_TIME:
+         case FMT_DTIME:
+         case FMT_WKDAY:
+         case FMT_MONTH:
+           return g_locale_to_utf8 (type_label[VT_DATE], -1, 0, 0, err);
            break;
          case FMT_DOLLAR:
-           return type_label[VT_DOLLAR];
+           return g_locale_to_utf8 (type_label[VT_DOLLAR], -1, 0, 0, err);
            break;
          case FMT_CCA:
          case FMT_CCB:
          case FMT_CCC:
          case FMT_CCD:
          case FMT_CCE:
-           return type_label[VT_CUSTOM];
+           return g_locale_to_utf8 (gettext (type_label[VT_CUSTOM]), -1, 0, 0, err);
            break;
          case FMT_A:
-           return type_label[VT_STRING];
+           return g_locale_to_utf8 (gettext (type_label[VT_STRING]), -1, 0, 0, err);
            break;
          default:
-           g_warning("Unknown format: \"%s\"\n", 
-                     fmt_to_string(write_spec));
+            {
+              char str[FMT_STRING_LEN_MAX + 1];
+              g_warning ("Unknown format: \"%s\"\n",
+                        fmt_to_string (write_spec, str));
+            }
            break;
          }
       }
       break;
     case COL_WIDTH:
       {
-       g_snprintf(buf, MAX_CELL_TEXT_LEN, "%d", write_spec->w);
-       return buf;
+       gchar *s;
+       GString *gstr = g_string_sized_new (10);
+       g_string_printf (gstr, _("%d"), write_spec->w);
+       s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
+       g_string_free (gstr, TRUE);
+       return s;
       }
       break;
     case COL_DECIMALS:
       {
-       g_snprintf(buf, MAX_CELL_TEXT_LEN, "%d", write_spec->d);
-       return buf;
+       gchar *s;
+       GString *gstr = g_string_sized_new (10);
+       g_string_printf (gstr, _("%d"), write_spec->d);
+       s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
+       g_string_free (gstr, TRUE);
+       return s;
       }
       break;
     case COL_COLUMNS:
       {
-       g_snprintf(buf, MAX_CELL_TEXT_LEN, 
-                  "%d", psppire_variable_get_columns(pv));
-       return buf;
+       gchar *s;
+       GString *gstr = g_string_sized_new (10);
+       g_string_printf (gstr, _("%d"), var_get_display_width (pv));
+       s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
+       g_string_free (gstr, TRUE);
+       return s;
       }
       break;
     case COL_LABEL:
-      return psppire_variable_get_label(pv);
+      return pspp_locale_to_utf8 (var_get_label (pv), -1, err);
       break;
+
     case COL_MISSING:
       {
-      const struct missing_values *miss = psppire_variable_get_missing(pv);
-      if ( mv_is_empty(miss)) 
-       return none;
-      else
-       {
-         if ( ! mv_has_range (miss))
-           {
-             const int n = mv_n_values(miss);
-             gchar *mv[4] = {0,0,0,0};
-             gint i;
-             for(i = 0 ; i < n; ++i ) 
-               {
-                 union value v;
-                 mv_peek_value(miss, &v, i);
-                 mv[i] = value_to_text(v, *write_spec);
-               }
-             g_stpcpy(buf, "");
-             for(i = 0 ; i < n; ++i ) 
-               {
-                 if ( i > 0) 
-                   g_strlcat(buf, ", ", MAX_CELL_TEXT_LEN);
-                 g_strlcat(buf, mv[i], MAX_CELL_TEXT_LEN);
-                 g_free(mv[i]);
-               }
-           }
-         else
-           {
-             gchar *l, *h;
-             union value low, high;
-             mv_peek_range(miss, &low.f, &high.f);
-                 
-             l = value_to_text(low, *write_spec);
-             h = value_to_text(high, *write_spec);
-
-             g_snprintf(buf, MAX_CELL_TEXT_LEN, "%s - %s", l, h);
-             g_free(l);
-             g_free(h);
-
-             if ( mv_has_value(miss)) 
-               {
-                 gchar buf2[MAX_CELL_TEXT_LEN];
-                 gchar *s = 0;
-                 union value v;
-                 mv_peek_value(miss, &v, 0);
-
-                 s = value_to_text(v, *write_spec);
-
-                 g_snprintf(buf2, MAX_CELL_TEXT_LEN, "%s, %s", buf, s);
-                 free(s);
-                 g_stpcpy(buf, buf2);
-               }
-           }
-
-         return buf;
-       }
+       return missing_values_to_string (pv, err);
       }
       break;
     case COL_VALUES:
       {
-       const struct val_labs *vls = psppire_variable_get_value_labels(pv);
-       if ( ! vls || 0 == val_labs_count(vls)) 
-         return none;
+       if ( ! var_has_value_labels (pv))
+         return g_locale_to_utf8 (gettext (none), -1, 0, 0, err);
        else
          {
-           struct val_labs_iterator *ip=0;
+           gchar *ss;
+           GString *gstr = g_string_sized_new (10);
+           const struct val_labs *vls = var_get_value_labels (pv);
+           struct val_labs_iterator *ip = 0;
            struct val_lab *vl = val_labs_first_sorted (vls, &ip);
 
-           g_assert(vl);
+           g_assert (vl);
 
            {
-             gchar *const vstr = value_to_text(vl->value, *write_spec);
+             gchar *const vstr = value_to_text (vl->value, *write_spec);
 
-             g_snprintf(buf, MAX_CELL_TEXT_LEN, "{%s,\"%s\"}_", vstr, vl->label);
-             g_free(vstr);
+             g_string_printf (gstr, "{%s,\"%s\"}_", vstr, vl->label);
+             g_free (vstr);
            }
 
-           val_labs_done(&ip);
+           val_labs_done (&ip);
 
-           return buf;
+           ss = pspp_locale_to_utf8 (gstr->str, gstr->len, err);
+           g_string_free (gstr, TRUE);
+           return ss;
          }
       }
       break;
     case COL_ALIGN:
-      return alignments[psppire_variable_get_alignment(pv)];
+      {
+       const gint align = var_get_alignment (pv);
+
+       g_assert (align < n_ALIGNMENTS);
+       return g_locale_to_utf8 (gettext (alignments[align]), -1, 0, 0, err);
+      }
       break;
     case COL_MEASURE:
-      return measures[psppire_variable_get_measure(pv)];
+      {
+       return measure_to_string (pv, err);
+      }
       break;
     }
   return 0;
@@ -615,21 +634,95 @@ text_for_column(const struct PsppireVariable *pv, gint c)
 
 /* Return the number of variables */
 gint
-psppire_var_store_get_var_cnt(PsppireVarStore  *store)
+psppire_var_store_get_var_cnt (PsppireVarStore  *store)
 {
-  return psppire_dict_get_var_cnt(store->dict);
+  return psppire_dict_get_var_cnt (store->dict);
 }
 
 
 void
-psppire_var_store_set_font(PsppireVarStore *store, PangoFontDescription *fd)
+psppire_var_store_set_font (PsppireVarStore *store, const PangoFontDescription *fd)
 {
   g_return_if_fail (store);
   g_return_if_fail (PSPPIRE_IS_VAR_STORE (store));
 
   store->font_desc = fd;
 
-  g_sheet_model_range_changed (G_SHEET_MODEL(store), -1, -1, -1, -1);
+  g_sheet_model_range_changed (G_SHEET_MODEL (store), -1, -1, -1, -1);
+}
+
+
+static gint
+psppire_var_store_get_row_count (const GSheetModel * model)
+{
+  gint rows = 0;
+  PsppireVarStore *vs = PSPPIRE_VAR_STORE (model);
+
+  if (vs->dict)
+    rows =  psppire_dict_get_var_cnt (vs->dict);
+
+  return rows ;
+}
+
+/* Row related funcs */
+
+static gint
+geometry_get_row_count (const GSheetRow *geom, gpointer data)
+{
+  gint rows = 0;
+  PsppireVarStore *vs = PSPPIRE_VAR_STORE (geom);
+
+  if (vs->dict)
+    rows =  psppire_dict_get_var_cnt (vs->dict);
+
+  return rows + TRAILING_ROWS;
+}
+
+
+static gint
+geometry_get_height (const GSheetRow *geom, gint row, gpointer data)
+{
+  return 25;
+}
+
+
+static gboolean
+geometry_is_sensitive (const GSheetRow *geom, gint row, gpointer data)
+{
+  PsppireVarStore *vs = PSPPIRE_VAR_STORE (geom);
+
+  if ( ! vs->dict)
+    return FALSE;
+
+  return  row < psppire_dict_get_var_cnt (vs->dict);
+}
+
+static
+gboolean always_true ()
+{
+  return TRUE;
+}
+
+
+static gchar *
+geometry_get_button_label (const GSheetRow *geom, gint unit, gpointer data)
+{
+  gchar *label = g_strdup_printf (_("%d"), unit);
+
+  return label;
+}
+
+
+static void
+psppire_var_store_sheet_row_init (GSheetRowIface *iface)
+{
+  iface->get_row_count =     geometry_get_row_count;
+  iface->get_height =        geometry_get_height;
+  iface->set_height =        0;
+  iface->get_visibility =    always_true;
+  iface->get_sensitivity =   geometry_is_sensitive;
+
+  iface->get_button_label = geometry_get_button_label;
 }