1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "ui/gui/psppire-data-sheet.h"
21 #include "data/case-map.h"
22 #include "data/casereader.h"
23 #include "data/casewriter.h"
24 #include "data/data-out.h"
25 #include "data/datasheet.h"
26 #include "data/format.h"
27 #include "data/value-labels.h"
28 #include "libpspp/intern.h"
29 #include "libpspp/range-set.h"
30 #include "ui/gui/executor.h"
31 #include "ui/gui/find-dialog.h"
32 #include "ui/gui/goto-case-dialog.h"
33 #include "ui/gui/builder-wrapper.h"
34 #include "ui/gui/helper.h"
35 #include "ui/gui/pspp-sheet-selection.h"
36 #include "ui/gui/psppire-cell-renderer-button.h"
37 #include "ui/gui/psppire-data-store.h"
38 #include "ui/gui/psppire-data-window.h"
39 #include "ui/gui/psppire-dialog-action-var-info.h"
40 #include "ui/gui/psppire-empty-list-store.h"
41 #include "ui/gui/psppire-marshal.h"
43 #include "gl/intprops.h"
44 #include "gl/xalloc.h"
47 #define _(msgid) gettext (msgid)
48 #define N_(msgid) msgid
50 static void psppire_data_sheet_dispose (GObject *);
51 static void psppire_data_sheet_unset_data_store (PsppireDataSheet *);
53 static void psppire_data_sheet_update_clip_actions (PsppireDataSheet *);
54 static void psppire_data_sheet_update_primary_selection (PsppireDataSheet *,
56 static void psppire_data_sheet_set_clip (PsppireDataSheet *, gboolean cut);
58 static void on_selection_changed (PsppSheetSelection *, gpointer);
59 static void on_owner_change (GtkClipboard *, GdkEventOwnerChange *, gpointer);
60 static void psppire_data_sheet_clip_received_cb (GtkClipboard *,
61 GtkSelectionData *, gpointer);
63 G_DEFINE_TYPE (PsppireDataSheet, psppire_data_sheet, PSPP_TYPE_SHEET_VIEW);
66 get_tooltip_location (GtkWidget *widget, GtkTooltip *tooltip,
68 size_t *row, PsppSheetViewColumn **columnp)
70 PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
74 PsppSheetViewColumn *tree_column;
75 GtkTreeModel *tree_model;
78 /* Check that WIDGET is really visible on the screen before we
79 do anything else. This is a bug fix for a sticky situation:
80 when text_data_import_assistant() returns, it frees the data
81 necessary to compose the tool tip message, but there may be
82 a tool tip under preparation at that point (even if there is
83 no visible tool tip) that will call back into us a little
84 bit later. Perhaps the correct solution to this problem is
85 to make the data related to the tool tips part of a GObject
86 that only gets destroyed when all references are released,
87 but this solution appears to be effective too. */
88 if (!gtk_widget_get_mapped (widget))
91 pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
93 if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
94 &path, &tree_column, NULL, NULL))
97 *columnp = tree_column;
99 pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, tree_column,
102 tree_model = pspp_sheet_view_get_model (tree_view);
103 ok = gtk_tree_model_get_iter (tree_model, &iter, path);
104 gtk_tree_path_free (path);
108 *row = GPOINTER_TO_INT (iter.user_data);
113 on_query_tooltip (GtkWidget *widget, gint wx, gint wy,
114 gboolean keyboard_mode UNUSED,
115 GtkTooltip *tooltip, gpointer data UNUSED)
117 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
118 PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
119 PsppSheetViewColumn *column;
120 struct variable *var;
126 g_return_val_if_fail (data_store != NULL, FALSE);
128 if (!get_tooltip_location (widget, tooltip, wx, wy, &row, &column))
131 var = g_object_get_data (G_OBJECT (column), "variable");
134 if (g_object_get_data (G_OBJECT (column), "new-var-column") == NULL)
137 gtk_tooltip_set_text (tooltip,
138 _("Enter a number to add a new variable."));
141 else if (row >= datasheet_get_n_rows (data_store->datasheet))
143 gtk_tooltip_set_text (tooltip, _("Enter a number to add a new case."));
147 width = var_get_width (var);
149 value_init (&v, width);
150 datasheet_get_value (data_store->datasheet, row, var_get_case_index (var),
153 label = var_lookup_value_label (var, &v);
156 if (data_sheet->show_value_labels)
158 char *s = value_to_text (v, var);
159 gtk_tooltip_set_text (tooltip, s);
163 gtk_tooltip_set_text (tooltip, label);
165 value_destroy (&v, width);
167 return label != NULL;
171 render_row_number_cell (PsppSheetViewColumn *tree_column,
172 GtkCellRenderer *cell,
177 PsppireDataStore *store = store_;
178 GValue gvalue = { 0, };
181 row = GPOINTER_TO_INT (iter->user_data);
183 g_value_init (&gvalue, G_TYPE_INT);
184 g_value_set_int (&gvalue, row + 1);
185 g_object_set_property (G_OBJECT (cell), "label", &gvalue);
186 g_value_unset (&gvalue);
188 if (row < datasheet_get_n_rows (store->datasheet))
189 g_object_set (cell, "editable", TRUE, NULL);
191 g_object_set (cell, "editable", FALSE, NULL);
194 "slash", psppire_data_store_filtered (store, row),
199 on_row_number_clicked (PsppireCellRendererButton *button,
201 PsppSheetView *sheet_view)
203 PsppSheetSelection *selection;
206 path = gtk_tree_path_new_from_string (path_string);
208 selection = pspp_sheet_view_get_selection (sheet_view);
209 pspp_sheet_selection_unselect_all (selection);
210 pspp_sheet_selection_select_path (selection, path);
211 pspp_sheet_selection_select_all_columns (selection);
213 gtk_tree_path_free (path);
217 make_row_number_column (PsppireDataSheet *data_sheet,
218 PsppireDataStore *ds)
220 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
221 PsppSheetViewColumn *column;
222 GtkCellRenderer *renderer;
224 renderer = psppire_cell_renderer_button_new ();
225 g_object_set (renderer, "xalign", 1.0, NULL);
226 g_signal_connect (renderer, "clicked", G_CALLBACK (on_row_number_clicked),
229 column = pspp_sheet_view_column_new_with_attributes (_("Case"),
231 pspp_sheet_view_column_set_selectable (column, TRUE);
232 pspp_sheet_view_column_set_row_head (column, TRUE);
233 pspp_sheet_view_column_set_tabbable (column, FALSE);
234 pspp_sheet_view_column_set_clickable (column, TRUE);
235 pspp_sheet_view_column_set_cell_data_func (
236 column, renderer, render_row_number_cell, ds, NULL);
237 pspp_sheet_view_column_set_fixed_width (column, 50);
238 pspp_sheet_view_column_set_visible (column, data_sheet->show_case_numbers);
239 pspp_sheet_view_append_column (sheet_view, column);
243 render_data_cell (PsppSheetViewColumn *tree_column,
244 GtkCellRenderer *cell,
247 gpointer data_sheet_)
249 PsppireDataSheet *data_sheet = data_sheet_;
250 PsppireDataStore *store = psppire_data_sheet_get_data_store (data_sheet);
251 struct variable *var;
257 row = GPOINTER_TO_INT (iter->user_data);
258 var = g_object_get_data (G_OBJECT (tree_column), "variable");
260 string = psppire_data_store_get_string (store, row, var,
261 data_sheet->show_value_labels);
264 GValue gvalue = { 0 };
266 g_value_init (&gvalue, G_TYPE_STRING);
267 g_value_take_string (&gvalue, string);
268 g_object_set_property (G_OBJECT (cell), "text", &gvalue);
269 g_value_unset (&gvalue);
272 g_object_set (G_OBJECT (cell), "text", "", NULL);
274 switch (var_get_alignment (var))
276 case ALIGN_LEFT: xalign = 0.0; break;
277 case ALIGN_RIGHT: xalign = 1.0; break;
278 case ALIGN_CENTRE: xalign = 0.5; break;
279 default: xalign = 0.0; break;
288 get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
292 g_object_set (G_OBJECT (renderer), "text", string, (void *) NULL);
293 gtk_cell_renderer_get_size (renderer, GTK_WIDGET (treeview),
294 NULL, NULL, NULL, &width, NULL);
299 get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
306 ds_put_byte_multiple (&s, '0', char_cnt);
307 ds_put_byte (&s, ' ');
308 width = get_string_width (treeview, renderer, ds_cstr (&s));
315 on_data_column_editing_started (GtkCellRenderer *cell,
316 GtkCellEditable *editable,
320 PsppSheetViewColumn *column = g_object_get_data (G_OBJECT (cell), "column");
321 PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
322 PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
323 struct variable *var;
325 g_return_if_fail (column);
326 g_return_if_fail (data_sheet);
327 g_return_if_fail (data_store);
330 g_object_ref (editable);
331 g_object_set_data_full (G_OBJECT (cell), "data-sheet-editable",
332 editable, g_object_unref);
334 var = g_object_get_data (G_OBJECT (column), "variable");
335 g_return_if_fail (var);
337 if (var_has_value_labels (var) && GTK_IS_COMBO_BOX (editable))
339 const struct val_labs *labels = var_get_value_labels (var);
340 const struct val_lab *vl;
341 GtkListStore *list_store;
343 list_store = gtk_list_store_new (1, G_TYPE_STRING);
344 for (vl = val_labs_first (labels); vl != NULL;
345 vl = val_labs_next (labels, vl))
349 gtk_list_store_append (list_store, &iter);
350 gtk_list_store_set (list_store, &iter,
351 0, val_lab_get_label (vl),
355 gtk_combo_box_set_model (GTK_COMBO_BOX (editable),
356 GTK_TREE_MODEL (list_store));
357 g_object_unref (list_store);
362 scroll_to_bottom (GtkWidget *widget,
363 GtkRequisition *requisition,
364 gpointer unused UNUSED)
366 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
367 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
368 GtkAdjustment *vadjust;
370 vadjust = pspp_sheet_view_get_vadjustment (sheet_view);
371 gtk_adjustment_set_value (vadjust, gtk_adjustment_get_upper (vadjust));
373 if (data_sheet->scroll_to_bottom_signal)
375 g_signal_handler_disconnect (data_sheet,
376 data_sheet->scroll_to_bottom_signal);
377 data_sheet->scroll_to_bottom_signal = 0;
382 on_data_column_edited (GtkCellRendererText *cell,
387 PsppSheetViewColumn *column = g_object_get_data (G_OBJECT (cell), "column");
388 PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
389 PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
390 GtkEditable *editable;
391 struct variable *var;
397 path = gtk_tree_path_new_from_string (path_string);
398 row = gtk_tree_path_get_indices (path)[0];
399 gtk_tree_path_free (path);
401 var = g_object_get_data (G_OBJECT (column), "variable");
403 new_row = row == psppire_data_store_get_case_count (data_store);
404 if (new_row && new_text[0] == '\0')
407 editable = g_object_steal_data (G_OBJECT (cell), "data-sheet-editable");
408 g_return_if_fail (editable != NULL);
409 is_val_lab = (GTK_IS_COMBO_BOX (editable)
410 && gtk_combo_box_get_active (GTK_COMBO_BOX (editable)) >= 0);
411 g_object_unref (editable);
413 psppire_data_store_set_string (data_store, new_text, row, var, is_val_lab);
415 if (new_row && !data_sheet->scroll_to_bottom_signal)
417 gtk_widget_queue_resize (GTK_WIDGET (data_sheet));
418 data_sheet->scroll_to_bottom_signal =
419 g_signal_connect (data_sheet, "size-request",
420 G_CALLBACK (scroll_to_bottom), NULL);
424 /* We could be more specific about what to redraw, if it seems
425 important for performance. */
426 gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
431 scroll_to_right (GtkWidget *widget,
432 PsppireDataSheet *data_sheet)
434 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
435 PsppSheetViewColumn *column, *prev;
436 GList *columns, *iter;
440 columns = pspp_sheet_view_get_columns (sheet_view);
441 for (iter = columns; iter; iter = iter->next)
443 PsppSheetViewColumn *c = iter->data;
444 if (g_object_get_data (G_OBJECT (c), "new-var-column"))
451 g_list_free (columns);
456 pspp_sheet_view_scroll_to_cell (sheet_view, NULL, column, FALSE, 0, 0);
462 pspp_sheet_view_get_cursor (sheet_view, &path, NULL);
465 pspp_sheet_view_set_cursor (sheet_view, path, prev, TRUE);
466 gtk_tree_path_free (path);
470 if (data_sheet->scroll_to_right_signal)
472 g_signal_handler_disconnect (widget, data_sheet->scroll_to_right_signal);
473 data_sheet->scroll_to_right_signal = 0;
478 on_new_variable_column_edited (GtkCellRendererText *cell,
483 PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
484 PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
485 PsppireDict *dict = data_store->dict;
486 struct variable *var;
491 if (new_text[0] == '\0')
493 /* User didn't enter anything so don't create a variable. */
497 path = gtk_tree_path_new_from_string (path_string);
498 row = gtk_tree_path_get_indices (path)[0];
499 gtk_tree_path_free (path);
501 if (!psppire_dict_generate_name (dict, name, sizeof name))
504 var = psppire_dict_insert_variable (dict, psppire_dict_get_var_cnt (dict),
506 g_return_if_fail (var != NULL);
508 psppire_data_store_set_string (data_store, new_text, row, var, FALSE);
510 if (!data_sheet->scroll_to_right_signal)
512 gtk_widget_queue_resize (GTK_WIDGET (data_sheet));
513 data_sheet->scroll_to_right_signal =
514 g_signal_connect_after (gtk_widget_get_toplevel (GTK_WIDGET (data_sheet)), "check-resize",
515 G_CALLBACK (scroll_to_right), data_sheet);
519 /* We could be more specific about what to redraw, if it seems
520 important for performance. */
521 gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
526 calc_width_conversion (PsppireDataSheet *data_sheet,
527 gint *base_width, gint *incr_width)
529 GtkCellRenderer *cell;
532 cell = gtk_cell_renderer_text_new ();
533 w1 = get_monospace_width (PSPP_SHEET_VIEW (data_sheet), cell, 1);
534 w10 = get_monospace_width (PSPP_SHEET_VIEW (data_sheet), cell, 10);
535 *incr_width = MAX (1, (w10 - w1) / 9);
536 *base_width = MAX (0, w10 - *incr_width * 10);
537 g_object_ref_sink (cell);
538 g_object_unref (cell);
542 display_width_from_pixel_width (PsppireDataSheet *data_sheet,
545 gint base_width, incr_width;
547 calc_width_conversion (data_sheet, &base_width, &incr_width);
548 return MAX ((pixel_width - base_width + incr_width / 2) / incr_width, 1);
552 display_width_to_pixel_width (PsppireDataSheet *data_sheet,
557 return base_width + incr_width * display_width;
561 on_data_column_resized (GObject *gobject,
565 PsppireDataSheet *data_sheet = user_data;
566 PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
567 PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (gobject);
568 struct variable *var;
572 if (data_store == NULL)
575 pixel_width = pspp_sheet_view_column_get_width (column);
576 if (pixel_width == pspp_sheet_view_column_get_fixed_width (column))
578 /* Short-circuit the expensive display_width_from_pixel_width()
579 calculation, to make loading .sav files with 2000 columns visibly
584 var = g_object_get_data (G_OBJECT (column), "variable");
585 display_width = display_width_from_pixel_width (data_sheet, pixel_width);
586 var_set_display_width (var, display_width);
590 do_data_column_popup_menu (PsppSheetViewColumn *column,
591 guint button, guint32 time)
593 GtkWidget *sheet_view = pspp_sheet_view_column_get_tree_view (column);
594 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
597 menu = get_widget_assert (data_sheet->builder, "datasheet-variable-popup");
598 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
602 on_data_column_popup_menu (PsppSheetViewColumn *column,
603 gpointer user_data UNUSED)
605 do_data_column_popup_menu (column, 0, gtk_get_current_event_time ());
609 on_column_button_press_event (PsppSheetViewColumn *column,
610 GdkEventButton *event,
611 gpointer user_data UNUSED)
613 PsppSheetSelection *selection;
614 PsppSheetView *sheet_view;
616 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
618 g_return_val_if_fail (sheet_view != NULL, FALSE);
620 selection = pspp_sheet_view_get_selection (sheet_view);
621 g_return_val_if_fail (selection != NULL, FALSE);
623 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
625 do_data_column_popup_menu (column, event->button, event->time);
628 else if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
630 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
631 struct variable *var;
633 var = g_object_get_data (G_OBJECT (column), "variable");
638 g_signal_emit_by_name (data_sheet, "var-double-clicked",
639 var_get_dict_index (var), &handled);
648 on_data_column_query_tooltip (PsppSheetViewColumn *column,
650 gpointer user_data UNUSED)
652 struct variable *var;
655 var = g_object_get_data (G_OBJECT (column), "variable");
656 g_return_val_if_fail (var != NULL, FALSE);
658 text = var_has_label (var) ? var_get_label (var) : var_get_name (var);
659 gtk_tooltip_set_text (tooltip, text);
665 add_data_column_cell_renderer (PsppireDataSheet *data_sheet,
666 PsppSheetViewColumn *column)
668 GtkCellRenderer *cell;
669 struct variable *var;
671 var = g_object_get_data (G_OBJECT (column), "variable");
672 g_return_if_fail (var != NULL);
674 if (var_has_value_labels (var))
676 cell = gtk_cell_renderer_combo_new ();
677 g_object_set (G_OBJECT (cell),
683 cell = gtk_cell_renderer_text_new ();
685 g_signal_connect (cell, "editing-started",
686 G_CALLBACK (on_data_column_editing_started), NULL);
687 g_signal_connect (cell, "edited", G_CALLBACK (on_data_column_edited), NULL);
689 g_object_set_data (G_OBJECT (cell), "column", column);
690 g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet);
692 pspp_sheet_view_column_clear (column);
693 pspp_sheet_view_column_pack_start (column, cell, TRUE);
695 pspp_sheet_view_column_set_cell_data_func (
696 column, cell, render_data_cell, data_sheet, NULL);
699 static PsppSheetViewColumn *
700 make_data_column (PsppireDataSheet *data_sheet, gint dict_idx,
701 gint base_width, gint incr_width)
703 PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
704 struct variable *var;
705 PsppSheetViewColumn *column;
709 var = psppire_dict_get_variable (data_store->dict, dict_idx);
711 column = pspp_sheet_view_column_new ();
713 name = escape_underscores (var_get_name (var));
714 pspp_sheet_view_column_set_title (column, name);
717 g_object_set_data (G_OBJECT (column), "variable", var);
719 width = display_width_to_pixel_width (data_sheet,
720 var_get_display_width (var),
721 base_width, incr_width);
722 pspp_sheet_view_column_set_min_width (column, 10);
723 pspp_sheet_view_column_set_fixed_width (column, width);
724 pspp_sheet_view_column_set_resizable (column, TRUE);
726 pspp_sheet_view_column_set_clickable (column, TRUE);
727 g_signal_connect (column, "notify::width",
728 G_CALLBACK (on_data_column_resized), data_sheet);
730 g_signal_connect (column, "button-press-event",
731 G_CALLBACK (on_column_button_press_event),
733 g_signal_connect (column, "query-tooltip",
734 G_CALLBACK (on_data_column_query_tooltip), NULL);
735 g_signal_connect (column, "popup-menu",
736 G_CALLBACK (on_data_column_popup_menu), data_sheet);
738 add_data_column_cell_renderer (data_sheet, column);
744 make_new_variable_column (PsppireDataSheet *data_sheet,
745 gint base_width, gint incr_width)
747 PsppSheetViewColumn *column;
748 GtkCellRenderer *cell;
751 cell = gtk_cell_renderer_text_new ();
752 g_object_set (cell, "editable", TRUE, NULL);
754 g_signal_connect (cell, "edited", G_CALLBACK (on_new_variable_column_edited),
757 column = pspp_sheet_view_column_new_with_attributes ("", cell, NULL);
758 g_object_set_data (G_OBJECT (column), "new-var-column", column);
760 width = display_width_to_pixel_width (data_sheet, 8, base_width, incr_width);
761 pspp_sheet_view_column_set_min_width (column, 10);
762 pspp_sheet_view_column_set_fixed_width (column, width);
763 pspp_sheet_view_column_set_tabbable (column, FALSE);
765 g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet);
766 g_signal_connect (column, "button-press-event",
767 G_CALLBACK (on_column_button_press_event),
769 g_signal_connect (column, "popup-menu",
770 G_CALLBACK (on_data_column_popup_menu), data_sheet);
772 pspp_sheet_view_column_set_visible (column, data_sheet->may_create_vars);
774 pspp_sheet_view_append_column (PSPP_SHEET_VIEW (data_sheet), column);
775 data_sheet->new_variable_column = column;
779 psppire_data_sheet_model_changed (GObject *gobject,
783 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (gobject);
784 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
785 PsppireDataStore *data_store;
787 /* Remove old columns. */
790 PsppSheetViewColumn *column = pspp_sheet_view_get_column (sheet_view, 0);
794 pspp_sheet_view_remove_column (sheet_view, column);
796 data_sheet->new_variable_column = NULL;
798 if (pspp_sheet_view_get_model (sheet_view) == NULL)
800 /* Don't create any columns at all if there's no model. Otherwise we'll
801 create some columns as part of the "dispose" callback for the sheet
802 view, which sets the model to NULL. That causes warnings to be
803 logged and is obviously undesirable in any case. */
807 /* Add new columns. */
808 data_store = psppire_data_sheet_get_data_store (data_sheet);
809 if (data_store != NULL)
811 gint base_width, incr_width;
814 calc_width_conversion (data_sheet, &base_width, &incr_width);
816 make_row_number_column (data_sheet, data_store);
817 for (i = 0; i < psppire_dict_get_var_cnt (data_store->dict); i++)
819 PsppSheetViewColumn *column;
821 column = make_data_column (data_sheet, i, base_width, incr_width);
822 pspp_sheet_view_append_column (sheet_view, column);
824 make_new_variable_column (data_sheet, base_width, incr_width);
835 PROP_MAY_CREATE_VARS,
836 PROP_MAY_DELETE_VARS,
841 psppire_data_sheet_set_property (GObject *object,
846 PsppireDataSheet *obj = PSPPIRE_DATA_SHEET (object);
850 case PROP_DATA_STORE:
851 psppire_data_sheet_set_data_store (
852 obj, PSPPIRE_DATA_STORE (g_value_get_object (value)));
855 case PROP_VALUE_LABELS:
856 psppire_data_sheet_set_value_labels (obj, g_value_get_boolean (value));
859 case PROP_CASE_NUMBERS:
860 psppire_data_sheet_set_case_numbers (obj, g_value_get_boolean (value));
863 case PROP_CURRENT_CASE:
864 psppire_data_sheet_goto_case (obj, g_value_get_long (value));
867 case PROP_MAY_CREATE_VARS:
868 psppire_data_sheet_set_may_create_vars (obj,
869 g_value_get_boolean (value));
872 case PROP_MAY_DELETE_VARS:
873 psppire_data_sheet_set_may_delete_vars (obj,
874 g_value_get_boolean (value));
877 case PROP_UI_MANAGER:
879 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
885 psppire_data_sheet_get_property (GObject *object,
890 PsppireDataSheet *obj = PSPPIRE_DATA_SHEET (object);
894 case PROP_DATA_STORE:
895 g_value_set_object (value, psppire_data_sheet_get_data_store (obj));
898 case PROP_VALUE_LABELS:
899 g_value_set_boolean (value, psppire_data_sheet_get_value_labels (obj));
902 case PROP_CASE_NUMBERS:
903 g_value_set_boolean (value, psppire_data_sheet_get_case_numbers (obj));
906 case PROP_CURRENT_CASE:
907 g_value_set_long (value, psppire_data_sheet_get_selected_case (obj));
910 case PROP_MAY_CREATE_VARS:
911 g_value_set_boolean (value, obj->may_create_vars);
914 case PROP_MAY_DELETE_VARS:
915 g_value_set_boolean (value, obj->may_delete_vars);
918 case PROP_UI_MANAGER:
919 g_value_set_object (value, psppire_data_sheet_get_ui_manager (obj));
923 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
929 psppire_data_sheet_get_value_labels (const PsppireDataSheet *ds)
931 return ds->show_value_labels;
935 psppire_data_sheet_set_value_labels (PsppireDataSheet *ds,
936 gboolean show_value_labels)
938 show_value_labels = !!show_value_labels;
939 if (show_value_labels != ds->show_value_labels)
941 ds->show_value_labels = show_value_labels;
942 g_object_notify (G_OBJECT (ds), "value-labels");
943 gtk_widget_queue_draw (GTK_WIDGET (ds));
945 /* Make the cell being edited refresh too. */
946 pspp_sheet_view_stop_editing (PSPP_SHEET_VIEW (ds), TRUE);
951 psppire_data_sheet_get_case_numbers (const PsppireDataSheet *ds)
953 return ds->show_case_numbers;
957 psppire_data_sheet_set_case_numbers (PsppireDataSheet *ds,
958 gboolean show_case_numbers)
960 show_case_numbers = !!show_case_numbers;
961 if (show_case_numbers != ds->show_case_numbers)
963 PsppSheetViewColumn *column;
965 ds->show_case_numbers = show_case_numbers;
966 column = pspp_sheet_view_get_column (PSPP_SHEET_VIEW (ds), 0);
968 pspp_sheet_view_column_set_visible (column, show_case_numbers);
970 g_object_notify (G_OBJECT (ds), "case-numbers");
971 gtk_widget_queue_draw (GTK_WIDGET (ds));
976 psppire_data_sheet_get_may_create_vars (PsppireDataSheet *data_sheet)
978 return data_sheet->may_create_vars;
982 psppire_data_sheet_set_may_create_vars (PsppireDataSheet *data_sheet,
983 gboolean may_create_vars)
985 if (data_sheet->may_create_vars != may_create_vars)
987 data_sheet->may_create_vars = may_create_vars;
988 if (data_sheet->new_variable_column)
989 pspp_sheet_view_column_set_visible (data_sheet->new_variable_column,
992 on_selection_changed (pspp_sheet_view_get_selection (
993 PSPP_SHEET_VIEW (data_sheet)), NULL);
998 psppire_data_sheet_get_may_delete_vars (PsppireDataSheet *data_sheet)
1000 return data_sheet->may_delete_vars;
1004 psppire_data_sheet_set_may_delete_vars (PsppireDataSheet *data_sheet,
1005 gboolean may_delete_vars)
1007 if (data_sheet->may_delete_vars != may_delete_vars)
1009 data_sheet->may_delete_vars = may_delete_vars;
1010 on_selection_changed (pspp_sheet_view_get_selection (
1011 PSPP_SHEET_VIEW (data_sheet)), NULL);
1015 static PsppSheetViewColumn *
1016 psppire_data_sheet_find_column_for_variable (PsppireDataSheet *data_sheet,
1019 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1020 PsppireDataStore *data_store;
1021 PsppSheetViewColumn *column;
1022 struct variable *var;
1025 data_store = psppire_data_sheet_get_data_store (data_sheet);
1026 g_return_val_if_fail (data_store != NULL, NULL);
1027 g_return_val_if_fail (data_store->dict != NULL, NULL);
1029 var = psppire_dict_get_variable (data_store->dict, dict_index);
1030 g_return_val_if_fail (var != NULL, NULL);
1033 list = pspp_sheet_view_get_columns (sheet_view);
1034 for (iter = list; iter != NULL; iter = iter->next)
1036 PsppSheetViewColumn *c = iter->data;
1039 v = g_object_get_data (G_OBJECT (c), "variable");
1052 psppire_data_sheet_goto_variable (PsppireDataSheet *data_sheet,
1055 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1056 PsppSheetViewColumn *column;
1058 column = psppire_data_sheet_find_column_for_variable (data_sheet,
1064 gint row = psppire_data_sheet_get_current_case (data_sheet);
1065 path = gtk_tree_path_new_from_indices (row >= 0 ? row : 0, -1);
1067 pspp_sheet_view_scroll_to_cell (sheet_view, path, column,
1069 pspp_sheet_view_set_cursor (sheet_view, path, column, FALSE);
1070 gtk_tree_path_free (path);
1075 psppire_data_sheet_get_current_variable (const PsppireDataSheet *data_sheet)
1077 PsppSheetSelection *selection;
1078 struct variable *var;
1079 GList *selected_columns;
1082 selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (data_sheet));
1083 selected_columns = pspp_sheet_selection_get_selected_columns (selection);
1086 for (iter = selected_columns; iter != NULL; iter = iter->next)
1088 PsppSheetViewColumn *column = iter->data;
1089 struct variable *v = g_object_get_data (G_OBJECT (column), "variable");
1102 g_list_free (selected_columns);
1108 psppire_data_sheet_goto_case (PsppireDataSheet *data_sheet, gint case_index)
1110 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1111 PsppireDataStore *store = data_sheet->data_store;
1112 PsppSheetSelection *selection;
1115 g_return_if_fail (case_index >= 0);
1116 g_return_if_fail (case_index < psppire_data_store_get_case_count (store));
1118 path = gtk_tree_path_new_from_indices (case_index, -1);
1120 /* Select the case. */
1121 selection = pspp_sheet_view_get_selection (sheet_view);
1122 pspp_sheet_selection_unselect_all (selection);
1123 pspp_sheet_selection_select_path (selection, path);
1124 pspp_sheet_selection_select_all_columns (selection);
1126 /* Scroll so that the case is visible. */
1127 pspp_sheet_view_scroll_to_cell (sheet_view, path, NULL, FALSE, 0.0, 0.0);
1129 gtk_tree_path_free (path);
1132 /* Returns the 0-based index of a selected case, if there is at least one, and
1135 If more than one case is selected, returns the one with the smallest index,
1136 that is, the index of the case closest to the beginning of the file. The
1137 row that can be used to insert a new case is not considered a case. */
1139 psppire_data_sheet_get_selected_case (const PsppireDataSheet *data_sheet)
1141 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1142 PsppireDataStore *store = data_sheet->data_store;
1143 const struct range_set_node *node;
1144 PsppSheetSelection *selection;
1145 struct range_set *rows;
1148 selection = pspp_sheet_view_get_selection (sheet_view);
1149 rows = pspp_sheet_selection_get_range_set (selection);
1150 node = range_set_first (rows);
1151 row = (node && node->start < psppire_data_store_get_case_count (store)
1154 range_set_destroy (rows);
1159 /* Returns the 0-based index of a selected case, if exactly one case is
1160 selected, and -1 otherwise. Returns -1 if the row that can be used to
1161 insert a new case is selected. */
1163 psppire_data_sheet_get_current_case (const PsppireDataSheet *data_sheet)
1165 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1166 PsppireDataStore *store = data_sheet->data_store;
1167 const struct range_set_node *node;
1168 PsppSheetSelection *selection;
1169 struct range_set *rows;
1172 selection = pspp_sheet_view_get_selection (sheet_view);
1173 if (pspp_sheet_selection_count_selected_rows (selection) != 1)
1176 rows = pspp_sheet_selection_get_range_set (selection);
1177 node = range_set_first (rows);
1178 row = (node && node->start < psppire_data_store_get_case_count (store)
1181 range_set_destroy (rows);
1187 psppire_data_sheet_get_ui_manager (PsppireDataSheet *data_sheet)
1189 if (data_sheet->uim == NULL)
1192 GTK_UI_MANAGER (get_object_assert (data_sheet->builder,
1194 GTK_TYPE_UI_MANAGER));
1195 g_object_ref (data_sheet->uim);
1198 return data_sheet->uim;
1202 psppire_data_sheet_dispose (GObject *object)
1204 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (object);
1206 if (data_sheet->dispose_has_run)
1209 data_sheet->dispose_has_run = TRUE;
1211 psppire_data_sheet_unset_data_store (data_sheet);
1213 g_object_unref (data_sheet->builder);
1215 if (data_sheet->uim)
1216 g_object_unref (data_sheet->uim);
1218 G_OBJECT_CLASS (psppire_data_sheet_parent_class)->dispose (object);
1222 psppire_data_sheet_map (GtkWidget *widget)
1226 GTK_WIDGET_CLASS (psppire_data_sheet_parent_class)->map (widget);
1228 clip = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1229 g_signal_connect (clip, "owner-change", G_CALLBACK (on_owner_change),
1231 on_owner_change (clip, NULL, widget);
1235 psppire_data_sheet_class_init (PsppireDataSheetClass *class)
1237 GObjectClass *gobject_class;
1238 GtkWidgetClass *widget_class;
1240 gobject_class = G_OBJECT_CLASS (class);
1241 gobject_class->set_property = psppire_data_sheet_set_property;
1242 gobject_class->get_property = psppire_data_sheet_get_property;
1243 gobject_class->dispose = psppire_data_sheet_dispose;
1245 widget_class = GTK_WIDGET_CLASS (class);
1246 widget_class->map = psppire_data_sheet_map;
1248 g_signal_new ("var-double-clicked",
1249 G_OBJECT_CLASS_TYPE (gobject_class),
1252 g_signal_accumulator_true_handled, NULL,
1253 psppire_marshal_BOOLEAN__INT,
1254 G_TYPE_BOOLEAN, 1, G_TYPE_INT);
1256 g_object_class_install_property (
1257 gobject_class, PROP_DATA_STORE,
1258 g_param_spec_object ("data-store",
1260 "The data store for the data sheet to display.",
1261 PSPPIRE_TYPE_DATA_STORE,
1262 G_PARAM_WRITABLE | G_PARAM_READABLE));
1264 g_object_class_install_property (
1265 gobject_class, PROP_VALUE_LABELS,
1266 g_param_spec_boolean ("value-labels",
1268 "Whether or not the data sheet should display labels instead of values",
1270 G_PARAM_WRITABLE | G_PARAM_READABLE));
1272 g_object_class_install_property (
1273 gobject_class, PROP_CASE_NUMBERS,
1274 g_param_spec_boolean ("case-numbers",
1276 "Whether or not the data sheet should display case numbers",
1278 G_PARAM_WRITABLE | G_PARAM_READABLE));
1280 g_object_class_install_property (
1283 g_param_spec_long ("current-case",
1285 "Zero based number of the selected case",
1288 G_PARAM_WRITABLE | G_PARAM_READABLE));
1290 g_object_class_install_property (
1292 PROP_MAY_CREATE_VARS,
1293 g_param_spec_boolean ("may-create-vars",
1294 "May create variables",
1295 "Whether the user may create more variables",
1297 G_PARAM_READWRITE));
1299 g_object_class_install_property (
1301 PROP_MAY_DELETE_VARS,
1302 g_param_spec_boolean ("may-delete-vars",
1303 "May delete variables",
1304 "Whether the user may delete variables",
1306 G_PARAM_READWRITE));
1308 g_object_class_install_property (
1311 g_param_spec_object ("ui-manager",
1313 "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.",
1314 GTK_TYPE_UI_MANAGER,
1319 do_popup_menu (GtkWidget *widget, guint button, guint32 time)
1321 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
1324 menu = get_widget_assert (data_sheet->builder, "datasheet-cases-popup");
1325 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
1329 on_popup_menu (GtkWidget *widget, gpointer user_data UNUSED)
1331 do_popup_menu (widget, 0, gtk_get_current_event_time ());
1335 on_button_pressed (GtkWidget *widget, GdkEventButton *event,
1336 gpointer user_data UNUSED)
1338 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
1340 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
1342 PsppSheetSelection *selection;
1344 selection = pspp_sheet_view_get_selection (sheet_view);
1345 if (pspp_sheet_selection_count_selected_rows (selection) <= 1)
1349 if (pspp_sheet_view_get_path_at_pos (sheet_view, event->x, event->y,
1350 &path, NULL, NULL, NULL))
1352 pspp_sheet_selection_unselect_all (selection);
1353 pspp_sheet_selection_select_path (selection, path);
1354 pspp_sheet_selection_select_all_columns (selection);
1355 gtk_tree_path_free (path);
1359 do_popup_menu (widget, event->button, event->time);
1368 on_edit_clear_cases (GtkAction *action, PsppireDataSheet *data_sheet)
1370 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1371 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
1372 const struct range_set_node *node;
1373 struct range_set *selected;
1375 selected = pspp_sheet_selection_get_range_set (selection);
1376 for (node = range_set_last (selected); node != NULL;
1377 node = range_set_prev (selected, node))
1379 unsigned long int start = range_set_node_get_start (node);
1380 unsigned long int count = range_set_node_get_width (node);
1382 psppire_data_store_delete_cases (data_sheet->data_store, start, count);
1384 range_set_destroy (selected);
1388 on_selection_changed (PsppSheetSelection *selection,
1389 gpointer user_data UNUSED)
1391 PsppSheetView *sheet_view = pspp_sheet_selection_get_tree_view (selection);
1392 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
1393 gint n_selected_rows;
1394 gboolean any_variables_selected;
1395 gboolean may_delete_cases, may_delete_vars, may_insert_vars;
1400 n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
1402 action = get_action_assert (data_sheet->builder, "edit_insert-case");
1403 gtk_action_set_sensitive (action, n_selected_rows > 0);
1405 switch (n_selected_rows)
1408 may_delete_cases = FALSE;
1412 /* The row used for inserting new cases cannot be deleted. */
1413 path = gtk_tree_path_new_from_indices (
1414 psppire_data_store_get_case_count (data_sheet->data_store), -1);
1415 may_delete_cases = !pspp_sheet_selection_path_is_selected (selection,
1417 gtk_tree_path_free (path);
1421 may_delete_cases = TRUE;
1424 action = get_action_assert (data_sheet->builder, "edit_clear-cases");
1425 gtk_action_set_sensitive (action, may_delete_cases);
1427 any_variables_selected = FALSE;
1428 may_delete_vars = may_insert_vars = FALSE;
1429 list = pspp_sheet_selection_get_selected_columns (selection);
1430 for (iter = list; iter != NULL; iter = iter->next)
1432 PsppSheetViewColumn *column = iter->data;
1433 struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
1437 may_delete_vars = may_insert_vars = TRUE;
1438 any_variables_selected = TRUE;
1441 if (g_object_get_data (G_OBJECT (column), "new-var-column") != NULL)
1442 may_insert_vars = TRUE;
1446 may_insert_vars = may_insert_vars && data_sheet->may_create_vars;
1447 may_delete_vars = may_delete_vars && data_sheet->may_delete_vars;
1449 action = get_action_assert (data_sheet->builder, "edit_insert-variable");
1450 gtk_action_set_sensitive (action, may_insert_vars);
1452 action = get_action_assert (data_sheet->builder, "edit_clear-variables");
1453 gtk_action_set_sensitive (action, may_delete_vars);
1455 action = get_action_assert (data_sheet->builder, "sort-up");
1456 gtk_action_set_sensitive (action, may_delete_vars);
1458 action = get_action_assert (data_sheet->builder, "sort-down");
1459 gtk_action_set_sensitive (action, may_delete_vars);
1461 psppire_data_sheet_update_clip_actions (data_sheet);
1462 psppire_data_sheet_update_primary_selection (data_sheet,
1463 (n_selected_rows > 0
1464 && any_variables_selected));
1468 psppire_data_sheet_get_selected_range (PsppireDataSheet *data_sheet,
1469 struct range_set **rowsp,
1470 struct range_set **colsp)
1472 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1473 PsppireDataStore *data_store = data_sheet->data_store;
1474 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
1475 unsigned long n_cases;
1476 struct range_set *rows, *cols;
1479 if (data_store == NULL)
1481 n_cases = psppire_data_store_get_case_count (data_store);
1483 rows = pspp_sheet_selection_get_range_set (selection);
1484 range_set_set0 (rows, n_cases, ULONG_MAX - n_cases);
1485 if (range_set_is_empty (rows))
1487 range_set_destroy (rows);
1491 cols = range_set_create ();
1492 list = pspp_sheet_selection_get_selected_columns (selection);
1493 for (iter = list; iter != NULL; iter = iter->next)
1495 PsppSheetViewColumn *column = iter->data;
1496 struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
1499 range_set_set1 (cols, var_get_dict_index (var), 1);
1502 if (range_set_is_empty (cols))
1504 range_set_destroy (rows);
1505 range_set_destroy (cols);
1515 on_edit_insert_case (GtkAction *action, PsppireDataSheet *data_sheet)
1517 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1518 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
1519 PsppireDataStore *data_store = data_sheet->data_store;
1520 struct range_set *selected;
1523 selected = pspp_sheet_selection_get_range_set (selection);
1524 row = range_set_scan (selected, 0);
1525 range_set_destroy (selected);
1527 if (row <= psppire_data_store_get_case_count (data_store))
1528 psppire_data_store_insert_new_case (data_store, row);
1532 on_edit_insert_variable (GtkAction *action, PsppireDataSheet *data_sheet)
1534 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1535 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
1536 PsppireDict *dict = data_sheet->data_store->dict;
1537 PsppSheetViewColumn *column;
1538 struct variable *var;
1543 list = pspp_sheet_selection_get_selected_columns (selection);
1546 column = list->data;
1549 var = g_object_get_data (G_OBJECT (column), "variable");
1550 index = var ? var_get_dict_index (var) : psppire_dict_get_var_cnt (dict);
1551 if (psppire_dict_generate_name (dict, name, sizeof name))
1552 psppire_dict_insert_variable (dict, index, name);
1556 on_edit_clear_variables (GtkAction *action, PsppireDataSheet *data_sheet)
1558 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1559 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
1560 PsppireDict *dict = data_sheet->data_store->dict;
1563 list = pspp_sheet_selection_get_selected_columns (selection);
1566 list = g_list_reverse (list);
1567 for (iter = list; iter; iter = iter->next)
1569 PsppSheetViewColumn *column = iter->data;
1570 struct variable *var;
1572 var = g_object_get_data (G_OBJECT (column), "variable");
1574 psppire_dict_delete_variables (dict, var_get_dict_index (var), 1);
1586 do_sort (PsppireDataSheet *data_sheet, enum sort_order order)
1588 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1589 PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
1590 PsppireDataWindow *pdw;
1595 pdw = psppire_data_window_for_data_store (data_sheet->data_store);
1596 g_return_if_fail (pdw != NULL);
1598 list = pspp_sheet_selection_get_selected_columns (selection);
1600 syntax = g_string_new ("SORT CASES BY");
1602 for (iter = list; iter; iter = iter->next)
1604 PsppSheetViewColumn *column = iter->data;
1605 struct variable *var;
1607 var = g_object_get_data (G_OBJECT (column), "variable");
1610 g_string_append_printf (syntax, " %s", var_get_name (var));
1616 if (order == SORT_DESCEND)
1617 g_string_append (syntax, " (DOWN)");
1618 g_string_append_c (syntax, '.');
1619 execute_const_syntax_string (pdw, syntax->str);
1621 g_string_free (syntax, TRUE);
1625 on_sort_up (GtkAction *action, PsppireDataSheet *data_sheet)
1627 do_sort (data_sheet, SORT_ASCEND);
1631 on_sort_down (GtkAction *action, PsppireDataSheet *data_sheet)
1633 do_sort (data_sheet, SORT_DESCEND);
1637 on_edit_goto_case (GtkAction *action, PsppireDataSheet *data_sheet)
1639 goto_case_dialog (data_sheet);
1643 on_edit_find (GtkAction *action, PsppireDataSheet *data_sheet)
1645 PsppireDataWindow *pdw;
1647 pdw = psppire_data_window_for_data_store (data_sheet->data_store);
1648 g_return_if_fail (pdw != NULL);
1654 on_edit_copy (GtkAction *action, PsppireDataSheet *data_sheet)
1656 psppire_data_sheet_set_clip (data_sheet, FALSE);
1660 on_edit_cut (GtkAction *action, PsppireDataSheet *data_sheet)
1662 psppire_data_sheet_set_clip (data_sheet, TRUE);
1666 on_edit_paste (GtkAction *action, PsppireDataSheet *data_sheet)
1668 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (data_sheet));
1669 GtkClipboard *clipboard =
1670 gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
1672 gtk_clipboard_request_contents (clipboard,
1673 gdk_atom_intern ("UTF8_STRING", TRUE),
1674 psppire_data_sheet_clip_received_cb,
1679 psppire_data_sheet_init (PsppireDataSheet *obj)
1681 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (obj);
1684 obj->show_value_labels = FALSE;
1685 obj->show_case_numbers = TRUE;
1686 obj->may_create_vars = TRUE;
1687 obj->may_delete_vars = TRUE;
1689 obj->owns_primary_selection = FALSE;
1691 obj->scroll_to_bottom_signal = 0;
1692 obj->scroll_to_right_signal = 0;
1693 obj->new_variable_column = NULL;
1694 obj->container = NULL;
1697 obj->dispose_has_run = FALSE;
1699 pspp_sheet_view_set_special_cells (sheet_view, PSPP_SHEET_VIEW_SPECIAL_CELLS_YES);
1701 g_signal_connect (obj, "notify::model",
1702 G_CALLBACK (psppire_data_sheet_model_changed), NULL);
1704 pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
1705 pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
1706 PSPP_SHEET_SELECTION_RECTANGLE);
1708 g_object_set (G_OBJECT (obj), "has-tooltip", TRUE, (void *) NULL);
1709 g_signal_connect (obj, "query-tooltip",
1710 G_CALLBACK (on_query_tooltip), NULL);
1711 g_signal_connect (obj, "button-press-event",
1712 G_CALLBACK (on_button_pressed), NULL);
1713 g_signal_connect (obj, "popup-menu", G_CALLBACK (on_popup_menu), NULL);
1715 obj->builder = builder_new ("data-sheet.ui");
1717 action = get_action_assert (obj->builder, "edit_clear-cases");
1718 g_signal_connect (action, "activate", G_CALLBACK (on_edit_clear_cases),
1720 gtk_action_set_sensitive (action, FALSE);
1721 g_signal_connect (pspp_sheet_view_get_selection (sheet_view),
1722 "changed", G_CALLBACK (on_selection_changed), NULL);
1724 action = get_action_assert (obj->builder, "edit_insert-case");
1725 g_signal_connect (action, "activate", G_CALLBACK (on_edit_insert_case),
1728 action = get_action_assert (obj->builder, "edit_insert-variable");
1729 g_signal_connect (action, "activate", G_CALLBACK (on_edit_insert_variable),
1732 action = get_action_assert (obj->builder, "edit_goto-case");
1733 g_signal_connect (action, "activate", G_CALLBACK (on_edit_goto_case),
1736 action = get_action_assert (obj->builder, "edit_copy");
1737 g_signal_connect (action, "activate", G_CALLBACK (on_edit_copy), obj);
1739 action = get_action_assert (obj->builder, "edit_cut");
1740 g_signal_connect (action, "activate", G_CALLBACK (on_edit_cut), obj);
1742 action = get_action_assert (obj->builder, "edit_paste");
1743 g_signal_connect (action, "activate", G_CALLBACK (on_edit_paste), obj);
1745 action = get_action_assert (obj->builder, "edit_clear-variables");
1746 g_signal_connect (action, "activate", G_CALLBACK (on_edit_clear_variables),
1749 action = get_action_assert (obj->builder, "edit_find");
1750 g_signal_connect (action, "activate", G_CALLBACK (on_edit_find), obj);
1752 action = get_action_assert (obj->builder, "sort-up");
1753 g_signal_connect (action, "activate", G_CALLBACK (on_sort_up), obj);
1755 action = get_action_assert (obj->builder, "sort-down");
1756 g_signal_connect (action, "activate", G_CALLBACK (on_sort_down), obj);
1761 psppire_data_sheet_new (void)
1763 return g_object_new (PSPP_TYPE_DATA_SHEET, NULL);
1767 psppire_data_sheet_get_data_store (PsppireDataSheet *data_sheet)
1769 return data_sheet->data_store;
1773 refresh_model (PsppireDataSheet *data_sheet)
1775 pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet), NULL);
1777 if (data_sheet->data_store != NULL)
1779 PsppireEmptyListStore *model;
1783 n_rows = psppire_data_store_get_case_count (data_sheet->data_store) + 1;
1784 model = psppire_empty_list_store_new (n_rows);
1785 pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet),
1786 GTK_TREE_MODEL (model));
1787 g_object_unref (model);
1789 action = get_action_assert (data_sheet->builder, "edit_copy");
1790 g_signal_connect (action, "activate", G_CALLBACK (on_edit_copy),
1796 on_case_inserted (PsppireDataStore *data_store, gint row,
1797 PsppireDataSheet *data_sheet)
1799 PsppireEmptyListStore *empty_list_store;
1800 GtkTreeModel *tree_model;
1803 g_return_if_fail (data_store == data_sheet->data_store);
1805 n_rows = psppire_data_store_get_case_count (data_store) + 1;
1806 if (row == n_rows - 1)
1809 tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
1810 empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
1811 psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
1812 psppire_empty_list_store_row_inserted (empty_list_store, row);
1816 on_cases_deleted (PsppireDataStore *data_store, gint first, gint n_cases,
1817 PsppireDataSheet *data_sheet)
1820 g_return_if_fail (data_store == data_sheet->data_store);
1824 /* This is a bit of a cop-out. We could do better, if it ever turns out
1825 that this performs too poorly. */
1826 refresh_model (data_sheet);
1830 PsppireEmptyListStore *empty_list_store;
1831 GtkTreeModel *tree_model;
1832 gint n_rows = psppire_data_store_get_case_count (data_store) + 1;
1834 tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
1835 empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
1836 psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
1837 psppire_empty_list_store_row_deleted (empty_list_store, first);
1842 on_case_change (PsppireDataStore *data_store, gint row,
1843 PsppireDataSheet *data_sheet)
1845 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1847 pspp_sheet_view_stop_editing (sheet_view, TRUE);
1848 gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
1852 on_backend_changed (PsppireDataStore *data_store,
1853 PsppireDataSheet *data_sheet)
1855 g_return_if_fail (data_store == data_sheet->data_store);
1856 refresh_model (data_sheet);
1860 on_variable_display_width_changed (PsppireDict *dict, int dict_index,
1861 PsppireDataSheet *data_sheet)
1863 PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
1864 PsppSheetViewColumn *column;
1865 struct variable *var;
1869 g_return_if_fail (data_sheet->data_store != NULL);
1870 g_return_if_fail (dict == data_sheet->data_store->dict);
1872 column = psppire_data_sheet_find_column_for_variable (data_sheet,
1877 var = psppire_dict_get_variable (data_store->dict, dict_index);
1878 g_return_if_fail (var != NULL);
1880 pixel_width = pspp_sheet_view_column_get_fixed_width (column);
1881 display_width = display_width_from_pixel_width (data_sheet, pixel_width);
1882 if (display_width != var_get_display_width (var))
1884 gint base_width, incr_width;
1886 display_width = var_get_display_width (var);
1887 calc_width_conversion (data_sheet, &base_width, &incr_width);
1888 pixel_width = display_width_to_pixel_width (data_sheet, display_width,
1889 base_width, incr_width);
1890 pspp_sheet_view_column_set_fixed_width (column, pixel_width);
1895 on_variable_changed (PsppireDict *dict, int dict_index,
1896 PsppireDataSheet *data_sheet)
1898 PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
1899 PsppSheetViewColumn *column;
1900 GtkCellRenderer *cell;
1901 struct variable *var;
1905 g_return_if_fail (data_sheet->data_store != NULL);
1906 g_return_if_fail (dict == data_sheet->data_store->dict);
1908 column = psppire_data_sheet_find_column_for_variable (data_sheet,
1913 var = psppire_dict_get_variable (data_store->dict, dict_index);
1914 g_return_if_fail (var != NULL);
1916 name = escape_underscores (var_get_name (var));
1917 if (strcmp (name, pspp_sheet_view_column_get_title (column)))
1918 pspp_sheet_view_column_set_title (column, name);
1921 cells = pspp_sheet_view_column_get_cell_renderers (column);
1922 g_return_if_fail (cells);
1924 g_list_free (cells);
1926 if (var_has_value_labels (var) != GTK_IS_CELL_RENDERER_COMBO (cell))
1928 /* Stop editing before we delete and replace the cell renderers.
1929 Otherwise if this column is currently being edited, an eventual call
1930 to pspp_sheet_view_stop_editing() will obtain a NULL cell and pass
1931 that to gtk_cell_renderer_stop_editing(), which causes a critical.
1933 It's possible that this is a bug in PsppSheetView, and it's possible
1934 that PsppSheetView inherits that from GtkTreeView, but I haven't
1935 investigated yet. */
1936 pspp_sheet_view_stop_editing (PSPP_SHEET_VIEW (data_sheet), TRUE);
1938 add_data_column_cell_renderer (data_sheet, column);
1943 on_variable_inserted (PsppireDict *dict, int var_index,
1944 PsppireDataSheet *data_sheet)
1946 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1947 gint base_width, incr_width;
1948 PsppSheetViewColumn *column;
1950 calc_width_conversion (data_sheet, &base_width, &incr_width);
1951 column = make_data_column (data_sheet, var_index, base_width, incr_width);
1952 pspp_sheet_view_insert_column (sheet_view, column, var_index + 1);
1956 on_variable_deleted (PsppireDict *dict,
1957 const struct variable *var, int case_idx, int width,
1958 PsppireDataSheet *data_sheet)
1960 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
1961 GList *columns, *iter;
1963 columns = pspp_sheet_view_get_columns (sheet_view);
1964 for (iter = columns; iter != NULL; iter = iter->next)
1966 PsppSheetViewColumn *column = iter->data;
1967 const struct variable *column_var;
1969 column_var = g_object_get_data (G_OBJECT (column), "variable");
1970 if (column_var == var)
1971 pspp_sheet_view_remove_column (sheet_view, column);
1973 g_list_free (columns);
1977 psppire_data_sheet_unset_data_store (PsppireDataSheet *data_sheet)
1979 PsppireDataStore *store = data_sheet->data_store;
1984 data_sheet->data_store = NULL;
1986 g_signal_handlers_disconnect_by_func (
1987 store, G_CALLBACK (on_backend_changed), data_sheet);
1988 g_signal_handlers_disconnect_by_func (
1989 store, G_CALLBACK (on_case_inserted), data_sheet);
1990 g_signal_handlers_disconnect_by_func (
1991 store, G_CALLBACK (on_cases_deleted), data_sheet);
1992 g_signal_handlers_disconnect_by_func (
1993 store, G_CALLBACK (on_case_change), data_sheet);
1995 g_signal_handlers_disconnect_by_func (
1996 store->dict, G_CALLBACK (on_variable_changed), data_sheet);
1997 g_signal_handlers_disconnect_by_func (
1998 store->dict, G_CALLBACK (on_variable_display_width_changed), data_sheet);
1999 g_signal_handlers_disconnect_by_func (
2000 store->dict, G_CALLBACK (on_variable_inserted), data_sheet);
2001 g_signal_handlers_disconnect_by_func (
2002 store->dict, G_CALLBACK (on_variable_deleted), data_sheet);
2004 g_object_unref (store);
2008 psppire_data_sheet_set_data_store (PsppireDataSheet *data_sheet,
2009 PsppireDataStore *data_store)
2011 psppire_data_sheet_unset_data_store (data_sheet);
2013 data_sheet->data_store = data_store;
2014 if (data_store != NULL)
2016 g_object_ref (data_store);
2017 g_signal_connect (data_store, "backend-changed",
2018 G_CALLBACK (on_backend_changed), data_sheet);
2019 g_signal_connect (data_store, "case-inserted",
2020 G_CALLBACK (on_case_inserted), data_sheet);
2021 g_signal_connect (data_store, "cases-deleted",
2022 G_CALLBACK (on_cases_deleted), data_sheet);
2023 g_signal_connect (data_store, "case-changed",
2024 G_CALLBACK (on_case_change), data_sheet);
2026 /* XXX it's unclean to hook into the dict this way--what if the dict
2027 changes? As of this writing, though, nothing ever changes the
2028 data_store's dict. */
2029 g_signal_connect (data_store->dict, "variable-changed",
2030 G_CALLBACK (on_variable_changed),
2032 g_signal_connect (data_store->dict, "variable-display-width-changed",
2033 G_CALLBACK (on_variable_display_width_changed),
2035 g_signal_connect (data_store->dict, "variable-inserted",
2036 G_CALLBACK (on_variable_inserted), data_sheet);
2037 g_signal_connect (data_store->dict, "variable-deleted",
2038 G_CALLBACK (on_variable_deleted), data_sheet);
2040 refresh_model (data_sheet);
2043 /* Clipboard stuff */
2045 /* A casereader and dictionary holding the data currently in the clip */
2046 static struct casereader *clip_datasheet = NULL;
2047 static struct dictionary *clip_dict = NULL;
2050 static void psppire_data_sheet_update_clipboard (PsppireDataSheet *);
2053 psppire_data_sheet_fetch_clip (PsppireDataSheet *data_sheet, gboolean cut,
2054 struct casereader **readerp,
2055 struct dictionary **dictp)
2057 struct casewriter *writer ;
2058 PsppireDataStore *ds = psppire_data_sheet_get_data_store (data_sheet);
2059 struct case_map *map = NULL;
2060 struct range_set *rows, *cols;
2061 const struct range_set_node *node;
2062 struct dictionary *dict;
2064 if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
2071 /* Construct clip dictionary. */
2072 *dictp = dict = dict_create (dict_get_encoding (ds->dict->dict));
2073 RANGE_SET_FOR_EACH (node, cols)
2077 for (dict_index = node->start; dict_index < node->end; dict_index++)
2079 struct variable *var = dict_get_var (ds->dict->dict, dict_index);
2080 dict_clone_var_assert (dict, var);
2084 /* Construct clip data. */
2085 map = case_map_by_name (ds->dict->dict, dict);
2086 writer = autopaging_writer_create (dict_get_proto (dict));
2087 RANGE_SET_FOR_EACH (node, rows)
2089 unsigned long int row;
2091 for (row = node->start; row < node->end; row++)
2093 struct ccase *old = psppire_data_store_get_case (ds, row);
2095 casewriter_write (writer, case_map_execute (map, old));
2097 casewriter_force_error (writer);
2100 case_map_destroy (map);
2102 /* Clear data that we copied out, if we're doing a "cut". */
2103 if (cut && !casewriter_error (writer))
2105 RANGE_SET_FOR_EACH (node, rows)
2107 unsigned long int row;
2109 for (row = node->start; row < node->end; row++)
2111 const struct range_set_node *node2;
2113 RANGE_SET_FOR_EACH (node2, cols)
2117 for (dict_index = node2->start; dict_index < node2->end;
2120 struct variable *var;
2122 var = dict_get_var (ds->dict->dict, dict_index);
2123 psppire_data_store_set_string (ds, "", row,
2131 range_set_destroy (rows);
2132 range_set_destroy (cols);
2134 *readerp = casewriter_make_reader (writer);
2139 /* Set the clip from the currently selected range in DATA_SHEET. If CUT is
2140 true, clears the original data from DATA_SHEET, otherwise leaves the
2141 original data in-place. */
2143 psppire_data_sheet_set_clip (PsppireDataSheet *data_sheet,
2146 struct casereader *reader;
2147 struct dictionary *dict;
2149 if (psppire_data_sheet_fetch_clip (data_sheet, cut, &reader, &dict))
2151 casereader_destroy (clip_datasheet);
2152 dict_destroy (clip_dict);
2154 clip_datasheet = reader;
2157 psppire_data_sheet_update_clipboard (data_sheet);
2168 /* Perform data_out for case CC, variable V, appending to STRING */
2170 data_out_g_string (GString *string, const struct variable *v,
2171 const struct ccase *cc)
2173 const struct fmt_spec *fs = var_get_print_format (v);
2174 const union value *val = case_data (cc, v);
2176 char *s = data_out (val, var_get_encoding (v), fs);
2178 g_string_append (string, s);
2184 clip_to_text (struct casereader *datasheet, struct dictionary *dict)
2189 const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (datasheet));
2190 const casenumber case_cnt = casereader_get_case_cnt (datasheet);
2191 const size_t var_cnt = dict_get_var_cnt (dict);
2193 string = g_string_sized_new (10 * val_cnt * case_cnt);
2195 for (r = 0 ; r < case_cnt ; ++r )
2200 cc = casereader_peek (datasheet, r);
2203 g_warning ("Clipboard seems to have inexplicably shrunk");
2207 for (c = 0 ; c < var_cnt ; ++c)
2209 const struct variable *v = dict_get_var (dict, c);
2210 data_out_g_string (string, v, cc);
2211 if ( c < val_cnt - 1 )
2212 g_string_append (string, "\t");
2216 g_string_append (string, "\n");
2226 clip_to_html (struct casereader *datasheet, struct dictionary *dict)
2231 const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (datasheet));
2232 const casenumber case_cnt = casereader_get_case_cnt (datasheet);
2233 const size_t var_cnt = dict_get_var_cnt (dict);
2235 /* Guestimate the size needed */
2236 string = g_string_sized_new (80 + 20 * val_cnt * case_cnt);
2238 g_string_append (string,
2239 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
2241 g_string_append (string, "<table>\n");
2242 for (r = 0 ; r < case_cnt ; ++r )
2245 struct ccase *cc = casereader_peek (datasheet, r);
2248 g_warning ("Clipboard seems to have inexplicably shrunk");
2251 g_string_append (string, "<tr>\n");
2253 for (c = 0 ; c < var_cnt ; ++c)
2255 const struct variable *v = dict_get_var (dict, c);
2256 g_string_append (string, "<td>");
2257 data_out_g_string (string, v, cc);
2258 g_string_append (string, "</td>\n");
2261 g_string_append (string, "</tr>\n");
2265 g_string_append (string, "</table>\n");
2273 psppire_data_sheet_clipboard_set (GtkSelectionData *selection_data,
2275 struct casereader *reader,
2276 struct dictionary *dict)
2278 GString *string = NULL;
2282 case SELECT_FMT_TEXT:
2283 string = clip_to_text (reader, dict);
2285 case SELECT_FMT_HTML:
2286 string = clip_to_html (reader, dict);
2289 g_assert_not_reached ();
2292 gtk_selection_data_set (selection_data, selection_data->target,
2294 (const guchar *) string->str, string->len);
2296 g_string_free (string, TRUE);
2300 psppire_data_sheet_clipboard_get_cb (GtkClipboard *clipboard,
2301 GtkSelectionData *selection_data,
2305 psppire_data_sheet_clipboard_set (selection_data, info,
2306 clip_datasheet, clip_dict);
2310 psppire_data_sheet_clipboard_clear_cb (GtkClipboard *clipboard,
2313 dict_destroy (clip_dict);
2316 casereader_destroy (clip_datasheet);
2317 clip_datasheet = NULL;
2321 static const GtkTargetEntry targets[] = {
2322 { "UTF8_STRING", 0, SELECT_FMT_TEXT },
2323 { "STRING", 0, SELECT_FMT_TEXT },
2324 { "TEXT", 0, SELECT_FMT_TEXT },
2325 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
2326 { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
2327 { "text/plain", 0, SELECT_FMT_TEXT },
2328 { "text/html", 0, SELECT_FMT_HTML }
2334 psppire_data_sheet_update_clipboard (PsppireDataSheet *sheet)
2336 GtkClipboard *clipboard =
2337 gtk_widget_get_clipboard (GTK_WIDGET (sheet),
2338 GDK_SELECTION_CLIPBOARD);
2340 if (!gtk_clipboard_set_with_owner (clipboard, targets,
2341 G_N_ELEMENTS (targets),
2342 psppire_data_sheet_clipboard_get_cb,
2343 psppire_data_sheet_clipboard_clear_cb,
2345 psppire_data_sheet_clipboard_clear_cb (clipboard, sheet);
2349 psppire_data_sheet_update_clip_actions (PsppireDataSheet *data_sheet)
2351 struct range_set *rows, *cols;
2355 enable = psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols);
2358 range_set_destroy (rows);
2359 range_set_destroy (cols);
2362 action = get_action_assert (data_sheet->builder, "edit_copy");
2363 gtk_action_set_sensitive (action, enable);
2365 action = get_action_assert (data_sheet->builder, "edit_cut");
2366 gtk_action_set_sensitive (action, enable);
2370 psppire_data_sheet_primary_get_cb (GtkClipboard *clipboard,
2371 GtkSelectionData *selection_data,
2375 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (data);
2376 struct casereader *reader;
2377 struct dictionary *dict;
2379 if (psppire_data_sheet_fetch_clip (data_sheet, FALSE, &reader, &dict))
2381 psppire_data_sheet_clipboard_set (selection_data, info,
2383 casereader_destroy (reader);
2384 dict_destroy (dict);
2389 psppire_data_sheet_update_primary_selection (PsppireDataSheet *data_sheet,
2390 gboolean should_own)
2392 GtkClipboard *clipboard;
2393 GdkDisplay *display;
2395 display = gtk_widget_get_display (GTK_WIDGET (data_sheet));
2396 clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_PRIMARY);
2397 g_return_if_fail (clipboard != NULL);
2399 printf ("owns_primary_selection=%d should_own=%d\n",
2400 data_sheet->owns_primary_selection, should_own);
2401 if (data_sheet->owns_primary_selection && !should_own)
2403 data_sheet->owns_primary_selection = FALSE;
2404 gtk_clipboard_clear (clipboard);
2406 else if (should_own)
2407 data_sheet->owns_primary_selection =
2408 gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
2409 psppire_data_sheet_primary_get_cb,
2410 NULL, G_OBJECT (data_sheet));
2413 /* A callback for when the clipboard contents have been received. */
2415 psppire_data_sheet_clip_received_cb (GtkClipboard *clipboard,
2416 GtkSelectionData *sd,
2419 PsppireDataSheet *data_sheet = data;
2420 PsppireDataStore *store = data_sheet->data_store;
2421 struct range_set *rows, *cols;
2423 gint next_row, next_column;
2427 if ( sd->length < 0 )
2430 if ( sd->type != gdk_atom_intern ("UTF8_STRING", FALSE))
2433 c = (char *) sd->data;
2435 /* Get the starting selected position in the data sheet. (Possibly we should
2436 only paste into the selected range if it's larger than one cell?) */
2437 if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
2439 next_row = range_set_first (rows)->start;
2440 first_column = next_column = range_set_first (cols)->start;
2441 range_set_destroy (rows);
2442 range_set_destroy (cols);
2444 g_return_if_fail (next_row >= 0);
2445 g_return_if_fail (next_column >= 0);
2447 while (count < sd->length)
2449 gint row = next_row;
2450 gint column = next_column;
2451 struct variable *var;
2454 while (*c != '\t' && *c != '\n' && count < sd->length)
2462 next_column = column + 1;
2464 else if ( *c == '\n')
2467 next_column = first_column;
2472 var = psppire_dict_get_variable (store->dict, column);
2474 psppire_data_store_set_string (store, s, row, var, FALSE);
2479 on_owner_change (GtkClipboard *clip, GdkEventOwnerChange *event, gpointer data)
2481 PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (data);
2482 gboolean compatible_target = FALSE;
2486 for (i = 0; i < G_N_ELEMENTS (targets); i++)
2488 GdkAtom atom = gdk_atom_intern (targets[i].target, TRUE);
2489 if (gtk_clipboard_wait_is_target_available (clip, atom))
2491 compatible_target = TRUE;
2496 action = get_action_assert (data_sheet->builder, "edit_paste");
2497 gtk_action_set_sensitive (action, compatible_target);