Adapt to new sheet
[pspp] / src / ui / gui / psppire-data-editor.c
index be911ba6d69817d928264eb13effd969272d029b..e3152e8ca2d6459d725e6f75c11c5935e95811c0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
 
    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
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtk.h>
-#include <gtk-contrib/gtkextra-sheet.h>
-#include "psppire-data-editor.h"
-#include "psppire-var-sheet.h"
 
-#include <language/syntax-string-source.h>
-#include "psppire-data-store.h"
-#include <ui/gui/sheet/psppire-axis.h>
-#include "helper.h"
+#include "ui/gui/psppire-data-editor.h"
 
+#include <gtk/gtk.h>
 #include <gtk-contrib/gtkxpaned.h>
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
 
+#include "data/datasheet.h"
+#include "data/value-labels.h"
+#include "libpspp/range-set.h"
+#include "libpspp/str.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/pspp-sheet-selection.h"
+#include "ui/gui/psppire-data-store.h"
+#include "ui/gui/psppire-value-entry.h"
+#include "ui/gui/psppire-var-sheet.h"
+#include "ui/gui/psppire-conf.h"
 
-static void psppire_data_editor_remove_split (PsppireDataEditor *de);
-static void psppire_data_editor_set_split (PsppireDataEditor *de);
-
-enum {
-  DATA_SELECTION_CHANGED,
-  DATA_AVAILABLE_CHANGED,
-  CASES_SELECTED,
-  VARIABLES_SELECTED,
-  n_SIGNALS
-};
-
-
-static guint data_editor_signals [n_SIGNALS] = { 0 };
+#include "ui/gui/efficient-sheet/jmd-sheet.h"
 
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
 
-static gboolean data_is_selected (PsppireDataEditor *de);
 
 static void psppire_data_editor_class_init          (PsppireDataEditorClass *klass);
 static void psppire_data_editor_init                (PsppireDataEditor      *de);
 
+static void disconnect_data_sheets (PsppireDataEditor *);
+static void refresh_entry (PsppireDataEditor *);
+static void psppire_data_editor_update_ui_manager (PsppireDataEditor *);
+
 GType
 psppire_data_editor_get_type (void)
 {
@@ -86,402 +79,104 @@ psppire_data_editor_dispose (GObject *obj)
 {
   PsppireDataEditor *de = (PsppireDataEditor *) obj;
 
-  if (de->dispose_has_run)
-    return;
-
-  g_object_unref (de->data_store);
-  g_object_unref (de->var_store);
-
-  /* Make sure dispose does not run twice. */
-  de->dispose_has_run = TRUE;
-
-  /* Chain up to the parent class */
-  G_OBJECT_CLASS (parent_class)->dispose (obj);
-}
-
-static void
-psppire_data_editor_finalize (GObject *obj)
-{
-   /* Chain up to the parent class */
-   G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-
-
-static void popup_variable_column_menu (PsppireSheet *sheet, gint column,
-                                       GdkEventButton *event, gpointer data);
-
-static void popup_variable_row_menu (PsppireSheet *sheet, gint row,
-                                    GdkEventButton *event, gpointer data);
-
-
-static void popup_cases_menu (PsppireSheet *sheet, gint row,
-                             GdkEventButton *event, gpointer data);
-
-
-
-
-
-/* Callback which occurs when the data sheet's column title
-   is double clicked */
-static gboolean
-on_data_column_clicked (PsppireDataEditor *de, gint col, gpointer data)
-{
-  PsppireSheetRange visible_range;
-  gint current_row, current_column;
-
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
-                                PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
-
-  psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->var_sheet),
-                            &current_row, &current_column);
-
-  psppire_sheet_set_active_cell (PSPPIRE_SHEET (de->var_sheet), col, current_column);
-
-
-  psppire_sheet_get_visible_range (PSPPIRE_SHEET (de->var_sheet), &visible_range);
-
-  if ( col < visible_range.row0 || col > visible_range.rowi)
-    psppire_sheet_moveto (PSPPIRE_SHEET (de->var_sheet), col, current_column, 0.5, 0.5);
-
-
-  return FALSE;
-}
-
-
-/* Callback which occurs when the var sheet's row title
-   button is double clicked */
-static gboolean
-on_var_row_clicked (PsppireDataEditor *de, gint row, gpointer data)
-{
-  PsppireSheetRange visible_range;
+  disconnect_data_sheets (de);
 
-  gint current_row, current_column;
-
-  gtk_notebook_set_current_page (GTK_NOTEBOOK(de), PSPPIRE_DATA_EDITOR_DATA_VIEW);
-
-  psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]),
-                            &current_row, &current_column);
-
-  psppire_sheet_set_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), current_row, row);
-
-  psppire_sheet_get_visible_range (PSPPIRE_SHEET (de->data_sheet[0]), &visible_range);
-
-  if ( row < visible_range.col0 || row > visible_range.coli)
-    psppire_sheet_moveto (PSPPIRE_SHEET (de->data_sheet[0]), -1, row, 0.5, 0.5);
-
-  return FALSE;
-}
+  if (de->data_store)
+    {
+      g_object_unref (de->data_store);
+      de->data_store = NULL;
+    }
 
+  if (de->dict)
+    {
+      g_object_unref (de->dict);
+      de->dict = NULL;
+    }
 
-/* Moves the focus to a new cell.
-   Returns TRUE iff the move should be disallowed */
-static gboolean
-traverse_cell_callback (PsppireSheet *sheet,
-                       PsppireSheetCell *existing_cell,
-                       PsppireSheetCell *new_cell,
-                       gpointer data)
-{
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
-  const PsppireDict *dict = de->data_store->dict;
+  if (de->font != NULL)
+    {
+      pango_font_description_free (de->font);
+      de->font = NULL;
+    }
 
-  if ( new_cell->col >= psppire_dict_get_var_cnt (dict))
-    return TRUE;
+  if (de->ui_manager)
+    {
+      g_object_unref (de->ui_manager);
+      de->ui_manager = NULL;
+    }
 
-  return FALSE;
+  /* Chain up to the parent class */
+  G_OBJECT_CLASS (parent_class)->dispose (obj);
 }
 
-
 enum
   {
     PROP_0,
     PROP_DATA_STORE,
-    PROP_VAR_STORE,
-    PROP_VS_ROW_MENU,
-    PROP_DS_COLUMN_MENU,
-    PROP_DS_ROW_MENU,
+    PROP_DICTIONARY,
     PROP_VALUE_LABELS,
-    PROP_CURRENT_CASE,
-    PROP_CURRENT_VAR,
-    PROP_DATA_SELECTED,
-    PROP_SPLIT_WINDOW
+    PROP_SPLIT_WINDOW,
+    PROP_UI_MANAGER
   };
 
-
-#define DEFAULT_ROW_HEIGHT 25
-
-static void
-new_data_callback (PsppireDataStore *ds, gpointer data)
-{
-  gint i;
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
-
-  casenumber n_cases =  psppire_data_store_get_case_count (ds);
-
-  for (i = 0; i < 2; ++i)
-    {
-      psppire_axis_clear (de->vaxis[i]);
-      psppire_axis_append_n (de->vaxis[i], n_cases, DEFAULT_ROW_HEIGHT);
-    }
-}
-
-static void
-case_inserted_callback (PsppireDataStore *ds, gint before, gpointer data)
-{
-  gint i;
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
-
-  for (i = 0; i < 2; ++i)
-    psppire_axis_insert (de->vaxis[i], before, DEFAULT_ROW_HEIGHT);
-}
-
-
-static void
-cases_deleted_callback (PsppireDataStore *ds, gint first, gint n_cases, gpointer data)
-{
-  gint i;
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
-
-  for (i = 0; i < 2; ++i)
-    psppire_axis_delete (de->vaxis[0], first, n_cases);
-}
-
-
-
-/* Return the width (in pixels) of an upper case M when rendered in the
-   current font of W
-*/
-static gint
-width_of_m (GtkWidget *w)
-{
-  PangoRectangle rect;
-  PangoLayout *layout = gtk_widget_create_pango_layout (w, "M");
-
-  pango_layout_get_pixel_extents (layout, NULL, &rect);
-
-  g_object_unref (layout);
-
-  return rect.width;
-}
-
-/* Callback for the axis' resize signal.
-   Changes the variable's display width */
-static void
-rewidth_variable (GtkWidget *w, gint unit, glong size)
-{
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (w);
-
-  const PsppireDict *dict = de->data_store->dict;
-  struct variable *var = psppire_dict_get_variable (dict, unit);
-
-  if (NULL == var)
-    return;
-
-  var_set_display_width (var, size / (float) width_of_m (w));
-}
-
-
-static void
-new_variables_callback (PsppireDict *dict, gpointer data)
-{
-  gint v;
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
-  gint m_width = width_of_m (GTK_WIDGET (de));
-
-  PsppireAxis *vaxis;
-  g_object_get (de->var_sheet, "vertical-axis", &vaxis, NULL);
-
-  psppire_axis_clear (vaxis);
-  psppire_axis_append_n (vaxis, 1 + psppire_dict_get_var_cnt (dict), DEFAULT_ROW_HEIGHT);
-
-  g_signal_connect_swapped (de->haxis, "resize-unit",
-                           G_CALLBACK (rewidth_variable), de);
-
-  psppire_axis_clear (de->haxis);
-
-  for (v = 0 ; v < psppire_dict_get_var_cnt (dict); ++v)
-    {
-      const struct variable *var = psppire_dict_get_variable (dict, v);
-
-      psppire_axis_append (de->haxis, m_width * var_get_display_width (var));
-    }
-}
-
-static void
-insert_variable_callback (PsppireDict *dict, gint x, gpointer data)
-{
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
-
-  gint m_width  = width_of_m (GTK_WIDGET (de));
-
-  PsppireAxis *var_vaxis;
-
-  const struct variable *var = psppire_dict_get_variable (dict, x);
-
-  g_object_get (de->var_sheet, "vertical-axis", &var_vaxis, NULL);
-
-  psppire_axis_insert (var_vaxis, x, DEFAULT_ROW_HEIGHT);
-
-
-  psppire_axis_insert (de->haxis, x, m_width * var_get_display_width (var));
-}
-
-
-static void
-delete_variable_callback (PsppireDict *dict, gint posn,
-                         gint x UNUSED, gint y UNUSED, gpointer data)
-{
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
-
-  PsppireAxis *var_vaxis;
-  g_object_get (de->var_sheet, "vertical-axis", &var_vaxis, NULL);
-
-  psppire_axis_delete (var_vaxis, posn, 1);
-
-  psppire_axis_delete (de->haxis, posn, 1);
-}
-
-
 static void
