1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2006, 2007 Free Software Foundation
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/>. */
21 #include <glade/glade.h>
24 #include "window-manager.h"
25 #include <gtksheet/gtksheet.h>
29 #include <data/procedure.h>
30 #include "psppire-dialog.h"
31 #include "psppire-selector.h"
32 #include "weight-cases-dialog.h"
33 #include "split-file-dialog.h"
34 #include "transpose-dialog.h"
35 #include "sort-cases-dialog.h"
36 #include "select-cases-dialog.h"
37 #include "compute-dialog.h"
38 #include "goto-case-dialog.h"
39 #include "find-dialog.h"
40 #include "rank-dialog.h"
41 #include "comments-dialog.h"
42 #include "variable-info-dialog.h"
43 #include "descriptives-dialog.h"
44 #include "dict-display.h"
45 #include "clipboard.h"
48 #include "oneway-anova-dialog.h"
49 #include "t-test-independent-samples-dialog.h"
51 #define _(msgid) gettext (msgid)
52 #define N_(msgid) msgid
54 #include "data-editor.h"
55 #include "syntax-editor.h"
56 #include <language/syntax-string-source.h>
57 #include <language/command.h>
58 #include <libpspp/syntax-gen.h>
59 #include "window-manager.h"
61 #include "psppire-data-store.h"
62 #include "psppire-var-store.h"
64 static void on_edit_copy (GtkMenuItem *, gpointer);
65 static void on_edit_cut (GtkMenuItem *, gpointer);
66 static void on_edit_paste (GtkAction *a, gpointer data);
69 static void create_data_sheet_variable_popup_menu (struct data_editor *);
70 static void create_data_sheet_cases_popup_menu (struct data_editor *);
72 static void popup_variable_menu (GtkSheet *, gint,
73 GdkEventButton *, gpointer data);
75 static void popup_cases_menu (GtkSheet *, gint,
76 GdkEventButton *, gpointer data);
78 /* Update the data_ref_entry with the reference of the active cell */
79 static gint update_data_ref_entry (const GtkSheet *sheet,
80 gint row, gint col, gpointer data);
82 static void register_data_editor_actions (struct data_editor *de);
84 static void insert_variable (GtkAction *, gpointer data);
85 static void insert_case (GtkAction *a, gpointer data);
86 static void delete_cases (GtkAction *a, gpointer data);
87 static void delete_variables (GtkAction *a, gpointer data);
89 static void toggle_value_labels (GtkToggleAction *a, gpointer data);
91 /* Switch between the VAR SHEET and the DATA SHEET */
93 static gboolean click2column (GtkWidget *w, gint col, gpointer data);
94 static gboolean click2row (GtkWidget *w, gint row, gpointer data);
97 /* Callback for when the dictionary changes properties*/
98 static void on_weight_change (GObject *, gint, gpointer);
99 static void on_filter_change (GObject *, gint, gpointer);
100 static void on_split_change (PsppireDict *, gpointer);
102 static void on_switch_sheet (GtkNotebook *notebook,
103 GtkNotebookPage *page,
107 static void status_bar_activate (GtkCheckMenuItem *, gpointer);
109 static void grid_lines_activate (GtkCheckMenuItem *, gpointer);
111 static void data_sheet_activate (GtkCheckMenuItem *, gpointer);
113 static void variable_sheet_activate (GtkCheckMenuItem *, gpointer );
115 static void fonts_activate (GtkMenuItem *, gpointer);
117 static void file_quit (GtkCheckMenuItem *, gpointer );
120 enable_delete_cases (GtkWidget *w, gint var, gpointer data)
122 struct data_editor *de = data;
124 gtk_action_set_visible (de->delete_cases, var != -1);
129 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
131 struct data_editor *de = data;
133 gtk_action_set_visible (de->delete_variables, var != -1);
138 /* Run the EXECUTE command. */
140 execute (GtkMenuItem *mi, gpointer data)
142 struct getl_interface *sss = create_syntax_string_source ("EXECUTE.");
144 execute_syntax (sss);
148 transformation_change_callback (bool transformations_pending,
151 struct data_editor *de = data;
152 GtkWidget *menuitem =
153 get_widget_assert (de->xml, "transform_run-pending");
154 GtkWidget *status_label =
155 get_widget_assert (de->xml, "case-counter-area");
157 gtk_widget_set_sensitive (menuitem, transformations_pending);
160 if ( transformations_pending)
161 gtk_label_set_text (GTK_LABEL (status_label),
162 _("Transformations Pending"));
164 gtk_label_set_text (GTK_LABEL (status_label), "");
168 static void open_data_file (const gchar *, struct data_editor *);
171 /* Puts FILE_NAME into the recent list.
172 If it's already in the list, it moves it to the top
175 add_most_recent (const char *file_name)
177 #if RECENT_LISTS_AVAILABLE
179 GtkRecentManager *manager = gtk_recent_manager_get_default();
180 gchar *uri = g_filename_to_uri (file_name, NULL, NULL);
182 gtk_recent_manager_remove_item (manager, uri, NULL);
184 if ( ! gtk_recent_manager_add_item (manager, uri))
185 g_warning ("Could not add item %s to recent list\n",uri);
193 #if RECENT_LISTS_AVAILABLE
196 on_recent_data_select (GtkMenuShell *menushell, gpointer user_data)
199 struct data_editor *de = user_data;
202 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
204 file = g_filename_from_uri (uri, NULL, NULL);
208 open_data_file (file, de);
214 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
218 struct syntax_editor *se ;
221 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
223 file = g_filename_from_uri (uri, NULL, NULL);
227 se = (struct syntax_editor *)
228 window_create (WINDOW_SYNTAX, file);
230 load_editor_from_file (se, file, NULL);
238 datum_entry_activate (GtkEntry *entry, gpointer data)
241 GtkSheet *data_sheet = GTK_SHEET (data);
242 PsppireDataStore *store = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
244 const char *text = gtk_entry_get_text (entry);
246 gtk_sheet_get_active_cell (data_sheet, &row, &column);
248 if ( row == -1 || column == -1)
251 psppire_data_store_set_string (store, text, row, column);
255 /* Update the Edit->Paste menuitem
256 If PAGE is not -1 , then it should be set to the current page of
257 the data editors notebook widget.
258 If -1, then it'll be queried.
261 update_paste_menuitem (struct data_editor *de, gint page)
263 GtkWidget * edit_paste = get_widget_assert (de->xml, "edit_paste");
264 GtkWidget *notebook = get_widget_assert (de->xml, "notebook");
265 GtkSheet * data_sheet ;
269 page = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
272 if ( PAGE_VAR_SHEET == page )
274 /* We don't yet support pasting to the var sheet */
275 gtk_widget_set_sensitive (edit_paste, FALSE);
279 data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
281 gtk_sheet_get_active_cell (data_sheet, &row, &column);
283 if ( row < 0 || column < 0 )
284 gtk_widget_set_sensitive (edit_paste, FALSE);
286 gtk_widget_set_sensitive (edit_paste, TRUE);
289 /* Update the Edit->Cut and Edit->Copy menuitems
290 If PAGE is not -1 , then it should be set to the current page of
291 the data editors notebook widget.
292 If -1, then it'll be queried.
295 update_cut_copy_menuitem (struct data_editor *de, gint page)
297 GtkWidget * edit_copy = get_widget_assert (de->xml, "edit_copy");
298 GtkWidget * edit_cut = get_widget_assert (de->xml, "edit_cut");
299 GtkWidget *notebook = get_widget_assert (de->xml, "notebook");
300 GtkSheet * data_sheet ;
304 page = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
307 if ( PAGE_VAR_SHEET == page )
309 /* We don't yet support copying from the var sheet */
310 gtk_widget_set_sensitive (edit_copy, FALSE);
311 gtk_widget_set_sensitive (edit_cut, FALSE);
315 data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
317 gtk_sheet_get_active_cell (data_sheet, &row, &column);
319 if ( row < 0 || column < 0 )
321 gtk_widget_set_sensitive (edit_copy, FALSE);
322 gtk_widget_set_sensitive (edit_cut, FALSE);
326 gtk_widget_set_sensitive (edit_copy, TRUE);
327 gtk_widget_set_sensitive (edit_cut, TRUE);
331 /* Callback for when the datasheet's active cell becomes active/inactive */
333 on_data_sheet_activate_change (GtkSheet *sheet,
334 gint row, gint column, gpointer data)
336 struct data_editor *de = data;
338 update_paste_menuitem (de, -1);
339 update_cut_copy_menuitem (de, -1);
344 extern struct dataset *the_dataset;
347 Create a new data editor.
350 new_data_editor (void)
352 struct data_editor *de ;
353 struct editor_window *e;
354 GtkSheet *var_sheet ;
355 GtkSheet *data_sheet ;
357 GtkWidget *datum_entry;
359 de = g_malloc0 (sizeof (*de));
361 e = (struct editor_window *) de;
363 de->xml = XML_NEW ("data-editor.glade");
366 dataset_add_transform_change_callback (the_dataset,
367 transformation_change_callback,
370 var_sheet = GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
371 data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
374 g_signal_connect (G_OBJECT (data_sheet), "activate",
375 G_CALLBACK (on_data_sheet_activate_change), de);
377 g_signal_connect (G_OBJECT (data_sheet), "deactivate",
378 G_CALLBACK (on_data_sheet_activate_change), de);
381 vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
383 g_assert(vs); /* Traps a possible bug in win32 build */
385 g_signal_connect (G_OBJECT (data_sheet), "activate",
386 G_CALLBACK (update_data_ref_entry),
389 datum_entry = get_widget_assert (de->xml, "datum_entry");
391 g_signal_connect (G_OBJECT (datum_entry), "activate",
392 G_CALLBACK (datum_entry_activate),
395 g_signal_connect (vs->dict, "weight-changed",
396 G_CALLBACK (on_weight_change),
399 g_signal_connect (vs->dict, "filter-changed",
400 G_CALLBACK (on_filter_change),
403 g_signal_connect (vs->dict, "split-changed",
404 G_CALLBACK (on_split_change),
407 connect_help (de->xml);
411 g_signal_connect (get_widget_assert (de->xml, "edit_copy"),
413 G_CALLBACK (on_edit_copy), de);
415 g_signal_connect (get_widget_assert (de->xml, "edit_cut"),
417 G_CALLBACK (on_edit_cut), de);
420 register_data_editor_actions (de);
422 de->toggle_value_labels =
423 gtk_toggle_action_new ("toggle-value-labels",
425 _("Show/hide value labels"),
426 "pspp-value-labels");
428 g_signal_connect (de->toggle_value_labels, "activate",
429 G_CALLBACK (toggle_value_labels), de);
432 gtk_action_connect_proxy (GTK_ACTION (de->toggle_value_labels),
433 get_widget_assert (de->xml,
434 "togglebutton-value-labels"));
437 gtk_action_connect_proxy (GTK_ACTION (de->toggle_value_labels),
438 get_widget_assert (de->xml,
439 "view_value-labels"));
442 gtk_action_new ("clear-cases",
444 _("Delete the cases at the selected position(s)"),
447 g_signal_connect (de->delete_cases, "activate",
448 G_CALLBACK (delete_cases), de);
450 gtk_action_connect_proxy (de->delete_cases,
451 get_widget_assert (de->xml, "edit_clear-cases"));
453 g_signal_connect (get_widget_assert (de->xml, "edit_paste"), "activate",
454 G_CALLBACK (on_edit_paste), de);
456 gtk_action_set_visible (de->delete_cases, FALSE);
458 de->delete_variables =
459 gtk_action_new ("clear-variables",
461 _("Delete the variables at the selected position(s)"),
462 "pspp-clear-variables");
464 g_signal_connect (de->delete_variables, "activate",
465 G_CALLBACK (delete_variables), de);
467 gtk_action_connect_proxy (de->delete_variables,
468 get_widget_assert (de->xml, "edit_clear-variables")
471 gtk_action_set_visible (de->delete_variables, FALSE);
473 de->insert_variable =
474 gtk_action_new ("insert-variable",
475 _("Insert Variable"),
476 _("Create a new variable at the current position"),
477 "pspp-insert-variable");
479 g_signal_connect (de->insert_variable, "activate",
480 G_CALLBACK (insert_variable), de);
483 gtk_action_connect_proxy (de->insert_variable,
484 get_widget_assert (de->xml, "button-insert-variable")
487 gtk_action_connect_proxy (de->insert_variable,
488 get_widget_assert (de->xml, "edit_insert-variable")
493 gtk_action_new ("insert-case",
495 _("Create a new case at the current position"),
498 g_signal_connect (de->insert_case, "activate",
499 G_CALLBACK (insert_case), de);
502 gtk_action_connect_proxy (de->insert_case,
503 get_widget_assert (de->xml, "button-insert-case")
507 gtk_action_connect_proxy (de->insert_case,
508 get_widget_assert (de->xml, "edit_insert-case")
513 de->invoke_goto_dialog =
514 gtk_action_new ("goto-case-dialog",
516 _("Jump to a Case in the Data Sheet"),
520 gtk_action_connect_proxy (de->invoke_goto_dialog,
521 get_widget_assert (de->xml, "button-goto-case")
524 gtk_action_connect_proxy (de->invoke_goto_dialog,
525 get_widget_assert (de->xml, "edit_goto-case")
529 g_signal_connect (de->invoke_goto_dialog, "activate",
530 G_CALLBACK (goto_case_dialog), de);
533 de->invoke_weight_cases_dialog =
534 gtk_action_new ("weight-cases-dialog",
536 _("Weight cases by variable"),
537 "pspp-weight-cases");
539 g_signal_connect (de->invoke_weight_cases_dialog, "activate",
540 G_CALLBACK (weight_cases_dialog), de);
543 de->invoke_transpose_dialog =
544 gtk_action_new ("transpose-dialog",
546 _("Transpose the cases with the variables"),
550 g_signal_connect (de->invoke_transpose_dialog, "activate",
551 G_CALLBACK (transpose_dialog), de);
555 de->invoke_split_file_dialog =
556 gtk_action_new ("split-file-dialog",
558 _("Split the active file"),
561 g_signal_connect (de->invoke_split_file_dialog, "activate",
562 G_CALLBACK (split_file_dialog), de);
566 de->invoke_sort_cases_dialog =
567 gtk_action_new ("sort-cases-dialog",
569 _("Sort cases in the active file"),
572 g_signal_connect (de->invoke_sort_cases_dialog, "activate",
573 G_CALLBACK (sort_cases_dialog), de);
575 de->invoke_select_cases_dialog =
576 gtk_action_new ("select-cases-dialog",
578 _("Select cases from the active file"),
579 "pspp-select-cases");
581 g_signal_connect (de->invoke_select_cases_dialog, "activate",
582 G_CALLBACK (select_cases_dialog), de);
585 de->invoke_compute_dialog =
586 gtk_action_new ("compute-dialog",
588 _("Compute new values for a variable"),
591 g_signal_connect (de->invoke_compute_dialog, "activate",
592 G_CALLBACK (compute_dialog), de);
594 de->invoke_oneway_anova_dialog =
595 gtk_action_new ("oneway-anova",
597 _("Perform one way analysis of variance"),
600 g_signal_connect (de->invoke_oneway_anova_dialog, "activate",
601 G_CALLBACK (oneway_anova_dialog), de);
603 de->invoke_t_test_independent_samples_dialog =
604 gtk_action_new ("t-test-independent-samples",
605 _("_Independent Samples T Test"),
606 _("Calculate T Test for samples from independent groups"),
609 g_signal_connect (de->invoke_t_test_independent_samples_dialog, "activate",
610 G_CALLBACK (t_test_independent_samples_dialog), de);
613 de->invoke_comments_dialog =
614 gtk_action_new ("commments-dialog",
615 _("Data File Comments"),
616 _("Commentary text for the data file"),
619 g_signal_connect (de->invoke_comments_dialog, "activate",
620 G_CALLBACK (comments_dialog), de);
622 de->invoke_find_dialog =
623 gtk_action_new ("find-dialog",
628 g_signal_connect (de->invoke_find_dialog, "activate",
629 G_CALLBACK (find_dialog), de);
632 de->invoke_rank_dialog =
633 gtk_action_new ("rank-dialog",
638 g_signal_connect (de->invoke_rank_dialog, "activate",
639 G_CALLBACK (rank_dialog), de);
642 de->invoke_variable_info_dialog =
643 gtk_action_new ("variable-info-dialog",
645 _("Jump to Variable"),
646 "pspp-goto-variable");
648 g_signal_connect (de->invoke_variable_info_dialog, "activate",
649 G_CALLBACK (variable_info_dialog), de);
651 de->invoke_descriptives_dialog =
652 gtk_action_new ("descriptives-dialog",
654 _("Calculate descriptive statistics (mean, variance, ...)"),
655 "pspp-descriptives");
657 g_signal_connect (de->invoke_descriptives_dialog, "activate",
658 G_CALLBACK (descriptives_dialog), de);
660 e->window = GTK_WINDOW (get_widget_assert (de->xml, "data_editor"));
662 g_signal_connect_swapped (get_widget_assert (de->xml,"file_new_data"),
664 G_CALLBACK (gtk_action_activate),
665 de->action_data_new);
667 g_signal_connect_swapped (get_widget_assert (de->xml,"file_open_data"),
669 G_CALLBACK (gtk_action_activate),
670 de->action_data_open);
673 #if RECENT_LISTS_AVAILABLE
675 GtkRecentManager *rm = gtk_recent_manager_get_default ();
676 GtkWidget *recent_data = get_widget_assert (de->xml, "file_recent-data");
677 GtkWidget *recent_files = get_widget_assert (de->xml, "file_recent-files");
678 GtkWidget *recent_separator = get_widget_assert (de->xml, "file_separator1");
680 GtkWidget *menu = gtk_recent_chooser_menu_new_for_manager (rm);
682 GtkRecentFilter *filter = gtk_recent_filter_new ();
684 gtk_widget_show (recent_data);
685 gtk_widget_show (recent_files);
686 gtk_widget_show (recent_separator);
688 gtk_recent_filter_add_pattern (filter, "*.sav");
689 gtk_recent_filter_add_pattern (filter, "*.SAV");
691 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
693 gtk_widget_set_sensitive (recent_data, TRUE);
694 g_signal_connect (menu, "selection-done",
695 G_CALLBACK (on_recent_data_select), de);
697 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu);
700 filter = gtk_recent_filter_new ();
701 menu = gtk_recent_chooser_menu_new_for_manager (rm);
703 gtk_recent_filter_add_pattern (filter, "*.sps");
704 gtk_recent_filter_add_pattern (filter, "*.SPS");
706 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
708 gtk_widget_set_sensitive (recent_files, TRUE);
709 g_signal_connect (menu, "selection-done",
710 G_CALLBACK (on_recent_files_select), de);
712 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu);
716 g_signal_connect (get_widget_assert (de->xml,"file_new_syntax"),
718 G_CALLBACK (new_syntax_window),
721 g_signal_connect (get_widget_assert (de->xml,"file_open_syntax"),
723 G_CALLBACK (open_syntax_window),
726 g_signal_connect_swapped (get_widget_assert (de->xml,"file_save"),
728 G_CALLBACK (gtk_action_activate),
729 de->action_data_save);
731 g_signal_connect_swapped (get_widget_assert (de->xml,"file_save_as"),
733 G_CALLBACK (gtk_action_activate),
734 de->action_data_save_as);
736 gtk_action_connect_proxy (de->invoke_find_dialog,
737 get_widget_assert (de->xml, "edit_find")
740 gtk_action_connect_proxy (de->invoke_find_dialog,
741 get_widget_assert (de->xml, "button-find")
744 gtk_action_connect_proxy (de->invoke_rank_dialog,
745 get_widget_assert (de->xml, "transform_rank")
748 gtk_action_connect_proxy (de->invoke_weight_cases_dialog,
749 get_widget_assert (de->xml, "data_weight-cases")
752 gtk_action_connect_proxy (de->invoke_transpose_dialog,
753 get_widget_assert (de->xml, "data_transpose")
756 gtk_action_connect_proxy (de->invoke_split_file_dialog,
757 get_widget_assert (de->xml, "data_split-file")
760 gtk_action_connect_proxy (de->invoke_sort_cases_dialog,
761 get_widget_assert (de->xml, "data_sort-cases")
764 gtk_action_connect_proxy (de->invoke_select_cases_dialog,
765 get_widget_assert (de->xml, "data_select-cases")
768 gtk_action_connect_proxy (de->invoke_compute_dialog,
769 get_widget_assert (de->xml, "transform_compute")
772 gtk_action_connect_proxy (de->invoke_t_test_independent_samples_dialog,
773 get_widget_assert (de->xml,
778 gtk_action_connect_proxy (de->invoke_oneway_anova_dialog,
779 get_widget_assert (de->xml,
784 gtk_action_connect_proxy (de->invoke_comments_dialog,
785 get_widget_assert (de->xml, "utilities_comments")
788 gtk_action_connect_proxy (de->invoke_variable_info_dialog,
789 get_widget_assert (de->xml, "utilities_variables")
792 gtk_action_connect_proxy (de->invoke_descriptives_dialog,
793 get_widget_assert (de->xml, "analyze_descriptives")
796 g_signal_connect (get_widget_assert (de->xml,"help_about"),
798 G_CALLBACK (about_new),
802 g_signal_connect (get_widget_assert (de->xml,"help_reference"),
804 G_CALLBACK (reference_manual),
807 g_signal_connect (data_sheet,
808 "double-click-column",
809 G_CALLBACK (click2column),
812 g_signal_connect (data_sheet,
814 G_CALLBACK (enable_delete_variables),
817 g_signal_connect (data_sheet,
819 G_CALLBACK (enable_delete_cases),
823 g_signal_connect (var_sheet,
825 GTK_SIGNAL_FUNC (click2row),
828 g_signal_connect_after (var_sheet,
830 G_CALLBACK (enable_delete_variables),
833 g_signal_connect (get_widget_assert (de->xml, "notebook"),
835 G_CALLBACK (on_switch_sheet), de);
838 g_signal_connect (get_widget_assert (de->xml, "view_statusbar"),
840 G_CALLBACK (status_bar_activate), de);
843 g_signal_connect (get_widget_assert (de->xml, "view_gridlines"),
845 G_CALLBACK (grid_lines_activate), de);
849 g_signal_connect (get_widget_assert (de->xml, "view_data"),
851 G_CALLBACK (data_sheet_activate), de);
853 g_signal_connect (get_widget_assert (de->xml, "view_variables"),
855 G_CALLBACK (variable_sheet_activate), de);
859 g_signal_connect (get_widget_assert (de->xml, "view_fonts"),
861 G_CALLBACK (fonts_activate), de);
866 gtk_action_connect_proxy (de->action_data_open,
867 get_widget_assert (de->xml, "button-open")
870 gtk_action_connect_proxy (de->action_data_save,
871 get_widget_assert (de->xml, "button-save")
874 gtk_action_connect_proxy (de->invoke_variable_info_dialog,
875 get_widget_assert (de->xml, "button-goto-variable")
878 gtk_action_connect_proxy (de->invoke_weight_cases_dialog,
879 get_widget_assert (de->xml, "button-weight-cases")
882 gtk_action_connect_proxy (de->invoke_split_file_dialog,
883 get_widget_assert (de->xml, "button-split-file")
886 gtk_action_connect_proxy (de->invoke_select_cases_dialog,
887 get_widget_assert (de->xml, "button-select-cases")
891 g_signal_connect (get_widget_assert (de->xml, "file_quit"),
893 G_CALLBACK (file_quit), de);
895 g_signal_connect (get_widget_assert (de->xml, "transform_run-pending"),
897 G_CALLBACK (execute), de);
900 g_signal_connect (get_widget_assert (de->xml, "windows_minimise_all"),
902 G_CALLBACK (minimise_all_windows), NULL);
905 create_data_sheet_variable_popup_menu (de);
906 create_data_sheet_cases_popup_menu (de);
908 g_signal_connect (G_OBJECT (data_sheet), "button-event-column",
909 G_CALLBACK (popup_variable_menu), de);
911 g_signal_connect (G_OBJECT (data_sheet), "button-event-row",
912 G_CALLBACK (popup_cases_menu), de);
918 /* Callback which occurs when the var sheet's row title
919 button is double clicked */
921 click2row (GtkWidget *w, gint row, gpointer data)
923 struct data_editor *de = data;
924 GtkSheetRange visible_range;
926 gint current_row, current_column;
928 GtkWidget *data_sheet = get_widget_assert (de->xml, "data_sheet");
930 data_editor_select_sheet (de, PAGE_DATA_SHEET);
932 gtk_sheet_get_active_cell (GTK_SHEET (data_sheet),
933 ¤t_row, ¤t_column);
935 gtk_sheet_set_active_cell (GTK_SHEET (data_sheet), current_row, row);
937 gtk_sheet_get_visible_range (GTK_SHEET (data_sheet), &visible_range);
939 if ( row < visible_range.col0 || row > visible_range.coli)
941 gtk_sheet_moveto (GTK_SHEET (data_sheet),
942 current_row, row, 0, 0);
949 /* Callback which occurs when the data sheet's column title
952 click2column (GtkWidget *w, gint col, gpointer data)
954 struct data_editor *de = data;
956 gint current_row, current_column;
958 GtkWidget *var_sheet = get_widget_assert (de->xml, "variable_sheet");
960 data_editor_select_sheet (de, PAGE_VAR_SHEET);
962 gtk_sheet_get_active_cell (GTK_SHEET (var_sheet),
963 ¤t_row, ¤t_column);
965 gtk_sheet_set_active_cell (GTK_SHEET (var_sheet), col, current_column);
972 new_data_window (GtkMenuItem *menuitem, gpointer parent)
974 window_create (WINDOW_DATA, NULL);
977 /* Callback for when the datasheet/varsheet is selected */
979 on_switch_sheet (GtkNotebook *notebook,
980 GtkNotebookPage *page,
984 struct data_editor *de = user_data;
986 GtkWidget *view_data = get_widget_assert (de->xml, "view_data");
987 GtkWidget *view_variables = get_widget_assert (de->xml, "view_variables");
992 gtk_widget_hide (view_variables);
993 gtk_widget_show (view_data);
994 gtk_action_set_sensitive (de->insert_variable, TRUE);
995 gtk_action_set_sensitive (de->insert_case, FALSE);
996 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
998 case PAGE_DATA_SHEET:
999 gtk_widget_show (view_variables);
1000 gtk_widget_show (view_data);
1001 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
1002 gtk_action_set_sensitive (de->insert_case, TRUE);
1005 g_assert_not_reached ();
1009 update_paste_menuitem (de, page_num);
1010 update_cut_copy_menuitem (de, page_num);
1015 data_editor_select_sheet (struct data_editor *de, gint page)
1017 gtk_notebook_set_current_page
1019 GTK_NOTEBOOK (get_widget_assert (de->xml,"notebook")), page
1026 status_bar_activate (GtkCheckMenuItem *menuitem, gpointer data)
1028 struct data_editor *de = data;
1029 GtkWidget *statusbar = get_widget_assert (de->xml, "status-bar");
1031 if ( gtk_check_menu_item_get_active (menuitem) )
1032 gtk_widget_show (statusbar);
1034 gtk_widget_hide (statusbar);
1039 grid_lines_activate (GtkCheckMenuItem *menuitem, gpointer data)
1041 struct data_editor *de = data;
1042 const bool grid_visible = gtk_check_menu_item_get_active (menuitem);
1044 gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml,
1048 gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml, "data_sheet")),
1055 data_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
1057 struct data_editor *de = data;
1059 data_editor_select_sheet (de, PAGE_DATA_SHEET);
1064 variable_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
1066 struct data_editor *de = data;
1068 data_editor_select_sheet (de, PAGE_VAR_SHEET);
1073 fonts_activate (GtkMenuItem *menuitem, gpointer data)
1075 struct data_editor *de = data;
1077 gtk_font_selection_dialog_new (_("Font Selection"));
1079 gtk_window_set_transient_for (GTK_WINDOW (dialog),
1080 GTK_WINDOW (get_widget_assert (de->xml,
1082 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
1084 GtkSheet *data_sheet =
1085 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1087 GtkSheet *var_sheet =
1088 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1090 PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
1091 PsppireVarStore *vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
1093 const gchar *font = gtk_font_selection_dialog_get_font_name
1094 (GTK_FONT_SELECTION_DIALOG (dialog));
1096 PangoFontDescription* font_desc =
1097 pango_font_description_from_string (font);
1099 psppire_var_store_set_font (vs, font_desc);
1100 psppire_data_store_set_font (ds, font_desc);
1103 gtk_widget_hide (dialog);
1108 /* Callback for the value labels action */
1110 toggle_value_labels (GtkToggleAction *ta, gpointer data)
1112 struct data_editor *de = data;
1114 GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1116 PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
1119 psppire_data_store_show_labels (ds,
1120 gtk_toggle_action_get_active (ta));
1125 file_quit (GtkCheckMenuItem *menuitem, gpointer data)
1127 /* FIXME: Need to be more intelligent here.
1128 Give the user the opportunity to save any unsaved data.
1134 delete_cases (GtkAction *action, gpointer data)
1136 struct data_editor *de = data;
1137 GtkSheet *data_sheet =
1138 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1140 GtkSheetRange range;
1142 PsppireDataStore *data_store = PSPPIRE_DATA_STORE
1143 (gtk_sheet_get_model (data_sheet) );
1146 /* This shouldn't be able to happen, because the action
1147 should be disabled */
1148 g_return_if_fail (gtk_sheet_get_state (data_sheet)
1149 == GTK_SHEET_ROW_SELECTED );
1151 gtk_sheet_get_selected_range (data_sheet, &range);
1153 gtk_sheet_unselect_range (data_sheet);
1155 psppire_data_store_delete_cases (data_store, range.row0,
1156 1 + range.rowi - range.row0);
1161 delete_variables (GtkAction *a, gpointer data)
1163 struct data_editor *de = data;
1164 GtkSheetRange range;
1166 GtkNotebook *notebook = GTK_NOTEBOOK (get_widget_assert (de->xml,
1169 const gint page = gtk_notebook_get_current_page (notebook);
1171 GtkSheet *sheet = GTK_SHEET (get_widget_assert (de->xml,
1172 (page == PAGE_VAR_SHEET) ?
1177 gtk_sheet_get_selected_range (sheet, &range);
1181 case PAGE_VAR_SHEET:
1183 PsppireVarStore *vs =
1184 PSPPIRE_VAR_STORE (gtk_sheet_get_model (sheet));
1186 psppire_dict_delete_variables (vs->dict,
1193 case PAGE_DATA_SHEET:
1195 PsppireDataStore *ds =
1196 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1198 psppire_dict_delete_variables (ds->dict,
1207 gtk_sheet_unselect_range (sheet);
1211 insert_case (GtkAction *action, gpointer data)
1214 struct data_editor *de = data;
1216 GtkSheet *data_sheet =
1217 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1219 PsppireDataStore *ds = PSPPIRE_DATA_STORE
1220 (gtk_sheet_get_model (data_sheet) );
1223 gtk_sheet_get_active_cell (data_sheet, ¤t_row, NULL);
1225 if (current_row < 0) current_row = 0;
1227 psppire_data_store_insert_new_case (ds, current_row);
1230 /* Insert a new variable before the current row in the variable sheet,
1231 or before the current column in the data sheet, whichever is selected */
1233 insert_variable (GtkAction *action, gpointer data)
1235 struct data_editor *de = data;
1238 GtkWidget *notebook = get_widget_assert (de->xml, "notebook");
1240 GtkSheet *var_sheet =
1241 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1243 PsppireVarStore *vs = PSPPIRE_VAR_STORE
1244 (gtk_sheet_get_model (var_sheet) );
1246 switch ( gtk_notebook_get_current_page ( GTK_NOTEBOOK (notebook)) )
1248 case PAGE_VAR_SHEET:
1249 posn = var_sheet->active_cell.row;
1251 case PAGE_DATA_SHEET:
1253 GtkSheet *data_sheet =
1254 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1256 if ( data_sheet->state == GTK_SHEET_COLUMN_SELECTED )
1257 posn = data_sheet->range.col0;
1259 posn = data_sheet->active_cell.col;
1263 g_assert_not_reached ();
1266 if ( posn == -1 ) posn = 0;
1268 psppire_dict_insert_variable (vs->dict, posn, NULL);
1271 /* Callback for when the dictionary changes its split variables */
1273 on_split_change (PsppireDict *dict, gpointer data)
1275 struct data_editor *de = data;
1277 size_t n_split_vars = dict_get_split_cnt (dict->dict);
1279 GtkWidget *split_status_area =
1280 get_widget_assert (de->xml, "split-file-status-area");
1282 if ( n_split_vars == 0 )
1284 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
1290 const struct variable *const * split_vars =
1291 dict_get_split_vars (dict->dict);
1293 text = g_string_new (_("Split by "));
1295 for (i = 0 ; i < n_split_vars - 1; ++i )
1297 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
1299 g_string_append (text, var_get_name (split_vars[i]));
1301 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
1303 g_string_free (text, TRUE);
1308 /* Callback for when the dictionary changes its filter variable */
1310 on_filter_change (GObject *o, gint filter_index, gpointer data)
1312 struct data_editor *de = data;
1313 GtkWidget *filter_status_area =
1314 get_widget_assert (de->xml, "filter-use-status-area");
1316 if ( filter_index == -1 )
1318 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
1322 GtkSheet *var_sheet =
1323 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1325 PsppireVarStore *vs = PSPPIRE_VAR_STORE
1326 (gtk_sheet_get_model (var_sheet) );
1328 struct variable *var = psppire_dict_get_variable (vs->dict,
1331 gchar *text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
1333 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
1339 /* Callback for when the dictionary changes its weights */
1341 on_weight_change (GObject *o, gint weight_index, gpointer data)
1343 struct data_editor *de = data;
1344 GtkWidget *weight_status_area =
1345 get_widget_assert (de->xml, "weight-status-area");
1347 if ( weight_index == -1 )
1349 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
1353 GtkSheet *var_sheet =
1354 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1356 PsppireVarStore *vs = PSPPIRE_VAR_STORE
1357 (gtk_sheet_get_model (var_sheet) );
1359 struct variable *var = psppire_dict_get_variable (vs->dict,
1362 gchar *text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
1364 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
1373 static void data_save_as_dialog (GtkAction *, struct data_editor *de);
1374 static void new_file (GtkAction *, struct editor_window *de);
1375 static void open_data_dialog (GtkAction *, struct data_editor *de);
1376 static void data_save (GtkAction *action, struct data_editor *e);
1379 /* Create the GtkActions and connect to their signals */
1381 register_data_editor_actions (struct data_editor *de)
1383 de->action_data_open =
1384 gtk_action_new ("data-open-dialog",
1386 _("Open a data file"),
1389 g_signal_connect (de->action_data_open, "activate",
1390 G_CALLBACK (open_data_dialog), de);
1393 de->action_data_save = gtk_action_new ("data-save",
1395 _("Save data to file"),
1398 g_signal_connect (de->action_data_save, "activate",
1399 G_CALLBACK (data_save), de);
1403 de->action_data_save_as = gtk_action_new ("data-save-as-dialog",
1405 _("Save data to file"),
1408 g_signal_connect (de->action_data_save_as, "activate",
1409 G_CALLBACK (data_save_as_dialog), de);
1411 de->action_data_new =
1412 gtk_action_new ("data-new",
1417 g_signal_connect (de->action_data_new, "activate",
1418 G_CALLBACK (new_file), de);
1421 /* Returns true if NAME has a suffix which might denote a PSPP file */
1423 name_has_suffix (const gchar *name)
1425 if ( g_str_has_suffix (name, ".sav"))
1427 if ( g_str_has_suffix (name, ".SAV"))
1429 if ( g_str_has_suffix (name, ".por"))
1431 if ( g_str_has_suffix (name, ".POR"))
1437 /* Append SUFFIX to the filename of DE */
1439 append_filename_suffix (struct data_editor *de, const gchar *suffix)
1441 if ( ! name_has_suffix (de->file_name))
1443 gchar *s = de->file_name;
1444 de->file_name = g_strconcat (de->file_name, suffix, NULL);
1449 /* Save DE to file */
1451 save_file (struct data_editor *de)
1453 struct getl_interface *sss;
1454 struct string file_name ;
1456 g_assert (de->file_name);
1458 ds_init_cstr (&file_name, de->file_name);
1459 gen_quoted_string (&file_name);
1461 if ( de->save_as_portable )
1463 append_filename_suffix (de, ".por");
1464 sss = create_syntax_string_source ("EXPORT OUTFILE=%s.",
1465 ds_cstr (&file_name));
1469 append_filename_suffix (de, ".sav");
1470 sss = create_syntax_string_source ("SAVE OUTFILE=%s.",
1471 ds_cstr (&file_name));
1474 ds_destroy (&file_name);
1476 execute_syntax (sss);
1480 /* Callback for data_save action.
1481 If there's an existing file name, then just save,
1482 otherwise prompt for a file name, then save */
1484 data_save (GtkAction *action, struct data_editor *de)
1489 data_save_as_dialog (action, de);
1493 /* Callback for data_save_as action. Prompt for a filename and save */
1495 data_save_as_dialog (GtkAction *action, struct data_editor *de)
1497 struct editor_window *e = (struct editor_window *) de;
1499 GtkWidget *button_sys;
1501 gtk_file_chooser_dialog_new (_("Save"),
1502 GTK_WINDOW (e->window),
1503 GTK_FILE_CHOOSER_ACTION_SAVE,
1504 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1505 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1508 GtkFileFilter *filter = gtk_file_filter_new ();
1509 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
1510 gtk_file_filter_add_pattern (filter, "*.sav");
1511 gtk_file_filter_add_pattern (filter, "*.SAV");
1512 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1514 filter = gtk_file_filter_new ();
1515 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
1516 gtk_file_filter_add_pattern (filter, "*.por");
1517 gtk_file_filter_add_pattern (filter, "*.POR");
1518 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1520 filter = gtk_file_filter_new ();
1521 gtk_file_filter_set_name (filter, _("All Files"));
1522 gtk_file_filter_add_pattern (filter, "*");
1523 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1526 GtkWidget *button_por;
1527 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
1529 gtk_radio_button_new_with_label (NULL, _("System File"));
1532 gtk_radio_button_new_with_label
1533 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
1534 _("Portable File"));
1536 gtk_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
1537 gtk_box_pack_start_defaults (GTK_BOX (vbox), button_por);
1539 gtk_widget_show_all (vbox);
1541 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
1544 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
1546 case GTK_RESPONSE_ACCEPT:
1548 g_free (de->file_name);
1551 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1553 de->save_as_portable =
1554 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
1558 window_set_name_from_filename (e, de->file_name);
1565 gtk_widget_destroy (dialog);
1569 /* Callback for data_new action.
1570 Performs the NEW FILE command */
1572 new_file (GtkAction *action, struct editor_window *e)
1574 struct data_editor *de = (struct data_editor *) e;
1576 struct getl_interface *sss =
1577 create_syntax_string_source ("NEW FILE.");
1579 execute_syntax (sss);
1581 g_free (de->file_name);
1582 de->file_name = NULL;
1584 default_window_name (e);
1589 open_data_file (const gchar *file_name, struct data_editor *de)
1591 struct getl_interface *sss;
1592 struct string filename;
1594 ds_init_cstr (&filename, file_name);
1596 gen_quoted_string (&filename);
1598 sss = create_syntax_string_source ("GET FILE=%s.",
1599 ds_cstr (&filename));
1600 ds_destroy (&filename);
1602 if (execute_syntax (sss) )
1604 window_set_name_from_filename ((struct editor_window *) de, file_name);
1605 add_most_recent (file_name);
1611 /* Callback for the data_open action.
1612 Prompts for a filename and opens it */
1614 open_data_dialog (GtkAction *action, struct data_editor *de)
1616 struct editor_window *e = (struct editor_window *) de;
1619 gtk_file_chooser_dialog_new (_("Open"),
1620 GTK_WINDOW (e->window),
1621 GTK_FILE_CHOOSER_ACTION_OPEN,
1622 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1623 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1626 GtkFileFilter *filter = gtk_file_filter_new ();
1627 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
1628 gtk_file_filter_add_pattern (filter, "*.sav");
1629 gtk_file_filter_add_pattern (filter, "*.SAV");
1630 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1632 filter = gtk_file_filter_new ();
1633 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
1634 gtk_file_filter_add_pattern (filter, "*.por");
1635 gtk_file_filter_add_pattern (filter, "*.POR");
1636 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1638 filter = gtk_file_filter_new ();
1639 gtk_file_filter_set_name (filter, _("All Files"));
1640 gtk_file_filter_add_pattern (filter, "*");
1641 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1646 gchar *dir_name = g_path_get_dirname (de->file_name);
1647 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
1652 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
1654 case GTK_RESPONSE_ACCEPT:
1656 g_free (de->file_name);
1658 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1660 open_data_file (de->file_name, de);
1667 gtk_widget_destroy (dialog);
1672 /* Update the data_ref_entry with the reference of the active cell */
1674 update_data_ref_entry (const GtkSheet *sheet, gint row, gint col, gpointer data)
1676 GladeXML *data_editor_xml = data;
1678 PsppireDataStore *data_store =
1679 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1681 g_return_val_if_fail (data_editor_xml, FALSE);
1685 const struct variable *var =
1686 psppire_dict_get_variable (data_store->dict, col);
1688 /* The entry where the reference to the current cell is displayed */
1689 GtkEntry *cell_ref_entry =
1690 GTK_ENTRY (get_widget_assert (data_editor_xml,
1692 GtkEntry *datum_entry =
1693 GTK_ENTRY (get_widget_assert (data_editor_xml,
1698 gchar *text = g_strdup_printf ("%d: %s", row + FIRST_CASE_NUMBER,
1699 var_get_name (var));
1701 gchar *s = pspp_locale_to_utf8 (text, -1, 0);
1705 gtk_entry_set_text (cell_ref_entry, s);
1710 gtk_entry_set_text (cell_ref_entry, "");
1716 psppire_data_store_get_string (data_store, row,
1717 var_get_dict_index(var));
1720 gtk_entry_set_text (datum_entry, text);
1725 gtk_entry_set_text (datum_entry, "");
1736 do_sort (PsppireDataStore *ds, int var, gboolean descend)
1738 GString *string = g_string_new ("SORT CASES BY ");
1740 const struct variable *v =
1741 psppire_dict_get_variable (ds->dict, var);
1743 g_string_append_printf (string, "%s", var_get_name (v));
1746 g_string_append (string, " (D)");
1748 g_string_append (string, ".");
1750 execute_syntax (create_syntax_string_source (string->str));
1752 g_string_free (string, TRUE);
1757 sort_up (GtkMenuItem *item, gpointer data)
1759 GtkSheet *sheet = data;
1760 GtkSheetRange range;
1761 gtk_sheet_get_selected_range (sheet, &range);
1763 do_sort (PSPPIRE_DATA_STORE (gtk_sheet_get_model(sheet)),
1769 sort_down (GtkMenuItem *item, gpointer data)
1771 GtkSheet *sheet = data;
1772 GtkSheetRange range;
1773 gtk_sheet_get_selected_range (sheet, &range);
1775 do_sort (PSPPIRE_DATA_STORE (gtk_sheet_get_model(sheet)),
1783 create_data_sheet_variable_popup_menu (struct data_editor *de)
1785 GtkSheet *sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1786 GtkWidget *menu = gtk_menu_new ();
1788 GtkWidget *sort_ascending =
1789 gtk_menu_item_new_with_label (_("Sort Ascending"));
1791 GtkWidget *sort_descending =
1792 gtk_menu_item_new_with_label (_("Sort Descending"));
1795 GtkWidget *insert_variable =
1796 gtk_menu_item_new_with_label (_("Insert Variable"));
1798 GtkWidget *clear_variable =
1799 gtk_menu_item_new_with_label (_("Clear"));
1802 gtk_action_connect_proxy (de->insert_variable,
1806 gtk_action_connect_proxy (de->delete_variables,
1810 gtk_menu_shell_append (GTK_MENU_SHELL (menu), insert_variable);
1813 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
1814 gtk_separator_menu_item_new ());
1817 gtk_menu_shell_append (GTK_MENU_SHELL (menu), clear_variable);
1820 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
1821 gtk_separator_menu_item_new ());
1824 g_signal_connect (G_OBJECT (sort_ascending), "activate",
1825 G_CALLBACK (sort_up), sheet);
1827 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sort_ascending);
1830 g_signal_connect (G_OBJECT (sort_descending), "activate",
1831 G_CALLBACK (sort_down), sheet);
1834 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sort_descending);
1836 gtk_widget_show_all (menu);
1839 de->data_sheet_variable_popup_menu = GTK_MENU(menu);
1844 create_data_sheet_cases_popup_menu (struct data_editor *de)
1846 GtkWidget *menu = gtk_menu_new ();
1848 GtkWidget *insert_case =
1849 gtk_menu_item_new_with_label (_("Insert Case"));
1851 GtkWidget *delete_case =
1852 gtk_menu_item_new_with_label (_("Clear"));
1855 gtk_action_connect_proxy (de->insert_case,
1859 gtk_action_connect_proxy (de->delete_cases,
1863 gtk_menu_shell_append (GTK_MENU_SHELL (menu), insert_case);
1866 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
1867 gtk_separator_menu_item_new ());
1870 gtk_menu_shell_append (GTK_MENU_SHELL (menu), delete_case);
1873 gtk_widget_show_all (menu);
1876 de->data_sheet_cases_popup_menu = GTK_MENU (menu);
1881 popup_variable_menu (GtkSheet *sheet, gint column,
1882 GdkEventButton *event, gpointer data)
1884 struct data_editor *de = data;
1886 PsppireDataStore *data_store =
1887 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1889 const struct variable *v =
1890 psppire_dict_get_variable (data_store->dict, column);
1892 if ( v && event->button == 3)
1895 gtk_sheet_select_column (sheet, column);
1897 gtk_menu_popup (GTK_MENU (de->data_sheet_variable_popup_menu),
1898 NULL, NULL, NULL, NULL,
1899 event->button, event->time);
1905 popup_cases_menu (GtkSheet *sheet, gint row,
1906 GdkEventButton *event, gpointer data)
1908 struct data_editor *de = data;
1910 PsppireDataStore *data_store =
1911 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1913 if ( row <= psppire_data_store_get_case_count (data_store) &&
1916 gtk_sheet_select_row (sheet, row);
1918 gtk_menu_popup (GTK_MENU (de->data_sheet_cases_popup_menu),
1919 NULL, NULL, NULL, NULL,
1920 event->button, event->time);
1926 on_edit_paste (GtkAction *a, gpointer data)
1928 GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1930 gtk_clipboard_request_contents (clipboard,
1931 gdk_atom_intern ("UTF8_STRING", TRUE),
1932 data_sheet_contents_received_callback,
1938 on_edit_copy (GtkMenuItem *m, gpointer data)
1940 struct data_editor *de = data;
1942 GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml,
1945 data_sheet_set_clip (data_sheet);
1951 on_edit_cut (GtkMenuItem *m, gpointer data)
1953 struct data_editor *de = data;
1954 gint max_rows, max_columns;
1956 GtkSheetRange range;
1957 PsppireDataStore *ds;
1958 GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml,
1961 data_sheet_set_clip (data_sheet);
1964 /* Now blank all the cells */
1965 gtk_sheet_get_selected_range (data_sheet, &range);
1967 ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
1970 /* If nothing selected, then use active cell */
1971 if ( range.row0 < 0 || range.col0 < 0 )
1974 gtk_sheet_get_active_cell (data_sheet, &row, &col);
1976 range.row0 = range.rowi = row;
1977 range.col0 = range.coli = col;
1980 /* The sheet range can include cells that do not include data.
1981 Exclude them from the range. */
1982 max_rows = psppire_data_store_get_case_count (ds);
1983 if (range.rowi >= max_rows)
1987 range.rowi = max_rows - 1;
1990 max_columns = dict_get_var_cnt (ds->dict->dict);
1991 if (range.coli >= max_columns)
1993 if (max_columns == 0)
1995 range.coli = max_columns - 1;
1998 g_return_if_fail (range.rowi >= range.row0);
1999 g_return_if_fail (range.row0 >= 0);
2000 g_return_if_fail (range.coli >= range.col0);
2001 g_return_if_fail (range.col0 >= 0);
2004 for (r = range.row0; r <= range.rowi ; ++r )
2008 for (c = range.col0 ; c <= range.coli; ++c)
2010 psppire_data_store_set_string (ds, "", r, c);
2014 /* and remove the selection */
2015 gtk_sheet_unselect_range (data_sheet);