Merge "master" into "psppsheet" to obtain bug fixes from "master". 20120709001830/pspp 20120710001843/pspp
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 9 Jul 2012 05:18:20 +0000 (22:18 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 9 Jul 2012 05:18:20 +0000 (22:18 -0700)
70 files changed:
lib/gtk-contrib/README
lib/gtk-contrib/automake.mk
lib/gtk-contrib/gtkextra-sheet.h [deleted file]
lib/gtk-contrib/gtkxpaned.c
lib/gtk-contrib/psppire-sheet.c [deleted file]
lib/gtk-contrib/psppire-sheet.h [deleted file]
src/libpspp/str.c
src/libpspp/str.h
src/ui/gui/aggregate-dialog.c
src/ui/gui/automake.mk
src/ui/gui/autorecode-dialog.c
src/ui/gui/binomial-dialog.c
src/ui/gui/chi-square-dialog.c
src/ui/gui/comments-dialog.c
src/ui/gui/compute-dialog.c
src/ui/gui/count-dialog.c
src/ui/gui/crosstabs-dialog.c
src/ui/gui/customentry.c [deleted file]
src/ui/gui/customentry.h [deleted file]
src/ui/gui/data-editor.ui
src/ui/gui/data-sheet.ui [new file with mode: 0644]
src/ui/gui/find-dialog.c
src/ui/gui/frequencies-dialog.c
src/ui/gui/goto-case-dialog.c
src/ui/gui/goto-case-dialog.h
src/ui/gui/k-related-dialog.c
src/ui/gui/ks-one-sample-dialog.c
src/ui/gui/marshaller-list
src/ui/gui/npar-two-sample-related.c
src/ui/gui/oneway-anova-dialog.c
src/ui/gui/paired-dialog.c
src/ui/gui/pspp-sheet-private.h
src/ui/gui/pspp-sheet-view.c
src/ui/gui/pspp-sheet-view.h
src/ui/gui/psppire-cell-renderer-button.c
src/ui/gui/psppire-cell-renderer-button.h
src/ui/gui/psppire-data-editor.c
src/ui/gui/psppire-data-editor.h
src/ui/gui/psppire-data-sheet.c [new file with mode: 0644]
src/ui/gui/psppire-data-sheet.h [new file with mode: 0644]
src/ui/gui/psppire-data-store.c
src/ui/gui/psppire-data-store.h
src/ui/gui/psppire-data-window.c
src/ui/gui/psppire-data-window.h
src/ui/gui/psppire-dialog-action-var-info.c
src/ui/gui/psppire-dialog-action.c
src/ui/gui/psppire-var-sheet.c
src/ui/gui/psppire-var-sheet.h
src/ui/gui/psppire-var-store.c [deleted file]
src/ui/gui/psppire-var-store.h [deleted file]
src/ui/gui/psppire.c
src/ui/gui/recode-dialog.c
src/ui/gui/runs-dialog.c
src/ui/gui/sheet/automake.mk [deleted file]
src/ui/gui/sheet/psppire-axis.c [deleted file]
src/ui/gui/sheet/psppire-axis.h [deleted file]
src/ui/gui/sheet/psppire-sheetmodel.c [deleted file]
src/ui/gui/sheet/psppire-sheetmodel.h [deleted file]
src/ui/gui/split-file-dialog.c
src/ui/gui/t-test-one-sample.c
src/ui/gui/t-test-paired-samples.c
src/ui/gui/text-data-import-dialog.c
src/ui/gui/text-data-import.ui
src/ui/gui/transpose-dialog.c
src/ui/gui/univariate-dialog.c
src/ui/gui/val-labs-dialog.c
src/ui/gui/val-labs-dialog.h
src/ui/gui/var-sheet.ui [new file with mode: 0644]
src/ui/gui/var-type-dialog.h
src/ui/gui/weight-cases-dialog.c

index e6e23d944a600d73c7fbda2faadb12539d70e195..c3ffaf2c66e63526d38c76d278fefed107b64f35 100644 (file)
@@ -3,8 +3,3 @@ This is not part of the GNU PSPP program, but is used with GNU PSPP.
 This directory contains a version of the GtkXPaned widget.  It includes
 minor modifications. GtkXPaned is licensed under the GNU Lesser
 General Public License.  See COPYING.LESSER. 
-
-
-This directory also contains the PsppireSheet widget which is a very
-heavily modified version of GtkSheet widget.  This modified version if
-licensed under the GNU General Public License version 3 or later.
index e694d714cdb345b445dfb49978e26b1f4bccdf93..e28c4933cd83cdf2c5f7581911a14e2bc6a1a857 100644 (file)
@@ -1,14 +1,10 @@
 ## Process this file with automake to produce Makefile.in  -*- makefile -*-
 
-noinst_LIBRARIES += lib/gtk-contrib/libgtksheet.a
+noinst_LIBRARIES += lib/gtk-contrib/libxpaned.a
 
-lib_gtk_contrib_libgtksheet_a_CPPFLAGS = $(AM_CPPFLAGS) -Isrc/ui/gui/include
-lib_gtk_contrib_libgtksheet_a_CFLAGS = $(GTK_CFLAGS) -Wall -DGDK_MULTIHEAD_SAFE=1
+lib_gtk_contrib_libxpaned_a_CFLAGS = $(GTK_CFLAGS) -Wall -DGDK_MULTIHEAD_SAFE=1
 
-lib_gtk_contrib_libgtksheet_a_SOURCES = \
-       lib/gtk-contrib/gtkextra-sheet.h \
-       lib/gtk-contrib/psppire-sheet.c \
-       lib/gtk-contrib/psppire-sheet.h \
+lib_gtk_contrib_libxpaned_a_SOURCES = \
        lib/gtk-contrib/gtkxpaned.c \
        lib/gtk-contrib/gtkxpaned.h
 
diff --git a/lib/gtk-contrib/gtkextra-sheet.h b/lib/gtk-contrib/gtkextra-sheet.h
deleted file mode 100644 (file)
index 6cad27f..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This version of GtkSheet has been heavily modified, for the specific
- *  requirements of PSPPIRE.
- *
- * GtkSheet widget for Gtk+.
- * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
- *
- * Based on GtkClist widget by Jay Painter, but major changes.
- * Memory allocation routines inspired on SC (Spreadsheet Calculator)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-
-#ifndef PSPPIRE_EXTRA_SHEET_H__
-#define PSPPIRE_EXTRA_SHEET_H__
-
-
-struct _PsppireSheet ;
-
-typedef struct _PsppireSheet PsppireSheet;
-
-
-struct _PsppireSheetButton
-{
-  GtkStateType state;
-  gchar *label;
-
-  gboolean label_visible;
-
-  GtkJustification justification;
-  gboolean overstruck;
-};
-
-struct _PsppireSheetCell
-{
-  gint row;
-  gint col;
-};
-
-typedef struct _PsppireSheetButton PsppireSheetButton;
-typedef struct _PsppireSheetCell PsppireSheetCell;
-
-PsppireSheetButton * psppire_sheet_button_new (void);
-
-void psppire_sheet_button_free (PsppireSheetButton *button);
-
-
-#endif /* PSPPIRE_EXTRA_SHEET_H__ */
-
-
index 96f89ada7df785b0f3416daeb83d894820a3e8a2..7b30bfa1f58b3ab26486dd2dc8d08546ac2a7d9b 100644 (file)
@@ -3,6 +3,7 @@
 **      10        20        30        40        50        60        70        80
 **
 **  library for GtkXPaned-widget, a 2x2 grid-like variation of GtkPaned of gtk+
+**  Copyright (C) 2012 Free Software Foundation, Inc.
 **  Copyright (C) 2005-2006 Mirco "MacSlow" Müller <macslow@bangang.de>
 **
 **  This library is free software; you can redistribute it and/or
@@ -687,8 +688,8 @@ static void gtk_xpaned_size_request (GtkWidget* widget,
        {
                gtk_widget_size_request (xpaned->bottom_right_child, &child_requisition);
 
-               requisition->width = MAX (requisition->width, child_requisition.width);
-               requisition->height = MAX (requisition->height, child_requisition.height);
+               requisition->width = child_requisition.width;
+               requisition->height = child_requisition.height;
        }
 
        /* add 2 times the set border-width to the GtkXPaneds requisition */
@@ -2445,14 +2446,6 @@ gtk_xpaned_compute_position (GtkXPaned* xpaned,
                        xpaned->top_left_child_size.width = top_left_child_req->width;
                        xpaned->top_left_child_size.height = top_left_child_req->height;
                }
-               else if (top_left_child_req->width + top_right_child_req->width != 0)
-               {
-                       xpaned->top_left_child_size.width = allocation->width * ((gdouble)top_left_child_req->width / (top_left_child_req->width + top_right_child_req->width)) + 0.5;
-               }
-               else if (top_left_child_req->height + top_right_child_req->height != 0)
-               {
-                       xpaned->top_left_child_size.height = allocation->height * ((gdouble)top_left_child_req->height / (top_left_child_req->height + top_right_child_req->height)) + 0.5;
-               }
                else
                {
                        xpaned->top_left_child_size.width = allocation->width * 0.5 + 0.5;
diff --git a/lib/gtk-contrib/psppire-sheet.c b/lib/gtk-contrib/psppire-sheet.c
deleted file mode 100644 (file)
index ecadf74..0000000
+++ /dev/null
@@ -1,4882 +0,0 @@
-/*
-  Copyright (C) 2006, 2008, 2009, 2011 Free Software Foundation
-
-  This program is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation, either version 3 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-  This file is derived from the gtksheet.c and extensively modified for the
-  requirements of PSPPIRE.  The changes are copyright by the
-  Free Software Foundation.  The copyright notice for the original work is
-  below.
-*/
-
-/* GtkSheet widget for Gtk+.
- * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
- *
- * Based on GtkClist widget by Jay Painter, but major changes.
- * Memory allocation routines inspired on SC (Spreadsheet Calculator)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * SECTION:psppiresheet
- * @short_description: spreadsheet widget for gtk2
- *
- * PsppireSheet is a matrix widget for GTK+. It consists of an scrollable grid of
- * cells where you can allocate text. Cell contents can be edited interactively
- * through a specially designed entry, GtkItemEntry.
- *
- */
-#include <config.h>
-
-#include <string.h>
-#include <glib.h>
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkbutton.h>
-#include <gtk/gtkadjustment.h>
-#include <gtk/gtktypeutils.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkcontainer.h>
-#include <pango/pango.h>
-#include "psppire-sheet.h"
-#include <ui/gui/psppire-marshal.h>
-#include <ui/gui/sheet/psppire-sheetmodel.h>
-#include <ui/gui/sheet/psppire-axis.h>
-#include <libpspp/misc.h>
-
-/* sheet flags */
-enum
-  {
-    PSPPIRE_SHEET_IN_XDRAG = 1 << 1,
-    PSPPIRE_SHEET_IN_YDRAG = 1 << 2,
-    PSPPIRE_SHEET_IN_DRAG = 1 << 3,
-
-    /* This flag is set when the user is actually in the process
-       of making a selection - ie while the mouse button is
-       depressed.
-    */
-    PSPPIRE_SHEET_IN_SELECTION = 1 << 4
-  };
-
-#define PSPPIRE_SHEET_FLAGS(sheet) (PSPPIRE_SHEET (sheet)->flags)
-#define PSPPIRE_SHEET_SET_FLAGS(sheet,flag) (PSPPIRE_SHEET_FLAGS (sheet) |= (flag))
-#define PSPPIRE_SHEET_UNSET_FLAGS(sheet,flag) (PSPPIRE_SHEET_FLAGS (sheet) &= ~ (flag))
-
-#define PSPPIRE_SHEET_IN_XDRAG(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_XDRAG)
-#define PSPPIRE_SHEET_IN_YDRAG(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_YDRAG)
-#define PSPPIRE_SHEET_IN_DRAG(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_DRAG)
-#define PSPPIRE_SHEET_IN_SELECTION(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_SELECTION)
-
-#define CELL_SPACING 1
-
-#define TIMEOUT_HOVER 300
-#define COLUMN_MIN_WIDTH 10
-#define COLUMN_TITLES_HEIGHT 4
-#define DEFAULT_COLUMN_WIDTH 80
-#define DEFAULT_ROW_HEIGHT 25
-
-static void set_entry_widget_font (PsppireSheet *sheet);
-
-static void psppire_sheet_update_primary_selection (PsppireSheet *sheet);
-static void draw_column_title_buttons_range (PsppireSheet *sheet, gint first, gint n);
-static void draw_row_title_buttons_range (PsppireSheet *sheet, gint first, gint n);
-static void redraw_range (PsppireSheet *sheet, PsppireSheetRange *range);
-
-
-static void set_row_height (PsppireSheet *sheet,
-                           gint row,
-                           gint height);
-
-static void destroy_hover_window (PsppireSheetHoverTitle *);
-static PsppireSheetHoverTitle *create_hover_window (void);
-
-static inline  void
-dispose_string (const PsppireSheet *sheet, gchar *text)
-{
-  PsppireSheetModel *model = psppire_sheet_get_model (sheet);
-
-  if ( ! model )
-    return;
-
-  if (psppire_sheet_model_free_strings (model))
-    g_free (text);
-}
-
-
-/* FIXME: Why bother with these two ? */
-
-/* returns the column index from a pixel location */
-static inline gint
-column_from_xpixel (const PsppireSheet *sheet, gint pixel)
-{
-  return psppire_axis_unit_at_pixel (sheet->haxis, pixel);
-}
-
-static inline gint
-row_from_ypixel (const PsppireSheet *sheet, gint pixel)
-{
-  return psppire_axis_unit_at_pixel (sheet->vaxis, pixel);
-}
-
-
-/* Return the lowest row number which is wholly or partially on
-   the visible range of the sheet */
-static inline glong
-min_visible_row (const PsppireSheet *sheet)
-{
-  return row_from_ypixel (sheet, sheet->vadjustment->value);
-}
-
-static inline glong
-min_fully_visible_row (const PsppireSheet *sheet)
-{
-  glong row = min_visible_row (sheet);
-
-  if ( psppire_axis_start_pixel (sheet->vaxis, row) < sheet->vadjustment->value)
-    row++;
-
-  return row;
-}
-
-static inline glong
-max_visible_row (const PsppireSheet *sheet)
-{
-  return row_from_ypixel (sheet, sheet->vadjustment->value + sheet->vadjustment->page_size);
-}
-
-
-static inline glong
-max_fully_visible_row (const PsppireSheet *sheet)
-{
-  glong row = max_visible_row (sheet);
-
-  if ( psppire_axis_start_pixel (sheet->vaxis, row)
-       +
-       psppire_axis_unit_size (sheet->vaxis, row)
-       > sheet->vadjustment->value)
-    row--;
-
-  return row;
-}
-
-
-/* Returns the lowest column number which is wholly or partially
-   on the sheet */
-static inline glong
-min_visible_column (const PsppireSheet *sheet)
-{
-  return column_from_xpixel (sheet, sheet->hadjustment->value);
-}
-
-static inline glong
-min_fully_visible_column (const PsppireSheet *sheet)
-{
-  glong col = min_visible_column (sheet);
-
-  if ( psppire_axis_start_pixel (sheet->haxis, col) < sheet->hadjustment->value)
-    col++;
-
-  return col;
-}
-
-
-/* Returns the highest column number which is wholly or partially
-   on the sheet */
-static inline glong
-max_visible_column (const PsppireSheet *sheet)
-{
-  return column_from_xpixel (sheet, sheet->hadjustment->value + sheet->hadjustment->page_size);
-}
-
-static inline glong
-max_fully_visible_column (const PsppireSheet *sheet)
-{
-  glong col = max_visible_column (sheet);
-
-  if ( psppire_axis_start_pixel (sheet->haxis, col)
-       +
-       psppire_axis_unit_size (sheet->haxis, col)
-       > sheet->hadjustment->value)
-    col--;
-
-  return col;
-}
-
-
-
-/* The size of the region (in pixels) around the row/column boundaries
-   where the height/width may be grabbed to change size */
-#define DRAG_WIDTH 6
-
-static gboolean
-on_column_boundary (const PsppireSheet *sheet, gint x, gint *column)
-{
-  gint col;
-  gint pixel;
-
-  x += sheet->hadjustment->value;
-
-  if ( x < 0)
-    return FALSE;
-
-  col = column_from_xpixel (sheet, x);
-
-  pixel = x - DRAG_WIDTH / 2;
-  if (pixel < 0)
-    pixel = 0;
-
-  if ( column_from_xpixel (sheet, pixel) < col )
-    {
-      *column = col - 1;
-      return TRUE;
-    }
-
-  if  ( column_from_xpixel (sheet, x + DRAG_WIDTH / 2) > col )
-    {
-      *column = col;
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-on_row_boundary (const PsppireSheet *sheet, gint y, gint *row)
-{
-  gint r;
-  gint pixel;
-
-  y += sheet->vadjustment->value;
-
-  if ( y < 0)
-    return FALSE;
-
-  r = row_from_ypixel (sheet, y);
-
-  pixel = y - DRAG_WIDTH / 2;
-  if (pixel < 0)
-    pixel = 0;
-
-  if ( row_from_ypixel (sheet, pixel) < r )
-    {
-      *row = r - 1;
-      return TRUE;
-    }
-
-  if  ( row_from_ypixel (sheet, y + DRAG_WIDTH / 2) > r )
-    {
-      *row = r;
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-
-static inline gboolean
-POSSIBLE_DRAG (const PsppireSheet *sheet, gint x, gint y,
-              gint *drag_row, gint *drag_column)
-{
-  gint ydrag, xdrag;
-
-  /* Can't drag if nothing is selected */
-  if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
-       sheet->range.col0 < 0 || sheet->range.coli < 0 )
-    return FALSE;
-
-  *drag_column = column_from_xpixel (sheet, x);
-  *drag_row = row_from_ypixel (sheet, y);
-
-  if (x >= psppire_axis_start_pixel (sheet->haxis, sheet->range.col0) - DRAG_WIDTH / 2 &&
-      x <= psppire_axis_start_pixel (sheet->haxis, sheet->range.coli) +
-      psppire_axis_unit_size (sheet->haxis, sheet->range.coli) + DRAG_WIDTH / 2)
-    {
-      ydrag = psppire_axis_start_pixel (sheet->vaxis, sheet->range.row0);
-      if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
-       {
-         *drag_row = sheet->range.row0;
-         return TRUE;
-       }
-      ydrag = psppire_axis_start_pixel (sheet->vaxis, sheet->range.rowi) +
-       psppire_axis_unit_size (sheet->vaxis, sheet->range.rowi);
-      if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
-       {
-         *drag_row = sheet->range.rowi;
-         return TRUE;
-       }
-    }
-
-  if (y >= psppire_axis_start_pixel (sheet->vaxis, sheet->range.row0) - DRAG_WIDTH / 2 &&
-      y <= psppire_axis_start_pixel (sheet->vaxis, sheet->range.rowi) +
-      psppire_axis_unit_size (sheet->vaxis, sheet->range.rowi) + DRAG_WIDTH / 2)
-    {
-      xdrag = psppire_axis_start_pixel (sheet->haxis, sheet->range.col0);
-      if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
-       {
-         *drag_column = sheet->range.col0;
-         return TRUE;
-       }
-      xdrag = psppire_axis_start_pixel (sheet->haxis, sheet->range.coli) +
-       psppire_axis_unit_size (sheet->haxis, sheet->range.coli);
-      if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
-       {
-         *drag_column = sheet->range.coli;
-         return TRUE;
-       }
-    }
-
-  return FALSE;
-}
-
-static inline gboolean
-POSSIBLE_RESIZE (const PsppireSheet *sheet, gint x, gint y,
-                gint *drag_row, gint *drag_column)
-{
-  gint xdrag, ydrag;
-
-  /* Can't drag if nothing is selected */
-  if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
-       sheet->range.col0 < 0 || sheet->range.coli < 0 )
-    return FALSE;
-
-  xdrag = psppire_axis_start_pixel (sheet->haxis, sheet->range.coli)+
-    psppire_axis_unit_size (sheet->haxis, sheet->range.coli);
-
-  ydrag = psppire_axis_start_pixel (sheet->vaxis, sheet->range.rowi) +
-    psppire_axis_unit_size (sheet->vaxis, sheet->range.rowi);
-
-  if (sheet->select_status == PSPPIRE_SHEET_COLUMN_SELECTED)
-    ydrag = psppire_axis_start_pixel (sheet->vaxis, min_visible_row (sheet));
-
-  if (sheet->select_status == PSPPIRE_SHEET_ROW_SELECTED)
-    xdrag = psppire_axis_start_pixel (sheet->haxis, min_visible_column (sheet));
-
-  *drag_column = column_from_xpixel (sheet, x);
-  *drag_row = row_from_ypixel (sheet, y);
-
-  if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2 &&
-      y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2) return TRUE;
-
-  return FALSE;
-}
-
-
-static void
-rectangle_from_range (PsppireSheet *sheet, const PsppireSheetRange *range,
-                     GdkRectangle *r)
-{
-  gint col0 = MIN (range->col0, range->coli);
-  gint coli = MAX (range->col0, range->coli);
-  gint row0 = MIN (range->row0, range->rowi);
-  gint rowi = MAX (range->row0, range->rowi);
-
-  if ( row0 == -1 ) row0 = min_visible_row (sheet);
-  if ( rowi == -1 ) rowi = max_visible_row (sheet);
-  if ( col0 == -1 ) col0 = min_visible_column (sheet);
-  if ( coli == -1 ) coli = max_visible_column (sheet);
-
-  r->x = psppire_axis_start_pixel (sheet->haxis, col0);
-  r->x -= round (sheet->hadjustment->value);
-
-  r->y = psppire_axis_start_pixel (sheet->vaxis, row0);
-  r->y -= round (sheet->vadjustment->value);
-
-  r->width = psppire_axis_start_pixel (sheet->haxis, coli) -
-    psppire_axis_start_pixel (sheet->haxis, col0) +
-    psppire_axis_unit_size (sheet->haxis, coli);
-
-  r->height = psppire_axis_start_pixel (sheet->vaxis, rowi) -
-    psppire_axis_start_pixel (sheet->vaxis, row0) +
-    psppire_axis_unit_size (sheet->vaxis, rowi);
-
-  if ( sheet->column_titles_visible)
-    {
-      r->y += sheet->column_title_area.height;
-    }
-
-  if ( sheet->row_titles_visible)
-    {
-      r->x += sheet->row_title_area.width;
-    }
-}
-
-static void
-rectangle_from_cell (PsppireSheet *sheet, gint row, gint col,
-                    GdkRectangle *r)
-{
-  PsppireSheetRange range;
-  g_return_if_fail (row >= 0);
-  g_return_if_fail (col >= 0);
-
-  range.row0 = range.rowi = row;
-  range.col0 = range.coli = col;
-
-  rectangle_from_range (sheet, &range, r);
-}
-
-
-static void psppire_sheet_class_init            (PsppireSheetClass *klass);
-static void psppire_sheet_init                          (PsppireSheet *sheet);
-static void psppire_sheet_dispose                       (GObject *object);
-static void psppire_sheet_finalize                      (GObject *object);
-static void psppire_sheet_style_set             (GtkWidget *widget,
-                                                 GtkStyle *previous_style);
-static void psppire_sheet_realize                       (GtkWidget *widget);
-static void psppire_sheet_unrealize             (GtkWidget *widget);
-static void psppire_sheet_map                   (GtkWidget *widget);
-static void psppire_sheet_unmap                         (GtkWidget *widget);
-static gint psppire_sheet_expose                        (GtkWidget *widget,
-                                                         GdkEventExpose *event);
-
-static void psppire_sheet_forall                        (GtkContainer *container,
-                                                         gboolean include_internals,
-                                                         GtkCallback callback,
-                                                         gpointer callback_data);
-
-static gboolean psppire_sheet_set_scroll_adjustments  (PsppireSheet *sheet,
-                                                      GtkAdjustment *hadjustment,
-                                                      GtkAdjustment *vadjustment);
-
-static gint psppire_sheet_button_press                  (GtkWidget *widget,
-                                                 GdkEventButton *event);
-static gint psppire_sheet_button_release                (GtkWidget *widget,
-                                                         GdkEventButton *event);
-static gint psppire_sheet_motion                        (GtkWidget *widget,
-                                                         GdkEventMotion *event);
-static gboolean psppire_sheet_crossing_notify           (GtkWidget *widget,
-                                                        GdkEventCrossing *event);
-static gint psppire_sheet_entry_key_press               (GtkWidget *widget,
-                                                         GdkEventKey *key);
-static gboolean psppire_sheet_key_press                 (GtkWidget *widget,
-                                                 GdkEventKey *key);
-static void psppire_sheet_size_request                  (GtkWidget *widget,
-                                                 GtkRequisition *requisition);
-static void psppire_sheet_size_allocate                 (GtkWidget *widget,
-                                                         GtkAllocation *allocation);
-
-static gboolean psppire_sheet_focus_in               (GtkWidget     *widget,
-                                                     GdkEventFocus *event);
-
-/* Sheet queries */
-
-static gboolean psppire_sheet_range_isvisible (const PsppireSheet *sheet,
-                                              const PsppireSheetRange *range);
-static gboolean psppire_sheet_cell_isvisible  (PsppireSheet *sheet,
-                                              gint row, gint column);
-/* Drawing Routines */
-
-/* draw cell */
-static void psppire_sheet_cell_draw (PsppireSheet *sheet, gint row, gint column);
-
-
-/* draw visible part of range. */
-static void draw_sheet_region (PsppireSheet *sheet, GdkRegion *region);
-
-
-/* Selection */
-static void psppire_sheet_draw_border           (PsppireSheet *sheet,
-                                                 PsppireSheetRange range);
-
-/* Active Cell handling */
-
-static void psppire_sheet_hide_entry_widget             (PsppireSheet *sheet);
-static void change_active_cell  (PsppireSheet *sheet, gint row, gint col);
-static gboolean psppire_sheet_draw_active_cell  (PsppireSheet *sheet);
-static void psppire_sheet_show_entry_widget             (PsppireSheet *sheet);
-static gboolean psppire_sheet_click_cell                (PsppireSheet *sheet,
-                                                         gint row,
-                                                         gint column);
-
-
-/* Scrollbars */
-
-static void adjust_scrollbars                   (PsppireSheet *sheet);
-static void vadjustment_value_changed           (GtkAdjustment *adjustment,
-                                                 gpointer data);
-static void hadjustment_value_changed           (GtkAdjustment *adjustment,
-                                                 gpointer data);
-
-
-static void draw_xor_vline                      (PsppireSheet *sheet);
-static void draw_xor_hline                      (PsppireSheet *sheet);
-static void draw_xor_rectangle                  (PsppireSheet *sheet,
-                                                 PsppireSheetRange range);
-
-/* Sheet Button */
-
-static void create_global_button                (PsppireSheet *sheet);
-static void global_button_clicked               (GtkWidget *widget,
-                                                 gpointer data);
-/* Sheet Entry */
-
-static void create_sheet_entry                  (PsppireSheet *sheet);
-static void psppire_sheet_size_allocate_entry   (PsppireSheet *sheet);
-
-/* Sheet button gadgets */
-
-static void draw_column_title_buttons   (PsppireSheet *sheet);
-static void draw_row_title_buttons      (PsppireSheet *sheet);
-
-
-static void size_allocate_global_button         (PsppireSheet *sheet);
-
-static void psppire_sheet_real_cell_clear               (PsppireSheet *sheet,
-                                                         gint row,
-                                                         gint column);
-
-
-/* Signals */
-enum
-  {
-    SELECT_ROW,
-    SELECT_COLUMN,
-    DOUBLE_CLICK_ROW,
-    DOUBLE_CLICK_COLUMN,
-    BUTTON_EVENT_ROW,
-    BUTTON_EVENT_COLUMN,
-    SELECT_RANGE,
-    RESIZE_RANGE,
-    MOVE_RANGE,
-    TRAVERSE,
-    ACTIVATE,
-    LAST_SIGNAL
-  };
-
-static GtkContainerClass *parent_class = NULL;
-static guint sheet_signals[LAST_SIGNAL] = { 0 };
-
-
-GType
-psppire_sheet_get_type ()
-{
-  static GType sheet_type = 0;
-
-  if (!sheet_type)
-    {
-      static const GTypeInfo sheet_info =
-       {
-         sizeof (PsppireSheetClass),
-         NULL,
-         NULL,
-         (GClassInitFunc) psppire_sheet_class_init,
-         NULL,
-         NULL,
-         sizeof (PsppireSheet),
-         0,
-         (GInstanceInitFunc) psppire_sheet_init,
-         NULL,
-       };
-
-      sheet_type =
-       g_type_register_static (GTK_TYPE_BIN, "PsppireSheet",
-                               &sheet_info, 0);
-    }
-  return sheet_type;
-}
-
-\f
-
-static PsppireSheetRange*
-psppire_sheet_range_copy (const PsppireSheetRange *range)
-{
-  PsppireSheetRange *new_range;
-
-  g_return_val_if_fail (range != NULL, NULL);
-
-  new_range = g_new (PsppireSheetRange, 1);
-
-  *new_range = *range;
-
-  return new_range;
-}
-
-static void
-psppire_sheet_range_free (PsppireSheetRange *range)
-{
-  g_return_if_fail (range != NULL);
-
-  g_free (range);
-}
-
-GType
-psppire_sheet_range_get_type (void)
-{
-  static GType sheet_range_type = 0;
-
-  if (!sheet_range_type)
-    {
-      sheet_range_type =
-       g_boxed_type_register_static ("PsppireSheetRange",
-                                     (GBoxedCopyFunc) psppire_sheet_range_copy,
-                                     (GBoxedFreeFunc) psppire_sheet_range_free);
-    }
-
-  return sheet_range_type;
-}
-
-static PsppireSheetCell*
-psppire_sheet_cell_copy (const PsppireSheetCell *cell)
-{
-  PsppireSheetCell *new_cell;
-
-  g_return_val_if_fail (cell != NULL, NULL);
-
-  new_cell = g_new (PsppireSheetCell, 1);
-
-  *new_cell = *cell;
-
-  return new_cell;
-}
-
-static void
-psppire_sheet_cell_free (PsppireSheetCell *cell)
-{
-  g_return_if_fail (cell != NULL);
-
-  g_free (cell);
-}
-
-GType
-psppire_sheet_cell_get_type (void)
-{
-  static GType sheet_cell_type = 0;
-
-  if (!sheet_cell_type)
-    {
-      sheet_cell_type =
-       g_boxed_type_register_static ("PsppireSheetCell",
-                                     (GBoxedCopyFunc) psppire_sheet_cell_copy,
-                                     (GBoxedFreeFunc) psppire_sheet_cell_free);
-    }
-
-  return sheet_cell_type;
-}
-\f
-
-/* Properties */
-enum
-  {
-    PROP_0,
-    PROP_VAXIS,
-    PROP_HAXIS,
-    PROP_CELL_PADDING,
-    PROP_MODEL
-  };
-
-static void
-resize_column (PsppireSheet *sheet, gint unit, glong size)
-{
-  PsppireSheetRange range;
-  range.col0 = unit;
-  range.coli = max_visible_column (sheet);
-  range.row0 = min_visible_row (sheet);
-  range.rowi = max_visible_row (sheet);
-
-  redraw_range (sheet, &range);
-
-  draw_column_title_buttons_range (sheet, range.col0, range.coli);
-}
-
-
-static void
-psppire_sheet_set_horizontal_axis (PsppireSheet *sheet, PsppireAxis *a)
-{
-  if ( sheet->haxis )
-    g_object_unref (sheet->haxis);
-
-  sheet->haxis = a;
-  g_signal_connect_swapped (a, "resize-unit", G_CALLBACK (resize_column), sheet);
-
-  if ( sheet->haxis )
-    g_object_ref (sheet->haxis);
-}
-
-static void
-resize_row (PsppireSheet *sheet, gint unit, glong size)
-{
-  PsppireSheetRange range;
-  range.col0 = min_visible_column (sheet);
-  range.coli = max_visible_column (sheet);
-  range.row0 = unit;
-  range.rowi = max_visible_row (sheet);
-
-  redraw_range (sheet, &range);
-
-  draw_row_title_buttons_range (sheet, range.row0, range.rowi);
-}
-
-static void
-psppire_sheet_set_vertical_axis (PsppireSheet *sheet, PsppireAxis *a)
-{
-  if ( sheet->vaxis )
-    g_object_unref (sheet->vaxis);
-
-  sheet->vaxis = a;
-
-  g_signal_connect_swapped (a, "resize-unit", G_CALLBACK (resize_row), sheet);
-
-  if ( sheet->vaxis )
-    g_object_ref (sheet->vaxis);
-}
-
-static const GtkBorder default_cell_padding = {3, 3, 3, 3};
-
-static void
-psppire_sheet_set_property (GObject         *object,
-                           guint            prop_id,
-                           const GValue    *value,
-                           GParamSpec      *pspec)
-
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (object);
-
-  switch (prop_id)
-    {
-    case PROP_CELL_PADDING:
-      if ( sheet->cell_padding)
-       g_boxed_free (GTK_TYPE_BORDER, sheet->cell_padding);
-
-      sheet->cell_padding = g_value_dup_boxed (value);
-
-      if (NULL == sheet->cell_padding)
-       sheet->cell_padding = g_boxed_copy (GTK_TYPE_BORDER,
-                                           &default_cell_padding);
-
-      if (sheet->vaxis)
-       g_object_set (sheet->vaxis, "padding",
-                     sheet->cell_padding->top + sheet->cell_padding->bottom,
-                     NULL);
-
-      if (sheet->haxis)
-       g_object_set (sheet->haxis, "padding",
-                     sheet->cell_padding->left + sheet->cell_padding->right,
-                     NULL);
-      break;
-    case PROP_VAXIS:
-      psppire_sheet_set_vertical_axis (sheet, g_value_get_pointer (value));
-      g_object_set (sheet->vaxis, "padding",
-                   sheet->cell_padding->top + sheet->cell_padding->bottom,
-                   NULL);
-      break;
-    case PROP_HAXIS:
-      psppire_sheet_set_horizontal_axis (sheet, g_value_get_pointer (value));
-      g_object_set (sheet->haxis, "padding",
-                   sheet->cell_padding->left + sheet->cell_padding->right,
-                   NULL);
-      break;
-    case PROP_MODEL:
-      psppire_sheet_set_model (sheet, g_value_get_pointer (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    };
-}
-
-static void
-psppire_sheet_get_property (GObject         *object,
-                           guint            prop_id,
-                           GValue          *value,
-                           GParamSpec      *pspec)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (object);
-
-  switch (prop_id)
-    {
-    case PROP_CELL_PADDING:
-      g_value_set_boxed (value, sheet->cell_padding);
-      break;
-    case PROP_VAXIS:
-      g_value_set_pointer (value, sheet->vaxis);
-      break;
-    case PROP_HAXIS:
-      g_value_set_pointer (value, sheet->haxis);
-      break;
-    case PROP_MODEL:
-      g_value_set_pointer (value, sheet->model);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    };
-}
-
-
-static void
-psppire_sheet_class_init (PsppireSheetClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  GParamSpec *haxis_spec ;
-  GParamSpec *vaxis_spec ;
-  GParamSpec *model_spec ;
-  GParamSpec *cell_padding_spec ;
-
-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  /**
-   * PsppireSheet::select-row
-   * @sheet: the sheet widget that emitted the signal
-   * @row: the newly selected row index, or -1 if no row is selected.
-   *
-   * A row has been selected.
-   */
-  sheet_signals[SELECT_ROW] =
-    g_signal_new ("select-row",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 offsetof (PsppireSheetClass, select_row),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__INT,
-                 G_TYPE_NONE,
-                 1,
-                 G_TYPE_INT);
-
-
-  /**
-   * PsppireSheet::select - column
-   * @sheet: the sheet widget that emitted the signal
-   * @column: the newly selected column index, or -1 if no column is selected.
-   *
-   * A column has been selected.
-   */
-  sheet_signals[SELECT_COLUMN] =
-    g_signal_new ("select-column",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 offsetof (PsppireSheetClass, select_column),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__INT,
-                 G_TYPE_NONE,
-                 1,
-                 G_TYPE_INT);
-
-
-  /**
-   * PsppireSheet::double-click-row
-   * @sheet: the sheet widget that emitted the signal
-   * @row: the row that was double clicked.
-   *
-   * A row's title button has been double clicked
-   */
-  sheet_signals[DOUBLE_CLICK_ROW] =
-    g_signal_new ("double-click-row",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__INT,
-                 G_TYPE_NONE,
-                 1,
-                 G_TYPE_INT);
-
-
-  /**
-   * PsppireSheet::double-click-column
-   * @sheet: the sheet widget that emitted the signal
-   * @column: the column that was double clicked.
-   *
-   * A column's title button has been double clicked
-   */
-  sheet_signals[DOUBLE_CLICK_COLUMN] =
-    g_signal_new ("double-click-column",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__INT,
-                 G_TYPE_NONE,
-                 1,
-                 G_TYPE_INT);
-
-
-  /**
-   * PsppireSheet::button-event-column
-   * @sheet: the sheet widget that emitted the signal
-   * @column: the column on which the event occured.
-   *
-   * A button event occured on a column title button
-   */
-  sheet_signals[BUTTON_EVENT_COLUMN] =
-    g_signal_new ("button-event-column",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 0,
-                 NULL, NULL,
-                 psppire_marshal_VOID__INT_POINTER,
-                 G_TYPE_NONE,
-                 2,
-                 G_TYPE_INT,
-                 G_TYPE_POINTER
-                 );
-
-
-  /**
-   * PsppireSheet::button-event-row
-   * @sheet: the sheet widget that emitted the signal
-   * @column: the column on which the event occured.
-   *
-   * A button event occured on a row title button
-   */
-  sheet_signals[BUTTON_EVENT_ROW] =
-    g_signal_new ("button-event-row",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 0,
-                 NULL, NULL,
-                 psppire_marshal_VOID__INT_POINTER,
-                 G_TYPE_NONE,
-                 2,
-                 G_TYPE_INT,
-                 G_TYPE_POINTER
-                 );
-
-
-  sheet_signals[SELECT_RANGE] =
-    g_signal_new ("select-range",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 offsetof (PsppireSheetClass, select_range),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__BOXED,
-                 G_TYPE_NONE,
-                 1,
-                 PSPPIRE_TYPE_SHEET_RANGE);
-
-
-  sheet_signals[RESIZE_RANGE] =
-    g_signal_new ("resize-range",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 offsetof (PsppireSheetClass, resize_range),
-                 NULL, NULL,
-                 psppire_marshal_VOID__BOXED_BOXED,
-                 G_TYPE_NONE,
-                 2,
-                 PSPPIRE_TYPE_SHEET_RANGE, PSPPIRE_TYPE_SHEET_RANGE
-                 );
-
-  sheet_signals[MOVE_RANGE] =
-    g_signal_new ("move-range",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 offsetof (PsppireSheetClass, move_range),
-                 NULL, NULL,
-                 psppire_marshal_VOID__BOXED_BOXED,
-                 G_TYPE_NONE,
-                 2,
-                 PSPPIRE_TYPE_SHEET_RANGE, PSPPIRE_TYPE_SHEET_RANGE
-                 );
-
-  sheet_signals[TRAVERSE] =
-    g_signal_new ("traverse",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 offsetof (PsppireSheetClass, traverse),
-                 NULL, NULL,
-                 psppire_marshal_BOOLEAN__BOXED_POINTER,
-                 G_TYPE_BOOLEAN, 2,
-                 PSPPIRE_TYPE_SHEET_CELL,
-                 G_TYPE_POINTER);
-
-
-  sheet_signals[ACTIVATE] =
-    g_signal_new ("activate",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 offsetof (PsppireSheetClass, activate),
-                 NULL, NULL,
-                 psppire_marshal_VOID__INT_INT_INT_INT,
-                 G_TYPE_NONE, 4,
-                 G_TYPE_INT, G_TYPE_INT,
-                 G_TYPE_INT, G_TYPE_INT);
-
-  widget_class->set_scroll_adjustments_signal =
-    g_signal_new ("set-scroll-adjustments",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 offsetof (PsppireSheetClass, set_scroll_adjustments),
-                 NULL, NULL,
-                 psppire_marshal_VOID__OBJECT_OBJECT,
-                 G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
-
-
-  container_class->add = NULL;
-  container_class->remove = NULL;
-  container_class->forall = psppire_sheet_forall;
-  container_class->set_focus_child = NULL;
-
-  object_class->dispose = psppire_sheet_dispose;
-  object_class->finalize = psppire_sheet_finalize;
-
-  cell_padding_spec =
-    g_param_spec_boxed ("cell-padding",
-                       "Cell Padding",
-                       "The space between a cell's contents and its border",
-                       GTK_TYPE_BORDER,
-                       G_PARAM_CONSTRUCT | G_PARAM_READABLE | G_PARAM_WRITABLE);
-
-  vaxis_spec =
-    g_param_spec_pointer ("vertical-axis",
-                         "Vertical Axis",
-                         "A pointer to the PsppireAxis object for the rows",
-                         G_PARAM_READABLE | G_PARAM_WRITABLE );
-
-  haxis_spec =
-    g_param_spec_pointer ("horizontal-axis",
-                         "Horizontal Axis",
-                         "A pointer to the PsppireAxis object for the columns",
-                         G_PARAM_READABLE | G_PARAM_WRITABLE );
-
-  model_spec =
-    g_param_spec_pointer ("model",
-                         "Model",
-                         "A pointer to the data model",
-                         G_PARAM_READABLE | G_PARAM_WRITABLE );
-
-
-  object_class->set_property = psppire_sheet_set_property;
-  object_class->get_property = psppire_sheet_get_property;
-
-  g_object_class_install_property (object_class,
-                                   PROP_VAXIS,
-                                   vaxis_spec);
-
-  g_object_class_install_property (object_class,
-                                   PROP_HAXIS,
-                                   haxis_spec);
-
-  g_object_class_install_property (object_class,
-                                   PROP_CELL_PADDING,
-                                   cell_padding_spec);
-
-  g_object_class_install_property (object_class,
-                                   PROP_MODEL,
-                                   model_spec);
-
-
-  widget_class->realize = psppire_sheet_realize;
-  widget_class->unrealize = psppire_sheet_unrealize;
-  widget_class->map = psppire_sheet_map;
-  widget_class->unmap = psppire_sheet_unmap;
-  widget_class->style_set = psppire_sheet_style_set;
-  widget_class->button_press_event = psppire_sheet_button_press;
-  widget_class->button_release_event = psppire_sheet_button_release;
-  widget_class->motion_notify_event = psppire_sheet_motion;
-  widget_class->enter_notify_event = psppire_sheet_crossing_notify;
-  widget_class->leave_notify_event = psppire_sheet_crossing_notify;
-  widget_class->key_press_event = psppire_sheet_key_press;
-  widget_class->expose_event = psppire_sheet_expose;
-  widget_class->size_request = psppire_sheet_size_request;
-  widget_class->size_allocate = psppire_sheet_size_allocate;
-  widget_class->focus_in_event = psppire_sheet_focus_in;
-  widget_class->focus_out_event = NULL;
-
-  klass->set_scroll_adjustments = psppire_sheet_set_scroll_adjustments;
-  klass->select_row = NULL;
-  klass->select_column = NULL;
-  klass->select_range = NULL;
-  klass->resize_range = NULL;
-  klass->move_range = NULL;
-  klass->traverse = NULL;
-  klass->activate = NULL;
-  klass->changed = NULL;
-}
-
-static void
-psppire_sheet_init (PsppireSheet *sheet)
-{
-  sheet->model = NULL;
-  sheet->haxis = NULL;
-  sheet->vaxis = NULL;
-
-  sheet->flags = 0;
-  sheet->select_status = PSPPIRE_SHEET_NORMAL;
-
-  GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
-  GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
-
-  sheet->column_title_window = NULL;
-  sheet->column_title_area.x = 0;
-  sheet->column_title_area.y = 0;
-  sheet->column_title_area.width = 0;
-  sheet->column_title_area.height = DEFAULT_ROW_HEIGHT;
-
-  sheet->row_title_window = NULL;
-  sheet->row_title_area.x = 0;
-  sheet->row_title_area.y = 0;
-  sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
-  sheet->row_title_area.height = 0;
-
-
-  sheet->active_cell.row = 0;
-  sheet->active_cell.col = 0;
-
-  sheet->range.row0 = 0;
-  sheet->range.rowi = 0;
-  sheet->range.col0 = 0;
-  sheet->range.coli = 0;
-
-  sheet->sheet_window = NULL;
-  sheet->entry_widget = NULL;
-  sheet->button = NULL;
-
-  sheet->hadjustment = NULL;
-  sheet->vadjustment = NULL;
-
-  sheet->cursor_drag = NULL;
-
-  sheet->xor_gc = NULL;
-  sheet->fg_gc = NULL;
-  sheet->bg_gc = NULL;
-  sheet->x_drag = 0;
-  sheet->y_drag = 0;
-  sheet->show_grid = TRUE;
-
-  sheet->motion_timer = 0;
-
-  sheet->row_titles_visible = TRUE;
-  sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
-
-  sheet->column_titles_visible = TRUE;
-
-
-  /* create sheet entry */
-  sheet->entry_type = GTK_TYPE_ENTRY;
-  create_sheet_entry (sheet);
-
-  /* create global selection button */
-  create_global_button (sheet);
-}
-
-
-/* Cause RANGE to be redrawn. If RANGE is null, then the
-   entire visible range will be redrawn.
-*/
-static void
-redraw_range (PsppireSheet *sheet, PsppireSheetRange *range)
-{
-  GdkRectangle rect;
-
-  if ( ! GTK_WIDGET_REALIZED (sheet))
-    return;
-
-  if ( NULL != range )
-    rectangle_from_range (sheet, range, &rect);
-  else
-    {
-      GdkRegion *r = gdk_drawable_get_visible_region (sheet->sheet_window);
-      gdk_region_get_clipbox (r, &rect);
-
-      if ( sheet->column_titles_visible)
-       {
-         rect.y += sheet->column_title_area.height;
-         rect.height -= sheet->column_title_area.height;
-       }
-
-      if ( sheet->row_titles_visible)
-       {
-         rect.x += sheet->row_title_area.width;
-         rect.width -= sheet->row_title_area.width;
-       }
-    }
-
-  gdk_window_invalidate_rect (sheet->sheet_window, &rect, FALSE);
-}
-
-
-/* Callback which occurs whenever columns are inserted / deleted in the model */
-static void
-columns_inserted_deleted_callback (PsppireSheetModel *model, gint first_column,
-                                  gint n_columns,
-                                  gpointer data)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (data);
-
-  PsppireSheetRange range;
-  gint model_columns = psppire_sheet_model_get_column_count (model);
-
-
-  /* Need to update all the columns starting from the first column and onwards.
-   * Previous column are unchanged, so don't need to be updated.
-   */
-  range.col0 = first_column;
-  range.row0 = 0;
-  range.coli = psppire_axis_unit_count (sheet->haxis) - 1;
-  range.rowi = psppire_axis_unit_count (sheet->vaxis) - 1;
-
-  adjust_scrollbars (sheet);
-
-  if (sheet->active_cell.col >= model_columns)
-    change_active_cell (sheet, sheet->active_cell.row, model_columns - 1);
-
-  draw_column_title_buttons_range (sheet,
-                                  first_column, max_visible_column (sheet));
-
-
-  redraw_range (sheet, &range);
-}
-
-
-
-
-/* Callback which occurs whenever rows are inserted / deleted in the model */
-static void
-rows_inserted_deleted_callback (PsppireSheetModel *model, gint first_row,
-                               gint n_rows, gpointer data)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (data);
-
-  PsppireSheetRange range;
-
-  gint model_rows = psppire_sheet_model_get_row_count (model);
-
-  /* Need to update all the rows starting from the first row and onwards.
-   * Previous rows are unchanged, so don't need to be updated.
-   */
-  range.row0 = first_row;
-  range.col0 = 0;
-  range.rowi = psppire_axis_unit_count (sheet->vaxis) - 1;
-  range.coli = psppire_axis_unit_count (sheet->haxis) - 1;
-
-  adjust_scrollbars (sheet);
-
-  if (sheet->active_cell.row >= model_rows)
-    change_active_cell (sheet, model_rows - 1, sheet->active_cell.col);
-
-  draw_row_title_buttons_range (sheet, first_row, max_visible_row (sheet));
-
-  redraw_range (sheet, &range);
-}
-
-/*
-  If row0 or rowi are negative, then all rows will be updated.
-  If col0 or coli are negative, then all columns will be updated.
-*/
-static void
-range_update_callback (PsppireSheetModel *m, gint row0, gint col0,
-                      gint rowi, gint coli, gpointer data)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (data);
-
-  PsppireSheetRange range;
-
-  range.row0 = row0;
-  range.col0 = col0;
-  range.rowi = rowi;
-  range.coli = coli;
-
-  if ( !GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    return;
-
-  if ( ( row0 < 0 && col0 < 0 ) || ( rowi < 0 && coli < 0 ) )
-    {
-      redraw_range (sheet, NULL);
-      adjust_scrollbars (sheet);
-
-      draw_row_title_buttons_range (sheet, min_visible_row (sheet),
-                                   max_visible_row (sheet));
-
-      draw_column_title_buttons_range (sheet, min_visible_column (sheet),
-                                      max_visible_column (sheet));
-
-      return;
-    }
-  else if ( row0 < 0 || rowi < 0 )
-    {
-      range.row0 = min_visible_row (sheet);
-      range.rowi = max_visible_row (sheet);
-    }
-  else if ( col0 < 0 || coli < 0 )
-    {
-      range.col0 = min_visible_column (sheet);
-      range.coli = max_visible_column (sheet);
-    }
-
-  redraw_range (sheet, &range);
-}
-
-
-/**
- * psppire_sheet_new:
- * @rows: initial number of rows
- * @columns: initial number of columns
- * @title: sheet title
- * @model: the model to use for the sheet data
- *
- * Creates a new sheet widget with the given number of rows and columns.
- *
- * Returns: the new sheet widget
- */
-GtkWidget *
-psppire_sheet_new (PsppireSheetModel *model)
-{
-  GtkWidget *widget = g_object_new (PSPPIRE_TYPE_SHEET,
-                                   "model", model,
-                                   NULL);
-  return widget;
-}
-
-
-/**
- * psppire_sheet_set_model
- * @sheet: the sheet to set the model for
- * @model: the model to use for the sheet data
- *
- * Sets the model for a PsppireSheet
- *
- */
-void
-psppire_sheet_set_model (PsppireSheet *sheet, PsppireSheetModel *model)
-{
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (sheet->model ) g_object_unref (sheet->model);
-
-  sheet->model = model;
-
-  if ( model)
-    {
-      g_object_ref (model);
-
-      sheet->update_handler_id = g_signal_connect (model, "range_changed",
-                                                  G_CALLBACK (range_update_callback),
-                                                  sheet);
-
-      g_signal_connect (model, "rows_inserted",
-                       G_CALLBACK (rows_inserted_deleted_callback), sheet);
-
-      g_signal_connect (model, "rows_deleted",
-                       G_CALLBACK (rows_inserted_deleted_callback), sheet);
-
-      g_signal_connect (model, "columns_inserted",
-                       G_CALLBACK (columns_inserted_deleted_callback), sheet);
-
-      g_signal_connect (model, "columns_deleted",
-                       G_CALLBACK (columns_inserted_deleted_callback), sheet);
-    }
-}
-
-
-void
-psppire_sheet_change_entry (PsppireSheet *sheet, GType entry_type)
-{
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (sheet->select_status == PSPPIRE_SHEET_NORMAL)
-    psppire_sheet_hide_entry_widget (sheet);
-
-  sheet->entry_type = entry_type;
-
-  create_sheet_entry (sheet);
-
-  if (sheet->select_status == PSPPIRE_SHEET_NORMAL)
-    psppire_sheet_show_entry_widget (sheet);
-}
-
-void
-psppire_sheet_show_grid (PsppireSheet *sheet, gboolean show)
-{
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (show == sheet->show_grid) return;
-
-  sheet->show_grid = show;
-
-  redraw_range (sheet, NULL);
-}
-
-gboolean
-psppire_sheet_grid_visible (PsppireSheet *sheet)
-{
-  g_return_val_if_fail (sheet != NULL, 0);
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0);
-
-  return sheet->show_grid;
-}
-
-guint
-psppire_sheet_get_columns_count (PsppireSheet *sheet)
-{
-  g_return_val_if_fail (sheet != NULL, 0);
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0);
-
-  return psppire_axis_unit_count (sheet->haxis);
-}
-
-static void set_column_width (PsppireSheet *sheet,
-                             gint column,
-                             gint width);
-
-
-void
-psppire_sheet_show_column_titles (PsppireSheet *sheet)
-{
-  if (sheet->column_titles_visible) return;
-
-  sheet->column_titles_visible = TRUE;
-
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    return;
-
-  gdk_window_show (sheet->column_title_window);
-  gdk_window_move_resize (sheet->column_title_window,
-                         sheet->column_title_area.x,
-                         sheet->column_title_area.y,
-                         sheet->column_title_area.width,
-                         sheet->column_title_area.height);
-
-  adjust_scrollbars (sheet);
-
-  if (sheet->vadjustment)
-    g_signal_emit_by_name (sheet->vadjustment,
-                          "value_changed");
-
-  size_allocate_global_button (sheet);
-
-  if ( sheet->row_titles_visible)
-    gtk_widget_show (sheet->button);
-}
-
-
-void
-psppire_sheet_show_row_titles (PsppireSheet *sheet)
-{
-  if (sheet->row_titles_visible) return;
-
-  sheet->row_titles_visible = TRUE;
-
-
-  if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    {
-      gdk_window_show (sheet->row_title_window);
-      gdk_window_move_resize (sheet->row_title_window,
-                             sheet->row_title_area.x,
-                             sheet->row_title_area.y,
-                             sheet->row_title_area.width,
-                             sheet->row_title_area.height);
-
-      adjust_scrollbars (sheet);
-    }
-
-  if (sheet->hadjustment)
-    g_signal_emit_by_name (sheet->hadjustment,
-                          "value_changed");
-
-  size_allocate_global_button (sheet);
-
-  if ( sheet->column_titles_visible)
-    gtk_widget_show (sheet->button);
-}
-
-void
-psppire_sheet_hide_column_titles (PsppireSheet *sheet)
-{
-  if (!sheet->column_titles_visible) return;
-
-  sheet->column_titles_visible = FALSE;
-
-  if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    {
-      if (sheet->column_title_window)
-       gdk_window_hide (sheet->column_title_window);
-
-      gtk_widget_hide (sheet->button);
-
-      adjust_scrollbars (sheet);
-    }
-
-  if (sheet->vadjustment)
-    g_signal_emit_by_name (sheet->vadjustment,
-                          "value_changed");
-}
-
-void
-psppire_sheet_hide_row_titles (PsppireSheet *sheet)
-{
-  if (!sheet->row_titles_visible) return;
-
-  sheet->row_titles_visible = FALSE;
-
-  if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    {
-      if (sheet->row_title_window)
-       gdk_window_hide (sheet->row_title_window);
-
-      gtk_widget_hide (sheet->button);
-
-      adjust_scrollbars (sheet);
-    }
-
-  if (sheet->hadjustment)
-    g_signal_emit_by_name (sheet->hadjustment,
-                          "value_changed");
-}
-
-
-/* Scroll the sheet so that the cell ROW, COLUMN is visible.
-   If {ROW,COL}_ALIGN is zero, then the cell will be placed
-   at the {top,left} of the sheet.  If it's 1, then it'll
-   be placed at the {bottom,right}.
-   ROW or COL may be -1, in which case scrolling in that dimension
-   does not occur.
-*/
-void
-psppire_sheet_moveto (PsppireSheet *sheet,
-                     gint row,
-                     gint col,
-                     gfloat row_align,
-                     gfloat col_align)
-{
-  gint width, height;
-
-  g_return_if_fail (row_align >= 0);
-  g_return_if_fail (col_align >= 0);
-
-  g_return_if_fail (row_align <= 1);
-  g_return_if_fail (col_align <= 1);
-
-  g_return_if_fail (col <
-                   psppire_axis_unit_count (sheet->haxis));
-  g_return_if_fail (row <
-                   psppire_axis_unit_count (sheet->vaxis));
-
-  gdk_drawable_get_size (sheet->sheet_window, &width, &height);
-
-
-  if (row >= 0)
-    {
-      gint y =  psppire_axis_start_pixel (sheet->vaxis, row);
-
-      gtk_adjustment_set_value (sheet->vadjustment, y - height * row_align);
-    }
-
-
-  if (col >= 0)
-    {
-      gint x =  psppire_axis_start_pixel (sheet->haxis, col);
-
-      gtk_adjustment_set_value (sheet->hadjustment, x - width * col_align);
-    }
-}
-
-
-
-
-static gboolean
-psppire_sheet_range_isvisible (const PsppireSheet *sheet,
-                              const PsppireSheetRange *range)
-{
-  g_return_val_if_fail (sheet != NULL, FALSE);
-
-  if (range->row0 < 0 || range->row0 >= psppire_axis_unit_count (sheet->vaxis))
-    return FALSE;
-
-  if (range->rowi < 0 || range->rowi >= psppire_axis_unit_count (sheet->vaxis))
-    return FALSE;
-
-  if (range->col0 < 0 || range->col0 >= psppire_axis_unit_count (sheet->haxis))
-    return FALSE;
-
-  if (range->coli < 0 || range->coli >= psppire_axis_unit_count (sheet->haxis))
-    return FALSE;
-
-  if (range->rowi < min_visible_row (sheet))
-    return FALSE;
-
-  if (range->row0 > max_visible_row (sheet))
-    return FALSE;
-
-  if (range->coli < min_visible_column (sheet))
-    return FALSE;
-
-  if (range->col0 > max_visible_column (sheet))
-    return FALSE;
-
-  return TRUE;
-}
-
-static gboolean
-psppire_sheet_cell_isvisible (PsppireSheet *sheet,
-                             gint row, gint column)
-{
-  PsppireSheetRange range;
-
-  range.row0 = row;
-  range.col0 = column;
-  range.rowi = row;
-  range.coli = column;
-
-  return psppire_sheet_range_isvisible (sheet, &range);
-}
-
-void
-psppire_sheet_get_visible_range (PsppireSheet *sheet, PsppireSheetRange *range)
-{
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet)) ;
-  g_return_if_fail (range != NULL);
-
-  range->row0 = min_visible_row (sheet);
-  range->col0 = min_visible_column (sheet);
-  range->rowi = max_visible_row (sheet);
-  range->coli = max_visible_column (sheet);
-}
-
-
-static gboolean
-psppire_sheet_set_scroll_adjustments (PsppireSheet *sheet,
-                                     GtkAdjustment *hadjustment,
-                                     GtkAdjustment *vadjustment)
-{
-  if ( sheet->vadjustment != vadjustment )
-    {
-      if (sheet->vadjustment)
-       g_object_unref (sheet->vadjustment);
-      sheet->vadjustment = vadjustment;
-
-      if ( vadjustment)
-       {
-         g_object_ref (vadjustment);
-
-         g_signal_connect (sheet->vadjustment, "value_changed",
-                           G_CALLBACK (vadjustment_value_changed),
-                           sheet);
-       }
-    }
-
-  if ( sheet->hadjustment != hadjustment )
-    {
-      if (sheet->hadjustment)
-       g_object_unref (sheet->hadjustment);
-
-      sheet->hadjustment = hadjustment;
-
-      if ( hadjustment)
-       {
-         g_object_ref (hadjustment);
-
-         g_signal_connect (sheet->hadjustment, "value_changed",
-                           G_CALLBACK (hadjustment_value_changed),
-                           sheet);
-       }
-    }
-  return TRUE;
-}
-
-static void
-psppire_sheet_finalize (GObject *object)
-{
-  PsppireSheet *sheet;
-
-  g_return_if_fail (object != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (object));
-
-  sheet = PSPPIRE_SHEET (object);
-
-  if (G_OBJECT_CLASS (parent_class)->finalize)
-    (*G_OBJECT_CLASS (parent_class)->finalize) (object);
-}
-
-static void
-psppire_sheet_dispose  (GObject *object)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (object);
-
-  g_return_if_fail (object != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (object));
-
-  if ( sheet->dispose_has_run )
-    return ;
-
-  sheet->dispose_has_run = TRUE;
-
-  if ( sheet->cell_padding)
-    g_boxed_free (GTK_TYPE_BORDER, sheet->cell_padding);
-
-  if (sheet->model) g_object_unref (sheet->model);
-  if (sheet->vaxis) g_object_unref (sheet->vaxis);
-  if (sheet->haxis) g_object_unref (sheet->haxis);
-
-  g_object_unref (sheet->button);
-  sheet->button = NULL;
-
-  /* unref adjustments */
-  if (sheet->hadjustment)
-    {
-      g_signal_handlers_disconnect_matched (sheet->hadjustment,
-                                           G_SIGNAL_MATCH_DATA,
-                                           0, 0, 0, 0,
-                                           sheet);
-
-      g_object_unref (sheet->hadjustment);
-      sheet->hadjustment = NULL;
-    }
-
-  if (sheet->vadjustment)
-    {
-      g_signal_handlers_disconnect_matched (sheet->vadjustment,
-                                           G_SIGNAL_MATCH_DATA,
-                                           0, 0, 0, 0,
-                                           sheet);
-
-      g_object_unref (sheet->vadjustment);
-
-      sheet->vadjustment = NULL;
-    }
-
-  if (G_OBJECT_CLASS (parent_class)->dispose)
-    (*G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-static void
-psppire_sheet_style_set (GtkWidget *widget,
-                        GtkStyle *previous_style)
-{
-  PsppireSheet *sheet;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (widget));
-
-  if (GTK_WIDGET_CLASS (parent_class)->style_set)
-    (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
-
-  sheet = PSPPIRE_SHEET (widget);
-
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      gtk_style_set_background (widget->style, widget->window, widget->state);
-    }
-
-  set_entry_widget_font (sheet);
-}
-
-
-static void
-psppire_sheet_realize (GtkWidget *widget)
-{
-  PsppireSheet *sheet;
-  GdkWindowAttr attributes;
-  const gint attributes_mask =
-    GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR;
-
-  GdkGCValues values;
-  GdkColormap *colormap;
-  GdkDisplay *display;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (widget));
-
-  sheet = PSPPIRE_SHEET (widget);
-
-  colormap = gtk_widget_get_colormap (widget);
-  display = gtk_widget_get_display (widget);
-
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.x = widget->allocation.x;
-  attributes.y = widget->allocation.y;
-  attributes.width = widget->allocation.width;
-  attributes.height = widget->allocation.height;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = colormap;
-
-  attributes.event_mask = gtk_widget_get_events (widget);
-  attributes.event_mask |= (GDK_EXPOSURE_MASK |
-                           GDK_BUTTON_PRESS_MASK |
-                           GDK_BUTTON_RELEASE_MASK |
-                           GDK_KEY_PRESS_MASK |
-                           GDK_ENTER_NOTIFY_MASK |
-                           GDK_LEAVE_NOTIFY_MASK |
-                           GDK_POINTER_MOTION_MASK |
-                           GDK_POINTER_MOTION_HINT_MASK);
-
-  attributes.cursor = gdk_cursor_new_for_display (display, GDK_TOP_LEFT_ARROW);
-
-  /* main window */
-  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
-
-  gdk_window_set_user_data (widget->window, sheet);
-
-  widget->style = gtk_style_attach (widget->style, widget->window);
-
-  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
-
-  gdk_color_parse ("white", &sheet->color[BG_COLOR]);
-  gdk_colormap_alloc_color (colormap, &sheet->color[BG_COLOR], FALSE,
-                           TRUE);
-  gdk_color_parse ("gray", &sheet->color[GRID_COLOR]);
-  gdk_colormap_alloc_color (colormap, &sheet->color[GRID_COLOR], FALSE,
-                           TRUE);
-
-  attributes.x = 0;
-  attributes.y = 0;
-  attributes.width = sheet->column_title_area.width;
-  attributes.height = sheet->column_title_area.height;
-
-
-  /* column - title window */
-  sheet->column_title_window =
-    gdk_window_new (widget->window, &attributes, attributes_mask);
-  gdk_window_set_user_data (sheet->column_title_window, sheet);
-  gtk_style_set_background (widget->style, sheet->column_title_window,
-                           GTK_STATE_NORMAL);
-
-
-  attributes.x = 0;
-  attributes.y = 0;
-  attributes.width = sheet->row_title_area.width;
-  attributes.height = sheet->row_title_area.height;
-
-  /* row - title window */
-  sheet->row_title_window = gdk_window_new (widget->window,
-                                           &attributes, attributes_mask);
-  gdk_window_set_user_data (sheet->row_title_window, sheet);
-  gtk_style_set_background (widget->style, sheet->row_title_window,
-                           GTK_STATE_NORMAL);
-
-  /* sheet - window */
-  attributes.cursor = gdk_cursor_new_for_display (display, GDK_PLUS);
-
-  attributes.x = 0;
-  attributes.y = 0;
-
-  sheet->sheet_window = gdk_window_new (widget->window,
-                                       &attributes, attributes_mask);
-  gdk_window_set_user_data (sheet->sheet_window, sheet);
-
-  gdk_cursor_unref (attributes.cursor);
-
-  gdk_window_set_background (sheet->sheet_window, &widget->style->white);
-  gdk_window_show (sheet->sheet_window);
-
-  /* GCs */
-  sheet->fg_gc = gdk_gc_new (widget->window);
-  sheet->bg_gc = gdk_gc_new (widget->window);
-
-  values.foreground = widget->style->white;
-  values.function = GDK_INVERT;
-  values.subwindow_mode = GDK_INCLUDE_INFERIORS;
-  values.line_width = MAX (sheet->cell_padding->left,
-                          MAX (sheet->cell_padding->right,
-                               MAX (sheet->cell_padding->top,
-                                    sheet->cell_padding->bottom)));
-
-  sheet->xor_gc = gdk_gc_new_with_values (widget->window,
-                                         &values,
-                                         GDK_GC_FOREGROUND |
-                                         GDK_GC_FUNCTION |
-                                         GDK_GC_SUBWINDOW |
-                                         GDK_GC_LINE_WIDTH
-                                         );
-
-  gtk_widget_set_parent_window (sheet->entry_widget, sheet->sheet_window);
-  gtk_widget_set_parent (sheet->entry_widget, GTK_WIDGET (sheet));
-
-  gtk_widget_set_parent_window (sheet->button, sheet->sheet_window);
-  gtk_widget_set_parent (sheet->button, GTK_WIDGET (sheet));
-
-  sheet->button->style = gtk_style_attach (sheet->button->style,
-                                          sheet->sheet_window);
-
-
-  sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_PLUS);
-
-  if (sheet->column_titles_visible)
-    gdk_window_show (sheet->column_title_window);
-  if (sheet->row_titles_visible)
-    gdk_window_show (sheet->row_title_window);
-
-  sheet->hover_window = create_hover_window ();
-
-  draw_row_title_buttons (sheet);
-  draw_column_title_buttons (sheet);
-
-  psppire_sheet_update_primary_selection (sheet);
-
-
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-}
-
-static void
-create_global_button (PsppireSheet *sheet)
-{
-  sheet->button = gtk_button_new_with_label (" ");
-
-  GTK_WIDGET_UNSET_FLAGS(sheet->button, GTK_CAN_FOCUS);
-
-  g_object_ref_sink (sheet->button);
-
-  g_signal_connect (sheet->button,
-                   "pressed",
-                   G_CALLBACK (global_button_clicked),
-                   sheet);
-}
-
-static void
-size_allocate_global_button (PsppireSheet *sheet)
-{
-  GtkAllocation allocation;
-
-  if (!sheet->column_titles_visible) return;
-  if (!sheet->row_titles_visible) return;
-
-  gtk_widget_size_request (sheet->button, NULL);
-
-  allocation.x = 0;
-  allocation.y = 0;
-  allocation.width = sheet->row_title_area.width;
-  allocation.height = sheet->column_title_area.height;
-
-  gtk_widget_size_allocate (sheet->button, &allocation);
-}
-
-static void
-global_button_clicked (GtkWidget *widget, gpointer data)
-{
-  psppire_sheet_click_cell (PSPPIRE_SHEET (data), -1, -1);
-}
-
-
-static void
-psppire_sheet_unrealize (GtkWidget *widget)
-{
-  PsppireSheet *sheet;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (widget));
-
-  sheet = PSPPIRE_SHEET (widget);
-
-  gdk_cursor_unref (sheet->cursor_drag);
-  sheet->cursor_drag = NULL;
-
-  gdk_colormap_free_colors (gtk_widget_get_colormap (widget),
-                           sheet->color, n_COLORS);
-
-  g_object_unref (sheet->xor_gc);
-  g_object_unref (sheet->fg_gc);
-  g_object_unref (sheet->bg_gc);
-
-  destroy_hover_window (sheet->hover_window);
-
-  gdk_window_destroy (sheet->sheet_window);
-  gdk_window_destroy (sheet->column_title_window);
-  gdk_window_destroy (sheet->row_title_window);
-
-  gtk_widget_unparent (sheet->entry_widget);
-  if (sheet->button != NULL)
-    gtk_widget_unparent (sheet->button);
-
-  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
-}
-
-static void
-psppire_sheet_map (GtkWidget *widget)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (widget);
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (widget));
-
-  if (!GTK_WIDGET_MAPPED (widget))
-    {
-      GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
-
-      gdk_window_show (widget->window);
-      gdk_window_show (sheet->sheet_window);
-
-      if (sheet->column_titles_visible)
-       {
-         draw_column_title_buttons (sheet);
-         gdk_window_show (sheet->column_title_window);
-       }
-      if (sheet->row_titles_visible)
-       {
-         draw_row_title_buttons (sheet);
-         gdk_window_show (sheet->row_title_window);
-       }
-
-      if (!GTK_WIDGET_MAPPED (sheet->entry_widget)
-         && sheet->active_cell.row >= 0
-         && sheet->active_cell.col >= 0 )
-       {
-         gtk_widget_show (sheet->entry_widget);
-         gtk_widget_map (sheet->entry_widget);
-       }
-
-      if (!GTK_WIDGET_MAPPED (sheet->button))
-       {
-         gtk_widget_show (sheet->button);
-         gtk_widget_map (sheet->button);
-       }
-
-      redraw_range (sheet, NULL);
-      change_active_cell (sheet,
-                         sheet->active_cell.row,
-                         sheet->active_cell.col);
-    }
-}
-
-static void
-psppire_sheet_unmap (GtkWidget *widget)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (widget);
-
-  if (!GTK_WIDGET_MAPPED (widget))
-    return;
-
-  GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
-
-  gdk_window_hide (sheet->sheet_window);
-  if (sheet->column_titles_visible)
-    gdk_window_hide (sheet->column_title_window);
-  if (sheet->row_titles_visible)
-    gdk_window_hide (sheet->row_title_window);
-  gdk_window_hide (widget->window);
-
-  gtk_widget_unmap (sheet->entry_widget);
-  gtk_widget_unmap (sheet->button);
-  gtk_widget_unmap (sheet->hover_window->window);
-}
-
-/* get cell attributes of the given cell */
-/* TRUE means that the cell is currently allocated */
-static gboolean psppire_sheet_get_attributes (const PsppireSheet *sheet,
-                                             gint row, gint col,
-                                             PsppireSheetCellAttr *attributes);
-
-
-
-static void
-psppire_sheet_cell_draw (PsppireSheet *sheet, gint row, gint col)
-{
-  PangoLayout *layout;
-  PangoRectangle text;
-  PangoFontDescription *font_desc = GTK_WIDGET (sheet)->style->font_desc;
-  gint font_height;
-
-  gchar *label;
-
-  PsppireSheetCellAttr attributes;
-  GdkRectangle area;
-
-  g_return_if_fail (sheet != NULL);
-
-  /* bail now if we aren't yet drawable */
-  if (!GTK_WIDGET_DRAWABLE (sheet)) return;
-
-  if (row < 0 ||
-      row >= psppire_axis_unit_count (sheet->vaxis))
-    return;
-
-  if (col < 0 ||
-      col >= psppire_axis_unit_count (sheet->haxis))
-    return;
-
-  psppire_sheet_get_attributes (sheet, row, col, &attributes);
-
-  /* select GC for background rectangle */
-  gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
-  gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
-
-  rectangle_from_cell (sheet, row, col, &area);
-
-  gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
-
-  if (sheet->show_grid)
-    {
-      gdk_gc_set_foreground (sheet->bg_gc, &sheet->color[GRID_COLOR]);
-
-      gdk_draw_rectangle (sheet->sheet_window,
-                         sheet->bg_gc,
-                         FALSE,
-                         area.x, area.y,
-                         area.width, area.height);
-    }
-
-
-  label = psppire_sheet_cell_get_text (sheet, row, col);
-  if (NULL == label)
-    return;
-
-
-  layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), label);
-  dispose_string (sheet, label);
-
-
-  pango_layout_set_font_description (layout, font_desc);
-
-  pango_layout_get_pixel_extents (layout, NULL, &text);
-
-  gdk_gc_set_clip_rectangle (sheet->fg_gc, &area);
-
-  font_height = pango_font_description_get_size (font_desc);
-  if ( !pango_font_description_get_size_is_absolute (font_desc))
-    font_height /= PANGO_SCALE;
-
-
-  if ( sheet->cell_padding )
-    {
-      area.x += sheet->cell_padding->left;
-      area.width -= sheet->cell_padding->right
-       + sheet->cell_padding->left;
-
-      area.y += sheet->cell_padding->top;
-      area.height -= sheet->cell_padding->bottom
-       +
-       sheet->cell_padding->top;
-    }
-
-  /* Centre the text vertically */
-  area.y += (area.height - font_height) / 2.0;
-
-  switch (attributes.justification)
-    {
-    case GTK_JUSTIFY_RIGHT:
-      area.x += area.width - text.width;
-      break;
-    case GTK_JUSTIFY_CENTER:
-      area.x += (area.width - text.width) / 2.0;
-      break;
-    case GTK_JUSTIFY_LEFT:
-      /* Do nothing */
-      break;
-    default:
-      g_critical ("Unhandled justification %d in column %d\n",
-                 attributes.justification, col);
-      break;
-    }
-
-  gdk_draw_layout (sheet->sheet_window, sheet->fg_gc,
-                  area.x,
-                  area.y,
-                  layout);
-
-  gdk_gc_set_clip_rectangle (sheet->fg_gc, NULL);
-  g_object_unref (layout);
-}
-
-
-static void
-draw_sheet_region (PsppireSheet *sheet, GdkRegion *region)
-{
-  PsppireSheetRange range;
-  GdkRectangle area;
-  gint y, x;
-  gint i, j;
-
-  PsppireSheetRange drawing_range;
-
-  gdk_region_get_clipbox (region, &area);
-
-  y = area.y + sheet->vadjustment->value;
-  x = area.x + sheet->hadjustment->value;
-
-  if ( sheet->column_titles_visible)
-    y -= sheet->column_title_area.height;
-
-  if ( sheet->row_titles_visible)
-    x -= sheet->row_title_area.width;
-
-  maximize_int (&x, 0);
-  maximize_int (&y, 0);
-
-  range.row0 = row_from_ypixel (sheet, y);
-  range.rowi = row_from_ypixel (sheet, y + area.height);
-
-  range.col0 = column_from_xpixel (sheet, x);
-  range.coli = column_from_xpixel (sheet, x + area.width);
-
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_SHEET (sheet));
-
-  if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
-  if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
-
-
-  drawing_range.row0 = MAX (range.row0, min_visible_row (sheet));
-  drawing_range.col0 = MAX (range.col0, min_visible_column (sheet));
-  drawing_range.rowi = MIN (range.rowi, max_visible_row (sheet));
-  drawing_range.coli = MIN (range.coli, max_visible_column (sheet));
-
-  g_return_if_fail (drawing_range.rowi >= drawing_range.row0);
-  g_return_if_fail (drawing_range.coli >= drawing_range.col0);
-
-  for (i = drawing_range.row0; i <= drawing_range.rowi; i++)
-    {
-      for (j = drawing_range.col0; j <= drawing_range.coli; j++)
-       psppire_sheet_cell_draw (sheet, i, j);
-    }
-
-  if (sheet->select_status == PSPPIRE_SHEET_NORMAL &&
-      sheet->active_cell.row >= drawing_range.row0 &&
-      sheet->active_cell.row <= drawing_range.rowi &&
-      sheet->active_cell.col >= drawing_range.col0 &&
-      sheet->active_cell.col <= drawing_range.coli)
-    psppire_sheet_show_entry_widget (sheet);
-}
-
-static void
-psppire_sheet_set_cell (PsppireSheet *sheet, gint row, gint col,
-                       GtkJustification justification,
-                       const gchar *text)
-{
-  PsppireSheetModel *model ;
-  gchar *old_text ;
-
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (col >= psppire_axis_unit_count (sheet->haxis)
-      || row >= psppire_axis_unit_count (sheet->vaxis))
-    return;
-
-  if (col < 0 || row < 0) return;
-
-  model = psppire_sheet_get_model (sheet);
-
-  old_text = psppire_sheet_model_get_string (model, row, col);
-
-  if (0 != g_strcmp0 (old_text, text))
-    {
-      g_signal_handler_block    (sheet->model, sheet->update_handler_id);
-      psppire_sheet_model_set_string (model, text, row, col);
-      g_signal_handler_unblock  (sheet->model, sheet->update_handler_id);
-    }
-
-  if ( psppire_sheet_model_free_strings (model))
-    g_free (old_text);
-}
-
-
-void
-psppire_sheet_cell_clear (PsppireSheet *sheet, gint row, gint column)
-{
-  PsppireSheetRange range;
-
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-  if (column >= psppire_axis_unit_count (sheet->haxis) ||
-      row >= psppire_axis_unit_count (sheet->vaxis)) return;
-
-  if (column < 0 || row < 0) return;
-
-  range.row0 = row;
-  range.rowi = row;
-  range.col0 = min_visible_column (sheet);
-  range.coli = max_visible_column (sheet);
-
-  psppire_sheet_real_cell_clear (sheet, row, column);
-
-  redraw_range (sheet, &range);
-}
-
-static void
-psppire_sheet_real_cell_clear (PsppireSheet *sheet, gint row, gint column)
-{
-  PsppireSheetModel *model = psppire_sheet_get_model (sheet);
-
-  gchar *old_text = psppire_sheet_cell_get_text (sheet, row, column);
-
-  if (old_text && strlen (old_text) > 0 )
-    {
-      psppire_sheet_model_datum_clear (model, row, column);
-    }
-
-  dispose_string (sheet, old_text);
-}
-
-gchar *
-psppire_sheet_cell_get_text (const PsppireSheet *sheet, gint row, gint col)
-{
-  PsppireSheetModel *model;
-  g_return_val_if_fail (sheet != NULL, NULL);
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), NULL);
-
-  if (col >= psppire_axis_unit_count (sheet->haxis) || row >= psppire_axis_unit_count (sheet->vaxis))
-    return NULL;
-  if (col < 0 || row < 0) return NULL;
-
-  model = psppire_sheet_get_model (sheet);
-
-  if ( !model )
-    return NULL;
-
-  return psppire_sheet_model_get_string (model, row, col);
-}
-
-
-/* Convert X, Y (in pixels) to *ROW, *COLUMN
-   If the function returns FALSE, then the results will be unreliable.
-*/
-static gboolean
-psppire_sheet_get_pixel_info (PsppireSheet *sheet,
-                             gint x,
-                             gint y,
-                             gint *row,
-                             gint *column)
-{
-  gint trow, tcol;
-  *row = -G_MAXINT;
-  *column = -G_MAXINT;
-
-  g_return_val_if_fail (sheet != NULL, 0);
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0);
-
-  /* bounds checking, return false if the user clicked
-     on a blank area */
-  if (y < 0)
-    return FALSE;
-
-  if (x < 0)
-    return FALSE;
-
-  if ( sheet->column_titles_visible)
-    y -= sheet->column_title_area.height;
-
-  y += sheet->vadjustment->value;
-
-  if ( y < 0 && sheet->column_titles_visible)
-    {
-      trow = -1;
-    }
-  else
-    {
-      trow = row_from_ypixel (sheet, y);
-      if (trow > psppire_axis_unit_count (sheet->vaxis))
-       return FALSE;
-    }
-
-  *row = trow;
-
-  if ( sheet->row_titles_visible)
-    x -= sheet->row_title_area.width;
-
-  x += sheet->hadjustment->value;
-
-  if ( x < 0 && sheet->row_titles_visible)
-    {
-      tcol = -1;
-    }
-  else
-    {
-      tcol = column_from_xpixel (sheet, x);
-      if (tcol > psppire_axis_unit_count (sheet->haxis))
-       return FALSE;
-    }
-
-  *column = tcol;
-
-  return TRUE;
-}
-
-gboolean
-psppire_sheet_get_cell_area (PsppireSheet *sheet,
-                            gint row,
-                            gint column,
-                            GdkRectangle *area)
-{
-  g_return_val_if_fail (sheet != NULL, 0);
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0);
-
-  if (row >= psppire_axis_unit_count (sheet->vaxis) || column >= psppire_axis_unit_count (sheet->haxis))
-    return FALSE;
-
-  area->x = (column == -1) ? 0 : psppire_axis_start_pixel (sheet->haxis, column);
-  area->y = (row == -1)    ? 0 : psppire_axis_start_pixel (sheet->vaxis, row);
-
-  area->width= (column == -1) ? sheet->row_title_area.width
-    : psppire_axis_unit_size (sheet->haxis, column);
-
-  area->height= (row == -1) ? sheet->column_title_area.height
-    : psppire_axis_unit_size (sheet->vaxis, row);
-
-  return TRUE;
-}
-
-void
-psppire_sheet_set_active_cell (PsppireSheet *sheet, gint row, gint col)
-{
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (row < -1 || col < -1)
-    return;
-
-  if (row >= psppire_axis_unit_count (sheet->vaxis)
-      ||
-      col >= psppire_axis_unit_count (sheet->haxis))
-    return;
-
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    return;
-
-  if ( row == -1 || col == -1)
-    {
-      psppire_sheet_hide_entry_widget (sheet);
-      return;
-    }
-
-  change_active_cell (sheet, row, col);
-}
-
-void
-psppire_sheet_get_active_cell (PsppireSheet *sheet, gint *row, gint *column)
-{
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if ( row ) *row = sheet->active_cell.row;
-  if (column) *column = sheet->active_cell.col;
-}
-
-static void
-entry_load_text (PsppireSheet *sheet)
-{
-  gint row, col;
-  const char *text;
-  GtkJustification justification;
-  PsppireSheetCellAttr attributes;
-
-  if (!GTK_WIDGET_VISIBLE (sheet->entry_widget)) return;
-  if (sheet->select_status != PSPPIRE_SHEET_NORMAL) return;
-
-  row = sheet->active_cell.row;
-  col = sheet->active_cell.col;
-
-  if (row < 0 || col < 0) return;
-
-  text = gtk_entry_get_text (psppire_sheet_get_entry (sheet));
-
-  if (text && strlen (text) > 0)
-    {
-      psppire_sheet_get_attributes (sheet, row, col, &attributes);
-      justification = attributes.justification;
-      psppire_sheet_set_cell (sheet, row, col, justification, text);
-    }
-}
-
-
-static void
-psppire_sheet_hide_entry_widget (PsppireSheet *sheet)
-{
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    return;
-
-  if (sheet->active_cell.row < 0 ||
-      sheet->active_cell.col < 0) return;
-
-  gtk_widget_hide (sheet->entry_widget);
-  gtk_widget_unmap (sheet->entry_widget);
-
-  GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (sheet->entry_widget), GTK_VISIBLE);
-}
-
-static void
-change_active_cell (PsppireSheet *sheet, gint row, gint col)
-{
-  gint old_row, old_col;
-
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (row < 0 || col < 0)
-    return;
-
-  if ( row > psppire_axis_unit_count (sheet->vaxis)
-       || col > psppire_axis_unit_count (sheet->haxis))
-    return;
-
-  old_row = sheet->active_cell.row;
-  old_col = sheet->active_cell.col;
-
-  entry_load_text (sheet);
-
-  /* Erase the old cell border */
-  psppire_sheet_draw_active_cell (sheet);
-
-  sheet->active_cell.row = row;
-  sheet->active_cell.col = col;
-
-  PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-
-  GTK_WIDGET_UNSET_FLAGS (sheet->entry_widget, GTK_HAS_FOCUS);
-
-  psppire_sheet_draw_active_cell (sheet);
-  psppire_sheet_show_entry_widget (sheet);
-
-  GTK_WIDGET_SET_FLAGS (sheet->entry_widget, GTK_HAS_FOCUS);
-
-  g_signal_emit (sheet, sheet_signals [ACTIVATE], 0,
-                row, col, old_row, old_col);
-
-}
-
-static void
-psppire_sheet_show_entry_widget (PsppireSheet *sheet)
-{
-  GtkEntry *sheet_entry;
-  PsppireSheetCellAttr attributes;
-
-  gint row, col;
-
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  row = sheet->active_cell.row;
-  col = sheet->active_cell.col;
-
-  /* Don't show the active cell, if there is no active cell: */
-  if (! (row >= 0 && col >= 0)) /* e.g row or coll == -1. */
-    return;
-
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
-  if (sheet->select_status != PSPPIRE_SHEET_NORMAL) return;
-  if (PSPPIRE_SHEET_IN_SELECTION (sheet)) return;
-
-  GTK_WIDGET_SET_FLAGS (GTK_WIDGET (sheet->entry_widget), GTK_VISIBLE);
-
-  sheet_entry = psppire_sheet_get_entry (sheet);
-
-  psppire_sheet_get_attributes (sheet, row, col, &attributes);
-
-  if (GTK_IS_ENTRY (sheet_entry))
-    {
-      gchar *text = psppire_sheet_cell_get_text (sheet, row, col);
-      const gchar *old_text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
-
-      if ( ! text )
-       text = g_strdup ("");
-
-      if (strcmp (old_text, text) != 0)
-       gtk_entry_set_text (sheet_entry, text);
-      
-      dispose_string (sheet, text);
-
-      {
-       switch (attributes.justification)
-         {
-         case GTK_JUSTIFY_RIGHT:
-           gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 1.0);
-           break;
-         case GTK_JUSTIFY_CENTER:
-           gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 0.5);
-           break;
-         case GTK_JUSTIFY_LEFT:
-         default:
-           gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 0.0);
-           break;
-         }
-      }
-    }
-
-  psppire_sheet_size_allocate_entry (sheet);
-
-  gtk_widget_set_sensitive (GTK_WIDGET (sheet_entry),
-                           psppire_sheet_model_is_editable (sheet->model,
-                                                            row, col));
-  gtk_widget_map (sheet->entry_widget);
-}
-
-static gboolean
-psppire_sheet_draw_active_cell (PsppireSheet *sheet)
-{
-  gint row, col;
-  PsppireSheetRange range;
-
-  row = sheet->active_cell.row;
-  col = sheet->active_cell.col;
-
-  if (row < 0 || col < 0) return FALSE;
-
-  if (!psppire_sheet_cell_isvisible (sheet, row, col))
-    return FALSE;
-
-  range.col0 = range.coli = col;
-  range.row0 = range.rowi = row;
-
-  psppire_sheet_draw_border (sheet, range);
-
-  return FALSE;
-}
-
-
-
-static void
-psppire_sheet_draw_border (PsppireSheet *sheet, PsppireSheetRange new_range)
-{
-  GdkRectangle area;
-
-  rectangle_from_range (sheet, &new_range, &area);
-
-  area.width ++;
-  area.height ++;
-
-  gdk_gc_set_clip_rectangle (sheet->xor_gc, &area);
-
-  area.x += sheet->cell_padding->left / 2;
-  area.y += sheet->cell_padding->top / 2;
-  area.width -= (sheet->cell_padding->left + sheet->cell_padding->right ) / 2;
-  area.height -= (sheet->cell_padding->top + sheet->cell_padding->bottom ) / 2;
-
-  gdk_draw_rectangle (sheet->sheet_window,  sheet->xor_gc,
-                     FALSE,
-                     area.x,
-                     area.y,
-                     area.width,
-                     area.height);
-
-  gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
-}
-
-\f
-
-/* Selection related functions */
-
-void
-psppire_sheet_select_row (PsppireSheet *sheet,  gint row)
-{
-  GdkRectangle area;
-  sheet->select_status = PSPPIRE_SHEET_ROW_SELECTED;
-
-  sheet->range.col0 = sheet->range.coli = -1;
-  sheet->range.row0 = sheet->range.rowi = row;
-
-  rectangle_from_range (sheet, &sheet->range, &area);
-  area.x++;
-  area.y++;
-
-  gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);
-
-  g_signal_emit (sheet, sheet_signals [SELECT_ROW], 0, row);
-}
-
-void
-psppire_sheet_select_column (PsppireSheet *sheet,  gint column)
-{
-  GdkRectangle area;
-  sheet->select_status = PSPPIRE_SHEET_COLUMN_SELECTED;
-
-  sheet->range.col0 = sheet->range.coli = column;
-  sheet->range.row0 = sheet->range.rowi = -1;
-
-  rectangle_from_range (sheet, &sheet->range, &area);
-  area.x++;
-  area.y++;
-
-  gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);
-
-  g_signal_emit (sheet, sheet_signals [SELECT_COLUMN], 0, column);
-}
-
-
-void
-psppire_sheet_select_range (PsppireSheet *sheet, const PsppireSheetRange *range)
-{
-  GdkRectangle area;
-  sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED;
-
-  sheet->range = *range;
-
-  rectangle_from_range (sheet, range, &area);
-  area.x++;
-  area.y++;
-  gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);
-}
-
-
-void
-psppire_sheet_unselect_range (PsppireSheet *sheet)
-{
-  sheet->select_status = PSPPIRE_SHEET_NORMAL;
-
-  if (sheet->sheet_window != NULL)
-    {
-      GdkRectangle area;
-
-      rectangle_from_range (sheet, &sheet->range, &area);
-      area.x++;
-      area.y++;
-      gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);
-    }
-
-  g_signal_emit (sheet, sheet_signals [SELECT_COLUMN], 0, -1);
-  g_signal_emit (sheet, sheet_signals [SELECT_ROW], 0, -1);  
-}
-
-void
-psppire_sheet_get_selected_range (PsppireSheet *sheet, PsppireSheetRange *range)
-{
-  g_return_if_fail (sheet != NULL);
-  *range = sheet->range;
-}
-\f
-
-static gint
-psppire_sheet_expose (GtkWidget *widget, GdkEventExpose *event)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (widget);
-
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  if (!GTK_WIDGET_DRAWABLE (widget))
-    return FALSE;
-
-  /* exposure events on the sheet */
-  if (event->window == sheet->row_title_window &&
-      sheet->row_titles_visible)
-    {
-      draw_row_title_buttons_range (sheet,
-                                   min_visible_row (sheet),
-                                   max_visible_row (sheet));
-    }
-
-  if (event->window == sheet->column_title_window &&
-      sheet->column_titles_visible)
-    {
-      draw_column_title_buttons_range (sheet,
-                                      min_visible_column (sheet),
-                                      max_visible_column (sheet));
-    }
-
-  if (event->window == sheet->sheet_window)
-    {
-      draw_sheet_region (sheet, event->region);
-
-      if (sheet->select_status != PSPPIRE_SHEET_NORMAL)
-       {
-         GdkRectangle area;
-
-         rectangle_from_range (sheet, &sheet->range, &area);
-             
-         gdk_draw_rectangle (sheet->sheet_window,
-                             sheet->xor_gc,
-                             TRUE,
-                             area.x + 1, area.y + 1,
-                             area.width, area.height);
-       }
-
-
-      if ((!PSPPIRE_SHEET_IN_XDRAG (sheet)) && (!PSPPIRE_SHEET_IN_YDRAG (sheet)))
-       {
-         GdkRectangle rect;
-         PsppireSheetRange range;
-         range.row0 = range.rowi =  sheet->active_cell.row;
-         range.col0 = range.coli =  sheet->active_cell.col;
-
-         rectangle_from_range (sheet, &range, &rect);
-
-         if (GDK_OVERLAP_RECTANGLE_OUT !=
-             gdk_region_rect_in (event->region, &rect))
-           {
-             psppire_sheet_draw_active_cell (sheet);
-           }
-       }
-
-    }
-
-  (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
-
-  return FALSE;
-}
-
-
-static gboolean
-psppire_sheet_button_press (GtkWidget *widget, GdkEventButton *event)
-{
-  PsppireSheet *sheet;
-  GdkModifierType mods;
-  gint x, y;
-  gint  row, column;
-
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  sheet = PSPPIRE_SHEET (widget);
-
-  /* Cancel any pending tooltips */
-  if (sheet->motion_timer)
-    {
-      g_source_remove (sheet->motion_timer);
-      sheet->motion_timer = 0;
-    }
-
-  gtk_widget_get_pointer (widget, &x, &y);
-  psppire_sheet_get_pixel_info (sheet, x, y, &row, &column);
-
-
-  if (event->window == sheet->column_title_window)
-    {
-      sheet->x_drag = event->x;
-      g_signal_emit (sheet,
-                    sheet_signals[BUTTON_EVENT_COLUMN], 0,
-                    column, event);
-
-      if (psppire_sheet_model_get_column_sensitivity (sheet->model, column))
-       {
-         if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
-           g_signal_emit (sheet,
-                          sheet_signals[DOUBLE_CLICK_COLUMN], 0, column);
-       }
-    }
-  
-  if (event->window == sheet->row_title_window)
-    {
-      g_signal_emit (sheet,
-                    sheet_signals[BUTTON_EVENT_ROW], 0,
-                    row, event);
-
-      if (psppire_sheet_model_get_row_sensitivity (sheet->model, row))
-       {
-         if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
-           g_signal_emit (sheet,
-                          sheet_signals[DOUBLE_CLICK_ROW], 0, row);
-       }
-    }
-
-  gdk_window_get_pointer (widget->window, NULL, NULL, &mods);
-
-  if (! (mods & GDK_BUTTON1_MASK)) return TRUE;
-
-
-  /* press on resize windows */
-  if (event->window == sheet->column_title_window)
-    {
-      sheet->x_drag = event->x;
-
-      if (on_column_boundary (sheet, sheet->x_drag, &sheet->drag_cell.col))
-       {
-         PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_XDRAG);
-         gdk_pointer_grab (sheet->column_title_window, FALSE,
-                           GDK_POINTER_MOTION_HINT_MASK |
-                           GDK_BUTTON1_MOTION_MASK |
-                           GDK_BUTTON_RELEASE_MASK,
-                           NULL, NULL, event->time);
-
-         draw_xor_vline (sheet);
-         return TRUE;
-       }
-    }
-
-  if (event->window == sheet->row_title_window)
-    {
-      sheet->y_drag = event->y;
-
-      if (on_row_boundary (sheet, sheet->y_drag, &sheet->drag_cell.row))
-       {
-         PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_YDRAG);
-         gdk_pointer_grab (sheet->row_title_window, FALSE,
-                           GDK_POINTER_MOTION_HINT_MASK |
-                           GDK_BUTTON1_MOTION_MASK |
-                           GDK_BUTTON_RELEASE_MASK,
-                           NULL, NULL, event->time);
-
-         draw_xor_hline (sheet);
-         return TRUE;
-       }
-    }
-
-  /* the sheet itself does not handle other than single click events */
-  if (event->type != GDK_BUTTON_PRESS) return FALSE;
-
-  /* selections on the sheet */
-  if (event->window == sheet->sheet_window)
-    {
-      gtk_widget_get_pointer (widget, &x, &y);
-      psppire_sheet_get_pixel_info (sheet, x, y, &row, &column);
-      gdk_pointer_grab (sheet->sheet_window, FALSE,
-                       GDK_POINTER_MOTION_HINT_MASK |
-                       GDK_BUTTON1_MOTION_MASK |
-                       GDK_BUTTON_RELEASE_MASK,
-                       NULL, NULL, event->time);
-      gtk_grab_add (GTK_WIDGET (sheet));
-
-      if ( sheet->select_status == PSPPIRE_SHEET_NORMAL)
-       {
-         sheet->range.row0 = row;
-         sheet->range.col0 = column;
-       }
-      else
-       {
-         psppire_sheet_unselect_range (sheet);
-       }
-      psppire_sheet_click_cell (sheet, row, column);
-    }
-
-  if (event->window == sheet->column_title_window)
-    {
-      gtk_widget_get_pointer (widget, &x, &y);
-      if ( sheet->row_titles_visible)
-       x -= sheet->row_title_area.width;
-
-      x += sheet->hadjustment->value;
-
-      column = column_from_xpixel (sheet, x);
-
-      if (psppire_sheet_model_get_column_sensitivity (sheet->model, column))
-       {
-         gtk_grab_add (GTK_WIDGET (sheet));
-         PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-       }
-    }
-
-  if (event->window == sheet->row_title_window)
-    {
-      gtk_widget_get_pointer (widget, &x, &y);
-      if ( sheet->column_titles_visible)
-       y -= sheet->column_title_area.height;
-
-      y += sheet->vadjustment->value;
-
-      row = row_from_ypixel (sheet, y);
-      if (psppire_sheet_model_get_row_sensitivity (sheet->model, row))
-       {
-         gtk_grab_add (GTK_WIDGET (sheet));
-         PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-       }
-    }
-
-  return TRUE;
-}
-
-static gboolean
-psppire_sheet_click_cell (PsppireSheet *sheet, gint row, gint column)
-{
-  PsppireSheetCell cell;
-  gboolean forbid_move;
-
-  cell.row = row;
-  cell.col = column;
-
-  if (row >= psppire_axis_unit_count (sheet->vaxis)
-      || column >= psppire_axis_unit_count (sheet->haxis))
-    {
-      return FALSE;
-    }
-
-  g_signal_emit (sheet, sheet_signals[TRAVERSE], 0,
-                &sheet->active_cell,
-                &cell,
-                &forbid_move);
-
-  if (forbid_move)
-    {
-      if (sheet->select_status == PSPPIRE_SHEET_NORMAL)
-       return FALSE;
-
-      row = sheet->active_cell.row;
-      column = sheet->active_cell.col;
-
-      change_active_cell (sheet, row, column);
-      return FALSE;
-    }
-
-  if (row == -1 && column >= 0)
-    {
-      psppire_sheet_select_column (sheet, column);
-      return TRUE;
-    }
-
-  if (column == -1 && row >= 0)
-    {
-      psppire_sheet_select_row (sheet, row);
-      return TRUE;
-    }
-
-  if (row == -1 && column == -1)
-    {
-      sheet->range.row0 = 0;
-      sheet->range.col0 = 0;
-      sheet->range.rowi = psppire_axis_unit_count (sheet->vaxis) - 1;
-      sheet->range.coli = psppire_axis_unit_count (sheet->haxis) - 1;
-      return TRUE;
-    }
-
-  if (sheet->select_status == PSPPIRE_SHEET_NORMAL)
-    change_active_cell (sheet, row, column);
-
-  gtk_widget_grab_focus (GTK_WIDGET (sheet->entry_widget));
-
-  return TRUE;
-}
-
-static gint
-psppire_sheet_button_release (GtkWidget *widget,
-                             GdkEventButton *event)
-{
-  GdkDisplay *display = gtk_widget_get_display (widget);
-
-  PsppireSheet *sheet = PSPPIRE_SHEET (widget);
-
-  /* release on resize windows */
-  if (PSPPIRE_SHEET_IN_XDRAG (sheet))
-    {
-      gint width;
-      PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_XDRAG);
-      PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-
-      gdk_display_pointer_ungrab (display, event->time);
-      draw_xor_vline (sheet);
-
-      width = event->x -
-       psppire_axis_start_pixel (sheet->haxis, sheet->drag_cell.col)
-       + sheet->hadjustment->value;
-
-      set_column_width (sheet, sheet->drag_cell.col, width);
-
-      return TRUE;
-    }
-
-  if (PSPPIRE_SHEET_IN_YDRAG (sheet))
-    {
-      gint height;
-      PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_YDRAG);
-      PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-
-      gdk_display_pointer_ungrab (display, event->time);
-      draw_xor_hline (sheet);
-
-      height = event->y -
-       psppire_axis_start_pixel (sheet->vaxis, sheet->drag_cell.row) +
-       sheet->vadjustment->value;
-
-      set_row_height (sheet, sheet->drag_cell.row, height);
-
-      return TRUE;
-    }
-
-  if (PSPPIRE_SHEET_IN_DRAG (sheet))
-    {
-      PsppireSheetRange old_range;
-      draw_xor_rectangle (sheet, sheet->drag_range);
-      PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_DRAG);
-      gdk_display_pointer_ungrab (display, event->time);
-
-      psppire_sheet_unselect_range (sheet);
-
-      old_range = sheet->range;
-      sheet->range = sheet->drag_range;
-      sheet->drag_range = old_range;
-      g_signal_emit (sheet, sheet_signals[MOVE_RANGE], 0,
-                    &sheet->drag_range, &sheet->range);
-      psppire_sheet_select_range (sheet, &sheet->range);
-    }
-
-  if (PSPPIRE_SHEET_IN_SELECTION (sheet))
-    {
-      PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-      sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED;
-
-      change_active_cell (sheet, sheet->active_cell.row,
-                         sheet->active_cell.col);
-    }
-
-  gdk_display_pointer_ungrab (display, event->time);
-  gtk_grab_remove (GTK_WIDGET (sheet));
-
-  PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-
-  return TRUE;
-}
-
-\f
-
-
-
-/* Shamelessly lifted from gtktooltips */
-static gboolean
-psppire_sheet_subtitle_paint_window (GtkWidget *tip_window)
-{
-  GtkRequisition req;
-
-  gtk_widget_size_request (tip_window, &req);
-  gtk_paint_flat_box (tip_window->style, tip_window->window,
-                     GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-                     NULL, GTK_WIDGET(tip_window), "tooltip",
-                     0, 0, req.width, req.height);
-
-  return FALSE;
-}
-
-static void
-destroy_hover_window (PsppireSheetHoverTitle *h)
-{
-  gtk_widget_destroy (h->window);
-  g_free (h);
-}
-
-static PsppireSheetHoverTitle *
-create_hover_window (void)
-{
-  PsppireSheetHoverTitle *hw = g_malloc (sizeof (*hw));
-
-  hw->window = gtk_window_new (GTK_WINDOW_POPUP);
-
-#if GTK_CHECK_VERSION (2, 9, 0)
-  gtk_window_set_type_hint (GTK_WINDOW (hw->window),
-                           GDK_WINDOW_TYPE_HINT_TOOLTIP);
-#endif
-
-  gtk_widget_set_app_paintable (hw->window, TRUE);
-  gtk_window_set_resizable (GTK_WINDOW (hw->window), FALSE);
-  gtk_widget_set_name (hw->window, "gtk-tooltips");
-  gtk_container_set_border_width (GTK_CONTAINER (hw->window), 4);
-
-  g_signal_connect (hw->window,
-                   "expose_event",
-                   G_CALLBACK (psppire_sheet_subtitle_paint_window),
-                   NULL);
-
-  hw->label = gtk_label_new (NULL);
-
-
-  gtk_label_set_line_wrap (GTK_LABEL (hw->label), TRUE);
-  gtk_misc_set_alignment (GTK_MISC (hw->label), 0.5, 0.5);
-
-  gtk_container_add (GTK_CONTAINER (hw->window), hw->label);
-
-  gtk_widget_show (hw->label);
-
-  g_signal_connect (hw->window,
-                   "destroy",
-                   G_CALLBACK (gtk_widget_destroyed),
-                   &hw->window);
-
-  return hw;
-}
-
-#define HOVER_WINDOW_Y_OFFSET 2
-
-static void
-show_subtitle (PsppireSheet *sheet, gint row, gint column,
-              const gchar *subtitle)
-{
-  gint x, y;
-  gint px, py;
-  gint width;
-
-  if ( ! subtitle )
-    return;
-
-  gtk_label_set_text (GTK_LABEL (sheet->hover_window->label),
-                     subtitle);
-
-
-  sheet->hover_window->row = row;
-  sheet->hover_window->column = column;
-
-  gdk_window_get_origin (GTK_WIDGET (sheet)->window, &x, &y);
-
-  gtk_widget_get_pointer (GTK_WIDGET (sheet), &px, &py);
-
-  gtk_widget_show (sheet->hover_window->window);
-
-  width = GTK_WIDGET (sheet->hover_window->label)->allocation.width;
-
-  if (row == -1 )
-    {
-      x += px;
-      x -= width / 2;
-      y += sheet->column_title_area.y;
-      y += sheet->column_title_area.height;
-      y += HOVER_WINDOW_Y_OFFSET;
-    }
-
-  if ( column == -1 )
-    {
-      y += py;
-      x += sheet->row_title_area.x;
-      x += sheet->row_title_area.width * 2 / 3.0;
-    }
-
-  gtk_window_move (GTK_WINDOW (sheet->hover_window->window),
-                  x, y);
-}
-
-static gboolean
-motion_timeout_callback (gpointer data)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (data);
-  gint x, y;
-  gint row, column;
-
-  gdk_threads_enter ();
-  gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
-
-  if ( psppire_sheet_get_pixel_info (sheet, x, y, &row, &column) )
-    {
-      if (sheet->row_title_under && row >= 0)
-       {
-         gchar *text = psppire_sheet_model_get_row_subtitle (sheet->model, row);
-
-         show_subtitle (sheet, row, -1, text);
-         g_free (text);
-       }
-
-      if (sheet->column_title_under && column >= 0)
-       {
-         gchar *text = psppire_sheet_model_get_column_subtitle (sheet->model,
-                                                                column);
-
-         show_subtitle (sheet, -1, column, text);
-
-         g_free (text);
-       }
-    }
-
-  gdk_threads_leave ();
-  return FALSE;
-}
-
-static gboolean
-psppire_sheet_motion (GtkWidget *widget,  GdkEventMotion *event)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (widget);
-  GdkModifierType mods;
-  GdkCursorType new_cursor;
-  gint x, y;
-  gint row, column;
-  GdkDisplay *display;
-
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  display = gtk_widget_get_display (widget);
-
-  /* selections on the sheet */
-  x = event->x;
-  y = event->y;
-
-  if (!GTK_WIDGET_VISIBLE (sheet->hover_window->window))
-    {
-      if ( sheet->motion_timer > 0 )
-       g_source_remove (sheet->motion_timer);
-      sheet->motion_timer =
-       g_timeout_add (TIMEOUT_HOVER, motion_timeout_callback, sheet);
-    }
-  else
-    {
-      gint row, column;
-      gint wx, wy;
-      gtk_widget_get_pointer (widget, &wx, &wy);
-
-      if ( psppire_sheet_get_pixel_info (sheet, wx, wy, &row, &column) )
-       {
-         if ( row != sheet->hover_window->row ||
-              column != sheet->hover_window->column)
-           {
-             gtk_widget_hide (sheet->hover_window->window);
-           }
-       }
-    }
-
-  if (event->window == sheet->column_title_window)
-    {
-      if (!PSPPIRE_SHEET_IN_SELECTION (sheet) &&
-         on_column_boundary (sheet, x, &column))
-       {
-         new_cursor = GDK_SB_H_DOUBLE_ARROW;
-         if (new_cursor != sheet->cursor_drag->type)
-           {
-             gdk_cursor_unref (sheet->cursor_drag);
-             sheet->cursor_drag =
-               gdk_cursor_new_for_display (display, new_cursor);
-
-             gdk_window_set_cursor (sheet->column_title_window,
-                                    sheet->cursor_drag);
-           }
-       }
-      else
-       {
-         new_cursor = GDK_TOP_LEFT_ARROW;
-         if (!PSPPIRE_SHEET_IN_XDRAG (sheet) &&
-             new_cursor != sheet->cursor_drag->type)
-           {
-             gdk_cursor_unref (sheet->cursor_drag);
-             sheet->cursor_drag =
-               gdk_cursor_new_for_display (display, new_cursor);
-             gdk_window_set_cursor (sheet->column_title_window,
-                                    sheet->cursor_drag);
-           }
-       }
-    }
-  else if (event->window == sheet->row_title_window)
-    {
-      if (!PSPPIRE_SHEET_IN_SELECTION (sheet) &&
-         on_row_boundary (sheet, y, &row))
-       {
-         new_cursor = GDK_SB_V_DOUBLE_ARROW;
-         if (new_cursor != sheet->cursor_drag->type)
-           {
-             gdk_cursor_unref (sheet->cursor_drag);
-             sheet->cursor_drag =
-               gdk_cursor_new_for_display (display, new_cursor);
-             gdk_window_set_cursor (sheet->row_title_window,
-                                    sheet->cursor_drag);
-           }
-       }
-      else
-       {
-         new_cursor = GDK_TOP_LEFT_ARROW;
-         if (!PSPPIRE_SHEET_IN_YDRAG (sheet) &&
-             new_cursor != sheet->cursor_drag->type)
-           {
-             gdk_cursor_unref (sheet->cursor_drag);
-             sheet->cursor_drag =
-               gdk_cursor_new_for_display (display, new_cursor);
-             gdk_window_set_cursor (sheet->row_title_window,
-                                    sheet->cursor_drag);
-           }
-       }
-    }
-
-  new_cursor = GDK_PLUS;
-  if ( event->window == sheet->sheet_window &&
-       !POSSIBLE_DRAG (sheet, x, y, &row, &column) &&
-       !PSPPIRE_SHEET_IN_DRAG (sheet) &&
-       !POSSIBLE_RESIZE (sheet, x, y, &row, &column) &&
-       new_cursor != sheet->cursor_drag->type)
-    {
-      gdk_cursor_unref (sheet->cursor_drag);
-      sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_PLUS);
-      gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
-    }
-
-  new_cursor = GDK_TOP_LEFT_ARROW;
-  if ( event->window == sheet->sheet_window &&
-       ! (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ) &&
-       (POSSIBLE_DRAG (sheet, x, y, &row, &column) ||
-       PSPPIRE_SHEET_IN_DRAG (sheet)) &&
-       new_cursor != sheet->cursor_drag->type)
-    {
-      gdk_cursor_unref (sheet->cursor_drag);
-      sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_TOP_LEFT_ARROW);
-      gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
-    }
-
-  gdk_window_get_pointer (widget->window, &x, &y, &mods);
-  if (! (mods & GDK_BUTTON1_MASK)) return FALSE;
-
-  if (PSPPIRE_SHEET_IN_XDRAG (sheet))
-    {
-      if (event->x != sheet->x_drag)
-       {
-         draw_xor_vline (sheet);
-         sheet->x_drag = event->x;
-         draw_xor_vline (sheet);
-       }
-
-      return TRUE;
-    }
-
-  if (PSPPIRE_SHEET_IN_YDRAG (sheet))
-    {
-      if (event->y != sheet->y_drag)
-       {
-         draw_xor_hline (sheet);
-         sheet->y_drag = event->y;
-         draw_xor_hline (sheet);
-       }
-
-      return TRUE;
-    }
-
-  if (PSPPIRE_SHEET_IN_DRAG (sheet))
-    {
-      PsppireSheetRange aux;
-      column = column_from_xpixel (sheet, x)- sheet->drag_cell.col;
-      row = row_from_ypixel (sheet, y) - sheet->drag_cell.row;
-      if (sheet->select_status == PSPPIRE_SHEET_COLUMN_SELECTED) row = 0;
-      if (sheet->select_status == PSPPIRE_SHEET_ROW_SELECTED) column = 0;
-      sheet->x_drag = x;
-      sheet->y_drag = y;
-      aux = sheet->range;
-      if (aux.row0 + row >= 0 && aux.rowi + row < psppire_axis_unit_count (sheet->vaxis) &&
-         aux.col0 + column >= 0 && aux.coli + column < psppire_axis_unit_count (sheet->haxis))
-       {
-         aux = sheet->drag_range;
-         sheet->drag_range.row0 = sheet->range.row0 + row;
-         sheet->drag_range.col0 = sheet->range.col0 + column;
-         sheet->drag_range.rowi = sheet->range.rowi + row;
-         sheet->drag_range.coli = sheet->range.coli + column;
-         if (aux.row0 != sheet->drag_range.row0 ||
-             aux.col0 != sheet->drag_range.col0)
-           {
-             draw_xor_rectangle (sheet, aux);
-             draw_xor_rectangle (sheet, sheet->drag_range);
-           }
-       }
-      return TRUE;
-    }
-
-  psppire_sheet_get_pixel_info (sheet, x, y, &row, &column);
-
-  if (sheet->select_status == PSPPIRE_SHEET_NORMAL && row == sheet->active_cell.row &&
-      column == sheet->active_cell.col) return TRUE;
-
-  if ( mods & GDK_BUTTON1_MASK)
-    {
-      if (PSPPIRE_SHEET_IN_SELECTION (sheet) )
-       {
-         /* Redraw the old range */
-         psppire_sheet_unselect_range (sheet);
-
-         sheet->range.rowi = row;
-         sheet->range.coli = column;
-
-         /* Redraw the new range */
-         psppire_sheet_select_range (sheet, &sheet->range);
-       }
-      else
-       {
-         PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-       }
-    }
-
-  return TRUE;
-}
-
-static gboolean
-psppire_sheet_crossing_notify (GtkWidget *widget,
-                              GdkEventCrossing *event)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (widget);
-
-  if (event->window == sheet->column_title_window)
-    sheet->column_title_under = event->type == GDK_ENTER_NOTIFY;
-  else if (event->window == sheet->row_title_window)
-    sheet->row_title_under = event->type == GDK_ENTER_NOTIFY;
-
-  if (event->type == GDK_LEAVE_NOTIFY)
-    gtk_widget_hide (sheet->hover_window->window);
-
-  return TRUE;
-}
-
-
-static gboolean
-psppire_sheet_focus_in (GtkWidget     *w,
-                       GdkEventFocus *event)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (w);
-
-  gtk_widget_grab_focus (sheet->entry_widget);
-
-  return TRUE;
-}
-
-
-
-static gint
-psppire_sheet_entry_key_press (GtkWidget *widget,
-                              GdkEventKey *key)
-{
-  gboolean focus;
-  g_signal_emit_by_name (widget, "key_press_event", key, &focus);
-  return focus;
-}
-
-
-/* Number of rows in a step-increment */
-#define ROWS_PER_STEP 1
-
-
-static void
-page_vertical (PsppireSheet *sheet, GtkScrollType dir)
-{
-  gint old_row = sheet->active_cell.row ;
-  glong vpixel = psppire_axis_start_pixel (sheet->vaxis, old_row);
-
-  gint new_row;
-
-  vpixel -= psppire_axis_start_pixel (sheet->vaxis,
-                                     min_visible_row (sheet));
-
-  switch ( dir)
-    {
-    case GTK_SCROLL_PAGE_DOWN:
-      gtk_adjustment_set_value (sheet->vadjustment,
-                               sheet->vadjustment->value +
-                               sheet->vadjustment->page_increment);
-      break;
-    case GTK_SCROLL_PAGE_UP:
-      gtk_adjustment_set_value (sheet->vadjustment,
-                               sheet->vadjustment->value -
-                               sheet->vadjustment->page_increment);
-
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-
-
-  vpixel += psppire_axis_start_pixel (sheet->vaxis,
-                                     min_visible_row (sheet));
-
-  new_row =  row_from_ypixel (sheet, vpixel);
-
-  change_active_cell (sheet, new_row,
-                     sheet->active_cell.col);
-}
-
-
-static void
-step_sheet (PsppireSheet *sheet, GtkScrollType dir)
-{
-  gint current_row = sheet->active_cell.row;
-  gint current_col = sheet->active_cell.col;
-  PsppireSheetCell new_cell ;
-  gboolean forbidden = FALSE;
-
-  new_cell.row = current_row;
-  new_cell.col = current_col;
-
-  switch ( dir)
-    {
-    case GTK_SCROLL_STEP_DOWN:
-      new_cell.row++;
-      break;
-    case GTK_SCROLL_STEP_UP:
-      new_cell.row--;
-      break;
-    case GTK_SCROLL_STEP_RIGHT:
-      new_cell.col++;
-      break;
-    case GTK_SCROLL_STEP_LEFT:
-      new_cell.col--;
-      break;
-    case GTK_SCROLL_STEP_FORWARD:
-      new_cell.col++;
-      if (new_cell.col >=
-         psppire_sheet_model_get_column_count (sheet->model))
-       {
-         new_cell.col = 0;
-         new_cell.row++;
-       }
-      break;
-    case GTK_SCROLL_STEP_BACKWARD:
-      new_cell.col--;
-      if (new_cell.col < 0)
-       {
-         new_cell.col =
-           psppire_sheet_model_get_column_count (sheet->model) - 1;
-         new_cell.row--;
-       }
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-
-  g_signal_emit (sheet, sheet_signals[TRAVERSE], 0,
-                &sheet->active_cell,
-                &new_cell,
-                &forbidden);
-
-  if (forbidden)
-    return;
-
-
-  maximize_int (&new_cell.row, 0);
-  maximize_int (&new_cell.col, 0);
-
-  minimize_int (&new_cell.row,
-               psppire_axis_unit_count (sheet->vaxis) - 1);
-
-  minimize_int (&new_cell.col,
-               psppire_axis_unit_count (sheet->haxis) - 1);
-
-  change_active_cell (sheet, new_cell.row, new_cell.col);
-
-
-  if ( new_cell.col > max_fully_visible_column (sheet))
-    {
-      glong hpos  =
-       psppire_axis_start_pixel (sheet->haxis,
-                                 new_cell.col + 1);
-      hpos -= sheet->hadjustment->page_size;
-
-      gtk_adjustment_set_value (sheet->hadjustment,
-                               hpos);
-    }
-  else if ( new_cell.col < min_fully_visible_column (sheet))
-    {
-      glong hpos  =
-       psppire_axis_start_pixel (sheet->haxis,
-                                 new_cell.col);
-
-      gtk_adjustment_set_value (sheet->hadjustment,
-                               hpos);
-    }
-
-
-  if ( new_cell.row > max_fully_visible_row (sheet))
-    {
-      glong vpos  =
-       psppire_axis_start_pixel (sheet->vaxis,
-                                 new_cell.row + 1);
-      vpos -= sheet->vadjustment->page_size;
-
-      gtk_adjustment_set_value (sheet->vadjustment,
-                               vpos);
-    }
-  else if ( new_cell.row < min_fully_visible_row (sheet))
-    {
-      glong vpos  =
-       psppire_axis_start_pixel (sheet->vaxis,
-                                 new_cell.row);
-
-      gtk_adjustment_set_value (sheet->vadjustment,
-                               vpos);
-    }
-
-  gtk_widget_grab_focus (GTK_WIDGET (sheet->entry_widget));
-}
-
-
-static gboolean
-psppire_sheet_key_press (GtkWidget *widget,
-                        GdkEventKey *key)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (widget);
-
-  PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-
-  switch (key->keyval)
-    {
-    case GDK_Tab:
-      step_sheet (sheet, GTK_SCROLL_STEP_FORWARD);
-      break;
-    case GDK_Right:
-      step_sheet (sheet, GTK_SCROLL_STEP_RIGHT);
-      break;
-    case GDK_ISO_Left_Tab:
-      step_sheet (sheet, GTK_SCROLL_STEP_BACKWARD);
-      break;
-    case GDK_Left:
-      step_sheet (sheet, GTK_SCROLL_STEP_LEFT);
-      break;
-    case GDK_Return:
-    case GDK_Down:
-      step_sheet (sheet, GTK_SCROLL_STEP_DOWN);
-      break;
-    case GDK_Up:
-      step_sheet (sheet, GTK_SCROLL_STEP_UP);
-      break;
-
-    case GDK_Page_Down:
-      page_vertical (sheet, GTK_SCROLL_PAGE_DOWN);
-      break;
-    case GDK_Page_Up:
-      page_vertical (sheet, GTK_SCROLL_PAGE_UP);
-      break;
-
-    case GDK_Home:
-      gtk_adjustment_set_value (sheet->vadjustment,
-                               sheet->vadjustment->lower);
-
-      change_active_cell (sheet,  0,
-                         sheet->active_cell.col);
-
-      break;
-
-    case GDK_End:
-      gtk_adjustment_set_value (sheet->vadjustment,
-                               sheet->vadjustment->upper -
-                               sheet->vadjustment->page_size -
-                               sheet->vadjustment->page_increment);
-
-      /*
-       change_active_cellx (sheet,
-       psppire_axis_unit_count (sheet->vaxis) - 1,
-       sheet->active_cell.col);
-      */
-      break;
-    case GDK_Delete:
-      psppire_sheet_real_cell_clear (sheet, sheet->active_cell.row, sheet->active_cell.col);
-      break;
-    default:
-      return FALSE;
-      break;
-    }
-
-  return TRUE;
-}
-
-static void
-psppire_sheet_size_request (GtkWidget *widget,
-                           GtkRequisition *requisition)
-{
-  PsppireSheet *sheet;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (widget));
-  g_return_if_fail (requisition != NULL);
-
-  sheet = PSPPIRE_SHEET (widget);
-
-  requisition->width = 3 * DEFAULT_COLUMN_WIDTH;
-  requisition->height = 3 * DEFAULT_ROW_HEIGHT;
-
-  /* compute the size of the column title area */
-  if (sheet->column_titles_visible)
-    requisition->height += sheet->column_title_area.height;
-
-  /* compute the size of the row title area */
-  if (sheet->row_titles_visible)
-    requisition->width += sheet->row_title_area.width;
-}
-
-
-static void
-psppire_sheet_size_allocate (GtkWidget *widget,
-                            GtkAllocation *allocation)
-{
-  PsppireSheet *sheet;
-  GtkAllocation sheet_allocation;
-  gint border_width;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (widget));
-  g_return_if_fail (allocation != NULL);
-
-  sheet = PSPPIRE_SHEET (widget);
-  widget->allocation = *allocation;
-  border_width = GTK_CONTAINER (widget)->border_width;
-
-  if (GTK_WIDGET_REALIZED (widget))
-    gdk_window_move_resize (widget->window,
-                           allocation->x + border_width,
-                           allocation->y + border_width,
-                           allocation->width - 2 * border_width,
-                           allocation->height - 2 * border_width);
-
-  sheet_allocation.x = 0;
-  sheet_allocation.y = 0;
-  sheet_allocation.width = allocation->width - 2 * border_width;
-  sheet_allocation.height = allocation->height - 2 * border_width;
-
-  if (GTK_WIDGET_REALIZED (widget))
-    gdk_window_move_resize (sheet->sheet_window,
-                           sheet_allocation.x,
-                           sheet_allocation.y,
-                           sheet_allocation.width,
-                           sheet_allocation.height);
-
-  /* position the window which holds the column title buttons */
-  sheet->column_title_area.x = 0;
-  sheet->column_title_area.y = 0;
-  sheet->column_title_area.width = sheet_allocation.width ;
-
-
-  /* position the window which holds the row title buttons */
-  sheet->row_title_area.x = 0;
-  sheet->row_title_area.y = 0;
-  sheet->row_title_area.height = sheet_allocation.height;
-
-  if (sheet->row_titles_visible)
-    sheet->column_title_area.x += sheet->row_title_area.width;
-
-  if (sheet->column_titles_visible)
-    sheet->row_title_area.y += sheet->column_title_area.height;
-
-  if (GTK_WIDGET_REALIZED (widget) && sheet->column_titles_visible)
-    gdk_window_move_resize (sheet->column_title_window,
-                           sheet->column_title_area.x,
-                           sheet->column_title_area.y,
-                           sheet->column_title_area.width,
-                           sheet->column_title_area.height);
-
-
-  if (GTK_WIDGET_REALIZED (widget) && sheet->row_titles_visible)
-    gdk_window_move_resize (sheet->row_title_window,
-                           sheet->row_title_area.x,
-                           sheet->row_title_area.y,
-                           sheet->row_title_area.width,
-                           sheet->row_title_area.height);
-
-  size_allocate_global_button (sheet);
-
-  if (sheet->haxis)
-    {
-      gint width = sheet->column_title_area.width;
-
-      if ( sheet->row_titles_visible)
-       width -= sheet->row_title_area.width;
-
-      g_object_set (sheet->haxis,
-                   "minimum-extent", width,
-                   NULL);
-    }
-
-
-  if (sheet->vaxis)
-    {
-      gint height = sheet->row_title_area.height;
-
-      if ( sheet->column_titles_visible)
-       height -= sheet->column_title_area.height;
-
-      g_object_set (sheet->vaxis,
-                   "minimum-extent", height,
-                   NULL);
-    }
-
-
-  /* set the scrollbars adjustments */
-  adjust_scrollbars (sheet);
-}
-
-static void
-draw_column_title_buttons (PsppireSheet *sheet)
-{
-  gint x, width;
-
-  if (!sheet->column_titles_visible) return;
-  if (!GTK_WIDGET_REALIZED (sheet))
-    return;
-
-  gdk_drawable_get_size (sheet->sheet_window, &width, NULL);
-  x = 0;
-
-  if (sheet->row_titles_visible)
-    {
-      x = sheet->row_title_area.width;
-    }
-
-  if (sheet->column_title_area.width != width || sheet->column_title_area.x != x)
-    {
-      sheet->column_title_area.width = width;
-      sheet->column_title_area.x = x;
-      gdk_window_move_resize (sheet->column_title_window,
-                             sheet->column_title_area.x,
-                             sheet->column_title_area.y,
-                             sheet->column_title_area.width,
-                             sheet->column_title_area.height);
-    }
-
-  if (max_visible_column (sheet) ==
-      psppire_axis_unit_count (sheet->haxis) - 1)
-    gdk_window_clear_area (sheet->column_title_window,
-                          0, 0,
-                          sheet->column_title_area.width,
-                          sheet->column_title_area.height);
-
-  if (!GTK_WIDGET_DRAWABLE (sheet)) return;
-
-  draw_column_title_buttons_range (sheet, min_visible_column (sheet), 
-                                  max_visible_column (sheet));
-}
-
-static void
-draw_row_title_buttons (PsppireSheet *sheet)
-{
-  gint y = 0;
-  gint height;
-
-  if (!sheet->row_titles_visible) return;
-  if (!GTK_WIDGET_REALIZED (sheet))
-    return;
-
-  gdk_drawable_get_size (sheet->sheet_window, NULL, &height);
-
-  if (sheet->column_titles_visible)
-    {
-      y = sheet->column_title_area.height;
-    }
-
-  if (sheet->row_title_area.height != height || sheet->row_title_area.y != y)
-    {
-      sheet->row_title_area.y = y;
-      sheet->row_title_area.height = height;
-      gdk_window_move_resize (sheet->row_title_window,
-                             sheet->row_title_area.x,
-                             sheet->row_title_area.y,
-                             sheet->row_title_area.width,
-                             sheet->row_title_area.height);
-    }
-
-  if (max_visible_row (sheet) == psppire_axis_unit_count (sheet->vaxis) - 1)
-    gdk_window_clear_area (sheet->row_title_window,
-                          0, 0,
-                          sheet->row_title_area.width,
-                          sheet->row_title_area.height);
-
-  if (!GTK_WIDGET_DRAWABLE (sheet)) return;
-
-  draw_row_title_buttons_range (sheet, min_visible_row (sheet),
-                               max_visible_row (sheet));
-}
-
-
-static void
-psppire_sheet_size_allocate_entry (PsppireSheet *sheet)
-{
-  GtkAllocation entry_alloc;
-  PsppireSheetCellAttr attributes = { 0 };
-  GtkEntry *sheet_entry;
-
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
-  if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
-
-  sheet_entry = psppire_sheet_get_entry (sheet);
-
-  if ( ! psppire_sheet_get_attributes (sheet, sheet->active_cell.row,
-                                      sheet->active_cell.col,
-                                      &attributes) )
-    return ;
-
-  if ( GTK_WIDGET_REALIZED (sheet->entry_widget) )
-    {
-      GtkStyle *style = GTK_WIDGET (sheet_entry)->style;
-
-      style->bg[GTK_STATE_NORMAL] = attributes.background;
-      style->fg[GTK_STATE_NORMAL] = attributes.foreground;
-      style->text[GTK_STATE_NORMAL] = attributes.foreground;
-      style->bg[GTK_STATE_ACTIVE] = attributes.background;
-      style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
-      style->text[GTK_STATE_ACTIVE] = attributes.foreground;
-    }
-
-  rectangle_from_cell (sheet, sheet->active_cell.row,
-                      sheet->active_cell.col, &entry_alloc);
-
-  entry_alloc.x += sheet->cell_padding->left;
-  entry_alloc.y += sheet->cell_padding->right;
-  entry_alloc.width -= sheet->cell_padding->left + sheet->cell_padding->right;
-  entry_alloc.height -= sheet->cell_padding->top + sheet->cell_padding->bottom;
-
-
-  gtk_widget_set_size_request (sheet->entry_widget, entry_alloc.width,
-                              entry_alloc.height);
-  gtk_widget_size_allocate (sheet->entry_widget, &entry_alloc);
-}
-
-
-/* Copy the sheet's font to the entry widget */
-static void
-set_entry_widget_font (PsppireSheet *sheet)
-{
-  GtkRcStyle *style = gtk_widget_get_modifier_style (sheet->entry_widget);
-
-  pango_font_description_free (style->font_desc);
-  style->font_desc = pango_font_description_copy (GTK_WIDGET (sheet)->style->font_desc);
-
-  gtk_widget_modify_style (sheet->entry_widget, style);
-}
-
-static void
-create_sheet_entry (PsppireSheet *sheet)
-{
-  if (sheet->entry_widget)
-    {
-      gtk_widget_unparent (sheet->entry_widget);
-    }
-
-  sheet->entry_widget = g_object_new (sheet->entry_type, NULL);
-  g_object_ref_sink (sheet->entry_widget);
-
-  gtk_widget_size_request (sheet->entry_widget, NULL);
-
-  if ( GTK_IS_ENTRY (sheet->entry_widget))
-    {
-      g_object_set (sheet->entry_widget,
-                   "has-frame", FALSE,
-                   NULL);
-    }
-
-  if (GTK_WIDGET_REALIZED (sheet))
-    {
-      gtk_widget_set_parent_window (sheet->entry_widget, sheet->sheet_window);
-      gtk_widget_set_parent (sheet->entry_widget, GTK_WIDGET (sheet));
-      gtk_widget_realize (sheet->entry_widget);
-    }
-
-  g_signal_connect_swapped (sheet->entry_widget, "key_press_event",
-                           G_CALLBACK (psppire_sheet_entry_key_press),
-                           sheet);
-
-  set_entry_widget_font (sheet);
-
-  gtk_widget_show (sheet->entry_widget);
-}
-
-
-/* Finds the last child widget that happens to be of type GtkEntry */
-static void
-find_entry (GtkWidget *w, gpointer user_data)
-{
-  GtkWidget **entry = user_data;
-  if ( GTK_IS_ENTRY (w))
-    {
-      *entry = w;
-    }
-}
-
-
-GtkEntry *
-psppire_sheet_get_entry (PsppireSheet *sheet)
-{
-  GtkWidget *w = sheet->entry_widget;
-
-  g_return_val_if_fail (sheet != NULL, NULL);
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), NULL);
-  g_return_val_if_fail (sheet->entry_widget != NULL, NULL);
-
-  while (! GTK_IS_ENTRY (w))
-    {
-      GtkWidget *entry = NULL;
-
-      if (GTK_IS_CONTAINER (w))
-       {
-         gtk_container_forall (GTK_CONTAINER (w), find_entry, &entry);
-
-         if (NULL == entry)
-           break;
-
-         w = entry;
-       }
-    }
-
-  return GTK_ENTRY (w);
-}
-
-
-static void
-draw_button (PsppireSheet *sheet, GdkWindow *window,
-            PsppireSheetButton *button, gboolean is_sensitive,
-            GdkRectangle allocation)
-{
-  GtkShadowType shadow_type;
-  gint text_width = 0, text_height = 0;
-  PangoAlignment align = PANGO_ALIGN_LEFT;
-
-  gboolean rtl ;
-
-  gint state = 0;
-
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (button != NULL);
-
-
-  rtl = gtk_widget_get_direction (GTK_WIDGET (sheet)) == GTK_TEXT_DIR_RTL;
-
-  gdk_window_clear_area (window,
-                        allocation.x, allocation.y,
-                        allocation.width, allocation.height);
-
-  gtk_widget_ensure_style (sheet->button);
-
-  gtk_paint_box (sheet->button->style, window,
-                GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-                &allocation,
-                GTK_WIDGET (sheet->button),
-                NULL,
-                allocation.x, allocation.y,
-                allocation.width, allocation.height);
-
-  state = button->state;
-  if (!is_sensitive) state = GTK_STATE_INSENSITIVE;
-
-  if (state == GTK_STATE_ACTIVE)
-    shadow_type = GTK_SHADOW_IN;
-  else
-    shadow_type = GTK_SHADOW_OUT;
-
-  if (state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
-    gtk_paint_box (sheet->button->style, window,
-                  button->state, shadow_type,
-                  &allocation, GTK_WIDGET (sheet->button),
-                  NULL,
-                  allocation.x, allocation.y,
-                  allocation.width, allocation.height);
-
-  if ( button->overstruck)
-    {
-      GdkPoint points[2] = {
-       {allocation.x,  allocation.y},
-       {allocation.x + allocation.width,
-        allocation.y + allocation.height}
-      };
-
-      gtk_paint_polygon (sheet->button->style,
-                        window,
-                        button->state,
-                        shadow_type,
-                        NULL,
-                        GTK_WIDGET (sheet),
-                        NULL,
-                        points,
-                        2,
-                        TRUE);
-    }
-
-  if (button->label_visible)
-    {
-      text_height = DEFAULT_ROW_HEIGHT -
-       2 * COLUMN_TITLES_HEIGHT;
-
-      gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
-                                &allocation);
-      gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc,
-                                &allocation);
-
-      allocation.y += 2 * sheet->button->style->ythickness;
-
-      if (button->label && strlen (button->label) > 0)
-       {
-         PangoRectangle rect;
-         gchar *line = button->label;
-
-         PangoLayout *layout = NULL;
-         gint real_x = allocation.x;
-         gint real_y = allocation.y;
-
-         layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), line);
-         pango_layout_get_extents (layout, NULL, &rect);
-
-         text_width = PANGO_PIXELS (rect.width);
-         switch (button->justification)
-           {
-           case GTK_JUSTIFY_LEFT:
-             real_x = allocation.x + COLUMN_TITLES_HEIGHT;
-             align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
-             break;
-           case GTK_JUSTIFY_RIGHT:
-             real_x = allocation.x + allocation.width - text_width - COLUMN_TITLES_HEIGHT;
-             align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
-             break;
-           case GTK_JUSTIFY_CENTER:
-           default:
-             real_x = allocation.x + (allocation.width - text_width)/2;
-             align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
-             pango_layout_set_justify (layout, TRUE);
-           }
-         pango_layout_set_alignment (layout, align);
-         gtk_paint_layout (GTK_WIDGET (sheet)->style,
-                           window,
-                           state,
-                           FALSE,
-                           &allocation,
-                           GTK_WIDGET (sheet),
-                           "label",
-                           real_x, real_y,
-                           layout);
-         g_object_unref (layout);
-       }
-
-      gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
-                                NULL);
-      gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, NULL);
-
-    }
-
-  psppire_sheet_button_free (button);
-}
-
-
-/* Draw the column title buttons FIRST through to LAST */
-static void
-draw_column_title_buttons_range (PsppireSheet *sheet, gint first, gint last)
-{
-  GdkRectangle rect;
-  gint col;
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
-
-  if (!sheet->column_titles_visible) return;
-
-  g_return_if_fail (first >= min_visible_column (sheet));
-  g_return_if_fail (last <= max_visible_column (sheet));
-
-  rect.y = 0;
-  rect.height = sheet->column_title_area.height;
-  rect.x = psppire_axis_start_pixel (sheet->haxis, first) + CELL_SPACING;
-  rect.width = psppire_axis_start_pixel (sheet->haxis, last) + CELL_SPACING
-    + psppire_axis_unit_size (sheet->haxis, last);
-
-  rect.x -= sheet->hadjustment->value;
-
-  minimize_int (&rect.width, sheet->column_title_area.width);
-  maximize_int (&rect.x, 0);
-
-  gdk_window_begin_paint_rect (sheet->column_title_window, &rect);
-
-  for (col = first ; col <= last ; ++col)
-    {
-      GdkRectangle allocation;
-      gboolean is_sensitive = FALSE;
-
-      PsppireSheetButton *
-       button = psppire_sheet_model_get_column_button (sheet->model, col);
-      allocation.y = 0;
-      allocation.x = psppire_axis_start_pixel (sheet->haxis, col)
-       + CELL_SPACING;
-      allocation.x -= sheet->hadjustment->value;
-
-      allocation.height = sheet->column_title_area.height;
-      allocation.width = psppire_axis_unit_size (sheet->haxis, col);
-      is_sensitive = psppire_sheet_model_get_column_sensitivity (sheet->model, col);
-
-      draw_button (sheet, sheet->column_title_window,
-                  button, is_sensitive, allocation);
-    }
-
-  gdk_window_end_paint (sheet->column_title_window);
-}
-
-
-static void
-draw_row_title_buttons_range (PsppireSheet *sheet, gint first, gint last)
-{
-  GdkRectangle rect;
-  gint row;
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
-
-  if (!sheet->row_titles_visible) return;
-
-  g_return_if_fail (first >= min_visible_row (sheet));
-  g_return_if_fail (last <= max_visible_row (sheet));
-
-  rect.x = 0;
-  rect.width = sheet->row_title_area.width;
-  rect.y = psppire_axis_start_pixel (sheet->vaxis, first) + CELL_SPACING;
-  rect.height = psppire_axis_start_pixel (sheet->vaxis, last) + CELL_SPACING
-    + psppire_axis_unit_size (sheet->vaxis, last);
-
-  rect.y -= sheet->vadjustment->value;
-
-  minimize_int (&rect.height, sheet->row_title_area.height);
-  maximize_int (&rect.y, 0);
-
-  gdk_window_begin_paint_rect (sheet->row_title_window, &rect);
-  for (row = first; row <= last; ++row)
-    {
-      GdkRectangle allocation;
-
-      gboolean is_sensitive = FALSE;
-
-      PsppireSheetButton *button =
-       psppire_sheet_model_get_row_button (sheet->model, row);
-      allocation.x = 0;
-      allocation.y = psppire_axis_start_pixel (sheet->vaxis, row)
-       + CELL_SPACING;
-      allocation.y -= sheet->vadjustment->value;
-
-      allocation.width = sheet->row_title_area.width;
-      allocation.height = psppire_axis_unit_size (sheet->vaxis, row);
-      is_sensitive = psppire_sheet_model_get_row_sensitivity (sheet->model, row);
-
-      draw_button (sheet, sheet->row_title_window,
-                  button, is_sensitive, allocation);
-    }
-
-  gdk_window_end_paint (sheet->row_title_window);
-}
-
-/* SCROLLBARS
- *
- * functions:
- * adjust_scrollbars
- * vadjustment_value_changed
- * hadjustment_value_changed */
-
-
-static void
-update_adjustment (GtkAdjustment *adj, PsppireAxis *axis, gint page_size)
-{
-  double position =
-    (adj->value + adj->page_size)
-    /
-    (adj->upper - adj->lower);
-
-  const glong last_item = psppire_axis_unit_count (axis) - 1;
-
-  if (isnan (position) || position < 0)
-    position = 0;
-
-  adj->upper =
-    psppire_axis_start_pixel (axis, last_item)
-    +
-    psppire_axis_unit_size (axis, last_item)
-    ;
-
-  adj->lower = 0;
-  adj->page_size = page_size;
-
-#if 0
-  adj->value = position * (adj->upper - adj->lower) - adj->page_size;
-
-  if ( adj->value < adj->lower)
-    adj->value = adj->lower;
-#endif
-
-  gtk_adjustment_changed (adj);
-}
-
-
-static void
-adjust_scrollbars (PsppireSheet *sheet)
-{
-  gint width, height;
-
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    return;
-
-  gdk_drawable_get_size (sheet->sheet_window, &width, &height);
-
-  if ( sheet->row_titles_visible)
-    width -= sheet->row_title_area.width;
-
-  if (sheet->column_titles_visible)
-    height -= sheet->column_title_area.height;
-
-  if (sheet->vadjustment)
-    {
-      glong last_row = psppire_axis_unit_count (sheet->vaxis) - 1;
-
-      sheet->vadjustment->step_increment =
-       ROWS_PER_STEP *
-       psppire_axis_unit_size (sheet->vaxis, last_row);
-
-      sheet->vadjustment->page_increment =
-       height -
-       sheet->column_title_area.height -
-       psppire_axis_unit_size (sheet->vaxis, last_row);
-
-      update_adjustment (sheet->vadjustment, sheet->vaxis, height);
-    }
-
-  if (sheet->hadjustment)
-    {
-      gint last_col = psppire_axis_unit_count (sheet->haxis) - 1;
-      sheet->hadjustment->step_increment = 1;
-
-      sheet->hadjustment->page_increment = width;
-
-      sheet->hadjustment->upper =
-       psppire_axis_start_pixel (sheet->haxis, last_col)
-       +
-       psppire_axis_unit_size (sheet->haxis, last_col)
-       ;
-
-      update_adjustment (sheet->hadjustment, sheet->haxis, width);
-    }
-}
-
-/* Subtracts the region of WIDGET from REGION */
-static void
-subtract_widget_region (GdkRegion *region, GtkWidget *widget)
-{
-  GdkRectangle rect;
-  GdkRectangle intersect;
-  GdkRegion *region2;
-
-  gdk_region_get_clipbox (region, &rect);
-  gtk_widget_intersect (widget,
-                       &rect,
-                       &intersect);
-
-  region2 = gdk_region_rectangle (&intersect);
-  gdk_region_subtract (region, region2);
-  gdk_region_destroy (region2);
-}
-
-static void
-vadjustment_value_changed (GtkAdjustment *adjustment,
-                          gpointer data)
-{
-  GdkRegion *region;
-  PsppireSheet *sheet = PSPPIRE_SHEET (data);
-
-  g_return_if_fail (adjustment != NULL);
-
-  if ( ! GTK_WIDGET_REALIZED (sheet)) return;
-
-  gtk_widget_hide (sheet->entry_widget);
-
-  region =
-    gdk_drawable_get_visible_region (GDK_DRAWABLE (sheet->sheet_window));
-
-  subtract_widget_region (region, sheet->button);
-  gdk_window_begin_paint_region (sheet->sheet_window, region);
-
-  draw_sheet_region (sheet, region);
-
-  draw_row_title_buttons (sheet);
-  psppire_sheet_draw_active_cell (sheet);
-
-  gdk_window_end_paint (sheet->sheet_window);
-  gdk_region_destroy (region);
-}
-
-
-static void
-hadjustment_value_changed (GtkAdjustment *adjustment,
-                          gpointer data)
-{
-  GdkRegion *region;
-  PsppireSheet *sheet = PSPPIRE_SHEET (data);
-
-  g_return_if_fail (adjustment != NULL);
-
-  if ( ! GTK_WIDGET_REALIZED (sheet)) return;
-
-  gtk_widget_hide (sheet->entry_widget);
-
-
-  region =
-    gdk_drawable_get_visible_region (GDK_DRAWABLE (sheet->sheet_window));
-
-  subtract_widget_region (region, sheet->button);
-  gdk_window_begin_paint_region (sheet->sheet_window, region);
-
-  draw_sheet_region (sheet, region);
-
-  draw_column_title_buttons (sheet);
-
-  psppire_sheet_draw_active_cell (sheet);
-
-  gdk_window_end_paint (sheet->sheet_window);
-
-  gdk_region_destroy (region);
-}
-
-
-/* COLUMN RESIZING */
-static void
-draw_xor_vline (PsppireSheet *sheet)
-{
-  gint height;
-  gint xpos = sheet->x_drag;
-  gdk_drawable_get_size (sheet->sheet_window,
-                        NULL, &height);
-
-  if (sheet->row_titles_visible)
-    xpos += sheet->row_title_area.width;
-
-  gdk_draw_line (GTK_WIDGET (sheet)->window, sheet->xor_gc,
-                xpos,
-                sheet->column_title_area.height,
-                xpos,
-                height + CELL_SPACING);
-}
-
-/* ROW RESIZING */
-static void
-draw_xor_hline (PsppireSheet *sheet)
-
-{
-  gint width;
-  gint ypos = sheet->y_drag;
-
-  gdk_drawable_get_size (sheet->sheet_window,
-                        &width, NULL);
-
-
-  if (sheet->column_titles_visible)
-    ypos += sheet->column_title_area.height;
-
-  gdk_draw_line (GTK_WIDGET (sheet)->window, sheet->xor_gc,
-                sheet->row_title_area.width,
-                ypos,
-                width + CELL_SPACING,
-                ypos);
-}
-
-/* SELECTED RANGE */
-static void
-draw_xor_rectangle (PsppireSheet *sheet, PsppireSheetRange range)
-{
-  gint i = 0;
-  GdkRectangle clip_area, area;
-  GdkGCValues values;
-
-  area.x = psppire_axis_start_pixel (sheet->haxis, range.col0);
-  area.y = psppire_axis_start_pixel (sheet->vaxis, range.row0);
-  area.width = psppire_axis_start_pixel (sheet->haxis, range.coli)- area.x+
-    psppire_axis_unit_size (sheet->haxis, range.coli);
-  area.height = psppire_axis_start_pixel (sheet->vaxis, range.rowi)- area.y +
-    psppire_axis_unit_size (sheet->vaxis, range.rowi);
-
-  clip_area.x = sheet->row_title_area.width;
-  clip_area.y = sheet->column_title_area.height;
-
-  gdk_drawable_get_size (sheet->sheet_window,
-                        &clip_area.width, &clip_area.height);
-
-  if (!sheet->row_titles_visible) clip_area.x = 0;
-  if (!sheet->column_titles_visible) clip_area.y = 0;
-
-  if (area.x < 0)
-    {
-      area.width = area.width + area.x;
-      area.x = 0;
-    }
-  if (area.width > clip_area.width) area.width = clip_area.width + 10;
-  if (area.y < 0)
-    {
-      area.height = area.height + area.y;
-      area.y = 0;
-    }
-  if (area.height > clip_area.height) area.height = clip_area.height + 10;
-
-  clip_area.x--;
-  clip_area.y--;
-  clip_area.width += 3;
-  clip_area.height += 3;
-
-  gdk_gc_get_values (sheet->xor_gc, &values);
-
-  gdk_gc_set_clip_rectangle (sheet->xor_gc, &clip_area);
-
-  gdk_draw_rectangle (sheet->sheet_window,
-                     sheet->xor_gc,
-                     FALSE,
-                     area.x + i, area.y + i,
-                     area.width - 2 * i, area.height - 2 * i);
-
-
-  gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
-
-  gdk_gc_set_foreground (sheet->xor_gc, &values.foreground);
-}
-
-
-static void
-set_column_width (PsppireSheet *sheet,
-                 gint column,
-                 gint width)
-{
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (column < 0 || column >= psppire_axis_unit_count (sheet->haxis))
-    return;
-
-  if ( width <= 0)
-    return;
-
-  psppire_axis_resize (sheet->haxis, column,
-                      width - sheet->cell_padding->left -
-                      sheet->cell_padding->right);
-
-  if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    {
-      draw_column_title_buttons (sheet);
-      adjust_scrollbars (sheet);
-      psppire_sheet_size_allocate_entry (sheet);
-      redraw_range (sheet, NULL);
-    }
-}
-
-static void
-set_row_height (PsppireSheet *sheet,
-               gint row,
-               gint height)
-{
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (row < 0 || row >= psppire_axis_unit_count (sheet->vaxis))
-    return;
-
-  if (height <= 0)
-    return;
-
-  psppire_axis_resize (sheet->vaxis, row,
-                      height - sheet->cell_padding->top -
-                      sheet->cell_padding->bottom);
-
-  if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) )
-    {
-      draw_row_title_buttons (sheet);
-      adjust_scrollbars (sheet);
-      psppire_sheet_size_allocate_entry (sheet);
-      redraw_range (sheet, NULL);
-    }
-}
-
-static gboolean
-psppire_sheet_get_attributes (const PsppireSheet *sheet, gint row, gint col,
-                             PsppireSheetCellAttr *attr)
-{
-  GdkColor *fg, *bg;
-  const GtkJustification *j ;
-  GdkColormap *colormap;
-
-  g_return_val_if_fail (sheet != NULL, FALSE);
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), FALSE);
-
-  if (row < 0 || col < 0) return FALSE;
-
-  attr->foreground = GTK_WIDGET (sheet)->style->black;
-  attr->background = sheet->color[BG_COLOR];
-
-  attr->border.width = 0;
-  attr->border.line_style = GDK_LINE_SOLID;
-  attr->border.cap_style = GDK_CAP_NOT_LAST;
-  attr->border.join_style = GDK_JOIN_MITER;
-  attr->border.mask = 0;
-  attr->border.color = GTK_WIDGET (sheet)->style->black;
-
-  colormap = gtk_widget_get_colormap (GTK_WIDGET (sheet));
-  fg = psppire_sheet_model_get_foreground (sheet->model, row, col);
-  if ( fg )
-    {
-      gdk_colormap_alloc_color (colormap, fg, TRUE, TRUE);
-      attr->foreground = *fg;
-    }
-
-  bg = psppire_sheet_model_get_background (sheet->model, row, col);
-  if ( bg )
-    {
-      gdk_colormap_alloc_color (colormap, bg, TRUE, TRUE);
-      attr->background = *bg;
-    }
-
-  attr->justification =
-    psppire_sheet_model_get_column_justification (sheet->model, col);
-
-  j = psppire_sheet_model_get_justification (sheet->model, row, col);
-  if (j)
-    attr->justification = *j;
-
-  return TRUE;
-}
-
-static void
-psppire_sheet_forall (GtkContainer *container,
-                     gboolean include_internals,
-                     GtkCallback callback,
-                     gpointer callback_data)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (container);
-
-  g_return_if_fail (callback != NULL);
-
-  if (sheet->button && sheet->button->parent)
-    (* callback) (sheet->button, callback_data);
-
-  if (sheet->entry_widget && GTK_IS_CONTAINER (sheet->entry_widget))
-    (* callback) (sheet->entry_widget, callback_data);
-}
-
-
-PsppireSheetModel *
-psppire_sheet_get_model (const PsppireSheet *sheet)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), NULL);
-
-  return sheet->model;
-}
-
-
-PsppireSheetButton *
-psppire_sheet_button_new (void)
-{
-  PsppireSheetButton *button = g_malloc (sizeof (PsppireSheetButton));
-
-  button->state = GTK_STATE_NORMAL;
-  button->label = NULL;
-  button->label_visible = TRUE;
-  button->justification = GTK_JUSTIFY_FILL;
-  button->overstruck = FALSE;
-
-  return button;
-}
-
-
-void
-psppire_sheet_button_free (PsppireSheetButton *button)
-{
-  if (!button) return ;
-
-  g_free (button->label);
-  g_free (button);
-}
-
-static void
-append_cell_text (GString *string, const PsppireSheet *sheet, gint r, gint c)
-{
-  gchar *celltext = psppire_sheet_cell_get_text (sheet, r, c);
-
-  if ( NULL == celltext)
-    return;
-
-  g_string_append (string, celltext);
-  g_free (celltext);
-}
-
-
-static GString *
-range_to_text (const PsppireSheet *sheet)
-{
-  gint r, c;
-  GString *string;
-
-  if ( !psppire_sheet_range_isvisible (sheet, &sheet->range))
-    return NULL;
-
-  string = g_string_sized_new (80);
-
-  for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
-    {
-      for (c = sheet->range.col0; c < sheet->range.coli; ++c)
-       {
-         append_cell_text (string, sheet, r, c);
-         g_string_append (string, "\t");
-       }
-      append_cell_text (string, sheet, r, c);
-      if ( r < sheet->range.rowi)
-       g_string_append (string, "\n");
-    }
-
-  return string;
-}
-
-static GString *
-range_to_html (const PsppireSheet *sheet)
-{
-  gint r, c;
-  GString *string;
-
-  if ( !psppire_sheet_range_isvisible (sheet, &sheet->range))
-    return NULL;
-
-  string = g_string_sized_new (480);
-
-  g_string_append (string, "<html>\n");
-  g_string_append (string, "<body>\n");
-  g_string_append (string, "<table>\n");
-  for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
-    {
-      g_string_append (string, "<tr>\n");
-      for (c = sheet->range.col0; c <= sheet->range.coli; ++c)
-       {
-         g_string_append (string, "<td>");
-         append_cell_text (string, sheet, r, c);
-         g_string_append (string, "</td>\n");
-       }
-      g_string_append (string, "</tr>\n");
-    }
-  g_string_append (string, "</table>\n");
-  g_string_append (string, "</body>\n");
-  g_string_append (string, "</html>\n");
-
-  return string;
-}
-
-enum {
-  SELECT_FMT_NULL,
-  SELECT_FMT_TEXT,
-  SELECT_FMT_HTML
-};
-
-static void
-primary_get_cb (GtkClipboard     *clipboard,
-               GtkSelectionData *selection_data,
-               guint             info,
-               gpointer          data)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (data);
-  GString *string = NULL;
-
-  switch (info)
-    {
-    case SELECT_FMT_TEXT:
-      string = range_to_text (sheet);
-      break;
-    case SELECT_FMT_HTML:
-      string = range_to_html (sheet);
-      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
-primary_clear_cb (GtkClipboard *clipboard,
-                 gpointer      data)
-{
-  PsppireSheet *sheet = PSPPIRE_SHEET (data);
-  if ( ! GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    return;
-
-  psppire_sheet_unselect_range (sheet);
-}
-
-static void
-psppire_sheet_update_primary_selection (PsppireSheet *sheet)
-{
-  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 }
-  };
-
-  GtkClipboard *clipboard;
-
-  if (!GTK_WIDGET_REALIZED (sheet))
-    return;
-
-  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (sheet),
-                                       GDK_SELECTION_PRIMARY);
-
-  if (psppire_sheet_range_isvisible (sheet, &sheet->range))
-    {
-      if (!gtk_clipboard_set_with_owner (clipboard, targets,
-                                        G_N_ELEMENTS (targets),
-                                        primary_get_cb, primary_clear_cb,
-                                        G_OBJECT (sheet)))
-       primary_clear_cb (clipboard, sheet);
-    }
-  else
-    {
-      if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (sheet))
-       gtk_clipboard_clear (clipboard);
-    }
-}
diff --git a/lib/gtk-contrib/psppire-sheet.h b/lib/gtk-contrib/psppire-sheet.h
deleted file mode 100644 (file)
index eccffe8..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
-   Copyright (C) 2006, 2008 Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
- This file is derived from the gtksheet.c and extensively modified for the
- requirements of PSPPIRE.  The changes are copyright by the
- Free Software Foundation.  The copyright notice for the original work is
- below.
-
-
- GtkSheet widget for Gtk+.
- * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
- *
- * Based on GtkClist widget by Jay Painter, but major changes.
- * Memory allocation routines inspired on SC (Spreadsheet Calculator)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#ifndef __PSPPIRE_SHEET_H__
-#define __PSPPIRE_SHEET_H__
-
-#include <gtk/gtk.h>
-
-#include "gtkextra-sheet.h"
-#include <ui/gui/sheet/psppire-sheetmodel.h>
-#include <ui/gui/sheet/psppire-axis.h>
-
-G_BEGIN_DECLS
-
-/* sheet->select_status */
-enum
-{
-  PSPPIRE_SHEET_NORMAL,
-  PSPPIRE_SHEET_ROW_SELECTED,
-  PSPPIRE_SHEET_COLUMN_SELECTED,
-  PSPPIRE_SHEET_RANGE_SELECTED
-};
-
-
-#define PSPPIRE_TYPE_SHEET_RANGE (psppire_sheet_range_get_type ())
-#define PSPPIRE_TYPE_SHEET_CELL (psppire_sheet_cell_get_type ())
-
-
-#define PSPPIRE_TYPE_SHEET          (psppire_sheet_get_type ())
-#define PSPPIRE_SHEET(obj)          G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPPIRE_TYPE_SHEET, PsppireSheet)
-#define PSPPIRE_SHEET_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST ((klass),  PSPPIRE_TYPE_SHEET, PsppireSheetClass)
-#define PSPPIRE_IS_SHEET(obj)       G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_SHEET)
-
-
-typedef struct _PsppireSheetClass PsppireSheetClass;
-typedef struct _PsppireSheetCellAttr     PsppireSheetCellAttr;
-
-typedef struct _PsppireSheetHoverTitle PsppireSheetHoverTitle;
-
-
-struct _PsppireSheetCellAttr
-{
-  GtkJustification justification;
-  GdkColor foreground;
-  GdkColor background;
-  PsppireSheetCellBorder border;
-};
-
-struct _PsppireSheetHoverTitle
-{
-  GtkWidget *window;
-  GtkWidget *label;
-  gint row, column;
-};
-
-enum
-  {
-    BG_COLOR,
-    GRID_COLOR,
-    n_COLORS
-  };
-
-struct _PsppireSheet
-{
-  GtkBin parent;
-
-  gboolean dispose_has_run;
-  PsppireAxis *haxis;
-  PsppireAxis *vaxis;
-
-  guint16 flags;
-
-  PsppireSheetModel *model;
-
-  /* Component colors */
-  GdkColor color[n_COLORS];
-  gboolean show_grid;
-
-  /* active cell */
-  PsppireSheetCell active_cell;
-
-  /* The GtkEntry used for editing the cells */
-  GtkWidget *entry_widget;
-
-  /* The type of entry_widget */
-  GType entry_type;
-
-  /* global selection button */
-  GtkWidget *button;
-
-  /* sheet state */
-  gint select_status;
-
-  /* selected range */
-  PsppireSheetRange range;
-
-  /* The space between a cell's contents and its border */
-  GtkBorder *cell_padding;
-
-  /* the scrolling window and its height and width to
-   * make things a little speedier */
-  GdkWindow *sheet_window;
-
-  /* border shadow style */
-  GtkShadowType shadow_type;
-
-  /* Column Titles */
-  GdkRectangle column_title_area;
-  GdkWindow *column_title_window;
-  gboolean column_titles_visible;
-  /* TRUE if the cursor is over the column title window */
-  gboolean column_title_under;
-
-  /* Row Titles */
-  GdkRectangle row_title_area;
-  GdkWindow *row_title_window;
-  gboolean row_titles_visible;
-  /* TRUE if the cursor is over the row title window */
-  gboolean row_title_under;
-
-  /*scrollbars*/
-  GtkAdjustment *hadjustment;
-  GtkAdjustment *vadjustment;
-
-  /* xor GC for the verticle drag line */
-  GdkGC *xor_gc;
-
-  /* gc for drawing unselected cells */
-  GdkGC *fg_gc;
-  GdkGC *bg_gc;
-
-  /* cursor used to indicate dragging */
-  GdkCursor *cursor_drag;
-
-  /* the current x-pixel location of the xor-drag vline */
-  gint x_drag;
-
-  /* the current y-pixel location of the xor-drag hline */
-  gint y_drag;
-
-  /* current cell being dragged */
-  PsppireSheetCell drag_cell;
-  /* current range being dragged */
-  PsppireSheetRange drag_range;
-
-  /* Used for the subtitle (popups) */
-  gint motion_timer;
-  PsppireSheetHoverTitle *hover_window;
-
-  gulong update_handler_id;
-};
-
-struct _PsppireSheetClass
-{
-  GtkBinClass parent_class;
-
- gboolean (*set_scroll_adjustments) (PsppireSheet *sheet,
-                                GtkAdjustment *hadjustment,
-                                GtkAdjustment *vadjustment);
-
- void (*select_row)            (PsppireSheet *sheet, gint row);
-
- void (*select_column)                 (PsppireSheet *sheet, gint column);
-
- void (*select_range)          (PsppireSheet *sheet, PsppireSheetRange *range);
-
- void (*resize_range)          (PsppireSheet *sheet,
-                               PsppireSheetRange *old_range,
-                               PsppireSheetRange *new_range);
-
- void (*move_range)                    (PsppireSheet *sheet,
-                               PsppireSheetRange *old_range,
-                               PsppireSheetRange *new_range);
-
- gboolean (*traverse)          (PsppireSheet *sheet,
-                               gint row, gint column,
-                               gint *new_row, gint *new_column);
-
- gboolean (*activate)          (PsppireSheet *sheet,
-                               gint row, gint column);
-
- void (*changed)               (PsppireSheet *sheet,
-                               gint row, gint column);
-};
-
-GType psppire_sheet_get_type (void);
-GType psppire_sheet_range_get_type (void);
-
-
-/* create a new sheet */
-GtkWidget * psppire_sheet_new (PsppireSheetModel *model);
-
-/* create a new sheet with custom entry */
-GtkWidget *
-psppire_sheet_new_with_custom_entry (GType entry_type);
-
-/* Change entry */
-void psppire_sheet_change_entry                (PsppireSheet *sheet, GType entry_type);
-
-GtkEntry *psppire_sheet_get_entry    (PsppireSheet *sheet);
-
-
-void psppire_sheet_get_selected_range (PsppireSheet *sheet,
-                                        PsppireSheetRange *range);
-
-void psppire_sheet_show_grid     (PsppireSheet *sheet,
-                                        gboolean show);
-
-gboolean psppire_sheet_grid_visible   (PsppireSheet *sheet);
-
-
-/* scroll the viewing area of the sheet to the given column
- * and row; row_align and col_align are between 0-1 representing the
- * location the row should appear on the screen, 0.0 being top or left,
- * 1.0 being bottom or right; if row or column is negative then there
- * is no change */
-void psppire_sheet_moveto (PsppireSheet *sheet,
-                 gint row,
-                 gint column,
-                 gfloat row_align,
-                  gfloat col_align);
-
-
-void psppire_sheet_show_row_titles             (PsppireSheet *sheet);
-void psppire_sheet_hide_row_titles             (PsppireSheet *sheet);
-void psppire_sheet_show_column_titles       (PsppireSheet *sheet);
-void psppire_sheet_hide_column_titles  (PsppireSheet *sheet);
-
-/* select the row. The range is then highlighted, and the bounds are stored
- * in sheet->range  */
-void psppire_sheet_select_row    (PsppireSheet * sheet,  gint row);
-
-/* select the column. The range is then highlighted, and the bounds are stored
- * in sheet->range  */
-void psppire_sheet_select_column (PsppireSheet * sheet,  gint column);
-
-/* highlight the selected range and store bounds in sheet->range */
-void psppire_sheet_select_range (PsppireSheet *sheet, const PsppireSheetRange *range);
-
-void psppire_sheet_get_visible_range (PsppireSheet *sheet, PsppireSheetRange *range);
-
-
-/* obvious */
-void psppire_sheet_unselect_range              (PsppireSheet *sheet);
-
-/* set active cell where the entry will be displayed */
-void psppire_sheet_set_active_cell (PsppireSheet *sheet,
-                               gint row, gint column);
-
-/* Sets *ROW and *COLUMN to be the coordinates of the active cell.
-   ROW and/or COLUMN may be null if the caller is not interested in their
-   values */
-void psppire_sheet_get_active_cell (PsppireSheet *sheet,
-                                       gint *row, gint *column);
-
-/* get cell contents */
-gchar *psppire_sheet_cell_get_text (const PsppireSheet *sheet, gint row, gint col);
-
-
-void psppire_sheet_set_model (PsppireSheet *sheet,
-                                  PsppireSheetModel *model);
-
-PsppireSheetModel * psppire_sheet_get_model (const PsppireSheet *sheet);
-
-
-G_END_DECLS
-
-
-#endif /* __PSPPIRE_SHEET_H__ */
-
-
index 79e9ea1e14dae1def667b3f4edd1ea60f4e0ac5d..44e4a1da28ee7183a98eb1e819a755bc55759c0f 100644 (file)
@@ -1548,6 +1548,13 @@ ds_put_byte_multiple (struct string *st, int ch, size_t cnt)
   memset (ds_put_uninit (st, cnt), ch, cnt);
 }
 
+/* Appends Unicode code point UC to ST in UTF-8 encoding. */
+void
+ds_put_unichar (struct string *st, ucs4_t uc)
+{
+  ds_extend (st, ds_length (st) + 6);
+  st->ss.length += u8_uctomb (CHAR_CAST (uint8_t *, ds_end (st)), uc, 6);
+}
 
 /* If relocation has been enabled, replace ST,
    with its relocated version */
index c8ab726797f8fbf82bdea0e336059d1ab1eec895..e017696cf60bdc1efc9dd12a744e3d9b7befeec5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -223,6 +223,7 @@ bool ds_read_stream (struct string *, size_t size, size_t cnt, FILE *stream);
 /* Append. */
 void ds_put_byte (struct string *, int ch);
 void ds_put_byte_multiple (struct string *, int ch, size_t);
+void ds_put_unichar (struct string *, ucs4_t uc);
 void ds_put_cstr (struct string *, const char *);
 void ds_put_substring (struct string *, struct substring);
 void ds_put_vformat (struct string *st, const char *, va_list)
index 7a48fce850603eec83e7672ee92af4688cd19564..7348cd5ed2bebf6220141c6134c3fb9b64293054 100644 (file)
@@ -469,8 +469,6 @@ aggregate_dialog (PsppireDataWindow *dw)
   struct aggregate fd;
   gint response;
 
-  PsppireVarStore *vs;
-
   GtkWidget *dialog ;
   GtkWidget *source ;
 
@@ -566,11 +564,9 @@ aggregate_dialog (PsppireDataWindow *dw)
 
   g_signal_connect_swapped (dialog, "refresh", G_CALLBACK (refresh),  &fd);
 
-  g_object_get (fd.de->data_editor, "var-store", &vs, NULL);
-
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fd.de));
 
-  g_object_get (vs, "dictionary", &fd.dict, NULL);
+  g_object_get (fd.de->data_editor, "dictionary", &fd.dict, NULL);
   g_object_set (source, "model", fd.dict, NULL);
 
 
index 3af7038e2e36651c37489f66d793dbaded3e016d..14beeb9a1ee85c2ecf47294f845bf9bed673c23d 100644 (file)
@@ -1,7 +1,5 @@
 ## Process this file with automake to produce Makefile.in  -*- makefile -*-
 
-include $(top_srcdir)/src/ui/gui/sheet/automake.mk
-
 UI_FILES = \
        src/ui/gui/aggregate.ui \
        src/ui/gui/autorecode.ui \
@@ -11,6 +9,7 @@ UI_FILES = \
        src/ui/gui/count.ui \
        src/ui/gui/crosstabs.ui \
        src/ui/gui/chi-square.ui \
+       src/ui/gui/data-sheet.ui \
        src/ui/gui/descriptives.ui \
        src/ui/gui/entry-dialog.ui \
        src/ui/gui/examine.ui \
@@ -42,7 +41,8 @@ UI_FILES = \
        src/ui/gui/variable-info.ui \
        src/ui/gui/data-editor.ui \
        src/ui/gui/output-viewer.ui \
-       src/ui/gui/syntax-editor.ui
+       src/ui/gui/syntax-editor.ui \
+       src/ui/gui/var-sheet.ui
 
 EXTRA_DIST += \
        src/ui/gui/OChangeLog \
@@ -69,8 +69,7 @@ endif
 
 
 src_ui_gui_psppire_LDADD = \
-        src/ui/gui/sheet/libsheet.la \
-       lib/gtk-contrib/libgtksheet.a \
+       lib/gtk-contrib/libxpaned.a \
        src/ui/libuicommon.la \
        src/libpspp.la \
        src/libpspp-core.la \
@@ -177,8 +176,6 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/count-dialog.h \
        src/ui/gui/crosstabs-dialog.c \
        src/ui/gui/crosstabs-dialog.h \
-       src/ui/gui/customentry.c \
-       src/ui/gui/customentry.h \
        src/ui/gui/dialog-common.c \
        src/ui/gui/dialog-common.h \
        src/ui/gui/dict-display.h \
@@ -216,6 +213,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-conf.h \
        src/ui/gui/psppire-data-editor.c \
        src/ui/gui/psppire-data-editor.h \
+       src/ui/gui/psppire-data-sheet.c \
+       src/ui/gui/psppire-data-sheet.h \
        src/ui/gui/psppire-data-store.c \
        src/ui/gui/psppire-data-store.h \
        src/ui/gui/psppire-data-window.c \
@@ -282,8 +281,6 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-var-ptr.h \
        src/ui/gui/psppire-var-sheet.c \
        src/ui/gui/psppire-var-sheet.h \
-       src/ui/gui/psppire-var-store.c \
-       src/ui/gui/psppire-var-store.h \
        src/ui/gui/psppire-vbuttonbox.h \
        src/ui/gui/psppire-window.c \
        src/ui/gui/psppire-window.h \
index f303e18d0f3ab4edb949ffe614d1f721ed4f21ba..8c771ce222d81e9ad9790dd20a5926cdb1d8a5d4 100644 (file)
@@ -271,7 +271,6 @@ autorecode_dialog (PsppireDataWindow *de)
   gint response;
 
   GtkBuilder *xml = builder_new ("autorecode.ui");
-  PsppireVarStore *vs;
 
   GtkWidget *dialog = get_widget_assert   (xml, "autorecode-dialog");
   GtkWidget *source = get_widget_assert   (xml, "dict-view");
@@ -324,11 +323,10 @@ autorecode_dialog (PsppireDataWindow *de)
 
     }
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_get (vs, "dictionary", &rd.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &rd.dict, NULL);
   g_object_set (source, "model", rd.dict, NULL);
 
 
index ee3fbd7bf2cdb76c5c1c57160fceb1dcd687fba8..90d9118ea6e29ea5c593cfc2d6438548974ebaaf 100644 (file)
@@ -146,7 +146,6 @@ binomial_dialog (PsppireDataWindow *dw)
   struct binomial_dialog bin_d;
 
   GtkBuilder *xml = builder_new ("binomial.ui");
-  PsppireVarStore *vs;
 
   GtkWidget *dialog = get_widget_assert   (xml, "binomial-dialog");
 
@@ -154,8 +153,6 @@ binomial_dialog (PsppireDataWindow *dw)
 
   GtkWidget *dict_view = get_widget_assert   (xml, "dict-view");
 
-  g_object_get (dw->data_editor, "var-store", &vs, NULL);
-
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (dw));
 
   bin_d.var_view  = get_widget_assert (xml, "variables-treeview");
@@ -165,7 +162,7 @@ binomial_dialog (PsppireDataWindow *dw)
   bin_d.cutpoint_entry =     get_widget_assert   (xml, "cutpoint-entry");
   bin_d.cutpoint_button =    get_widget_assert   (xml, "radiobutton4");
 
-  g_object_get (vs, "dictionary", &bin_d.dict, NULL);
+  g_object_get (dw->data_editor, "dictionary", &bin_d.dict, NULL);
   g_object_set (dict_view,
                "model", bin_d.dict, 
                "predicate", var_is_numeric,
index dfa39f06eba9df63651810834c535fd7a27e554a..64a6356ce188f3d0356c3d6051102ddbe083f942 100644 (file)
@@ -162,7 +162,6 @@ chisquare_dialog (PsppireDataWindow *dw)
   struct chisquare_dialog csd;
 
   GtkBuilder *xml = builder_new ("chi-square.ui");
-  PsppireVarStore *vs;
 
   GtkWidget *dialog = get_widget_assert   (xml, "chisquare-dialog");
 
@@ -189,12 +188,10 @@ chisquare_dialog (PsppireDataWindow *dw)
 
   csd.values_button = get_widget_assert   (xml, "radiobutton2");
 
-  g_object_get (dw->data_editor, "var-store", &vs, NULL);
-
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (dw));
  
 
-  g_object_get (vs, "dictionary", &csd.dict, NULL);
+  g_object_get (dw->data_editor, "dictionary", &csd.dict, NULL);
   g_object_set (dict_view,
                "model", csd.dict, 
                "predicate", var_is_numeric,
index 68249afdcb82d39cdd6a25738287714ba14ad4ed..1d31777379a0e3c7b4d3dbe951b44d60d4db4350 100644 (file)
@@ -22,7 +22,6 @@
 #include "psppire-data-editor.h"
 #include "executor.h"
 #include "helper.h"
-#include "psppire-var-store.h"
 #include <ui/syntax-gen.h>
 
 #include "comments-dialog.h"
@@ -104,9 +103,6 @@ comments_dialog (PsppireDataWindow *de)
   GtkWidget *label = get_widget_assert (xml, "column-number-label");
   GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
 
-  PsppireVarStore *vs = NULL;
-
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
@@ -144,7 +140,7 @@ comments_dialog (PsppireDataWindow *de)
   }
 
   cd.xml = xml;
-  g_object_get (vs, "dictionary", &cd.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &cd.dict, NULL);
 
   g_signal_connect (buffer, "mark-set",
                    G_CALLBACK (set_column_number), label);
index debc412341eca9e5af6b9ed6eaa07fae2b25cee8..9ddb66d48e4fcc848cbf48eb4b95eaf2754d7114 100644 (file)
@@ -21,7 +21,6 @@
 #include "psppire-dialog.h"
 #include "psppire-keypad.h"
 #include "psppire-data-window.h"
-#include "psppire-var-store.h"
 #include "psppire-selector.h"
 #include "dialog-common.h"
 #include <libpspp/i18n.h>
@@ -369,7 +368,6 @@ compute_dialog (PsppireDataWindow *de)
 {
   gint response;
 
-  PsppireVarStore *vs = NULL;
   struct compute_dialog scd;
 
   GtkBuilder *xml = builder_new ("compute.ui");
@@ -388,8 +386,7 @@ compute_dialog (PsppireDataWindow *de)
        get_widget_assert (xml, "radio-button-expression-label");
 
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-  g_object_get (vs, "dictionary", &scd.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &scd.dict, NULL);
   scd.use_type = FALSE;
 
   g_signal_connect (expression, "toggled",
index b0d417f8eb1fcdf29f2358c71da3de12a11b824a..135cc473304fa91c43eaf9b59ea5eec75bfecafb 100644 (file)
@@ -114,7 +114,6 @@ dialog_state_valid (gpointer data)
 void count_dialog (PsppireDataWindow *de)
 {
   gint response;
-  PsppireVarStore *vs = NULL;
   struct cnt_dialog cnt;
 
   GtkBuilder *builder = builder_new ("count.ui");
@@ -137,9 +136,7 @@ void count_dialog (PsppireDataWindow *de)
   g_signal_connect (cnt.dialog, "refresh", G_CALLBACK (refresh),  &cnt);
 
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
-  g_object_get (vs, "dictionary", &cnt.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &cnt.dict, NULL);
 
   gtk_window_set_transient_for (GTK_WINDOW (cnt.dialog), GTK_WINDOW (de));
 
index dc046679c73278085ebee4d6b04e8caa1d701b34..3cb8218b91465e09dd584ccc9e2f955aa0de049b 100644 (file)
@@ -28,7 +28,6 @@
 #include <ui/gui/dict-display.h>
 #include "executor.h"
 #include <ui/gui/psppire-dialog.h>
-#include <ui/gui/psppire-var-store.h>
 #include <ui/gui/builder-wrapper.h>
 #include "helper.h"
 
@@ -350,7 +349,6 @@ crosstabs_dialog (PsppireDataWindow *de)
   struct crosstabs_dialog cd;
 
   GtkBuilder *xml = builder_new ("crosstabs.ui");
-  PsppireVarStore *vs = NULL;
   PsppireDict *dict = NULL;
 
 
@@ -366,8 +364,6 @@ crosstabs_dialog (PsppireDataWindow *de)
   cd.stat_view = get_widget_assert (xml, "stats-view");
   cd.cell_view = get_widget_assert (xml, "cell-view");
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
   put_checkbox_items_in_treeview (GTK_TREE_VIEW(cd.stat_view),
                                  B_CS_STATS_DEFAULT,
                                  N_CROSSTABS_STATS,
@@ -381,12 +377,12 @@ crosstabs_dialog (PsppireDataWindow *de)
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_get (vs, "dictionary", &dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &dict, NULL);
   g_object_set (source, "model", dict, NULL);
 
   cd.row_vars = GTK_TREE_VIEW (dest_rows);
   cd.col_vars = GTK_TREE_VIEW (dest_cols);
-  g_object_get (vs, "dictionary", &cd.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &cd.dict, NULL);
   cd.format_dialog = get_widget_assert (xml, "format-dialog");
   cd.table_button = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "print-tables"));
   cd.pivot_button = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "pivot"));
diff --git a/src/ui/gui/customentry.c b/src/ui/gui/customentry.c
deleted file mode 100644 (file)
index b7d0ce2..0000000
+++ /dev/null
@@ -1,443 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005, 2007, 2010, 2011  Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-/*
-   This widget is a subclass of GtkEntry.  It's an entry widget with a
-   button on the right hand side.
-
-   This code is heavily based upon the GtkSpinButton widget.  Therefore
-   the copyright notice of that code is pasted below.
-
-   Please note however,  this code is covered by the GPL, not the LGPL.
-*/
-
-/* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * GtkSpinButton widget for GTK+
- * Copyright (C) 1998 Lars Hamann and Stefan Jeske
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-
-
-/*
- * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
- * file for a list of people on the GTK+ Team.  See the ChangeLog
- * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#include <config.h>
-
-#include <gtk/gtk.h>
-#include "customentry.h"
-#include "helper.h"
-
-static void psppire_custom_entry_class_init          (PsppireCustomEntryClass *klass);
-static void psppire_custom_entry_init                (PsppireCustomEntry      *ce);
-
-static GtkEntryClass *parent_class = NULL;
-
-/* Signals */
-enum
-{
-  CLICKED,
-  n_SIGNALS
-};
-
-
-static guint custom_entry_signals[n_SIGNALS] = {0};
-
-
-GType
-psppire_custom_entry_get_type (void)
-{
-  static GType ce_type = 0;
-
-  if (!ce_type)
-    {
-      static const GTypeInfo ce_info =
-       {
-         sizeof (PsppireCustomEntryClass),
-         NULL, /* base_init */
-         NULL, /* base_finalize */
-         (GClassInitFunc) psppire_custom_entry_class_init,
-         NULL, /* class_finalize */
-         NULL, /* class_data */
-         sizeof (PsppireCustomEntry),
-         0,
-         (GInstanceInitFunc) psppire_custom_entry_init,
-       };
-
-      ce_type = g_type_register_static (GTK_TYPE_ENTRY, "PsppireCustomEntry",
-                                       &ce_info, 0);
-    }
-
-  return ce_type;
-}
-
-
-static void
-psppire_custom_entry_map (GtkWidget *widget)
-{
-  if (gtk_widget_get_realized (widget) && !gtk_widget_get_mapped (widget))
-    {
-      GTK_WIDGET_CLASS (parent_class)->map (widget);
-      gdk_window_show (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
-    }
-}
-
-static void
-psppire_custom_entry_unmap (GtkWidget *widget)
-{
-  if (gtk_widget_get_mapped (widget))
-    {
-      gdk_window_hide (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
-      GTK_WIDGET_CLASS (parent_class)->unmap (widget);
-    }
-}
-
-static gint psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry);
-
-static void
-psppire_custom_entry_realize (GtkWidget *widget)
-{
-  PsppireCustomEntry *custom_entry;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  guint real_width;
-  gint button_size ;
-
-  custom_entry = PSPPIRE_CUSTOM_ENTRY (widget);
-
-  button_size = psppire_custom_entry_get_button_width (custom_entry);
-
-  real_width = widget->allocation.width;
-  widget->allocation.width -= button_size + 2 * widget->style->xthickness;
-  gtk_widget_set_events (widget, gtk_widget_get_events (widget) |
-                        GDK_KEY_RELEASE_MASK);
-  GTK_WIDGET_CLASS (parent_class)->realize (widget);
-
-  widget->allocation.width = real_width;
-
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
-  attributes.event_mask = gtk_widget_get_events (widget);
-  attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
-    | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
-    | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
-
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-
-  attributes.x = (widget->allocation.x +
-                 widget->allocation.width - button_size -
-                 2 * widget->style->xthickness);
-  attributes.y = widget->allocation.y + (widget->allocation.height -
-                                        widget->requisition.height) / 2;
-  attributes.width = button_size + 2 * widget->style->xthickness;
-  attributes.height = widget->requisition.height;
-
-  custom_entry->panel = gdk_window_new (gtk_widget_get_parent_window (widget),
-                                       &attributes, attributes_mask);
-  gdk_window_set_user_data (custom_entry->panel, widget);
-
-  gtk_style_set_background (widget->style, custom_entry->panel, GTK_STATE_NORMAL);
-
-
-  gtk_widget_queue_resize (GTK_WIDGET (custom_entry));
-}
-
-
-#define MIN_BUTTON_WIDTH  6
-
-static gint
-psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry)
-{
-  const gint size = pango_font_description_get_size
-    (GTK_WIDGET (custom_entry)->style->font_desc);
-
-  gint button_width = MAX (PANGO_PIXELS (size), MIN_BUTTON_WIDTH);
-
-  return button_width - button_width % 2; /* force even */
-}
-
-/**
- * custom_entry_get_shadow_type:
- * @custom_entry: a #PsppireCustomEntry
- *
- * Convenience function to Get the shadow type from the underlying widget's
- * style.
- *
- * Return value: the #GtkShadowType
- **/
-static gint
-psppire_custom_entry_get_shadow_type (PsppireCustomEntry *custom_entry)
-{
-  GtkShadowType rc_shadow_type;
-
-  gtk_widget_style_get (GTK_WIDGET (custom_entry), "shadow_type", &rc_shadow_type, NULL);
-
-  return rc_shadow_type;
-}
-
-
-static void
-psppire_custom_entry_unrealize (GtkWidget *widget)
-{
-  PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
-
-  GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
-
-  if (ce->panel)
-    {
-      gdk_window_set_user_data (ce->panel, NULL);
-      gdk_window_destroy (ce->panel);
-      ce->panel = NULL;
-    }
-}
-
-
-static void
-psppire_custom_entry_redraw (PsppireCustomEntry *custom_entry)
-{
-  GtkWidget *widget;
-
-  widget = GTK_WIDGET (custom_entry);
-
-  if (gtk_widget_is_drawable (widget))
-    {
-      gtk_widget_queue_draw (widget);
-
-      /* We must invalidate the panel window ourselves, because it
-       * is not a child of widget->window
-       */
-      gdk_window_invalidate_rect (custom_entry->panel, NULL, TRUE);
-    }
-}
-
-
-static gint
-psppire_custom_entry_expose (GtkWidget      *widget,
-                    GdkEventExpose *event)
-{
-  PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
-
-  g_return_val_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  if (gtk_widget_is_drawable (widget))
-    {
-      gboolean is_editable;
-      GtkShadowType shadow_type;
-      GdkRectangle rect;
-
-      rect.x = 0;
-      rect.y = 0;
-
-      if (event->window != ce->panel)
-       GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
-
-      gdk_drawable_get_size (ce->panel, &rect.width, &rect.height);
-
-      gdk_window_begin_paint_rect (ce->panel, &rect);
-
-
-      shadow_type = psppire_custom_entry_get_shadow_type (ce);
-
-      g_object_get (widget, "editable", &is_editable, NULL);
-
-      gtk_paint_box (widget->style, ce->panel,
-                    is_editable ? GTK_STATE_NORMAL: GTK_STATE_INSENSITIVE,
-                    shadow_type,
-                    NULL, widget, "customentry",
-                    rect.x, rect.y, rect.width, rect.height);
-
-
-      gdk_window_end_paint (ce->panel);
-    }
-
-  return FALSE;
-}
-
-
-static gint
-psppire_custom_entry_button_press (GtkWidget      *widget,
-                          GdkEventButton *event);
-
-static void
-psppire_custom_entry_size_allocate (GtkWidget     *widget,
-                           GtkAllocation *allocation);
-
-
-
-static void
-psppire_custom_entry_class_init (PsppireCustomEntryClass *klass)
-{
-  GObjectClass     *gobject_class = G_OBJECT_CLASS (klass);
-
-  GtkWidgetClass   *widget_class;
-  GtkEntryClass   *entry_class;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  widget_class   = (GtkWidgetClass*)   klass;
-  entry_class   = (GtkEntryClass*)   klass;
-
-  widget_class->map = psppire_custom_entry_map;
-  widget_class->unmap = psppire_custom_entry_unmap;
-
-  widget_class->realize = psppire_custom_entry_realize;
-  widget_class->unrealize = psppire_custom_entry_unrealize;
-
-  widget_class->expose_event = psppire_custom_entry_expose;
-  widget_class->button_press_event = psppire_custom_entry_button_press;
-
-  widget_class->size_allocate = psppire_custom_entry_size_allocate;
-
-
-  gtk_widget_class_install_style_property_parser
-    (widget_class,
-     g_param_spec_enum ("shadow_type",
-                       "Shadow Type",
-                       "Style of bevel around the custom entry button",
-                       GTK_TYPE_SHADOW_TYPE,
-                       GTK_SHADOW_ETCHED_IN,
-                       G_PARAM_READABLE),
-     gtk_rc_property_parse_enum);
-
-  custom_entry_signals[CLICKED] =
-    g_signal_new ("clicked",
-                 G_TYPE_FROM_CLASS (gobject_class),
-                 G_SIGNAL_RUN_LAST,
-                 0,
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE,
-                 0);
-
-
-}
-
-static void
-psppire_custom_entry_init (PsppireCustomEntry *ce)
-{
-}
-
-GtkWidget*
-psppire_custom_entry_new ()
-{
-  return GTK_WIDGET (g_object_new (psppire_custom_entry_get_type (), NULL));
-}
-
-
-
-static gint
-psppire_custom_entry_button_press (GtkWidget *widget,
-                                  GdkEventButton *event)
-{
-  PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
-
-  if (event->window == ce->panel)
-    {
-      gboolean is_editable ;
-      if (!gtk_widget_has_focus (widget))
-       gtk_widget_grab_focus (widget);
-
-      g_object_get (ce, "editable", &is_editable, NULL);
-
-      if ( event->button == 1 && is_editable )
-       g_signal_emit (widget, custom_entry_signals[CLICKED], 0);
-
-    }
-  else
-    return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
-
-  return FALSE;
-}
-
-
-
-static void
-psppire_custom_entry_size_allocate (GtkWidget     *widget,
-                           GtkAllocation *allocation)
-{
-  PsppireCustomEntry *ce;
-  GtkAllocation entry_allocation;
-  GtkAllocation panel_allocation;
-  gint button_width;
-  gint panel_width;
-
-  g_return_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget));
-  g_return_if_fail (allocation != NULL);
-
-  ce = PSPPIRE_CUSTOM_ENTRY (widget);
-  button_width = psppire_custom_entry_get_button_width (ce);
-  panel_width = button_width + 2 * widget->style->xthickness;
-
-  widget->allocation = *allocation;
-
-  entry_allocation = *allocation;
-  entry_allocation.width -= panel_width;
-
-  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
-    {
-      entry_allocation.x += panel_width;
-      panel_allocation.x = allocation->x;
-    }
-  else
-    {
-      panel_allocation.x = allocation->x + allocation->width - panel_width;
-    }
-
-  panel_allocation.width = panel_width;
-  panel_allocation.height = MIN (widget->requisition.height, allocation->height);
-
-  panel_allocation.y = allocation->y + (allocation->height -
-                                       panel_allocation.height) / 2;
-
-  GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, &entry_allocation);
-
-  if (gtk_widget_get_realized (widget))
-    {
-      gdk_window_move_resize (PSPPIRE_CUSTOM_ENTRY (widget)->panel,
-                             panel_allocation.x,
-                             panel_allocation.y,
-                             panel_allocation.width,
-                             panel_allocation.height);
-    }
-
-  psppire_custom_entry_redraw (ce);
-}
-
-
-
-
-
diff --git a/src/ui/gui/customentry.h b/src/ui/gui/customentry.h
deleted file mode 100644 (file)
index 123ab8c..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005  Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-/*
-   This widget is a subclass of GtkEntry.  It's an entry widget with a
-   button on the right hand side.
-
-   This code is heavily based upon the GtkSpinButton widget.  Therefore
-   the copyright notice of that code is pasted below.
-
-   Please note however,  this code is covered by the GPL, not the LGPL.
-*/
-
-/* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * GtkSpinButton widget for GTK+
- * Copyright (C) 1998 Lars Hamann and Stefan Jeske
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library.  If not, see
- * <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
- * file for a list of people on the GTK+ Team.  See the ChangeLog
- * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-
-#ifndef __PSPPIRE_CUSTOM_ENTRY_H__
-#define __PSPPIRE_CUSTOM_ENTRY_H__
-
-
-#include <glib.h>
-#include <glib-object.h>
-
-
-GType psppire_custom_entry_get_type (void);
-
-G_BEGIN_DECLS
-
-#define PSPPIRE_CUSTOM_ENTRY_TYPE (psppire_custom_entry_get_type ())
-
-#define PSPPIRE_CUSTOM_ENTRY(obj)            \
-     (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPPIRE_CUSTOM_ENTRY_TYPE, PsppireCustomEntry))
-
-#define PSPPIRE_CUSTOM_ENTRY_CLASS(klass)    \
-     (G_TYPE_CHECK_CLASS_CAST ((klass),PSPPIRE_CUSTOM_ENTRY_TYPE, PsppireCustomEntryClass))
-
-#define PSPPIRE_IS_CUSTOM_ENTRY(obj)         \
-     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_CUSTOM_ENTRY_TYPE))
-
-#define IS_PSPPIRE_CUSTOM_ENTRY_CLASS(klass) \
-     (G_TYPE_CHECK_CLASS_TYPE ((klass),  PSPPIRE_CUSTOM_ENTRY_TYPE))
-
-
-typedef struct _PsppireCustomEntry       PsppireCustomEntry;
-typedef struct _PsppireCustomEntryClass  PsppireCustomEntryClass;
-
-struct _PsppireCustomEntry
-{
-  GtkEntry entry;
-
-  GdkWindow *panel;
-};
-
-struct _PsppireCustomEntryClass
-{
-  GtkEntryClass parent_class;
-
-  void (*clicked)  (PsppireCustomEntry *spin_button);
-
-};
-
-GType          custom_entry_get_type        (void);
-GtkWidget*     custom_entry_new             (void);
-
-G_END_DECLS
-
-#endif /* __PSPPIRE_CUSTOM_ENTRY_H__ */
index cfa5b3e91834ea6e4cab79daaf83f02d0b8e7902..26821ebf17b936b2d31affbfb964b9c627b14c1f 100644 (file)
@@ -1,20 +1,6 @@
 <?xml version="1.0"?>
 <interface>
   <object class="GtkUIManager" id="uimanager1">
-    <child>
-      <object class="GtkActionGroup" id="actiongroup2">
-        <child>
-          <object class="GtkAction" id="sort-up">
-            <property name="stock-id">gtk-sort-ascending</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="sort-down">
-            <property name="stock-id">gtk-sort-descending</property>
-          </object>
-        </child>
-      </object>
-    </child>
     <child>
       <object class="GtkActionGroup" id="actiongroup1">
         <child>
             <property name="label" translatable="yes">_Edit</property>
           </object>
         </child>
-        <child>
-          <object class="GtkAction" id="action_insert-variable">
-            <property name="name">action_insert-variable</property>
-            <property name="label" translatable="yes">Insert Variable</property>
-            <property name="tooltip" translatable="yes">Create a new variable at the current position</property>
-           <property name="stock-id">pspp-insert-variable</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="edit_insert-case">
-            <property name="name">edit_insert-case</property>
-            <property name="label" translatable="yes">Insert Cases</property>
-            <property name="tooltip" translatable="yes">Create a new case at the current position</property>
-           <property name="stock-id">pspp-insert-case</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="edit_goto-case">
-            <property name="label" translatable="yes">Go To Case...</property>
-            <property name="name">edit_goto-case</property>
-            <property name="tooltip" translatable="yes">Jump to a case in the data sheet</property>
-           <property name="stock-id">gtk-jump-to</property>
-
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="edit_cut">
-            <property name="stock-id">gtk-cut</property>
-            <property name="name">edit_cut</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="edit_copy">
-            <property name="stock-id">gtk-copy</property>
-            <property name="name">edit_copy</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="edit_paste">
-            <property name="stock-id">gtk-paste</property>
-            <property name="name">edit_paste</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="edit_clear-variables">
-            <property name="name">edit_clear-variables</property>
-            <property name="label" translatable="yes">Cl_ear Variables</property>
-           <property name="tooltip" translatable="yes">Delete the variables at the selected position(s)</property>
-            <property name="stock-id">gtk-clear</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="edit_clear-cases">
-            <property name="name">edit_clear-cases</property>
-            <property name="stock-id">gtk-clear</property>
-            <property name="label" translatable="yes">_Clear Cases</property>
-            <property name="tooltip" translatable="yes">Delete the cases at the selected position(s)</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="edit_find">
-            <property name="stock-id">gtk-find</property>
-            <property name="name">edit_find</property>
-            <property name="label" translatable="yes">_Find...</property>
-          </object>
-        </child>
         <child>
           <object class="GtkAction" id="view">
             <property name="name">view</property>
           <separator/>
           <menuitem action="file_quit"/>
         </menu>
-        <menu action="edit">
-          <menuitem action="action_insert-variable"/>
-          <menuitem action="edit_insert-case"/>
-          <menuitem action="edit_goto-case"/>
-          <separator/>
-          <menuitem action="edit_cut"/>
-          <menuitem action="edit_copy"/>
-          <menuitem action="edit_paste"/>
-          <menuitem action="edit_clear-variables"/>
-          <menuitem action="edit_clear-cases"/>
-          <separator/>
-          <menuitem action="edit_find"/>
-        </menu>
+       <placeholder name="DataSheetEditMenu"/>
+       <placeholder name="VarSheetEditMenu"/>
         <menu action="view">
           <menuitem action="view_statusbar"/>
           <separator/>
         </menu>
       </menubar>
       <toolbar action="toolbar">
-        <placeholder name="tool-items">
-          <toolitem name="toolbar_open" action="file_open"/>
-          <toolitem name="toolbar_save" action="file_save"/>
-         <separator/>
-          <toolitem name="toolbar_goto-case" action="edit_goto-case"/>
-          <toolitem name="toolbar_goto-variable" action="utilities_variables"/>
-         <separator/>
-          <toolitem name="toolbar_find" action="edit_find"/>
-         <separator/>
-         <toolitem name="toolbar_insert-cases" action="edit_insert-case"/>
-         <toolitem name="toolbar_insert-variable" action="action_insert-variable"/>
-         <separator/>
-         <toolitem name="toolbar_split-file" action="data_split-file"/>
-         <toolitem name="toolbar_weight-cases" action="data_weight-cases"/>
-         <toolitem name="toolbar_select-cases" action="data_select-cases"/>
-         <separator/>
-         <toolitem name="toolbar_select-cases" action="view_value-labels"/>
-        </placeholder>
-      </toolbar>
-      <popup name="datasheet-variable-popup">
-       <menuitem action="action_insert-variable"/>
-       <separator/>
-       <menuitem action="edit_clear-variables"/>
+       <toolitem name="toolbar_open" action="file_open"/>
+       <toolitem name="toolbar_save" action="file_save"/>
        <separator/>
-        <menuitem action="sort-up"/>
-        <menuitem action="sort-down"/>
-      </popup>
-      <popup name="varsheet-variable-popup">
-       <menuitem action="action_insert-variable"/>
+       <placeholder name="DataSheetToolItems"/>
+       <placeholder name="VarSheetToolItems"/>
        <separator/>
-       <menuitem action="edit_clear-variables"/>
-      </popup>
-      <popup name="datasheet-cases-popup">
-       <menuitem action="edit_insert-case"/>
+       <toolitem name="toolbar_split-file" action="data_split-file"/>
+       <toolitem name="toolbar_weight-cases" action="data_weight-cases"/>
+       <toolitem name="toolbar_select-cases" action="data_select-cases"/>
        <separator/>
-       <menuitem action="edit_clear-cases"/>
-      </popup>
+       <toolitem name="toolbar_select-cases" action="view_value-labels"/>
+      </toolbar>
     </ui>
   </object>
   <!-- interface-requires gtk+ 2.6 -->
   <object class="GtkMenuBar" constructor="uimanager1" id="menubar">
     <property name="visible">True</property>
   </object>
-  <object class="GtkMenu" constructor="uimanager1" id="datasheet-variable-popup">
-    <property name="visible">True</property>
-  </object>
-  <object class="GtkMenu" constructor="uimanager1" id="varsheet-variable-popup">
-    <property name="visible">True</property>
-  </object>
-  <object class="GtkMenu" constructor="uimanager1" id="datasheet-cases-popup">
-    <property name="visible">True</property>
-  </object>
   <object class="GtkHandleBox" id="handlebox1">
     <property name="visible">True</property>
     <child>
diff --git a/src/ui/gui/data-sheet.ui b/src/ui/gui/data-sheet.ui
new file mode 100644 (file)
index 0000000..c97160d
--- /dev/null
@@ -0,0 +1,147 @@
+<?xml version="1.0"?>
+<interface>
+  <object class="GtkUIManager" id="data_sheet_uim">
+    <ui>
+      <menubar name="menubar">
+       <placeholder name="DataSheetEditMenu">
+         <menu name="edit" action="edit2">
+           <menuitem action="edit_insert-variable"/>
+           <menuitem action="edit_insert-case"/>
+           <menuitem action="edit_goto-variable"/>
+           <menuitem action="edit_goto-case"/>
+           <separator/>
+           <menuitem action="edit_cut"/>
+           <menuitem action="edit_copy"/>
+           <menuitem action="edit_paste"/>
+           <menuitem action="edit_clear-variables"/>
+           <menuitem action="edit_clear-cases"/>
+           <separator/>
+           <menuitem action="edit_find"/>
+         </menu>
+       </placeholder>
+      </menubar>
+      <toolbar name="toolbar">
+       <placeholder name="DataSheetToolItems">
+         <toolitem name="toolbar_goto-variable" action="edit_goto-variable"/>
+         <toolitem name="toolbar_goto-case" action="edit_goto-case"/>
+         <toolitem name="toolbar_find" action="edit_find"/>
+         <toolitem name="toolbar_insert-cases" action="edit_insert-case"/>
+         <toolitem name="toolbar_insert-variable" action="edit_insert-variable"/>
+       </placeholder>
+      </toolbar>
+      <popup name="datasheet-variable-popup">
+       <menuitem action="edit_insert-variable"/>
+       <separator/>
+       <menuitem action="edit_clear-variables"/>
+       <separator/>
+        <menuitem action="sort-up"/>
+        <menuitem action="sort-down"/>
+      </popup>
+      <popup name="datasheet-cases-popup">
+       <menuitem action="edit_insert-case"/>
+       <separator/>
+       <menuitem action="edit_clear-cases"/>
+      </popup>
+    </ui>
+    <child>
+      <object class="GtkActionGroup" id="actiongroup3">
+        <child>
+          <object class="GtkAction" id="edit2">
+            <property name="name">edit</property>
+            <property name="label" translatable="yes">_Edit</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="edit_insert-variable">
+            <property name="name">edit_insert-variable</property>
+            <property name="label" translatable="yes">Insert Variable</property>
+            <property name="tooltip" translatable="yes">Create a new variable at the current position</property>
+           <property name="stock-id">pspp-insert-variable</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="edit_insert-case">
+            <property name="name">edit_insert-case</property>
+            <property name="label" translatable="yes">Insert Cases</property>
+            <property name="tooltip" translatable="yes">Create a new case at the current position</property>
+           <property name="stock-id">pspp-insert-case</property>
+          </object>
+        </child>
+        <child>
+          <object class="PsppireDialogActionVarInfo" id="edit_goto-variable">
+            <property name="name">edit_goto-variable</property>
+            <property name="label" translatable="yes">Go To Variable...</property>
+           <property name="tooltip" translatable="yes">Jump to variable</property>
+           <property name="stock-id">pspp-goto-variable</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="edit_goto-case">
+            <property name="label" translatable="yes">Go To Case...</property>
+            <property name="name">edit_goto-case</property>
+            <property name="tooltip" translatable="yes">Jump to a case in the data sheet</property>
+           <property name="stock-id">gtk-jump-to</property>
+
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="edit_cut">
+            <property name="stock-id">gtk-cut</property>
+            <property name="name">edit_cut</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="edit_copy">
+            <property name="stock-id">gtk-copy</property>
+            <property name="name">edit_copy</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="edit_paste">
+            <property name="stock-id">gtk-paste</property>
+            <property name="name">edit_paste</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="edit_clear-variables">
+            <property name="name">edit_clear-variables</property>
+            <property name="label" translatable="yes">Cl_ear Variables</property>
+           <property name="tooltip" translatable="yes">Delete the variables at the selected position(s)</property>
+            <property name="stock-id">gtk-clear</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="edit_clear-cases">
+            <property name="name">edit_clear-cases</property>
+            <property name="stock-id">gtk-clear</property>
+            <property name="label" translatable="yes">_Clear Cases</property>
+            <property name="tooltip" translatable="yes">Delete the cases at the selected position(s)</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="edit_find">
+            <property name="stock-id">gtk-find</property>
+            <property name="name">edit_find</property>
+            <property name="label" translatable="yes">_Find...</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="sort-up">
+            <property name="stock-id">gtk-sort-ascending</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="sort-down">
+            <property name="stock-id">gtk-sort-descending</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkMenu" constructor="data_sheet_uim" id="datasheet-cases-popup">
+    <property name="visible">True</property>
+  </object>
+  <object class="GtkMenu" constructor="data_sheet_uim" id="datasheet-variable-popup">
+    <property name="visible">True</property>
+  </object>
+</interface>
index 0f856f94629d29c58383d9a1fc3d078015b47bf4..1bdf35e422cd86811168a7a26d03aad439d13d71 100644 (file)
@@ -20,37 +20,35 @@ which match particular strings */
 
 #include <config.h>
 
-#include "find-dialog.h"
-#include "psppire-selector.h"
-#include "psppire-dialog.h"
-#include "builder-wrapper.h"
-#include "helper.h"
-#include "psppire-data-window.h"
-#include "dict-display.h"
-#include <data/value.h>
-#include <data/format.h>
-#include <data/datasheet.h>
-#include <data/data-in.h>
-#include "psppire-data-store.h"
 #include <ctype.h>
-#include <sys/types.h>
-#include <regex.h>
-#include <libpspp/cast.h>
-#include <libpspp/message.h>
-
 #include <gtk/gtk.h>
+#include <regex.h>
 #include <stdlib.h>
+#include <sys/types.h>
 
-#include "xalloc.h"
+#include "data/data-in.h"
+#include "data/datasheet.h"
+#include "data/format.h"
+#include "data/value.h"
+#include "libpspp/cast.h"
+#include "libpspp/message.h"
+#include "ui/gui/builder-wrapper.h"
+#include "ui/gui/dict-display.h"
+#include "ui/gui/find-dialog.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/psppire-data-sheet.h"
+#include "ui/gui/psppire-data-store.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dialog.h"
+#include "ui/gui/psppire-selector.h"
+
+#include "gl/xalloc.h"
 
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
 
-/* FIXME: These shouldn't be here */
-#include "psppire-var-store.h"
-
 struct find_dialog
 {
   GtkBuilder *xml;
@@ -102,12 +100,13 @@ refresh (GObject *obj, const struct find_dialog *fd)
 static void
 do_find (GObject *obj, const struct find_dialog *fd)
 {
+  PsppireDataSheet *data_sheet;
   casenumber x = -1;
   gint column = -1;
   glong row;
 
-  g_object_get (fd->de->data_editor, "current-case", &row, NULL);
-
+  data_sheet = psppire_data_editor_get_active_data_sheet (fd->de->data_editor);
+  row = psppire_data_sheet_get_selected_case (data_sheet);
   if ( row < 0 )
     row = 0;
 
@@ -119,10 +118,8 @@ do_find (GObject *obj, const struct find_dialog *fd)
       gtk_notebook_set_current_page (GTK_NOTEBOOK (fd->de->data_editor),
                                     PSPPIRE_DATA_EDITOR_DATA_VIEW);
 
-      g_object_set (fd->de->data_editor,
-                   "current-case", x,
-                   "current-variable", column,
-                   NULL);
+      psppire_data_sheet_goto_case (data_sheet, x);
+      psppire_data_sheet_show_variable (data_sheet, column);
     }
 
 }
@@ -196,7 +193,6 @@ find_dialog (PsppireDataWindow *de)
 
   GtkWidget *buttonbox;
 
-  PsppireVarStore *vs ;
   PsppireDataStore *ds ;
 
   fd.xml = builder_new ("find.ui");
@@ -215,12 +211,10 @@ find_dialog (PsppireDataWindow *de)
   selector = get_widget_assert (fd.xml, "find-selector");
 
   g_object_get (de->data_editor,
-               "var-store", &vs,
+               "dictionary", &fd.dict,
                "data-store", &ds,
                NULL);
 
-  g_object_get (vs, "dictionary", &fd.dict, NULL);
-
   fd.data = ds->datasheet;
 
   fd.variable_entry        = get_widget_assert (fd.xml, "find-variable-entry");
index 8db8ddc88b1abb27efc4e1b04d18d9741ea368a0..32871e0a8b9fd5cef0535169fe07bfd2a6def52e 100644 (file)
@@ -28,7 +28,6 @@
 #include <ui/gui/dict-display.h>
 #include <ui/gui/builder-wrapper.h>
 #include <ui/gui/psppire-dialog.h>
-#include <ui/gui/psppire-var-store.h>
 #include "executor.h"
 #include "helper.h"
 
@@ -468,10 +467,6 @@ frequencies_dialog (PsppireDataWindow *de)
   GtkWidget *charts_button = get_widget_assert (xml, "charts-button");
   GtkWidget *stats_treeview = get_widget_assert (xml, "stats-treeview");
 
-  PsppireVarStore *vs = NULL;
-
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
   put_checkbox_items_in_treeview (GTK_TREE_VIEW(stats_treeview),
                                  B_FS_DEFAULT,
                                  N_FREQUENCY_STATS,
@@ -481,7 +476,7 @@ frequencies_dialog (PsppireDataWindow *de)
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_get (vs, "dictionary", &fd.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &fd.dict, NULL);
   g_object_set (source, "model", fd.dict, NULL);
 
   fd.stat_vars = GTK_TREE_VIEW (dest);
index 1b85a53665e7817abfd169d61be3a84ee677b735..282f41636883c21315d1f21d6ed08cfa1903a922 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2012  Free Software Foundation
+   Copyright (C) 2007, 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 
 static void
-refresh (const PsppireDataWindow *de, GtkBuilder *xml)
+refresh (PsppireDataSheet *ds, GtkBuilder *xml)
 {
-  PsppireDataStore *ds = NULL;
+  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (ds);
   casenumber case_count ;
 
   GtkWidget *case_num_entry = get_widget_assert (xml, "goto-case-case-num-entry");
 
-  g_object_get (de->data_editor, "data-store", &ds, NULL);
-
-  case_count =  psppire_data_store_get_case_count (ds);
+  case_count =  psppire_data_store_get_case_count (data_store);
 
   gtk_spin_button_set_range (GTK_SPIN_BUTTON (case_num_entry), 1, case_count);
 }
 
 void
-goto_case_dialog (PsppireDataWindow *de)
+goto_case_dialog (PsppireDataSheet *ds)
 {
+  GtkWindow *top_level;
   gint response;
   GtkBuilder *xml = builder_new ("goto-case.ui");
-
   GtkWidget *dialog = get_widget_assert   (xml, "goto-case-dialog");
 
-  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
+  top_level = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (ds)));
+  gtk_window_set_transient_for (GTK_WINDOW (dialog), top_level);
 
-  refresh (de, xml);
+  refresh (ds, xml);
 
   response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
 
   if ( response == PSPPIRE_RESPONSE_GOTO )
     {
+      PsppireDataStore *data_store = psppire_data_sheet_get_data_store (ds);
       glong case_num;
       GtkWidget *case_num_entry =
        get_widget_assert (xml, "goto-case-case-num-entry");
@@ -61,6 +61,8 @@ goto_case_dialog (PsppireDataWindow *de)
       case_num = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (case_num_entry))
        - FIRST_CASE_NUMBER ;
 
-      g_object_set (de->data_editor, "current-case", case_num, NULL);
+      if (case_num >= 0
+          && case_num < psppire_data_store_get_case_count (data_store))
+        psppire_data_sheet_goto_case (ds, case_num);
     }
 }
index 9435cb2c1f44ee805f1c4155a90ea7155c31ac2c..e7c70eee258fec818241c6c6ea232d72b4f24f70 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2010  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -17,8 +17,8 @@
 #ifndef __GOTO_CASE_DIALOG_H
 #define __GOTO_CASE_DIALOG_H
 
-#include "psppire-data-window.h"
+#include "psppire-data-sheet.h"
 
-void goto_case_dialog (PsppireDataWindow * data);
+void goto_case_dialog (PsppireDataSheet *ds);
 
 #endif
index 171894527cc626c0ae541736d28117b869d2a6db..867583ade1590ca90e2bd07b8e9557219d7e21e7 100644 (file)
@@ -126,14 +126,11 @@ k_related_dialog (PsppireDataWindow *dw)
   struct k_related_dialog krd;
 
   GtkBuilder *xml = builder_new ("k-related.ui");
-  PsppireVarStore *vs;
 
   GtkWidget *dialog = get_widget_assert   (xml, "k-related-dialog");
 
   GtkWidget *dict_view = get_widget_assert   (xml, "dict-view");
 
-  g_object_get (dw->data_editor, "var-store", &vs, NULL);
-
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (dw));
 
   krd.var_view  = get_widget_assert (xml, "variables-treeview");
@@ -142,7 +139,7 @@ k_related_dialog (PsppireDataWindow *dw)
   krd.kendal =  get_widget_assert (xml, "kendal-checkbutton");
   krd.cochran =  get_widget_assert (xml, "cochran-checkbutton");
 
-  g_object_get (vs, "dictionary", &krd.dict, NULL);
+  g_object_get (dw->data_editor, "dictionary", &krd.dict, NULL);
   g_object_set (dict_view,
                "model", krd.dict, 
                "predicate", var_is_numeric,
index afdac0817fbb71546e8482926242dc4d9674c5b2..ba27e58bf33edd3904bf5578d8085b995619afd4 100644 (file)
@@ -106,8 +106,6 @@ ks_one_sample_dialog (PsppireDataWindow *dw)
   struct ks_one_sample fd;
   gint response;
 
-  PsppireVarStore *vs;
-
   GtkWidget *dialog ;
   GtkWidget *source ;
 
@@ -128,11 +126,9 @@ ks_one_sample_dialog (PsppireDataWindow *dw)
 
   fd.variables = get_widget_assert   (fd.xml, "psppire-var-view1");
 
-  g_object_get (fd.de->data_editor, "var-store", &vs, NULL);
-
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fd.de));
 
-  g_object_get (vs, "dictionary", &fd.dict, NULL);
+  g_object_get (fd.de->data_editor, "dictionary", &fd.dict, NULL);
   g_object_set (source, "model", fd.dict,
                "predicate", var_is_numeric,
                NULL);
index 1f85ee6d7055428446408994273570feb62872ff..f3e4042b1c0cb324b45c457bce389e75f9d6f854 100644 (file)
@@ -5,6 +5,7 @@ BOOLEAN:BOOLEAN,BOOLEAN,BOOLEAN
 BOOLEAN:BOXED
 BOOLEAN:ENUM
 BOOLEAN:ENUM,INT
+BOOLEAN:INT
 BOOLEAN:BOXED,BOXED
 BOOLEAN:BOXED,POINTER
 BOOLEAN:OBJECT
index ac3bcd54e55674896381ab77f234ded7af0998bb..c26f6114eacd5e9f1a5011b91752bb3b37d810c6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011  Free Software Foundation
+   Copyright (C) 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@
 #include "psppire-var-view.h"
 
 #include "psppire-dict.h"
-#include "psppire-var-store.h"
 
 #include "dialog-common.h"
 #include "psppire-dialog.h"
index 387fa4f2ec831fba2be43ad388db3a5b06cd98ff..7992b94c71c91c7637c2252fc51b1620c42e74de 100644 (file)
@@ -19,7 +19,6 @@
 #include <gtk/gtk.h>
 #include "oneway-anova-dialog.h"
 #include "psppire-dict.h"
-#include "psppire-var-store.h"
 #include "psppire-var-view.h"
 #include "builder-wrapper.h"
 #include "psppire-data-window.h"
@@ -126,8 +125,6 @@ oneway_anova_dialog (PsppireDataWindow *de)
 {
   gint response;
 
-  PsppireVarStore *vs = NULL;
-
   struct oneway_anova_dialog ow;
 
   GtkBuilder *builder = builder_new ("oneway.ui");
@@ -156,9 +153,7 @@ oneway_anova_dialog (PsppireDataWindow *de)
   ow.homogeneity =
     GTK_TOGGLE_BUTTON (get_widget_assert (builder, "checkbutton2"));
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
-  g_object_get (vs, "dictionary", &ow.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &ow.dict, NULL);
 
   ow.dialog =
     GTK_WINDOW (get_widget_assert (builder, "oneway-anova-dialog"));
index 2b61903fd9aed9ff43fdfb15c351b3d25ea06d69..3cf2aa31d3b71e91c8305b460c585e0a1a6c8286 100644 (file)
@@ -27,7 +27,6 @@
 #include "psppire-var-view.h"
 
 #include "psppire-dict.h"
-#include "psppire-var-store.h"
 
 #include "dialog-common.h"
 #include "psppire-dialog.h"
@@ -147,8 +146,6 @@ two_sample_dialog_create (PsppireDataWindow *de)
   GtkWidget *selector ;
   struct paired_samples_dialog *tt_d = g_malloc (sizeof *tt_d);
 
-  PsppireVarStore *vs = NULL;
-
   tt_d->xml = builder_new ("paired-samples.ui");
 
   dict_view = get_widget_assert (tt_d->xml, "paired-samples-t-test-treeview1");
@@ -157,9 +154,7 @@ two_sample_dialog_create (PsppireDataWindow *de)
 
   tt_d->dialog = get_widget_assert (tt_d->xml, "t-test-paired-samples-dialog");
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
-  g_object_get (vs, "dictionary", &tt_d->dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &tt_d->dict, NULL);
   tt_d->pairs_treeview =
    get_widget_assert (tt_d->xml, "paired-samples-t-test-treeview2");
 
index abb8366c6aee107a68e8cd3655e5bbdb630bc497..80e15ccf13d91f8c276e5f638111aec4de46ef3a 100644 (file)
@@ -157,6 +157,7 @@ struct _PsppSheetViewPrivate
 
   /* Cell Editing */
   PsppSheetViewColumn *edited_column;
+  gint edited_row;
 
   /* Selection information */
   PsppSheetSelection *selection;
@@ -239,7 +240,7 @@ struct _PsppSheetViewPrivate
 
   /* Grid and tree lines */
   PsppSheetViewGridLines grid_lines;
-  GdkGC *grid_line_gc;
+  GdkGC *grid_line_gc[5];
 
   /* Special cells. */
   PsppSheetViewSpecialCells special_cells;
index eb7654fab90d904c5cecefaf7b03f280ee06114c..c569d20403c201d967cbe7832349f71452141901 100644 (file)
@@ -160,8 +160,7 @@ static void     pspp_sheet_view_get_property         (GObject         *object,
                                                    GValue          *value,
                                                    GParamSpec      *pspec);
 
-/* gtkobject signals */
-static void     pspp_sheet_view_destroy              (GtkObject        *object);
+static void     pspp_sheet_view_dispose              (GObject        *object);
 
 /* gtkwidget signals */
 static void     pspp_sheet_view_realize              (GtkWidget        *widget);
@@ -429,6 +428,8 @@ static void     remove_scroll_timeout                (PsppSheetView *tree_view);
 
 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
 
+static GtkBindingSet *edit_bindings;
+
 \f
 
 /* GType Methods
@@ -442,15 +443,17 @@ static void
 pspp_sheet_view_class_init (PsppSheetViewClass *class)
 {
   GObjectClass *o_class;
-  GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;
   GtkContainerClass *container_class;
-  GtkBindingSet *binding_set;
+  GtkBindingSet *binding_set[2];
+  int i;
+
+  binding_set[0] = gtk_binding_set_by_class (class);
 
-  binding_set = gtk_binding_set_by_class (class);
+  binding_set[1] = gtk_binding_set_new ("PsppSheetViewEditing");
+  edit_bindings = binding_set[1];
 
   o_class = (GObjectClass *) class;
-  object_class = (GtkObjectClass *) class;
   widget_class = (GtkWidgetClass *) class;
   container_class = (GtkContainerClass *) class;
 
@@ -458,9 +461,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
   o_class->set_property = pspp_sheet_view_set_property;
   o_class->get_property = pspp_sheet_view_get_property;
   o_class->finalize = pspp_sheet_view_finalize;
-
-  /* GtkObject signals */
-  object_class->destroy = pspp_sheet_view_destroy;
+  o_class->dispose = pspp_sheet_view_dispose;
 
   /* GtkWidget signals */
   widget_class->map = pspp_sheet_view_map;
@@ -817,7 +818,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
 
   tree_view_signals[MOVE_CURSOR] =
     g_signal_new ("move-cursor",
-                 G_TYPE_FROM_CLASS (object_class),
+                 G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (PsppSheetViewClass, move_cursor),
                  NULL, NULL,
@@ -828,7 +829,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
 
   tree_view_signals[SELECT_ALL] =
     g_signal_new ("select-all",
-                 G_TYPE_FROM_CLASS (object_class),
+                 G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (PsppSheetViewClass, select_all),
                  NULL, NULL,
@@ -837,7 +838,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
 
   tree_view_signals[UNSELECT_ALL] =
     g_signal_new ("unselect-all",
-                 G_TYPE_FROM_CLASS (object_class),
+                 G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (PsppSheetViewClass, unselect_all),
                  NULL, NULL,
@@ -846,7 +847,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
 
   tree_view_signals[SELECT_CURSOR_ROW] =
     g_signal_new ("select-cursor-row",
-                 G_TYPE_FROM_CLASS (object_class),
+                 G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (PsppSheetViewClass, select_cursor_row),
                  NULL, NULL,
@@ -856,7 +857,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
 
   tree_view_signals[TOGGLE_CURSOR_ROW] =
     g_signal_new ("toggle-cursor-row",
-                 G_TYPE_FROM_CLASS (object_class),
+                 G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (PsppSheetViewClass, toggle_cursor_row),
                  NULL, NULL,
@@ -865,7 +866,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
 
   tree_view_signals[START_INTERACTIVE_SEARCH] =
     g_signal_new ("start-interactive-search",
-                 G_TYPE_FROM_CLASS (object_class),
+                 G_TYPE_FROM_CLASS (o_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (PsppSheetViewClass, start_interactive_search),
                  NULL, NULL,
@@ -873,110 +874,113 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
                  G_TYPE_BOOLEAN, 0);
 
   /* Key bindings */
-  pspp_sheet_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
-                                 GTK_MOVEMENT_DISPLAY_LINES, -1);
-  pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
-                                 GTK_MOVEMENT_DISPLAY_LINES, -1);
+  for (i = 0; i < 2; i++)
+    {
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Up, 0, TRUE,
+                                        GTK_MOVEMENT_DISPLAY_LINES, -1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Up, 0, TRUE,
+                                        GTK_MOVEMENT_DISPLAY_LINES, -1);
 
-  pspp_sheet_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
-                                 GTK_MOVEMENT_DISPLAY_LINES, 1);
-  pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
-                                 GTK_MOVEMENT_DISPLAY_LINES, 1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Down, 0, TRUE,
+                                        GTK_MOVEMENT_DISPLAY_LINES, 1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Down, 0, TRUE,
+                                        GTK_MOVEMENT_DISPLAY_LINES, 1);
 
-  pspp_sheet_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
-                                 GTK_MOVEMENT_DISPLAY_LINES, -1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_p, GDK_CONTROL_MASK, FALSE,
+                                        GTK_MOVEMENT_DISPLAY_LINES, -1);
 
-  pspp_sheet_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
-                                 GTK_MOVEMENT_DISPLAY_LINES, 1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_n, GDK_CONTROL_MASK, FALSE,
+                                        GTK_MOVEMENT_DISPLAY_LINES, 1);
 
-  pspp_sheet_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
-                                 GTK_MOVEMENT_BUFFER_ENDS, -1);
-  pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
-                                 GTK_MOVEMENT_BUFFER_ENDS, -1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Home, 0, TRUE,
+                                        GTK_MOVEMENT_BUFFER_ENDS, -1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Home, 0, TRUE,
+                                        GTK_MOVEMENT_BUFFER_ENDS, -1);
 
-  pspp_sheet_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
-                                 GTK_MOVEMENT_BUFFER_ENDS, 1);
-  pspp_sheet_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
-                                 GTK_MOVEMENT_BUFFER_ENDS, 1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_End, 0, TRUE,
+                                        GTK_MOVEMENT_BUFFER_ENDS, 1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_End, 0, TRUE,
+                                        GTK_MOVEMENT_BUFFER_ENDS, 1);
 
-  pspp_sheet_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
-                                 GTK_MOVEMENT_PAGES, -1);
-  pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
-                                 GTK_MOVEMENT_PAGES, -1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Up, 0, TRUE,
+                                        GTK_MOVEMENT_PAGES, -1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Up, 0, TRUE,
+                                        GTK_MOVEMENT_PAGES, -1);
 
-  pspp_sheet_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
-                                 GTK_MOVEMENT_PAGES, 1);
-  pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
-                                 GTK_MOVEMENT_PAGES, 1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Down, 0, TRUE,
+                                        GTK_MOVEMENT_PAGES, 1);
+      pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Down, 0, TRUE,
+                                        GTK_MOVEMENT_PAGES, 1);
 
 
-  gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move-cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, 1);
+      gtk_binding_entry_add_signal (binding_set[i], GDK_Right, 0, "move-cursor", 2,
+                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+                                    G_TYPE_INT, 1);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move-cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, -1);
+      gtk_binding_entry_add_signal (binding_set[i], GDK_Left, 0, "move-cursor", 2,
+                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+                                    G_TYPE_INT, -1);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move-cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, 1);
+      gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, 0, "move-cursor", 2,
+                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+                                    G_TYPE_INT, 1);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move-cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, -1);
+      gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, 0, "move-cursor", 2,
+                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+                                    G_TYPE_INT, -1);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
-                                "move-cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, 1);
+      gtk_binding_entry_add_signal (binding_set[i], GDK_Right, GDK_CONTROL_MASK,
+                                    "move-cursor", 2,
+                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+                                    G_TYPE_INT, 1);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
-                                "move-cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, -1);
+      gtk_binding_entry_add_signal (binding_set[i], GDK_Left, GDK_CONTROL_MASK,
+                                    "move-cursor", 2,
+                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+                                    G_TYPE_INT, -1);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
-                                "move-cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, 1);
+      gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, GDK_CONTROL_MASK,
+                                    "move-cursor", 2,
+                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+                                    G_TYPE_INT, 1);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
-                                "move-cursor", 2,
-                               G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
-                               G_TYPE_INT, -1);
+      gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, GDK_CONTROL_MASK,
+                                    "move-cursor", 2,
+                                    G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+                                    G_TYPE_INT, -1);
+
+      gtk_binding_entry_add_signal (binding_set[i], GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
+
+      gtk_binding_entry_add_signal (binding_set[i], GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
+    }
 
-  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
+  gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
+  gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
+  gtk_binding_entry_add_signal (binding_set[0], GDK_a, GDK_CONTROL_MASK, "select-all", 0);
+  gtk_binding_entry_add_signal (binding_set[0], GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
+  gtk_binding_entry_add_signal (binding_set[0], GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
+  gtk_binding_entry_add_signal (binding_set[0], GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
+  gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
+  gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1,
+  gtk_binding_entry_add_signal (binding_set[0], GDK_space, 0, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1,
+  gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, 0, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1,
+  gtk_binding_entry_add_signal (binding_set[0], GDK_Return, 0, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1,
+  gtk_binding_entry_add_signal (binding_set[0], GDK_ISO_Enter, 0, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
-  gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1,
+  gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Enter, 0, "select-cursor-row", 1,
                                G_TYPE_BOOLEAN, TRUE);
 
-  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
-
-  gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
-
-  gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
+  gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, 0, "select-cursor-parent", 0);
+  gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
 
   g_type_class_add_private (o_class, sizeof (PsppSheetViewPrivate));
 }
@@ -1051,6 +1055,8 @@ pspp_sheet_view_init (PsppSheetView *tree_view)
   tree_view->priv->anchor_column = NULL;
 
   tree_view->priv->button_style = NULL;
+
+  tree_view->dispose_has_run = FALSE;
 }
 
 \f
@@ -1208,9 +1214,41 @@ pspp_sheet_view_get_property (GObject    *object,
 }
 
 static void
-pspp_sheet_view_finalize (GObject *object)
+pspp_sheet_view_dispose (GObject *object)
 {
-  G_OBJECT_CLASS (pspp_sheet_view_parent_class)->finalize (object);
+  PsppSheetView *tree_view = PSPP_SHEET_VIEW (object);
+
+  if (tree_view->dispose_has_run)
+    return;
+
+  tree_view->dispose_has_run = TRUE;
+
+  if (tree_view->priv->selection != NULL)
+    {
+      _pspp_sheet_selection_set_tree_view (tree_view->priv->selection, NULL);
+      g_object_unref (tree_view->priv->selection);
+      tree_view->priv->selection = NULL;
+    }
+
+  if (tree_view->priv->hadjustment)
+    {
+      g_object_unref (tree_view->priv->hadjustment);
+      tree_view->priv->hadjustment = NULL;
+    }
+  if (tree_view->priv->vadjustment)
+    {
+      g_object_unref (tree_view->priv->vadjustment);
+      tree_view->priv->vadjustment = NULL;
+    }
+
+  if (tree_view->priv->button_style)
+    {
+      g_object_unref (tree_view->priv->button_style);
+      tree_view->priv->button_style = NULL;
+    }
+
+
+  G_OBJECT_CLASS (pspp_sheet_view_parent_class)->dispose (object);
 }
 
 \f
@@ -1224,14 +1262,10 @@ pspp_sheet_view_buildable_add_child (GtkBuildable *tree_view,
   pspp_sheet_view_append_column (PSPP_SHEET_VIEW (tree_view), PSPP_SHEET_VIEW_COLUMN (child));
 }
 
-/* GtkObject Methods
- */
-
 static void
-pspp_sheet_view_destroy (GtkObject *object)
+pspp_sheet_view_finalize (GObject *object)
 {
   PsppSheetView *tree_view = PSPP_SHEET_VIEW (object);
-  GList *list;
 
   pspp_sheet_view_stop_editing (tree_view, TRUE);
 
@@ -1241,27 +1275,9 @@ pspp_sheet_view_destroy (GtkObject *object)
       tree_view->priv->selected = NULL;
     }
 
-  if (tree_view->priv->columns != NULL)
-    {
-      list = tree_view->priv->columns;
-      while (list)
-       {
-         PsppSheetViewColumn *column;
-         column = PSPP_SHEET_VIEW_COLUMN (list->data);
-         list = list->next;
-         pspp_sheet_view_remove_column (tree_view, column);
-       }
-      tree_view->priv->columns = NULL;
-    }
 
   tree_view->priv->prelight_node = -1;
 
-  if (tree_view->priv->selection != NULL)
-    {
-      _pspp_sheet_selection_set_tree_view (tree_view->priv->selection, NULL);
-      g_object_unref (tree_view->priv->selection);
-      tree_view->priv->selection = NULL;
-    }
 
   if (tree_view->priv->scroll_to_path != NULL)
     {
@@ -1328,24 +1344,8 @@ pspp_sheet_view_destroy (GtkObject *object)
 
   pspp_sheet_view_set_model (tree_view, NULL);
 
-  if (tree_view->priv->hadjustment)
-    {
-      g_object_unref (tree_view->priv->hadjustment);
-      tree_view->priv->hadjustment = NULL;
-    }
-  if (tree_view->priv->vadjustment)
-    {
-      g_object_unref (tree_view->priv->vadjustment);
-      tree_view->priv->vadjustment = NULL;
-    }
-
-  if (tree_view->priv->button_style)
-    {
-      g_object_unref (tree_view->priv->button_style);
-      tree_view->priv->button_style = NULL;
-    }
 
-  GTK_OBJECT_CLASS (pspp_sheet_view_parent_class)->destroy (object);
+  G_OBJECT_CLASS (pspp_sheet_view_parent_class)->finalize (object);
 }
 
 \f
@@ -1420,6 +1420,7 @@ pspp_sheet_view_map (GtkWidget *widget)
 static void
 pspp_sheet_view_realize (GtkWidget *widget)
 {
+  gint i;
   PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
   GList *tmp_list;
   GdkWindowAttr attributes;
@@ -1501,15 +1502,24 @@ pspp_sheet_view_realize (GtkWidget *widget)
   pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
 
   install_presize_handler (tree_view); 
+
+  for (i = 0; i < 5; ++i)
+    {
+      tree_view->priv->grid_line_gc[i] = gdk_gc_new (widget->window);
+      gdk_gc_copy (tree_view->priv->grid_line_gc[i], widget->style->text_aa_gc[i]);
+    }
 }
 
 static void
 pspp_sheet_view_unrealize (GtkWidget *widget)
 {
+  gint x;
   PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
   PsppSheetViewPrivate *priv = tree_view->priv;
   GList *list;
 
+  GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->unrealize (widget);
+
   if (priv->scroll_timeout != 0)
     {
       g_source_remove (priv->scroll_timeout);
@@ -1571,13 +1581,21 @@ pspp_sheet_view_unrealize (GtkWidget *widget)
       priv->drag_highlight_window = NULL;
     }
 
-  if (priv->grid_line_gc)
+  for (x = 0 ; x < 5 ; ++x)
+    g_object_unref (priv->grid_line_gc[x]);
+
+  if (tree_view->priv->columns != NULL)
     {
-      g_object_unref (priv->grid_line_gc);
-      priv->grid_line_gc = NULL;
+      list = tree_view->priv->columns;
+      while (list)
+       {
+         PsppSheetViewColumn *column;
+         column = PSPP_SHEET_VIEW_COLUMN (list->data);
+         list = list->next;
+         pspp_sheet_view_remove_column (tree_view, column);
+       }
+      tree_view->priv->columns = NULL;
     }
-
-  GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->unrealize (widget);
 }
 
 /* GtkWidget::size_request helper */
@@ -3727,7 +3745,7 @@ pspp_sheet_view_draw_grid_lines (PsppSheetView    *tree_view,
       if (current_x - 1 >= event->area.x
           && current_x - 1 < event->area.x + event->area.width)
         gdk_draw_line (event->window,
-                       tree_view->priv->grid_line_gc,
+                       tree_view->priv->grid_line_gc[GTK_WIDGET(tree_view)->state],
                        current_x - 1, min_y,
                        current_x - 1, max_y - min_y);
     }
@@ -4110,14 +4128,14 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
            {
              if (background_area.y > 0)
                gdk_draw_line (event->window,
-                              tree_view->priv->grid_line_gc,
+                              tree_view->priv->grid_line_gc[widget->state],
                               background_area.x, background_area.y,
                               background_area.x + background_area.width,
                               background_area.y);
 
              if (y_offset + max_height >= event->area.height)
                gdk_draw_line (event->window,
-                              tree_view->priv->grid_line_gc,
+                              tree_view->priv->grid_line_gc[widget->state],
                               background_area.x, background_area.y + max_height,
                               background_area.x + background_area.width,
                               background_area.y + max_height);
@@ -5342,6 +5360,9 @@ do_presize_handler (PsppSheetView *tree_view)
   validate_visible_area (tree_view);
   tree_view->priv->presize_handler_timer = 0;
 
+  if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
+    return FALSE;
+
   gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
 
   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
@@ -6806,9 +6827,18 @@ pspp_sheet_view_style_set (GtkWidget *widget,
 
   if (gtk_widget_get_realized (widget))
     {
+      gint i;
+      PsppSheetViewPrivate *priv = PSPP_SHEET_VIEW (widget)->priv;
+
       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
+      for (i = 0; i < 5 ; ++i)
+       {
+         g_object_unref (priv->grid_line_gc[i]);
+         priv->grid_line_gc[i] = gdk_gc_new (widget->window);
+         gdk_gc_copy (priv->grid_line_gc[i], widget->style->text_aa_gc[i]);
+       }
 
       pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
     }
@@ -8026,7 +8056,7 @@ pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view,
       gboolean left, right;
 
       column = list->data;
-      if (column->visible == FALSE)
+      if (column->visible == FALSE || column->row_head)
        goto loop_end;
 
       pspp_sheet_view_column_cell_set_cell_data (column,
@@ -9206,7 +9236,8 @@ pspp_sheet_view_remove_column (PsppSheetView       *tree_view,
        }
 
       if (tree_view->priv->n_columns == 0 &&
-         pspp_sheet_view_get_headers_visible (tree_view))
+         pspp_sheet_view_get_headers_visible (tree_view) && 
+         tree_view->priv->header_window)
        gdk_window_hide (tree_view->priv->header_window);
 
       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
@@ -12060,6 +12091,154 @@ pspp_sheet_view_editable_clicked (GtkButton *button,
                                                sheet_view);
 }
 
+static gboolean
+is_all_selected (GtkWidget *widget)
+{
+  GtkEntryBuffer *buffer;
+  gint start_pos, end_pos;
+
+  if (!GTK_IS_ENTRY (widget))
+    return FALSE;
+
+  buffer = gtk_entry_get_buffer (GTK_ENTRY (widget));
+  return (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget),
+                                             &start_pos, &end_pos)
+          && start_pos == 0
+          && end_pos == gtk_entry_buffer_get_length (buffer));
+}
+
+static gboolean
+is_at_left (GtkWidget *widget)
+{
+  return (GTK_IS_ENTRY (widget)
+          && gtk_editable_get_position (GTK_EDITABLE (widget)) == 0);
+}
+
+static gboolean
+is_at_right (GtkWidget *widget)
+{
+  GtkEntryBuffer *buffer;
+  gint length;
+
+  if (!GTK_IS_ENTRY (widget))
+    return FALSE;
+
+  buffer = gtk_entry_get_buffer (GTK_ENTRY (widget));
+  length = gtk_entry_buffer_get_length (buffer);
+  return gtk_editable_get_position (GTK_EDITABLE (widget)) == length;
+}
+
+static gboolean
+pspp_sheet_view_event (GtkWidget *widget,
+                       GdkEventKey *event,
+                       PsppSheetView *tree_view)
+{
+  PsppSheetViewColumn *column;
+  GtkTreePath *path;
+  gboolean handled;
+  gboolean cancel;
+  guint keyval;
+  guint state;
+  gint row;
+
+  /* Intercept only key press events.
+     It would make sense to use "key-press-event" instead of "event", but
+     GtkEntry attaches its own signal handler to "key-press-event" that runs
+     before ours and overrides our desired behavior for GDK_Up and GDK_Down.
+  */
+  if (event->type != GDK_KEY_PRESS)
+    return FALSE;
+
+  if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK))
+    {
+      /* Pass through most keys that include modifiers. */
+      if ((event->keyval == GDK_Tab || event->keyval == GDK_ISO_Left_Tab)
+          && !(event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)))
+        {
+          /* Special case for Shift-Tab. */
+        }
+      else
+        return FALSE;
+    }
+
+  keyval = event->keyval;
+  state = event->state & ~(GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK);
+  cancel = FALSE;
+  switch (event->keyval)
+    {
+    case GDK_Left:      case GDK_KP_Left:
+      if (!is_all_selected (widget) && !is_at_left (widget))
+        return FALSE;
+      break;
+
+    case GDK_Right:     case GDK_KP_Right:
+      if (!is_all_selected (widget) && !is_at_right (widget))
+        return FALSE;
+      break;
+
+    case GDK_Up:        case GDK_KP_Up:
+    case GDK_Down:      case GDK_KP_Down:
+      break;
+
+    case GDK_Page_Up:   case GDK_KP_Page_Up:
+    case GDK_Page_Down: case GDK_KP_Page_Down:
+      break;
+
+    case GDK_Escape:
+      cancel = TRUE;
+      break;
+
+    case GDK_Return:
+      keyval = GDK_Down;
+      break;
+
+    case GDK_Tab:
+    case GDK_ISO_Left_Tab:
+      keyval = event->state & GDK_SHIFT_MASK ? GDK_Left : GDK_Right;
+      break;
+
+    default:
+      return FALSE;
+    }
+
+  row = tree_view->priv->edited_row;
+  column = tree_view->priv->edited_column;
+  path = gtk_tree_path_new_from_indices (row, -1);
+
+  pspp_sheet_view_stop_editing (tree_view, cancel);
+  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+
+  pspp_sheet_view_set_cursor (tree_view, path, column, FALSE);
+  gtk_tree_path_free (path);
+
+  handled = gtk_binding_set_activate (edit_bindings, keyval, state,
+                                      GTK_OBJECT (tree_view));
+  if (handled)
+    g_signal_stop_emission_by_name (widget, "event");
+
+  pspp_sheet_view_get_cursor (tree_view, &path, NULL);
+  pspp_sheet_view_start_editing (tree_view, path);
+  gtk_tree_path_free (path);
+
+  return handled;
+}
+
+static void
+pspp_sheet_view_override_cell_keypresses (GtkWidget *widget,
+                                          gpointer data)
+{
+  PsppSheetView *sheet_view = data;
+
+  g_signal_connect (widget, "event",
+                    G_CALLBACK (pspp_sheet_view_event),
+                    sheet_view);
+
+  if (GTK_IS_CONTAINER (widget))
+    gtk_container_foreach (GTK_CONTAINER (widget),
+                           pspp_sheet_view_override_cell_keypresses,
+                           data);
+}
+
 static void
 pspp_sheet_view_real_start_editing (PsppSheetView       *tree_view,
                                  PsppSheetViewColumn *column,
@@ -12072,10 +12251,15 @@ pspp_sheet_view_real_start_editing (PsppSheetView       *tree_view,
   PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection);
   gint pre_val = tree_view->priv->vadjustment->value;
   GtkRequisition requisition;
+  gint row;
+
+  g_return_if_fail (gtk_tree_path_get_depth (path) == 1);
 
   tree_view->priv->edited_column = column;
   _pspp_sheet_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
 
+  row = gtk_tree_path_get_indices (path)[0];
+  tree_view->priv->edited_row = row;
   pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE);
   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
 
@@ -12116,11 +12300,14 @@ pspp_sheet_view_real_start_editing (PsppSheetView       *tree_view,
                         G_CALLBACK (pspp_sheet_view_editable_button_press_event),
                         tree_view);
       g_object_set_data (G_OBJECT (cell_editable), "pspp-sheet-view-node",
-                         GINT_TO_POINTER (gtk_tree_path_get_indices (path)[0]));
+                         GINT_TO_POINTER (row));
       g_signal_connect (cell_editable, "clicked",
                         G_CALLBACK (pspp_sheet_view_editable_clicked),
                         tree_view);
     }
+
+  pspp_sheet_view_override_cell_keypresses (GTK_WIDGET (cell_editable),
+                                            tree_view);
 }
 
 void
@@ -12345,29 +12532,6 @@ pspp_sheet_view_set_grid_lines (PsppSheetView           *tree_view,
   old_grid_lines = priv->grid_lines;
   priv->grid_lines = grid_lines;
   
-  if (gtk_widget_get_realized (widget))
-    {
-      if (grid_lines == PSPP_SHEET_VIEW_GRID_LINES_NONE &&
-         priv->grid_line_gc)
-       {
-         g_object_unref (priv->grid_line_gc);
-         priv->grid_line_gc = NULL;
-       }
-      
-      if (grid_lines != PSPP_SHEET_VIEW_GRID_LINES_NONE && 
-         !priv->grid_line_gc)
-       {
-         gint line_width;
-
-         gtk_widget_style_get (widget,
-                               "grid-line-width", &line_width,
-                               NULL);
-      
-         priv->grid_line_gc = gdk_gc_new (widget->window);
-         gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
-       }      
-    }
-
   if (old_grid_lines != grid_lines)
     {
       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
index 73210f1521e2736297adf50ebbbf1e08a30d6cb3..dc9bf681593a3104313b6172bdafd08928ec75bf 100644 (file)
@@ -102,6 +102,8 @@ struct _PsppSheetView
   GtkContainer parent;
 
   PsppSheetViewPrivate *GSEAL (priv);
+
+  gboolean dispose_has_run ;
 };
 
 struct _PsppSheetViewClass
index 88de4bc655459b02286c93336bf80c10c232edd0..ac90984a3d233c35823a86dfde80f2d6e92481d4 100644 (file)
@@ -30,7 +30,7 @@
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-static void psppire_cell_renderer_button_destroy (GtkObject *);
+static void psppire_cell_renderer_button_dispose (GObject *);
 static void psppire_cell_renderer_button_finalize (GObject *);
 
 static void update_style_cache (PsppireCellRendererButton *button,
@@ -134,13 +134,6 @@ on_style_set (GtkWidget                 *base,
   update_style_cache (button, NULL);
 }
 
-static void
-on_destroy (GtkObject                 *base,
-            PsppireCellRendererButton *button)
-{
-  update_style_cache (button, NULL);
-}
-
 static void
 update_style_cache (PsppireCellRendererButton *button,
                     GtkWidget                 *widget)
@@ -167,11 +160,6 @@ update_style_cache (PsppireCellRendererButton *button,
                                        button->style_set_handler);
           button->style_set_handler = 0;
         }
-      if (button->destroy_handler)
-        {
-          g_signal_handler_disconnect (button->base, button->destroy_handler);
-          button->destroy_handler = 0;
-        }
       g_object_unref (button->base);
       button->base = NULL;
     }
@@ -186,10 +174,6 @@ update_style_cache (PsppireCellRendererButton *button,
       button->style_set_handler = g_signal_connect (widget, "style-set",
                                                     G_CALLBACK (on_style_set),
                                                     button);
-      button->destroy_handler = g_signal_connect (widget, "destroy",
-                                                  G_CALLBACK (on_destroy),
-                                                  button);
-
       g_object_ref (widget);
       g_object_ref (button->button_style);
       g_object_ref (button->label_style);
@@ -370,6 +354,16 @@ psppire_cell_renderer_button_press_event (GtkButton      *button,
 {
   PsppireCellRendererButton *cell_button = data;
 
+  if (event->button == 3)
+    {
+      /* Allow right-click events to propagate upward in the widget hierarchy.
+         Otherwise right-click menus, that trigger on a button-press-event on
+         the containing PsppSheetView, will pop up if the button is rendered as
+         a facade but not if the button widget exists.  */
+      g_signal_stop_emission_by_name (button, "button-press-event");
+      return FALSE;
+    }
+
   if (cell_button->click_time != 0)
     {
       GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button));
@@ -466,14 +460,12 @@ static void
 psppire_cell_renderer_button_class_init (PsppireCellRendererButtonClass *class)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-  GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
 
   gobject_class->set_property = psppire_cell_renderer_button_set_property;
   gobject_class->get_property = psppire_cell_renderer_button_get_property;
   gobject_class->finalize = psppire_cell_renderer_button_finalize;
-
-  gtk_object_class->destroy = psppire_cell_renderer_button_destroy;
+  gobject_class->dispose = psppire_cell_renderer_button_dispose;
 
   cell_class->get_size = psppire_cell_renderer_button_get_size;
   cell_class->render = psppire_cell_renderer_button_render;
@@ -540,7 +532,7 @@ psppire_cell_renderer_button_init (PsppireCellRendererButton *obj)
   obj->label_style = NULL;
   obj->base = NULL;
   obj->style_set_handler = 0;
-  obj->destroy_handler = 0;
+  obj->dispose_has_run = FALSE;
 }
 
 static void
@@ -552,13 +544,20 @@ psppire_cell_renderer_button_finalize (GObject *obj)
 }
 
 static void
-psppire_cell_renderer_button_destroy (GtkObject *obj)
+psppire_cell_renderer_button_dispose (GObject *obj)
 {
   PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (obj);
 
+  if (button->dispose_has_run)
+    return;
+  
+  button->dispose_has_run = TRUE;
+
+  /* When called with NULL, as we are doing here, update_style_cache
+     does nothing more than to drop references */
   update_style_cache (button, NULL);
 
-  GTK_OBJECT_CLASS (psppire_cell_renderer_button_parent_class)->destroy (obj);
+  G_OBJECT_CLASS (psppire_cell_renderer_button_parent_class)->dispose (obj);
 }
 
 GtkCellRenderer *
index a878f516b278ac9926c9320a9f2bec181158f2d7..28d5dd14e5062ff8807ac4172eedec3895a26517 100644 (file)
@@ -31,7 +31,8 @@ G_BEGIN_DECLS
 typedef struct _PsppireCellRendererButton      PsppireCellRendererButton;
 typedef struct _PsppireCellRendererButtonClass PsppireCellRendererButtonClass;
 
-struct _PsppireCellRendererButton {
+struct _PsppireCellRendererButton
+{
   GtkCellRenderer parent;
 
   gboolean editable;
@@ -52,7 +53,7 @@ struct _PsppireCellRendererButton {
   GtkStyle *label_style;
   GtkWidget *base;
   gulong style_set_handler;
-  gulong destroy_handler;
+  gboolean dispose_has_run;
 };
 
 struct _PsppireCellRendererButtonClass {
index 16b1393df3977593f2e94c226ead0fedd478c6e5..26c375640580d527a0e435291f5a1b345c9b45f5 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <gtk/gtk.h>
-#include <gtk-contrib/gtkextra-sheet.h>
-#include "psppire-data-editor.h"
-#include "psppire-var-sheet.h"
-#include "psppire.h"
 
-#include "psppire-data-store.h"
-#include <libpspp/i18n.h>
-#include <ui/gui/sheet/psppire-axis.h>
-#include "executor.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
-
-
-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 "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-sheet.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.h"
 
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
 
-static gboolean data_is_selected (PsppireDataEditor *de);
+#define FOR_EACH_DATA_SHEET(DATA_SHEET, IDX, DATA_EDITOR)       \
+  for ((IDX) = 0;                                               \
+       (IDX) < 4                                                \
+         && ((DATA_SHEET) = PSPPIRE_DATA_SHEET (                \
+               (DATA_EDITOR)->data_sheets[IDX])) != NULL;       \
+       (IDX)++)
 
 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,416 +84,105 @@ psppire_data_editor_dispose (GObject *obj)
 {
   PsppireDataEditor *de = (PsppireDataEditor *) obj;
 
-  if (de->dispose_has_run)
-    return;
-
-  g_object_unref (de->data_window);
-  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);
-
-
-
-
+  disconnect_data_sheets (de);
 
-/* 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;
-
-  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_WINDOW,
     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);
-    }
-
-  /* All of the data (potentially) changed, so unselect any selected cell(s) in
-     the data sheets.  If we don't do this, then the sheet remembers the value
-     that was in the selected cell and stores it back, wiping out whatever
-     value there is in the new data.  Bug #30502. */
-  if (de->data_sheet[0] != NULL)
-    psppire_sheet_unselect_range (PSPPIRE_SHEET (de->data_sheet[0]));
-}
-
-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,
-                          const struct variable *var UNUSED,
-                          gint dict_idx, gint case_idx 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, dict_idx, 1);
-
-  psppire_axis_delete (de->haxis, dict_idx, 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);
-
-  /* Don't allow zero width */
-  if ( var_width < 1 )
-    var_width = 1;
+  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (de->var_sheet);
+  PsppireDataSheet *data_sheet;
+  int i;
 
-  psppire_axis_resize (de->haxis, posn, m_width * var_width);
+  FOR_EACH_DATA_SHEET (data_sheet, i, de)
+    psppire_data_sheet_set_data_store (data_sheet, de->data_store);
+  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);
+  PsppireDataSheet *data_sheet;
+  int i;
 
   switch (prop_id)
     {
     case PROP_SPLIT_WINDOW:
       psppire_data_editor_split_window (de, g_value_get_boolean (value));
       break;
-    case PROP_DATA_WINDOW:
-      de->data_window = g_value_get_pointer (value);
-      g_object_ref (de->data_window);
-      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);
+      psppire_data_editor_refresh_model (de);
 
-      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_signal_connect (de->data_store, "case-inserted",
-                       G_CALLBACK (case_inserted_callback), 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);
-
-       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_signal_connect_swapped (de->data_store, "case-changed",
+                                G_CALLBACK (refresh_entry), de);
 
-       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);
-      }
+    case PROP_DICTIONARY:
+      if (de->dict)
+        g_object_unref (de->dict);
+      de->dict = g_value_get_pointer (value);
+      g_object_ref (de->dict);
+
+      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));
-      }
+      FOR_EACH_DATA_SHEET (data_sheet, i, de)
+        psppire_data_sheet_set_value_labels (data_sheet,
+                                          g_value_get_boolean (value));
       break;
+    case PROP_UI_MANAGER:
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -515,74 +202,64 @@ psppire_data_editor_get_property (GObject         *object,
     case PROP_SPLIT_WINDOW:
       g_value_set_boolean (value, de->split);
       break;
-    case PROP_DATA_WINDOW:
-      g_value_set_pointer (value, de->data_window);
-      break;
     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);
+    case PROP_DICTIONARY:
+      g_value_set_pointer (value, de->dict);
       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);
-      }
-      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:
+      g_value_set_boolean (value,
+                           psppire_data_sheet_get_value_labels (
+                             PSPPIRE_DATA_SHEET (de->data_sheets[0])));
       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,
+                                 GtkNotebookPage *page,
+                                 guint            page_num)
+{
+  GTK_NOTEBOOK_CLASS (parent_class)->switch_page (notebook, page, 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_window_spec ;
   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;
 
-  
-
-  data_window_spec =
-    g_param_spec_pointer ("data-window",
-                         "Data Window",
-                         "A pointer to the data window associated with this editor",
-                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE );
+  container_class->set_focus_child = psppire_data_editor_set_focus_child;
 
-  g_object_class_install_property (object_class,
-                                   PROP_DATA_WINDOW,
-                                   data_window_spec);
+  notebook_class->switch_page = psppire_data_editor_switch_page;
 
   data_store_spec =
     g_param_spec_pointer ("data-store",
@@ -594,51 +271,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",
@@ -652,45 +293,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",
@@ -702,723 +304,478 @@ 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 (PsppireDataSheet *data_sheet,
+                                  gint dict_index,
+                                  PsppireDataEditor *de)
 {
-  PsppireDataEditor *de = data;
-
-  PsppireDataStore *data_store =
-    PSPPIRE_DATA_STORE (psppire_sheet_get_model (sheet));
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
+                                 PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
 
-  if (data_store)
-    {
-      const struct variable *var =
-       psppire_dict_get_variable (data_store->dict, col);
+  psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
+                                   dict_index);
 
-      if ( var )
-       {
-         gchar *text = g_strdup_printf ("%d: %s", row + FIRST_CASE_NUMBER,
-                                        var_get_name (var));
+  return TRUE;
+}
 
+static gboolean
+on_var_sheet_var_double_clicked (PsppireVarSheet *var_sheet, gint dict_index,
+                                 PsppireDataEditor *de)
+{
+  PsppireDataSheet *data_sheet;
 
-         gtk_entry_set_text (GTK_ENTRY (de->cell_ref_entry), text);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
+                                 PSPPIRE_DATA_EDITOR_DATA_VIEW);
 
-         g_free (text);
-       }
-      else
-       goto blank_entry;
+  data_sheet = psppire_data_editor_get_active_data_sheet (de);
+  psppire_data_sheet_show_variable (data_sheet, dict_index);
 
-      if ( var )
-       {
-         gchar *text =
-           psppire_data_store_get_string (data_store, row,
-                                          var_get_dict_index(var));
+  return TRUE;
+}
 
-         if ( ! text )
-           goto blank_entry;
+/* Refreshes 'de->cell_ref_label' and 'de->datum_entry' from the currently
+   active cell or cells. */
+static void
+refresh_entry (PsppireDataEditor *de)
+{
+  PsppireDataSheet *data_sheet = psppire_data_editor_get_active_data_sheet (de);
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
 
-         g_strchug (text);
+  gchar *ref_cell_text;
+  GList *selected_columns, *iter;
+  struct variable *var;
+  gint n_cases;
+  gint n_vars;
 
-         gtk_entry_set_text (GTK_ENTRY (de->datum_entry), text);
+  selected_columns = pspp_sheet_selection_get_selected_columns (selection);
+  n_vars = 0;
+  var = NULL;
+  for (iter = selected_columns; iter != NULL; iter = iter->next)
+    {
+      PsppSheetViewColumn *column = iter->data;
+      struct variable *v = g_object_get_data (G_OBJECT (column), "variable");
+      if (v != NULL)
+        {
+          var = v;
+          n_vars++;
+        }
+    }
+  g_list_free (selected_columns);
 
-         g_free (text);
-       }
-      else
-       goto blank_entry;
+  n_cases = pspp_sheet_selection_count_selected_rows (selection);
+  if (n_cases > 0)
+    {
+      /* The final row is selectable but it isn't a case (it's just used to add
+         more cases), so don't count it. */
+      GtkTreePath *path;
+      gint case_count;
 
+      case_count = psppire_data_store_get_case_count (de->data_store);
+      path = gtk_tree_path_new_from_indices (case_count, -1);
+      if (pspp_sheet_selection_path_is_selected (selection, path))
+        n_cases--;
+      gtk_tree_path_free (path);
     }
 
-  return FALSE;
-
- blank_entry:
-  gtk_entry_set_text (GTK_ENTRY (de->datum_entry), "");
+  ref_cell_text = NULL;
+  if (n_cases == 1 && n_vars == 1)
+    {
+      PsppireValueEntry *value_entry = PSPPIRE_VALUE_ENTRY (de->datum_entry);
+      struct range_set *selected_rows;
+      gboolean show_value_labels;
+      union value value;
+      int width;
+      gint row;
 
-  return FALSE;
-}
+      selected_rows = pspp_sheet_selection_get_range_set (selection);
+      row = range_set_scan (selected_rows, 0);
+      range_set_destroy (selected_rows);
 
+      ref_cell_text = g_strdup_printf ("%d : %s", row + 1, var_get_name (var));
 
-static void
-datum_entry_activate (GtkEntry *entry, gpointer data)
-{
-  gint row, column;
-  PsppireDataEditor *de = data;
+      show_value_labels = psppire_data_sheet_get_value_labels (data_sheet);
 
-  const gchar *text = gtk_entry_get_text (entry);
+      psppire_value_entry_set_variable (value_entry, var);
+      psppire_value_entry_set_show_value_label (value_entry,
+                                                show_value_labels);
 
-  psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &column);
+      width = var_get_width (var);
+      value_init (&value, width);
+      datasheet_get_value (de->data_store->datasheet,
+                           row, var_get_case_index (var), &value);
+      psppire_value_entry_set_value (value_entry, &value, width);
+      value_destroy (&value, width);
 
-  if ( row == -1 || column == -1)
-    return;
+      gtk_widget_set_sensitive (de->datum_entry, TRUE);
+    }
+  else
+    {
+      if (n_cases == 0 || n_vars == 0)
+        {
+          ref_cell_text = NULL;
+        }
+      else
+        {
+          struct string s;
+
+          /* The glib string library does not understand the ' printf modifier
+             on all platforms, but the "struct string" library does (because
+             Gnulib fixes that problem), so use the latter.  */
+          ds_init_empty (&s);
+          ds_put_format (&s, ngettext ("%'d case", "%'d cases", n_cases),
+                         n_cases);
+          ds_put_byte (&s, ' ');
+          ds_put_unichar (&s, 0xd7); /* U+00D7 MULTIPLICATION SIGN */
+          ds_put_byte (&s, ' ');
+          ds_put_format (&s, ngettext ("%'d variable", "%'d variables",
+                                       n_vars),
+                         n_vars);
+          ref_cell_text = ds_steal_cstr (&s);
+        }
+
+      psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (de->datum_entry),
+                                        NULL);
+      gtk_entry_set_text (
+        GTK_ENTRY (gtk_bin_get_child (GTK_BIN (de->datum_entry))), "");
+      gtk_widget_set_sensitive (de->datum_entry, FALSE);
+    }
 
-  psppire_data_store_set_string (de->data_store, text, row, column);
+  gtk_label_set_label (GTK_LABEL (de->cell_ref_label),
+                       ref_cell_text ? ref_cell_text : "");
+  g_free (ref_cell_text);
 }
 
-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);
+  PsppireDataSheet *data_sheet = psppire_data_editor_get_active_data_sheet (de);
+  struct variable *var;
+  union value value;
+  int width;
+  gint row;
 
-  g_signal_connect (clip, "owner-change", G_CALLBACK (on_owner_change), w);
-}
+  row = psppire_data_sheet_get_current_case (data_sheet);
+  var = psppire_data_sheet_get_current_variable (data_sheet);
+  if (row < 0 || !var)
+    return;
 
+  width = var_get_width (var);
+  value_init (&value, width);
+  if (psppire_value_entry_get_value (PSPPIRE_VALUE_ENTRY (de->datum_entry),
+                                     &value, width))
+    psppire_data_store_set_value (de->data_store, row, var, &value);
+  value_destroy (&value, width);
+}
 
 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);
+  /* 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))
+    {
+      PsppireDataSheet *ds;
+      int i;
 
-  g_object_set (de->sheet_bin[i],
-               "border-width", 3,
-               "shadow-type",  GTK_SHADOW_ETCHED_IN,
-               NULL);
+      FOR_EACH_DATA_SHEET (ds, i, de)
+        {
+          PsppSheetSelection *s;
 
-  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);
-
-  gtk_widget_show (de->sheet_bin[i]);
-}
-
-
-static void
-init_data_sheet (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);
-}
+          s = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
+          if (s != selection)
+            pspp_sheet_selection_unselect_all (s);
+        }
+    }
 
+  refresh_entry (de);
+}
 
+/* Ensures that rows in the right-hand panes in the split view have the same
+   row height as the left-hand panes.  Otherwise, the rows in the right-hand
+   pane tend to be smaller, because the right-hand pane doesn't have buttons
+   for case numbers. */
 static void
-psppire_data_editor_init (PsppireDataEditor *de)
+on_data_sheet_fixed_height_notify (PsppireDataSheet *ds,
+                                   GParamSpec *pspec,
+                                   PsppireDataEditor *de)
 {
-  GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
-  GtkWidget *sw_vs = gtk_scrolled_window_new (NULL, NULL);
-
-  init_data_sheet (de);
-
-  de->data_vbox = gtk_vbox_new (FALSE, 0);
-  de->var_sheet = psppire_var_sheet_new ();
-
-  g_object_set (de, "tab-pos", GTK_POS_BOTTOM, NULL);
-
-  de->datum_entry = gtk_entry_new ();
-  de->cell_ref_entry = gtk_entry_new ();
-
-  g_object_set (de->cell_ref_entry,
-               "sensitive", FALSE,
-               "editable",  FALSE,
-               "width_chars", 25,
-               NULL);
-
-  gtk_box_pack_start (GTK_BOX (hbox), de->cell_ref_entry, FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (hbox), de->datum_entry, TRUE, TRUE, 0);
-
-
-  gtk_container_add (GTK_CONTAINER (sw_vs), de->var_sheet);
-  gtk_widget_show_all (sw_vs);
-
-
-  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);
-
-
-  psppire_data_editor_remove_split (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);
+  enum
+    {
+      TL = GTK_XPANED_TOP_LEFT,
+      TR = GTK_XPANED_TOP_RIGHT,
+      BL = GTK_XPANED_BOTTOM_LEFT,
+      BR = GTK_XPANED_BOTTOM_RIGHT
+    };
 
+  int fixed_height = pspp_sheet_view_get_fixed_height (PSPP_SHEET_VIEW (ds));
 
-  de->dispose_has_run = FALSE;
+  pspp_sheet_view_set_fixed_height (PSPP_SHEET_VIEW (de->data_sheets[TR]),
+                                    fixed_height);
+  pspp_sheet_view_set_fixed_height (PSPP_SHEET_VIEW (de->data_sheets[BR]),
+                                    fixed_height);
 }
 
-
-GtkWidget*
-psppire_data_editor_new (PsppireDataWindow *data_window,
-                         PsppireVarStore *var_store,
-                        PsppireDataStore *data_store)
-{
-  return  g_object_new (PSPPIRE_DATA_EDITOR_TYPE,
-                        "data-window", data_window,
-                        "var-store",  var_store,
-                        "data-store",  data_store,
-                        NULL);
-}
-
-
 static void
-psppire_data_editor_remove_split (PsppireDataEditor *de)
+disconnect_data_sheets (PsppireDataEditor *de)
 {
-  if ( !de->split ) return;
-  de->split = FALSE;
+  PsppireDataSheet *ds;
+  int i;
 
-  g_object_ref (de->sheet_bin[0]);
-  gtk_container_remove (GTK_CONTAINER (de->paned), de->sheet_bin[0]);
+  FOR_EACH_DATA_SHEET (ds, i, de)
+    {
+      PsppSheetSelection *selection;
 
-  g_object_ref (de->paned);
-  gtk_container_remove (GTK_CONTAINER (de->data_vbox), de->paned);
+      if (ds == NULL)
+        {
+          /* This can only happen if 'dispose' runs more than once. */
+          continue;
+        }
 
-  gtk_box_pack_start (GTK_BOX (de->data_vbox), de->sheet_bin[0],
-                     TRUE, TRUE, 0);
+      if (i == GTK_XPANED_TOP_LEFT)
+        g_signal_handlers_disconnect_by_func (
+          ds, G_CALLBACK (on_data_sheet_fixed_height_notify), de);
 
-  g_object_unref (de->sheet_bin[0]);
+      g_signal_handlers_disconnect_by_func (
+        ds, G_CALLBACK (refresh_entry), de);
+      g_signal_handlers_disconnect_by_func (
+        ds, G_CALLBACK (on_data_sheet_var_double_clicked), de);
 
-  g_object_set (de->sheet_bin[0], "vscrollbar-policy",
-               GTK_POLICY_ALWAYS, NULL);
+      selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
+      g_signal_handlers_disconnect_by_func (
+        selection, G_CALLBACK (on_data_sheet_selection_changed), de);
 
-  g_object_set (de->sheet_bin[0], "hscrollbar-policy",
-               GTK_POLICY_ALWAYS, NULL);
+      de->data_sheets[i] = NULL;
+    }
 }
 
-
-static void
-psppire_data_editor_set_split (PsppireDataEditor *de)
+static GtkWidget *
+make_data_sheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines)
 {
-  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);
+  PsppSheetSelection *selection;
+  GtkWidget *ds;
 
-  gtk_box_pack_start (GTK_BOX (de->data_vbox), de->paned,
-                     TRUE, TRUE, 0);
+  ds = psppire_data_sheet_new ();
+  pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (ds), grid_lines);
 
-  g_object_unref (de->paned);
+  g_signal_connect_swapped (ds, "notify::value-labels",
+                            G_CALLBACK (refresh_entry), de);
+  g_signal_connect (ds, "var-double-clicked",
+                    G_CALLBACK (on_data_sheet_var_double_clicked), de);
 
-  g_object_set (de->sheet_bin[0], "vscrollbar-policy",
-               GTK_POLICY_NEVER, NULL);
+  selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
+  g_signal_connect (selection, "changed",
+                    G_CALLBACK (on_data_sheet_selection_changed), de);
 
-  g_object_set (de->sheet_bin[0], "hscrollbar-policy",
-               GTK_POLICY_NEVER, NULL);
+  return ds;
 }
 
-void
-psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split)
+static GtkWidget *
+make_single_datasheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines)
 {
-  if (split )
-    psppire_data_editor_set_split (de);
-  else
-    psppire_data_editor_remove_split (de);
+  GtkWidget *data_sheet_scroller;
 
-  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);
+  de->data_sheets[0] = make_data_sheet (de, grid_lines);
+  de->data_sheets[1] = de->data_sheets[2] = de->data_sheets[3] = NULL;
 
+  /* Put data sheet in scroller. */
+  data_sheet_scroller = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (data_sheet_scroller),
+                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_container_add (GTK_CONTAINER (data_sheet_scroller), de->data_sheets[0]);
 
-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);
+  return data_sheet_scroller;
 }
 
-
-
-void
-psppire_data_editor_clip_cut (PsppireDataEditor *de)
+static GtkWidget *
+make_split_datasheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines)
 {
-  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 )
+  /* Panes, in the order in which we want to create them. */
+  enum
     {
-      gint row, col;
-      psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &col);
+      TL,                       /* top left */
+      TR,                       /* top right */
+      BL,                       /* bottom left */
+      BR                        /* bottom right */
+    };
 
-      range.row0 = range.rowi = row;
-      range.col0 = range.coli = col;
-    }
+  PsppSheetView *ds[4];
+  GtkXPaned *xpaned;
+  int i;
 
-  /* 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;
-    }
+  xpaned = GTK_XPANED (gtk_xpaned_new ());
 
-  max_columns = dict_get_var_cnt (ds->dict->dict);
-  if (range.coli >= max_columns)
+  for (i = 0; i < 4; i++)
     {
-      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);
+      GtkAdjustment *hadjust, *vadjust;
+      GtkPolicyType hpolicy, vpolicy;
+      GtkWidget *scroller;
 
+      de->data_sheets[i] = make_data_sheet (de, grid_lines);
+      ds[i] = PSPP_SHEET_VIEW (de->data_sheets[i]);
 
-  for (r = range.row0; r <= range.rowi ; ++r )
-    {
-      gint c;
+      if (i == BL)
+        hadjust = pspp_sheet_view_get_hadjustment (ds[TL]);
+      else if (i == BR)
+        hadjust = pspp_sheet_view_get_hadjustment (ds[TR]);
+      else
+        hadjust = NULL;
 
-      for (c = range.col0 ; c <= range.coli; ++c)
-       {
-         psppire_data_store_set_string (ds, "", r, c);
-       }
+      if (i == TR)
+        vadjust = pspp_sheet_view_get_vadjustment (ds[TL]);
+      else if (i == BR)
+        vadjust = pspp_sheet_view_get_vadjustment (ds[BL]);
+      else
+        vadjust = NULL;
+
+      scroller = gtk_scrolled_window_new (hadjust, vadjust);
+      gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller),
+                                           GTK_SHADOW_ETCHED_IN);
+      hpolicy = i == TL || i == TR ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS;
+      vpolicy = i == TL || i == BL ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS;
+      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
+                                      hpolicy, vpolicy);
+      gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (ds[i]));
+
+      switch (i)
+        {
+        case TL:
+          gtk_xpaned_pack_top_left (xpaned, scroller, TRUE, TRUE);
+          break;
+
+        case TR:
+          gtk_xpaned_pack_top_right (xpaned, scroller, TRUE, TRUE);
+          break;
+
+        case BL:
+          gtk_xpaned_pack_bottom_left (xpaned, scroller, TRUE, TRUE);
+          break;
+
+        case BR:
+          gtk_xpaned_pack_bottom_right (xpaned, scroller, TRUE, TRUE);
+          break;
+
+        default:
+          g_warn_if_reached ();
+        }
     }
 
-  /* and remove the selection */
-  psppire_sheet_unselect_range (PSPPIRE_SHEET (de->data_sheet[0]));
-}
-
-
-\f
-
-/* Popup menu related stuff */
+  /* Bottom sheets don't display variable names. */
+  pspp_sheet_view_set_headers_visible (ds[BL], FALSE);
+  pspp_sheet_view_set_headers_visible (ds[BR], FALSE);
 
-static void
-popup_variable_column_menu (PsppireSheet *sheet, gint column,
-                    GdkEventButton *event, gpointer data)
-{
-  GtkMenu *menu = GTK_MENU (data);
+  /* Right sheets don't display case numbers. */
+  psppire_data_sheet_set_case_numbers (PSPPIRE_DATA_SHEET (ds[TR]), FALSE);
+  psppire_data_sheet_set_case_numbers (PSPPIRE_DATA_SHEET (ds[BR]), FALSE);
 
-  PsppireDataStore *data_store =
-    PSPPIRE_DATA_STORE (psppire_sheet_get_model (sheet));
+  g_signal_connect (ds[TL], "notify::fixed-height",
+                    G_CALLBACK (on_data_sheet_fixed_height_notify), de);
 
-  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);
-    }
+  return GTK_WIDGET (xpaned);
 }
 
-
 static void
-popup_variable_row_menu (PsppireSheet *sheet, gint row,
-                    GdkEventButton *event, gpointer data)
+psppire_data_editor_init (PsppireDataEditor *de)
 {
-  GtkMenu *menu = GTK_MENU (data);
+  GtkWidget *var_sheet_scroller;
+  GtkWidget *hbox;
 
-  PsppireVarStore *var_store =
-    PSPPIRE_VAR_STORE (psppire_sheet_get_model (sheet));
-  
-  PsppireDict *dict;
-  const struct variable *v ;
-
-  g_object_get (var_store, "dictionary", &dict, NULL);
-
-  v = psppire_dict_get_variable (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);
-    }
-}
+  de->font = NULL;
+  de->ui_manager = NULL;
+  de->old_vbox_widget = NULL;
 
+  g_object_set (de, "tab-pos", GTK_POS_BOTTOM, NULL);
 
-static void
-popup_cases_menu (PsppireSheet *sheet, gint row,
-                 GdkEventButton *event, gpointer data)
-{
-  GtkMenu *menu = GTK_MENU (data);
+  de->cell_ref_label = gtk_label_new ("");
+  gtk_label_set_width_chars (GTK_LABEL (de->cell_ref_label), 25);
+  gtk_misc_set_alignment (GTK_MISC (de->cell_ref_label), 0.0, 0.5);
 
-  PsppireDataStore *data_store =
-    PSPPIRE_DATA_STORE (psppire_sheet_get_model (sheet));
+  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);
 
-  if ( row <= psppire_data_store_get_case_count (data_store) &&
-       event->button == 3)
-    {
-      psppire_sheet_select_row (sheet, row);
-
-      gtk_menu_popup (menu,
-                     NULL, NULL, NULL, NULL,
-                     event->button, event->time);
-    }
-}
+  hbox = gtk_hbox_new (FALSE, 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);
 
-\f
+  de->split = FALSE;
+  de->datasheet_vbox_widget
+    = make_single_datasheet (de, GTK_TREE_VIEW_GRID_LINES_BOTH);
 
-/* Sorting */
+  de->vbox = gtk_vbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (de->vbox), hbox, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (de->vbox), de->datasheet_vbox_widget,
+                      TRUE, TRUE, 0);
 
-static void
-do_sort (PsppireDataEditor *de, int var, gboolean descend)
-{
-  const struct variable *v
-    = psppire_dict_get_variable (de->data_store->dict, var);
-  gchar *syntax;
+  gtk_notebook_append_page (GTK_NOTEBOOK (de), de->vbox,
+                           gtk_label_new_with_mnemonic (_("Data View")));
 
-  syntax = g_strdup_printf ("SORT CASES BY %s%s.",
-                            var_get_name (v), descend ? " (D)" : "");
-  g_free (execute_syntax_string (de->data_window, syntax));
-}
+  gtk_widget_show_all (de->vbox);
+
+  de->var_sheet = GTK_WIDGET (psppire_var_sheet_new ());
+  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")));
 
+  g_signal_connect (de->var_sheet, "var-double-clicked",
+                    G_CALLBACK (on_var_sheet_var_double_clicked), de);
 
-/* Sort the data by the the variable which the editor has currently
-   selected */
-void
-psppire_data_editor_sort_ascending  (PsppireDataEditor *de)
-{
-  PsppireSheetRange range;
-  psppire_sheet_get_selected_range (PSPPIRE_SHEET(de->data_sheet[0]), &range);
+  g_object_set (de, "can-focus", FALSE, NULL);
 
-  do_sort (de,  range.col0, FALSE);
+  psppire_data_editor_update_ui_manager (de);
 }
 
-
-/* Sort the data by the the variable which the editor has currently
-   selected */
-void
-psppire_data_editor_sort_descending (PsppireDataEditor *de)
+GtkWidget*
+psppire_data_editor_new (PsppireDict *dict,
+                        PsppireDataStore *data_store)
 {
-  PsppireSheetRange range;
-  psppire_sheet_get_selected_range (PSPPIRE_SHEET(de->data_sheet[0]), &range);
-
-  do_sort (de,  range.col0, TRUE);
+  return  g_object_new (PSPPIRE_DATA_EDITOR_TYPE,
+                        "dictionary",  dict,
+                        "data-store",  data_store,
+                        NULL);
 }
-
-
 \f
-
-
-/* Insert a new variable  before the currently selected position */
-void
-psppire_data_editor_insert_variable (PsppireDataEditor *de)
-{
-  glong posn = 0;
-
-  switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
-    {
-    case PSPPIRE_DATA_EDITOR_DATA_VIEW:
-      if ( PSPPIRE_SHEET (de->data_sheet[0])->select_status
-          == 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 ( PSPPIRE_SHEET (de->var_sheet)->select_status
-          == 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;
-    };
-
-  psppire_dict_insert_variable (de->data_store->dict, posn, NULL);
-}
-
-/* Insert a new case before the currently selected position */
-void
-psppire_data_editor_insert_case (PsppireDataEditor *de)
-{
-  glong posn = -1;
-
-  if ( PSPPIRE_SHEET (de->data_sheet[0])->select_status == 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;
-
-  psppire_data_store_insert_new_case (de->data_store, posn);
-}
-
-/* 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;
-
-  psppire_data_store_delete_cases (de->data_store, first, n);
-
-  psppire_sheet_unselect_range (PSPPIRE_SHEET (de->data_sheet[0]));
-}
-
-/* Delete the variables currently selected in the
-   datasheet or variable sheet */
+/* Turns the visible grid on or off, according to GRID_VISIBLE, for DE's data
+   sheet(s) and variable sheet. */
 void
-psppire_data_editor_delete_variables (PsppireDataEditor *de)
+psppire_data_editor_show_grid (PsppireDataEditor *de, gboolean grid_visible)
 {
-  PsppireDict *dict = NULL;
-  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 ();
-      break;
-    }
-
-  g_object_get (de->var_store, "dictionary", &dict, NULL);
+  GtkTreeViewGridLines grid;
+  PsppireDataSheet *data_sheet;
+  int i;
 
-  psppire_dict_delete_variables (dict, first, n);
+  grid = (grid_visible
+          ? GTK_TREE_VIEW_GRID_LINES_BOTH
+          : GTK_TREE_VIEW_GRID_LINES_NONE);
 
-  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);
+  FOR_EACH_DATA_SHEET (data_sheet, i, de)
+    pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (data_sheet), grid);
+  pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet), grid);
 }
 
 
 static void
-set_font (GtkWidget *w, gpointer data)
+set_font_recursively (GtkWidget *w, gpointer data)
 {
   PangoFontDescription *font_desc = data;
   GtkRcStyle *style = gtk_widget_get_modifier_style (w);
@@ -1429,500 +786,171 @@ set_font (GtkWidget *w, gpointer data)
   gtk_widget_modify_style (w, style);
 
   if ( GTK_IS_CONTAINER (w))
-    gtk_container_foreach (GTK_CONTAINER (w), set_font, font_desc);
+    gtk_container_foreach (GTK_CONTAINER (w), set_font_recursively, font_desc);
 }
 
+/* Sets FONT_DESC as the font used by the data sheet(s) and variable sheet. */
 void
 psppire_data_editor_set_font (PsppireDataEditor *de, PangoFontDescription *font_desc)
 {
-  set_font (GTK_WIDGET (de), font_desc);
-}
+  set_font_recursively (GTK_WIDGET (de), font_desc);
 
-
-\f
-
-
-static void
-emit_selected_signal (PsppireDataEditor *de)
-{
-  gboolean data_selected = data_is_selected (de);
-
-  g_signal_emit (de, data_editor_signals[DATA_SELECTION_CHANGED], 0, data_selected);
+  if (de->font)
+    pango_font_description_free (de->font);
+  de->font = pango_font_description_copy (font_desc);
 }
 
-
-static void
-on_activate (PsppireDataEditor *de)
+/* 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_split_window (PsppireDataEditor *de, gboolean split)
 {
-  gint row, col;
-  psppire_sheet_get_active_cell (PSPPIRE_SHEET (de->data_sheet[0]), &row, &col);
+  GtkTreeViewGridLines grid_lines;
 
+  if (split == de->split)
+    return;
 
-  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);
-}
+  grid_lines = pspp_sheet_view_get_grid_lines (
+    PSPP_SHEET_VIEW (de->data_sheets[0]));
 
+  disconnect_data_sheets (de);
+  if (de->old_vbox_widget)
+    g_object_unref (de->old_vbox_widget);
+  de->old_vbox_widget = de->datasheet_vbox_widget;
+  g_object_ref (de->old_vbox_widget);
+  /* FIXME:  old_vbox_widget needs to be unreffed in dispose.
+       (currently it seems to provoke an error if I do that.  
+       I don't know why. */
+  gtk_container_remove (GTK_CONTAINER (de->vbox), de->datasheet_vbox_widget);
 
-static void
-on_select_range (PsppireDataEditor *de)
-{
-  PsppireSheetRange range;
+  if (split)
+    de->datasheet_vbox_widget = make_split_datasheet (de, grid_lines);
+  else
+    de->datasheet_vbox_widget = make_single_datasheet (de, grid_lines);
 
-  psppire_sheet_get_selected_range (PSPPIRE_SHEET (de->data_sheet[0]), &range);
+  psppire_data_editor_refresh_model (de);
 
-  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;
-    }
+  gtk_box_pack_start (GTK_BOX (de->vbox), de->datasheet_vbox_widget,
+                      TRUE, TRUE, 0);
+  gtk_widget_show_all (de->vbox);
 
-  emit_selected_signal (de);
-}
+  if (de->font)
+    set_font_recursively (GTK_WIDGET (de), de->font);
 
+  de->split = split;
+  g_object_notify (G_OBJECT (de), "split");
+  psppire_data_editor_update_ui_manager (de);
+}
 
-static gboolean
-on_switch_page (PsppireDataEditor *de, GtkNotebookPage *p,
-               gint pagenum, gpointer data)
+/* 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_goto_variable (PsppireDataEditor *de, gint dict_index)
 {
-  switch (pagenum)
+  PsppireDataSheet *data_sheet;
+
+  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);
+      data_sheet = psppire_data_editor_get_active_data_sheet (de);
+      psppire_data_sheet_show_variable (data_sheet, dict_index);
       break;
+
     case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
-      gtk_widget_grab_focus (de->var_sheet);
-      emit_selected_signal (de);
+      psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
+                                       dict_index);
       break;
-    default:
-      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;
 }
 
+/* Returns the "active" data sheet in DE.  If DE is in single-paned mode, this
+   is the only data sheet.  If DE is in split mode (showing four data sheets),
+   this is the focused data sheet or, if none is focused, the data sheet with
+   selected cells or, if none has selected cells, the upper-left data sheet. */
+PsppireDataSheet *
+psppire_data_editor_get_active_data_sheet (PsppireDataEditor *de)
+{
+  if (de->split)
+    {
+      PsppireDataSheet *data_sheet;
+      GtkWidget *scroller;
+      int i;
+
+      /* If one of the datasheet's scrollers is focused, choose that one. */
+      scroller = gtk_container_get_focus_child (
+        GTK_CONTAINER (de->datasheet_vbox_widget));
+      if (scroller != NULL)
+        return PSPPIRE_DATA_SHEET (gtk_bin_get_child (GTK_BIN (scroller)));
+
+      /* Otherwise if there's a nonempty selection in some data sheet, choose
+         that one. */
+      FOR_EACH_DATA_SHEET (data_sheet, i, de)
+        {
+          PsppSheetSelection *selection;
+
+          selection = pspp_sheet_view_get_selection (
+            PSPP_SHEET_VIEW (data_sheet));
+          if (pspp_sheet_selection_count_selected_rows (selection)
+              && pspp_sheet_selection_count_selected_columns (selection))
+            return data_sheet;
+        }
+    }
 
-static void
-on_select_row (PsppireSheet *sheet, gint row, PsppireDataEditor *de)
-{
-  g_signal_emit (de, data_editor_signals[CASES_SELECTED], 0, row);
+  return PSPPIRE_DATA_SHEET (de->data_sheets[0]);
 }
 
+/* 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
-on_select_variable (PsppireSheet *sheet, gint var, 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)
 {
-  g_signal_emit (de, data_editor_signals[VARIABLES_SELECTED], 0, var);
+  psppire_data_editor_update_ui_manager (de);
+  return de->ui_manager;
 }
 
-
-\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)
+psppire_data_editor_update_ui_manager (PsppireDataEditor *de)
 {
-  int i;
-  struct casewriter *writer ;
-  PsppireSheetRange range;
-  PsppireDataStore *ds;
-  struct case_map *map = NULL;
-  casenumber max_rows;
-  size_t max_columns;
-  gint row0, rowi;
-  gint col0, coli;
-
-  ds = PSPPIRE_DATA_STORE (psppire_sheet_get_model (sheet));
-
-  psppire_sheet_get_selected_range (sheet, &range);
-
-  col0 = MIN (range.col0, range.coli);
-  coli = MAX (range.col0, range.coli);
-  row0 = MIN (range.row0, range.rowi);
-  rowi = MAX (range.row0, range.rowi);
-
-   /* If nothing selected, then use active cell */
-  if ( row0 < 0 || col0 < 0 )
-    {
-      gint row, col;
-      psppire_sheet_get_active_cell (sheet, &row, &col);
+  PsppireDataSheet *data_sheet;
+  GtkUIManager *ui_manager;
 
-      row0 = rowi = row;
-      col0 = coli = col;
-    }
+  ui_manager = NULL;
 
-  /* 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 (rowi >= max_rows)
-    {
-      if (max_rows == 0)
-        return;
-      rowi = max_rows - 1;
-    }
-  max_columns = dict_get_var_cnt (ds->dict->dict);
-  if (coli >= max_columns)
-    {
-      if (max_columns == 0)
-        return;
-      coli = max_columns - 1;
-    }
-
-  /* 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 (dict_get_encoding (ds->dict->dict));
-  for (i = col0; i <= coli; i++)
-    dict_clone_var_assert (clip_dict, dict_get_var (ds->dict->dict, i));
-
-  /* Construct clip data. */
-  map = case_map_by_name (ds->dict->dict, clip_dict);
-  writer = autopaging_writer_create (dict_get_proto (clip_dict));
-  for (i = row0; i <= rowi ; ++i )
+  switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
     {
-      struct ccase *old = psppire_data_store_get_case (ds, i);
-      if (old != NULL)
-        casewriter_write (writer, case_map_execute (map, old));
+    case PSPPIRE_DATA_EDITOR_DATA_VIEW:
+      data_sheet = psppire_data_editor_get_active_data_sheet (de);
+      if (data_sheet != NULL)
+        ui_manager = psppire_data_sheet_get_ui_manager (data_sheet);
       else
-        casewriter_force_error (writer);
-    }
-  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)
-{
-  const struct fmt_spec *fs = var_get_print_format (v);
-  const union value *val = case_data (cc, v);
-
-  char *s = data_out (val, var_get_encoding (v), fs);
-
-  g_string_append (string, s);
-
-  g_free (s);
-}
-
-static GString *
-clip_to_text (void)
-{
-  casenumber r;
-  GString *string;
-
-  const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (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 = caseproto_get_n_widths (casereader_get_proto (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 (80 + 20 * val_cnt * case_cnt);
-
-  g_string_append (string,
-                  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
-
-  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 ();
+        {
+          /* This happens transiently in psppire_data_editor_split_window(). */
+        }
       break;
-    case SELECT_FMT_HTML:
-      string = clip_to_html ();
+
+    case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
+      ui_manager = psppire_var_sheet_get_ui_manager (
+        PSPPIRE_VAR_SHEET (de->var_sheet));
       break;
+
     default:
-      g_assert_not_reached ();
+      /* This happens transiently in psppire_data_editor_init(). */
+      break;
     }
 
-  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)
+  if (ui_manager != de->ui_manager)
     {
-      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);
-    }
-}
-
+      if (de->ui_manager)
+        g_object_unref (de->ui_manager);
+      if (ui_manager)
+        g_object_ref (ui_manager);
+      de->ui_manager = ui_manager;
 
-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_object_notify (G_OBJECT (de), "ui-manager");
     }
-
-  g_signal_emit (de, data_editor_signals[DATA_AVAILABLE_CHANGED], 0,
-                compatible_target);
 }
index f6f55d7ca5c56c9381dc8dd0b332248eb09738a2..35666600decca02e6f3b06e471ff79422f974a3e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
 #ifndef __PSPPIRE_DATA_EDITOR_H__
 #define __PSPPIRE_DATA_EDITOR_H__
 
+/* PsppireDataEditor is a GtkNotebook for editing a single PSPP dataset.
+
+   PsppireDataEditor has two tabs that normally contain a PsppireDataSheet and
+   a PsppireVarSheet.  The user can choose to "split" the PsppireDataSheet view
+   into four views within the single tab.  PsppireDataEditor also adds some
+   decorations above the PsppireDataSheet to note the current cell and allow
+   the current cell to be edited.
+
+   PsppireDataEditor's normal parent in the widget hierarchy is
+   PsppireDataWindow. */
 
 #include <glib.h>
 #include <glib-object.h>
 #include <gtk/gtk.h>
 
-#include <ui/gui/sheet/psppire-axis.h>
-#include "psppire-var-store.h"
 #include "psppire-data-store.h"
+#include "ui/gui/pspp-sheet-view.h"
 
 G_BEGIN_DECLS
 
@@ -44,30 +53,28 @@ struct _PsppireDataEditor
   GtkNotebook parent;
 
   /* <private> */
-  gboolean dispose_has_run;
-  GtkWidget *cell_ref_entry;
-  GtkWidget *datum_entry;
-  GtkWidget *var_sheet;
-  struct _PsppireDataWindow *data_window;
   PsppireDataStore *data_store;
-  PsppireVarStore *var_store;
-
-  GtkWidget *sheet_bin[4];
-  GtkWidget *data_sheet[4];
-
-  GtkWidget *data_vbox;
+  PsppireDict *dict;
 
-  GtkWidget *paned;
-  gboolean split;
+  /* Font to use in var sheet and data sheet(s), NULL to use system default. */
+  struct _PangoFontDescription *font;
 
-  PsppireAxis *vaxis[2];
+  /* Variable sheet tab. */
+  GtkWidget *var_sheet;
 
-  /* There's only one horizontal axis, since the
-     column widths are parameters of the variables */
-  PsppireAxis *haxis;
+  /* Data sheet tab. */
+  GtkWidget *vbox;             /* Top-level widget in tab. */
+  GtkWidget *cell_ref_label;   /* GtkLabel that shows selected case and var. */
+  GtkWidget *datum_entry;      /* GtkComboBoxEntry for editing current cell. */
+  GtkWidget *datasheet_vbox_widget; /* ->vbox child that holds data sheets. */
+  GtkWidget *data_sheets[4];   /* Normally one data sheet; four, if split. */
+  gboolean split;              /* True if data sheets are split. */
+
+  /* UI manager for whichever var or data sheet is currently in use. */
+  GtkUIManager *ui_manager;
+  GtkWidget *old_vbox_widget;
 };
 
-
 struct _PsppireDataEditorClass
 {
   GtkNotebookClass parent_class;
@@ -75,25 +82,19 @@ struct _PsppireDataEditorClass
 
 
 GType          psppire_data_editor_get_type        (void);
-GtkWidget*     psppire_data_editor_new             (struct _PsppireDataWindow *, PsppireVarStore *, PsppireDataStore *);
-void           psppire_data_editor_clip_copy       (PsppireDataEditor *);
-void           psppire_data_editor_clip_paste      (PsppireDataEditor *);
-void           psppire_data_editor_clip_cut        (PsppireDataEditor *);
-void           psppire_data_editor_sort_ascending  (PsppireDataEditor *);
-void           psppire_data_editor_sort_descending (PsppireDataEditor *);
-void           psppire_data_editor_insert_variable (PsppireDataEditor *);
-void           psppire_data_editor_delete_variables (PsppireDataEditor *);
+GtkWidget*     psppire_data_editor_new             (PsppireDict *, PsppireDataStore *);
 void           psppire_data_editor_show_grid       (PsppireDataEditor *, gboolean);
-void           psppire_data_editor_insert_case     (PsppireDataEditor *);
-void           psppire_data_editor_delete_cases    (PsppireDataEditor *);
 void           psppire_data_editor_set_font        (PsppireDataEditor *, PangoFontDescription *);
-void           psppire_data_editor_delete_cases    (PsppireDataEditor *);
 void           psppire_data_editor_split_window    (PsppireDataEditor *, gboolean );
 
+void           psppire_data_editor_goto_variable   (PsppireDataEditor *, gint dict_index);
 
-G_END_DECLS
+struct _PsppireDataSheet *psppire_data_editor_get_active_data_sheet (PsppireDataEditor *);
+
+GtkUIManager *psppire_data_editor_get_ui_manager (PsppireDataEditor *);
 
 enum {PSPPIRE_DATA_EDITOR_DATA_VIEW = 0, PSPPIRE_DATA_EDITOR_VARIABLE_VIEW};
 
+G_END_DECLS
 
 #endif /* __PSPPIRE_DATA_EDITOR_H__ */
diff --git a/src/ui/gui/psppire-data-sheet.c b/src/ui/gui/psppire-data-sheet.c
new file mode 100644 (file)
index 0000000..b6bf67c
--- /dev/null
@@ -0,0 +1,2249 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "ui/gui/psppire-data-sheet.h"
+
+#include "data/case-map.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/data-out.h"
+#include "data/datasheet.h"
+#include "data/format.h"
+#include "data/value-labels.h"
+#include "libpspp/intern.h"
+#include "libpspp/range-set.h"
+#include "ui/gui/executor.h"
+#include "ui/gui/find-dialog.h"
+#include "ui/gui/goto-case-dialog.h"
+#include "ui/gui/builder-wrapper.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/pspp-sheet-selection.h"
+#include "ui/gui/psppire-cell-renderer-button.h"
+#include "ui/gui/psppire-data-store.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dialog-action-var-info.h"
+#include "ui/gui/psppire-empty-list-store.h"
+#include "ui/gui/psppire-marshal.h"
+
+#include "gl/intprops.h"
+#include "gl/xalloc.h"
+
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+static void psppire_data_sheet_dispose (GObject *);
+static void psppire_data_sheet_unset_data_store (PsppireDataSheet *);
+
+static void psppire_data_sheet_update_clip_actions (PsppireDataSheet *);
+static void psppire_data_sheet_set_clip (PsppireDataSheet *);
+
+static void on_selection_changed (PsppSheetSelection *, gpointer);
+
+G_DEFINE_TYPE (PsppireDataSheet, psppire_data_sheet, PSPP_TYPE_SHEET_VIEW);
+
+static gboolean
+get_tooltip_location (GtkWidget *widget, GtkTooltip *tooltip,
+                      gint wx, gint wy,
+                      size_t *row, PsppSheetViewColumn **columnp)
+{
+  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
+  gint bx, by;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  PsppSheetViewColumn *tree_column;
+  GtkTreeModel *tree_model;
+  bool ok;
+
+  /* Check that WIDGET is really visible on the screen before we
+     do anything else.  This is a bug fix for a sticky situation:
+     when text_data_import_assistant() returns, it frees the data
+     necessary to compose the tool tip message, but there may be
+     a tool tip under preparation at that point (even if there is
+     no visible tool tip) that will call back into us a little
+     bit later.  Perhaps the correct solution to this problem is
+     to make the data related to the tool tips part of a GObject
+     that only gets destroyed when all references are released,
+     but this solution appears to be effective too. */
+  if (!gtk_widget_get_mapped (widget))
+    return FALSE;
+
+  pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
+                                                     wx, wy, &bx, &by);
+  if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
+                                      &path, &tree_column, NULL, NULL))
+    return FALSE;
+
+  *columnp = tree_column;
+
+  pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, tree_column,
+                                    NULL);
+
+  tree_model = pspp_sheet_view_get_model (tree_view);
+  ok = gtk_tree_model_get_iter (tree_model, &iter, path);
+  gtk_tree_path_free (path);
+  if (!ok)
+    return FALSE;
+
+  *row = GPOINTER_TO_INT (iter.user_data);
+  return TRUE;
+}
+
+static gboolean
+on_query_tooltip (GtkWidget *widget, gint wx, gint wy,
+                  gboolean keyboard_mode UNUSED,
+                  GtkTooltip *tooltip, gpointer data UNUSED)
+{
+  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
+  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
+  PsppSheetViewColumn *column;
+  struct variable *var;
+  const char *label;
+  union value v;
+  size_t row;
+  int width;
+
+  g_return_val_if_fail (data_store != NULL, FALSE);
+
+  if (!get_tooltip_location (widget, tooltip, wx, wy, &row, &column))
+    return FALSE;
+
+  var = g_object_get_data (G_OBJECT (column), "variable");
+  if (var == NULL)
+    {
+      if (g_object_get_data (G_OBJECT (column), "new-var-column") == NULL)
+        return FALSE;
+
+      gtk_tooltip_set_text (tooltip,
+                            _("Enter a number to add a new variable."));
+      return TRUE;
+    }
+  else if (row >= datasheet_get_n_rows (data_store->datasheet))
+    {
+      gtk_tooltip_set_text (tooltip, _("Enter a number to add a new case."));
+      return TRUE;
+    }
+
+  width = var_get_width (var);
+
+  value_init (&v, width);
+  datasheet_get_value (data_store->datasheet, row, var_get_case_index (var),
+                       &v);
+
+  label = var_lookup_value_label (var, &v);
+  if (label != NULL)
+    {
+      if (data_sheet->show_value_labels)
+        {
+          char *s = value_to_text (v, var);
+          gtk_tooltip_set_text (tooltip, s);
+          free (s);
+        }
+      else
+        gtk_tooltip_set_text (tooltip, label);
+    }
+  value_destroy (&v, width);
+
+  return label != NULL;
+}
+
+static void
+render_row_number_cell (PsppSheetViewColumn *tree_column,
+                        GtkCellRenderer *cell,
+                        GtkTreeModel *model,
+                        GtkTreeIter *iter,
+                        gpointer store_)
+{
+  PsppireDataStore *store = store_;
+  GValue gvalue = { 0, };
+  gint row;
+
+  row = GPOINTER_TO_INT (iter->user_data);
+
+  g_value_init (&gvalue, G_TYPE_INT);
+  g_value_set_int (&gvalue, row + 1);
+  g_object_set_property (G_OBJECT (cell), "label", &gvalue);
+  g_value_unset (&gvalue);
+
+  if (row < datasheet_get_n_rows (store->datasheet))
+    g_object_set (cell, "editable", TRUE, NULL);
+  else
+    g_object_set (cell, "editable", FALSE, NULL);
+
+  g_object_set (cell,
+                "slash", psppire_data_store_filtered (store, row),
+                NULL);
+}
+
+static void
+on_row_number_clicked (PsppireCellRendererButton *button,
+                       gchar *path_string,
+                       PsppSheetView *sheet_view)
+{
+  PsppSheetSelection *selection;
+  GtkTreePath *path;
+
+  path = gtk_tree_path_new_from_string (path_string);
+
+  selection = pspp_sheet_view_get_selection (sheet_view);
+  pspp_sheet_selection_unselect_all (selection);
+  pspp_sheet_selection_select_path (selection, path);
+  pspp_sheet_selection_select_all_columns (selection);
+
+  gtk_tree_path_free (path);
+}
+
+static void
+make_row_number_column (PsppireDataSheet *data_sheet,
+                        PsppireDataStore *ds)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppSheetViewColumn *column;
+  GtkCellRenderer *renderer;
+
+  renderer = psppire_cell_renderer_button_new ();
+  g_object_set (renderer, "xalign", 1.0, NULL);
+  g_signal_connect (renderer, "clicked", G_CALLBACK (on_row_number_clicked),
+                    sheet_view);
+
+  column = pspp_sheet_view_column_new_with_attributes (_("Case"),
+                                                       renderer, NULL);
+  g_object_set (column, "selectable", FALSE, "row-head", TRUE, NULL);
+  pspp_sheet_view_column_set_cell_data_func (
+    column, renderer, render_row_number_cell, ds, NULL);
+  pspp_sheet_view_column_set_fixed_width (column, 50);
+  pspp_sheet_view_column_set_visible (column, data_sheet->show_case_numbers);
+  pspp_sheet_view_append_column (sheet_view, column);
+}
+
+static void
+render_data_cell (PsppSheetViewColumn *tree_column,
+                  GtkCellRenderer *cell,
+                  GtkTreeModel *model,
+                  GtkTreeIter *iter,
+                  gpointer data_sheet_)
+{
+  PsppireDataSheet *data_sheet = data_sheet_;
+  PsppireDataStore *store = psppire_data_sheet_get_data_store (data_sheet);
+  struct variable *var;
+  gchar *string;
+  gint row;
+
+  double xalign;
+
+  row = GPOINTER_TO_INT (iter->user_data);
+  var = g_object_get_data (G_OBJECT (tree_column), "variable");
+
+  string = psppire_data_store_get_string (store, row, var,
+                                          data_sheet->show_value_labels);
+  if (string != NULL)
+    {
+      GValue gvalue = { 0 };
+
+      g_value_init (&gvalue, G_TYPE_STRING);
+      g_value_take_string (&gvalue, string);
+      g_object_set_property (G_OBJECT (cell), "text", &gvalue);
+      g_value_unset (&gvalue);
+    }
+  else
+    g_object_set (G_OBJECT (cell), "text", "", NULL);
+
+  switch (var_get_alignment (var))
+    {
+    case ALIGN_LEFT: xalign = 0.0; break;
+    case ALIGN_RIGHT: xalign = 1.0; break;
+    case ALIGN_CENTRE: xalign = 0.5; break;
+    default: xalign = 0.0; break;
+    }
+  g_object_set (cell,
+                "xalign", xalign,
+                "editable", TRUE,
+                NULL);
+}
+
+static gint
+get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
+                  const char *string)
+{
+  gint width;
+  g_object_set (G_OBJECT (renderer), "text", string, (void *) NULL);
+  gtk_cell_renderer_get_size (renderer, GTK_WIDGET (treeview),
+                              NULL, NULL, NULL, &width, NULL);
+  return width;
+}
+
+static gint
+get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
+                     size_t char_cnt)
+{
+  struct string s;
+  gint width;
+
+  ds_init_empty (&s);
+  ds_put_byte_multiple (&s, '0', char_cnt);
+  ds_put_byte (&s, ' ');
+  width = get_string_width (treeview, renderer, ds_cstr (&s));
+  ds_destroy (&s);
+
+  return width;
+}
+
+static void
+on_data_column_editing_started (GtkCellRenderer *cell,
+                                GtkCellEditable *editable,
+                                const gchar     *path,
+                                gpointer         user_data)
+{
+  PsppSheetViewColumn *column = g_object_get_data (G_OBJECT (cell), "column");
+  PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
+  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
+  struct variable *var;
+
+  g_return_if_fail (column);
+  g_return_if_fail (data_sheet);
+  g_return_if_fail (data_store);
+
+
+  g_object_ref (editable);
+  g_object_set_data_full (G_OBJECT (cell), "data-sheet-editable",
+                          editable, g_object_unref);
+
+  var = g_object_get_data (G_OBJECT (column), "variable");
+  g_return_if_fail (var);
+
+  if (var_has_value_labels (var) && GTK_IS_COMBO_BOX (editable))
+    {
+      const struct val_labs *labels = var_get_value_labels (var);
+      const struct val_lab *vl;
+      GtkListStore *list_store;
+
+      list_store = gtk_list_store_new (1, G_TYPE_STRING);
+      for (vl = val_labs_first (labels); vl != NULL;
+           vl = val_labs_next (labels, vl))
+        {
+          GtkTreeIter iter;
+
+          gtk_list_store_append (list_store, &iter);
+          gtk_list_store_set (list_store, &iter,
+                              0, val_lab_get_label (vl),
+                              -1);
+        }
+
+      gtk_combo_box_set_model (GTK_COMBO_BOX (editable),
+                               GTK_TREE_MODEL (list_store));
+      g_object_unref (list_store);
+    }
+}
+
+static void
+scroll_to_bottom (GtkWidget      *widget,
+                  GtkRequisition *requisition,
+                  gpointer        unused UNUSED)
+{
+  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
+  GtkAdjustment *vadjust;
+
+  vadjust = pspp_sheet_view_get_vadjustment (sheet_view);
+  gtk_adjustment_set_value (vadjust, gtk_adjustment_get_upper (vadjust));
+
+  if (data_sheet->scroll_to_bottom_signal)
+    {
+      g_signal_handler_disconnect (data_sheet,
+                                   data_sheet->scroll_to_bottom_signal);
+      data_sheet->scroll_to_bottom_signal = 0;
+    }
+}
+
+static void
+on_data_column_edited (GtkCellRendererText *cell,
+                       gchar               *path_string,
+                       gchar               *new_text,
+                       gpointer             user_data)
+{
+  PsppSheetViewColumn *column = g_object_get_data (G_OBJECT (cell), "column");
+  PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
+  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
+  GtkEditable *editable;
+  struct variable *var;
+  GtkTreePath *path;
+  gboolean is_val_lab;
+  gboolean new_row;
+  gint row;
+
+  path = gtk_tree_path_new_from_string (path_string);
+  row = gtk_tree_path_get_indices (path)[0];
+  gtk_tree_path_free (path);
+
+  var = g_object_get_data (G_OBJECT (column), "variable");
+
+  new_row = row == psppire_data_store_get_case_count (data_store);
+  if (new_row && new_text[0] == '\0')
+    return;
+
+  editable = g_object_steal_data (G_OBJECT (cell), "data-sheet-editable");
+  g_return_if_fail (editable != NULL);
+  is_val_lab = (GTK_IS_COMBO_BOX (editable)
+                && gtk_combo_box_get_active (GTK_COMBO_BOX (editable)) >= 0);
+  g_object_unref (editable);
+
+  psppire_data_store_set_string (data_store, new_text, row, var, is_val_lab);
+
+  if (new_row && !data_sheet->scroll_to_bottom_signal)
+    {
+      gtk_widget_queue_resize (GTK_WIDGET (data_sheet));
+      data_sheet->scroll_to_bottom_signal =
+        g_signal_connect (data_sheet, "size-request",
+                          G_CALLBACK (scroll_to_bottom), NULL);
+    }
+  else
+    {
+      /* We could be more specific about what to redraw, if it seems
+         important for performance. */
+      gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
+    }
+}
+
+static void
+scroll_to_right (GtkWidget      *widget,
+                 PsppireDataSheet  *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppSheetViewColumn *column, *prev;
+  GList *columns, *iter;
+
+  column = NULL;
+  prev = NULL;
+  columns = pspp_sheet_view_get_columns (sheet_view);
+  for (iter = columns; iter; iter = iter->next)
+    {
+      PsppSheetViewColumn *c = iter->data;
+      if (g_object_get_data (G_OBJECT (c), "new-var-column"))
+        {
+          column = c;
+          break;
+        }
+      prev = c;
+    }
+  g_list_free (columns);
+
+  if (column == NULL)
+    return;
+
+  pspp_sheet_view_scroll_to_cell (sheet_view, NULL, column, FALSE, 0, 0);
+
+  if (prev)
+    {
+      GtkTreePath *path;
+
+      pspp_sheet_view_get_cursor (sheet_view, &path, NULL);
+      if (path)
+        {
+          pspp_sheet_view_set_cursor (sheet_view, path, prev, TRUE);
+          gtk_tree_path_free (path);
+        }
+    }
+
+  if (data_sheet->scroll_to_right_signal)
+    {
+      g_signal_handler_disconnect (widget, data_sheet->scroll_to_right_signal);
+      data_sheet->scroll_to_right_signal = 0;
+    }
+}
+
+static void
+on_new_variable_column_edited (GtkCellRendererText *cell,
+                               gchar               *path_string,
+                               gchar               *new_text,
+                               gpointer             user_data)
+{
+  PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
+  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
+  PsppireDict *dict = data_store->dict;
+  struct variable *var;
+  GtkTreePath *path;
+  char name[64];
+  gint row;
+
+  if (new_text[0] == '\0')
+    {
+      /* User didn't enter anything so don't create a variable. */
+      return;
+    }
+
+  path = gtk_tree_path_new_from_string (path_string);
+  row = gtk_tree_path_get_indices (path)[0];
+  gtk_tree_path_free (path);
+
+  if (!psppire_dict_generate_name (dict, name, sizeof name))
+    return;
+
+  var = psppire_dict_insert_variable (dict, psppire_dict_get_var_cnt (dict),
+                                      name);
+  g_return_if_fail (var != NULL);
+
+  psppire_data_store_set_string (data_store, new_text, row, var, FALSE);
+
+  if (!data_sheet->scroll_to_right_signal)
+    {
+      gtk_widget_queue_resize (GTK_WIDGET (data_sheet));
+      data_sheet->scroll_to_right_signal =
+        g_signal_connect_after (gtk_widget_get_toplevel (GTK_WIDGET (data_sheet)), "check-resize",
+                                G_CALLBACK (scroll_to_right), data_sheet);
+    }
+  else
+    {
+      /* We could be more specific about what to redraw, if it seems
+         important for performance. */
+      gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
+    }
+}
+
+static void
+calc_width_conversion (PsppireDataSheet *data_sheet,
+                       gint *base_width, gint *incr_width)
+{
+  GtkCellRenderer *cell;
+  gint w1, w10;
+
+  cell = gtk_cell_renderer_text_new ();
+  w1 = get_monospace_width (PSPP_SHEET_VIEW (data_sheet), cell, 1);
+  w10 = get_monospace_width (PSPP_SHEET_VIEW (data_sheet), cell, 10);
+  *incr_width = MAX (1, (w10 - w1) / 9);
+  *base_width = MAX (0, w10 - *incr_width * 10);
+  g_object_ref_sink (cell);
+  g_object_unref (cell);
+}
+
+static gint
+display_width_from_pixel_width (PsppireDataSheet *data_sheet,
+                                gint pixel_width)
+{
+  gint base_width, incr_width;
+
+  calc_width_conversion (data_sheet, &base_width, &incr_width);
+  return MAX ((pixel_width - base_width + incr_width / 2) / incr_width, 1);
+}
+
+static gint
+display_width_to_pixel_width (PsppireDataSheet *data_sheet,
+                              gint display_width,
+                              gint base_width,
+                              gint incr_width)
+{
+  return base_width + incr_width * display_width;
+}
+
+static void
+on_data_column_resized (GObject    *gobject,
+                        GParamSpec *pspec,
+                        gpointer    user_data)
+{
+  PsppireDataSheet *data_sheet = user_data;
+  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
+  PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (gobject);
+  struct variable *var;
+  gint pixel_width;
+  int display_width;
+
+  if (data_store == NULL)
+    return;
+
+  pixel_width = pspp_sheet_view_column_get_width (column);
+  if (pixel_width == pspp_sheet_view_column_get_fixed_width (column))
+    {
+      /* Short-circuit the expensive display_width_from_pixel_width()
+         calculation, to make loading .sav files with 2000 columns visibly
+         faster. */
+      return;
+    }
+
+  var = g_object_get_data (G_OBJECT (column), "variable");
+  display_width = display_width_from_pixel_width (data_sheet, pixel_width);
+  var_set_display_width (var, display_width);
+}
+
+static void
+do_data_column_popup_menu (PsppSheetViewColumn *column,
+                           guint button, guint32 time)
+{
+  GtkWidget *sheet_view = pspp_sheet_view_column_get_tree_view (column);
+  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
+  GtkWidget *menu;
+
+  menu = get_widget_assert (data_sheet->builder, "datasheet-variable-popup");
+  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
+}
+
+static void
+on_data_column_popup_menu (PsppSheetViewColumn *column,
+                           gpointer user_data UNUSED)
+{
+  do_data_column_popup_menu (column, 0, gtk_get_current_event_time ());
+}
+
+static gboolean
+on_column_button_press_event (PsppSheetViewColumn *column,
+                              GdkEventButton *event,
+                              gpointer user_data UNUSED)
+{
+  PsppSheetSelection *selection;
+  PsppSheetView *sheet_view;
+
+  sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
+                                  column));
+  g_return_val_if_fail (sheet_view != NULL, FALSE);
+
+  selection = pspp_sheet_view_get_selection (sheet_view);
+  g_return_val_if_fail (selection != NULL, FALSE);
+
+  if (event->type == GDK_BUTTON_PRESS && event->button == 3)
+    {
+      do_data_column_popup_menu (column, event->button, event->time);
+      return TRUE;
+    }
+  else if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
+    {
+      PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
+      struct variable *var;
+
+      var = g_object_get_data (G_OBJECT (column), "variable");
+      if (var != NULL)
+        {
+          gboolean handled;
+
+          g_signal_emit_by_name (data_sheet, "var-double-clicked",
+                                 var_get_dict_index (var), &handled);
+          return handled;
+        }
+    }
+
+  return FALSE;
+}
+
+static gboolean
+on_data_column_query_tooltip (PsppSheetViewColumn *column,
+                              GtkTooltip *tooltip,
+                              gpointer user_data UNUSED)
+{
+  struct variable *var;
+  const char *text;
+
+  var = g_object_get_data (G_OBJECT (column), "variable");
+  g_return_val_if_fail (var != NULL, FALSE);
+
+  text = var_has_label (var) ? var_get_label (var) : var_get_name (var);
+  gtk_tooltip_set_text (tooltip, text);
+
+  return TRUE;
+}
+
+static void
+add_data_column_cell_renderer (PsppireDataSheet *data_sheet,
+                               PsppSheetViewColumn *column)
+{
+  GtkCellRenderer *cell;
+  struct variable *var;
+
+  var = g_object_get_data (G_OBJECT (column), "variable");
+  g_return_if_fail (var != NULL);
+
+  if (var_has_value_labels (var))
+    {
+      cell = gtk_cell_renderer_combo_new ();
+      g_object_set (G_OBJECT (cell),
+                    "has-entry", TRUE,
+                    "text-column", 0,
+                    NULL);
+    }
+  else
+    cell = gtk_cell_renderer_text_new ();
+
+  g_signal_connect (cell, "editing-started",
+                    G_CALLBACK (on_data_column_editing_started), NULL);
+  g_signal_connect (cell, "edited", G_CALLBACK (on_data_column_edited), NULL);
+
+  g_object_set_data (G_OBJECT (cell), "column", column);
+  g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet);
+
+  pspp_sheet_view_column_clear (column);
+  pspp_sheet_view_column_pack_start (column, cell, TRUE);
+
+  pspp_sheet_view_column_set_cell_data_func (
+    column, cell, render_data_cell, data_sheet, NULL);
+}
+
+static PsppSheetViewColumn *
+make_data_column (PsppireDataSheet *data_sheet, gint dict_idx,
+                  gint base_width, gint incr_width)
+{
+  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
+  struct variable *var;
+  PsppSheetViewColumn *column;
+  char *name;
+  int width;
+
+  var = psppire_dict_get_variable (data_store->dict, dict_idx);
+
+  column = pspp_sheet_view_column_new ();
+
+  name = escape_underscores (var_get_name (var));
+  pspp_sheet_view_column_set_title (column, name);
+  free (name);
+
+  g_object_set_data (G_OBJECT (column), "variable", var);
+
+  width = display_width_to_pixel_width (data_sheet,
+                                        var_get_display_width (var),
+                                        base_width, incr_width);
+  pspp_sheet_view_column_set_min_width (column, 10);
+  pspp_sheet_view_column_set_fixed_width (column, width);
+  pspp_sheet_view_column_set_resizable (column, TRUE);
+
+  pspp_sheet_view_column_set_clickable (column, TRUE);
+  g_signal_connect (column, "notify::width",
+                    G_CALLBACK (on_data_column_resized), data_sheet);
+
+  g_signal_connect (column, "button-press-event",
+                    G_CALLBACK (on_column_button_press_event),
+                    data_sheet);
+  g_signal_connect (column, "query-tooltip",
+                    G_CALLBACK (on_data_column_query_tooltip), NULL);
+  g_signal_connect (column, "popup-menu",
+                    G_CALLBACK (on_data_column_popup_menu), data_sheet);
+
+  add_data_column_cell_renderer (data_sheet, column);
+
+  return column;
+}
+
+static void
+make_new_variable_column (PsppireDataSheet *data_sheet,
+                          gint base_width, gint incr_width)
+{
+  PsppSheetViewColumn *column;
+  GtkCellRenderer *cell;
+  int width;
+
+  cell = gtk_cell_renderer_text_new ();
+  g_object_set (cell, "editable", TRUE, NULL);
+
+  g_signal_connect (cell, "edited", G_CALLBACK (on_new_variable_column_edited),
+                    NULL);
+
+  column = pspp_sheet_view_column_new_with_attributes ("", cell, NULL);
+  g_object_set_data (G_OBJECT (column), "new-var-column", column);
+
+  width = display_width_to_pixel_width (data_sheet, 8, base_width, incr_width);
+  pspp_sheet_view_column_set_min_width (column, 10);
+  pspp_sheet_view_column_set_fixed_width (column, width);
+
+  g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet);
+  g_signal_connect (column, "button-press-event",
+                    G_CALLBACK (on_column_button_press_event),
+                    data_sheet);
+  g_signal_connect (column, "popup-menu",
+                    G_CALLBACK (on_data_column_popup_menu), data_sheet);
+
+  pspp_sheet_view_column_set_visible (column, data_sheet->may_create_vars);
+
+  pspp_sheet_view_append_column (PSPP_SHEET_VIEW (data_sheet), column);
+  data_sheet->new_variable_column = column;
+}
+
+static void
+psppire_data_sheet_model_changed (GObject    *gobject,
+                                  GParamSpec *pspec,
+                                  gpointer    user_data)
+{
+  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (gobject);
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppireDataStore *data_store;
+
+  /* Remove old columns. */
+  for (;;)
+    {
+      PsppSheetViewColumn *column = pspp_sheet_view_get_column (sheet_view, 0);
+      if (column == NULL)
+        break;
+
+      pspp_sheet_view_remove_column (sheet_view, column);
+    }
+  data_sheet->new_variable_column = NULL;
+
+  if (pspp_sheet_view_get_model (sheet_view) == NULL)
+    {
+      /* Don't create any columns at all if there's no model.  Otherwise we'll
+         create some columns as part of the "dispose" callback for the sheet
+         view, which sets the model to NULL.  That causes warnings to be
+         logged and is obviously undesirable in any case. */
+      return;
+    }
+
+  /* Add new columns. */
+  data_store = psppire_data_sheet_get_data_store (data_sheet);
+  if (data_store != NULL)
+    {
+      gint base_width, incr_width;
+      int i;
+
+      calc_width_conversion (data_sheet, &base_width, &incr_width);
+
+      make_row_number_column (data_sheet, data_store);
+      for (i = 0; i < psppire_dict_get_var_cnt (data_store->dict); i++)
+        {
+          PsppSheetViewColumn *column;
+
+          column = make_data_column (data_sheet, i, base_width, incr_width);
+          pspp_sheet_view_append_column (sheet_view, column);
+        }
+      make_new_variable_column (data_sheet, base_width, incr_width);
+    }
+}
+
+enum
+  {
+    PROP_0,
+    PROP_DATA_STORE,
+    PROP_VALUE_LABELS,
+    PROP_CASE_NUMBERS,
+    PROP_CURRENT_CASE,
+    PROP_MAY_CREATE_VARS,
+    PROP_MAY_DELETE_VARS,
+    PROP_UI_MANAGER
+  };
+
+static void
+psppire_data_sheet_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  PsppireDataSheet *obj = PSPPIRE_DATA_SHEET (object);
+
+  switch (prop_id)
+    {
+    case PROP_DATA_STORE:
+      psppire_data_sheet_set_data_store (
+        obj, PSPPIRE_DATA_STORE (g_value_get_object (value)));
+      break;
+
+    case PROP_VALUE_LABELS:
+      psppire_data_sheet_set_value_labels (obj, g_value_get_boolean (value));
+      break;
+
+    case PROP_CASE_NUMBERS:
+      psppire_data_sheet_set_case_numbers (obj, g_value_get_boolean (value));
+      break;
+
+    case PROP_CURRENT_CASE:
+      psppire_data_sheet_goto_case (obj, g_value_get_long (value));
+      break;
+
+    case PROP_MAY_CREATE_VARS:
+      psppire_data_sheet_set_may_create_vars (obj,
+                                              g_value_get_boolean (value));
+      break;
+
+    case PROP_MAY_DELETE_VARS:
+      psppire_data_sheet_set_may_delete_vars (obj,
+                                              g_value_get_boolean (value));
+      break;
+
+    case PROP_UI_MANAGER:
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+psppire_data_sheet_get_property (GObject      *object,
+                                 guint         prop_id,
+                                 GValue       *value,
+                                 GParamSpec   *pspec)
+{
+  PsppireDataSheet *obj = PSPPIRE_DATA_SHEET (object);
+
+  switch (prop_id)
+    {
+    case PROP_DATA_STORE:
+      g_value_set_object (value, psppire_data_sheet_get_data_store (obj));
+      break;
+
+    case PROP_VALUE_LABELS:
+      g_value_set_boolean (value, psppire_data_sheet_get_value_labels (obj));
+      break;
+
+    case PROP_CASE_NUMBERS:
+      g_value_set_boolean (value, psppire_data_sheet_get_case_numbers (obj));
+      break;
+
+    case PROP_CURRENT_CASE:
+      g_value_set_long (value, psppire_data_sheet_get_selected_case (obj));
+      break;
+
+    case PROP_MAY_CREATE_VARS:
+      g_value_set_boolean (value, obj->may_create_vars);
+      break;
+
+    case PROP_MAY_DELETE_VARS:
+      g_value_set_boolean (value, obj->may_delete_vars);
+      break;
+
+    case PROP_UI_MANAGER:
+      g_value_set_object (value, psppire_data_sheet_get_ui_manager (obj));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+gboolean
+psppire_data_sheet_get_value_labels (const PsppireDataSheet *ds)
+{
+  return ds->show_value_labels;
+}
+
+void
+psppire_data_sheet_set_value_labels (PsppireDataSheet *ds,
+                                  gboolean show_value_labels)
+{
+  show_value_labels = !!show_value_labels;
+  if (show_value_labels != ds->show_value_labels)
+    {
+      ds->show_value_labels = show_value_labels;
+      g_object_notify (G_OBJECT (ds), "value-labels");
+      gtk_widget_queue_draw (GTK_WIDGET (ds));
+
+      /* Make the cell being edited refresh too. */
+      pspp_sheet_view_stop_editing (PSPP_SHEET_VIEW (ds), TRUE);
+    }
+}
+
+gboolean
+psppire_data_sheet_get_case_numbers (const PsppireDataSheet *ds)
+{
+  return ds->show_case_numbers;
+}
+
+void
+psppire_data_sheet_set_case_numbers (PsppireDataSheet *ds,
+                                     gboolean show_case_numbers)
+{
+  show_case_numbers = !!show_case_numbers;
+  if (show_case_numbers != ds->show_case_numbers)
+    {
+      PsppSheetViewColumn *column;
+
+      ds->show_case_numbers = show_case_numbers;
+      column = pspp_sheet_view_get_column (PSPP_SHEET_VIEW (ds), 0);
+      if (column)
+        pspp_sheet_view_column_set_visible (column, show_case_numbers);
+
+      g_object_notify (G_OBJECT (ds), "case-numbers");
+      gtk_widget_queue_draw (GTK_WIDGET (ds));
+    }
+}
+
+gboolean
+psppire_data_sheet_get_may_create_vars (PsppireDataSheet *data_sheet)
+{
+  return data_sheet->may_create_vars;
+}
+
+void
+psppire_data_sheet_set_may_create_vars (PsppireDataSheet *data_sheet,
+                                       gboolean may_create_vars)
+{
+  if (data_sheet->may_create_vars != may_create_vars)
+    {
+      data_sheet->may_create_vars = may_create_vars;
+      if (data_sheet->new_variable_column)
+        pspp_sheet_view_column_set_visible (data_sheet->new_variable_column,
+                                            may_create_vars);
+
+      on_selection_changed (pspp_sheet_view_get_selection (
+                              PSPP_SHEET_VIEW (data_sheet)), NULL);
+    }
+}
+
+gboolean
+psppire_data_sheet_get_may_delete_vars (PsppireDataSheet *data_sheet)
+{
+  return data_sheet->may_delete_vars;
+}
+
+void
+psppire_data_sheet_set_may_delete_vars (PsppireDataSheet *data_sheet,
+                                       gboolean may_delete_vars)
+{
+  if (data_sheet->may_delete_vars != may_delete_vars)
+    {
+      data_sheet->may_delete_vars = may_delete_vars;
+      on_selection_changed (pspp_sheet_view_get_selection (
+                              PSPP_SHEET_VIEW (data_sheet)), NULL);
+    }
+}
+
+static PsppSheetViewColumn *
+psppire_data_sheet_find_column_for_variable (PsppireDataSheet *data_sheet,
+                                             gint dict_index)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppireDataStore *data_store;
+  PsppSheetViewColumn *column;
+  struct variable *var;
+  GList *list, *iter;
+
+  data_store = psppire_data_sheet_get_data_store (data_sheet);
+  g_return_val_if_fail (data_store != NULL, NULL);
+  g_return_val_if_fail (data_store->dict != NULL, NULL);
+
+  var = psppire_dict_get_variable (data_store->dict, dict_index);
+  g_return_val_if_fail (var != NULL, NULL);
+
+  column = NULL;
+  list = pspp_sheet_view_get_columns (sheet_view);
+  for (iter = list; iter != NULL; iter = iter->next)
+    {
+      PsppSheetViewColumn *c = iter->data;
+      struct variable *v;
+
+      v = g_object_get_data (G_OBJECT (c), "variable");
+      if (v == var)
+        {
+          column = c;
+          break;
+        }
+    }
+  g_list_free (list);
+
+  return column;
+}
+
+void
+psppire_data_sheet_show_variable (PsppireDataSheet *data_sheet,
+                                  gint dict_index)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppSheetViewColumn *column;
+
+  column = psppire_data_sheet_find_column_for_variable (data_sheet,
+                                                        dict_index);
+  if (column != NULL)
+    pspp_sheet_view_scroll_to_cell (sheet_view, NULL, column,
+                                    FALSE, 0.0, 0.0);
+}
+
+struct variable *
+psppire_data_sheet_get_current_variable (const PsppireDataSheet *data_sheet)
+{
+  PsppSheetSelection *selection;
+  struct variable *var;
+  GList *selected_columns;
+  GList *iter;
+
+  selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (data_sheet));
+  selected_columns = pspp_sheet_selection_get_selected_columns (selection);
+
+  var = NULL;
+  for (iter = selected_columns; iter != NULL; iter = iter->next)
+    {
+      PsppSheetViewColumn *column = iter->data;
+      struct variable *v = g_object_get_data (G_OBJECT (column), "variable");
+      if (v != NULL)
+        {
+          if (var)
+            {
+              var = NULL;
+              break;
+            }
+          else
+            var = v;
+        }
+    }
+
+  g_list_free (selected_columns);
+
+  return var;
+
+}
+void
+psppire_data_sheet_goto_case (PsppireDataSheet *data_sheet, gint case_index)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppireDataStore *store = data_sheet->data_store;
+  PsppSheetSelection *selection;
+  GtkTreePath *path;
+
+  g_return_if_fail (case_index >= 0);
+  g_return_if_fail (case_index < psppire_data_store_get_case_count (store));
+
+  path = gtk_tree_path_new_from_indices (case_index, -1);
+
+  /* Select the case. */
+  selection = pspp_sheet_view_get_selection (sheet_view);
+  pspp_sheet_selection_unselect_all (selection);
+  pspp_sheet_selection_select_path (selection, path);
+  pspp_sheet_selection_select_all_columns (selection);
+
+  /* Scroll so that the case is visible. */
+  pspp_sheet_view_scroll_to_cell (sheet_view, path, NULL, FALSE, 0.0, 0.0);
+
+  gtk_tree_path_free (path);
+}
+
+/* Returns the 0-based index of a selected case, if there is at least one, and
+   -1 otherwise.
+
+   If more than one case is selected, returns the one with the smallest index,
+   that is, the index of the case closest to the beginning of the file.  The
+   row that can be used to insert a new case is not considered a case. */
+gint
+psppire_data_sheet_get_selected_case (const PsppireDataSheet *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppireDataStore *store = data_sheet->data_store;
+  const struct range_set_node *node;
+  PsppSheetSelection *selection;
+  struct range_set *rows;
+  gint row;
+
+  selection = pspp_sheet_view_get_selection (sheet_view);
+  rows = pspp_sheet_selection_get_range_set (selection);
+  node = range_set_first (rows);
+  row = (node && node->start < psppire_data_store_get_case_count (store)
+         ? node->start
+         : -1);
+  range_set_destroy (rows);
+
+  return row;
+}
+
+/* Returns the 0-based index of a selected case, if exactly one case is
+   selected, and -1 otherwise.  Returns -1 if the row that can be used to
+   insert a new case is selected. */
+gint
+psppire_data_sheet_get_current_case (const PsppireDataSheet *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppireDataStore *store = data_sheet->data_store;
+  const struct range_set_node *node;
+  PsppSheetSelection *selection;
+  struct range_set *rows;
+  gint row;
+
+  selection = pspp_sheet_view_get_selection (sheet_view);
+  if (pspp_sheet_selection_count_selected_rows (selection) != 1)
+    return -1;
+
+  rows = pspp_sheet_selection_get_range_set (selection);
+  node = range_set_first (rows);
+  row = (node && node->start < psppire_data_store_get_case_count (store)
+         ? node->start
+         : -1);
+  range_set_destroy (rows);
+
+  return row;
+}
+
+GtkUIManager *
+psppire_data_sheet_get_ui_manager (PsppireDataSheet *data_sheet)
+{
+  if (data_sheet->uim == NULL)
+    {
+      data_sheet->uim = 
+       GTK_UI_MANAGER (get_object_assert (data_sheet->builder,
+                                          "data_sheet_uim",
+                                          GTK_TYPE_UI_MANAGER));
+      g_object_ref (data_sheet->uim);
+    }
+
+  return data_sheet->uim;
+}
+
+static void
+psppire_data_sheet_dispose (GObject *object)
+{
+  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (object);
+
+  if (data_sheet->dispose_has_run)
+    return;
+
+  data_sheet->dispose_has_run = TRUE;
+
+  psppire_data_sheet_unset_data_store (data_sheet);
+
+  g_object_unref (data_sheet->builder);
+
+  if (data_sheet->uim)
+    g_object_unref (data_sheet->uim);
+
+  G_OBJECT_CLASS (psppire_data_sheet_parent_class)->dispose (object);
+}
+
+static void
+psppire_data_sheet_class_init (PsppireDataSheetClass *class)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (class);
+  gobject_class->set_property = psppire_data_sheet_set_property;
+  gobject_class->get_property = psppire_data_sheet_get_property;
+
+  gobject_class->dispose = psppire_data_sheet_dispose;
+
+  g_signal_new ("var-double-clicked",
+                G_OBJECT_CLASS_TYPE (gobject_class),
+                G_SIGNAL_RUN_LAST,
+                0,
+                g_signal_accumulator_true_handled, NULL,
+                psppire_marshal_BOOLEAN__INT,
+                G_TYPE_BOOLEAN, 1, G_TYPE_INT);
+
+  g_object_class_install_property (
+    gobject_class, PROP_DATA_STORE,
+    g_param_spec_object ("data-store",
+                         "Data Store",
+                         "The data store for the data sheet to display.",
+                         PSPPIRE_TYPE_DATA_STORE,
+                         G_PARAM_WRITABLE | G_PARAM_READABLE));
+
+  g_object_class_install_property (
+    gobject_class, PROP_VALUE_LABELS,
+    g_param_spec_boolean ("value-labels",
+                          "Value Labels",
+                          "Whether or not the data sheet should display labels instead of values",
+                         FALSE,
+                          G_PARAM_WRITABLE | G_PARAM_READABLE));
+
+  g_object_class_install_property (
+    gobject_class, PROP_CASE_NUMBERS,
+    g_param_spec_boolean ("case-numbers",
+                          "Case Numbers",
+                          "Whether or not the data sheet should display case numbers",
+                         FALSE,
+                          G_PARAM_WRITABLE | G_PARAM_READABLE));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_CURRENT_CASE,
+    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 (
+    gobject_class,
+    PROP_MAY_CREATE_VARS,
+    g_param_spec_boolean ("may-create-vars",
+                          "May create variables",
+                          "Whether the user may create more variables",
+                          TRUE,
+                          G_PARAM_READWRITE));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_MAY_DELETE_VARS,
+    g_param_spec_boolean ("may-delete-vars",
+                          "May delete variables",
+                          "Whether the user may delete variables",
+                          TRUE,
+                          G_PARAM_READWRITE));
+
+  g_object_class_install_property (
+    gobject_class,
+    PROP_UI_MANAGER,
+    g_param_spec_object ("ui-manager",
+                         "UI Manager",
+                         "UI manager for the data sheet.  The client should merge this UI manager with the active UI manager to obtain data sheet specific menu items and tool bar items.",
+                         GTK_TYPE_UI_MANAGER,
+                         G_PARAM_READABLE));
+}
+
+static void
+do_popup_menu (GtkWidget *widget, guint button, guint32 time)
+{
+  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
+  GtkWidget *menu;
+
+  menu = get_widget_assert (data_sheet->builder, "datasheet-cases-popup");
+  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
+}
+
+static void
+on_popup_menu (GtkWidget *widget, gpointer user_data UNUSED)
+{
+  do_popup_menu (widget, 0, gtk_get_current_event_time ());
+}
+
+static gboolean
+on_button_pressed (GtkWidget *widget, GdkEventButton *event,
+                   gpointer user_data UNUSED)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
+
+  if (event->type == GDK_BUTTON_PRESS && event->button == 3)
+    {
+      PsppSheetSelection *selection;
+
+      selection = pspp_sheet_view_get_selection (sheet_view);
+      if (pspp_sheet_selection_count_selected_rows (selection) <= 1)
+        {
+          GtkTreePath *path;
+
+          if (pspp_sheet_view_get_path_at_pos (sheet_view, event->x, event->y,
+                                               &path, NULL, NULL, NULL))
+            {
+              pspp_sheet_selection_unselect_all (selection);
+              pspp_sheet_selection_select_path (selection, path);
+              pspp_sheet_selection_select_all_columns (selection);
+              gtk_tree_path_free (path);
+            }
+        }
+
+      do_popup_menu (widget, event->button, event->time);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+on_edit_clear_cases (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
+  const struct range_set_node *node;
+  struct range_set *selected;
+
+  selected = pspp_sheet_selection_get_range_set (selection);
+  for (node = range_set_last (selected); node != NULL;
+       node = range_set_prev (selected, node))
+    {
+      unsigned long int start = range_set_node_get_start (node);
+      unsigned long int count = range_set_node_get_width (node);
+
+      psppire_data_store_delete_cases (data_sheet->data_store, start, count);
+    }
+  range_set_destroy (selected);
+}
+
+static void
+on_selection_changed (PsppSheetSelection *selection,
+                      gpointer user_data UNUSED)
+{
+  PsppSheetView *sheet_view = pspp_sheet_selection_get_tree_view (selection);
+  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
+  gint n_selected_rows;
+  gboolean may_delete_cases, may_delete_vars, may_insert_vars;
+  GList *list, *iter;
+  GtkTreePath *path;
+  GtkAction *action;
+
+  n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
+
+  action = get_action_assert (data_sheet->builder, "edit_insert-case");
+  gtk_action_set_sensitive (action, n_selected_rows > 0);
+
+  switch (n_selected_rows)
+    {
+    case 0:
+      may_delete_cases = FALSE;
+      break;
+
+    case 1:
+      /* The row used for inserting new cases cannot be deleted. */
+      path = gtk_tree_path_new_from_indices (
+        psppire_data_store_get_case_count (data_sheet->data_store), -1);
+      may_delete_cases = !pspp_sheet_selection_path_is_selected (selection,
+                                                                 path);
+      gtk_tree_path_free (path);
+      break;
+
+    default:
+      may_delete_cases = TRUE;
+      break;
+    }
+  action = get_action_assert (data_sheet->builder, "edit_clear-cases");
+  gtk_action_set_sensitive (action, may_delete_cases);
+
+  may_delete_vars = may_insert_vars = FALSE;
+  list = pspp_sheet_selection_get_selected_columns (selection);
+  for (iter = list; iter != NULL; iter = iter->next)
+    {
+      PsppSheetViewColumn *column = iter->data;
+      struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
+
+      if (var != NULL)
+        {
+          may_delete_vars = may_insert_vars = TRUE;
+          break;
+        }
+      if (g_object_get_data (G_OBJECT (column), "new-var-column") != NULL)
+        may_insert_vars = TRUE;
+    }
+  g_list_free (list);
+
+  may_insert_vars = may_insert_vars && data_sheet->may_create_vars;
+  may_delete_vars = may_delete_vars && data_sheet->may_delete_vars;
+
+  action = get_action_assert (data_sheet->builder, "edit_insert-variable");
+  gtk_action_set_sensitive (action, may_insert_vars);
+
+  action = get_action_assert (data_sheet->builder, "edit_clear-variables");
+  gtk_action_set_sensitive (action, may_delete_vars);
+
+  action = get_action_assert (data_sheet->builder, "sort-up");
+  gtk_action_set_sensitive (action, may_delete_vars);
+
+  action = get_action_assert (data_sheet->builder, "sort-down");
+  gtk_action_set_sensitive (action, may_delete_vars);
+
+  psppire_data_sheet_update_clip_actions (data_sheet);
+}
+
+static gboolean
+psppire_data_sheet_get_selected_range (PsppireDataSheet *data_sheet,
+                                    struct range_set **rowsp,
+                                    struct range_set **colsp)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppireDataStore *data_store = data_sheet->data_store;
+  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
+  unsigned long n_cases;
+  struct range_set *rows, *cols;
+  GList *list, *iter;
+
+  if (data_store == NULL)
+    return FALSE;
+  n_cases = psppire_data_store_get_case_count (data_store);
+
+  rows = pspp_sheet_selection_get_range_set (selection);
+  range_set_set0 (rows, n_cases, ULONG_MAX - n_cases);
+  if (range_set_is_empty (rows))
+    {
+      range_set_destroy (rows);
+      return FALSE;
+    }
+
+  cols = range_set_create ();
+  list = pspp_sheet_selection_get_selected_columns (selection);
+  for (iter = list; iter != NULL; iter = iter->next)
+    {
+      PsppSheetViewColumn *column = iter->data;
+      struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
+
+      if (var != NULL)
+        range_set_set1 (cols, var_get_dict_index (var), 1);
+    }
+  g_list_free (list);
+  if (range_set_is_empty (cols))
+    {
+      range_set_destroy (rows);
+      range_set_destroy (cols);
+      return FALSE;
+    }
+
+  *rowsp = rows;
+  *colsp = cols;
+  return TRUE;
+}
+
+static void
+on_edit_insert_case (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
+  PsppireDataStore *data_store = data_sheet->data_store;
+  struct range_set *selected;
+  unsigned long row;
+
+  selected = pspp_sheet_selection_get_range_set (selection);
+  row = range_set_scan (selected, 0);
+  range_set_destroy (selected);
+
+  if (row <= psppire_data_store_get_case_count (data_store))
+    psppire_data_store_insert_new_case (data_store, row);
+}
+
+static void
+on_edit_insert_variable (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
+  PsppireDict *dict = data_sheet->data_store->dict;
+  PsppSheetViewColumn *column;
+  struct variable *var;
+  gchar name[64];
+  GList *list;
+  gint index;
+
+  list = pspp_sheet_selection_get_selected_columns (selection);
+  if (list == NULL)
+    return;
+  column = list->data;
+  g_list_free (list);
+
+  var = g_object_get_data (G_OBJECT (column), "variable");
+  index = var ? var_get_dict_index (var) : psppire_dict_get_var_cnt (dict);
+  if (psppire_dict_generate_name (dict, name, sizeof name))
+    psppire_dict_insert_variable (dict, index, name);
+}
+
+static void
+on_edit_clear_variables (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
+  PsppireDict *dict = data_sheet->data_store->dict;
+  GList *list, *iter;
+
+  list = pspp_sheet_selection_get_selected_columns (selection);
+  if (list == NULL)
+    return;
+  list = g_list_reverse (list);
+  for (iter = list; iter; iter = iter->next)
+    {
+      PsppSheetViewColumn *column = iter->data;
+      struct variable *var;
+
+      var = g_object_get_data (G_OBJECT (column), "variable");
+      if (var != NULL)
+        psppire_dict_delete_variables (dict, var_get_dict_index (var), 1);
+    }
+  g_list_free (list);
+}
+
+enum sort_order
+  {
+    SORT_ASCEND,
+    SORT_DESCEND
+  };
+
+static void
+do_sort (PsppireDataSheet *data_sheet, enum sort_order order)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
+  PsppireDataWindow *pdw;
+  GList *list, *iter;
+  GString *syntax;
+  int n_vars;
+
+  pdw = psppire_data_window_for_data_store (data_sheet->data_store);
+  g_return_if_fail (pdw != NULL);
+
+  list = pspp_sheet_selection_get_selected_columns (selection);
+
+  syntax = g_string_new ("SORT CASES BY");
+  n_vars = 0;
+  for (iter = list; iter; iter = iter->next)
+    {
+      PsppSheetViewColumn *column = iter->data;
+      struct variable *var;
+
+      var = g_object_get_data (G_OBJECT (column), "variable");
+      if (var != NULL)
+        {
+          g_string_append_printf (syntax, " %s", var_get_name (var));
+          n_vars++;
+        }
+    }
+  if (n_vars > 0)
+    {
+      if (order == SORT_DESCEND)
+        g_string_append (syntax, " (DOWN)");
+      g_string_append_c (syntax, '.');
+      execute_const_syntax_string (pdw, syntax->str);
+    }
+  g_string_free (syntax, TRUE);
+}
+
+void
+on_sort_up (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  do_sort (data_sheet, SORT_ASCEND);
+}
+
+void
+on_sort_down (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  do_sort (data_sheet, SORT_DESCEND);
+}
+
+void
+on_edit_goto_case (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  goto_case_dialog (data_sheet);
+}
+
+void
+on_edit_find (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  PsppireDataWindow *pdw;
+
+  pdw = psppire_data_window_for_data_store (data_sheet->data_store);
+  g_return_if_fail (pdw != NULL);
+
+  find_dialog (pdw);
+}
+
+void
+on_edit_copy (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  psppire_data_sheet_set_clip (data_sheet);
+}
+
+static void
+psppire_data_sheet_init (PsppireDataSheet *obj)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (obj);
+  GtkAction *action;
+
+  obj->show_value_labels = FALSE;
+  obj->show_case_numbers = TRUE;
+  obj->may_create_vars = TRUE;
+  obj->may_delete_vars = TRUE;
+
+  obj->scroll_to_bottom_signal = 0;
+  obj->scroll_to_right_signal = 0;
+  obj->new_variable_column = NULL;
+  obj->container = NULL;
+
+  obj->uim = NULL;
+  obj->dispose_has_run = FALSE;
+
+  pspp_sheet_view_set_special_cells (sheet_view, PSPP_SHEET_VIEW_SPECIAL_CELLS_YES);
+
+  g_signal_connect (obj, "notify::model",
+                    G_CALLBACK (psppire_data_sheet_model_changed), NULL);
+
+  pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
+  pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
+                                 PSPP_SHEET_SELECTION_RECTANGLE);
+
+  g_object_set (G_OBJECT (obj), "has-tooltip", TRUE, (void *) NULL);
+  g_signal_connect (obj, "query-tooltip",
+                    G_CALLBACK (on_query_tooltip), NULL);
+  g_signal_connect (obj, "button-press-event",
+                    G_CALLBACK (on_button_pressed), NULL);
+  g_signal_connect (obj, "popup-menu", G_CALLBACK (on_popup_menu), NULL);
+
+  obj->builder = builder_new ("data-sheet.ui");
+
+  action = get_action_assert (obj->builder, "edit_clear-cases");
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_clear_cases),
+                    obj);
+  gtk_action_set_sensitive (action, FALSE);
+  g_signal_connect (pspp_sheet_view_get_selection (sheet_view),
+                    "changed", G_CALLBACK (on_selection_changed), NULL);
+
+  action = get_action_assert (obj->builder, "edit_insert-case");
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_insert_case),
+                    obj);
+
+  action = get_action_assert (obj->builder, "edit_insert-variable");
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_insert_variable),
+                    obj);
+
+  action = get_action_assert (obj->builder, "edit_goto-case");
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_goto_case),
+                    obj);
+
+  action = get_action_assert (obj->builder, "edit_copy");
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_copy), obj);
+
+  action = get_action_assert (obj->builder, "edit_clear-variables");
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_clear_variables),
+                    obj);
+
+  action = get_action_assert (obj->builder, "edit_find");
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_find), obj);
+
+  action = get_action_assert (obj->builder, "sort-up");
+  g_signal_connect (action, "activate", G_CALLBACK (on_sort_up), obj);
+
+  action = get_action_assert (obj->builder, "sort-down");
+  g_signal_connect (action, "activate", G_CALLBACK (on_sort_down), obj);
+
+}
+
+GtkWidget *
+psppire_data_sheet_new (void)
+{
+  return g_object_new (PSPP_TYPE_DATA_SHEET, NULL);
+}
+
+PsppireDataStore *
+psppire_data_sheet_get_data_store (PsppireDataSheet *data_sheet)
+{
+  return data_sheet->data_store;
+}
+
+static void
+refresh_model (PsppireDataSheet *data_sheet)
+{
+  pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet), NULL);
+
+  if (data_sheet->data_store != NULL)
+    {
+      PsppireEmptyListStore *model;
+      GtkAction *action;
+      int n_rows;
+
+      n_rows = psppire_data_store_get_case_count (data_sheet->data_store) + 1;
+      model = psppire_empty_list_store_new (n_rows);
+      pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet),
+                                 GTK_TREE_MODEL (model));
+      g_object_unref (model);
+
+      action = get_action_assert (data_sheet->builder, "edit_copy");
+      g_signal_connect (action, "activate", G_CALLBACK (on_edit_copy),
+                        data_sheet);
+    }
+}
+
+static void
+on_case_inserted (PsppireDataStore *data_store, gint row,
+                  PsppireDataSheet *data_sheet)
+{
+  PsppireEmptyListStore *empty_list_store;
+  GtkTreeModel *tree_model;
+  gint n_rows;
+
+  g_return_if_fail (data_store == data_sheet->data_store);
+
+  n_rows = psppire_data_store_get_case_count (data_store) + 1;
+  if (row == n_rows - 1)
+    row++;
+
+  tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
+  empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
+  psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
+  psppire_empty_list_store_row_inserted (empty_list_store, row);
+}
+
+static void
+on_cases_deleted (PsppireDataStore *data_store, gint first, gint n_cases,
+                  PsppireDataSheet *data_sheet)
+{
+
+  g_return_if_fail (data_store == data_sheet->data_store);
+
+  if (n_cases > 1)
+    {
+      /* This is a bit of a cop-out.  We could do better, if it ever turns out
+         that this performs too poorly. */
+      refresh_model (data_sheet);
+    }
+  else
+    {
+      PsppireEmptyListStore *empty_list_store;
+      GtkTreeModel *tree_model;
+      gint n_rows = psppire_data_store_get_case_count (data_store) + 1;
+
+      tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
+      empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
+      psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
+      psppire_empty_list_store_row_deleted (empty_list_store, first);
+    }
+}
+
+static void
+on_case_change (PsppireDataStore *data_store, gint row,
+                PsppireDataSheet *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+
+  pspp_sheet_view_stop_editing (sheet_view, TRUE);
+  gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
+}
+
+static void
+on_backend_changed (PsppireDataStore *data_store,
+                    PsppireDataSheet *data_sheet)
+{
+  g_return_if_fail (data_store == data_sheet->data_store);
+  refresh_model (data_sheet);
+}
+
+static void
+on_variable_display_width_changed (PsppireDict *dict, int dict_index,
+                                   PsppireDataSheet *data_sheet)
+{
+  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
+  PsppSheetViewColumn *column;
+  struct variable *var;
+  int display_width;
+  gint pixel_width;
+
+  g_return_if_fail (data_sheet->data_store != NULL);
+  g_return_if_fail (dict == data_sheet->data_store->dict);
+
+  column = psppire_data_sheet_find_column_for_variable (data_sheet,
+                                                        dict_index);
+  if (column == NULL)
+    return;
+
+  var = psppire_dict_get_variable (data_store->dict, dict_index);
+  g_return_if_fail (var != NULL);
+
+  pixel_width = pspp_sheet_view_column_get_fixed_width (column);
+  display_width = display_width_from_pixel_width (data_sheet, pixel_width);
+  if (display_width != var_get_display_width (var))
+    {
+      gint base_width, incr_width;
+
+      display_width = var_get_display_width (var);
+      calc_width_conversion (data_sheet, &base_width, &incr_width);
+      pixel_width = display_width_to_pixel_width (data_sheet, display_width,
+                                                  base_width, incr_width);
+      pspp_sheet_view_column_set_fixed_width (column, pixel_width);
+    }
+}
+
+static void
+on_variable_changed (PsppireDict *dict, int dict_index,
+                     PsppireDataSheet *data_sheet)
+{
+  PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
+  PsppSheetViewColumn *column;
+  GtkCellRenderer *cell;
+  struct variable *var;
+  GList *cells;
+  char *name;
+
+  g_return_if_fail (data_sheet->data_store != NULL);
+  g_return_if_fail (dict == data_sheet->data_store->dict);
+
+  column = psppire_data_sheet_find_column_for_variable (data_sheet,
+                                                        dict_index);
+  if (column == NULL)
+    return;
+
+  var = psppire_dict_get_variable (data_store->dict, dict_index);
+  g_return_if_fail (var != NULL);
+
+  name = escape_underscores (var_get_name (var));
+  if (strcmp (name, pspp_sheet_view_column_get_title (column)))
+    pspp_sheet_view_column_set_title (column, name);
+  free (name);
+
+  cells = pspp_sheet_view_column_get_cell_renderers (column);
+  g_return_if_fail (cells);
+  cell = cells->data;
+  g_list_free (cells);
+
+  if (var_has_value_labels (var) != GTK_IS_CELL_RENDERER_COMBO (cell))
+    {
+      /* Stop editing before we delete and replace the cell renderers.
+         Otherwise if this column is currently being edited, an eventual call
+         to pspp_sheet_view_stop_editing() will obtain a NULL cell and pass
+         that to gtk_cell_renderer_stop_editing(), which causes a critical.
+
+         It's possible that this is a bug in PsppSheetView, and it's possible
+         that PsppSheetView inherits that from GtkTreeView, but I haven't
+         investigated yet. */
+      pspp_sheet_view_stop_editing (PSPP_SHEET_VIEW (data_sheet), TRUE);
+
+      add_data_column_cell_renderer (data_sheet, column);
+    }
+}
+
+static void
+on_variable_inserted (PsppireDict *dict, int var_index,
+                      PsppireDataSheet *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  gint base_width, incr_width;
+  PsppSheetViewColumn *column;
+
+  calc_width_conversion (data_sheet, &base_width, &incr_width);
+  column = make_data_column (data_sheet, var_index, base_width, incr_width);
+  pspp_sheet_view_insert_column (sheet_view, column, var_index + 1);
+}
+
+static void
+on_variable_deleted (PsppireDict *dict,
+                     const struct variable *var, int case_idx, int width,
+                     PsppireDataSheet *data_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
+  GList *columns, *iter;
+
+  columns = pspp_sheet_view_get_columns (sheet_view);
+  for (iter = columns; iter != NULL; iter = iter->next)
+    {
+      PsppSheetViewColumn *column = iter->data;
+      const struct variable *column_var;
+
+      column_var = g_object_get_data (G_OBJECT (column), "variable");
+      if (column_var == var)
+        pspp_sheet_view_remove_column (sheet_view, column);
+    }
+  g_list_free (columns);
+}
+
+static void
+psppire_data_sheet_unset_data_store (PsppireDataSheet *data_sheet)
+{
+  PsppireDataStore *store = data_sheet->data_store;
+
+  if (store == NULL)
+    return;
+
+  data_sheet->data_store = NULL;
+
+  g_signal_handlers_disconnect_by_func (
+    store, G_CALLBACK (on_backend_changed), data_sheet);
+  g_signal_handlers_disconnect_by_func (
+    store, G_CALLBACK (on_case_inserted), data_sheet);
+  g_signal_handlers_disconnect_by_func (
+    store, G_CALLBACK (on_cases_deleted), data_sheet);
+  g_signal_handlers_disconnect_by_func (
+    store, G_CALLBACK (on_case_change), data_sheet);
+
+  g_signal_handlers_disconnect_by_func (
+    store->dict, G_CALLBACK (on_variable_changed), data_sheet);
+  g_signal_handlers_disconnect_by_func (
+    store->dict, G_CALLBACK (on_variable_display_width_changed), data_sheet);
+  g_signal_handlers_disconnect_by_func (
+    store->dict, G_CALLBACK (on_variable_inserted), data_sheet);
+  g_signal_handlers_disconnect_by_func (
+    store->dict, G_CALLBACK (on_variable_deleted), data_sheet);
+
+  g_object_unref (store);
+}
+
+void
+psppire_data_sheet_set_data_store (PsppireDataSheet *data_sheet,
+                                PsppireDataStore *data_store)
+{
+  psppire_data_sheet_unset_data_store (data_sheet);
+
+  data_sheet->data_store = data_store;
+  if (data_store != NULL)
+    {
+      g_object_ref (data_store);
+      g_signal_connect (data_store, "backend-changed",
+                        G_CALLBACK (on_backend_changed), data_sheet);
+      g_signal_connect (data_store, "case-inserted",
+                        G_CALLBACK (on_case_inserted), data_sheet);
+      g_signal_connect (data_store, "cases-deleted",
+                        G_CALLBACK (on_cases_deleted), data_sheet);
+      g_signal_connect (data_store, "case-changed",
+                        G_CALLBACK (on_case_change), data_sheet);
+
+      /* XXX it's unclean to hook into the dict this way--what if the dict
+         changes?  As of this writing, though, nothing ever changes the
+         data_store's dict. */
+      g_signal_connect (data_store->dict, "variable-changed",
+                        G_CALLBACK (on_variable_changed),
+                        data_sheet);
+      g_signal_connect (data_store->dict, "variable-display-width-changed",
+                        G_CALLBACK (on_variable_display_width_changed),
+                        data_sheet);
+      g_signal_connect (data_store->dict, "variable-inserted",
+                        G_CALLBACK (on_variable_inserted), data_sheet);
+      g_signal_connect (data_store->dict, "variable-deleted",
+                        G_CALLBACK (on_variable_deleted), data_sheet);
+    }
+  refresh_model (data_sheet);
+}
+\f
+/* Clipboard stuff */
+
+/* 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 psppire_data_sheet_update_clipboard (PsppireDataSheet *);
+
+/* Set the clip according to the currently
+   selected range in the data sheet */
+static void
+psppire_data_sheet_set_clip (PsppireDataSheet *data_sheet)
+{
+  struct casewriter *writer ;
+  PsppireDataStore *ds = psppire_data_sheet_get_data_store (data_sheet);
+  struct case_map *map = NULL;
+  struct range_set *rows, *cols;
+  const struct range_set_node *node;
+
+  if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
+    return;
+
+
+  /* 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 (dict_get_encoding (ds->dict->dict));
+  RANGE_SET_FOR_EACH (node, cols)
+    {
+      int dict_index;
+
+      for (dict_index = node->start; dict_index < node->end; dict_index++)
+        {
+          struct variable *var = dict_get_var (ds->dict->dict, dict_index);
+          dict_clone_var_assert (clip_dict, var);
+        }
+    }
+
+  /* Construct clip data. */
+  map = case_map_by_name (ds->dict->dict, clip_dict);
+  writer = autopaging_writer_create (dict_get_proto (clip_dict));
+  RANGE_SET_FOR_EACH (node, rows)
+    {
+      unsigned long int row;
+
+      for (row = node->start; row < node->end; row++)
+        {
+          struct ccase *old = psppire_data_store_get_case (ds, row);
+          if (old != NULL)
+            casewriter_write (writer, case_map_execute (map, old));
+          else
+            casewriter_force_error (writer);
+        }
+    }
+  case_map_destroy (map);
+
+  range_set_destroy (rows);
+  range_set_destroy (cols);
+
+  clip_datasheet = casewriter_make_reader (writer);
+
+  psppire_data_sheet_update_clipboard (data_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)
+{
+  const struct fmt_spec *fs = var_get_print_format (v);
+  const union value *val = case_data (cc, v);
+
+  char *s = data_out (val, var_get_encoding (v), fs);
+
+  g_string_append (string, s);
+
+  g_free (s);
+}
+
+static GString *
+clip_to_text (void)
+{
+  casenumber r;
+  GString *string;
+
+  const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (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 = caseproto_get_n_widths (casereader_get_proto (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 (80 + 20 * val_cnt * case_cnt);
+
+  g_string_append (string,
+                  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
+
+  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
+psppire_data_sheet_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
+psppire_data_sheet_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
+psppire_data_sheet_update_clipboard (PsppireDataSheet *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),
+                                    psppire_data_sheet_clipboard_get_cb,
+                                     psppire_data_sheet_clipboard_clear_cb,
+                                    G_OBJECT (sheet)))
+    psppire_data_sheet_clipboard_clear_cb (clipboard, sheet);
+}
+
+static void
+psppire_data_sheet_update_clip_actions (PsppireDataSheet *data_sheet)
+{
+  struct range_set *rows, *cols;
+  GtkAction *action;
+  gboolean enable;
+
+  enable = psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols);
+  if (enable)
+    {
+      range_set_destroy (rows);
+      range_set_destroy (cols);
+    }
+
+  action = get_action_assert (data_sheet->builder, "edit_copy");
+  gtk_action_set_sensitive (action, enable);
+
+  action = get_action_assert (data_sheet->builder, "edit_cut");
+  gtk_action_set_sensitive (action, enable);
+}
+
diff --git a/src/ui/gui/psppire-data-sheet.h b/src/ui/gui/psppire-data-sheet.h
new file mode 100644 (file)
index 0000000..a94bad7
--- /dev/null
@@ -0,0 +1,100 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef PSPPIRE_DATA_SHEET_H
+#define PSPPIRE_DATA_SHEET_H 1
+
+/* PsppireDataSheet is a PsppSheetView that displays the data in a dataset,
+   with one column per variable and one row per case.
+
+   PsppireDataSheet is usually a child of PsppireDataEditor in the widget
+   hierarchy.  Other widgets can also use it. */
+
+#include <gtk/gtk.h>
+#include "ui/gui/pspp-sheet-view.h"
+
+G_BEGIN_DECLS
+
+#define PSPP_TYPE_DATA_SHEET              (psppire_data_sheet_get_type())
+#define PSPPIRE_DATA_SHEET(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPP_TYPE_DATA_SHEET,PsppireDataSheet))
+#define PSPPIRE_DATA_SHEET_CLASS(class)   (G_TYPE_CHECK_CLASS_CAST ((class),PSPP_TYPE_DATA_SHEET,PsppireDataSheetClass))
+#define PSPP_IS_DATA_SHEET(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPP_TYPE_DATA_SHEET))
+#define PSPP_IS_DATA_SHEET_CLASS(class)   (G_TYPE_CHECK_CLASS_TYPE ((class),PSPP_TYPE_DATA_SHEET))
+#define PSPPIRE_DATA_SHEET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),PSPP_TYPE_DATA_SHEET,PsppireDataSheetClass))
+
+typedef struct _PsppireDataSheet      PsppireDataSheet;
+typedef struct _PsppireDataSheetClass PsppireDataSheetClass;
+
+struct _PsppireDataSheet
+{
+  PsppSheetView parent;
+
+  struct _PsppireDataStore *data_store;
+  gboolean show_value_labels;
+  gboolean show_case_numbers;
+  gboolean may_create_vars;
+  gboolean may_delete_vars;
+
+  guint scroll_to_bottom_signal;
+  guint scroll_to_right_signal;
+
+  PsppSheetViewColumn *new_variable_column;
+
+  GtkBuilder *builder;
+
+  GtkWidget *container;
+  GtkUIManager *uim;
+  gboolean dispose_has_run;
+};
+
+struct _PsppireDataSheetClass 
+{
+  PsppSheetViewClass parent_class;
+};
+
+GType psppire_data_sheet_get_type (void) G_GNUC_CONST;
+GtkWidget *psppire_data_sheet_new (void);
+
+struct _PsppireDataStore *psppire_data_sheet_get_data_store (PsppireDataSheet *);
+void psppire_data_sheet_set_data_store (PsppireDataSheet *,
+                                        struct _PsppireDataStore *);
+
+gboolean psppire_data_sheet_get_value_labels (const PsppireDataSheet *);
+void psppire_data_sheet_set_value_labels (PsppireDataSheet *,
+                                          gboolean show_value_labels);
+
+gboolean psppire_data_sheet_get_case_numbers (const PsppireDataSheet *);
+void psppire_data_sheet_set_case_numbers (PsppireDataSheet *,
+                                          gboolean show_case_numbers);
+
+gboolean psppire_data_sheet_get_may_create_vars (PsppireDataSheet *);
+void psppire_data_sheet_set_may_create_vars (PsppireDataSheet *, gboolean);
+
+gboolean psppire_data_sheet_get_may_delete_vars (PsppireDataSheet *);
+void psppire_data_sheet_set_may_delete_vars (PsppireDataSheet *, gboolean);
+
+void psppire_data_sheet_show_variable (PsppireDataSheet *, gint dict_index);
+struct variable *psppire_data_sheet_get_current_variable (const PsppireDataSheet *);
+
+void psppire_data_sheet_goto_case (PsppireDataSheet *, gint case_index);
+gint psppire_data_sheet_get_selected_case (const PsppireDataSheet *);
+gint psppire_data_sheet_get_current_case (const PsppireDataSheet *);
+
+GtkUIManager *psppire_data_sheet_get_ui_manager (PsppireDataSheet *);
+
+G_END_DECLS
+
+#endif /* PSPPIRE_DATA_SHEET_H */
index fb89dfa20e928c68557a82186b63680e5601b84b..047cca78113fddef9a70e1f53becabfc0cacb9fb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006, 2008, 2009, 2010, 2012  Free Software Foundation
+   Copyright (C) 2006, 2008, 2009, 2010, 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -25,7 +25,6 @@
 #include <data/data-out.h>
 #include <data/variable.h>
 
-#include <ui/gui/sheet/psppire-sheetmodel.h>
 #include <ui/gui/psppire-marshal.h>
 
 #include <pango/pango-context.h>
 
 static void psppire_data_store_init            (PsppireDataStore      *data_store);
 static void psppire_data_store_class_init      (PsppireDataStoreClass *class);
-static void psppire_data_store_sheet_model_init (PsppireSheetModelIface *iface);
 
 static void psppire_data_store_finalize        (GObject           *object);
 static void psppire_data_store_dispose        (GObject           *object);
 
-static gboolean psppire_data_store_clear_datum (PsppireSheetModel *model,
-                                         glong row, glong column);
-
-
 static gboolean psppire_data_store_insert_case (PsppireDataStore *ds,
                                                struct ccase *cc,
                                                casenumber posn);
@@ -68,8 +62,6 @@ static gboolean psppire_data_store_data_in (PsppireDataStore *ds,
                                            struct substring input,
                                            const struct fmt_spec *fmt);
 
-
-
 static GObjectClass *parent_class = NULL;
 
 
@@ -105,22 +97,9 @@ psppire_data_store_get_type (void)
         (GInstanceInitFunc) psppire_data_store_init,
       };
 
-      static const GInterfaceInfo sheet_model_info =
-      {
-       (GInterfaceInitFunc) psppire_data_store_sheet_model_init,
-       NULL,
-       NULL
-      };
-
-
       data_store_type = g_type_register_static (G_TYPE_OBJECT,
                                                "PsppireDataStore",
                                                &data_store_info, 0);
-
-      g_type_add_interface_static (data_store_type,
-                                  PSPPIRE_TYPE_SHEET_MODEL,
-                                  &sheet_model_info);
-
     }
 
   return data_store_type;
@@ -190,27 +169,6 @@ static gboolean
 psppire_data_store_insert_value (PsppireDataStore *ds,
                                  gint width, gint where);
 
-static bool
-psppire_data_store_get_value (const PsppireDataStore *ds,
-                             casenumber casenum, size_t idx,
-                             union value *value);
-
-
-static gboolean
-psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
-                             gint idx, union value *v);
-
-
-
-
-static glong
-psppire_data_store_get_var_count (const PsppireSheetModel *model)
-{
-  const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
-
-  return psppire_dict_get_var_cnt (store->dict);
-}
-
 casenumber
 psppire_data_store_get_case_count (const PsppireDataStore *store)
 {
@@ -229,13 +187,6 @@ psppire_data_store_get_proto (const PsppireDataStore *store)
   return psppire_dict_get_proto (store->dict);
 }
 
-static casenumber
-psppire_data_store_get_case_count_wrapper (const PsppireSheetModel *model)
-{
-  const PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
-  return psppire_data_store_get_case_count (store);
-}
-
 static void
 psppire_data_store_init (PsppireDataStore *data_store)
 {
@@ -244,94 +195,24 @@ psppire_data_store_init (PsppireDataStore *data_store)
   data_store->dispose_has_run = FALSE;
 }
 
-static inline gchar *
-psppire_data_store_get_string_wrapper (const PsppireSheetModel *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 (PsppireSheetModel *model,
-                                      const gchar *text,
-                                      glong row, glong column)
-{
-  return psppire_data_store_set_string (PSPPIRE_DATA_STORE (model), text,
-                                       row, column);
-}
-
-
-
-static gchar * get_column_subtitle (const PsppireSheetModel *model, gint col);
-static gchar * get_column_button_label (const PsppireSheetModel *model, gint col);
-static gboolean get_column_sensitivity (const PsppireSheetModel *model, gint col);
-static GtkJustification get_column_justification (const PsppireSheetModel *model, gint col);
-
-static gchar * get_row_button_label (const PsppireSheetModel *model, gint row);
-static gboolean get_row_sensitivity (const PsppireSheetModel *model, gint row);
-static gboolean get_row_overstrike (const PsppireSheetModel *model, gint row);
-
-
-static void
-psppire_data_store_sheet_model_init (PsppireSheetModelIface *iface)
-{
-  iface->free_strings = TRUE;
-  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->get_foreground = NULL;
-  iface->get_background = NULL;
-  iface->get_column_count = psppire_data_store_get_var_count;
-  iface->get_row_count = psppire_data_store_get_case_count_wrapper;
-
-  iface->get_column_subtitle = get_column_subtitle;
-  iface->get_column_title = get_column_button_label;
-  iface->get_column_sensitivity = get_column_sensitivity;
-  iface->get_column_justification = get_column_justification;
-
-  iface->get_row_title = get_row_button_label;
-  iface->get_row_sensitivity = get_row_sensitivity;
-  iface->get_row_overstrike = get_row_overstrike;
-}
-
-
 /*
    A callback which occurs after a variable has been deleted.
  */
 static void
 delete_variable_callback (GObject *obj, const struct variable *var UNUSED,
                           gint dict_index, gint case_index,
-                         gpointer data)
+                          gpointer data)
 {
   PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
 
 
-  psppire_sheet_model_columns_deleted (PSPPIRE_SHEET_MODEL (store), dict_index, 1);
   datasheet_delete_columns (store->datasheet, case_index, 1);
   datasheet_insert_column (store->datasheet, NULL, -1, case_index);
-#if AXIS_TRANSITION
-
-
-  psppire_sheet_column_columns_changed (PSPPIRE_SHEET_COLUMN (store),
-                                  dict_index, -1);
-#endif
 }
 
 static void
 variable_changed_callback (GObject *obj, gint var_num, gpointer data)
 {
-#if AXIS_TRANSITION
-  PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
-
-  psppire_sheet_column_columns_changed (PSPPIRE_SHEET_COLUMN (store),
-                                 var_num, 1);
-
-  psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (store),
-                              -1, var_num,
-                              -1, var_num);
-#endif
 }
 
 static void
@@ -348,14 +229,6 @@ insert_variable_callback (GObject *obj, gint var_num, gpointer data)
   variable = psppire_dict_get_variable (store->dict, var_num);
   posn = var_get_case_index (variable);
   psppire_data_store_insert_value (store, var_get_width (variable), posn);
-
-#if AXIS_TRANSITION
-
-  psppire_sheet_column_columns_changed (PSPPIRE_SHEET_COLUMN (store),
-                                 var_num, 1);
-#endif
-
-  psppire_sheet_model_columns_inserted (PSPPIRE_SHEET_MODEL (store), var_num, 1);
 }
 
 struct resize_datum_aux
@@ -437,9 +310,6 @@ psppire_data_store_set_reader (PsppireDataStore *ds,
 
   ds->datasheet = datasheet_create (reader);
 
-  psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (ds),
-                              -1, -1, -1, -1);
-
   if ( ds->dict )
     for (i = 0 ; i < n_dict_signals; ++i )
       {
@@ -504,11 +374,6 @@ psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *di
 
 
   /* The entire model has changed */
-  psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (data_store), -1, -1, -1, -1);
-
-#if AXIS_TRANSITION
-  psppire_sheet_column_columns_changed (PSPPIRE_SHEET_COLUMN (data_store), 0, -1);
-#endif
 
   if ( data_store->dict )
     for (i = 0 ; i < n_dict_signals; ++i )
@@ -524,6 +389,13 @@ psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *di
 static void
 psppire_data_store_finalize (GObject *object)
 {
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (object);
+
+  if (ds->datasheet)
+    {
+      datasheet_destroy (ds->datasheet);
+      ds->datasheet = NULL;
+    }
 
   /* must chain up */
   (* parent_class->finalize) (object);
@@ -538,11 +410,6 @@ psppire_data_store_dispose (GObject *object)
   if (ds->dispose_has_run)
     return;
 
-  if (ds->datasheet)
-    {
-      datasheet_destroy (ds->datasheet);
-      ds->datasheet = NULL;
-    }
 
   /* must chain up */
   (* parent_class->dispose) (object);
@@ -575,132 +442,86 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
   return result;
 }
 
-
 gchar *
-psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
+psppire_data_store_get_string (PsppireDataStore *store,
+                               glong row, const struct variable *var,
+                               bool use_value_label)
 {
-  gint idx;
-  char *text;
-  const struct fmt_spec *fp ;
-  const struct variable *pv ;
-  const struct dictionary *dict;
+  gchar *string;
   union value v;
   int width;
 
-  g_return_val_if_fail (store->dict, NULL);
-  g_return_val_if_fail (store->datasheet, NULL);
-
-  dict = store->dict->dict;
-
-  if (column >= psppire_dict_get_var_cnt (store->dict))
-    return NULL;
+  g_return_val_if_fail (store != NULL, NULL);
+  g_return_val_if_fail (var != NULL, NULL);
 
-  if ( row >= psppire_data_store_get_case_count (store))
+  if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
     return NULL;
 
-  pv = psppire_dict_get_variable (store->dict, column);
-
-  g_assert (pv);
-
-  idx = var_get_case_index (pv);
-  width = var_get_width (pv);
-
-  g_assert (idx >= 0);
-
+  width = var_get_width (var);
   value_init (&v, width);
-  if (!psppire_data_store_get_value (store, row, idx, &v))
-    return NULL;
+  datasheet_get_value (store->datasheet, row, var_get_case_index (var), &v);
 
-  if ( store->show_labels)
+  string = NULL;
+  if (use_value_label)
     {
-      const gchar *label = var_lookup_value_label (pv, &v);
-      if (label)
-        {
-          value_destroy (&v, width);
-         return g_strdup (label);
-        }
+      const char *label = var_lookup_value_label (var, &v);
+      if (label != NULL)
+        string = g_strdup (label);
     }
+  if (string == NULL)
+    string = value_to_text (v, var);
 
-  fp = var_get_print_format (pv);
-
-  text = data_out (&v, dict_get_encoding (dict), fp);
-
-  g_strchomp (text);
-
-  value_destroy (&v, width);
-  return text;
-}
-
-
-static gboolean
-psppire_data_store_clear_datum (PsppireSheetModel *model,
-                                         glong row, glong col)
-{
-  PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
-
-  union value v;
-  const struct variable *pv = psppire_dict_get_variable (store->dict, col);
-  int width = var_get_width (pv);
-
-  const gint index = var_get_case_index (pv) ;
-
-  value_init (&v, width);
-  value_set_missing (&v, width);
-  psppire_data_store_set_value (store, row, index, &v);
   value_destroy (&v, width);
 
-  psppire_sheet_model_range_changed (model, row, col, row, col);
+  return string;
+}
 
 
-  return TRUE;
-}
+/* Attempts to update that part of the variable store which corresponds to VAR
+   within ROW with the value TEXT.
 
+   If USE_VALUE_LABEL is true, and TEXT is a value label for the column's
+   variable, then stores the value from that value label instead of the literal
+   TEXT.
 
-/* 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.
-*/
+   Returns true if anything was updated, false otherwise.  */
 gboolean
 psppire_data_store_set_string (PsppireDataStore *store,
-                              const gchar *text, glong row, glong col)
+                              const gchar *text,
+                               glong row, const struct variable *var,
+                               gboolean use_value_label)
 {
+  gint case_index;
   glong n_cases;
-  const struct variable *pv = psppire_dict_get_variable (store->dict, col);
-  if ( NULL == pv)
-    return FALSE;
+  gboolean ok;
 
   n_cases = psppire_data_store_get_case_count (store);
-
-  if ( row > n_cases)
+  if (row > n_cases)
     return FALSE;
-
   if (row == n_cases)
     psppire_data_store_insert_new_case (store, row);
 
-  psppire_data_store_data_in (store, row,
-                             var_get_case_index (pv), ss_cstr (text),
-                             var_get_print_format (pv));
-
-  psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (store), row, col, row, col);
+  case_index = var_get_case_index (var);
+  if (use_value_label)
+    {
+      const struct val_labs *vls = var_get_value_labels (var);
+      const union value *value = vls ? val_labs_find_value (vls, text) : NULL;
+      if (value)
+        ok = datasheet_put_value (store->datasheet, row, case_index, value);
+      else
+        ok = FALSE;
+    }
+  else
+    ok = psppire_data_store_data_in (store, row, case_index, ss_cstr (text),
+                                     var_get_print_format (var));
 
-  return TRUE;
+  if (ok)
+    g_signal_emit (store, signals [CASE_CHANGED], 0, row);
+  return ok;
 }
 
 
 
-void
-psppire_data_store_show_labels (PsppireDataStore *store, gboolean show_labels)
-{
-  g_return_if_fail (store);
-  g_return_if_fail (PSPPIRE_IS_DATA_STORE (store));
-
-  store->show_labels = show_labels;
-
-  psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (store),
-                                -1, -1, -1, -1);
-}
-
-
 void
 psppire_data_store_clear (PsppireDataStore *ds)
 {
@@ -743,93 +564,6 @@ psppire_data_store_get_reader (PsppireDataStore *ds)
 
 static const gchar null_var_name[]=N_("var");
 
-\f
-
-/* Row related funcs */
-
-static gchar *
-get_row_button_label (const PsppireSheetModel *model, gint unit)
-{
-  // PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
-
-  return g_strdup_printf (_("%d"), unit + FIRST_CASE_NUMBER);
-}
-
-
-static gboolean
-get_row_sensitivity (const PsppireSheetModel *model, gint unit)
-{
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
-
-  return (unit < psppire_data_store_get_case_count (ds));
-}
-
-
-\f
-
-/* Column related stuff */
-
-static gchar *
-get_column_subtitle (const PsppireSheetModel *model, gint col)
-{
-  const struct variable *v ;
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
-
-  if ( col >= psppire_dict_get_var_cnt (ds->dict) )
-    return NULL;
-
-  v = psppire_dict_get_variable (ds->dict, col);
-
-  if ( ! var_has_label (v))
-    return NULL;
-
-  return xstrdup (var_get_label (v));
-}
-
-static gchar *
-get_column_button_label (const PsppireSheetModel *model, gint col)
-{
-  struct variable *pv ;
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
-
-  if ( col >= psppire_dict_get_var_cnt (ds->dict) )
-    return xstrdup (gettext (null_var_name));
-
-  pv = psppire_dict_get_variable (ds->dict, col);
-
-  if (NULL == pv)
-    return NULL;
-
-  return xstrdup (var_get_name (pv));
-}
-
-static gboolean
-get_column_sensitivity (const PsppireSheetModel *model, gint col)
-{
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
-
-  return (col < psppire_dict_get_var_cnt (ds->dict));
-}
-
-
-
-static GtkJustification
-get_column_justification (const PsppireSheetModel *model, gint col)
-{
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
-  const struct variable *pv ;
-
-  if ( col >= psppire_dict_get_var_cnt (ds->dict) )
-    return GTK_JUSTIFY_LEFT;
-
-  pv = psppire_dict_get_variable (ds->dict, col);
-
-  return (var_get_alignment (pv) == ALIGN_LEFT ? GTK_JUSTIFY_LEFT
-          : var_get_alignment (pv) == ALIGN_RIGHT ? GTK_JUSTIFY_RIGHT
-          : GTK_JUSTIFY_CENTER);
-}
-
-
 
 \f
 
@@ -861,7 +595,6 @@ psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first,
   datasheet_delete_rows (ds->datasheet, first, n_cases);
 
   g_signal_emit (ds, signals [CASES_DELETED], 0, first, n_cases);
-  psppire_sheet_model_rows_deleted (PSPPIRE_SHEET_MODEL (ds), first, n_cases);
 
   return TRUE;
 }
@@ -883,10 +616,7 @@ psppire_data_store_insert_case (PsppireDataStore *ds,
   result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
 
   if ( result )
-    {
-      g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
-      psppire_sheet_model_rows_inserted (PSPPIRE_SHEET_MODEL (ds), posn, 1);
-    }
+    g_signal_emit (ds, signals [CASE_INSERTED], 0, posn);
   else
     g_warning ("Cannot insert case at position %ld\n", posn);
 
@@ -894,38 +624,28 @@ psppire_data_store_insert_case (PsppireDataStore *ds,
 }
 
 
-/* Copies the IDXth value from case CASENUM into VALUE, which
-   must be of the correct width for IDX.
-   Returns true if successful, false on failure. */
-static bool
-psppire_data_store_get_value (const PsppireDataStore *ds,
-                             casenumber casenum, size_t idx,
-                             union value *value)
-{
-  g_return_val_if_fail (ds, false);
-  g_return_val_if_fail (ds->datasheet, false);
-  g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), false);
-
-  return datasheet_get_value (ds->datasheet, casenum, idx, value);
-}
-
-
-
-/* Set the IDXth value of case C to V.
+/* Set the value of VAR in case CASENUM to V.
    V must be the correct width for IDX.
    Returns true if successful, false on I/O error. */
-static gboolean
+gboolean
 psppire_data_store_set_value (PsppireDataStore *ds, casenumber casenum,
-                             gint idx, union value *v)
+                             const struct variable *var, const union value *v)
 {
+  glong n_cases;
   bool ok;
 
   g_return_val_if_fail (ds, FALSE);
   g_return_val_if_fail (ds->datasheet, FALSE);
 
-  g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
+  n_cases = psppire_data_store_get_case_count (ds);
+  if ( casenum > n_cases)
+    return FALSE;
+
+  if (casenum == n_cases)
+    psppire_data_store_insert_new_case (ds, casenum);
 
-  ok = datasheet_put_value (ds->datasheet, casenum, idx, v);
+  ok = datasheet_put_value (ds->datasheet, casenum, var_get_case_index (var),
+                            v);
   if (ok)
     g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
 
@@ -964,9 +684,6 @@ psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
   value_destroy (&value, width);
 
-  if (ok)
-    g_signal_emit (ds, signals [CASE_CHANGED], 0, casenum);
-
   return ok;
 }
 
@@ -988,40 +705,38 @@ psppire_data_store_insert_value (PsppireDataStore *ds,
     ds->datasheet = datasheet_create (NULL);
 
   value_init (&value, width);
-  if (width == 0)
-    value.f = 0;
-  else
-    value_set_missing (&value, width);
+  value_set_missing (&value, width);
 
   datasheet_insert_column (ds->datasheet, &value, width, where);
+  value_destroy (&value, width);
 
   return TRUE;
 }
 
-static gboolean
-get_row_overstrike (const PsppireSheetModel *model, gint row)
+gboolean
+psppire_data_store_filtered (PsppireDataStore *ds,
+                             glong row)
 {
   union value val;
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
-
-  const struct dictionary *dict = ds->dict->dict;
 
-  const struct variable *filter = dict_get_filter (dict);
+  const struct dictionary *dict;
+  const struct variable *filter;
 
   if ( row < 0 || row >= datasheet_get_n_rows (ds->datasheet))
     return FALSE;
 
+  dict = ds->dict->dict;
+  g_return_val_if_fail (dict, FALSE);
+  filter = dict_get_filter (dict);
   if ( ! filter)
     return FALSE;
 
-  g_assert (var_is_numeric (filter));
-
+  g_return_val_if_fail (var_is_numeric (filter), FALSE);
   value_init (&val, 0);
   if ( ! datasheet_get_value (ds->datasheet, row,
-                             var_get_case_index (filter),
-                             &val) )
+                              var_get_case_index (filter),
+                              &val) )
     return FALSE;
 
-
   return (val.f == 0.0);
 }
index 6e2ec906fc49289eb0dd8865af87b7f00826d59a..8096962ad740e1266b70a4c72ef33fe53c7a5ec1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006, 2009  Free Software Foundation
+   Copyright (C) 2006, 2009, 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -74,9 +74,6 @@ struct _PsppireDataStore
   PsppireDict *dict;
   struct datasheet *datasheet;
 
-  gboolean show_labels;
-
-  //  gint cf_handler_id [n_cf_signals];
   gint dict_handler_id [n_dict_signals];
 };
 
@@ -96,9 +93,6 @@ void psppire_data_store_set_reader (PsppireDataStore *ds,
 void psppire_data_store_set_dictionary (PsppireDataStore *data_store,
                                        PsppireDict *dict);
 
-void psppire_data_store_show_labels (PsppireDataStore *store,
-                                    gboolean show_labels);
-
 void psppire_data_store_clear (PsppireDataStore *data_store);
 
 gboolean psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn);
@@ -109,12 +103,17 @@ gboolean psppire_data_store_delete_cases (PsppireDataStore *ds, casenumber first
 
 struct casereader * psppire_data_store_get_reader (PsppireDataStore *ds);
 
-gchar * psppire_data_store_get_string (PsppireDataStore *ds,
-                                      casenumber row, glong column);
-
+gchar *psppire_data_store_get_string (PsppireDataStore *,
+                                      glong row, const struct variable *,
+                                      bool use_value_label);
+gboolean psppire_data_store_set_value (PsppireDataStore *,
+                                       casenumber casenum,
+                                       const struct variable *,
+                                       const union value *);
 gboolean psppire_data_store_set_string (PsppireDataStore *ds,
                                        const gchar *text,
-                                       glong row, glong column);
+                                       glong row, const struct variable *,
+                                        gboolean use_value_label);
 
 
 gboolean psppire_data_store_filtered (PsppireDataStore *ds,
index c22f7bb293acb05ec957931a8f2a693db728b86e..204c8f1c849d68abed8cd4e6dee7d0c89fd4d278 100644 (file)
@@ -35,9 +35,7 @@
 #include "ui/gui/crosstabs-dialog.h"
 #include "ui/gui/entry-dialog.h"
 #include "ui/gui/executor.h"
-#include "ui/gui/find-dialog.h"
 #include "ui/gui/frequencies-dialog.h"
-#include "ui/gui/goto-case-dialog.h"
 #include "ui/gui/help-menu.h"
 #include "ui/gui/helper.h"
 #include "ui/gui/helper.h"
@@ -45,6 +43,7 @@
 #include "ui/gui/npar-two-sample-related.h"
 #include "ui/gui/oneway-anova-dialog.h"
 #include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dialog-action.h"
 #include "ui/gui/psppire-syntax-window.h"
 #include "ui/gui/psppire-window.h"
 #include "ui/gui/psppire.h"
@@ -88,6 +87,10 @@ static void psppire_data_window_get_property (GObject         *object,
                                               GValue          *value,
                                               GParamSpec      *pspec);
 
+static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
+static void psppire_data_window_remove_ui (PsppireDataWindow *,
+                                           GtkUIManager *, guint);
+
 GType
 psppire_data_window_get_type (void)
 {
@@ -152,24 +155,6 @@ psppire_data_window_class_init (PsppireDataWindowClass *class)
                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
 }
 \f
-static void
-set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
-{
-  GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
-
-  gtk_action_set_sensitive (edit_paste, x);
-}
-
-static void
-set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
-{
-  GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
-  GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
-
-  gtk_action_set_sensitive (edit_copy, x);
-  gtk_action_set_sensitive (edit_cut, x);
-}
-
 /* Run the EXECUTE command. */
 static void
 execute (PsppireDataWindow *dw)
@@ -216,13 +201,11 @@ on_filter_change (GObject *o, gint filter_index, gpointer data)
     }
   else
     {
-      PsppireVarStore *vs = NULL;
       PsppireDict *dict = NULL;
       struct variable *var ;
       gchar *text ;
 
-      g_object_get (de->data_editor, "var-store", &vs, NULL);
-      g_object_get (vs, "dictionary", &dict, NULL);
+      g_object_get (de->data_editor, "dictionary", &dict, NULL);
 
       var = psppire_dict_get_variable (dict, filter_index);
 
@@ -289,12 +272,10 @@ on_weight_change (GObject *o, gint weight_index, gpointer data)
   else
     {
       struct variable *var ;
-      PsppireVarStore *vs = NULL;
       PsppireDict *dict = NULL;
       gchar *text;
 
-      g_object_get (de->data_editor, "var-store", &vs, NULL);
-      g_object_get (vs, "dictionary", &dict, NULL);
+      g_object_get (de->data_editor, "dictionary", &dict, NULL);
 
       var = psppire_dict_get_variable (dict, weight_index);
 
@@ -430,19 +411,6 @@ save_file (PsppireWindow *w)
 }
 
 
-static void
-insert_case (PsppireDataWindow *dw)
-{
-  psppire_data_editor_insert_case (dw->data_editor);
-}
-
-static void
-on_insert_variable (PsppireDataWindow *dw)
-{
-  psppire_data_editor_insert_variable (dw->data_editor);
-}
-
-
 static void
 display_dict (PsppireDataWindow *de)
 {
@@ -627,27 +595,6 @@ on_rename_dataset (PsppireDataWindow *de)
   free (new_name);
 }
 
-static void
-on_edit_paste (PsppireDataWindow  *de)
-{
-  psppire_data_editor_clip_paste (de->data_editor);
-}
-
-static void
-on_edit_copy (PsppireDataWindow  *de)
-{
-  psppire_data_editor_clip_copy (de->data_editor);
-}
-
-
-
-static void
-on_edit_cut (PsppireDataWindow  *de)
-{
-  psppire_data_editor_clip_cut (de->data_editor);
-}
-
-
 static void
 status_bar_activate (PsppireDataWindow  *de, GtkToggleAction *action)
 {
@@ -742,7 +689,6 @@ file_quit (PsppireDataWindow *de)
   psppire_quit ();
 }
 
-
 static void
 on_recent_data_select (GtkMenuShell *menushell,
                       PsppireWindow *window)
@@ -827,75 +773,52 @@ on_recent_files_select (GtkMenuShell *menushell,   gpointer user_data)
   g_free (file);
 }
 
-
-
 static void
-enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
+set_unsaved (gpointer w)
 {
-  PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
-
-  gtk_action_set_visible (de->delete_cases, case_num != -1);
+  psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
 }
 
-
 static void
-enable_delete_variables (GtkWidget *w, gint var, gpointer data)
+on_switch_page (PsppireDataEditor *de, GtkNotebookPage *p,
+               gint pagenum, PsppireDataWindow *dw)
 {
-  PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
-
-  gtk_action_set_visible (de->delete_variables, var != -1);
+  GtkWidget *page_menu_item;
+  gboolean is_ds;
+  const char *path;
+
+  is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
+  path = (is_ds
+          ? "/ui/menubar/view/view_data"
+          : "/ui/menubar/view/view_variables");
+  page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
+  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
 }
 
-/* Callback for when the datasheet/varsheet is selected */
 static void
-on_switch_sheet (GtkNotebook *notebook,
-                GtkNotebookPage *page,
-                guint page_num,
-                gpointer user_data)
+on_ui_manager_changed (PsppireDataEditor *de,
+                       GParamSpec *pspec UNUSED,
+                       PsppireDataWindow *dw)
 {
-  PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
-
-  GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
-
-  GtkWidget *view_data =
-    gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
-
-  GtkWidget *view_variables =
-    gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
+  GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
+  if (uim == dw->uim)
+    return;
 
-  switch (page_num)
+  if (dw->uim)
     {
-    case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
-      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
-                                      TRUE);
-      gtk_action_set_sensitive (de->insert_variable, TRUE);
-      gtk_action_set_sensitive (de->insert_case, FALSE);
-      gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
-      break;
-    case PSPPIRE_DATA_EDITOR_DATA_VIEW:
-      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
-      gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
-      gtk_action_set_sensitive (de->insert_case, TRUE);
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
+      psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
+      g_object_unref (dw->uim);
+      dw->uim = NULL;
     }
 
-#if 0
-  update_paste_menuitem (de, page_num);
-#endif
-}
-
-
-
-static void
-set_unsaved (gpointer w)
-{
-  psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
+  dw->uim = uim;
+  if (dw->uim)
+    {
+      g_object_ref (dw->uim);
+      dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
+    }
 }
 
-
 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
    Returns a pointer to the action
 */
@@ -920,14 +843,15 @@ connect_action (PsppireDataWindow *dw, const char *action_name,
 static void
 psppire_data_window_init (PsppireDataWindow *de)
 {
-  GtkUIManager *uim;
-
   de->builder = builder_new ("data-editor.ui");
 
-  uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
+  de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
 
   PSPPIRE_WINDOW (de)->menu =
-    GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
+    GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
+
+  de->uim = NULL;
+  de->merge_id = 0;
 }
 
 static void
@@ -940,8 +864,6 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
       transformation_change_callback, /* transformations_changed */
     };
 
-  PsppireDict *dict;
-
   GtkWidget *menubar;
   GtkWidget *hb ;
   GtkWidget *sb ;
@@ -949,18 +871,21 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
   GtkWidget *box = gtk_vbox_new (FALSE, 0);
 
   de->dataset = ds;
-  dict = psppire_dict_new_from_dict (dataset_dict (ds));
-  de->var_store = psppire_var_store_new (dict);
-  de->data_store = psppire_data_store_new (dict);
+  de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
+  de->data_store = psppire_data_store_new (de->dict);
   psppire_data_store_set_reader (de->data_store, NULL);
 
   menubar = get_widget_assert (de->builder, "menubar");
   hb = get_widget_assert (de->builder, "handlebox1");
   sb = get_widget_assert (de->builder, "status-bar");
 
+  de->uim = NULL;
+  de->merge_id = 0;
+
   de->data_editor =
-    PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
-                                                  de->data_store));
+    PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
+  g_signal_connect (de->data_editor, "switch-page",
+                    G_CALLBACK (on_switch_page), de);
 
   g_signal_connect_swapped (de->data_store, "case-changed",
                            G_CALLBACK (set_unsaved), de);
@@ -982,34 +907,19 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
 
   gtk_container_add (GTK_CONTAINER (de), box);
 
-  set_cut_copy_menuitem_sensitivity (de, FALSE);
-
-  g_signal_connect_swapped (de->data_editor, "data-selection-changed",
-                           G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
-
-
-  set_paste_menuitem_sensitivity (de, FALSE);
-
-  g_signal_connect_swapped (de->data_editor, "data-available-changed",
-                           G_CALLBACK (set_paste_menuitem_sensitivity), de);
-
-  g_signal_connect (dict, "weight-changed",
+  g_signal_connect (de->dict, "weight-changed",
                    G_CALLBACK (on_weight_change),
                    de);
 
-  g_signal_connect (dict, "filter-changed",
+  g_signal_connect (de->dict, "filter-changed",
                    G_CALLBACK (on_filter_change),
                    de);
 
-  g_signal_connect (dict, "split-changed",
+  g_signal_connect (de->dict, "split-changed",
                    G_CALLBACK (on_split_change),
                    de);
 
 
-  connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
-
-  connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
-
   connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
 
   connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
@@ -1026,40 +936,13 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
 
   connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
 
-  connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
-
-  de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
-
-  de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
-
-  de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
-
   g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
 
-  {
-    de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
-
-    g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
-
-    gtk_action_set_visible (de->delete_cases, FALSE);
-  }
-
-
-  {
-    de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
-
-    g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
-
-    gtk_action_set_visible (de->delete_variables, FALSE);
-  }
-
-
   connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
   connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
   connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
   connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
   connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
-  connect_action (de, "edit_find", G_CALLBACK (find_dialog));
   connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
   connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
   connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
@@ -1080,13 +963,11 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
   connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
 
   {
-    GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
-
     GtkWidget *recent_data =
-      gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
+      gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
 
     GtkWidget *recent_files =
-      gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
+      gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
 
 
     GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
@@ -1134,21 +1015,6 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
   connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
 
 
-  g_signal_connect (de->data_editor,
-                   "cases-selected",
-                   G_CALLBACK (enable_delete_cases),
-                   de);
-
-  g_signal_connect (de->data_editor,
-                   "variables-selected",
-                   G_CALLBACK (enable_delete_variables),
-                   de);
-
-
-  g_signal_connect (de->data_editor,
-                   "switch-page",
-                   G_CALLBACK (on_switch_sheet), de);
-
   gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
   gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
 
@@ -1170,36 +1036,11 @@ psppire_data_window_finish_init (PsppireDataWindow *de,
 
   g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
 
-  {
-    GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
-
-    merge_help_menu (uim);
-  }
-
-  {
-    GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
-                                                               "datasheet-cases-popup");
+  merge_help_menu (de->ui_manager);
 
-    GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
-                                                                 "varsheet-variable-popup");
-
-    GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
-                                                                  "datasheet-variable-popup");
-
-    g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
-                             G_CALLBACK (psppire_data_editor_sort_ascending),
-                             de->data_editor);
-
-    g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
-                             G_CALLBACK (psppire_data_editor_sort_descending),
-                             de->data_editor);
-
-    g_object_set (de->data_editor,
-                 "datasheet-column-menu", data_sheet_variable_popup_menu,
-                 "datasheet-row-menu", data_sheet_cases_popup_menu,
-                 "varsheet-row-menu", var_sheet_variable_popup_menu,
-                 NULL);
-  }
+  g_signal_connect (de->data_editor, "notify::ui-manager",
+                    G_CALLBACK (on_ui_manager_changed), de);
+  on_ui_manager_changed (de->data_editor, NULL, de);
 
   gtk_widget_show (GTK_WIDGET (de->data_editor));
   gtk_widget_show (box);
@@ -1212,16 +1053,23 @@ psppire_data_window_dispose (GObject *object)
 {
   PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
 
+  if (dw->uim)
+    {
+      psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
+      g_object_unref (dw->uim);
+      dw->uim = NULL;
+    }
+
   if (dw->builder != NULL)
     {
       g_object_unref (dw->builder);
       dw->builder = NULL;
     }
 
-  if (dw->var_store)
+  if (dw->dict)
     {
-      g_object_unref (dw->var_store);
-      dw->var_store = NULL;
+      g_object_unref (dw->dict);
+      dw->dict = NULL;
     }
 
   if (dw->data_store)
@@ -1278,6 +1126,65 @@ psppire_data_window_get_property (GObject         *object,
     };
 }
 
+static guint
+psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
+{
+  gchar *ui_string;
+  guint merge_id;
+  GList *list;
+
+  ui_string = gtk_ui_manager_get_ui (uim);
+  merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
+                                                -1, NULL);
+  g_free (ui_string);
+
+  g_return_val_if_fail (merge_id != 0, 0);
+
+  list = gtk_ui_manager_get_action_groups (uim);
+  for (; list != NULL; list = list->next)
+    {
+      GtkActionGroup *action_group = list->data;
+      GList *actions = gtk_action_group_list_actions (action_group);
+      GList *action;
+
+      for (action = actions; action != NULL; action = action->next)
+        {
+          GtkAction *a = action->data;
+
+          if (PSPPIRE_IS_DIALOG_ACTION (a))
+            g_object_set (a, "manager", pdw->ui_manager, NULL);
+        }
+
+      gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
+    }
+
+  gtk_window_add_accel_group (GTK_WINDOW (pdw),
+                              gtk_ui_manager_get_accel_group (uim));
+
+  return merge_id;
+}
+
+static void
+psppire_data_window_remove_ui (PsppireDataWindow *pdw,
+                               GtkUIManager *uim, guint merge_id)
+{
+  GList *list;
+
+  g_return_if_fail (merge_id != 0);
+
+  gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
+
+  list = gtk_ui_manager_get_action_groups (uim);
+  for (; list != NULL; list = list->next)
+    {
+      GtkActionGroup *action_group = list->data;
+      gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
+    }
+
+  gtk_window_remove_accel_group (GTK_WINDOW (pdw),
+                                 gtk_ui_manager_get_accel_group (uim));
+}
+
 GtkWidget*
 psppire_data_window_new (struct dataset *ds)
 {
@@ -1310,7 +1217,7 @@ psppire_data_window_new (struct dataset *ds)
 bool
 psppire_data_window_is_empty (PsppireDataWindow *dw)
 {
-  return psppire_var_store_get_var_cnt (dw->var_store) == 0;
+  return psppire_dict_get_var_cnt (dw->dict) == 0;
 }
 
 static void
@@ -1355,6 +1262,18 @@ psppire_data_window_for_dataset (struct dataset *ds)
   return NULL;
 }
 
+PsppireDataWindow *
+psppire_data_window_for_data_store (PsppireDataStore *data_store)
+{
+  PsppireDataWindow *pdw;
+
+  ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
+    if (pdw->data_store == data_store)
+      return pdw;
+
+  return NULL;
+}
+
 void
 create_data_window (void)
 {
@@ -1368,10 +1287,14 @@ open_data_window (PsppireWindow *victim, const char *file_name)
 
   if (PSPPIRE_IS_DATA_WINDOW (victim)
       && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
-    window = GTK_WIDGET (victim);
+    {
+      window = GTK_WIDGET (victim);
+      gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
+    }
   else
     window = psppire_data_window_new (NULL);
 
   psppire_window_load (PSPPIRE_WINDOW (window), file_name);
-  gtk_widget_show (window);
+  gtk_widget_show_all (window);
 }
+
index 93b51b0cee9aa7e5f7e973672869de8dd923e620..d63f49aed751a70c4ae40da32109d01d28b1207a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2010, 2011  Free Software Foundation
+   Copyright (C) 2008, 2010, 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #ifndef __PSPPIRE_DATA_WINDOW_H__
 #define __PSPPIRE_DATA_WINDOW_H__
 
+/* PsppireDataWindow is a top-level window for editing a PSPP dataset.
+
+   PsppireDataWindow contains a PsppireDataEditor.
+
+   PsppireDataWindow's own functionality basically amounts to managing menus
+   and toolbars.  In addition to maintaining some menu itema and toolbar items
+   of its own, it merges in menu and toolbar items provided by its child
+   PsppireDataEditor (based on the "ui-manager" property of PsppireDataEditor).
+ */
 
 #include <glib.h>
 #include <glib-object.h>
@@ -50,24 +59,20 @@ struct _PsppireDataWindow
   /* <private> */
   PsppireDataEditor *data_editor;
   GtkBuilder *builder;
+  GtkUIManager *ui_manager;
 
-  PsppireVarStore *var_store;
+  PsppireDict *dict;
   struct dataset *dataset;
   PsppireDataStore *data_store;
 
-  GtkAction *invoke_goto_dialog;
-
-  GtkAction *insert_variable;
-  GtkAction *insert_case;
-  GtkAction *delete_variables;
-  GtkAction *delete_cases;
-
-
   gboolean save_as_portable;
 
   struct ll ll;                 /* In global 'all_data_windows' list. */
   unsigned long int lazy_serial;
   unsigned int dataset_seqno;
+
+  GtkUIManager *uim;
+  guint merge_id;
 };
 
 struct _PsppireDataWindowClass
@@ -86,6 +91,7 @@ void psppire_data_window_set_default (PsppireDataWindow *);
 void psppire_data_window_undefault (PsppireDataWindow *);
 
 PsppireDataWindow *psppire_data_window_for_dataset (struct dataset *);
+PsppireDataWindow *psppire_data_window_for_data_store (PsppireDataStore *);
 
 bool psppire_data_window_is_empty (PsppireDataWindow *);
 void create_data_window (void);
index 226fc58a9677df63c1a2fb1cfea13449de91ba5c..0c17222fa378b75f58a41512efa0792f23550a1d 100644 (file)
 
 #include <config.h>
 
-#include "psppire-dialog-action-var-info.h"
+#include "ui/gui/psppire-dialog-action-var-info.h"
 
-#include <data/variable.h>
-#include <data/format.h>
-#include <data/value-labels.h>
-#include <libpspp/i18n.h>
+#include <gtk/gtk.h>
 
-#include "var-display.h"
-#include "helper.h"
-#include "psppire-var-view.h"
-#include "psppire-dictview.h"
-
-#include "psppire-dialog.h"
-#include "builder-wrapper.h"
-#include "psppire-data-window.h"
+#include "data/format.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "libpspp/i18n.h"
+#include "ui/gui/builder-wrapper.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dialog.h"
+#include "ui/gui/psppire-dictview.h"
+#include "ui/gui/var-display.h"
 
 static void psppire_dialog_action_var_info_init            (PsppireDialogActionVarInfo      *act);
 static void psppire_dialog_action_var_info_class_init      (PsppireDialogActionVarInfoClass *class);
@@ -178,9 +177,8 @@ jump_to (PsppireDialog *d, gint response, gpointer data)
 
   g_object_get (pda, "top-level", &dw, NULL);
 
-  g_object_set (dw->data_editor,
-               "current-variable", var_get_dict_index (var),
-               NULL);
+  psppire_data_editor_goto_variable (dw->data_editor,
+                                     var_get_dict_index (var));
 }
 
 static void
@@ -228,4 +226,3 @@ static void
 psppire_dialog_action_var_info_init (PsppireDialogActionVarInfo *act)
 {
 }
-
index 8bf5a8d5450ac2106e1f435bc7d07bdfc7699c80..1a19ebb9a57ad3fce50e073b3a56d57f5618afa5 100644 (file)
@@ -88,7 +88,6 @@ psppire_dialog_action_activate (PsppireDialogAction *act)
 {
   gint response;
 
-  PsppireVarStore *vs;
   PsppireDialogActionClass *class = PSPPIRE_DIALOG_ACTION_GET_CLASS (act);
 
   GSList *sl = gtk_ui_manager_get_toplevels (act->uim, GTK_UI_MANAGER_MENUBAR | GTK_UI_MANAGER_TOOLBAR);
@@ -97,9 +96,7 @@ psppire_dialog_action_activate (PsppireDialogAction *act)
   act->toplevel = gtk_widget_get_toplevel (GTK_WIDGET (sl->data));
   g_slist_free (sl);
 
-  vs = PSPPIRE_DATA_WINDOW(act->toplevel)->var_store;
-  
-  g_object_get (vs, "dictionary", &act->dict, NULL);
+  act->dict = PSPPIRE_DATA_WINDOW(act->toplevel)->dict;
   
   g_object_set (act->source, "model", act->dict, NULL);
   
@@ -140,7 +137,7 @@ psppire_dialog_action_class_init (PsppireDialogActionClass *class)
                         "Manager",
                         "The GtkUIManager which created this object",
                         GTK_TYPE_UI_MANAGER,
-                        G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
+                        G_PARAM_READWRITE);
 
   GParamSpec *toplevel_spec =
     g_param_spec_object ("top-level",
index 648d9fd786ee149bdeafd7e972c382d4893dc66a..930c27797ff8c0b2d5ec0da37567d7e5e1bc0c38 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
+   Copyright (C) 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 "psppire-var-sheet.h"
-#include <ui/gui/sheet/psppire-axis.h>
 
-#include "builder-wrapper.h"
-#include "helper.h"
-
-#include "customentry.h"
-#include <data/variable.h>
-#include "psppire-var-store.h"
+#include "ui/gui/psppire-var-sheet.h"
+
+#include "data/format.h"
+#include "data/value-labels.h"
+#include "libpspp/range-set.h"
+#include "ui/gui/builder-wrapper.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/missing-val-dialog.h"
+#include "ui/gui/pspp-sheet-selection.h"
+#include "ui/gui/psppire-cell-renderer-button.h"
+#include "ui/gui/psppire-data-editor.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dialog-action-var-info.h"
+#include "ui/gui/psppire-empty-list-store.h"
+#include "ui/gui/psppire-marshal.h"
+#include "ui/gui/val-labs-dialog.h"
+#include "ui/gui/var-display.h"
+#include "ui/gui/var-type-dialog.h"
+
+#include "gl/intprops.h"
 
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
+enum vs_column
+  {
+    VS_NAME,
+    VS_TYPE,
+    VS_WIDTH,
+    VS_DECIMALS,
+    VS_LABEL,
+    VS_VALUES,
+    VS_MISSING,
+    VS_COLUMNS,
+    VS_ALIGN,
+    VS_MEASURE
+  };
 
-static void psppire_var_sheet_class_init  (PsppireVarSheetClass *klass);
-static void psppire_var_sheet_init        (PsppireVarSheet      *vs);
-static void psppire_var_sheet_realize     (GtkWidget *w);
-static void psppire_var_sheet_unrealize   (GtkWidget *w);
+G_DEFINE_TYPE (PsppireVarSheet, psppire_var_sheet, PSPP_TYPE_SHEET_VIEW);
 
+static void
+set_spin_cell (GtkCellRenderer *cell, int value, int min, int max, int step)
+{
+  char text[INT_BUFSIZE_BOUND (int)];
+  GtkAdjustment *adjust;
+
+  if (max > min)
+    adjust = GTK_ADJUSTMENT (gtk_adjustment_new (value, min, max,
+                                                 step, step, 0.0));
+  else
+    adjust = NULL;
+
+  sprintf (text, "%d", value);
+  g_object_set (cell,
+                "text", text,
+                "adjustment", adjust,
+                "editable", TRUE,
+                NULL);
+}
 
-enum
-  {
-    PSPPIRE_VAR_SHEET_MAY_CREATE_VARS = 1
-  };
+static void
+error_dialog (GtkWindow *w, gchar *primary_text, gchar *secondary_text)
+{
+  GtkWidget *dialog =
+    gtk_message_dialog_new (w,
+                           GTK_DIALOG_DESTROY_WITH_PARENT,
+                           GTK_MESSAGE_ERROR,
+                           GTK_BUTTONS_CLOSE, "%s", primary_text);
 
-GType
-psppire_var_sheet_get_type (void)
+  g_object_set (dialog, "icon-name", "psppicon", NULL);
+
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                           "%s", secondary_text);
+
+  gtk_dialog_run (GTK_DIALOG (dialog));
+
+  gtk_widget_destroy (dialog);
+}
+
+static void
+on_name_column_editing_started (GtkCellRenderer *cell,
+                                GtkCellEditable *editable,
+                                const gchar     *path,
+                                gpointer         user_data)
 {
-  static GType vs_type = 0;
+  PsppireVarSheet *var_sheet = g_object_get_data (G_OBJECT (cell), "var-sheet");
+  PsppireDict *dict = psppire_var_sheet_get_dictionary (var_sheet);
 
-  if (!vs_type)
+  g_return_if_fail (var_sheet);
+          g_return_if_fail (dict);
+
+  if (GTK_IS_ENTRY (editable))
     {
-      static const GTypeInfo vs_info =
-      {
-       sizeof (PsppireVarSheetClass),
-       NULL, /* base_init */
-        NULL, /* base_finalize */
-       (GClassInitFunc) psppire_var_sheet_class_init,
-        NULL, /* class_finalize */
-       NULL, /* class_data */
-        sizeof (PsppireVarSheet),
-       0,
-       (GInstanceInitFunc) psppire_var_sheet_init,
-      };
-
-      vs_type = g_type_register_static (PSPPIRE_TYPE_SHEET, "PsppireVarSheet",
-                                       &vs_info, 0);
+      GtkEntry *entry = GTK_ENTRY (editable);
+      if (gtk_entry_get_text (entry)[0] == '\0')
+        {
+          gchar name[64];
+          if (psppire_dict_generate_name (dict, name, sizeof name))
+            gtk_entry_set_text (entry, name);
+        }
     }
+}
+
+static void
+scroll_to_bottom (GtkWidget      *widget,
+                  GtkRequisition *requisition,
+                  gpointer        unused UNUSED)
+{
+  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
+  GtkAdjustment *vadjust;
+
+  vadjust = pspp_sheet_view_get_vadjustment (sheet_view);
+  gtk_adjustment_set_value (vadjust, gtk_adjustment_get_upper (vadjust));
 
-  return vs_type;
+  if (var_sheet->scroll_to_bottom_signal)
+    {
+      g_signal_handler_disconnect (var_sheet,
+                                   var_sheet->scroll_to_bottom_signal);
+      var_sheet->scroll_to_bottom_signal = 0;
+    }
 }
 
-static GObjectClass * parent_class = NULL;
+static void
+on_var_column_edited (GtkCellRendererText *cell,
+                      gchar               *path_string,
+                      gchar               *new_text,
+                      gpointer             user_data)
+{
+  PsppireVarSheet *var_sheet = user_data;
+  GtkWindow *window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (var_sheet)));
+  struct dictionary *dict = var_sheet->dict->dict;
+  enum vs_column column_id;
+  struct variable *var;
+  int width, decimals;
+  GtkTreePath *path;
+  gint row;
+
+  path = gtk_tree_path_new_from_string (path_string);
+  row = gtk_tree_path_get_indices (path)[0];
+  gtk_tree_path_free (path);
+
+  column_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell),
+                                                  "column-id"));
+
+  var = psppire_dict_get_variable (var_sheet->dict, row);
+  if (var == NULL)
+    {
+      g_return_if_fail (column_id == VS_NAME);
+
+      if (!dict_id_is_valid (dict, new_text, false))
+        error_dialog (window,
+                      g_strdup (_("Cannot create variable.")),
+                      g_strdup_printf (_("\"%s\" is not a valid variable "
+                                         "name."), new_text));
+      else if (dict_lookup_var (dict, new_text) != NULL)
+        error_dialog (window,
+                      g_strdup (_("Cannot create variable.")),
+                      g_strdup_printf (_("This dictionary already contains "
+                                         "a variable named \"%s\"."),
+                                         new_text));
+      else
+        {
+          dict_create_var (var_sheet->dict->dict, new_text, 0);
+          if (!var_sheet->scroll_to_bottom_signal)
+            {
+              gtk_widget_queue_resize (GTK_WIDGET (var_sheet));
+              var_sheet->scroll_to_bottom_signal =
+                g_signal_connect (var_sheet, "size-request",
+                                  G_CALLBACK (scroll_to_bottom), NULL);
+            }
+        }
+
+      return;
+    }
+
+  switch (column_id)
+    {
+    case VS_NAME:
+      if (!dict_id_is_valid (dict, new_text, false))
+        error_dialog (window,
+                      g_strdup (_("Cannot rename variable.")),
+                      g_strdup_printf (_("\"%s\" is not a valid variable "
+                                         "name."), new_text));
+      else if (dict_lookup_var (dict, new_text) != NULL
+               && dict_lookup_var (dict, new_text) != var)
+        error_dialog (window,
+                      g_strdup (_("Cannot rename variable.")),
+                      g_strdup_printf (_("This dictionary already contains "
+                                         "a variable named \"%s\"."),
+                                         new_text));
+      else
+        dict_rename_var (dict, var, new_text);
+      break;
+
+    case VS_TYPE:
+      /* Not reachable. */
+      break;
+
+    case VS_WIDTH:
+      width = atoi (new_text);
+      if (width > 0)
+        {
+          struct fmt_spec format;
+
+          format = *var_get_print_format (var);
+          fmt_change_width (&format, width, var_sheet->format_use);
+          var_set_print_format (var, &format);
+          var_set_width (var, fmt_var_width (&format));
+        }
+      break;
+
+    case VS_DECIMALS:
+      decimals = atoi (new_text);
+      if (decimals >= 0)
+        {
+          struct fmt_spec format;
+
+          format = *var_get_print_format (var);
+          fmt_change_decimals (&format, decimals, var_sheet->format_use);
+          var_set_print_format (var, &format);
+        }
+      break;
+
+    case VS_LABEL:
+      var_set_label (var, new_text, false);
+      break;
+
+    case VS_VALUES:
+    case VS_MISSING:
+      break;
+
+    case VS_COLUMNS:
+      width = atoi (new_text);
+      if (width > 0 && width < 2 * MAX_STRING)
+        var_set_display_width (var, width);
+      break;
+
+    case VS_ALIGN:
+      if (!strcmp (new_text, alignment_to_string (ALIGN_LEFT)))
+        var_set_alignment (var, ALIGN_LEFT);
+      else if (!strcmp (new_text, alignment_to_string (ALIGN_CENTRE)))
+        var_set_alignment (var, ALIGN_CENTRE);
+      else if (!strcmp (new_text, alignment_to_string (ALIGN_RIGHT)))
+        var_set_alignment (var, ALIGN_RIGHT);
+      break;
+
+    case VS_MEASURE:
+      if (!strcmp (new_text, measure_to_string (MEASURE_NOMINAL)))
+        var_set_measure (var, MEASURE_NOMINAL);
+      else if (!strcmp (new_text, measure_to_string (MEASURE_ORDINAL)))
+        var_set_measure (var, MEASURE_ORDINAL);
+      else if (!strcmp (new_text, measure_to_string (MEASURE_SCALE)))
+        var_set_measure (var, MEASURE_SCALE);
+      break;
+    }
+}
 
 static void
-psppire_var_sheet_dispose (GObject *obj)
+render_popup_cell (PsppSheetViewColumn *tree_column,
+                   GtkCellRenderer *cell,
+                   GtkTreeModel *model,
+                   GtkTreeIter *iter,
+                   void *user_data)
 {
-  PsppireVarSheet *vs = (PsppireVarSheet *)obj;
+  PsppireVarSheet *var_sheet = user_data;
+  gint row;
 
-  if (vs->dispose_has_run)
-    return;
+  row = GPOINTER_TO_INT (iter->user_data);
+  g_object_set (cell,
+                "editable", row < psppire_dict_get_var_cnt (var_sheet->dict),
+                NULL);
+}
 
-  /* Make sure dispose does not run twice. */
-  vs->dispose_has_run = TRUE;
+static void
+render_var_cell (PsppSheetViewColumn *tree_column,
+                 GtkCellRenderer *cell,
+                 GtkTreeModel *model,
+                 GtkTreeIter *iter,
+                 void *user_data)
+{
+  PsppireVarSheet *var_sheet = user_data;
+  const struct fmt_spec *print;
+  enum vs_column column_id;
+  struct variable *var;
+  gint row;
 
-  /* Chain up to the parent class */
-  G_OBJECT_CLASS (parent_class)->dispose (obj);
+  column_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
+                                                  "column-number")) - 1;
+  row = GPOINTER_TO_INT (iter->user_data);
+
+  if (row >= psppire_dict_get_var_cnt (var_sheet->dict))
+    {
+      g_object_set (cell,
+                    "text", "",
+                    "editable", column_id == VS_NAME,
+                    NULL);
+      if (column_id == VS_WIDTH
+          || column_id == VS_DECIMALS
+          || column_id == VS_COLUMNS)
+        g_object_set (cell, "adjustment", NULL, NULL);
+      return;
+    }
+
+  var = psppire_dict_get_variable (var_sheet->dict, row);
+
+  print = var_get_print_format (var);
+  switch (column_id)
+    {
+    case VS_NAME:
+      g_object_set (cell,
+                    "text", var_get_name (var),
+                    "editable", TRUE,
+                    NULL);
+      break;
+
+    case VS_TYPE:
+      g_object_set (cell,
+                    "text", fmt_gui_name (print->type),
+                    "editable", FALSE,
+                    NULL);
+      break;
+
+    case VS_WIDTH:
+      {
+        int step = fmt_step_width (print->type);
+        if (var_is_numeric (var))
+          set_spin_cell (cell, print->w,
+                         fmt_min_width (print->type, var_sheet->format_use),
+                         fmt_max_width (print->type, var_sheet->format_use),
+                         step);
+        else
+          set_spin_cell (cell, print->w, 0, 0, step);
+      }
+      break;
+
+    case VS_DECIMALS:
+      if (fmt_takes_decimals (print->type))
+        {
+          int max_w = fmt_max_width (print->type, var_sheet->format_use);
+          int max_d = fmt_max_decimals (print->type, max_w,
+                                        var_sheet->format_use);
+          set_spin_cell (cell, print->d, 0, max_d, 1);
+        }
+      else
+        g_object_set (cell,
+                      "text", "",
+                      "editable", FALSE,
+                      "adjustment", NULL,
+                      NULL);
+      break;
+
+    case VS_LABEL:
+      g_object_set (cell,
+                    "text", var_has_label (var) ? var_get_label (var) : "",
+                    "editable", TRUE,
+                    NULL);
+      break;
+
+    case VS_VALUES:
+      g_object_set (cell, "editable", FALSE, NULL);
+      if ( ! var_has_value_labels (var))
+        g_object_set (cell, "text", _("None"), NULL);
+      else
+        {
+          const struct val_labs *vls = var_get_value_labels (var);
+          const struct val_lab **labels = val_labs_sorted (vls);
+          const struct val_lab *vl = labels[0];
+          gchar *vstr = value_to_text (vl->value, var);
+          char *text = xasprintf (_("{%s, %s}..."), vstr,
+                                  val_lab_get_escaped_label (vl));
+          free (vstr);
+
+          g_object_set (cell, "text", text, NULL);
+          free (labels);
+        }
+      break;
+
+    case VS_MISSING:
+      {
+        char *text = missing_values_to_string (var_sheet->dict, var, NULL);
+        g_object_set (cell,
+                      "text", text,
+                      "editable", FALSE,
+                      NULL);
+        free (text);
+      }
+      break;
+
+    case VS_COLUMNS:
+      set_spin_cell (cell, var_get_display_width (var), 1, 2 * MAX_STRING, 1);
+      break;
+
+    case VS_ALIGN:
+      g_object_set (cell,
+                    "text", alignment_to_string (var_get_alignment (var)),
+                    "editable", TRUE,
+                    NULL);
+      break;
+
+    case VS_MEASURE:
+      g_object_set (cell,
+                    "text", measure_to_string (var_get_measure (var)),
+                    "editable", TRUE,
+                    NULL);
+      break;
+    }
+}
+
+static struct variable *
+path_string_to_variable (PsppireVarSheet *var_sheet, gchar *path_string)
+{
+  PsppireDict *dict;
+  GtkTreePath *path;
+  gint row;
+
+  path = gtk_tree_path_new_from_string (path_string);
+  row = gtk_tree_path_get_indices (path)[0];
+  gtk_tree_path_free (path);
+
+  dict = psppire_var_sheet_get_dictionary (var_sheet);
+  g_return_val_if_fail (dict != NULL, NULL);
+
+  return psppire_dict_get_variable (dict, row);
 }
 
 static void
-psppire_var_sheet_finalize (GObject *obj)
+on_type_click (PsppireCellRendererButton *cell,
+               gchar *path,
+               PsppireVarSheet *var_sheet)
 {
-   /* Chain up to the parent class */
-   G_OBJECT_CLASS (parent_class)->finalize (obj);
+  var_sheet->var_type_dialog->pv = path_string_to_variable (var_sheet, path);
+  var_type_dialog_show (var_sheet->var_type_dialog);
+}
+
+static void
+on_value_labels_click (PsppireCellRendererButton *cell,
+                       gchar *path,
+                       PsppireVarSheet *var_sheet)
+{
+  struct variable *var = path_string_to_variable (var_sheet, path);
+  val_labs_dialog_set_target_variable (var_sheet->val_labs_dialog, var);
+  val_labs_dialog_show (var_sheet->val_labs_dialog);
+}
+
+static void
+on_missing_values_click (PsppireCellRendererButton *cell,
+                         gchar *path,
+                         PsppireVarSheet *var_sheet)
+{
+  var_sheet->missing_val_dialog->pv = path_string_to_variable (var_sheet,
+                                                               path);
+  missing_val_dialog_show (var_sheet->missing_val_dialog);
+}
+
+static gint
+get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
+                  const char *string)
+{
+  gint width;
+  g_object_set (G_OBJECT (renderer),
+                PSPPIRE_IS_CELL_RENDERER_BUTTON (renderer) ? "label" : "text",
+                string, (void *) NULL);
+  gtk_cell_renderer_get_size (renderer, GTK_WIDGET (treeview),
+                              NULL, NULL, NULL, &width, NULL);
+  return width;
+}
+
+static gint
+get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
+                     size_t char_cnt)
+{
+  struct string s;
+  gint width;
+
+  ds_init_empty (&s);
+  ds_put_byte_multiple (&s, '0', char_cnt);
+  ds_put_byte (&s, ' ');
+  width = get_string_width (treeview, renderer, ds_cstr (&s));
+  ds_destroy (&s);
+
+  return width;
+}
+
+static PsppSheetViewColumn *
+add_var_sheet_column (PsppireVarSheet *var_sheet, GtkCellRenderer *renderer,
+                      enum vs_column column_id,
+                      const char *title, int width)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
+  int title_width, content_width;
+  PsppSheetViewColumn *column;
+
+  column = pspp_sheet_view_column_new_with_attributes (title, renderer, NULL);
+  g_object_set_data (G_OBJECT (column), "column-number",
+                     GINT_TO_POINTER (column_id) + 1);
+
+  pspp_sheet_view_column_set_cell_data_func (
+    column, renderer, render_var_cell, var_sheet, NULL);
+
+  title_width = get_string_width (sheet_view, renderer, title);
+  content_width = get_monospace_width (sheet_view, renderer, width);
+  g_object_set_data (G_OBJECT (column), "content-width",
+                     GINT_TO_POINTER (content_width));
+
+  pspp_sheet_view_column_set_fixed_width (column,
+                                          MAX (title_width, content_width));
+  pspp_sheet_view_column_set_resizable (column, TRUE);
+
+  pspp_sheet_view_append_column (sheet_view, column);
+
+  g_signal_connect (renderer, "edited",
+                    G_CALLBACK (on_var_column_edited),
+                    var_sheet);
+  g_object_set_data (G_OBJECT (renderer), "column-id",
+                     GINT_TO_POINTER (column_id));
+  g_object_set_data (G_OBJECT (renderer), "var-sheet", var_sheet);
+
+  return column;
 }
 
+static PsppSheetViewColumn *
+add_text_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
+                 const char *title, int width)
+{
+  return add_var_sheet_column (var_sheet, gtk_cell_renderer_text_new (),
+                               column_id, title, width);
+}
 
-struct column_parameters
+static PsppSheetViewColumn *
+add_spin_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
+                 const char *title, int width)
 {
-  gchar label[20];
-  gint width ;
-};
+  return add_var_sheet_column (var_sheet, gtk_cell_renderer_spin_new (),
+                               column_id, title, width);
+}
 
-#define n_ALIGNMENTS 3
+static PsppSheetViewColumn *
+add_combo_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
+                  const char *title, int width,
+                  ...)
+{
+  GtkCellRenderer *cell;
+  GtkListStore *store;
+  const char *name;
+  va_list args;
+
+  store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
+  va_start (args, width);
+  while ((name = va_arg (args, const char *)) != NULL)
+    {
+      int value = va_arg (args, int);
+      gtk_list_store_insert_with_values (store, NULL, G_MAXINT,
+                                         0, value,
+                                         1, name,
+                                         -1);
+    }
+  va_end (args);
 
-const gchar *const alignments[n_ALIGNMENTS + 1]={
-  N_("Left"),
-  N_("Right"),
-  N_("Center"),
-  0
-};
+  cell = gtk_cell_renderer_combo_new ();
+  g_object_set (cell,
+                "has-entry", FALSE,
+                "model", GTK_TREE_MODEL (store),
+                "text-column", 1,
+                NULL);
 
-const gchar *const measures[n_MEASURES + 1]={
-  N_("Nominal"),
-  N_("Ordinal"),
-  N_("Scale"),
-  0
-};
+  return add_var_sheet_column (var_sheet, cell, column_id, title, width);
 
+}
 
+static void
+add_popup_menu (PsppireVarSheet *var_sheet,
+                PsppSheetViewColumn *column,
+                void (*on_click) (PsppireCellRendererButton *,
+                                  gchar *path,
+                                  PsppireVarSheet *var_sheet))
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
+  const char *button_label = "...";
+  GtkCellRenderer *button_renderer;
+  gint content_width;
+
+  button_renderer = psppire_cell_renderer_button_new ();
+  g_object_set (button_renderer,
+                "label", button_label,
+                "editable", TRUE,
+                NULL);
+  g_signal_connect (button_renderer, "clicked", G_CALLBACK (on_click),
+                    var_sheet);
+  pspp_sheet_view_column_pack_start (column, button_renderer, FALSE);
+  pspp_sheet_view_column_set_cell_data_func (
+    column, button_renderer, render_popup_cell, var_sheet, NULL);
+
+  content_width = GPOINTER_TO_INT (g_object_get_data (
+                                     G_OBJECT (column), "content-width"));
+  content_width += get_string_width (sheet_view, button_renderer,
+                                     button_label);
+  if (content_width > pspp_sheet_view_column_get_fixed_width (column))
+    pspp_sheet_view_column_set_fixed_width (column, content_width);
+}
 
-/* Create a list store from an array of strings */
-static GtkListStore *
-create_label_list (const gchar *const *labels)
+static gboolean
+get_tooltip_location (GtkWidget *widget, GtkTooltip *tooltip,
+                      gint wx, gint wy, size_t *row, size_t *column)
 {
-  const gchar *s;
-  gint i = 0;
+  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
+  gint bx, by;
+  GtkTreePath *path;
   GtkTreeIter iter;
+  PsppSheetViewColumn *tree_column;
+  GtkTreeModel *tree_model;
+  gpointer column_ptr;
+  bool ok;
+
+  /* Check that WIDGET is really visible on the screen before we
+     do anything else.  This is a bug fix for a sticky situation:
+     when text_data_import_assistant() returns, it frees the data
+     necessary to compose the tool tip message, but there may be
+     a tool tip under preparation at that point (even if there is
+     no visible tool tip) that will call back into us a little
+     bit later.  Perhaps the correct solution to this problem is
+     to make the data related to the tool tips part of a GObject
+     that only gets destroyed when all references are released,
+     but this solution appears to be effective too. */
+  if (!gtk_widget_get_mapped (widget))
+    return FALSE;
+
+  pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
+                                                     wx, wy, &bx, &by);
+  if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
+                                      &path, &tree_column, NULL, NULL))
+    return FALSE;
+
+  column_ptr = g_object_get_data (G_OBJECT (tree_column), "column-number");
+  if (column_ptr == NULL)
+    return FALSE;
+  *column = GPOINTER_TO_INT (column_ptr) - 1;
+
+  pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, tree_column,
+                                    NULL);
+
+  tree_model = pspp_sheet_view_get_model (tree_view);
+  ok = gtk_tree_model_get_iter (tree_model, &iter, path);
+  gtk_tree_path_free (path);
+  if (!ok)
+    return FALSE;
+
+  *row = GPOINTER_TO_INT (iter.user_data);
+  return TRUE;
+}
+
+static gboolean
+on_query_var_tooltip (GtkWidget *widget, gint wx, gint wy,
+                      gboolean keyboard_mode UNUSED,
+                      GtkTooltip *tooltip, gpointer *user_data UNUSED)
+{
+  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
+  PsppireDict *dict;
+  struct variable *var;
+  size_t row, column;
+
+  if (!get_tooltip_location (widget, tooltip, wx, wy, &row, &column))
+    return FALSE;
+
+  dict = psppire_var_sheet_get_dictionary (var_sheet);
+  g_return_val_if_fail (dict != NULL, FALSE);
+
+  if (row >= psppire_dict_get_var_cnt (dict))
+    {
+      gtk_tooltip_set_text (tooltip, _("Enter a variable name to add a "
+                                       "new variable."));
+      return TRUE;
+    }
+
+  var = psppire_dict_get_variable (dict, row);
+  g_return_val_if_fail (var != NULL, FALSE);
+
+  switch (column)
+    {
+    case VS_TYPE:
+      {
+        char text[FMT_STRING_LEN_MAX + 1];
+
+        fmt_to_string (var_get_print_format (var), text);
+        gtk_tooltip_set_text (tooltip, text);
+        return TRUE;
+      }
+
+    case VS_VALUES:
+      if (var_has_value_labels (var))
+        {
+          const struct val_labs *vls = var_get_value_labels (var);
+          const struct val_lab **labels = val_labs_sorted (vls);
+          struct string s;
+          size_t i;
+
+          ds_init_empty (&s);
+          for (i = 0; i < val_labs_count (vls); i++)
+            {
+              const struct val_lab *vl = labels[i];
+              gchar *vstr;
+
+              if (i >= 10 || ds_length (&s) > 500)
+                {
+                  ds_put_cstr (&s, "...");
+                  break;
+                }
+
+              vstr = value_to_text (vl->value, var);
+              ds_put_format (&s, _("{%s, %s}\n"), vstr,
+                             val_lab_get_escaped_label (vl));
+              free (vstr);
+
+            }
+          ds_chomp_byte (&s, '\n');
+
+          gtk_tooltip_set_text (tooltip, ds_cstr (&s));
+          ds_destroy (&s);
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+do_popup_menu (GtkWidget *widget, guint button, guint32 time)
+{
+  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
+  GtkWidget *menu;
+
+  menu = get_widget_assert (var_sheet->builder, "varsheet-variable-popup");
+  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
+}
 
-  GtkListStore *list_store = gtk_list_store_new (1, G_TYPE_STRING);
+static void
+on_popup_menu (GtkWidget *widget, gpointer user_data UNUSED)
+{
+  do_popup_menu (widget, 0, gtk_get_current_event_time ());
+}
+
+static gboolean
+on_button_pressed (GtkWidget *widget, GdkEventButton *event,
+                   gpointer user_data UNUSED)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
 
-  while ( (s = labels[i++]))
+  if (event->type == GDK_BUTTON_PRESS && event->button == 3)
     {
-      gtk_list_store_append (list_store, &iter);
-      gtk_list_store_set (list_store, &iter,
-                         0, gettext (s),
-                         -1);
+      PsppSheetSelection *selection;
+
+      selection = pspp_sheet_view_get_selection (sheet_view);
+      if (pspp_sheet_selection_count_selected_rows (selection) <= 1)
+        {
+          GtkTreePath *path;
+
+          if (pspp_sheet_view_get_path_at_pos (sheet_view, event->x, event->y,
+                                               &path, NULL, NULL, NULL))
+            {
+              pspp_sheet_selection_unselect_all (selection);
+              pspp_sheet_selection_select_path (selection, path);
+              gtk_tree_path_free (path);
+            }
+        }
+
+      do_popup_menu (widget, event->button, event->time);
+      return TRUE;
     }
 
-  return list_store;
+  return FALSE;
+}
+\f
+GType
+psppire_fmt_use_get_type (void)
+{
+  static GType etype = 0;
+  if (etype == 0)
+    {
+      static const GEnumValue values[] =
+       {
+         { FMT_FOR_INPUT, "FMT_FOR_INPUT", "input" },
+         { FMT_FOR_OUTPUT, "FMT_FOR_OUTPUT", "output" },
+         { 0, NULL, NULL }
+       };
+
+      etype = g_enum_register_static
+       (g_intern_static_string ("PsppireFmtUse"), values);
+    }
+  return etype;
 }
 
+enum
+  {
+    PROP_0,
+    PROP_DICTIONARY,
+    PROP_MAY_CREATE_VARS,
+    PROP_MAY_DELETE_VARS,
+    PROP_FORMAT_TYPE,
+    PROP_UI_MANAGER
+  };
 
 static void
 psppire_var_sheet_set_property (GObject      *object,
-                                guint         property_id,
-                                const GValue *value,
-                                GParamSpec   *pspec)
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
 {
-  PsppireVarSheet *self = (PsppireVarSheet *) object;
+  PsppireVarSheet *obj = PSPPIRE_VAR_SHEET (object);
 
-  switch (property_id)
+  switch (prop_id)
     {
-    case PSPPIRE_VAR_SHEET_MAY_CREATE_VARS:
-      self->may_create_vars = g_value_get_boolean (value);
+    case PROP_DICTIONARY:
+      psppire_var_sheet_set_dictionary (obj,
+                                        PSPPIRE_DICT (g_value_get_object (
+                                                        value)));
+      break;
+
+    case PROP_MAY_CREATE_VARS:
+      psppire_var_sheet_set_may_create_vars (obj,
+                                             g_value_get_boolean (value));
+      break;
+
+    case PROP_MAY_DELETE_VARS:
+      psppire_var_sheet_set_may_delete_vars (obj,
+                                             g_value_get_boolean (value));
       break;
 
+    case PROP_FORMAT_TYPE:
+      obj->format_use = g_value_get_enum (value);
+      break;
+
+    case PROP_UI_MANAGER:
     default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
 
 static void
 psppire_var_sheet_get_property (GObject      *object,
-                                guint         property_id,
+                                guint         prop_id,
                                 GValue       *value,
                                 GParamSpec   *pspec)
 {
-  PsppireVarSheet *self = (PsppireVarSheet *) object;
+  PsppireVarSheet *obj = PSPPIRE_VAR_SHEET (object);
 
-  switch (property_id)
+  switch (prop_id)
     {
-    case PSPPIRE_VAR_SHEET_MAY_CREATE_VARS:
-      g_value_set_boolean (value, self->may_create_vars);
+    case PROP_DICTIONARY:
+      g_value_set_object (value,
+                          G_OBJECT (psppire_var_sheet_get_dictionary (obj)));
+      break;
+
+    case PROP_MAY_CREATE_VARS:
+      g_value_set_boolean (value, obj->may_create_vars);
+      break;
+
+    case PROP_MAY_DELETE_VARS:
+      g_value_set_boolean (value, obj->may_delete_vars);
+      break;
+
+    case PROP_FORMAT_TYPE:
+      g_value_set_enum (value, obj->format_use);
+      break;
+
+    case PROP_UI_MANAGER:
+      g_value_set_object (value, psppire_var_sheet_get_ui_manager (obj));
       break;
 
     default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
 
+static void
+psppire_var_sheet_realize (GtkWidget *w)
+{
+  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (w);
+  GtkWindow *toplevel;
+
+  GTK_WIDGET_CLASS (psppire_var_sheet_parent_class)->realize (w);
+
+  toplevel = GTK_WINDOW (gtk_widget_get_toplevel (w));
+  var_sheet->val_labs_dialog = val_labs_dialog_create (toplevel);
+  var_sheet->missing_val_dialog = missing_val_dialog_create (toplevel);
+  var_sheet->var_type_dialog = var_type_dialog_create (toplevel);
+}
 
 static void
-psppire_var_sheet_class_init (PsppireVarSheetClass *klass)
+psppire_var_sheet_dispose (GObject *obj)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (obj);
+  int i;
+
+  if (var_sheet->dispose_has_run)
+    return;
+
+  var_sheet->dispose_has_run = TRUE;
+
+  for (i = 0; i < PSPPIRE_VAR_SHEET_N_SIGNALS; i++)
+    if ( var_sheet->dict_signals[i])
+      g_signal_handler_disconnect (var_sheet->dict,
+                                  var_sheet->dict_signals[i]);
+
+  if (var_sheet->dict)
+    g_object_unref (var_sheet->dict);
+  
+  if (var_sheet->uim)
+    g_object_unref (var_sheet->uim);
+
+  /* These dialogs are not GObjects (although they should be!)
+    But for now, unreffing them only causes a GCritical Error
+    so comment them out for now. (and accept the memory leakage)
+
+  g_object_unref (var_sheet->val_labs_dialog);
+  g_object_unref (var_sheet->missing_val_dialog);
+  g_object_unref (var_sheet->var_type_dialog);
+  */
+
+  G_OBJECT_CLASS (psppire_var_sheet_parent_class)->dispose (obj);
+}
+
+static void
+psppire_var_sheet_class_init (PsppireVarSheetClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
   GParamSpec *pspec;
 
-  parent_class = g_type_class_peek_parent (klass);
+  gobject_class->set_property = psppire_var_sheet_set_property;
+  gobject_class->get_property = psppire_var_sheet_get_property;
+  gobject_class->dispose = psppire_var_sheet_dispose;
 
-  object_class->dispose = psppire_var_sheet_dispose;
-  object_class->finalize = psppire_var_sheet_finalize;
   widget_class->realize = psppire_var_sheet_realize;
-  widget_class->unrealize = psppire_var_sheet_unrealize;
-  object_class->set_property = psppire_var_sheet_set_property;
-  object_class->get_property = psppire_var_sheet_get_property;
+
+  g_signal_new ("var-double-clicked",
+                G_OBJECT_CLASS_TYPE (gobject_class),
+                G_SIGNAL_RUN_LAST,
+                0,
+                g_signal_accumulator_true_handled, NULL,
+                psppire_marshal_BOOLEAN__INT,
+                G_TYPE_BOOLEAN, 1, G_TYPE_INT);
+
+  pspec = g_param_spec_object ("dictionary",
+                               "Dictionary displayed by the sheet",
+                               "The PsppireDict that the sheet displays "
+                               "may allow the user to edit",
+                               PSPPIRE_TYPE_DICT,
+                               G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_DICTIONARY, pspec);
 
   pspec = g_param_spec_boolean ("may-create-vars",
                                 "May create variables",
                                 "Whether the user may create more variables",
                                 TRUE,
                                 G_PARAM_READWRITE);
-  g_object_class_install_property (object_class,
-                                   PSPPIRE_VAR_SHEET_MAY_CREATE_VARS,
-                                   pspec);
+  g_object_class_install_property (gobject_class, PROP_MAY_CREATE_VARS, pspec);
 
-  klass->measure_list = create_label_list (measures);
-  klass->alignment_list = create_label_list (alignments);
+  pspec = g_param_spec_boolean ("may-delete-vars",
+                                "May delete variables",
+                                "Whether the user may delete variables",
+                                TRUE,
+                                G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_MAY_DELETE_VARS, pspec);
+
+  pspec = g_param_spec_enum ("format-use",
+                             "Use of variable format",
+                             ("Whether variables have input or output "
+                              "formats"),
+                             PSPPIRE_TYPE_FMT_USE,
+                             FMT_FOR_OUTPUT,
+                             G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_FORMAT_TYPE, pspec);
+
+  pspec = g_param_spec_object ("ui-manager",
+                               "UI Manager",
+                               "UI manager for the variable sheet.  The client should merge this UI manager with the active UI manager to obtain variable sheet specific menu items and tool bar items.",
+                               GTK_TYPE_UI_MANAGER,
+                               G_PARAM_READABLE);
+  g_object_class_install_property (gobject_class, PROP_UI_MANAGER, pspec);
 }
 
-
-
-/* Callback for when the alignment combo box
-   item is selected */
 static void
-change_alignment (GtkComboBox *cb,
-                 struct variable *var)
+render_row_number_cell (PsppSheetViewColumn *tree_column,
+                        GtkCellRenderer *cell,
+                        GtkTreeModel *model,
+                        GtkTreeIter *iter,
+                        gpointer user_data)
 {
-  gint active_item = gtk_combo_box_get_active (cb);
+  PsppireVarSheet *var_sheet = user_data;
+  GValue gvalue = { 0, };
+  gint row;
 
-  if ( active_item < 0 ) return ;
-
-  var_set_alignment (var, active_item);
-}
+  row = GPOINTER_TO_INT (iter->user_data);
 
+  g_value_init (&gvalue, G_TYPE_INT);
+  g_value_set_int (&gvalue, row + 1);
+  g_object_set_property (G_OBJECT (cell), "label", &gvalue);
+  g_value_unset (&gvalue);
 
+  if (!var_sheet->dict || row < psppire_dict_get_var_cnt (var_sheet->dict))
+    g_object_set (cell, "editable", TRUE, NULL);
+  else
+    g_object_set (cell, "editable", FALSE, NULL);
+}
 
-/* Callback for when the measure combo box
-   item is selected */
 static void
-change_measure (GtkComboBox *cb,
-               struct variable *var)
+psppire_var_sheet_row_number_double_clicked (PsppireCellRendererButton *button,
+                                             gchar *path_string,
+                                             PsppireVarSheet *var_sheet)
 {
-  gint active_item = gtk_combo_box_get_active (cb);
+  GtkTreePath *path;
 
-  if ( active_item < 0 ) return ;
+  g_return_if_fail (var_sheet->dict != NULL);
 
-  var_set_measure (var, active_item);
+  path = gtk_tree_path_new_from_string (path_string);
+  if (gtk_tree_path_get_depth (path) == 1)
+    {
+      gint *indices = gtk_tree_path_get_indices (path);
+      if (indices[0] < psppire_dict_get_var_cnt (var_sheet->dict))
+        {
+          gboolean handled;
+          g_signal_emit_by_name (var_sheet, "var-double-clicked",
+                                 indices[0], &handled);
+        }
+    }
+  gtk_tree_path_free (path);
 }
 
+static PsppSheetViewColumn *
+make_row_number_column (PsppireVarSheet *var_sheet)
+{
+  PsppSheetViewColumn *column;
+  GtkCellRenderer *renderer;
+
+  renderer = psppire_cell_renderer_button_new ();
+  g_object_set (renderer, "xalign", 1.0, NULL);
+  g_signal_connect (renderer, "double-clicked",
+                    G_CALLBACK (psppire_var_sheet_row_number_double_clicked),
+                    var_sheet);
+
+  column = pspp_sheet_view_column_new_with_attributes (_("Variable"),
+                                                       renderer, NULL);
+  pspp_sheet_view_column_set_cell_data_func (
+    column, renderer, render_row_number_cell, var_sheet, NULL);
+  pspp_sheet_view_column_set_fixed_width (column, 50);
+  return column;
+}
 
-/* Moves the focus to a new cell.
-   Returns TRUE iff the move should be disallowed */
-static gboolean
-traverse_cell_callback (PsppireSheet *sheet,
-                       const PsppireSheetCell *existing_cell,
-                       PsppireSheetCell *new_cell)
+static void
+on_edit_clear_variables (GtkAction *action, PsppireVarSheet *var_sheet)
 {
-  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (sheet);
-  PsppireVarStore *var_store = PSPPIRE_VAR_STORE (psppire_sheet_get_model (sheet));
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
+  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
+  PsppireDict *dict = var_sheet->dict;
+  const struct range_set_node *node;
+  struct range_set *selected;
+
+  selected = pspp_sheet_selection_get_range_set (selection);
+  for (node = range_set_last (selected); node != NULL;
+       node = range_set_prev (selected, node))
+    {
+      int i;
+
+      for (i = 1; i <= range_set_node_get_width (node); i++)
+        {
+          unsigned long row = range_set_node_get_end (node) - i;
+          if (row >= 0 && row < psppire_dict_get_var_cnt (dict))
+            psppire_dict_delete_variables (dict, row, 1);
+        }
+    }
+  range_set_destroy (selected);
+}
 
-  gint n_vars = psppire_var_store_get_var_cnt (var_store);
+static void
+on_selection_changed (PsppSheetSelection *selection,
+                      gpointer user_data UNUSED)
+{
+  PsppSheetView *sheet_view = pspp_sheet_selection_get_tree_view (selection);
+  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (sheet_view);
+  gint n_selected_rows;
+  gboolean may_delete;
+  GtkTreePath *path;
+  GtkAction *action;
 
-  if (new_cell->col >=  PSPPIRE_VAR_STORE_n_COLS)
-    return TRUE;
+  n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
 
-  if (new_cell->row >= n_vars && !var_sheet->may_create_vars)
-    return TRUE;
+  action = get_action_assert (var_sheet->builder, "edit_insert-variable");
+  gtk_action_set_sensitive (action, (var_sheet->may_create_vars
+                                     && n_selected_rows > 0));
 
-  if ( existing_cell->row == n_vars && new_cell->row >= n_vars)
+  switch (n_selected_rows)
     {
-      GtkEntry *entry = psppire_sheet_get_entry (sheet);
-
-      const gchar *name = gtk_entry_get_text (entry);
-
-      if (! psppire_dict_check_name (var_store->dictionary, name, TRUE))
-       return TRUE;
+    case 0:
+      may_delete = FALSE;
+      break;
 
-      psppire_dict_insert_variable (var_store->dictionary, existing_cell->row, name);
+    case 1:
+      /* The row used for inserting new variables cannot be deleted. */
+      path = gtk_tree_path_new_from_indices (
+        psppire_dict_get_var_cnt (var_sheet->dict), -1);
+      may_delete = !pspp_sheet_selection_path_is_selected (selection, path);
+      gtk_tree_path_free (path);
+      break;
 
-      return FALSE;
+    default:
+      may_delete = TRUE;
+      break;
     }
+  action = get_action_assert (var_sheet->builder, "edit_clear-variables");
+  gtk_action_set_sensitive (action, var_sheet->may_delete_vars && may_delete);
+}
 
+static void
+on_edit_insert_variable (GtkAction *action, PsppireVarSheet *var_sheet)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
+  PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
+  PsppireDict *dict = var_sheet->dict;
+  struct range_set *selected;
+  unsigned long row;
 
-  /* If the destination cell is outside the current  variables, then
-     automatically create variables for the new rows.
-  */
-  if ( ((new_cell->row > n_vars) ||
-        (new_cell->row == n_vars &&
-        new_cell->col != PSPPIRE_VAR_STORE_COL_NAME)) )
+  selected = pspp_sheet_selection_get_range_set (selection);
+  row = range_set_scan (selected, 0);
+  range_set_destroy (selected);
+
+  if (row <= psppire_dict_get_var_cnt (dict))
     {
-      gint i;
-      for ( i = n_vars ; i <= new_cell->row; ++i )
-       psppire_dict_insert_variable (var_store->dictionary, i, NULL);
+      gchar name[64];;
+      if (psppire_dict_generate_name (dict, name, sizeof name))
+        psppire_dict_insert_variable (dict, row, name);
     }
-
-  return FALSE;
 }
 
-
-
-/*
-   Callback whenever the active cell changes on the var sheet.
-*/
 static void
-var_sheet_change_active_cell (PsppireVarSheet *vs,
-                             gint row, gint column,
-                             gint oldrow, gint oldcolumn,
-                             gpointer data)
+psppire_var_sheet_init (PsppireVarSheet *obj)
 {
-  PsppireVarStore *var_store;
-  PsppireVarSheetClass *vs_class =
-    PSPPIRE_VAR_SHEET_CLASS(G_OBJECT_GET_CLASS (vs));
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (obj);
+  PsppSheetViewColumn *column;
+  GtkAction *action;
+  GList *list;
 
-  struct variable *var ;
-  PsppireSheet *sheet = PSPPIRE_SHEET (vs);
+  obj->dict = NULL;
+  obj->format_use = PSPPIRE_TYPE_FMT_USE;
+  obj->may_create_vars = TRUE;
+  obj->may_delete_vars = TRUE;
 
-  g_return_if_fail (sheet != NULL);
+  obj->scroll_to_bottom_signal = 0;
 
-  var_store = PSPPIRE_VAR_STORE (psppire_sheet_get_model (sheet));
+  obj->container = NULL;
+  obj->dispose_has_run = FALSE;
+  obj->uim = NULL;
 
-  g_assert (var_store);
+  pspp_sheet_view_append_column (sheet_view, make_row_number_column (obj));
 
-  g_return_if_fail (oldcolumn == PSPPIRE_VAR_STORE_COL_NAME ||
-                   row < psppire_var_store_get_var_cnt (var_store));
-
-  var = psppire_var_store_get_var (var_store, row);
-
-  switch (column)
-    {
-    case PSPPIRE_VAR_STORE_COL_ALIGN:
-      {
-       GtkEntry *entry;
-       static GtkListStore *list_store = NULL;
-       GtkComboBoxEntry *cbe;
-       psppire_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
-       entry = psppire_sheet_get_entry (sheet);
-       cbe = GTK_COMBO_BOX_ENTRY (GTK_WIDGET (entry)->parent);
+  column = add_text_column (obj, VS_NAME, _("Name"), 12);
+  list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
+  g_signal_connect (list->data, "editing-started",
+                    G_CALLBACK (on_name_column_editing_started), NULL);
+  g_list_free (list);
 
-       if ( ! list_store) list_store = create_label_list (alignments);
+  column = add_text_column (obj, VS_TYPE, _("Type"), 8);
+  add_popup_menu (obj, column, on_type_click);
 
-       gtk_combo_box_set_model (GTK_COMBO_BOX (cbe),
-                               GTK_TREE_MODEL (vs_class->alignment_list));
+  add_spin_column (obj, VS_WIDTH, _("Width"), 5);
 
-       gtk_combo_box_entry_set_text_column (cbe, 0);
+  add_spin_column (obj, VS_DECIMALS, _("Decimals"), 2);
 
-       g_signal_connect (cbe, "changed",
-                        G_CALLBACK (change_alignment), var);
-      }
-      break;
+  add_text_column (obj, VS_LABEL, _("Label"), 20);
 
-    case PSPPIRE_VAR_STORE_COL_MEASURE:
-      {
-       GtkEntry *entry;
-       GtkComboBoxEntry *cbe;
-       psppire_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
-       entry = psppire_sheet_get_entry (sheet);
-       cbe = GTK_COMBO_BOX_ENTRY (GTK_WIDGET (entry)->parent);
+  column = add_text_column (obj, VS_VALUES, _("Value Labels"), 20);
+  add_popup_menu (obj, column, on_value_labels_click);
 
-       gtk_combo_box_set_model (GTK_COMBO_BOX (cbe),
-                               GTK_TREE_MODEL (vs_class->measure_list));
+  column = add_text_column (obj, VS_MISSING, _("Missing Values"), 20);
+  add_popup_menu (obj, column, on_missing_values_click);
 
-       gtk_combo_box_entry_set_text_column (cbe, 0);
+  add_spin_column (obj, VS_COLUMNS, _("Columns"), 3);
 
-       g_signal_connect (cbe, "changed",
-                         G_CALLBACK (change_measure), var);
-      }
-      break;
+  add_combo_column (obj, VS_ALIGN, _("Align"), 6,
+                    alignment_to_string (ALIGN_LEFT), ALIGN_LEFT,
+                    alignment_to_string (ALIGN_CENTRE), ALIGN_CENTRE,
+                    alignment_to_string (ALIGN_RIGHT), ALIGN_RIGHT,
+                    NULL);
 
-    case PSPPIRE_VAR_STORE_COL_VALUES:
-      {
-       PsppireCustomEntry *customEntry;
+  add_combo_column (obj, VS_MEASURE, _("Measure"), 10,
+                    measure_to_string (MEASURE_NOMINAL), MEASURE_NOMINAL,
+                    measure_to_string (MEASURE_ORDINAL), MEASURE_ORDINAL,
+                    measure_to_string (MEASURE_SCALE), MEASURE_SCALE,
+                    NULL);
 
-       psppire_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
+  pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
+  pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
+                                 PSPP_SHEET_SELECTION_MULTIPLE);
 
-       customEntry =
-         PSPPIRE_CUSTOM_ENTRY (psppire_sheet_get_entry (sheet));
+  g_object_set (G_OBJECT (obj), "has-tooltip", TRUE, NULL);
+  g_signal_connect (obj, "query-tooltip",
+                    G_CALLBACK (on_query_var_tooltip), NULL);
+  g_signal_connect (obj, "button-press-event",
+                    G_CALLBACK (on_button_pressed), NULL);
+  g_signal_connect (obj, "popup-menu", G_CALLBACK (on_popup_menu), NULL);
 
-       val_labs_dialog_set_target_variable (vs->val_labs_dialog, var);
+  obj->builder = builder_new ("var-sheet.ui");
 
-       g_signal_connect_swapped (customEntry,
-                                 "clicked",
-                                 G_CALLBACK (val_labs_dialog_show),
-                                 vs->val_labs_dialog);
-      }
-      break;
+  action = get_action_assert (obj->builder, "edit_clear-variables");
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_clear_variables),
+                    obj);
+  gtk_action_set_sensitive (action, FALSE);
+  g_signal_connect (pspp_sheet_view_get_selection (sheet_view),
+                    "changed", G_CALLBACK (on_selection_changed), NULL);
 
-    case PSPPIRE_VAR_STORE_COL_MISSING:
-      {
-       PsppireCustomEntry *customEntry;
+  action = get_action_assert (obj->builder, "edit_insert-variable");
+  gtk_action_set_sensitive (action, FALSE);
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_insert_variable),
+                    obj);
+}
 
-       psppire_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
+GtkWidget *
+psppire_var_sheet_new (void)
+{
+  return g_object_new (PSPPIRE_VAR_SHEET_TYPE, NULL);
+}
 
-       customEntry =
-         PSPPIRE_CUSTOM_ENTRY (psppire_sheet_get_entry (sheet));
+PsppireDict *
+psppire_var_sheet_get_dictionary (PsppireVarSheet *var_sheet)
+{
+  return var_sheet->dict;
+}
 
-       vs->missing_val_dialog->pv =
-         psppire_var_store_get_var (var_store, row);
+static void
+refresh_model (PsppireVarSheet *var_sheet)
+{
+  pspp_sheet_view_set_model (PSPP_SHEET_VIEW (var_sheet), NULL);
 
-       g_signal_connect_swapped (customEntry,
-                                 "clicked",
-                                 G_CALLBACK (missing_val_dialog_show),
-                                 vs->missing_val_dialog);
-      }
-      break;
+  if (var_sheet->dict != NULL)
+    {
+      PsppireEmptyListStore *store;
+      int n_rows;
+
+      n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
+                + var_sheet->may_create_vars);
+      store = psppire_empty_list_store_new (n_rows);
+      pspp_sheet_view_set_model (PSPP_SHEET_VIEW (var_sheet),
+                                 GTK_TREE_MODEL (store));
+      g_object_unref (store);
+    }
+}
 
-    case PSPPIRE_VAR_STORE_COL_TYPE:
-      {
-       PsppireCustomEntry *customEntry;
+static void
+on_var_inserted (PsppireDict *dict, glong row, PsppireVarSheet *var_sheet)
+{
+  PsppireEmptyListStore *store;
+  int n_rows;
 
-       psppire_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
+  g_return_if_fail (dict == var_sheet->dict);
 
-       customEntry =
-         PSPPIRE_CUSTOM_ENTRY (psppire_sheet_get_entry (sheet));
+  store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
+                                      PSPP_SHEET_VIEW (var_sheet)));
+  g_return_if_fail (store != NULL);
 
+  n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
+            + var_sheet->may_create_vars);
+  psppire_empty_list_store_set_n_rows (store, n_rows);
+  psppire_empty_list_store_row_inserted (store, row);
+}
 
-       /* Popup the Variable Type dialog box */
-       vs->var_type_dialog->pv = var;
+static void
+on_var_deleted (PsppireDict *dict,
+                const struct variable *var, int dict_idx, int case_idx,
+                PsppireVarSheet *var_sheet)
+{
+  PsppireEmptyListStore *store;
+  int n_rows;
 
-       g_signal_connect_swapped (customEntry,
-                                "clicked",
-                                G_CALLBACK (var_type_dialog_show),
-                                 vs->var_type_dialog);
-      }
-      break;
+  g_return_if_fail (dict == var_sheet->dict);
 
-    case PSPPIRE_VAR_STORE_COL_WIDTH:
-    case PSPPIRE_VAR_STORE_COL_DECIMALS:
-    case PSPPIRE_VAR_STORE_COL_COLUMNS:
-      {
-       if ( psppire_sheet_model_is_editable (PSPPIRE_SHEET_MODEL(var_store),
-                                             row, column))
-         {
-           gint r_min, r_max;
-
-           const gchar *s = psppire_sheet_cell_get_text (sheet, row, column);
-
-           if (s)
-             {
-               GtkSpinButton *spinButton ;
-               const gint current_value  = g_strtod (s, NULL);
-               GtkObject *adj ;
-
-               const struct fmt_spec *fmt = var_get_print_format (var);
-               switch (column)
-                 {
-                 case PSPPIRE_VAR_STORE_COL_WIDTH:
-                   r_min = MAX (fmt->d + 1, fmt_min_output_width (fmt->type));
-                   r_max = fmt_max_output_width (fmt->type);
-                   break;
-                 case PSPPIRE_VAR_STORE_COL_DECIMALS:
-                   r_min = 0 ;
-                   r_max = fmt_max_output_decimals (fmt->type, fmt->w);
-                   break;
-                 case PSPPIRE_VAR_STORE_COL_COLUMNS:
-                   r_min = 1;
-                   r_max = 255 ; /* Is this a sensible value ? */
-                   break;
-                 default:
-                   g_assert_not_reached ();
-                 }
-
-               adj = gtk_adjustment_new (current_value,
-                                         r_min, r_max,
-                                         1.0, 1.0, /* steps */
-                                         0);
-
-               psppire_sheet_change_entry (sheet, GTK_TYPE_SPIN_BUTTON);
-
-               spinButton =
-                 GTK_SPIN_BUTTON (psppire_sheet_get_entry (sheet));
-
-               gtk_spin_button_set_adjustment (spinButton, GTK_ADJUSTMENT (adj));
-               gtk_spin_button_set_digits (spinButton, 0);
-             }
-         }
-      }
-      break;
+  store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
+                                      PSPP_SHEET_VIEW (var_sheet)));
+  g_return_if_fail (store != NULL);
 
-    default:
-      psppire_sheet_change_entry (sheet, GTK_TYPE_ENTRY);
-      break;
-    }
+  n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
+            + var_sheet->may_create_vars);
+  psppire_empty_list_store_set_n_rows (store, n_rows);
+  psppire_empty_list_store_row_deleted (store, dict_idx);
 }
 
-
 static void
-psppire_var_sheet_realize (GtkWidget *w)
+on_backend_changed (PsppireDict *dict, PsppireVarSheet *var_sheet)
 {
-  PsppireVarSheet *vs = PSPPIRE_VAR_SHEET (w);
+  g_return_if_fail (dict == var_sheet->dict);
+  refresh_model (var_sheet);
+}
 
-  GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (vs));
+void
+psppire_var_sheet_set_dictionary (PsppireVarSheet *var_sheet,
+                                  PsppireDict *dict)
+{
+  if (var_sheet->dict != NULL)
+    {
+      int i;
+      
+      for (i = 0; i < PSPPIRE_VAR_SHEET_N_SIGNALS; i++)
+       {
+         if (var_sheet->dict_signals[i])
+           g_signal_handler_disconnect (var_sheet->dict,
+                                        var_sheet->dict_signals[i]);
+         
+         var_sheet->dict_signals[i] = 0;
+       }
+
+      g_object_unref (var_sheet->dict);
+    }
 
-  vs->val_labs_dialog = val_labs_dialog_create (GTK_WINDOW (toplevel));
+  var_sheet->dict = dict;
 
-  vs->missing_val_dialog = missing_val_dialog_create (GTK_WINDOW (toplevel));
-  vs->var_type_dialog = var_type_dialog_create (GTK_WINDOW (toplevel));
+  if (dict != NULL)
+    {
+      g_object_ref (dict);
 
-  /* Chain up to the parent class */
-  GTK_WIDGET_CLASS (parent_class)->realize (w);
-}
+      var_sheet->dict_signals[PSPPIRE_VAR_SHEET_BACKEND_CHANGED]
+        = g_signal_connect (dict, "backend-changed",
+                            G_CALLBACK (on_backend_changed), var_sheet);
 
-static void
-psppire_var_sheet_unrealize (GtkWidget *w)
-{
-  PsppireVarSheet *vs = PSPPIRE_VAR_SHEET (w);
+      var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_DELETED]
+        = g_signal_connect (dict, "variable-inserted",
+                            G_CALLBACK (on_var_inserted), var_sheet);
 
-  g_free (vs->val_labs_dialog);
-  g_free (vs->missing_val_dialog);
-  g_free (vs->var_type_dialog);
+      var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_INSERTED]
+        = g_signal_connect (dict, "variable-deleted",
+                            G_CALLBACK (on_var_deleted), var_sheet);
+    }
 
-  /* Chain up to the parent class */
-  GTK_WIDGET_CLASS (parent_class)->unrealize (w);
+  refresh_model (var_sheet);
 }
 
+gboolean
+psppire_var_sheet_get_may_create_vars (PsppireVarSheet *var_sheet)
+{
+  return var_sheet->may_create_vars;
+}
 
-
-static void
-psppire_var_sheet_init (PsppireVarSheet *vs)
+void
+psppire_var_sheet_set_may_create_vars (PsppireVarSheet *var_sheet,
+                                       gboolean may_create_vars)
 {
-  GtkBuilder *builder = builder_new ("data-editor.ui");
+  if (var_sheet->may_create_vars != may_create_vars)
+    {
+      PsppireEmptyListStore *store;
+      gint n_rows;
 
-  connect_help (builder);
+      var_sheet->may_create_vars = may_create_vars;
 
-  g_object_unref (builder);
+      store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
+                                          PSPP_SHEET_VIEW (var_sheet)));
+      g_return_if_fail (store != NULL);
 
-  vs->dispose_has_run = FALSE;
-  vs->may_create_vars = TRUE;
+      n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
+                + var_sheet->may_create_vars);
+      psppire_empty_list_store_set_n_rows (store, n_rows);
 
-  g_signal_connect (vs, "activate",
-                   G_CALLBACK (var_sheet_change_active_cell),
-                   NULL);
+      if (may_create_vars)
+        psppire_empty_list_store_row_inserted (store, n_rows - 1);
+      else
+        psppire_empty_list_store_row_deleted (store, n_rows);
 
-  g_signal_connect (vs, "traverse",
-                   G_CALLBACK (traverse_cell_callback), NULL);
+      on_selection_changed (pspp_sheet_view_get_selection (
+                              PSPP_SHEET_VIEW (var_sheet)), NULL);
+    }
 }
 
-
-static const struct column_parameters column_def[] = {
-  { N_("Name"),    80},
-  { N_("Type"),    100},
-  { N_("Width"),   57},
-  { N_("Decimals"),91},
-  { N_("Label"),   95},
-  { N_("Values"),  103},
-  { N_("Missing"), 95},
-  { N_("Columns"), 80},
-  { N_("Align"),   69},
-  { N_("Measure"), 99},
-};
-
-GtkWidget*
-psppire_var_sheet_new (void)
+gboolean
+psppire_var_sheet_get_may_delete_vars (PsppireVarSheet *var_sheet)
 {
-  gint i;
-  PsppireAxis *ha = psppire_axis_new ();
-  PsppireAxis *va = psppire_axis_new ();
-
-  GtkWidget *w = g_object_new (psppire_var_sheet_get_type (), NULL);
+  return var_sheet->may_delete_vars;
+}
 
-  for (i = 0 ; i < 10 ; ++i)
-    psppire_axis_append (ha, column_def[i].width);
+void
+psppire_var_sheet_set_may_delete_vars (PsppireVarSheet *var_sheet,
+                                       gboolean may_delete_vars)
+{
+  if (var_sheet->may_delete_vars != may_delete_vars)
+    {
+      var_sheet->may_delete_vars = may_delete_vars;
+      on_selection_changed (pspp_sheet_view_get_selection (
+                              PSPP_SHEET_VIEW (var_sheet)), NULL);
+    }
+}
 
-  g_object_set (va,
-               "default-size", 25,
-               NULL);
+void
+psppire_var_sheet_goto_variable (PsppireVarSheet *var_sheet, int dict_index)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
+  GtkTreePath *path;
 
-  g_object_set (ha, "minimum-extent", 0,
-               NULL);
+  path = gtk_tree_path_new_from_indices (dict_index, -1);
+  pspp_sheet_view_scroll_to_cell (sheet_view, path, NULL, FALSE, 0.0, 0.0);
+  pspp_sheet_view_set_cursor (sheet_view, path, NULL, FALSE);
+  gtk_tree_path_free (path);
+}
 
-  g_object_set (w,
-               "horizontal-axis", ha,
-               "vertical-axis", va,
-               NULL);
+GtkUIManager *
+psppire_var_sheet_get_ui_manager (PsppireVarSheet *var_sheet)
+{
+  if (var_sheet->uim == NULL)
+    {
+      var_sheet->uim = GTK_UI_MANAGER (get_object_assert (var_sheet->builder,
+                                                         "var_sheet_uim",
+                                                         GTK_TYPE_UI_MANAGER));
+      g_object_ref (var_sheet->uim);
+    }
 
-  return w;
+  return var_sheet->uim;
 }
+
index b996275c70404e94ea09e4c79a046d2783796dcb..754dd258928b46143503da9808a9381f752b0503 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
 #ifndef __PSPPIRE_VAR_SHEET_H__
 #define __PSPPIRE_VAR_SHEET_H__
 
+/* PsppireVarSheet is a PsppSheetView that displays the variables in a
+   dictionary, one variable per row.
 
-#include <glib.h>
-#include <glib-object.h>
-#include <gtk-contrib/psppire-sheet.h>
-#include "val-labs-dialog.h"
-#include "missing-val-dialog.h"
-#include "var-type-dialog.h"
+   PsppireDataSheet is usually a child of PsppireDataEditor in the widget
+   hierarchy.  Other widgets can also use it. */
+
+#include <gtk/gtk.h>
+#include "data/format.h"
+#include "ui/gui/pspp-sheet-view.h"
 
 
 G_BEGIN_DECLS
 
+#define PSPPIRE_TYPE_FMT_USE (psppire_fmt_use_get_type ())
+
+GType psppire_fmt_use_get_type (void) G_GNUC_CONST;
+\f
 #define PSPPIRE_VAR_SHEET_TYPE            (psppire_var_sheet_get_type ())
 #define PSPPIRE_VAR_SHEET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPPIRE_VAR_SHEET_TYPE, PsppireVarSheet))
 #define PSPPIRE_VAR_SHEET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PSPPIRE_VAR_SHEET_TYPE, PsppireVarSheetClass))
@@ -38,36 +44,62 @@ G_BEGIN_DECLS
 typedef struct _PsppireVarSheet       PsppireVarSheet;
 typedef struct _PsppireVarSheetClass  PsppireVarSheetClass;
 
+enum
+{
+    PSPPIRE_VAR_SHEET_BACKEND_CHANGED,
+    PSPPIRE_VAR_SHEET_VARIABLE_INSERTED,
+    PSPPIRE_VAR_SHEET_VARIABLE_DELETED,
+    PSPPIRE_VAR_SHEET_N_SIGNALS
+ };
+
 struct _PsppireVarSheet
 {
-  PsppireSheet parent;
+  PsppSheetView parent;
 
-  gboolean dispose_has_run;
   gboolean may_create_vars;
+  gboolean may_delete_vars;
+  enum fmt_use format_use;
 
-  struct val_labs_dialog *val_labs_dialog ;
-  struct missing_val_dialog *missing_val_dialog ;
-  struct var_type_dialog *var_type_dialog ;
-};
+  struct _PsppireDict *dict;
+  struct val_labs_dialog *val_labs_dialog;
+  struct missing_val_dialog *missing_val_dialog;
+  struct var_type_dialog *var_type_dialog;
 
+  gulong scroll_to_bottom_signal;
+  gulong dict_signals[PSPPIRE_VAR_SHEET_N_SIGNALS];
 
-struct _PsppireVarSheetClass
-{
-  PsppireSheetClass parent_class;
+  GtkBuilder *builder;
+
+  GtkWidget *container;
+  gulong on_switch_page_handler;
 
-  GtkListStore *alignment_list;
-  GtkListStore *measure_list;
+  GtkUIManager *uim;
 
-  void (*var_sheet)(PsppireVarSheet*);
+  gboolean dispose_has_run;
 };
 
+struct _PsppireVarSheetClass
+{
+  PsppSheetViewClass parent_class;
+};
 
 GType          psppire_var_sheet_get_type        (void);
 GtkWidget*     psppire_var_sheet_new             (void);
 
-G_END_DECLS
+struct _PsppireDict *psppire_var_sheet_get_dictionary (PsppireVarSheet *);
+void psppire_var_sheet_set_dictionary (PsppireVarSheet *,
+                                       struct _PsppireDict *);
+
+gboolean psppire_var_sheet_get_may_create_vars (PsppireVarSheet *);
+void psppire_var_sheet_set_may_create_vars (PsppireVarSheet *, gboolean);
 
+gboolean psppire_var_sheet_get_may_delete_vars (PsppireVarSheet *);
+void psppire_var_sheet_set_may_delete_vars (PsppireVarSheet *, gboolean);
 
+void psppire_var_sheet_goto_variable (PsppireVarSheet *, int dict_index);
 
+GtkUIManager *psppire_var_sheet_get_ui_manager (PsppireVarSheet *);
+
+G_END_DECLS
 
 #endif /* __PSPPIRE_VAR_SHEET_H__ */
diff --git a/src/ui/gui/psppire-var-store.c b/src/ui/gui/psppire-var-store.c
deleted file mode 100644 (file)
index bc348ef..0000000
+++ /dev/null
@@ -1,788 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006, 2009, 2010, 2011, 2012  Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-#include <string.h>
-#include <stdlib.h>
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-
-#include <libpspp/i18n.h>
-
-#include <gobject/gvaluecollector.h>
-
-#include <ui/gui/sheet/psppire-sheetmodel.h>
-
-#include "psppire-var-store.h"
-#include "helper.h"
-
-#include <data/dictionary.h>
-#include <data/variable.h>
-#include <data/format.h>
-#include <data/missing-values.h>
-
-#include "val-labs-dialog.h"
-#include "missing-val-dialog.h"
-#include <data/value-labels.h>
-
-#include "var-display.h"
-
-static void
-var_change_callback (GtkWidget *w, gint n, gpointer data)
-{
-  PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
-
-  psppire_sheet_model_range_changed (model,
-                                n, 0, n, PSPPIRE_VAR_STORE_n_COLS);
-}
-
-
-static void
-var_delete_callback (GtkWidget *w, const struct variable *var UNUSED,
-                     gint dict_idx, gint case_idx UNUSED, gpointer data)
-{
-  PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
-
-  psppire_sheet_model_rows_deleted (model, dict_idx, 1);
-}
-
-
-
-static void
-var_insert_callback (GtkWidget *w, glong row, gpointer data)
-{
-  PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
-
-  psppire_sheet_model_rows_inserted (model, row, 1);
-}
-
-static void
-refresh (PsppireDict  *d, gpointer data)
-{
-  PsppireVarStore *vs = data;
-
-  psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (vs), -1, -1, -1, -1);
-}
-
-enum
-  {
-    PROP_0,
-    PSPPIRE_VAR_STORE_FORMAT_TYPE,
-    PSPPIRE_VAR_STORE_DICT
-  };
-
-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 (PsppireSheetModelIface *iface);
-static void         psppire_var_store_finalize        (GObject           *object);
-static void         psppire_var_store_dispose        (GObject           *object);
-
-
-static gchar *psppire_var_store_get_string (const PsppireSheetModel *sheet_model, glong row, glong column);
-
-static gboolean  psppire_var_store_clear (PsppireSheetModel *model,  glong row, glong col);
-
-
-static gboolean psppire_var_store_set_string (PsppireSheetModel *model,
-                                         const gchar *text, glong row, glong column);
-
-static glong psppire_var_store_get_row_count (const PsppireSheetModel * model);
-static glong psppire_var_store_get_column_count (const PsppireSheetModel * model);
-
-static gchar *text_for_column (PsppireVarStore *vs, const struct variable *pv,
-                              gint c, GError **err);
-
-
-static GObjectClass *parent_class = NULL;
-
-GType
-psppire_var_store_format_type_get_type (void)
-{
-  static GType etype = 0;
-  if (etype == 0)
-    {
-      static const GEnumValue values[] =
-       {
-         { PSPPIRE_VAR_STORE_INPUT_FORMATS,
-            "PSPPIRE_VAR_STORE_INPUT_FORMATS",
-            "input" },
-         { PSPPIRE_VAR_STORE_OUTPUT_FORMATS,
-            "PSPPIRE_VAR_STORE_OUTPUT_FORMATS",
-            "output" },
-         { 0, NULL, NULL }
-       };
-
-      etype = g_enum_register_static
-       (g_intern_static_string ("PsppireVarStoreFormatType"), values);
-
-    }
-  return etype;
-}
-
-GType
-psppire_var_store_get_type (void)
-{
-  static GType var_store_type = 0;
-
-  if (!var_store_type)
-    {
-      static const GTypeInfo var_store_info =
-      {
-       sizeof (PsppireVarStoreClass),
-       NULL,           /* base_init */
-       NULL,           /* base_finalize */
-        (GClassInitFunc) psppire_var_store_class_init,
-       NULL,           /* class_finalize */
-       NULL,           /* class_data */
-        sizeof (PsppireVarStore),
-       0,
-        (GInstanceInitFunc) psppire_var_store_init,
-      };
-
-      static const GInterfaceInfo sheet_model_info =
-      {
-       (GInterfaceInitFunc) psppire_var_store_sheet_model_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,
-                                  PSPPIRE_TYPE_SHEET_MODEL,
-                                  &sheet_model_info);
-    }
-
-  return var_store_type;
-}
-
-static void
-psppire_var_store_set_property (GObject      *object,
-                                guint         property_id,
-                                const GValue *value,
-                                GParamSpec   *pspec)
-{
-  PsppireVarStore *self = (PsppireVarStore *) object;
-
-  switch (property_id)
-    {
-    case PSPPIRE_VAR_STORE_FORMAT_TYPE:
-      self->format_type = g_value_get_enum (value);
-      break;
-
-    case PSPPIRE_VAR_STORE_DICT:
-      if ( self->dictionary)
-       g_object_unref (self->dictionary);
-      self->dictionary = g_value_dup_object (value);
-      g_signal_connect (self->dictionary, "variable-changed", G_CALLBACK (var_change_callback),
-                       self);
-
-      g_signal_connect (self->dictionary, "variable-deleted", G_CALLBACK (var_delete_callback),
-                       self);
-
-      g_signal_connect (self->dictionary, "variable-inserted",
-                       G_CALLBACK (var_insert_callback), self);
-
-      g_signal_connect (self->dictionary, "backend-changed", G_CALLBACK (refresh),
-                       self);
-
-      /* The entire model has changed */
-      psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (self), -1, -1, -1, -1);
-
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
-      break;
-    }
-}
-
-static void
-psppire_var_store_get_property (GObject      *object,
-                        guint         property_id,
-                        GValue       *value,
-                        GParamSpec   *pspec)
-{
-  PsppireVarStore *self = (PsppireVarStore *) object;
-
-  switch (property_id)
-    {
-    case PSPPIRE_VAR_STORE_FORMAT_TYPE:
-      g_value_set_enum (value, self->format_type);
-      break;
-
-    case PSPPIRE_VAR_STORE_DICT:
-      g_value_take_object (value, self->dictionary);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-    }
-}
-
-
-static void
-psppire_var_store_class_init (PsppireVarStoreClass *class)
-{
-  GObjectClass *object_class;
-  GParamSpec *format_pspec;
-  GParamSpec *dict_pspec;
-
-  parent_class = g_type_class_peek_parent (class);
-  object_class = (GObjectClass*) class;
-
-  object_class->finalize = psppire_var_store_finalize;
-  object_class->dispose = psppire_var_store_dispose;
-  object_class->set_property = psppire_var_store_set_property;
-  object_class->get_property = psppire_var_store_get_property;
-
-  format_pspec = g_param_spec_enum ("format-type",
-                             "Variable format type",
-                             ("Whether variables have input or output "
-                              "formats"),
-                             PSPPIRE_TYPE_VAR_STORE_FORMAT_TYPE,
-                             PSPPIRE_VAR_STORE_OUTPUT_FORMATS,
-                             G_PARAM_READWRITE);
-
-  g_object_class_install_property (object_class,
-                                   PSPPIRE_VAR_STORE_FORMAT_TYPE,
-                                   format_pspec);
-
-  dict_pspec = g_param_spec_object ("dictionary",
-                                   "Dictionary",
-                                   "The PsppireDict represented by this var store",
-                                   PSPPIRE_TYPE_DICT,
-                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
-                                   
-  g_object_class_install_property (object_class,
-                                   PSPPIRE_VAR_STORE_DICT,
-                                   dict_pspec);
-}
-
-#define DISABLED_COLOR "gray"
-
-static void
-psppire_var_store_init (PsppireVarStore *var_store)
-{
-  if ( ! gdk_color_parse (DISABLED_COLOR, &var_store->disabled))
-       g_critical ("Could not parse color `%s'", DISABLED_COLOR);
-
-  var_store->dictionary = NULL;
-  var_store->format_type = PSPPIRE_VAR_STORE_OUTPUT_FORMATS;
-}
-
-static gboolean
-psppire_var_store_item_editable (PsppireVarStore *var_store, glong row, glong column)
-{
-  const struct fmt_spec *write_spec ;
-
-  struct variable *pv = psppire_var_store_get_var (var_store, row);
-
-  if ( !pv )
-    return TRUE;
-
-  if ( var_is_alpha (pv) && column == PSPPIRE_VAR_STORE_COL_DECIMALS )
-    return FALSE;
-
-  write_spec = var_get_print_format (pv);
-
-  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:
-      if ( column == PSPPIRE_VAR_STORE_COL_DECIMALS || column == PSPPIRE_VAR_STORE_COL_WIDTH)
-       return FALSE;
-      break;
-    default:
-      break;
-    }
-
-  return TRUE;
-}
-
-
-struct variable *
-psppire_var_store_get_var (PsppireVarStore *store, glong row)
-{
-  return psppire_dict_get_variable (store->dictionary, row);
-}
-
-static gboolean
-psppire_var_store_is_editable (const PsppireSheetModel *model, glong row, glong column)
-{
-  PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
-  return psppire_var_store_item_editable (store, row, column);
-}
-
-
-static GdkColor *
-psppire_var_store_get_foreground (const PsppireSheetModel *model, glong row, glong column)
-{
-  PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
-
-  if ( ! psppire_var_store_item_editable (store, row, column) )
-    return &store->disabled;
-
-  return NULL;
-}
-
-
-static gchar *get_column_title (const PsppireSheetModel *model, gint col);
-static gchar *get_row_title (const PsppireSheetModel *model, gint row);
-static gboolean get_row_sensitivity (const PsppireSheetModel *model, gint row);
-
-static void
-psppire_var_store_sheet_model_init (PsppireSheetModelIface *iface)
-{
-  iface->get_row_count = psppire_var_store_get_row_count;
-  iface->get_column_count = psppire_var_store_get_column_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;
-  iface->is_editable = psppire_var_store_is_editable;
-  iface->get_foreground = psppire_var_store_get_foreground;
-  iface->get_background = NULL;
-  iface->get_justification = NULL;
-
-  iface->get_column_title = get_column_title;
-
-  iface->get_row_title = get_row_title;
-  iface->get_row_sensitivity = get_row_sensitivity;
-
-  iface->get_row_overstrike = NULL;
-}
-
-/**
- * psppire_var_store_new:
- * @dict: The dictionary for this var_store.
- *
- *
- * Return value: a new #PsppireVarStore
- **/
-PsppireVarStore *
-psppire_var_store_new (PsppireDict *dict)
-{
-  PsppireVarStore *retval;
-
-  retval = g_object_new (GTK_TYPE_VAR_STORE, "dictionary", dict, NULL);
-
-  //  psppire_var_store_set_dictionary (retval, dict);
-
-  return retval;
-}
-
-#if 0
-/**
- * psppire_var_store_replace_set_dictionary:
- * @var_store: The variable store
- * @dict: The dictionary to set
- *
- * If a dictionary is already associated with the var-store, then it will be
- * destroyed.
- **/
-void
-psppire_var_store_set_dictionary (PsppireVarStore *var_store, PsppireDict *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),
-                  var_store);
-
-  g_signal_connect (dict, "variable-deleted", G_CALLBACK (var_delete_callback),
-                  var_store);
-
-  g_signal_connect (dict, "variable-inserted",
-                   G_CALLBACK (var_insert_callback), var_store);
-
-  g_signal_connect (dict, "backend-changed", G_CALLBACK (refresh),
-                   var_store);
-
-  /* The entire model has changed */
-  psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (var_store), -1, -1, -1, -1);
-}
-#endif
-
-static void
-psppire_var_store_finalize (GObject *object)
-{
-  /* must chain up */
-  (* parent_class->finalize) (object);
-}
-
-static void
-psppire_var_store_dispose (GObject *object)
-{
-  PsppireVarStore *self = PSPPIRE_VAR_STORE (object);
-
-  if (self->dictionary)
-    g_object_unref (self->dictionary);
-
-  /* must chain up */
-  (* parent_class->finalize) (object);
-}
-
-
-static gchar *
-psppire_var_store_get_string (const PsppireSheetModel *model,
-                             glong row, glong column)
-{
-  PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
-
-  struct variable *pv;
-
-  if ( row >= psppire_dict_get_var_cnt (store->dictionary))
-    return 0;
-
-  pv = psppire_dict_get_variable (store->dictionary, row);
-
-  return text_for_column (store, pv, column, 0);
-}
-
-
-/* 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 (PsppireSheetModel *model,  glong row, glong col)
-{
-  struct variable *pv ;
-
-  PsppireVarStore *var_store = PSPPIRE_VAR_STORE (model);
-
-  if ( row >= psppire_dict_get_var_cnt (var_store->dictionary))
-      return FALSE;
-
-  pv = psppire_var_store_get_var (var_store, row);
-
-  if ( !pv )
-    return FALSE;
-
-  switch (col)
-    {
-    case PSPPIRE_VAR_STORE_COL_LABEL:
-      var_clear_label (pv);
-      return TRUE;
-      break;
-    }
-
-  return FALSE;
-}
-
-/* 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 (PsppireSheetModel *model,
-                         const gchar *text, glong row, glong col)
-{
-  struct variable *pv ;
-
-  PsppireVarStore *var_store = PSPPIRE_VAR_STORE (model);
-
-  if ( row >= psppire_dict_get_var_cnt (var_store->dictionary))
-      return FALSE;
-
-  pv = psppire_var_store_get_var (var_store, row);
-
-  if ( !pv )
-    return FALSE;
-
-  switch (col)
-    {
-    case PSPPIRE_VAR_STORE_COL_NAME:
-      {
-       gboolean ok;
-       ok =  psppire_dict_rename_var (var_store->dictionary, pv, text);
-       return ok;
-      }
-    case PSPPIRE_VAR_STORE_COL_COLUMNS:
-      if ( ! text) return FALSE;
-      var_set_display_width (pv, atoi (text));
-      return TRUE;
-      break;
-    case PSPPIRE_VAR_STORE_COL_WIDTH:
-      {
-       const int width = atoi (text);
-       if ( ! text)
-         return FALSE;
-
-       if (width < 0)
-         return FALSE;
-
-       if ( var_is_alpha (pv))
-         {
-           if ( width > MAX_STRING )
-             return FALSE;
-           var_set_width (pv, width);
-         }
-       else
-         {
-            bool for_input
-              = var_store->format_type == PSPPIRE_VAR_STORE_INPUT_FORMATS;
-           struct fmt_spec fmt ;
-           fmt = *var_get_print_format (pv);
-           if ( width < fmt_min_width (fmt.type, for_input)
-                ||
-                width > fmt_max_width (fmt.type, for_input))
-             return FALSE;
-
-           fmt.w = width;
-           fmt.d = MIN (fmt_max_decimals (fmt.type, width, for_input), fmt.d);
-
-           var_set_both_formats (pv, &fmt);
-         }
-
-       return TRUE;
-      }
-      break;
-    case PSPPIRE_VAR_STORE_COL_DECIMALS:
-      {
-        bool for_input
-          = var_store->format_type == PSPPIRE_VAR_STORE_INPUT_FORMATS;
-       int decimals;
-       struct fmt_spec fmt;
-       if ( ! text) return FALSE;
-       decimals = atoi (text);
-       fmt = *var_get_print_format (pv);
-       if ( decimals >
-            fmt_max_decimals (fmt.type,
-                               fmt.w,
-                               for_input
-                               ))
-         return FALSE;
-
-       fmt.d = decimals;
-       var_set_both_formats (pv, &fmt);
-       return TRUE;
-      }
-      break;
-    case PSPPIRE_VAR_STORE_COL_LABEL:
-      {
-       var_set_label (pv, text, true);
-       return TRUE;
-      }
-      break;
-    case PSPPIRE_VAR_STORE_COL_TYPE:
-    case PSPPIRE_VAR_STORE_COL_VALUES:
-    case PSPPIRE_VAR_STORE_COL_MISSING:
-    case PSPPIRE_VAR_STORE_COL_ALIGN:
-    case PSPPIRE_VAR_STORE_COL_MEASURE:
-      /* These can be modified only by their respective dialog boxes */
-      return FALSE;
-      break;
-    default:
-      g_assert_not_reached ();
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-
-static const gchar none[] = N_("None");
-
-static  gchar *
-text_for_column (PsppireVarStore *vs,
-                const struct variable *pv, gint c, GError **err)
-{
-  PsppireDict *dict = vs->dictionary;
-
-  const struct fmt_spec *format = var_get_print_format (pv);
-
-  switch (c)
-    {
-    case PSPPIRE_VAR_STORE_COL_NAME:
-      return xstrdup (var_get_name (pv));
-      break;
-    case PSPPIRE_VAR_STORE_COL_TYPE:
-      return xstrdup (fmt_gui_name (format->type));
-      break;
-    case PSPPIRE_VAR_STORE_COL_WIDTH:
-      {
-       gchar *s;
-       GString *gstr = g_string_sized_new (10);
-       g_string_printf (gstr, _("%d"), format->w);
-       s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
-       g_string_free (gstr, TRUE);
-       return s;
-      }
-      break;
-    case PSPPIRE_VAR_STORE_COL_DECIMALS:
-      {
-       gchar *s;
-       GString *gstr = g_string_sized_new (10);
-       g_string_printf (gstr, _("%d"), format->d);
-       s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
-       g_string_free (gstr, TRUE);
-       return s;
-      }
-      break;
-    case PSPPIRE_VAR_STORE_COL_COLUMNS:
-      {
-       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 PSPPIRE_VAR_STORE_COL_LABEL:
-      {
-       const char *label = var_get_label (pv);
-       if (label)
-         return xstrdup (label);
-       return NULL;
-      }
-      break;
-
-    case PSPPIRE_VAR_STORE_COL_MISSING:
-      {
-       return missing_values_to_string (dict, pv, err);
-      }
-      break;
-    case PSPPIRE_VAR_STORE_COL_VALUES:
-      {
-       if ( ! var_has_value_labels (pv))
-         return xstrdup (gettext (none));
-       else
-         {
-           const struct val_labs *vls = var_get_value_labels (pv);
-            const struct val_lab **labels = val_labs_sorted (vls);
-           const struct val_lab *vl = labels[0];
-            free (labels);
-
-           g_assert (vl);
-
-           {
-             gchar *const vstr = value_to_text (vl->value, pv);
-
-             return g_strdup_printf (_("{%s,`%s'}_"), vstr,
-                                      val_lab_get_escaped_label (vl));
-           }
-         }
-      }
-      break;
-    case PSPPIRE_VAR_STORE_COL_ALIGN:
-      {
-       const gint align = var_get_alignment (pv);
-
-       g_assert (align < n_ALIGNMENTS);
-       return xstrdup (alignment_to_string (align));
-      }
-      break;
-    case PSPPIRE_VAR_STORE_COL_MEASURE:
-      {
-       return xstrdup (measure_to_string (var_get_measure (pv)));
-      }
-      break;
-    }
-  return 0;
-}
-
-
-
-/* Return the number of variables */
-gint
-psppire_var_store_get_var_cnt (PsppireVarStore  *store)
-{
-  return psppire_dict_get_var_cnt (store->dictionary);
-}
-
-
-static glong
-psppire_var_store_get_row_count (const PsppireSheetModel * model)
-{
-  gint rows = 0;
-  PsppireVarStore *vs = PSPPIRE_VAR_STORE (model);
-
-  if (vs->dictionary)
-    rows =  psppire_dict_get_var_cnt (vs->dictionary);
-
-  return rows ;
-}
-
-static glong
-psppire_var_store_get_column_count (const PsppireSheetModel * model)
-{
-  return PSPPIRE_VAR_STORE_n_COLS ;
-}
-
-\f
-
-/* Row related funcs */
-
-
-static gboolean
-get_row_sensitivity (const PsppireSheetModel *model, gint row)
-{
-  PsppireVarStore *vs = PSPPIRE_VAR_STORE (model);
-
-  if ( ! vs->dictionary)
-    return FALSE;
-
-  return  row < psppire_dict_get_var_cnt (vs->dictionary);
-}
-
-
-static gchar *
-get_row_title (const PsppireSheetModel *model, gint unit)
-{
-  return g_strdup_printf (_("%d"), unit + 1);
-}
-
-
-\f
-
-static const gchar *column_titles[] = {
-  N_("Name"),
-  N_("Type"),
-  N_("Width"),
-  N_("Decimals"),
-  N_("Label"),
-  N_("Values"),
-  N_("Missing"),
-  N_("Columns"),
-  N_("Align"),
-  N_("Measure"),
-};
-
-
-static gchar *
-get_column_title (const PsppireSheetModel *model, gint col)
-{
-  if ( col >= 10)
-    return NULL;
-  return g_strdup (gettext (column_titles[col]));
-}
diff --git a/src/ui/gui/psppire-var-store.h b/src/ui/gui/psppire-var-store.h
deleted file mode 100644 (file)
index e4c2ecd..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006  Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef __PSPPIRE_VAR_STORE_H__
-#define __PSPPIRE_VAR_STORE_H__
-
-#include "psppire-dict.h"
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-/* PSPPIRE variable store format type, to determine whether a
-   PSPPIRE variable store contains variable input formats or
-   variable output formats.  */
-GType psppire_var_store_format_type_get_type (void);
-
-typedef enum
-  {
-    PSPPIRE_VAR_STORE_INPUT_FORMATS,
-    PSPPIRE_VAR_STORE_OUTPUT_FORMATS
-  }
-PsppireVarStoreFormatType;
-
-#define PSPPIRE_TYPE_VAR_STORE_FORMAT_TYPE \
-        (psppire_var_store_format_type_get_type ())
-
-/* PSPPIRE variable store. */
-#define GTK_TYPE_VAR_STORE            (psppire_var_store_get_type ())
-
-#define PSPPIRE_VAR_STORE(obj)        (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
-                                                                   GTK_TYPE_VAR_STORE, PsppireVarStore))
-
-#define PSPPIRE_VAR_STORE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), \
-                                                                GTK_TYPE_VAR_STORE, \
-                                                                 PsppireVarStoreClass))
-
-#define PSPPIRE_IS_VAR_STORE(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_VAR_STORE))
-
-#define PSPPIRE_IS_VAR_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_VAR_STORE))
-
-#define PSPPIRE_VAR_STORE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
-                                                                  GTK_TYPE_VAR_STORE, \
-                                                                  PsppireVarStoreClass))
-
-typedef struct _PsppireVarStore       PsppireVarStore;
-typedef struct _PsppireVarStoreClass  PsppireVarStoreClass;
-
-struct _PsppireVarStore
-{
-  GObject parent;
-
-  /*< private >*/
-  PsppireDict *dictionary;
-  GdkColor disabled;
-  PsppireVarStoreFormatType format_type;
-};
-
-struct _PsppireVarStoreClass
-{
-  GObjectClass parent_class;
-
-  /* Padding for future expansion */
-  void (*_gtk_reserved1) (void);
-  void (*_gtk_reserved2) (void);
-  void (*_gtk_reserved3) (void);
-  void (*_gtk_reserved4) (void);
-};
-
-
-GType         psppire_var_store_get_type         (void) G_GNUC_CONST;
-PsppireVarStore *psppire_var_store_new              (PsppireDict *dict);
-struct variable * psppire_var_store_get_var (PsppireVarStore *store, glong row);
-
-/* Return the number of variables */
-gint psppire_var_store_get_var_cnt (PsppireVarStore      *var_store);
-
-void psppire_var_store_set_font (PsppireVarStore *store, const PangoFontDescription *fd);
-
-
-G_END_DECLS
-
-
-enum {
- PSPPIRE_VAR_STORE_COL_NAME,
- PSPPIRE_VAR_STORE_COL_TYPE,
- PSPPIRE_VAR_STORE_COL_WIDTH,
- PSPPIRE_VAR_STORE_COL_DECIMALS,
- PSPPIRE_VAR_STORE_COL_LABEL,
- PSPPIRE_VAR_STORE_COL_VALUES,
- PSPPIRE_VAR_STORE_COL_MISSING,
- PSPPIRE_VAR_STORE_COL_COLUMNS,
- PSPPIRE_VAR_STORE_COL_ALIGN,
- PSPPIRE_VAR_STORE_COL_MEASURE,
- PSPPIRE_VAR_STORE_n_COLS
-};
-
-#endif /* __PSPPIRE_VAR_STORE_H__ */
index be095248a940cdbb6b37befc651f88ec19158b22..36716f3a26b9a537d7ad3707965de7463c36e9be 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2005, 2006, 2009, 2010, 2011  Free Software Foundation
+   Copyright (C) 2004, 2005, 2006, 2009, 2010, 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -51,7 +51,6 @@
 #include "ui/gui/psppire-output-window.h"
 #include "ui/gui/psppire-syntax-window.h"
 #include "ui/gui/psppire-selector.h"
-#include "ui/gui/psppire-var-store.h"
 #include "ui/gui/psppire-var-view.h"
 #include "ui/gui/psppire-window-register.h"
 #include "ui/gui/widgets.h"
@@ -74,8 +73,6 @@ static gchar *local_to_filename_encoding (const char *fn);
 void
 initialize (const char *data_file)
 {
-  PsppireDataWindow *data_window;
-
   i18n_init ();
 
   preregister_widgets ();
@@ -100,8 +97,6 @@ initialize (const char *data_file)
   psppire_selector_set_default_selection_func (PSPPIRE_VAR_VIEW_TYPE, insert_source_row_into_tree_view);
   psppire_selector_set_default_selection_func (GTK_TYPE_TREE_VIEW, insert_source_row_into_tree_view);
 
-  data_window = psppire_default_data_window ();
-
   if (data_file)
     {
       gchar *filename = local_to_filename_encoding (data_file);
@@ -109,12 +104,17 @@ initialize (const char *data_file)
       /* Check to see if the file is a .sav or a .por file.  If not
          assume that it is a syntax file */
       if ( any_reader_may_open (filename))
-        psppire_window_load (PSPPIRE_WINDOW (data_window), filename);
+        open_data_window (NULL, filename);
       else
-        open_syntax_window (filename, NULL);
+        {
+          create_data_window ();
+          open_syntax_window (filename, NULL);
+        }
 
       g_free (filename);
     }
+  else
+    create_data_window ();
 }
 
 
index 012b2f26c1689b394edf039f85178d479a5ea100..eddb4f0d62072aac2c119b266df00dcd30184079 100644 (file)
@@ -37,7 +37,6 @@
 #include <ui/gui/builder-wrapper.h>
 #include "helper.h"
 #include <ui/gui/psppire-dialog.h>
-#include <ui/gui/psppire-var-store.h>
 
 #include "psppire-val-chooser.h"
 
@@ -611,9 +610,6 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
 
   GtkWidget *output_variable_box = get_widget_assert (builder,"frame4");
 
-  PsppireVarStore *vs = NULL;
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
   rd.change_button = get_widget_assert (builder, "change-button");
   rd.varmap = NULL;
   rd.dialog = get_widget_assert   (builder, "recode-dialog");
@@ -622,7 +618,7 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
   rd.new_name_entry = get_widget_assert (builder, "dest-name-entry");
   rd.new_label_entry = get_widget_assert (builder, "dest-label-entry");
 
-  g_object_get (vs, "dictionary", &rd.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &rd.dict, NULL);
 
   rd.value_map = gtk_list_store_new (2,
                                     old_value_get_type (),
index 6f877e827d9aeda97ed3680da5af88b7b9936e3f..7bc05f2422c711c2a3884aa340f791dc8d4dfc35 100644 (file)
@@ -122,8 +122,6 @@ runs_dialog (PsppireDataWindow *dw)
   struct runs fd;
   gint response;
 
-  PsppireVarStore *vs;
-
   GtkWidget *dialog ;
   GtkWidget *source ;
 
@@ -145,11 +143,9 @@ runs_dialog (PsppireDataWindow *dw)
 
   fd.variables = get_widget_assert   (fd.xml, "psppire-var-view1");
 
-  g_object_get (fd.de->data_editor, "var-store", &vs, NULL);
-
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fd.de));
 
-  g_object_get (vs, "dictionary", &fd.dict, NULL);
+  g_object_get (fd.de->data_editor, "dictionary", &fd.dict, NULL);
   g_object_set (source, "model", fd.dict,
                "predicate", var_is_numeric,
                NULL);
diff --git a/src/ui/gui/sheet/automake.mk b/src/ui/gui/sheet/automake.mk
deleted file mode 100644 (file)
index 1043a57..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-## Process this file with automake to produce Makefile.in  -*- makefile -*-
-
-if HAVE_GUI
-noinst_LTLIBRARIES += src/ui/gui/sheet/libsheet.la
-
-src_ui_gui_sheet_libsheet_la_CFLAGS = $(GTK_CFLAGS)
-
-src_ui_gui_sheet_libsheet_la_SOURCES = \
-       src/ui/gui/sheet/psppire-axis.c \
-       src/ui/gui/sheet/psppire-axis.h \
-       src/ui/gui/sheet/psppire-sheetmodel.c \
-       src/ui/gui/sheet/psppire-sheetmodel.h
-endif
diff --git a/src/ui/gui/sheet/psppire-axis.c b/src/ui/gui/sheet/psppire-axis.c
deleted file mode 100644 (file)
index 9cc879d..0000000
+++ /dev/null
@@ -1,634 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2010  Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <ui/gui/psppire-marshal.h>
-#include <libpspp/tower.h>
-#include <libpspp/pool.h>
-#include "psppire-axis.h"
-#include <math.h>
-#include <libpspp/misc.h>
-
-
-/* Signals */
-enum
-  {
-    RESIZE_UNIT,
-    n_signals
-  };
-
-static guint signals[n_signals] ;
-
-/* --- prototypes --- */
-static void psppire_axis_class_init (PsppireAxisClass  *class);
-static void psppire_axis_init  (PsppireAxis            *axis);
-static void psppire_axis_finalize   (GObject           *object);
-
-
-/* --- variables --- */
-static GObjectClass     *parent_class = NULL;
-
-
-struct axis_node
-{
-  struct tower_node pixel_node;
-  struct tower_node unit_node;
-};
-
-void
-psppire_axis_dump (const PsppireAxis *a)
-{
-  struct tower_node *n = tower_first (&a->unit_tower);
-
-  g_debug ("Axis %p", a);
-  while (n)
-    {
-      const struct axis_node *an = tower_data (n, struct axis_node, unit_node);
-      const struct tower_node *pn = &an->pixel_node;
-      g_debug ("%ld units of height %g",
-              n->size, pn->size / (gdouble) n->size);
-
-      n =  tower_next (&a->unit_tower, n);
-    }
-  g_debug ("\n");
-}
-
-/* Increment the size of every unit by INC.
-   Note that INC is signed. So if INC is negative,
-   then size will end up smaller.
-*/
-static void
-axis_increment (PsppireAxis *axis, gint inc)
-{
-  struct tower_node *n = tower_first (&axis->pixel_tower);
-
-  while (n)
-    {
-      struct axis_node *an = tower_data (n, struct axis_node, pixel_node);
-      struct tower_node *pn = &an->pixel_node;
-      const gint existing_size = tower_node_get_size (pn);
-
-      tower_resize (&axis->pixel_tower, pn, existing_size + inc *
-                   tower_node_get_size (&an->unit_node));
-
-      n = tower_next (&axis->pixel_tower, n);
-    }
-}
-
-
-/* Return the unit covered by PIXEL */
-gint
-psppire_axis_unit_at_pixel (const PsppireAxis *a, glong pixel)
-{
-  unsigned long int start;
-  struct tower_node *n;
-  struct axis_node *an;
-  gdouble fraction;
-
-  glong size = tower_height (&a->pixel_tower);
-
-  g_return_val_if_fail (pixel >= 0, -1);
-
-  if (pixel >= size)
-    {
-      gint n_items = tower_height (&a->unit_tower);
-      glong extra = pixel - size;
-
-      return n_items - 1 + DIV_RND_UP (extra,  a->default_size);
-    }
-
-
-  n = tower_lookup (&a->pixel_tower, pixel, &start);
-  an = tower_data (n, struct axis_node, pixel_node);
-
-  fraction = (pixel - start) / (gdouble) tower_node_get_size (&an->pixel_node);
-
-  return  tower_node_get_level (&an->unit_node)
-    + fraction * tower_node_get_size (&an->unit_node);
-}
-
-
-gint
-psppire_axis_unit_count (const PsppireAxis *a)
-{
-  glong filler = 0;
-  glong actual_size;
-
-  actual_size = tower_height (&a->pixel_tower);
-
-  if ( actual_size < a->min_extent )
-    filler = DIV_RND_UP (a->min_extent - actual_size, a->default_size);
-
-  return tower_height (&a->unit_tower) + filler;
-}
-
-
-/* Return the starting pixel of UNIT */
-glong
-psppire_axis_start_pixel (const PsppireAxis *a, gint unit)
-{
-  gdouble fraction;
-  struct tower_node *n ;
-  struct axis_node *an;
-
-  unsigned long int start;
-
-  gint the_count, size ;
-
-  the_count =  tower_height (&a->unit_tower);
-  size = tower_height (&a->pixel_tower);
-
-  if ( unit >= the_count)
-    {
-      return  size + (unit - the_count) * a->default_size;
-    }
-
-  if ( unit < 0)
-    return -1;
-
-  if ( unit >= tower_height (&a->unit_tower))
-    return -1;
-
-  n = tower_lookup (&a->unit_tower, unit, &start);
-
-  an = tower_data (n, struct axis_node, unit_node);
-
-  fraction = (unit - start) / (gdouble) tower_node_get_size (&an->unit_node);
-
-  return  tower_node_get_level (&an->pixel_node) +
-    rint (fraction * tower_node_get_size (&an->pixel_node));
-}
-
-gint
-psppire_axis_unit_size (const PsppireAxis *axis, gint unit)
-{
-  struct tower_node *n ;
-  struct axis_node *an;
-
-  unsigned long int start;
-
-  if  (unit >= tower_height (&axis->unit_tower))
-    return axis->default_size;
-
-  if ( unit < 0)
-    return 0;
-
-  if ( unit >= tower_height (&axis->unit_tower))
-    return 0;
-
-  n = tower_lookup (&axis->unit_tower, unit, &start);
-
-  an = tower_data (n, struct axis_node, unit_node);
-
-  return rint (tower_node_get_size (&an->pixel_node)
-               / (gdouble) tower_node_get_size (&an->unit_node));
-}
-
-
-
-/* --- functions --- */
-/**
- * psppire_axis_get_type:
- * @returns: the type ID for accelerator groups.
- */
-GType
-psppire_axis_get_type (void)
-{
-  static GType object_type = 0;
-
-  if (!object_type)
-    {
-      static const GTypeInfo object_info = {
-       sizeof (PsppireAxisClass),
-       (GBaseInitFunc) NULL,
-       (GBaseFinalizeFunc) NULL,
-       (GClassInitFunc) psppire_axis_class_init,
-       NULL,   /* class_finalize */
-       NULL,   /* class_data */
-       sizeof (PsppireAxis),
-       0,      /* n_preallocs */
-       (GInstanceInitFunc) psppire_axis_init,
-      };
-
-      object_type = g_type_register_static (G_TYPE_OBJECT,
-                                           "PsppireAxis",
-                                           &object_info, 0);
-
-    }
-
-  return object_type;
-}
-
-enum
-  {
-    PROP_0,
-    PROP_MIN_EXTENT,
-    PROP_DEFAULT_SIZE,
-    PROP_PADDING
-  };
-
-
-static void
-psppire_axis_get_property (GObject         *object,
-                          guint            prop_id,
-                          GValue          *value,
-                          GParamSpec      *pspec)
-{
-  PsppireAxis *axis = PSPPIRE_AXIS (object);
-
-  switch (prop_id)
-    {
-    case PROP_PADDING:
-      g_value_set_int (value, axis->padding);
-      break;
-    case PROP_MIN_EXTENT:
-      g_value_set_long (value, axis->min_extent);
-      break;
-    case PROP_DEFAULT_SIZE:
-      g_value_set_int (value, axis->default_size);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    };
-}
-
-
-static void
-psppire_axis_set_property (GObject         *object,
-                          guint            prop_id,
-                          const GValue    *value,
-                          GParamSpec      *pspec)
-{
-  PsppireAxis *axis = PSPPIRE_AXIS (object);
-
-  switch (prop_id)
-    {
-    case PROP_PADDING:
-      {
-       const gint old_value = axis->padding;
-       axis->padding = g_value_get_int (value);
-       axis_increment (axis, axis->padding - old_value);
-      }
-      break;
-    case PROP_MIN_EXTENT:
-      axis->min_extent = g_value_get_long (value);
-      break;
-    case PROP_DEFAULT_SIZE:
-      axis->default_size = g_value_get_int (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    };
-}
-
-
-static void
-psppire_axis_class_init (PsppireAxisClass *class)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (class);
-
-  GParamSpec *padding_spec;
-  GParamSpec *min_extent_spec;
-  GParamSpec *default_size_spec;
-
-  parent_class = g_type_class_peek_parent (class);
-
-  object_class->set_property = psppire_axis_set_property;
-  object_class->get_property = psppire_axis_get_property;
-
-
-  min_extent_spec =
-    g_param_spec_long ("minimum-extent",
-                      "Minimum Extent",
-                      "The smallest extent to which the axis will provide units (typically set to the height/width of the associated widget).",
-                      0, G_MAXLONG,
-                      0,
-                      G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
-
-  g_object_class_install_property (object_class,
-                                   PROP_MIN_EXTENT,
-                                   min_extent_spec);
-
-
-  default_size_spec =
-    g_param_spec_int ("default-size",
-                     "Default Size",
-                     "The size given to units which haven't been explicity inserted",
-                     0, G_MAXINT,
-                     25,
-                     G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
-
-
-  g_object_class_install_property (object_class,
-                                   PROP_DEFAULT_SIZE,
-                                   default_size_spec);
-
-  padding_spec =
-    g_param_spec_int ("padding",
-                     "Padding",
-                     "Extra space implicitly added to each unit",
-                     0, G_MAXINT,
-                     0,
-                     G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE );
-
-
-  g_object_class_install_property (object_class,
-                                   PROP_PADDING,
-                                   padding_spec);
-
-
-
-  signals[RESIZE_UNIT] =
-    g_signal_new ("resize-unit",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 0,
-                 NULL, NULL,
-                 psppire_marshal_VOID__INT_LONG,
-                 G_TYPE_NONE,
-                 2,
-                 G_TYPE_INT,
-                 G_TYPE_LONG
-                 );
-
-
-  object_class->finalize = psppire_axis_finalize;
-}
-
-
-static void
-psppire_axis_init (PsppireAxis *axis)
-{
-  tower_init (&axis->pixel_tower);
-  tower_init (&axis->unit_tower);
-
-  axis->pool = pool_create ();
-  axis->padding = 0;
-}
-
-
-static void
-psppire_axis_finalize (GObject *object)
-{
-  PsppireAxis *a = PSPPIRE_AXIS (object);
-  pool_destroy (a->pool);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-/**
- * psppire_axis_new:
- * @returns: a new #PsppireAxis object
- *
- * Creates a new #PsppireAxis.
- */
-PsppireAxis*
-psppire_axis_new (void)
-{
-  return g_object_new (G_TYPE_PSPPIRE_AXIS, NULL);
-}
-
-
-\f
-
-void
-psppire_axis_append (PsppireAxis *a, gint size)
-{
-  psppire_axis_append_n (a, 1, size);
-}
-
-
-/* Append N_UNITS of size SIZE to A.
-   The value of the "padding" property will be added to SIZE
-   unit before appending.
-*/
-void
-psppire_axis_append_n (PsppireAxis *a, gint n_units, gint size)
-{
-  struct axis_node *node;
-
-  if  (n_units == 0)
-    return;
-
-  node = pool_malloc (a->pool, sizeof *node);
-
-  tower_insert (&a->unit_tower, n_units, &node->unit_node, NULL);
-  tower_insert (&a->pixel_tower, (size + a->padding) * n_units,
-    &node->pixel_node, NULL);
-}
-
-
-/* Split the node of both towers at POSN */
-static void
-split (PsppireAxis *a, gint posn)
-{
-  unsigned long int existing_unit_size;
-  unsigned long int existing_pixel_size;
-  unsigned long int start;
-  gdouble fraction;
-  struct axis_node *new_node ;
-  struct tower_node *n;
-  struct axis_node *existing_node;
-
-  g_return_if_fail (posn <= tower_height (&a->unit_tower));
-
-  /* Nothing needs to be done */
-  if ( posn == 0 || posn  == tower_height (&a->unit_tower))
-    return;
-
-  n = tower_lookup (&a->unit_tower, posn, &start);
-
-  existing_node = tower_data (n, struct axis_node, unit_node);
-
-  /* Nothing needs to be done, if the range element is already split here */
-  if ( posn - start == 0)
-    return;
-
-  existing_unit_size = tower_node_get_size (&existing_node->unit_node);
-  existing_pixel_size = tower_node_get_size (&existing_node->pixel_node);
-
-  fraction = (posn - start) / (gdouble) existing_unit_size;
-
-  new_node = pool_malloc (a->pool, sizeof (*new_node));
-
-  tower_resize (&a->unit_tower, &existing_node->unit_node, posn - start);
-
-  tower_resize (&a->pixel_tower, &existing_node->pixel_node,
-               rintf (fraction * existing_pixel_size));
-
-  tower_insert (&a->unit_tower,
-               existing_unit_size - (posn - start),
-               &new_node->unit_node,
-               tower_next (&a->unit_tower, &existing_node->unit_node));
-
-
-  tower_insert (&a->pixel_tower,
-               rintf (existing_pixel_size * (1 - fraction)),
-               &new_node->pixel_node,
-               tower_next (&a->pixel_tower, &existing_node->pixel_node));
-}
-
-
-/* Insert a new unit of size SIZE before POSN.
-   The value of the "padding" property will be added to SIZE before
-   the unit is inserted.
- */
-void
-psppire_axis_insert (PsppireAxis *a, gint posn, gint size)
-{
-  struct axis_node *before = NULL;
-  struct axis_node *new_node;
-
-  g_return_if_fail ( posn >= 0);
-  g_return_if_fail ( posn <= tower_height (&a->unit_tower));
-
-  if ( posn < tower_height (&a->unit_tower))
-    {
-      unsigned long int start = 0;
-      struct tower_node *n;
-
-      split (a, posn);
-
-      n = tower_lookup (&a->unit_tower, posn, &start);
-      g_assert (posn == start);
-
-      before = tower_data (n, struct axis_node, unit_node);
-    }
-
-  new_node = pool_malloc (a->pool, sizeof (*new_node));
-
-  tower_insert (&a->unit_tower,
-               1,
-               &new_node->unit_node,
-               before ? &before->unit_node : NULL);
-
-  tower_insert (&a->pixel_tower,
-               size + a->padding,
-               &new_node->pixel_node,
-               before ? &before->pixel_node : NULL);
-}
-
-
-/* Make the element at POSN singular.
-   Return a pointer to the node for this element */
-static struct axis_node *
-make_single (PsppireAxis *a, gint posn)
-{
-  unsigned long int start;
-  struct tower_node *n;
-
-  g_return_val_if_fail (posn < tower_height (&a->unit_tower), NULL);
-
-  n = tower_lookup (&a->unit_tower, posn, &start);
-
-  if ( 1 != tower_node_get_size (n))
-    {
-      split (a, posn + 1);
-      n = tower_lookup (&a->unit_tower, posn, &start);
-
-      if ( 1 != tower_node_get_size (n))
-       {
-         split (a, posn);
-         n = tower_lookup (&a->unit_tower, posn, &start);
-       }
-    }
-
-  g_assert (1 == tower_node_get_size (n));
-
-  return tower_data (n, struct axis_node, unit_node);
-}
-
-
-/*
-  Set the size of the unit at POSN to be SIZE plus the
-  current value of "padding"
- */
-void
-psppire_axis_resize (PsppireAxis *axis, gint posn, glong size)
-{
-  struct axis_node *an;
-  g_return_if_fail (posn >= 0);
-  g_return_if_fail (size > 0);
-
-  /* Silently ignore this request if the position is greater than the number of
-     units in the axis */
-  if (posn >= tower_height (&axis->unit_tower))
-    return ;
-
-  an = make_single (axis, posn);
-
-  tower_resize (&axis->pixel_tower, &an->pixel_node, size + axis->padding);
-
-  g_signal_emit (axis, signals[RESIZE_UNIT], 0, posn, size + axis->padding);
-}
-
-
-
-
-
-
-void
-psppire_axis_clear (PsppireAxis *a)
-{
-  pool_destroy (a->pool);
-  a->pool = pool_create ();
-
-  tower_init (&a->pixel_tower);
-  tower_init (&a->unit_tower);
-}
-
-
-
-void
-psppire_axis_delete (PsppireAxis *a, gint first, gint n_units)
-{
-  gint units_to_delete = n_units;
-  unsigned long int start;
-  struct tower_node *unit_node ;
-  g_return_if_fail (first + n_units <= tower_height (&a->unit_tower));
-
-  split (a, first);
-  split (a, first + n_units);
-
-  unit_node = tower_lookup (&a->unit_tower, first, &start);
-  g_assert (start == first);
-
-  while (units_to_delete > 0)
-    {
-      struct tower_node *next_unit_node;
-      struct axis_node *an = tower_data (unit_node,
-                                        struct axis_node, unit_node);
-
-      g_assert (unit_node == &an->unit_node);
-      g_assert (unit_node->size <= n_units);
-
-      units_to_delete -= unit_node->size;
-
-      next_unit_node = tower_next (&a->unit_tower, unit_node);
-
-      tower_delete (&a->unit_tower, unit_node);
-      tower_delete (&a->pixel_tower, &an->pixel_node);
-
-      pool_free (a->pool, an);
-
-      unit_node = next_unit_node;
-    }
-}
diff --git a/src/ui/gui/sheet/psppire-axis.h b/src/ui/gui/sheet/psppire-axis.h
deleted file mode 100644 (file)
index 50a6a39..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009  Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-
-#ifndef PSPPIRE_AXIS_H__
-#define PSPPIRE_AXIS_H__
-
-
-#include <glib-object.h>
-#include <glib.h>
-#include <libpspp/tower.h>
-
-G_BEGIN_DECLS
-
-
-/* --- type macros --- */
-#define G_TYPE_PSPPIRE_AXIS              (psppire_axis_get_type ())
-#define PSPPIRE_AXIS(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_PSPPIRE_AXIS, PsppireAxis))
-#define PSPPIRE_AXIS_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_PSPPIRE_AXIS, PsppireAxisClass))
-#define PSPPIRE_IS_AXIS(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), G_TYPE_PSPPIRE_AXIS))
-#define PSPPIRE_IS_AXIS_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_PSPPIRE_AXIS))
-#define PSPPIRE_AXIS_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_PSPPIRE_AXIS, PsppireAxisClass))
-
-
-
-/* --- typedefs & structures --- */
-typedef struct _PsppireAxis       PsppireAxis;
-typedef struct _PsppireAxisClass PsppireAxisClass;
-
-struct pool;
-
-struct _PsppireAxis
-{
-  GObject  parent;
-
-  struct tower pixel_tower;
-  struct tower unit_tower;
-
-  struct pool *pool;
-
-  glong min_extent;
-  gint default_size;
-  gint padding;
-};
-
-struct _PsppireAxisClass
-{
-  GObjectClass parent_class;
-};
-
-GType          psppire_axis_get_type (void);
-
-PsppireAxis*   psppire_axis_new (void);
-
-\f
-/* Interface between axis and model */
-
-void psppire_axis_insert (PsppireAxis *a, gint posn, gint size);
-
-void psppire_axis_append (PsppireAxis *a, gint size);
-
-void psppire_axis_append_n (PsppireAxis *a, gint n_units, gint size);
-
-void psppire_axis_resize (PsppireAxis *a, gint posn, glong size);
-
-void psppire_axis_clear (PsppireAxis *);
-
-void psppire_axis_delete (PsppireAxis *, gint first, gint n_cases);
-
-\f
-
-gint  psppire_axis_unit_count (const PsppireAxis *);
-glong psppire_axis_start_pixel (const PsppireAxis *a, gint unit);
-gint  psppire_axis_unit_size (const PsppireAxis *a, gint unit);
-gint  psppire_axis_unit_at_pixel (const PsppireAxis *a, glong pixel);
-
-G_END_DECLS
-
-#endif /* PSPPIRE_AXIS_H__ */
diff --git a/src/ui/gui/sheet/psppire-sheetmodel.c b/src/ui/gui/sheet/psppire-sheetmodel.c
deleted file mode 100644 (file)
index a948d45..0000000
+++ /dev/null
@@ -1,548 +0,0 @@
-/* PsppireSheetModel --- an abstract model for the PsppireSheet widget.
-   Copyright (C) 2006, 2008 Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include <glib.h>
-#include "psppire-sheetmodel.h"
-#include <ui/gui/psppire-marshal.h>
-
-enum {
-  RANGE_CHANGED,
-  ROWS_INSERTED,
-  ROWS_DELETED,
-  COLUMNS_INSERTED,
-  COLUMNS_DELETED,
-  LAST_SIGNAL
-};
-
-static guint sheet_model_signals[LAST_SIGNAL] = { 0 };
-
-
-static void      psppire_sheet_model_base_init   (gpointer           g_class);
-
-
-GType
-psppire_sheet_model_get_type (void)
-{
-  static GType sheet_model_type = 0;
-
-  if (! sheet_model_type)
-    {
-      static const GTypeInfo sheet_model_info =
-      {
-        sizeof (PsppireSheetModelIface), /* class_size */
-       psppire_sheet_model_base_init,   /* base_init */
-       NULL,           /* base_finalize */
-       NULL,
-       NULL,           /* class_finalize */
-       NULL,           /* class_data */
-       0,
-       0,              /* n_preallocs */
-       NULL
-      };
-
-      sheet_model_type =
-       g_type_register_static (G_TYPE_INTERFACE, "PsppireSheetModel",
-                               &sheet_model_info, 0);
-
-      g_type_interface_add_prerequisite (sheet_model_type, G_TYPE_OBJECT);
-    }
-
-  return sheet_model_type;
-}
-
-static void
-psppire_sheet_model_base_init (gpointer g_class)
-{
-  static gboolean initialized = FALSE;
-
-  if (! initialized)
-    {
-      sheet_model_signals[RANGE_CHANGED] =
-       g_signal_new ("range_changed",
-                     PSPPIRE_TYPE_SHEET_MODEL,
-                     G_SIGNAL_RUN_LAST,
-                     G_STRUCT_OFFSET (PsppireSheetModelIface, range_changed),
-                     NULL, NULL,
-                     psppire_marshal_VOID__INT_INT_INT_INT,
-                     G_TYPE_NONE, 4,
-                     G_TYPE_INT,
-                     G_TYPE_INT,
-                     G_TYPE_INT,
-                     G_TYPE_INT);
-
-
-
-      sheet_model_signals[ROWS_INSERTED] =
-       g_signal_new ("rows_inserted",
-                     PSPPIRE_TYPE_SHEET_MODEL,
-                     G_SIGNAL_RUN_LAST,
-                     G_STRUCT_OFFSET (PsppireSheetModelIface, rows_inserted),
-                     NULL, NULL,
-                     psppire_marshal_VOID__INT_INT,
-                     G_TYPE_NONE, 2,
-                     G_TYPE_INT,
-                     G_TYPE_INT);
-
-
-      sheet_model_signals[ROWS_DELETED] =
-       g_signal_new ("rows_deleted",
-                     PSPPIRE_TYPE_SHEET_MODEL,
-                     G_SIGNAL_RUN_LAST,
-                     G_STRUCT_OFFSET (PsppireSheetModelIface, rows_deleted),
-                     NULL, NULL,
-                     psppire_marshal_VOID__INT_INT,
-                     G_TYPE_NONE, 2,
-                     G_TYPE_INT,
-                     G_TYPE_INT);
-
-      sheet_model_signals[COLUMNS_INSERTED] =
-       g_signal_new ("columns_inserted",
-                     PSPPIRE_TYPE_SHEET_MODEL,
-                     G_SIGNAL_RUN_LAST,
-                     G_STRUCT_OFFSET (PsppireSheetModelIface, columns_inserted),
-                     NULL, NULL,
-                     psppire_marshal_VOID__INT_INT,
-                     G_TYPE_NONE, 2,
-                     G_TYPE_INT,
-                     G_TYPE_INT);
-
-
-      sheet_model_signals[COLUMNS_DELETED] =
-       g_signal_new ("columns_deleted",
-                     PSPPIRE_TYPE_SHEET_MODEL,
-                     G_SIGNAL_RUN_LAST,
-                     G_STRUCT_OFFSET (PsppireSheetModelIface, columns_deleted),
-                     NULL, NULL,
-                     psppire_marshal_VOID__INT_INT,
-                     G_TYPE_NONE, 2,
-                     G_TYPE_INT,
-                     G_TYPE_INT);
-
-
-      initialized = TRUE;
-    }
-}
-
-
-/**
- * psppire_sheet_model_free_strings
- * @sheet_model: A #PsppireSheetModel
- *
- * Returns: True if strings obtained with get_string should be freed by the
- * sheet when no longer required.
- **/
-gboolean
-psppire_sheet_model_free_strings (const PsppireSheetModel *sheet_model)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (sheet_model), FALSE);
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (sheet_model)->free_strings;
-}
-
-
-/**
- * psppire_sheet_model_get_string:
- * @sheet_model: A #PsppireSheetModel
- * @row: The row of the cell to be retrieved.
- * @column: The column of the cell to be retrieved.
- *
- * Retrieves the datum at location ROW, COLUMN in the form of a string.
- * Returns: The string representation of the datum, or NULL on error.
- **/
-gchar *
-psppire_sheet_model_get_string (const PsppireSheetModel *sheet_model,
-                         glong row, glong column)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (sheet_model), 0);
-
-  g_assert (PSPPIRE_SHEET_MODEL_GET_IFACE (sheet_model)->get_string);
-
-  return (PSPPIRE_SHEET_MODEL_GET_IFACE (sheet_model)->get_string) (sheet_model, row, column);
-}
-
-/**
- * psppire_sheet_model_set_string
- * @sheet_model: A #PsppireSheetModel
- * @text: The text describing the datum to be set.
- * @row: The row of the cell to be cleared.
- * @column: The column of the cell to be cleared.
- *
- * Sets the datum at a location from a string.
- * Returns: TRUE if the datum was changed, FALSE otherwise.
- **/
-gboolean
-psppire_sheet_model_set_string      (PsppireSheetModel *sheet_model,
-                                const gchar *text,
-                                glong row, glong column)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (sheet_model), FALSE);
-
-  g_assert (PSPPIRE_SHEET_MODEL_GET_IFACE (sheet_model)->set_string);
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (sheet_model)->set_string (sheet_model,
-                                                           text, row, column);
-}
-
-
-
-/**
- * psppire_sheet_model_datum_clear:
- * @sheet_model: A #PsppireSheetModel
- * @row: The row of the cell to be cleared.
- * @column: The column of the cell to be cleared.
- *
- * Called when the datum at a location is to be cleared.
- * Returns: TRUE if the datum was cleared, FALSE otherwise.
- **/
-gboolean
-psppire_sheet_model_datum_clear    (PsppireSheetModel *sheet_model,
-                               glong row, glong column)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (sheet_model), FALSE);
-
-  g_assert (PSPPIRE_SHEET_MODEL_GET_IFACE (sheet_model)->clear_datum);
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (sheet_model)->clear_datum (sheet_model,
-                                                               row, column);
-}
-
-
-/**
- * psppire_sheet_model_range_changed:
- * @sheet_model: A #PsppireSheetModel
- * @range: The #PsppireSheetRange range of cells which have changed.
- *
- * Emits the "range_changed" signal on @sheet_model.
- **/
-void
-psppire_sheet_model_range_changed (PsppireSheetModel *sheet_model,
-                              glong row0, glong col0,
-                              glong rowi, glong coli)
-{
-  g_return_if_fail (PSPPIRE_IS_SHEET_MODEL (sheet_model));
-
-  g_signal_emit (sheet_model, sheet_model_signals[RANGE_CHANGED], 0,
-                row0, col0, rowi, coli);
-}
-
-
-
-
-/**
- * psppire_sheet_model_rows_inserted:
- * @sheet_model: A #PsppireSheetModel
- * @row: The row before which the new rows should be inserted.
- * @n_rows: The number of rows to insert.
- *
- * Emits the "rows_inserted" signal on @sheet_model.
- **/
-void
-psppire_sheet_model_rows_inserted (PsppireSheetModel *sheet_model,
-                              glong row, glong n_rows)
-{
-  g_return_if_fail (PSPPIRE_IS_SHEET_MODEL (sheet_model));
-
-  g_signal_emit (sheet_model, sheet_model_signals[ROWS_INSERTED], 0,
-                row, n_rows);
-}
-
-
-/**
- * psppire_sheet_model_columns_inserted:
- * @sheet_model: A #PsppireSheetModel
- * @column: The column before which the new columns should be inserted.
- * @n_columns: The number of columns to insert.
- *
- * Emits the "columns_inserted" signal on @sheet_model.
- **/
-void
-psppire_sheet_model_columns_inserted (PsppireSheetModel *sheet_model,
-                              glong column, glong n_columns)
-{
-  g_return_if_fail (PSPPIRE_IS_SHEET_MODEL (sheet_model));
-
-  g_signal_emit (sheet_model, sheet_model_signals[COLUMNS_INSERTED], 0,
-                column, n_columns);
-}
-
-
-
-
-/**
- * psppire_sheet_model_rows_deleted:
- * @sheet_model: A #PsppireSheetModel
- * @row: The first row to be deleted.
- * @n_rows: The number of rows to delete.
- *
- * Emits the "rows_deleted" signal on @sheet_model.
- **/
-void
-psppire_sheet_model_rows_deleted (PsppireSheetModel *sheet_model,
-                              glong row, glong n_rows)
-{
-  g_return_if_fail (PSPPIRE_IS_SHEET_MODEL (sheet_model));
-
-  g_signal_emit (sheet_model, sheet_model_signals[ROWS_DELETED], 0,
-                row, n_rows);
-}
-
-
-
-/**
- * psppire_sheet_model_columns_deleted:
- * @sheet_model: A #PsppireSheetModel
- * @column: The first column to be deleted.
- * @n_columns: The number of columns to delete.
- *
- * Emits the "columns_deleted" signal on @sheet_model.
- **/
-void
-psppire_sheet_model_columns_deleted (PsppireSheetModel *sheet_model,
-                              glong column, glong n_columns)
-{
-  g_return_if_fail (PSPPIRE_IS_SHEET_MODEL (sheet_model));
-
-  g_signal_emit (sheet_model, sheet_model_signals[COLUMNS_DELETED], 0,
-                column, n_columns);
-}
-
-
-
-
-
-/**
- * psppire_sheet_model_is_editable:
- * @sheet_model: A #PsppireSheetModel
- * @row: The row
- * @column: The column
- *
- * Returns: TRUE if the cell is editable, FALSE otherwise
- **/
-gboolean
-psppire_sheet_model_is_editable (const PsppireSheetModel *model,
-                            glong row, glong column)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), TRUE);
-
-  if ( ! PSPPIRE_SHEET_MODEL_GET_IFACE (model)->is_editable )
-    return TRUE;
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->is_editable (model,
-                                                         row, column);
-}
-
-
-/**
- * psppire_sheet_model_get_foreground:
- * @sheet_model: A #PsppireSheetModel
- * @row: The row
- * @column: The column
- *
- * Returns the foreground colour of the cell at @row, @column
- * The color is unallocated.  It will be allocated by the viewing object.
- **/
-GdkColor *
-psppire_sheet_model_get_foreground (const PsppireSheetModel *model,
-                               glong row, glong column)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), NULL);
-
-  if ( ! PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_foreground )
-    return NULL;
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_foreground (model,
-                                                           row, column);
-}
-
-/**
- * psppire_sheet_model_get_background:
- * @sheet_model: A #PsppireSheetModel
- * @row: The row
- * @column: The column
- *
- * Returns the background colour of the cell at @row, @column
- * The color is unallocated.  It will be allocated by the viewing object.
- **/
-GdkColor *
-psppire_sheet_model_get_background (const PsppireSheetModel *model,
-                               glong row, glong column)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), NULL);
-
-  if ( ! PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_background )
-    return NULL;
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_background (model,
-                                                           row, column);
-}
-
-/**
- * psppire_sheet_model_get_justification:
- * @sheet_model: A #PsppireSheetModel
- * @row: The row
- * @column: The column
- *
- * Returns the justification of the cell at @row, @column
- * Returns: the justification, or NULL on error.
- **/
-const GtkJustification *
-psppire_sheet_model_get_justification (const PsppireSheetModel *model,
-                                  glong row, glong column)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), NULL);
-
-  if ( ! PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_justification)
-    return NULL;
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_justification (model,
-                                                              row, column);
-}
-
-
-/**
- * psppire_sheet_model_get_column_count:
- * @model: A #PsppireSheetModel
- *
- * Returns the total number of columns represented by the model
- **/
-glong
-psppire_sheet_model_get_column_count (const PsppireSheetModel *model)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), -1);
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_column_count (model);
-}
-
-/**
- * psppire_sheet_model_get_row_count:
- * @model: A #PsppireSheetModel
- *
- * Returns the total number of rows represented by the model
- **/
-gint
-psppire_sheet_model_get_row_count(const PsppireSheetModel *model)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), -1);
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_row_count (model);
-}
-
-\f
-
-/* Column related functions  */
-gboolean
-psppire_sheet_model_get_column_sensitivity (const PsppireSheetModel *model, gint col)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), FALSE);
-
-  if ( NULL == PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_column_sensitivity)
-    return TRUE;
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_column_sensitivity (model, col);
-}
-
-
-gchar *
-psppire_sheet_model_get_column_subtitle (const PsppireSheetModel *model,
-                                  gint col)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), NULL);
-  g_return_val_if_fail (col >= 0, NULL);
-
-  if ( NULL == PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_column_subtitle)
-    return NULL;
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_column_subtitle (model, col);
-}
-
-
-PsppireSheetButton *
-psppire_sheet_model_get_column_button (const PsppireSheetModel *model,
-                                gint col)
-{
-  PsppireSheetButton *button = psppire_sheet_button_new ();
-
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), NULL);
-
-  if ( PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_column_title)
-    button->label = PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_column_title (model, col);
-
-  button->overstruck = FALSE;
-
-  return button;
-}
-
-GtkJustification
-psppire_sheet_model_get_column_justification (const PsppireSheetModel *model,
-                                       gint col)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), GTK_JUSTIFY_LEFT);
-
-  if ( PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_column_justification)
-    return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_column_justification (model, col);
-
-  return GTK_JUSTIFY_LEFT;
-}
-
-\f
-
-gboolean
-psppire_sheet_model_get_row_sensitivity (const PsppireSheetModel *model, gint row)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), FALSE);
-
-  if ( NULL == PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_row_sensitivity)
-    return TRUE;
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_row_sensitivity (model, row);
-}
-
-
-
-gchar *
-psppire_sheet_model_get_row_subtitle (const PsppireSheetModel *model,
-                               gint row)
-{
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), NULL);
-
-  if ( NULL == PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_row_subtitle)
-    return NULL;
-
-  return PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_row_subtitle (model, row);
-}
-
-
-PsppireSheetButton *
-psppire_sheet_model_get_row_button (const PsppireSheetModel *model,
-                                gint row)
-{
-  PsppireSheetButton *button = psppire_sheet_button_new ();
-
-  g_return_val_if_fail (PSPPIRE_IS_SHEET_MODEL (model), NULL);
-
-  if ( PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_row_title)
-    button->label =
-      PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_row_title (model, row);
-
-  if ( PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_row_overstrike)
-    button->overstruck =
-      PSPPIRE_SHEET_MODEL_GET_IFACE (model)->get_row_overstrike (model, row);
-
-  return button;
-}
-
diff --git a/src/ui/gui/sheet/psppire-sheetmodel.h b/src/ui/gui/sheet/psppire-sheetmodel.h
deleted file mode 100644 (file)
index c851907..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/* PsppireSheetModel --- an abstract model for the PsppireSheet widget.
- * Copyright (C) 2006, 2008 Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef __PSPPIRE_SHEET_MODEL_H__
-#define __PSPPIRE_SHEET_MODEL_H__
-
-
-/* This file provides an abstract interface or the data displayed by the
-   PsppireSheet widget */
-
-#include <glib-object.h>
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-#include <gtk-contrib/gtkextra-sheet.h>
-
-G_BEGIN_DECLS
-
-#define PSPPIRE_TYPE_SHEET_MODEL            (psppire_sheet_model_get_type ())
-#define PSPPIRE_SHEET_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPPIRE_TYPE_SHEET_MODEL, PsppireSheetModel))
-#define PSPPIRE_IS_SHEET_MODEL(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_SHEET_MODEL))
-#define PSPPIRE_SHEET_MODEL_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PSPPIRE_TYPE_SHEET_MODEL, PsppireSheetModelIface))
-
-typedef enum
-{
-  PSPPIRE_SHEET_LEFT_BORDER     = 1 << 0,
-  PSPPIRE_SHEET_RIGHT_BORDER    = 1 << 1,
-  PSPPIRE_SHEET_TOP_BORDER      = 1 << 2,
-  PSPPIRE_SHEET_BOTTOM_BORDER   = 1 << 3
-} PsppireSheetBorderType ;
-
-
-typedef struct _PsppireSheetModel        PsppireSheetModel; /* Dummy typedef */
-typedef struct _PsppireSheetModelIface   PsppireSheetModelIface;
-typedef struct _PsppireSheetRange PsppireSheetRange;
-typedef struct _PsppireSheetCellBorder     PsppireSheetCellBorder;
-
-struct _PsppireSheetRange
-{
-  gint row0, col0; /* upper-left cell */
-  gint rowi, coli; /* lower-right cell */
-};
-
-struct _PsppireSheetCellBorder
-{
-  PsppireSheetBorderType mask;
-  guint width;
-  GdkLineStyle line_style;
-  GdkCapStyle cap_style;
-  GdkJoinStyle join_style;
-  GdkColor color;
-};
-
-
-
-struct _PsppireSheetModelIface
-{
-  GTypeInterface g_iface;
-
-  gboolean free_strings;
-
-  /* Signals */
-  void         (* range_changed)    (PsppireSheetModel *sheet_model,
-                                    glong row0, glong col0,
-                                    glong rowi, glong coli);
-
-  void         (* rows_inserted)    (PsppireSheetModel *sheet_model,
-                                    glong row, glong n_rows);
-
-  void         (* rows_deleted)     (PsppireSheetModel *sheet_model,
-                                    glong row, glong n_rows);
-
-  void         (* columns_inserted)    (PsppireSheetModel *sheet_model,
-                                       glong column, glong n_columns);
-
-  void         (* columns_deleted)     (PsppireSheetModel *sheet_model,
-                                       glong column, glong n_columns);
-
-
-
-  /* Virtual Table */
-
-  gchar *      (* get_string)      (const PsppireSheetModel *sheet_model,
-                                   glong row, glong column);
-
-  gboolean  (* set_string) (PsppireSheetModel *sheet_model,
-                           const gchar *s, glong row, glong column);
-
-  gboolean  (* clear_datum) (PsppireSheetModel *sheet_model,
-                            glong row, glong column);
-
-  gboolean (* is_editable) (const PsppireSheetModel *sheet_model, glong row, glong column);
-
-  GdkColor *  (* get_foreground) (const PsppireSheetModel *sheet_model,
-                                 glong row, glong column);
-
-  GdkColor *  (* get_background) (const PsppireSheetModel *sheet_model,
-                                 glong row, glong column);
-
-  const GtkJustification *  (* get_justification) (const PsppireSheetModel *sheet_model,
-                                                  glong row, glong column);
-
-  /* column related metadata */
-
-  gchar * (*get_column_title) (const PsppireSheetModel *, gint col);
-  gchar * (*get_column_subtitle) (const PsppireSheetModel *, gint col);
-  gboolean (*get_column_sensitivity) (const PsppireSheetModel *, gint col);
-  GtkJustification (*get_column_justification) (const PsppireSheetModel *mode, gint col);
-  const PsppireSheetButton * (* get_button) (const PsppireSheetModel *model, gint col);
-
-  glong (*get_column_count) (const PsppireSheetModel *model);
-
-
-  /* row related metadata */
-  gchar * (*get_row_title) (const PsppireSheetModel *, gint row);
-  gchar * (*get_row_subtitle) (const PsppireSheetModel *, gint row);
-  glong (*get_row_count) (const PsppireSheetModel *model);
-  gboolean (*get_row_sensitivity) (const PsppireSheetModel *, gint row);
-
-  gboolean (*get_row_overstrike) (const PsppireSheetModel *, gint row);
-};
-
-
-
-GType              psppire_sheet_model_get_type   (void) G_GNUC_CONST;
-
-
-gchar * psppire_sheet_model_get_string (const PsppireSheetModel *sheet_model,
-                                 glong row, glong column);
-
-gboolean  psppire_sheet_model_set_string (PsppireSheetModel *sheet_model,
-                                   const gchar *s,
-                                   glong row, glong column);
-
-gboolean psppire_sheet_model_datum_clear    (PsppireSheetModel *sheet_model,
-                                      glong row, glong column);
-
-
-void psppire_sheet_model_range_changed (PsppireSheetModel *sheet_model,
-                                 glong row0, glong col0,
-                                 glong rowi, glong coli);
-
-void psppire_sheet_model_rows_deleted (PsppireSheetModel *sheet_model,
-                                glong row, glong n_rows);
-
-void psppire_sheet_model_rows_inserted (PsppireSheetModel *sheet_model,
-                                 glong row, glong n_rows);
-
-void psppire_sheet_model_columns_inserted (PsppireSheetModel *sheet_model,
-                                    glong column, glong n_columns);
-
-void psppire_sheet_model_columns_deleted (PsppireSheetModel *sheet_model,
-                                   glong column, glong n_columns);
-
-
-gboolean psppire_sheet_model_is_editable (const PsppireSheetModel *model,
-                                   glong row, glong column);
-
-gboolean psppire_sheet_model_is_visible
- (const PsppireSheetModel *model, glong row, glong column);
-
-
-GdkColor *psppire_sheet_model_get_foreground
- (const PsppireSheetModel *model, glong row, glong column);
-
-GdkColor *psppire_sheet_model_get_background
- (const PsppireSheetModel *model, glong row, glong column);
-
-const GtkJustification *psppire_sheet_model_get_justification
- (const PsppireSheetModel *model, glong row, glong column);
-
-const PsppireSheetCellBorder * psppire_sheet_model_get_cell_border
- (const PsppireSheetModel *model, glong row, glong column);
-
-gboolean psppire_sheet_model_free_strings (const PsppireSheetModel *sheet_model);
-
-glong psppire_sheet_model_get_column_count (const PsppireSheetModel *sheet_model);
-
-gint psppire_sheet_model_get_row_count (const PsppireSheetModel *sheet_model);
-
-\f
-
-gboolean psppire_sheet_model_get_column_sensitivity (const PsppireSheetModel *model,
-                                              gint col);
-
-gchar * psppire_sheet_model_get_column_subtitle (const PsppireSheetModel *model,
-                                           gint col);
-
-PsppireSheetButton * psppire_sheet_model_get_column_button (const PsppireSheetModel *, gint);
-
-GtkJustification psppire_sheet_model_get_column_justification (const PsppireSheetModel *,
-                                                        gint);
-
-\f
-
-gboolean psppire_sheet_model_get_row_sensitivity (const PsppireSheetModel *model,
-                                           gint row);
-
-
-gchar * psppire_sheet_model_get_row_subtitle (const PsppireSheetModel *model,
-                                           gint row);
-
-
-PsppireSheetButton * psppire_sheet_model_get_row_button (const PsppireSheetModel *, gint);
-
-
-
-
-G_END_DECLS
-
-#endif /* __PSPPIRE_SHEET_MODEL_H__ */
index 6e9259ee425113ca17fae2ca22279ed49a557da0..82ef6315456bd1f9e3f2c6451cd303d2308c6ca1 100644 (file)
@@ -34,9 +34,6 @@
 
 #include "dialog-common.h"
 
-/* FIXME: These shouldn't be here */
-#include "psppire-var-store.h"
-
 
 struct split_file_dialog
 {
@@ -165,7 +162,6 @@ split_file_dialog (PsppireDataWindow *de)
 {
   gint response;
   struct split_file_dialog sfd;
-  PsppireVarStore *vs ;
 
   GtkWidget *dialog   ;
   GtkWidget *source   ;
@@ -181,9 +177,7 @@ split_file_dialog (PsppireDataWindow *de)
 
   sfd.tv = GTK_TREE_VIEW (get_widget_assert (sfd.xml, "split-file-grouping-vars"));
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
-  g_object_get (vs, "dictionary", &sfd.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &sfd.dict, NULL);
 
   sfd.selector = PSPPIRE_SELECTOR (get_widget_assert (sfd.xml, "split-file-selector"));
 
index 02d3eff345d780631500ea0419b460b958406fb8..d2bc12638363f53e5ee69db41eca0ec17118ac48 100644 (file)
@@ -20,7 +20,6 @@
 #include <gtk/gtk.h>
 #include "t-test-one-sample.h"
 #include "psppire-dict.h"
-#include "psppire-var-store.h"
 #include "psppire-var-view.h"
 #include "builder-wrapper.h"
 #include "psppire-data-window.h"
@@ -125,8 +124,6 @@ t_test_one_sample_dialog (PsppireDataWindow *de)
   struct tt_one_sample_dialog tt_d;
   gint response;
 
-  PsppireVarStore *vs = NULL;
-
   GtkBuilder *xml = builder_new ("t-test.ui");
 
   GtkWidget *dict_view =
@@ -137,9 +134,7 @@ t_test_one_sample_dialog (PsppireDataWindow *de)
 
   GtkWidget *dialog = get_widget_assert (xml, "t-test-one-sample-dialog");
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
-  g_object_get (vs, "dictionary", &tt_d.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &tt_d.dict, NULL);
   tt_d.vars_treeview = get_widget_assert (xml, "one-sample-t-test-treeview1");
   tt_d.test_value_entry = get_widget_assert (xml, "test-value-entry");
   tt_d.opt = tt_options_dialog_create (GTK_WINDOW (de));
index 212691d39b4c242f5158e40d4d3727d5018e1882..1b1cfbc87f7ac7f29b7248596e7537bd2212252d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2011  Free Software Foundation
+   Copyright (C) 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -26,7 +26,6 @@
 #include "psppire-var-view.h"
 
 #include "psppire-dict.h"
-#include "psppire-var-store.h"
 
 #include "dialog-common.h"
 #include "psppire-dialog.h"
index 907dd7ab4cb683ebe4f61a3fcc842ec35ec64e48..0abeb56f6884c75b013925e8876ddfd02124e9cc 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <gtk-contrib/psppire-sheet.h>
 #include <gtk/gtk.h>
 #include <limits.h>
 #include <stdlib.h>
 #include "libpspp/i18n.h"
 #include "libpspp/line-reader.h"
 #include "libpspp/message.h"
+#include "ui/gui/builder-wrapper.h"
 #include "ui/gui/checkbox-treeview.h"
 #include "ui/gui/dialog-common.h"
 #include "ui/gui/executor.h"
 #include "ui/gui/helper.h"
-#include "ui/gui/builder-wrapper.h"
+#include "ui/gui/pspp-sheet-selection.h"
+#include "ui/gui/pspp-sheet-view.h"
 #include "ui/gui/psppire-data-window.h"
 #include "ui/gui/psppire-dialog.h"
 #include "ui/gui/psppire-encoding-selector.h"
 #include "ui/gui/psppire-empty-list-store.h"
-#include "ui/gui/psppire-var-sheet.h"
-#include "ui/gui/psppire-var-store.h"
 #include "ui/gui/psppire-scanf.h"
+#include "ui/gui/psppire-var-sheet.h"
 #include "ui/syntax-gen.h"
 
 #include "gl/error.h"
@@ -115,7 +115,7 @@ struct first_line_page
     bool variable_names; /* Variable names above first line of data? */
 
     GtkWidget *page;
-    GtkTreeView *tree_view;
+    PsppSheetView *tree_view;
     GtkWidget *variable_names_cb;
   };
 static void init_first_line_page (struct import_assistant *);
@@ -140,7 +140,7 @@ struct separators_page
     GtkWidget *quote_combo;
     GtkEntry *quote_entry;
     GtkWidget *escape_cb;
-    GtkTreeView *fields_tree_view;
+    PsppSheetView *fields_tree_view;
   };
 /* The columns that the separators divide the data into. */
 struct column
@@ -177,7 +177,7 @@ struct formats_page
     struct dictionary *dict;
 
     GtkWidget *page;
-    GtkTreeView *data_tree_view;
+    PsppSheetView *data_tree_view;
     PsppireDict *psppire_dict;
     struct variable **modified_vars;
     size_t modified_var_cnt;
@@ -205,17 +205,17 @@ static gboolean get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
                                       size_t *row, size_t *column);
 static void make_tree_view (const struct import_assistant *ia,
                             size_t first_line,
-                            GtkTreeView **tree_view);
+                            PsppSheetView **tree_view);
 static void add_line_number_column (const struct import_assistant *,
-                                    GtkTreeView *);
-static gint get_monospace_width (GtkTreeView *, GtkCellRenderer *,
+                                    PsppSheetView *);
+static gint get_monospace_width (PsppSheetView *, GtkCellRenderer *,
                                  size_t char_cnt);
-static gint get_string_width (GtkTreeView *, GtkCellRenderer *,
+static gint get_string_width (PsppSheetView *, GtkCellRenderer *,
                               const char *string);
-static GtkTreeViewColumn *make_data_column (struct import_assistant *,
-                                            GtkTreeView *, bool input,
+static PsppSheetViewColumn *make_data_column (struct import_assistant *,
+                                            PsppSheetView *, bool input,
                                             gint column_idx);
-static GtkTreeView *create_data_tree_view (bool input, GtkContainer *parent,
+static PsppSheetView *create_data_tree_view (bool input, GtkContainer *parent,
                                            struct import_assistant *);
 static void push_watch_cursor (struct import_assistant *);
 static void pop_watch_cursor (struct import_assistant *);
@@ -861,9 +861,9 @@ on_intro_amount_changed (struct import_assistant *ia)
 \f
 /* The "first line" page of the assistant. */
 
-static GtkTreeView *create_lines_tree_view (GtkContainer *parent_window,
+static PsppSheetView *create_lines_tree_view (GtkContainer *parent_window,
                                             struct import_assistant *);
-static void on_first_line_change (GtkTreeSelection *,
+static void on_first_line_change (PsppSheetSelection *,
                                   struct import_assistant *);
 static void on_variable_names_cb_toggle (GtkToggleButton *,
                                          struct import_assistant *);
@@ -883,11 +883,12 @@ init_first_line_page (struct import_assistant *ia)
   p->tree_view = create_lines_tree_view (
     GTK_CONTAINER (get_widget_assert (builder, "first-line-scroller")), ia);
   p->variable_names_cb = get_widget_assert (builder, "variable-names");
-  gtk_tree_selection_set_mode (
-    gtk_tree_view_get_selection (GTK_TREE_VIEW (p->tree_view)),
-    GTK_SELECTION_BROWSE);
+  pspp_sheet_selection_set_mode (
+    pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (p->tree_view)),
+    PSPP_SHEET_SELECTION_BROWSE);
+  pspp_sheet_view_set_rubber_banding (PSPP_SHEET_VIEW (p->tree_view), TRUE);
   set_first_line (ia);
-  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (p->tree_view)),
+  g_signal_connect (pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (p->tree_view)),
                     "changed", G_CALLBACK (on_first_line_change), ia);
   g_signal_connect (p->variable_names_cb, "toggled",
                     G_CALLBACK (on_variable_names_cb_toggle), ia);
@@ -903,7 +904,7 @@ reset_first_line_page (struct import_assistant *ia)
 }
 
 static void
-render_line (GtkTreeViewColumn *tree_column,
+render_line (PsppSheetViewColumn *tree_column,
              GtkCellRenderer *cell,
              GtkTreeModel *tree_model,
              GtkTreeIter *iter,
@@ -921,11 +922,11 @@ render_line (GtkTreeViewColumn *tree_column,
 
 /* Creates and returns a tree view that contains each of the
    lines in IA's file as a row. */
-static GtkTreeView *
+static PsppSheetView *
 create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia)
 {
-  GtkTreeView *tree_view;
-  GtkTreeViewColumn *column;
+  PsppSheetView *tree_view;
+  PsppSheetViewColumn *column;
   size_t max_line_length;
   gint content_width, header_width;
   size_t i;
@@ -933,11 +934,11 @@ create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia)
 
   make_tree_view (ia, 0, &tree_view);
 
-  column = gtk_tree_view_column_new_with_attributes (
-     title, ia->asst.fixed_renderer, (void *) NULL);
-  gtk_tree_view_column_set_cell_data_func (column, ia->asst.fixed_renderer,
+  column = pspp_sheet_view_column_new_with_attributes (
+    title, ia->asst.fixed_renderer, (void *) NULL);
+  pspp_sheet_view_column_set_cell_data_func (column, ia->asst.fixed_renderer,
                                            render_line, NULL, NULL);
-  gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+  pspp_sheet_view_column_set_resizable (column, TRUE);
 
   max_line_length = 0;
   for (i = 0; i < ia->file.line_cnt; i++)
@@ -949,11 +950,9 @@ create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia)
   content_width = get_monospace_width (tree_view, ia->asst.fixed_renderer,
                                        max_line_length);
   header_width = get_string_width (tree_view, ia->asst.prop_renderer, title);
-  gtk_tree_view_column_set_fixed_width (column, MAX (content_width,
+  pspp_sheet_view_column_set_fixed_width (column, MAX (content_width,
                                                      header_width));
-  gtk_tree_view_append_column (tree_view, column);
-
-  gtk_tree_view_set_fixed_height_mode (tree_view, true);
+  pspp_sheet_view_append_column (tree_view, column);
 
   gtk_container_add (parent, GTK_WIDGET (tree_view));
   gtk_widget_show (GTK_WIDGET (tree_view));
@@ -964,7 +963,7 @@ create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia)
 /* Called when the line selected in the first_line tree view
    changes. */
 static void
-on_first_line_change (GtkTreeSelection *selection UNUSED,
+on_first_line_change (PsppSheetSelection *selection UNUSED,
                       struct import_assistant *ia)
 {
   get_first_line (ia);
@@ -986,7 +985,7 @@ set_first_line (struct import_assistant *ia)
   GtkTreePath *path;
 
   path = gtk_tree_path_new_from_indices (ia->first_line.skip_lines, -1);
-  gtk_tree_view_set_cursor (GTK_TREE_VIEW (ia->first_line.tree_view),
+  pspp_sheet_view_set_cursor (PSPP_SHEET_VIEW (ia->first_line.tree_view),
                             path, NULL, false);
   gtk_tree_path_free (path);
 
@@ -1001,12 +1000,12 @@ set_first_line (struct import_assistant *ia)
 static void
 get_first_line (struct import_assistant *ia)
 {
-  GtkTreeSelection *selection;
+  PsppSheetSelection *selection;
   GtkTreeIter iter;
   GtkTreeModel *model;
 
-  selection = gtk_tree_view_get_selection (ia->first_line.tree_view);
-  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+  selection = pspp_sheet_view_get_selection (ia->first_line.tree_view);
+  if (pspp_sheet_selection_get_selected (selection, &model, &iter))
     {
       GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
       int row = gtk_tree_path_get_indices (path)[0];
@@ -1043,7 +1042,7 @@ static void on_quote_combo_change (GtkComboBox *combo,
 static void on_quote_cb_toggle (GtkToggleButton *quote_cb,
                                 struct import_assistant *);
 static void on_separator_toggle (GtkToggleButton *, struct import_assistant *);
-static void render_input_cell (GtkTreeViewColumn *tree_column,
+static void render_input_cell (PsppSheetViewColumn *tree_column,
                                GtkCellRenderer *cell,
                                GtkTreeModel *model, GtkTreeIter *iter,
                                gpointer ia);
@@ -1121,7 +1120,7 @@ init_separators_page (struct import_assistant *ia)
 
   set_separators (ia);
   set_quote_list (GTK_COMBO_BOX_ENTRY (p->quote_combo));
-  p->fields_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "fields"));
+  p->fields_tree_view = PSPP_SHEET_VIEW (get_widget_assert (builder, "fields"));
   g_signal_connect (p->quote_combo, "changed",
                     G_CALLBACK (on_quote_combo_change), ia);
   g_signal_connect (p->quote_cb, "toggled",
@@ -1546,7 +1545,7 @@ on_separator_toggle (GtkToggleButton *toggle UNUSED,
 /* Called to render one of the cells in the fields preview tree
    view. */
 static void
-render_input_cell (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
+render_input_cell (PsppSheetViewColumn *tree_column, GtkCellRenderer *cell,
                    GtkTreeModel *model, GtkTreeIter *iter,
                    gpointer ia_)
 {
@@ -1612,7 +1611,7 @@ init_formats_page (struct import_assistant *ia)
 
   p->page = add_page_to_assistant (ia, get_widget_assert (builder, "Formats"),
                                    GTK_ASSISTANT_PAGE_CONFIRM);
-  p->data_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "data"));
+  p->data_tree_view = PSPP_SHEET_VIEW (get_widget_assert (builder, "data"));
   p->modified_vars = NULL;
   p->modified_var_cnt = 0;
   p->dict = NULL;
@@ -1639,7 +1638,6 @@ prepare_formats_page (struct import_assistant *ia)
 {
   struct dictionary *dict;
   PsppireDict *psppire_dict;
-  PsppireVarStore *var_store;
   GtkBin *vars_scroller;
   GtkWidget *old_var_sheet;
   PsppireVarSheet *var_sheet;
@@ -1705,14 +1703,13 @@ prepare_formats_page (struct import_assistant *ia)
      psppire_dict for now, but it should.  After it does, we
      should g_object_ref the psppire_dict here, since we also
      hold a reference via ia->formats.dict. */
-  var_store = psppire_var_store_new (psppire_dict);
-  g_object_set (var_store,
-                "format-type", PSPPIRE_VAR_STORE_INPUT_FORMATS,
-                (void *) NULL);
   var_sheet = PSPPIRE_VAR_SHEET (psppire_var_sheet_new ());
   g_object_set (var_sheet,
-                "model", var_store,
+                "dictionary", psppire_dict,
                 "may-create-vars", FALSE,
+                "may-delete-vars", FALSE,
+                "format-use", FMT_FOR_INPUT,
+                "enable-grid-lines", PSPP_SHEET_VIEW_GRID_LINES_BOTH,
                 (void *) NULL);
 
   vars_scroller = GTK_BIN (get_widget_assert (ia->asst.builder, "vars-scroller"));
@@ -1764,14 +1761,14 @@ on_variable_change (PsppireDict *dict, int dict_idx,
                     struct import_assistant *ia)
 {
   struct formats_page *p = &ia->formats;
-  GtkTreeView *tv = ia->formats.data_tree_view;
+  PsppSheetView *tv = ia->formats.data_tree_view;
   gint column_idx = dict_idx + 1;
 
   push_watch_cursor (ia);
 
   /* Remove previous column and replace with new column. */
-  gtk_tree_view_remove_column (tv, gtk_tree_view_get_column (tv, column_idx));
-  gtk_tree_view_insert_column (tv, make_data_column (ia, tv, false, dict_idx),
+  pspp_sheet_view_remove_column (tv, pspp_sheet_view_get_column (tv, column_idx));
+  pspp_sheet_view_insert_column (tv, make_data_column (ia, tv, false, dict_idx),
                                column_idx);
 
   /* Save a copy of the modified variable in modified_vars, so
@@ -1859,7 +1856,7 @@ parse_field (struct import_assistant *ia,
 /* Called to render one of the cells in the data preview tree
    view. */
 static void
-render_output_cell (GtkTreeViewColumn *tree_column,
+render_output_cell (PsppSheetViewColumn *tree_column,
                     GtkCellRenderer *cell,
                     GtkTreeModel *model,
                     GtkTreeIter *iter,
@@ -1919,11 +1916,11 @@ get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
                       const struct import_assistant *ia,
                       size_t *row, size_t *column)
 {
-  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+  PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
   gint bx, by;
   GtkTreePath *path;
   GtkTreeIter iter;
-  GtkTreeViewColumn *tree_column;
+  PsppSheetViewColumn *tree_column;
   GtkTreeModel *tree_model;
   bool ok;
 
@@ -1940,16 +1937,16 @@ get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
   if (!gtk_widget_get_mapped (widget))
     return FALSE;
 
-  gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
+  pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
                                                      wx, wy, &bx, &by);
-  if (!gtk_tree_view_get_path_at_pos (tree_view, bx, by,
+  if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
                                       &path, &tree_column, NULL, NULL))
     return FALSE;
 
   *column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
                                                 "column-number"));
 
-  tree_model = gtk_tree_view_get_model (tree_view);
+  tree_model = pspp_sheet_view_get_model (tree_view);
   ok = gtk_tree_model_get_iter (tree_model, &iter, path);
   gtk_tree_path_free (path);
   if (!ok)
@@ -1962,24 +1959,25 @@ get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
 static void
 make_tree_view (const struct import_assistant *ia,
                 size_t first_line,
-                GtkTreeView **tree_view)
+                PsppSheetView **tree_view)
 {
   GtkTreeModel *model;
 
-  *tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
+  *tree_view = PSPP_SHEET_VIEW (pspp_sheet_view_new ());
+  pspp_sheet_view_set_grid_lines (*tree_view, PSPP_SHEET_VIEW_GRID_LINES_BOTH);
   model = GTK_TREE_MODEL (psppire_empty_list_store_new (
                             ia->file.line_cnt - first_line));
   g_object_set_data (G_OBJECT (model), "lines", ia->file.lines + first_line);
   g_object_set_data (G_OBJECT (model), "first-line",
                      GINT_TO_POINTER (first_line));
-  gtk_tree_view_set_model (*tree_view, model);
+  pspp_sheet_view_set_model (*tree_view, model);
   g_object_unref (model);
 
   add_line_number_column (ia, *tree_view);
 }
 
 static void
-render_line_number (GtkTreeViewColumn *tree_column,
+render_line_number (PsppSheetViewColumn *tree_column,
                     GtkCellRenderer *cell,
                     GtkTreeModel *tree_model,
                     GtkTreeIter *iter,
@@ -1997,23 +1995,22 @@ render_line_number (GtkTreeViewColumn *tree_column,
 
 static void
 add_line_number_column (const struct import_assistant *ia,
-                        GtkTreeView *treeview)
+                        PsppSheetView *treeview)
 {
-  GtkTreeViewColumn *column;
+  PsppSheetViewColumn *column;
 
-  column = gtk_tree_view_column_new_with_attributes (
+  column = pspp_sheet_view_column_new_with_attributes (
     _("Line"), ia->asst.prop_renderer, (void *) NULL);
-  gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
-  gtk_tree_view_column_set_fixed_width (
+  pspp_sheet_view_column_set_fixed_width (
     column, get_monospace_width (treeview, ia->asst.prop_renderer, 5));
-  gtk_tree_view_column_set_resizable (column, TRUE);
-  gtk_tree_view_column_set_cell_data_func (column, ia->asst.prop_renderer,
-                                           render_line_number, NULL, NULL);
-  gtk_tree_view_append_column (treeview, column);
+  pspp_sheet_view_column_set_resizable (column, TRUE);
+  pspp_sheet_view_column_set_cell_data_func (column, ia->asst.prop_renderer,
+                                             render_line_number, NULL, NULL);
+  pspp_sheet_view_append_column (treeview, column);
 }
 
 static gint
-get_monospace_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
+get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
                      size_t char_cnt)
 {
   struct string s;
@@ -2029,7 +2026,7 @@ get_monospace_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
 }
 
 static gint
-get_string_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
+get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
                   const char *string)
 {
   gint width;
@@ -2039,15 +2036,15 @@ get_string_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
   return width;
 }
 
-static GtkTreeViewColumn *
-make_data_column (struct import_assistant *ia, GtkTreeView *tree_view,
+static PsppSheetViewColumn *
+make_data_column (struct import_assistant *ia, PsppSheetView *tree_view,
                   bool input, gint dict_idx)
 {
   struct variable *var = NULL;
   struct column *column = NULL;
   size_t char_cnt;
   gint content_width, header_width;
-  GtkTreeViewColumn *tree_column;
+  PsppSheetViewColumn *tree_column;
   char *name;
 
   if (input)
@@ -2062,44 +2059,43 @@ make_data_column (struct import_assistant *ia, GtkTreeView *tree_view,
   header_width = get_string_width (tree_view, ia->asst.prop_renderer,
                                    name);
 
-  tree_column = gtk_tree_view_column_new ();
+  tree_column = pspp_sheet_view_column_new ();
   g_object_set_data (G_OBJECT (tree_column), "column-number",
                      GINT_TO_POINTER (dict_idx));
-  gtk_tree_view_column_set_title (tree_column, name);
-  gtk_tree_view_column_pack_start (tree_column, ia->asst.fixed_renderer,
+  pspp_sheet_view_column_set_title (tree_column, name);
+  pspp_sheet_view_column_pack_start (tree_column, ia->asst.fixed_renderer,
                                    FALSE);
-  gtk_tree_view_column_set_cell_data_func (
+  pspp_sheet_view_column_set_cell_data_func (
     tree_column, ia->asst.fixed_renderer,
     input ? render_input_cell : render_output_cell, ia, NULL);
-  gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_FIXED);
-  gtk_tree_view_column_set_fixed_width (tree_column, MAX (content_width,
+  pspp_sheet_view_column_set_fixed_width (tree_column, MAX (content_width,
                                                           header_width));
+  pspp_sheet_view_column_set_resizable (tree_column, TRUE);
 
   free (name);
 
   return tree_column;
 }
 
-static GtkTreeView *
+static PsppSheetView *
 create_data_tree_view (bool input, GtkContainer *parent,
                        struct import_assistant *ia)
 {
-  GtkTreeView *tree_view;
+  PsppSheetView *tree_view;
   gint i;
 
   make_tree_view (ia, ia->first_line.skip_lines, &tree_view);
-  gtk_tree_selection_set_mode (gtk_tree_view_get_selection (tree_view),
-                               GTK_SELECTION_NONE);
+  pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (tree_view),
+                               PSPP_SHEET_SELECTION_NONE);
 
   for (i = 0; i < ia->separators.column_cnt; i++)
-    gtk_tree_view_append_column (tree_view,
+    pspp_sheet_view_append_column (tree_view,
                                  make_data_column (ia, tree_view, input, i));
 
   g_object_set (G_OBJECT (tree_view), "has-tooltip", TRUE, (void *) NULL);
   g_signal_connect (tree_view, "query-tooltip",
                     G_CALLBACK (input ? on_query_input_tooltip
                                 : on_query_output_tooltip), ia);
-  gtk_tree_view_set_fixed_height_mode (tree_view, true);
 
   gtk_container_add (parent, GTK_WIDGET (tree_view));
   gtk_widget_show (GTK_WIDGET (tree_view));
index d8a33d118a39beec98546e09147e42308a6b5ae6..7c09e49aa2621b1c5f7ee51b2ecf5a045be9ca8a 100644 (file)
@@ -158,7 +158,7 @@ The selected file contains N lines of text.  Only the first M of these will be s
             <property name="hscrollbar_policy">automatic</property>
             <property name="vscrollbar_policy">automatic</property>
             <child>
-              <object class="GtkTreeView" id="first-line">
+              <object class="PsppSheetView" id="first-line">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@@ -508,7 +508,7 @@ The selected file contains N lines of text.  Only the first M of these will be s
                     <property name="hscrollbar_policy">automatic</property>
                     <property name="vscrollbar_policy">automatic</property>
                     <child>
-                      <object class="GtkTreeView" id="fields">
+                      <object class="PsppSheetView" id="fields">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@@ -621,7 +621,7 @@ The selected file contains N lines of text.  Only the first M of these will be s
                         <property name="hscrollbar_policy">automatic</property>
                         <property name="vscrollbar_policy">automatic</property>
                         <child>
-                          <object class="GtkTreeView" id="data">
+                          <object class="PsppSheetView" id="data">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
index f91b55258c1a05bbe14c57aea5bde10287978ea0..742dff527bd7110fb15022ee1694f7c4bb5ce7e5 100644 (file)
 #define N_(msgid) msgid
 
 
-/* FIXME: These shouldn't be here */
-#include "psppire-var-store.h"
-
-
 static gchar * generate_syntax (PsppireDict *dict, GtkBuilder *xml);
 
 static void
@@ -84,15 +80,11 @@ transpose_dialog (PsppireDataWindow *de)
 
   GtkBuilder *xml = builder_new ("psppire.ui");
 
-  PsppireVarStore *vs = NULL;
-
   GtkWidget *dialog = get_widget_assert (xml, "transpose-dialog");
   GtkWidget *source = get_widget_assert (xml, "source-treeview");
   GtkWidget *selector2 = get_widget_assert (xml, "psppire-selector3");
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
-  g_object_get (vs, "dictionary", &dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &dict, NULL);
   g_object_set (source, "model", dict, NULL);
 
   psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector2),
index 44e341a26b5c8a7466d2326b2d5f46d8b82052d7..2f241498603f3fd9397545d7eea7a7aa9d60f3fc 100644 (file)
@@ -114,13 +114,9 @@ univariate_dialog (PsppireDataWindow * de)
   GtkWidget *factor_selector = get_widget_assert (xml, "factor-selector");
 
 
-  PsppireVarStore *vs = NULL;
-
   uv_d.dep_entry = get_widget_assert (xml, "dep-entry");
   uv_d.factor_list = get_widget_assert (xml, "factors-view");
 
-  g_object_get (de->data_editor, "var-store", &vs, NULL);
-
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
   g_signal_connect (dialog, "refresh", G_CALLBACK (refresh),  &uv_d);
 
@@ -128,7 +124,7 @@ univariate_dialog (PsppireDataWindow * de)
                                      dialog_state_valid, &uv_d);
 
 
-  g_object_get (vs, "dictionary", &uv_d.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &uv_d.dict, NULL);
   g_object_set (source, "model", uv_d.dict, NULL);
 
   psppire_selector_set_allow (PSPPIRE_SELECTOR (dep_selector),
index 6b556d6de7861baa006530b2cfcf943fe0ff46d9..5b4f7cffba98f0f73b43c56acd2b0f5fcd86f26b 100644 (file)
@@ -26,8 +26,6 @@
 #include "val-labs-dialog.h"
 #include <data/value-labels.h>
 #include <data/format.h>
-#include "psppire-var-sheet.h"
-#include "psppire-var-store.h"
 #include <libpspp/i18n.h>
 
 #include "helper.h"
index 85feaaca7891ec1115639d70886730fc26078c08..89b85d073e9bb9cd322fd5c77d3ed67f557d2d42 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005, 2011  Free Software Foundation
+   Copyright (C) 2005, 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -24,8 +24,6 @@
 
 #include <gtk/gtk.h>
 #include <data/variable.h>
-//#include <gtk-contrib/psppire-sheet.h>
-#include "psppire-var-store.h"
 
 struct val_labs;
 
diff --git a/src/ui/gui/var-sheet.ui b/src/ui/gui/var-sheet.ui
new file mode 100644 (file)
index 0000000..148a8d8
--- /dev/null
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<interface>
+  <object class="GtkUIManager" id="var_sheet_uim">
+    <ui>
+      <menubar name="menubar">
+       <placeholder name="VarSheetEditMenu">
+         <menu action="edit">
+           <menuitem action="edit_insert-variable"/>
+           <menuitem action="edit_goto-variable"/>
+           <separator/>
+           <menuitem action="edit_cut"/>
+           <menuitem action="edit_copy"/>
+           <menuitem action="edit_paste"/>
+           <menuitem action="edit_clear-variables"/>
+         </menu>
+       </placeholder>
+      </menubar>
+      <toolbar name="toolbar">
+       <placeholder name="VarSheetToolItems">
+         <toolitem name="toolbar_goto-variable" action="edit_goto-variable"/>
+         <toolitem name="toolbar_insert-variable" action="edit_insert-variable"/>
+       </placeholder>
+      </toolbar>
+      <popup name="varsheet-variable-popup">
+       <menuitem action="edit_insert-variable"/>
+       <separator/>
+       <menuitem action="edit_clear-variables"/>
+      </popup>
+    </ui>
+    <child>
+      <object class="GtkActionGroup" id="actiongroup4">
+       <child>
+         <object class="GtkAction" id="edit">
+           <property name="name">edit</property>
+           <property name="label" translatable="yes">_Edit</property>
+         </object>
+       </child>
+       <child>
+         <object class="GtkAction" id="edit_insert-variable">
+           <property name="name">edit_insert-variable</property>
+           <property name="label" translatable="yes">Insert Variable</property>
+           <property name="tooltip" translatable="yes">Create a new variable at the current position</property>
+           <property name="stock-id">pspp-insert-variable</property>
+         </object>
+       </child>
+        <child>
+          <object class="PsppireDialogActionVarInfo" id="edit_goto-variable">
+            <property name="name">edit_goto-variable</property>
+            <property name="label" translatable="yes">Go To Variable...</property>
+           <property name="tooltip" translatable="yes">Jump to variable</property>
+           <property name="stock-id">pspp-goto-variable</property>
+          </object>
+        </child>
+       <child>
+         <object class="GtkAction" id="edit_cut">
+           <property name="stock-id">gtk-cut</property>
+           <property name="name">edit_cut</property>
+         </object>
+       </child>
+       <child>
+         <object class="GtkAction" id="edit_copy">
+           <property name="stock-id">gtk-copy</property>
+           <property name="name">edit_copy</property>
+         </object>
+       </child>
+       <child>
+         <object class="GtkAction" id="edit_paste">
+           <property name="stock-id">gtk-paste</property>
+           <property name="name">edit_paste</property>
+         </object>
+       </child>
+       <child>
+         <object class="GtkAction" id="edit_clear-variables">
+           <property name="name">edit_clear-variables</property>
+           <property name="label" translatable="yes">Cl_ear Variables</property>
+           <property name="tooltip" translatable="yes">Delete the variables at the selected position(s)</property>
+           <property name="stock-id">gtk-clear</property>
+         </object>
+       </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkMenu" constructor="var_sheet_uim" id="varsheet-variable-popup">
+    <property name="visible">True</property>
+  </object>
+</interface>
index e194771667e73fe5840d57de84f1aa5419744815..8e11160e3e46386774c0870b17185f7d926be4eb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005, 2011  Free Software Foundation
+   Copyright (C) 2005, 2011, 2012  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -20,8 +20,6 @@
 
 #include <data/format.h>
 
-#include "psppire-var-store.h"
-
 /*  This module describes the behaviour of the Variable Type dialog box,
     used for input of the variable type parameter in the var sheet */
 
index c19eda0d06974c3c7ea0d18adeb149fbbacf8ae7..27b4fc03a1b9e1a1c1ed86b3daa3d54eed9408dc 100644 (file)
@@ -32,8 +32,6 @@
 #define N_(msgid) msgid
 
 
-#include "psppire-var-store.h"
-
 struct weight_cases_dialog
 {
   PsppireDict *dict;
@@ -119,10 +117,7 @@ weight_cases_dialog (PsppireDataWindow *de)
 
   GtkWidget *selector = get_widget_assert (xml, "weight-cases-selector");
 
-  PsppireVarStore *vs = NULL;
-
-  g_object_get (de->data_editor, "var-store", &vs,  NULL);
-  g_object_get (vs, "dictionary", &wcd.dict, NULL);
+  g_object_get (de->data_editor, "dictionary", &wcd.dict, NULL);
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));