-rewidth_variable_callback (PsppireDict *dict, gint posn, gpointer data)
+psppire_data_editor_refresh_model (PsppireDataEditor *de)
 {
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
-  gint m_width = width_of_m (GTK_WIDGET (de));
-
-  const struct variable *var = psppire_dict_get_variable (dict, posn);
-
-  gint var_width = var_get_display_width (var);
+  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (de->var_sheet);
+    int i;
 
-  /* Don't allow zero width */
-  if ( var_width < 1 )
-    var_width = 1;
-
-  psppire_axis_resize (de->haxis, posn, m_width * var_width);
+  psppire_var_sheet_set_dictionary (var_sheet, de->dict);
 }
 
-
 static void
 psppire_data_editor_set_property (GObject         *object,
                                  guint            prop_id,
                                  const GValue    *value,
                                  GParamSpec      *pspec)
 {
-  int i;
   PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (object);
 
+  int i;
+
   switch (prop_id)
     {
     case PROP_SPLIT_WINDOW:
       psppire_data_editor_split_window (de, g_value_get_boolean (value));
       break;
     case PROP_DATA_STORE:
-      if ( de->data_store) g_object_unref (de->data_store);
+      if ( de->data_store)
+        {
+          g_signal_handlers_disconnect_by_func (de->data_store,
+                                                G_CALLBACK (refresh_entry),
+                                                de);
+          g_object_unref (de->data_store);
+        }
+
       de->data_store = g_value_get_pointer (value);
       g_object_ref (de->data_store);
+      g_print ("NEW STORE\n");
 
-      for (i = 0 ; i < 4 ; ++i )
-       {
-         g_object_set (de->data_sheet[i],
-                       "model", de->data_store,
-                       NULL);
-
-         g_signal_connect_swapped (de->data_store->dict, "filter-changed",
-                                   G_CALLBACK (gtk_widget_queue_draw),
-                                   de->data_sheet[i]);
-       }
-
-      g_signal_connect (de->data_store->dict, "backend-changed",
-                       G_CALLBACK (new_variables_callback), de);
-
-      g_signal_connect (de->data_store->dict, "variable-inserted",
-                       G_CALLBACK (insert_variable_callback), de);
-
-      g_signal_connect (de->data_store->dict, "variable-deleted",
-                       G_CALLBACK (delete_variable_callback), de);
-
-      g_signal_connect (de->data_store->dict, "variable-display-width-changed",
-                       G_CALLBACK (rewidth_variable_callback), de);
-
-      g_signal_connect (de->data_store, "backend-changed",
-                       G_CALLBACK (new_data_callback), de);
+      g_object_set (de->data_sheet, "data-model", de->data_store, NULL);
+      psppire_data_editor_refresh_model (de);
 
-      g_signal_connect (de->data_store, "case-inserted",
-                       G_CALLBACK (case_inserted_callback), de);
+      g_signal_connect_swapped (de->data_store, "case-changed",
+                                G_CALLBACK (refresh_entry), de);
 
-      g_signal_connect (de->data_store, "cases-deleted",
-                       G_CALLBACK (cases_deleted_callback), de);
-
-      break;
-    case PROP_VAR_STORE:
-      if ( de->var_store) g_object_unref (de->var_store);
-      de->var_store = g_value_get_pointer (value);
-      g_object_ref (de->var_store);
-
-      g_object_set (de->var_sheet,
-                   "model", de->var_store,
-                   NULL);
-      break;
-    case PROP_VS_ROW_MENU:
-      {
-       GObject *menu = g_value_get_object (value);
-
-       g_signal_connect (de->var_sheet, "button-event-row",
-                         G_CALLBACK (popup_variable_row_menu), menu);
-      }
       break;
-    case PROP_DS_COLUMN_MENU:
-      {
-       GObject *menu = g_value_get_object (value);
+    case PROP_DICTIONARY:
+      if (de->dict)
+        g_object_unref (de->dict);
+      de->dict = g_value_get_pointer (value);
+      g_object_ref (de->dict);
 
-       g_signal_connect (de->data_sheet[0], "button-event-column",
-                         G_CALLBACK (popup_variable_column_menu), menu);
-      }
-      break;
-    case PROP_DS_ROW_MENU:
-      {
-       GObject *menu = g_value_get_object (value);
+      g_object_set (de->data_sheet, "hmodel", de->dict, NULL);
 
-       g_signal_connect (de->data_sheet[0], "button-event-row",
-                         G_CALLBACK (popup_cases_menu), menu);
-      }
-      break;
-    case PROP_CURRENT_VAR:
-      {
-       gint row, col;
-       gint var = g_value_get_long (value);
-       switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (object)))
-         {
-         case PSPPIRE_DATA_EDITOR_DATA_VIEW:
-           psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &col);
-           psppire_sheet_set_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), row, var);
-           psppire_sheet_moveto (PSPPIRE_SHEET (de->data_sheet[0]), -1, var, 0.5, 0.5);
-           break;
-         case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
-           psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->var_sheet), &row, &col);
-           psppire_sheet_set_active_cell (PSPPIRE_SHEET (de->var_sheet), var, col);
-           psppire_sheet_moveto (PSPPIRE_SHEET (de->var_sheet), var, -1,  0.5, 0.5);
-           break;
-         default:
-           g_assert_not_reached ();
-           break;
-         };
-      }
-      break;
-    case PROP_CURRENT_CASE:
-      {
-       gint row, col;
-       gint case_num = g_value_get_long (value);
-       psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &col);
-       psppire_sheet_set_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), case_num, col);
-       psppire_sheet_moveto (PSPPIRE_SHEET (de->data_sheet[0]), case_num, -1, 0.5, 0.5);
-      }
+      psppire_var_sheet_set_dictionary (PSPPIRE_VAR_SHEET (de->var_sheet),
+                                        de->dict);
       break;
     case PROP_VALUE_LABELS:
-      {
-       psppire_data_store_show_labels (de->data_store,
-                                       g_value_get_boolean (value));
-      }
       break;
+    case PROP_UI_MANAGER:
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -504,57 +199,58 @@ psppire_data_editor_get_property (GObject         *object,
     case PROP_DATA_STORE:
       g_value_set_pointer (value, de->data_store);
       break;
-    case PROP_VAR_STORE:
-      g_value_set_pointer (value, de->var_store);
-      break;
-    case PROP_CURRENT_CASE:
-      {
-       gint row, column;
-       psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &column);
-       g_value_set_long (value, row);
-      }
+    case PROP_DICTIONARY:
+      g_value_set_pointer (value, de->dict);
       break;
-    case PROP_CURRENT_VAR:
-      {
-       gint row, column;
-       psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &column);
-       g_value_set_long (value, column);
-      }
+    case PROP_VALUE_LABELS:
       break;
