Merge 'master' into 'psppsheet'.
[pspp] / src / ui / gui / psppire-data-sheet.c
index ad20fac0547e8861b597bdadd2abdca1b78a716d..e1ecbbb924a005bd0646c62a3558765965814fa1 100644 (file)
@@ -54,6 +54,9 @@ static void psppire_data_sheet_update_clip_actions (PsppireDataSheet *);
 static void psppire_data_sheet_set_clip (PsppireDataSheet *, gboolean cut);
 
 static void on_selection_changed (PsppSheetSelection *, gpointer);
+static void on_owner_change (GtkClipboard *, GdkEventOwnerChange *, gpointer);
+static void psppire_data_sheet_clip_received_cb (GtkClipboard *,
+                                                 GtkSelectionData *, gpointer);
 
 G_DEFINE_TYPE (PsppireDataSheet, psppire_data_sheet, PSPP_TYPE_SHEET_VIEW);
 
@@ -225,6 +228,7 @@ make_row_number_column (PsppireDataSheet *data_sheet,
                                                        renderer, NULL);
   pspp_sheet_view_column_set_selectable (column, TRUE);
   pspp_sheet_view_column_set_row_head (column, TRUE);
+  pspp_sheet_view_column_set_tabbable (column, FALSE);
   pspp_sheet_view_column_set_clickable (column, TRUE);
   pspp_sheet_view_column_set_cell_data_func (
     column, renderer, render_row_number_cell, ds, NULL);
@@ -754,6 +758,7 @@ make_new_variable_column (PsppireDataSheet *data_sheet,
   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);
+  pspp_sheet_view_column_set_tabbable (column, FALSE);
 
   g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet);
   g_signal_connect (column, "button-press-event",
@@ -1042,7 +1047,7 @@ psppire_data_sheet_find_column_for_variable (PsppireDataSheet *data_sheet,
 }
 
 void
-psppire_data_sheet_show_variable (PsppireDataSheet *data_sheet,
+psppire_data_sheet_goto_variable (PsppireDataSheet *data_sheet,
                                   gint dict_index)
 {
   PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
@@ -1051,8 +1056,17 @@ psppire_data_sheet_show_variable (PsppireDataSheet *data_sheet,
   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);
+    {
+      GtkTreePath *path;
+
+      gint row = psppire_data_sheet_get_current_case (data_sheet);
+      path = gtk_tree_path_new_from_indices (row >= 0 ? row : 0, -1);
+
+      pspp_sheet_view_scroll_to_cell (sheet_view, path, column,
+                                      FALSE, 0.0, 0.0);
+      pspp_sheet_view_set_cursor (sheet_view, path, column, FALSE);
+      gtk_tree_path_free (path);
+    }
 }
 
 struct variable *
@@ -1202,17 +1216,33 @@ psppire_data_sheet_dispose (GObject *object)
   G_OBJECT_CLASS (psppire_data_sheet_parent_class)->dispose (object);
 }
 
+static void
+psppire_data_sheet_map (GtkWidget *widget)
+{
+  GtkClipboard *clip;
+
+  GTK_WIDGET_CLASS (psppire_data_sheet_parent_class)->map (widget);
+
+  clip = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
+  g_signal_connect (clip, "owner-change", G_CALLBACK (on_owner_change),
+                    widget);
+  on_owner_change (clip, NULL, widget);
+}
+
 static void
 psppire_data_sheet_class_init (PsppireDataSheetClass *class)
 {
   GObjectClass *gobject_class;
+  GtkWidgetClass *widget_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;
 
+  widget_class = GTK_WIDGET_CLASS (class);
+  widget_class->map = psppire_data_sheet_map;
+
   g_signal_new ("var-double-clicked",
                 G_OBJECT_CLASS_TYPE (gobject_class),
                 G_SIGNAL_RUN_LAST,
@@ -1624,6 +1654,19 @@ on_edit_cut (GtkAction *action, PsppireDataSheet *data_sheet)
   psppire_data_sheet_set_clip (data_sheet, TRUE);
 }
 
+void
+on_edit_paste (GtkAction *action, PsppireDataSheet *data_sheet)
+{
+  GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (data_sheet));
+  GtkClipboard *clipboard =
+    gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
+
+  gtk_clipboard_request_contents (clipboard,
+                                  gdk_atom_intern ("UTF8_STRING", TRUE),
+                                  psppire_data_sheet_clip_received_cb,
+                                  data_sheet);
+}
+
 static void
 psppire_data_sheet_init (PsppireDataSheet *obj)
 {
@@ -1686,6 +1729,9 @@ psppire_data_sheet_init (PsppireDataSheet *obj)
   action = get_action_assert (obj->builder, "edit_cut");
   g_signal_connect (action, "activate", G_CALLBACK (on_edit_cut), obj);
 
+  action = get_action_assert (obj->builder, "edit_paste");
+  g_signal_connect (action, "activate", G_CALLBACK (on_edit_paste), obj);
+
   action = get_action_assert (obj->builder, "edit_clear-variables");
   g_signal_connect (action, "activate", G_CALLBACK (on_edit_clear_variables),
                     obj);
@@ -2288,4 +2334,90 @@ psppire_data_sheet_update_clip_actions (PsppireDataSheet *data_sheet)
   action = get_action_assert (data_sheet->builder, "edit_cut");
   gtk_action_set_sensitive (action, enable);
 }
+\f
+/* A callback for when the clipboard contents have been received. */
+static void
+psppire_data_sheet_clip_received_cb (GtkClipboard *clipboard,
+                                     GtkSelectionData *sd,
+                                     gpointer data)
+{
+  PsppireDataSheet *data_sheet = data;
+  PsppireDataStore *store = data_sheet->data_store;
+  struct range_set *rows, *cols;
+  gint count = 0;
+  gint next_row, next_column;
+  gint first_column;
+  char *c;
+
+  if ( sd->length < 0 )
+    return;
+
+  if ( sd->type != gdk_atom_intern ("UTF8_STRING", FALSE))
+    return;
+
+  c = (char *) sd->data;
+
+  /* Get the starting selected position in the data sheet.  (Possibly we should
+     only paste into the selected range if it's larger than one cell?) */
+  if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
+    return;
+  next_row = range_set_first (rows)->start;
+  first_column = next_column = range_set_first (cols)->start;
+  range_set_destroy (rows);
+  range_set_destroy (cols);
+
+  g_return_if_fail (next_row >= 0);
+  g_return_if_fail (next_column >= 0);
+
+  while (count < sd->length)
+    {
+      gint row = next_row;
+      gint column = next_column;
+      struct variable *var;
+      char *s = c;
+
+      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++;
+
+      var = psppire_dict_get_variable (store->dict, column);
+      if (var != NULL)
+        psppire_data_store_set_string (store, s, row, var, FALSE);
+    }
+}
+
+static void
+on_owner_change (GtkClipboard *clip, GdkEventOwnerChange *event, gpointer data)
+{
+  PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (data);
+  gboolean compatible_target = FALSE;
+  GtkAction *action;
+  gint i;
 
+  for (i = 0; i < G_N_ELEMENTS (targets); i++)
+    {
+      GdkAtom atom = gdk_atom_intern (targets[i].target, TRUE);
+      if (gtk_clipboard_wait_is_target_available (clip, atom))
+        {
+          compatible_target = TRUE;
+          break;
+        }
+    }
+
+  action = get_action_assert (data_sheet->builder, "edit_paste");
+  gtk_action_set_sensitive (action, compatible_target);
+}