-    case PROP_DATA_SELECTED:
-      g_value_set_boolean (value, data_is_selected (de));
+    case PROP_UI_MANAGER:
+      g_value_set_object (value, psppire_data_editor_get_ui_manager (de));
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
-    };
+    }
+}
+
+static void
+psppire_data_editor_switch_page (GtkNotebook     *notebook,
+                                GtkWidget *w,
+                                 guint            page_num)
+{
+  GTK_NOTEBOOK_CLASS (parent_class)->switch_page (notebook, w, page_num);
+  psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (notebook));
 }
 
+static void
+psppire_data_editor_set_focus_child (GtkContainer *container,
+                                     GtkWidget    *widget)
+{
+  GTK_CONTAINER_CLASS (parent_class)->set_focus_child (container, widget);
+  psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (container));
+}
 
 static void
 psppire_data_editor_class_init (PsppireDataEditorClass *klass)
 {
   GParamSpec *data_store_spec ;
-  GParamSpec *var_store_spec ;
-  GParamSpec *column_menu_spec;
-  GParamSpec *ds_row_menu_spec;
-  GParamSpec *vs_row_menu_spec;
+  GParamSpec *dict_spec ;
   GParamSpec *value_labels_spec;
-  GParamSpec *current_case_spec;
-  GParamSpec *current_var_spec;
-  GParamSpec *data_selected_spec;
   GParamSpec *split_window_spec;
+  GParamSpec *ui_manager_spec;
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+  GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass);
 
   parent_class = g_type_class_peek_parent (klass);
 
   object_class->dispose = psppire_data_editor_dispose;
-  object_class->finalize = psppire_data_editor_finalize;
-
   object_class->set_property = psppire_data_editor_set_property;
   object_class->get_property = psppire_data_editor_get_property;
 
-  
+  container_class->set_focus_child = psppire_data_editor_set_focus_child;
+
+  notebook_class->switch_page = psppire_data_editor_switch_page;
 
   data_store_spec =
     g_param_spec_pointer ("data-store",
@@ -566,51 +262,15 @@ psppire_data_editor_class_init (PsppireDataEditorClass *klass)
                                    PROP_DATA_STORE,
                                    data_store_spec);
 
-  var_store_spec =
-    g_param_spec_pointer ("var-store",
-                         "Variable Store",
-                         "A pointer to the variable store associated with this editor",
+  dict_spec =
+    g_param_spec_pointer ("dictionary",
+                         "Dictionary",
+                         "A pointer to the dictionary associated with this editor",
                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE );
 
   g_object_class_install_property (object_class,
-                                   PROP_VAR_STORE,
-                                   var_store_spec);
-
-  column_menu_spec =
-    g_param_spec_object ("datasheet-column-menu",
-                        "Data Sheet Column Menu",
-                        "A menu to be displayed when button 3 is pressed in thedata sheet's column title buttons",
-                        GTK_TYPE_MENU,
-                        G_PARAM_WRITABLE);
-
-  g_object_class_install_property (object_class,
-                                   PROP_DS_COLUMN_MENU,
-                                   column_menu_spec);
-
-
-  ds_row_menu_spec =
-    g_param_spec_object ("datasheet-row-menu",
-                        "Data Sheet Row Menu",
-                        "A menu to be displayed when button 3 is pressed in the data sheet's row title buttons",
-                        GTK_TYPE_MENU,
-                        G_PARAM_WRITABLE);
-
-  g_object_class_install_property (object_class,
-                                   PROP_DS_ROW_MENU,
-                                   ds_row_menu_spec);
-
-
-  vs_row_menu_spec =
-    g_param_spec_object ("varsheet-row-menu",
-                        "Variable Sheet Row Menu",
-                        "A menu to be displayed when button 3 is pressed in the variable sheet's row title buttons",
-                        GTK_TYPE_MENU,
-                        G_PARAM_WRITABLE);
-
-  g_object_class_install_property (object_class,
-                                   PROP_VS_ROW_MENU,
-                                   vs_row_menu_spec);
-
+                                   PROP_DICTIONARY,
+                                   dict_spec);
 
   value_labels_spec =
     g_param_spec_boolean ("value-labels",
@@ -624,45 +284,6 @@ psppire_data_editor_class_init (PsppireDataEditorClass *klass)
                                    value_labels_spec);
 
 
-  current_case_spec =
-    g_param_spec_long ("current-case",
-                      "Current Case",
-                      "Zero based number of the selected case",
-                      0, CASENUMBER_MAX,
-                      0,
-                      G_PARAM_WRITABLE | G_PARAM_READABLE);
-
-  g_object_class_install_property (object_class,
-                                   PROP_CURRENT_CASE,
-                                   current_case_spec);
-
-
-  current_var_spec =
-    g_param_spec_long ("current-variable",
-                      "Current Variable",
-                      "Zero based number of the selected variable",
-                      0, G_MAXINT,
-                      0,
-                      G_PARAM_WRITABLE | G_PARAM_READABLE);
-
-  g_object_class_install_property (object_class,
-                                   PROP_CURRENT_VAR,
-                                   current_var_spec);
-
-
-  data_selected_spec =
-    g_param_spec_boolean ("data-selected",
-                         "Data Selected",
-                         "True iff the data view is active and  one or more cells of data have been selected.",
-                         FALSE,
-                         G_PARAM_READABLE);
-
-  g_object_class_install_property (object_class,
-                                   PROP_DATA_SELECTED,
-                                   data_selected_spec);
-
-
-
   split_window_spec =
     g_param_spec_boolean ("split",
                          "Split Window",
@@ -674,1226 +295,295 @@ psppire_data_editor_class_init (PsppireDataEditorClass *klass)
                                    PROP_SPLIT_WINDOW,
                                    split_window_spec);
 
-  data_editor_signals [DATA_SELECTION_CHANGED] =
-    g_signal_new ("data-selection-changed",
-                 G_TYPE_FROM_CLASS (klass),
-                 G_SIGNAL_RUN_FIRST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__BOOLEAN,
-                 G_TYPE_NONE,
-                 1,
-                 G_TYPE_BOOLEAN);
-
-  data_editor_signals [CASES_SELECTED] =
-    g_signal_new ("cases-selected",
-                 G_TYPE_FROM_CLASS (klass),
-                 G_SIGNAL_RUN_FIRST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__INT,
-                 G_TYPE_NONE,
-                 1,
-                 G_TYPE_INT);
-
-
-  data_editor_signals [VARIABLES_SELECTED] =
-    g_signal_new ("variables-selected",
-                 G_TYPE_FROM_CLASS (klass),
-                 G_SIGNAL_RUN_FIRST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__INT,
-                 G_TYPE_NONE,
-                 1,
-                 G_TYPE_INT);
-
-
-  data_editor_signals [DATA_AVAILABLE_CHANGED] =
-    g_signal_new ("data-available-changed",
-                 G_TYPE_FROM_CLASS (klass),
-                 G_SIGNAL_RUN_FIRST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__BOOLEAN,
-                 G_TYPE_NONE,
-                 1,
-                 G_TYPE_BOOLEAN);
+  ui_manager_spec =
+    g_param_spec_object ("ui-manager",
+                         "UI Manager",
+                         "UI manager for the active notebook tab.  The client should merge this UI manager with the active UI manager to obtain menu items and tool bar items specific to the active notebook tab.",
+                         GTK_TYPE_UI_MANAGER,
+                         G_PARAM_READABLE);
+  g_object_class_install_property (object_class,
+                                   PROP_UI_MANAGER,
+                                   ui_manager_spec);
 }
 
-/* Update the data_ref_entry with the reference of the active cell */
-static gint
-update_data_ref_entry (const PsppireSheet *sheet,
-                      gint row, gint col,
-                      gint old_row, gint old_col,
-                      gpointer data)
+static gboolean
+on_data_sheet_var_double_clicked (GtkWidget *data_sheet,
+                                  gint dict_index,
+                                  PsppireDataEditor *de)
 {
-  PsppireDataEditor *de = data;
-
-  PsppireDataStore *data_store =
-    PSPPIRE_DATA_STORE (psppire_sheet_get_model (sheet));
-
-  if (data_store)
-    {
-      const struct variable *var =
-       psppire_dict_get_variable (data_store->dict, col);
-
-      if ( var )
-       {
-         gchar *text = g_strdup_printf ("%d: %s", row + FIRST_CASE_NUMBER,
-                                        var_get_name (var));
-
-         gchar *s = pspp_locale_to_utf8 (text, -1, 0);
-
-         g_free (text);
-
-         gtk_entry_set_text (GTK_ENTRY (de->cell_ref_entry), s);
-
-         g_free (s);
-       }
-      else
-       goto blank_entry;
-
-      if ( var )
-       {
-         gchar *text =
-           psppire_data_store_get_string (data_store, row,
-                                          var_get_dict_index(var));
-
-         if ( ! text )
-           goto blank_entry;
-
-         g_strchug (text);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
+                                 PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
 
-         gtk_entry_set_text (GTK_ENTRY (de->datum_entry), text);
+  psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
+                                   dict_index);
 
-         g_free (text);
-       }
-      else
-       goto blank_entry;
+  return TRUE;
+}
 
-    }
+static gboolean
+on_var_sheet_var_double_clicked (PsppireVarSheet *var_sheet, gint dict_index,
+                                 PsppireDataEditor *de)
+{
 
-  return FALSE;
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
+                                 PSPPIRE_DATA_EDITOR_DATA_VIEW);
 
- blank_entry:
-  gtk_entry_set_text (GTK_ENTRY (de->datum_entry), "");
 
-  return FALSE;
+  return TRUE;
 }
 
-
+/* Refreshes 'de->cell_ref_label' and 'de->datum_entry' from the currently
+   active cell or cells. */
 static void
-datum_entry_activate (GtkEntry *entry, gpointer data)
+refresh_entry (PsppireDataEditor *de)
 {
-  gint row, column;
-  PsppireDataEditor *de = data;
-
-  const gchar *text = gtk_entry_get_text (entry);
-
-  psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &column);
-
-  if ( row == -1 || column == -1)
-    return;
-
-  psppire_data_store_set_string (de->data_store, text, row, column);
 }
 
-static void on_activate (PsppireDataEditor *de);
-static gboolean on_switch_page (PsppireDataEditor *de, GtkNotebookPage *p, gint pagenum, gpointer data);
-static void on_select_range (PsppireDataEditor *de);
-
-static void on_select_row (PsppireSheet *, gint, PsppireDataEditor *);
-static void on_select_variable (PsppireSheet *, gint, PsppireDataEditor *);
-
-
-static void on_owner_change (GtkClipboard *,
-                            GdkEventOwnerChange *, gpointer);
-
 static void
-on_map (GtkWidget *w)
+on_datum_entry_activate (PsppireValueEntry *entry, PsppireDataEditor *de)
 {
-  GtkClipboard *clip = gtk_widget_get_clipboard (w, GDK_SELECTION_CLIPBOARD);
-
-  g_signal_connect (clip, "owner-change", G_CALLBACK (on_owner_change), w);
 }
 
-
 static void
-init_sheet (PsppireDataEditor *de, int i,
-           GtkAdjustment *hadj, GtkAdjustment *vadj,
-           PsppireAxis *vaxis,
-           PsppireAxis *haxis
-           )
+on_data_sheet_selection_changed (PsppSheetSelection *selection,
+                                 PsppireDataEditor *de)
 {
-  de->sheet_bin[i] = gtk_scrolled_window_new (hadj, vadj);
-
-  de->data_sheet[i] = psppire_sheet_new (NULL);
-
-  g_object_set (de->sheet_bin[i],
-               "border-width", 3,
-               "shadow-type",  GTK_SHADOW_ETCHED_IN,
-               NULL);
-
-  g_object_set (haxis, "default-size", 75, NULL);
-  g_object_set (vaxis, "default-size", 25, NULL);
-
-  g_object_set (de->data_sheet[i],
-               "horizontal-axis", haxis,
-               "vertical-axis", vaxis,
-               NULL);
-
-  gtk_container_add (GTK_CONTAINER (de->sheet_bin[i]), de->data_sheet[i]);
-
-  g_signal_connect (de->data_sheet[i], "traverse",
-                   G_CALLBACK (traverse_cell_callback), de);
+  /* In a split view, ensure that only a single data sheet has a nonempty
+     selection.  */
+  if (de->split
+      && pspp_sheet_selection_count_selected_rows (selection)
+      && pspp_sheet_selection_count_selected_columns (selection))
+    {
+    }
 
-  gtk_widget_show (de->sheet_bin[i]);
+  refresh_entry (de);
 }
 
 
 static void
-init_data_sheet (PsppireDataEditor *de)
+disconnect_data_sheets (PsppireDataEditor *de)
 {
-  GtkAdjustment *vadj0, *hadj0;
-  GtkAdjustment *vadj1, *hadj1;
-  GtkWidget *sheet ;
-
-  de->vaxis[0] = psppire_axis_new ();
-  de->vaxis[1] = psppire_axis_new ();
-
-  /* There's only one horizontal axis, since the
-     column widths are parameters of the variables */
-  de->haxis = psppire_axis_new ();
-
-  de->split = TRUE;
-  de->paned = gtk_xpaned_new ();
-
-  init_sheet (de, 0, NULL, NULL, de->vaxis[0], de->haxis);
-  gtk_widget_show (de->sheet_bin[0]);
-  vadj0 = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (de->sheet_bin[0]));
-  hadj0 = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (de->sheet_bin[0]));
-
-  g_object_set (de->sheet_bin[0], "vscrollbar-policy", GTK_POLICY_NEVER, NULL);
-  g_object_set (de->sheet_bin[0], "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
-
-  init_sheet (de, 1, NULL, vadj0, de->vaxis[0], de->haxis);
-  gtk_widget_show (de->sheet_bin[1]);
-  sheet = gtk_bin_get_child (GTK_BIN (de->sheet_bin[1]));
-  psppire_sheet_hide_row_titles (PSPPIRE_SHEET (sheet));
-  hadj1 = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (de->sheet_bin[1]));
-  g_object_set (de->sheet_bin[1], "vscrollbar-policy", GTK_POLICY_ALWAYS, NULL);
-  g_object_set (de->sheet_bin[1], "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
-
-  init_sheet (de, 2, hadj0, NULL, de->vaxis[1], de->haxis);
-  gtk_widget_show (de->sheet_bin[2]);
-  sheet = gtk_bin_get_child (GTK_BIN (de->sheet_bin[2]));
-  psppire_sheet_hide_column_titles (PSPPIRE_SHEET (sheet));
-  g_object_set (de->sheet_bin[2], "vscrollbar-policy", GTK_POLICY_NEVER, NULL);
-  g_object_set (de->sheet_bin[2], "hscrollbar-policy", GTK_POLICY_ALWAYS, NULL);
-  vadj1 = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (de->sheet_bin[2]));
-
-  init_sheet (de, 3, hadj1, vadj1, de->vaxis[1], de->haxis);
-  gtk_widget_show (de->sheet_bin[3]);
-  sheet = gtk_bin_get_child (GTK_BIN (de->sheet_bin[3]));
-  psppire_sheet_hide_column_titles (PSPPIRE_SHEET (sheet));
-  psppire_sheet_hide_row_titles (PSPPIRE_SHEET (sheet));
-  g_object_set (de->sheet_bin[3], "vscrollbar-policy", GTK_POLICY_ALWAYS, NULL);
-  g_object_set (de->sheet_bin[3], "hscrollbar-policy", GTK_POLICY_ALWAYS, NULL);
-
-  gtk_xpaned_pack_top_left (GTK_XPANED (de->paned), de->sheet_bin[0], TRUE, TRUE);
-  gtk_xpaned_pack_top_right (GTK_XPANED (de->paned), de->sheet_bin[1], TRUE, TRUE);
-  gtk_xpaned_pack_bottom_left (GTK_XPANED (de->paned), de->sheet_bin[2], TRUE, TRUE);
-  gtk_xpaned_pack_bottom_right (GTK_XPANED (de->paned), de->sheet_bin[3], TRUE, TRUE);
-
-  gtk_xpaned_set_position_y (GTK_XPANED (de->paned), 150);
-  gtk_xpaned_set_position_x (GTK_XPANED (de->paned), 350);
+  int i;
+
 }
 
 
+static void set_font_recursively (GtkWidget *w, gpointer data);
+
 static void
 psppire_data_editor_init (PsppireDataEditor *de)
 {
-  GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
-  GtkWidget *sw_vs = gtk_scrolled_window_new (NULL, NULL);
+  GtkWidget *var_sheet_scroller;
+  GtkWidget *hbox;
+  gchar *fontname = NULL;
 
-  init_data_sheet (de);
-
-  de->data_vbox = gtk_vbox_new (FALSE, 0);
-  de->var_sheet = psppire_var_sheet_new ();
+  de->font = NULL;
+  de->ui_manager = NULL;
+  de->old_vbox_widget = NULL;
 
   g_object_set (de, "tab-pos", GTK_POS_BOTTOM, NULL);
 
-  de->datum_entry = gtk_entry_new ();
-  de->cell_ref_entry = gtk_entry_new ();
+  de->cell_ref_label = gtk_label_new ("");
+  gtk_label_set_width_chars (GTK_LABEL (de->cell_ref_label), 25);
+  gtk_widget_set_valign (de->cell_ref_label, GTK_ALIGN_CENTER);
 
-  g_object_set (de->cell_ref_entry,
-               "sensitive", FALSE,
-               "editable",  FALSE,
-               "width_chars", 25,
-               NULL);
+  de->datum_entry = psppire_value_entry_new ();
+  g_signal_connect (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (de->datum_entry))),
+                    "activate", G_CALLBACK (on_datum_entry_activate), de);
 
-  gtk_box_pack_start (GTK_BOX (hbox), de->cell_ref_entry, FALSE, FALSE, 0);
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), de->cell_ref_label, FALSE, FALSE, 0);
   gtk_box_pack_start (GTK_BOX (hbox), de->datum_entry, TRUE, TRUE, 0);
 
+  de->split = FALSE;
+  de->data_sheet = g_object_new (JMD_TYPE_SHEET,
+                                "splitter", GTK_TYPE_XPANED,
+                                NULL);
+  GtkWidget *button = jmd_sheet_get_button (JMD_SHEET (de->data_sheet));
+  gtk_button_set_label (GTK_BUTTON (button), _("Case"));
+  de->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+  gtk_box_pack_start (GTK_BOX (de->vbox), hbox, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (de->vbox), de->data_sheet, TRUE, TRUE, 0);
+
+  gtk_notebook_append_page (GTK_NOTEBOOK (de), de->vbox,
+                           gtk_label_new_with_mnemonic (_("Data View")));
 
-  gtk_container_add (GTK_CONTAINER (sw_vs), de->var_sheet);
-  gtk_widget_show_all (sw_vs);
+  gtk_widget_show_all (de->vbox);
 
+  de->var_sheet = GTK_WIDGET (psppire_var_sheet_new ());
 
-  gtk_box_pack_start (GTK_BOX (de->data_vbox), hbox, FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (de->data_vbox), de->paned, TRUE, TRUE, 0);
+  pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet),
+                                  GTK_TREE_VIEW_GRID_LINES_BOTH);
+  var_sheet_scroller = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (var_sheet_scroller),
+                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_container_add (GTK_CONTAINER (var_sheet_scroller), de->var_sheet);
+  gtk_widget_show_all (var_sheet_scroller);
 
+  gtk_notebook_append_page (GTK_NOTEBOOK (de), var_sheet_scroller,
+                           gtk_label_new_with_mnemonic (_("Variable View")));
 
-  psppire_data_editor_remove_split (de);
+  g_signal_connect (de->var_sheet, "var-double-clicked",
+                    G_CALLBACK (on_var_sheet_var_double_clicked), de);
 
-  gtk_widget_show_all (de->data_vbox);
-
-  gtk_notebook_append_page (GTK_NOTEBOOK (de), de->data_vbox,
-                           gtk_label_new_with_mnemonic (_("Data View")));
-
-  gtk_notebook_append_page (GTK_NOTEBOOK (de), sw_vs,
-                           gtk_label_new_with_mnemonic (_("Variable View")));
-
-  g_signal_connect (de->data_sheet[0], "activate",
-                   G_CALLBACK (update_data_ref_entry),
-                   de);
-
-  g_signal_connect (de->datum_entry, "activate",
-                   G_CALLBACK (datum_entry_activate),
-                   de);
-
-
-  g_signal_connect_swapped (de->data_sheet[0],
-                   "double-click-column",
-                   G_CALLBACK (on_data_column_clicked),
-                   de);
-
-  g_signal_connect_swapped (de->var_sheet,
-                   "double-click-row",
-                   G_CALLBACK (on_var_row_clicked),
-                   de);
-
-  g_signal_connect_swapped (de->data_sheet[0], "activate",
-                           G_CALLBACK (on_activate),
-                           de);
-
-  g_signal_connect_swapped (de->data_sheet[0], "select-range",
-                           G_CALLBACK (on_select_range),
-                           de);
-
-  g_signal_connect (de->data_sheet[0], "select-row",
-                   G_CALLBACK (on_select_row), de);
-
-  g_signal_connect (de->data_sheet[0], "select-column",
-                   G_CALLBACK (on_select_variable), de);
-
-
-  g_signal_connect (de->var_sheet, "select-row",
-                   G_CALLBACK (on_select_variable), de);
-
-
-  g_signal_connect_after (de, "switch-page",
-                   G_CALLBACK (on_switch_page),
-                   NULL);
-
-  g_object_set (de, "can-focus", FALSE, NULL);
-
-  g_signal_connect (de, "map", G_CALLBACK (on_map), NULL);
-
-
-  //     psppire_sheet_hide_column_titles (de->var_sheet);
-  //  psppire_sheet_hide_row_titles (de->data_sheet);
+  g_object_set (de, "can-focus", FALSE, NULL);
 
+  if (psppire_conf_get_string (psppire_conf_new (),
+                          "Data Editor", "font",
+                               &fontname) )
+    {
+      de->font = pango_font_description_from_string (fontname);
+      g_free (fontname);
+      set_font_recursively (GTK_WIDGET (de), de->font);
+    }
 
-  de->dispose_has_run = FALSE;
+  psppire_data_editor_update_ui_manager (de);
 }
 
-
 GtkWidget*
-psppire_data_editor_new (PsppireVarStore *var_store,
+psppire_data_editor_new (PsppireDict *dict,
                         PsppireDataStore *data_store)
 {
   return  g_object_new (PSPPIRE_DATA_EDITOR_TYPE,
-                                    "var-store",  var_store,
-                                    "data-store",  data_store,
-                                    NULL);
-}
-
-
-static void
-psppire_data_editor_remove_split (PsppireDataEditor *de)
-{
-  if ( !de->split ) return;
-  de->split = FALSE;
-
-  g_object_ref (de->sheet_bin[0]);
-  gtk_container_remove (GTK_CONTAINER (de->paned), de->sheet_bin[0]);
-
-  g_object_ref (de->paned);
-  gtk_container_remove (GTK_CONTAINER (de->data_vbox), de->paned);
-
-  gtk_box_pack_start (GTK_BOX (de->data_vbox), de->sheet_bin[0],
-                     TRUE, TRUE, 0);
-
-  g_object_unref (de->sheet_bin[0]);
-
-  g_object_set (de->sheet_bin[0], "vscrollbar-policy",
-               GTK_POLICY_ALWAYS, NULL);
-
-  g_object_set (de->sheet_bin[0], "hscrollbar-policy",
-               GTK_POLICY_ALWAYS, NULL);
+                        "dictionary",  dict,
+                        "data-store",  data_store,
+                        NULL);
 }
-
-
-static void
-psppire_data_editor_set_split (PsppireDataEditor *de)
-{
-  if ( de->split ) return;
-  de->split = TRUE;
-
-  g_object_ref (de->sheet_bin[0]);
-  gtk_container_remove (GTK_CONTAINER (de->data_vbox), de->sheet_bin[0]);
-
-  gtk_xpaned_pack_top_left (GTK_XPANED (de->paned), de->sheet_bin [0],
-                           TRUE, TRUE);
-
-  gtk_box_pack_start (GTK_BOX (de->data_vbox), de->paned,
-                     TRUE, TRUE, 0);
-
-  g_object_unref (de->paned);
-
-  g_object_set (de->sheet_bin[0], "vscrollbar-policy",
-               GTK_POLICY_NEVER, NULL);
-
-  g_object_set (de->sheet_bin[0], "hscrollbar-policy",
-               GTK_POLICY_NEVER, NULL);
-}
-
-void
-psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split)
-{
-  if (split )
-    psppire_data_editor_set_split (de);
-  else
-    psppire_data_editor_remove_split (de);
-
-  gtk_widget_show_all (de->data_vbox);
-}
-
-static void data_sheet_set_clip (PsppireSheet *sheet);
-static void data_sheet_contents_received_callback (GtkClipboard *clipboard,
-                                                  GtkSelectionData *sd,
-                                                  gpointer data);
-
-
-void
-psppire_data_editor_clip_copy (PsppireDataEditor *de)
-{
-  data_sheet_set_clip (PSPPIRE_SHEET (de->data_sheet[0]));
-}
-
-void
-psppire_data_editor_clip_paste (PsppireDataEditor *de)
-{
-  GdkDisplay *display = gtk_widget_get_display ( GTK_WIDGET (de));
-  GtkClipboard *clipboard =
-    gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
-
-  gtk_clipboard_request_contents (clipboard,
-                                 gdk_atom_intern ("UTF8_STRING", TRUE),
-                                 data_sheet_contents_received_callback,
-                                 de);
-}
-
-
-
-void
-psppire_data_editor_clip_cut (PsppireDataEditor *de)
-{
-  gint max_rows, max_columns;
-  gint r;
-  PsppireSheetRange range;
-  PsppireDataStore *ds = de->data_store;
-
-  data_sheet_set_clip (PSPPIRE_SHEET (de->data_sheet[0]));
-
-  /* Now blank all the cells */
-  psppire_sheet_get_selected_range (PSPPIRE_SHEET (de->data_sheet[0]), &range);
-
-   /* If nothing selected, then use active cell */
-  if ( range.row0 < 0 || range.col0 < 0 )
-    {
-      gint row, col;
-      psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &col);
-
-      range.row0 = range.rowi = row;
-      range.col0 = range.coli = col;
-    }
-
-  /* The sheet range can include cells that do not include data.
-     Exclude them from the range. */
-  max_rows = psppire_data_store_get_case_count (ds);
-  if (range.rowi >= max_rows)
-    {
-      if (max_rows == 0)
-        return;
-      range.rowi = max_rows - 1;
-    }
-
-  max_columns = dict_get_var_cnt (ds->dict->dict);
-  if (range.coli >= max_columns)
-    {
-      if (max_columns == 0)
-        return;
-      range.coli = max_columns - 1;
-    }
-
-  g_return_if_fail (range.rowi >= range.row0);
-  g_return_if_fail (range.row0 >= 0);
-  g_return_if_fail (range.coli >= range.col0);
-  g_return_if_fail (range.col0 >= 0);
-
-
-  for (r = range.row0; r <= range.rowi ; ++r )
-    {
-      gint c;
-
-      for (c = range.col0 ; c <= range.coli; ++c)
-       {
-         psppire_data_store_set_string (ds, "", r, c);
-       }
-    }
-
-  /* and remove the selection */
-  psppire_sheet_unselect_range (PSPPIRE_SHEET (de->data_sheet[0]));
-}
-
-
 \f
-
-/* Popup menu related stuff */
-
-static void
-popup_variable_column_menu (PsppireSheet *sheet, gint column,
-                    GdkEventButton *event, gpointer data)
-{
-  GtkMenu *menu = GTK_MENU (data);
-
-  PsppireDataStore *data_store =
-    PSPPIRE_DATA_STORE (psppire_sheet_get_model (sheet));
-
-  const struct variable *v =
-    psppire_dict_get_variable (data_store->dict, column);
-
-  if ( v && event->button == 3)
-    {
-      psppire_sheet_select_column (sheet, column);
-
-      gtk_menu_popup (menu,
-                     NULL, NULL, NULL, NULL,
-                     event->button, event->time);
-    }
-}
-
-
-static void
-popup_variable_row_menu (PsppireSheet *sheet, gint row,
-                    GdkEventButton *event, gpointer data)
-{
-  GtkMenu *menu = GTK_MENU (data);
-
-  PsppireVarStore *var_store =
-    PSPPIRE_VAR_STORE (psppire_sheet_get_model (sheet));
-
-  const struct variable *v =
-    psppire_dict_get_variable (var_store->dict, row);
-
-  if ( v && event->button == 3)
-    {
-      psppire_sheet_select_row (sheet, row);
-
-      gtk_menu_popup (menu,
-                     NULL, NULL, NULL, NULL,
-                     event->button, event->time);
-    }
-}
-
-
-static void
-popup_cases_menu (PsppireSheet *sheet, gint row,
-                 GdkEventButton *event, gpointer data)
+/* Turns the visible grid on or off, according to GRID_VISIBLE, for DE's data
+   sheet(s) and variable sheet. */
+void
+psppire_data_editor_show_grid (PsppireDataEditor *de, gboolean grid_visible)
 {
-  GtkMenu *menu = GTK_MENU (data);
-
-  PsppireDataStore *data_store =
-    PSPPIRE_DATA_STORE (psppire_sheet_get_model (sheet));
+  GtkTreeViewGridLines grid;
+  int i;
 
-  if ( row <= psppire_data_store_get_case_count (data_store) &&
-       event->button == 3)
-    {
-      psppire_sheet_select_row (sheet, row);
+  grid = (grid_visible
+          ? GTK_TREE_VIEW_GRID_LINES_BOTH
+          : GTK_TREE_VIEW_GRID_LINES_NONE);
 
-      gtk_menu_popup (menu,
-                     NULL, NULL, NULL, NULL,
-                     event->button, event->time);
-    }
+  pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet), grid);
 }
 
-\f
-
-/* Sorting */
 
 static void
-do_sort (PsppireDataStore *ds, int var, gboolean descend)
+set_font_recursively (GtkWidget *w, gpointer data)
 {
-  GString *string = g_string_new ("SORT CASES BY ");
-
-  const struct variable *v =
-    psppire_dict_get_variable (ds->dict, var);
-
-  g_string_append_printf (string, "%s", var_get_name (v));
-
-  if ( descend )
-    g_string_append (string, " (D)");
-
-  g_string_append (string, ".");
+  PangoFontDescription *font_desc = data;
 
-  execute_syntax (create_syntax_string_source (string->str));
+  gtk_widget_override_font (w, font_desc);
 
-  g_string_free (string, TRUE);
+  if ( GTK_IS_CONTAINER (w))
+    gtk_container_foreach (GTK_CONTAINER (w), set_font_recursively, font_desc);
 }
 
-
-/* Sort the data by the the variable which the editor has currently
-   selected */
+/* Sets FONT_DESC as the font used by the data sheet(s) and variable sheet. */
 void
-psppire_data_editor_sort_ascending  (PsppireDataEditor *de)
+psppire_data_editor_set_font (PsppireDataEditor *de, PangoFontDescription *font_desc)
 {
-  PsppireSheetRange range;
-  psppire_sheet_get_selected_range (PSPPIRE_SHEET(de->data_sheet[0]), &range);
+  gchar *font_name;
+  set_font_recursively (GTK_WIDGET (de), font_desc);
 
-  do_sort (de->data_store,  range.col0, FALSE);
-}
+  if (de->font)
+    pango_font_description_free (de->font);
+  de->font = pango_font_description_copy (font_desc);
+  font_name = pango_font_description_to_string (de->font);
 
+  psppire_conf_set_string (psppire_conf_new (),
+                          "Data Editor", "font",
+                          font_name);
 
-/* Sort the data by the the variable which the editor has currently
-   selected */
-void
-psppire_data_editor_sort_descending (PsppireDataEditor *de)
-{
-  PsppireSheetRange range;
-  psppire_sheet_get_selected_range (PSPPIRE_SHEET(de->data_sheet[0]), &range);
-
-  do_sort (de->data_store,  range.col0, TRUE);
 }
 
-
-\f
-
-
-/* Insert a new variable  before the currently selected position */
+/* If SPLIT is TRUE, splits DE's data sheet into four panes.
+   If SPLIT is FALSE, un-splits it into a single pane. */
 void
-psppire_data_editor_insert_variable (PsppireDataEditor *de)
+psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split)
 {
-  glong posn = 0;
-
-  switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
-    {
-    case PSPPIRE_DATA_EDITOR_DATA_VIEW:
-      if ( de->data_sheet[0]->state == PSPPIRE_SHEET_COLUMN_SELECTED )
-       posn = PSPPIRE_SHEET (de->data_sheet[0])->range.col0;
-      else
-       posn = PSPPIRE_SHEET (de->data_sheet[0])->active_cell.col;
-      break;
-    case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
-      if ( de->var_sheet->state == PSPPIRE_SHEET_ROW_SELECTED )
-       posn = PSPPIRE_SHEET (de->var_sheet)->range.row0;
-      else
-       posn = PSPPIRE_SHEET (de->var_sheet)->active_cell.row;
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
-    };
+  GtkTreeViewGridLines grid_lines;
+  gboolean labels;
 
-  psppire_dict_insert_variable (de->data_store->dict, posn, NULL);
-}
+  if (split == de->split)
+    return;
 
-/* Insert a new case before the currently selected position */
-void
-psppire_data_editor_insert_case (PsppireDataEditor *de)
-{
-  glong posn = -1;
 
-  if ( de->data_sheet[0]->state == PSPPIRE_SHEET_ROW_SELECTED )
-    posn = PSPPIRE_SHEET (de->data_sheet[0])->range.row0;
-  else
-    posn = PSPPIRE_SHEET (de->data_sheet[0])->active_cell.row;
 
-  if ( posn == -1 ) posn = 0;
+  disconnect_data_sheets (de);
 
-  psppire_data_store_insert_new_case (de->data_store, posn);
-}
+  psppire_data_editor_refresh_model (de);
 
-/* Delete the cases currently selected in the data sheet */
-void
-psppire_data_editor_delete_cases    (PsppireDataEditor *de)
-{
-  gint first = PSPPIRE_SHEET (de->data_sheet[0])->range.row0;
-  gint n = PSPPIRE_SHEET (de->data_sheet[0])->range.rowi - first + 1;
+  gtk_widget_show_all (de->vbox);
 
-  psppire_data_store_delete_cases (de->data_store, first, n);
+  if (de->font)
+    set_font_recursively (GTK_WIDGET (de), de->font);
 
-  psppire_sheet_unselect_range (PSPPIRE_SHEET (de->data_sheet[0]));
+  de->split = split;
+  g_object_notify (G_OBJECT (de), "split");
+  psppire_data_editor_update_ui_manager (de);
 }
 
-/* Delete the variables currently selected in the
-   datasheet or variable sheet */
+/* Makes the variable with dictionary index DICT_INDEX in DE's dictionary
+   visible and selected in the active view in DE. */
 void
-psppire_data_editor_delete_variables (PsppireDataEditor *de)
+psppire_data_editor_goto_variable (PsppireDataEditor *de, gint dict_index)
 {
-  gint first, n;
 
   switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
     {
-    case PSPPIRE_DATA_EDITOR_DATA_VIEW:
-      first = PSPPIRE_SHEET (de->data_sheet[0])->range.col0;
-      n = PSPPIRE_SHEET (de->data_sheet[0])->range.coli - first + 1;
-      break;
+
     case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
-      first = PSPPIRE_SHEET (de->var_sheet)->range.row0;
-      n = PSPPIRE_SHEET (de->var_sheet)->range.rowi - first + 1;
-      break;
-    default:
-      g_assert_not_reached ();
+      psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
+                                       dict_index);
       break;
     }
-
-  psppire_dict_delete_variables (de->var_store->dict, first, n);
-
-  psppire_sheet_unselect_range (PSPPIRE_SHEET (de->data_sheet[0]));
-  psppire_sheet_unselect_range (PSPPIRE_SHEET (de->var_sheet));
-}
-
-
-void
-psppire_data_editor_show_grid (PsppireDataEditor *de, gboolean grid_visible)
-{
-  psppire_sheet_show_grid (PSPPIRE_SHEET (de->var_sheet), grid_visible);
-  psppire_sheet_show_grid (PSPPIRE_SHEET (de->data_sheet[0]), grid_visible);
-}
-
-
-static void
-set_font (GtkWidget *w, gpointer data)
-{
-  PangoFontDescription *font_desc = data;
-  GtkRcStyle *style = gtk_widget_get_modifier_style (w);
-
-  pango_font_description_free (style->font_desc);
-  style->font_desc = pango_font_description_copy (font_desc);
-
-  gtk_widget_modify_style (w, style);
-
-  if ( GTK_IS_CONTAINER (w))
-    gtk_container_foreach (GTK_CONTAINER (w), set_font, font_desc);
-}
-
-void
-psppire_data_editor_set_font (PsppireDataEditor *de, PangoFontDescription *font_desc)
-{
-  set_font (GTK_WIDGET (de), font_desc);
-  gtk_container_foreach (GTK_CONTAINER (de), set_font, font_desc);
 }
 
 
-\f
-
+/* Returns the UI manager that should be merged into DE's toplevel widget's UI
+   manager to display menu items and toolbar items specific to DE's current
+   page and data sheet.
 
-static void
-emit_selected_signal (PsppireDataEditor *de)
+   DE's toplevel widget can watch for changes by connecting to DE's
+   notify::ui-manager signal. */
+GtkUIManager *
+psppire_data_editor_get_ui_manager (PsppireDataEditor *de)
 {
-  gboolean data_selected = data_is_selected (de);
-
-  g_signal_emit (de, data_editor_signals[DATA_SELECTION_CHANGED], 0, data_selected);
+  psppire_data_editor_update_ui_manager (de);
+  return de->ui_manager;
 }
 
-
 static void
-on_activate (PsppireDataEditor *de)
+psppire_data_editor_update_ui_manager (PsppireDataEditor *de)
 {
-  gint row, col;
-  psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &col);
+  GtkUIManager *ui_manager;
 
+  ui_manager = NULL;
 
-  if ( row < psppire_data_store_get_case_count (de->data_store)
-       &&
-       col < psppire_var_store_get_var_cnt (de->var_store))
-    {
-      emit_selected_signal (de);
-      return ;
-    }
-
-  emit_selected_signal (de);
-}
-
-
-static void
-on_select_range (PsppireDataEditor *de)
-{
-  PsppireSheetRange range;
-
-  psppire_sheet_get_selected_range (PSPPIRE_SHEET (de->data_sheet[0]), &range);
-
-  if ( range.rowi < psppire_data_store_get_case_count (de->data_store)
-       &&
-       range.coli < psppire_var_store_get_var_cnt (de->var_store))
-    {
-      emit_selected_signal (de);
-      return;
-    }
-
-  emit_selected_signal (de);
-}
-
-
-static gboolean
-on_switch_page (PsppireDataEditor *de, GtkNotebookPage *p,
-               gint pagenum, gpointer data)
-{
-  switch (pagenum)
+  switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
     {
     case PSPPIRE_DATA_EDITOR_DATA_VIEW:
-      gtk_widget_grab_focus (de->data_vbox);
-      on_select_range (de);
       break;
+
     case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
-      gtk_widget_grab_focus (de->var_sheet);
-      emit_selected_signal (de);
+      ui_manager = psppire_var_sheet_get_ui_manager (
+        PSPPIRE_VAR_SHEET (de->var_sheet));
       break;
+
     default:
+      /* This happens transiently in psppire_data_editor_init(). */
       break;
-    };
-
-  return TRUE;
-}
-
-
-
-static gboolean
-data_is_selected (PsppireDataEditor *de)
-{
-  PsppireSheetRange range;
-  gint row, col;
-
-  if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (de)) != PSPPIRE_DATA_EDITOR_DATA_VIEW)
-    return FALSE;
-
-  psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &col);
-
-  if ( row >= psppire_data_store_get_case_count (de->data_store)
-       ||
-       col >= psppire_var_store_get_var_cnt (de->var_store))
-    {
-      return FALSE;
-    }
-
-  psppire_sheet_get_selected_range (PSPPIRE_SHEET (de->data_sheet[0]), &range);
-
-  if ( range.rowi >= psppire_data_store_get_case_count (de->data_store)
-       ||
-       range.coli >= psppire_var_store_get_var_cnt (de->var_store))
-    {
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-
-static void
-on_select_row (PsppireSheet *sheet, gint row, PsppireDataEditor *de)
-{
-  g_signal_emit (de, data_editor_signals[CASES_SELECTED], 0, row);
-}
-
-
-static void
-on_select_variable (PsppireSheet *sheet, gint var, PsppireDataEditor *de)
-{
-  g_signal_emit (de, data_editor_signals[VARIABLES_SELECTED], 0, var);
-}
-
-
-\f
-
-/* Clipboard stuff */
-
-
-#include <data/casereader.h>
-#include <data/case-map.h>
-#include <data/casewriter.h>
-
-#include <data/data-out.h>
-#include "xalloc.h"
-
-/* A casereader and dictionary holding the data currently in the clip */
-static struct casereader *clip_datasheet = NULL;
-static struct dictionary *clip_dict = NULL;
-
-
-static void data_sheet_update_clipboard (PsppireSheet *);
-
-/* Set the clip according to the currently
-   selected range in the data sheet */
-static void
-data_sheet_set_clip (PsppireSheet *sheet)
-{
-  int i;
-  struct casewriter *writer ;
-  PsppireSheetRange range;
-  PsppireDataStore *ds;
-  struct case_map *map = NULL;
-  casenumber max_rows;
-  size_t max_columns;
-
-  ds = PSPPIRE_DATA_STORE (psppire_sheet_get_model (sheet));
-
-  psppire_sheet_get_selected_range (sheet, &range);
-
-   /* If nothing selected, then use active cell */
-  if ( range.row0 < 0 || range.col0 < 0 )
-    {
-      gint row, col;
-      psppire_sheet_get_active_cell (sheet, &row, &col);
-
-      range.row0 = range.rowi = row;
-      range.col0 = range.coli = col;
-    }
-
-  /* The sheet range can include cells that do not include data.
-     Exclude them from the range. */
-  max_rows = psppire_data_store_get_case_count (ds);
-  if (range.rowi >= max_rows)
-    {
-      if (max_rows == 0)
-        return;
-      range.rowi = max_rows - 1;
-    }
-  max_columns = dict_get_var_cnt (ds->dict->dict);
-  if (range.coli >= max_columns)
-    {
-      if (max_columns == 0)
-        return;
-      range.coli = max_columns - 1;
-    }
-
-  g_return_if_fail (range.rowi >= range.row0);
-  g_return_if_fail (range.row0 >= 0);
-  g_return_if_fail (range.coli >= range.col0);
-  g_return_if_fail (range.col0 >= 0);
-
-  /* Destroy any existing clip */
-  if ( clip_datasheet )
-    {
-      casereader_destroy (clip_datasheet);
-      clip_datasheet = NULL;
-    }
-
-  if ( clip_dict )
-    {
-      dict_destroy (clip_dict);
-      clip_dict = NULL;
     }
 
-  /* Construct clip dictionary. */
-  clip_dict = dict_create ();
-  for (i = range.col0; i <= range.coli; i++)
+  if (ui_manager != de->ui_manager)
     {
-      const struct variable *old = dict_get_var (ds->dict->dict, i);
-      dict_clone_var_assert (clip_dict, old, var_get_name (old));
-    }
+      if (de->ui_manager)
+        g_object_unref (de->ui_manager);
+      if (ui_manager)
+        g_object_ref (ui_manager);
+      de->ui_manager = ui_manager;
 
-  /* Construct clip data. */
-  map = case_map_by_name (ds->dict->dict, clip_dict);
-  writer = autopaging_writer_create (dict_get_next_value_idx (clip_dict));
-  for (i = range.row0; i <= range.rowi ; ++i )
-    {
-      struct ccase *old = psppire_data_store_get_case (ds, i);
-      if (old != NULL)
-        casewriter_write (writer, case_map_execute (map, old));
-      else
-        casewriter_force_error (writer);
+      g_object_notify (G_OBJECT (de), "ui-manager");
     }
-  case_map_destroy (map);
-
-  clip_datasheet = casewriter_make_reader (writer);
-
-  data_sheet_update_clipboard (sheet);
 }
 
-enum {
-  SELECT_FMT_NULL,
-  SELECT_FMT_TEXT,
-  SELECT_FMT_HTML
-};
-
-
-/* Perform data_out for case CC, variable V, appending to STRING */
-static void
-data_out_g_string (GString *string, const struct variable *v,
-                  const struct ccase *cc)
-{
-  char *buf ;
-
-  const struct fmt_spec *fs = var_get_print_format (v);
-  const union value *val = case_data (cc, v);
-  buf = xzalloc (fs->w);
-
-  data_out (val, fs, buf);
-
-  g_string_append_len (string, buf, fs->w);
-
-  g_free (buf);
-}
-
-static GString *
-clip_to_text (void)
-{
-  casenumber r;
-  GString *string;
-
-  const size_t val_cnt = casereader_get_value_cnt (clip_datasheet);
-  const casenumber case_cnt = casereader_get_case_cnt (clip_datasheet);
-  const size_t var_cnt = dict_get_var_cnt (clip_dict);
-
-  string = g_string_sized_new (10 * val_cnt * case_cnt);
 
-  for (r = 0 ; r < case_cnt ; ++r )
-    {
-      int c;
-      struct ccase *cc;
-
-      cc = casereader_peek (clip_datasheet, r);
-      if (cc == NULL)
-       {
-         g_warning ("Clipboard seems to have inexplicably shrunk");
-         break;
-       }
-
-      for (c = 0 ; c < var_cnt ; ++c)
-       {
-         const struct variable *v = dict_get_var (clip_dict, c);
-         data_out_g_string (string, v, cc);
-         if ( c < val_cnt - 1 )
-           g_string_append (string, "\t");
-       }
-
-      if ( r < case_cnt)
-       g_string_append (string, "\n");
-
-      case_unref (cc);
-    }
-
-  return string;
-}
-
-
-static GString *
-clip_to_html (void)
-{
-  casenumber r;
-  GString *string;
-
-  const size_t val_cnt = casereader_get_value_cnt (clip_datasheet);
-  const casenumber case_cnt = casereader_get_case_cnt (clip_datasheet);
-  const size_t var_cnt = dict_get_var_cnt (clip_dict);
-
-
-  /* Guestimate the size needed */
-  string = g_string_sized_new (20 * val_cnt * case_cnt);
-
-  g_string_append (string, "<table>\n");
-  for (r = 0 ; r < case_cnt ; ++r )
-    {
-      int c;
-      struct ccase *cc = casereader_peek (clip_datasheet, r);
-      if (cc == NULL)
-       {
-         g_warning ("Clipboard seems to have inexplicably shrunk");
-         break;
-       }
-      g_string_append (string, "<tr>\n");
-
-      for (c = 0 ; c < var_cnt ; ++c)
-       {
-         const struct variable *v = dict_get_var (clip_dict, c);
-         g_string_append (string, "<td>");
-         data_out_g_string (string, v, cc);
-         g_string_append (string, "</td>\n");
-       }
-
-      g_string_append (string, "</tr>\n");
-
-      case_unref (cc);
-    }
-  g_string_append (string, "</table>\n");
-
-  return string;
-}
-
-
-
-static void
-clipboard_get_cb (GtkClipboard     *clipboard,
-                 GtkSelectionData *selection_data,
-                 guint             info,
-                 gpointer          data)
-{
-  GString *string = NULL;
-
-  switch (info)
-    {
-    case SELECT_FMT_TEXT:
-      string = clip_to_text ();
-      break;
-    case SELECT_FMT_HTML:
-      string = clip_to_html ();
-      break;
-    default:
-      g_assert_not_reached ();
-    }
-
-  gtk_selection_data_set (selection_data, selection_data->target,
-                         8,
-                         (const guchar *) string->str, string->len);
-
-  g_string_free (string, TRUE);
-}
-
-static void
-clipboard_clear_cb (GtkClipboard *clipboard,
-                   gpointer data)
-{
-  dict_destroy (clip_dict);
-  clip_dict = NULL;
-
-  casereader_destroy (clip_datasheet);
-  clip_datasheet = NULL;
-}
-
-
-static const GtkTargetEntry targets[] = {
-  { "UTF8_STRING",   0, SELECT_FMT_TEXT },
-  { "STRING",        0, SELECT_FMT_TEXT },
-  { "TEXT",          0, SELECT_FMT_TEXT },
-  { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
-  { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
-  { "text/plain",    0, SELECT_FMT_TEXT },
-  { "text/html",     0, SELECT_FMT_HTML }
-};
-
-
-
-static void
-data_sheet_update_clipboard (PsppireSheet *sheet)
-{
-  GtkClipboard *clipboard =
-    gtk_widget_get_clipboard (GTK_WIDGET (sheet),
-                             GDK_SELECTION_CLIPBOARD);
-
-  if (!gtk_clipboard_set_with_owner (clipboard, targets,
-                                    G_N_ELEMENTS (targets),
-                                    clipboard_get_cb, clipboard_clear_cb,
-                                    G_OBJECT (sheet)))
-    clipboard_clear_cb (clipboard, sheet);
-}
-
-
-
-/* A callback for when the clipboard contents have been received */
-static void
-data_sheet_contents_received_callback (GtkClipboard *clipboard,
-                                     GtkSelectionData *sd,
-                                     gpointer data)
-{
-  gint count = 0;
-  gint row, column;
-  gint next_row, next_column;
-  gint first_column;
-  char *c;
-  PsppireDataEditor *data_editor = data;
-
-  if ( sd->length < 0 )
-    return;
-
-  if ( sd->type != gdk_atom_intern ("UTF8_STRING", FALSE))
-    return;
-
-  c = (char *) sd->data;
-
-  /* Paste text to selected position */
-  psppire_sheet_get_active_cell (PSPPIRE_SHEET (data_editor->data_sheet[0]),
-                            &row, &column);
-
-  g_return_if_fail (row >= 0);
-  g_return_if_fail (column >= 0);
-
-  first_column = column;
-  next_row = row;
-  next_column = column;
-  while (count < sd->length)
-    {
-      char *s = c;
-
-      row = next_row;
-      column = next_column;
-      while (*c != '\t' && *c != '\n' && count < sd->length)
-       {
-         c++;
-         count++;
-       }
-      if ( *c == '\t')
-       {
-         next_row = row ;
-         next_column = column + 1;
-       }
-      else if ( *c == '\n')
-       {
-         next_row = row + 1;
-         next_column = first_column;
-       }
-      *c++ = '\0';
-      count++;
-
-
-      /* Append some new cases if pasting beyond the last row */
-      if ( row >= psppire_data_store_get_case_count (data_editor->data_store))
-       psppire_data_store_insert_new_case (data_editor->data_store, row);
-
-      psppire_data_store_set_string (data_editor->data_store, s, row, column);
-    }
-}
-
-
-static void
-on_owner_change (GtkClipboard *clip, GdkEventOwnerChange *event, gpointer data)
-{
-  gint i;
-  gboolean compatible_target = FALSE;
-  PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
-
-  for (i = 0 ; i < sizeof (targets) / sizeof(targets[0]) ; ++i )
-    {
-      GdkAtom atom = gdk_atom_intern (targets[i].target, TRUE);
-      if ( gtk_clipboard_wait_is_target_available (clip, atom))
-       {
-         compatible_target = TRUE;
-         break;
-       }
-    }
-
-  g_signal_emit (de, data_editor_signals[DATA_AVAILABLE_CHANGED], 0,
-                compatible_target);
-}