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 "recode-dialog.h"
42 #include "comments-dialog.h"
43 #include "variable-info-dialog.h"
44 #include "descriptives-dialog.h"
45 #include "dict-display.h"
46 #include "clipboard.h"
49 #include "oneway-anova-dialog.h"
50 #include "t-test-independent-samples-dialog.h"
52 #define _(msgid) gettext (msgid)
53 #define N_(msgid) msgid
55 #include "data-editor.h"
56 #include "syntax-editor.h"
57 #include <language/syntax-string-source.h>
58 #include <language/command.h>
59 #include <libpspp/syntax-gen.h>
60 #include "window-manager.h"
62 #include "psppire-data-store.h"
63 #include "psppire-var-store.h"
65 static void on_edit_copy (GtkMenuItem *, gpointer);
66 static void on_edit_cut (GtkMenuItem *, gpointer);
67 static void on_edit_paste (GtkAction *a, gpointer data);
70 static void create_data_sheet_variable_popup_menu (struct data_editor *);
71 static void create_data_sheet_cases_popup_menu (struct data_editor *);
73 static void popup_variable_menu (GtkSheet *, gint,
74 GdkEventButton *, gpointer data);
76 static void popup_cases_menu (GtkSheet *, gint,
77 GdkEventButton *, gpointer data);
79 /* Update the data_ref_entry with the reference of the active cell */
80 static gint update_data_ref_entry (const GtkSheet *sheet,
81 gint row, gint col, gpointer data);
83 static void register_data_editor_actions (struct data_editor *de);
85 static void insert_variable (GtkAction *, gpointer data);
86 static void insert_case (GtkAction *a, gpointer data);
87 static void delete_cases (GtkAction *a, gpointer data);
88 static void delete_variables (GtkAction *a, gpointer data);
90 static void toggle_value_labels (GtkToggleAction *a, gpointer data);
92 /* Switch between the VAR SHEET and the DATA SHEET */
94 static gboolean click2column (GtkWidget *w, gint col, gpointer data);
95 static gboolean click2row (GtkWidget *w, gint row, gpointer data);
98 /* Callback for when the dictionary changes properties*/
99 static void on_weight_change (GObject *, gint, gpointer);
100 static void on_filter_change (GObject *, gint, gpointer);
101 static void on_split_change (PsppireDict *, gpointer);
103 static void on_switch_sheet (GtkNotebook *notebook,
104 GtkNotebookPage *page,
108 static void status_bar_activate (GtkCheckMenuItem *, gpointer);
110 static void grid_lines_activate (GtkCheckMenuItem *, gpointer);
112 static void data_sheet_activate (GtkCheckMenuItem *, gpointer);
114 static void variable_sheet_activate (GtkCheckMenuItem *, gpointer );
116 static void fonts_activate (GtkMenuItem *, gpointer);
118 static void file_quit (GtkCheckMenuItem *, gpointer );
121 enable_delete_cases (GtkWidget *w, gint var, gpointer data)
123 struct data_editor *de = data;
125 gtk_action_set_visible (de->delete_cases, var != -1);
130 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
132 struct data_editor *de = data;
134 gtk_action_set_visible (de->delete_variables, var != -1);
139 /* Run the EXECUTE command. */
141 execute (GtkMenuItem *mi, gpointer data)
143 struct getl_interface *sss = create_syntax_string_source ("EXECUTE.");
145 execute_syntax (sss);
149 transformation_change_callback (bool transformations_pending,
152 struct data_editor *de = data;
153 GtkWidget *menuitem =
154 get_widget_assert (de->xml, "transform_run-pending");
155 GtkWidget *status_label =
156 get_widget_assert (de->xml, "case-counter-area");
158 gtk_widget_set_sensitive (menuitem, transformations_pending);
161 if ( transformations_pending)
162 gtk_label_set_text (GTK_LABEL (status_label),
163 _("Transformations Pending"));
165 gtk_label_set_text (GTK_LABEL (status_label), "");
169 static void open_data_file (const gchar *, struct data_editor *);
172 /* Puts FILE_NAME into the recent list.
173 If it's already in the list, it moves it to the top
176 add_most_recent (const char *file_name)
178 #if RECENT_LISTS_AVAILABLE
180 GtkRecentManager *manager = gtk_recent_manager_get_default();
181 gchar *uri = g_filename_to_uri (file_name, NULL, NULL);
183 gtk_recent_manager_remove_item (manager, uri, NULL);
185 if ( ! gtk_recent_manager_add_item (manager, uri))
186 g_warning ("Could not add item %s to recent list\n",uri);
194 #if RECENT_LISTS_AVAILABLE
197 on_recent_data_select (GtkMenuShell *menushell, gpointer user_data)
200 struct data_editor *de = user_data;
203 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
205 file = g_filename_from_uri (uri, NULL, NULL);
209 open_data_file (file, de);
215 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
219 struct syntax_editor *se ;
222 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
224 file = g_filename_from_uri (uri, NULL, NULL);
228 se = (struct syntax_editor *)
229 window_create (WINDOW_SYNTAX, file);
231 load_editor_from_file (se, file, NULL);
239 datum_entry_activate (GtkEntry *entry, gpointer data)
242 GtkSheet *data_sheet = GTK_SHEET (data);
243 PsppireDataStore *store = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
245 const char *text = gtk_entry_get_text (entry);
247 gtk_sheet_get_active_cell (data_sheet, &row, &column);
249 if ( row == -1 || column == -1)
252 psppire_data_store_set_string (store, text, row, column);
256 /* Update the Edit->Paste menuitem
257 If PAGE is not -1 , then it should be set to the current page of
258 the data editors notebook widget.
259 If -1, then it'll be queried.
262 update_paste_menuitem (struct data_editor *de, gint page)
264 GtkWidget * edit_paste = get_widget_assert (de->xml, "edit_paste");
265 GtkWidget *notebook = get_widget_assert (de->xml, "notebook");
266 GtkSheet * data_sheet ;
270 page = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
273 if ( PAGE_VAR_SHEET == page )
275 /* We don't yet support pasting to the var sheet */
276 gtk_widget_set_sensitive (edit_paste, FALSE);
280 data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
282 gtk_sheet_get_active_cell (data_sheet, &row, &column);
284 if ( row < 0 || column < 0 )
285 gtk_widget_set_sensitive (edit_paste, FALSE);
287 gtk_widget_set_sensitive (edit_paste, TRUE);
290 /* Update the Edit->Cut and Edit->Copy menuitems
291 If PAGE is not -1 , then it should be set to the current page of
292 the data editors notebook widget.
293 If -1, then it'll be queried.
296 update_cut_copy_menuitem (struct data_editor *de, gint page)
298 GtkWidget * edit_copy = get_widget_assert (de->xml, "edit_copy");
299 GtkWidget * edit_cut = get_widget_assert (de->xml, "edit_cut");
300 GtkWidget *notebook = get_widget_assert (de->xml, "notebook");
301 GtkSheet * data_sheet ;
305 page = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
308 if ( PAGE_VAR_SHEET == page )
310 /* We don't yet support copying from the var sheet */
311 gtk_widget_set_sensitive (edit_copy, FALSE);
312 gtk_widget_set_sensitive (edit_cut, FALSE);
316 data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
318 gtk_sheet_get_active_cell (data_sheet, &row, &column);
320 if ( row < 0 || column < 0 )
322 gtk_widget_set_sensitive (edit_copy, FALSE);
323 gtk_widget_set_sensitive (edit_cut, FALSE);
327 gtk_widget_set_sensitive (edit_copy, TRUE);
328 gtk_widget_set_sensitive (edit_cut, TRUE);
332 /* Callback for when the datasheet's active cell becomes active/inactive */
334 on_data_sheet_activate_change (GtkSheet *sheet,
335 gint row, gint column, gpointer data)
337 struct data_editor *de = data;
339 update_paste_menuitem (de, -1);
340 update_cut_copy_menuitem (de, -1);
345 extern struct dataset *the_dataset;
348 Create a new data editor.
351 new_data_editor (void)
353 struct data_editor *de ;
354 struct editor_window *e;
355 GtkSheet *var_sheet ;
356 GtkSheet *data_sheet ;
358 GtkWidget *datum_entry;
360 de = g_malloc0 (sizeof (*de));
362 e = (struct editor_window *) de;
364 de->xml = XML_NEW ("data-editor.glade");
367 dataset_add_transform_change_callback (the_dataset,
368 transformation_change_callback,
371 var_sheet = GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
372 data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
375 g_signal_connect (G_OBJECT (data_sheet), "activate",
376 G_CALLBACK (on_data_sheet_activate_change), de);
378 g_signal_connect (G_OBJECT (data_sheet), "deactivate",
379 G_CALLBACK (on_data_sheet_activate_change), de);
382 vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
384 g_assert(vs); /* Traps a possible bug in win32 build */
386 g_signal_connect (G_OBJECT (data_sheet), "activate",
387 G_CALLBACK (update_data_ref_entry),
390 datum_entry = get_widget_assert (de->xml, "datum_entry");
392 g_signal_connect (G_OBJECT (datum_entry), "activate",
393 G_CALLBACK (datum_entry_activate),
396 g_signal_connect (vs->dict, "weight-changed",
397 G_CALLBACK (on_weight_change),
400 g_signal_connect (vs->dict, "filter-changed",
401 G_CALLBACK (on_filter_change),
404 g_signal_connect (vs->dict, "split-changed",
405 G_CALLBACK (on_split_change),
408 connect_help (de->xml);
412 g_signal_connect (get_widget_assert (de->xml, "edit_copy"),
414 G_CALLBACK (on_edit_copy), de);
416 g_signal_connect (get_widget_assert (de->xml, "edit_cut"),
418 G_CALLBACK (on_edit_cut), de);
421 register_data_editor_actions (de);
423 de->toggle_value_labels =
424 gtk_toggle_action_new ("toggle-value-labels",
426 _("Show/hide value labels"),
427 "pspp-value-labels");
429 g_signal_connect (de->toggle_value_labels, "activate",
430 G_CALLBACK (toggle_value_labels), de);
433 gtk_action_connect_proxy (GTK_ACTION (de->toggle_value_labels),
434 get_widget_assert (de->xml,
435 "togglebutton-value-labels"));
438 gtk_action_connect_proxy (GTK_ACTION (de->toggle_value_labels),
439 get_widget_assert (de->xml,
440 "view_value-labels"));
443 gtk_action_new ("clear-cases",
445 _("Delete the cases at the selected position(s)"),
448 g_signal_connect (de->delete_cases, "activate",
449 G_CALLBACK (delete_cases), de);
451 gtk_action_connect_proxy (de->delete_cases,
452 get_widget_assert (de->xml, "edit_clear-cases"));
454 g_signal_connect (get_widget_assert (de->xml, "edit_paste"), "activate",
455 G_CALLBACK (on_edit_paste), de);
457 gtk_action_set_visible (de->delete_cases, FALSE);
459 de->delete_variables =
460 gtk_action_new ("clear-variables",
462 _("Delete the variables at the selected position(s)"),
463 "pspp-clear-variables");
465 g_signal_connect (de->delete_variables, "activate",
466 G_CALLBACK (delete_variables), de);
468 gtk_action_connect_proxy (de->delete_variables,
469 get_widget_assert (de->xml, "edit_clear-variables")
472 gtk_action_set_visible (de->delete_variables, FALSE);
474 de->insert_variable =
475 gtk_action_new ("insert-variable",
476 _("Insert Variable"),
477 _("Create a new variable at the current position"),
478 "pspp-insert-variable");
480 g_signal_connect (de->insert_variable, "activate",
481 G_CALLBACK (insert_variable), de);
484 gtk_action_connect_proxy (de->insert_variable,
485 get_widget_assert (de->xml, "button-insert-variable")
488 gtk_action_connect_proxy (de->insert_variable,
489 get_widget_assert (de->xml, "edit_insert-variable")
494 gtk_action_new ("insert-case",
496 _("Create a new case at the current position"),
499 g_signal_connect (de->insert_case, "activate",
500 G_CALLBACK (insert_case), de);
503 gtk_action_connect_proxy (de->insert_case,
504 get_widget_assert (de->xml, "button-insert-case")
508 gtk_action_connect_proxy (de->insert_case,
509 get_widget_assert (de->xml, "edit_insert-case")
514 de->invoke_goto_dialog =
515 gtk_action_new ("goto-case-dialog",
517 _("Jump to a Case in the Data Sheet"),
521 gtk_action_connect_proxy (de->invoke_goto_dialog,
522 get_widget_assert (de->xml, "button-goto-case")
525 gtk_action_connect_proxy (de->invoke_goto_dialog,
526 get_widget_assert (de->xml, "edit_goto-case")
530 g_signal_connect (de->invoke_goto_dialog, "activate",
531 G_CALLBACK (goto_case_dialog), de);
534 de->invoke_weight_cases_dialog =
535 gtk_action_new ("weight-cases-dialog",
537 _("Weight cases by variable"),
538 "pspp-weight-cases");
540 g_signal_connect (de->invoke_weight_cases_dialog, "activate",
541 G_CALLBACK (weight_cases_dialog), de);
544 de->invoke_transpose_dialog =
545 gtk_action_new ("transpose-dialog",
547 _("Transpose the cases with the variables"),
551 g_signal_connect (de->invoke_transpose_dialog, "activate",
552 G_CALLBACK (transpose_dialog), de);
556 de->invoke_split_file_dialog =
557 gtk_action_new ("split-file-dialog",
559 _("Split the active file"),
562 g_signal_connect (de->invoke_split_file_dialog, "activate",
563 G_CALLBACK (split_file_dialog), de);
567 de->invoke_sort_cases_dialog =
568 gtk_action_new ("sort-cases-dialog",
570 _("Sort cases in the active file"),
573 g_signal_connect (de->invoke_sort_cases_dialog, "activate",
574 G_CALLBACK (sort_cases_dialog), de);
576 de->invoke_select_cases_dialog =
577 gtk_action_new ("select-cases-dialog",
579 _("Select cases from the active file"),
580 "pspp-select-cases");
582 g_signal_connect (de->invoke_select_cases_dialog, "activate",
583 G_CALLBACK (select_cases_dialog), de);
586 de->invoke_compute_dialog =
587 gtk_action_new ("compute-dialog",
589 _("Compute new values for a variable"),
592 g_signal_connect (de->invoke_compute_dialog, "activate",
593 G_CALLBACK (compute_dialog), de);
595 de->invoke_oneway_anova_dialog =
596 gtk_action_new ("oneway-anova",
598 _("Perform one way analysis of variance"),
601 g_signal_connect (de->invoke_oneway_anova_dialog, "activate",
602 G_CALLBACK (oneway_anova_dialog), de);
604 de->invoke_t_test_independent_samples_dialog =
605 gtk_action_new ("t-test-independent-samples",
606 _("_Independent Samples T Test"),
607 _("Calculate T Test for samples from independent groups"),
610 g_signal_connect (de->invoke_t_test_independent_samples_dialog, "activate",
611 G_CALLBACK (t_test_independent_samples_dialog), de);
614 de->invoke_comments_dialog =
615 gtk_action_new ("commments-dialog",
616 _("Data File Comments"),
617 _("Commentary text for the data file"),
620 g_signal_connect (de->invoke_comments_dialog, "activate",
621 G_CALLBACK (comments_dialog), de);
623 de->invoke_find_dialog =
624 gtk_action_new ("find-dialog",
629 g_signal_connect (de->invoke_find_dialog, "activate",
630 G_CALLBACK (find_dialog), de);
633 de->invoke_rank_dialog =
634 gtk_action_new ("rank-dialog",
639 g_signal_connect (de->invoke_rank_dialog, "activate",
640 G_CALLBACK (rank_dialog), de);
643 de->invoke_recode_same_dialog =
644 gtk_action_new ("recode-same-dialog",
645 _("Recode into _Same Variables"),
646 _("Recode values into the same Variables"),
649 g_signal_connect (de->invoke_recode_same_dialog, "activate",
650 G_CALLBACK (recode_same_dialog), de);
653 de->invoke_recode_different_dialog =
654 gtk_action_new ("recode-different-dialog",
655 _("Recode into _Different Variables"),
656 _("Recode values into different Variables"),
657 "pspp-recode-different");
659 g_signal_connect (de->invoke_recode_different_dialog, "activate",
660 G_CALLBACK (recode_different_dialog), de);
663 de->invoke_variable_info_dialog =
664 gtk_action_new ("variable-info-dialog",
666 _("Jump to Variable"),
667 "pspp-goto-variable");
669 g_signal_connect (de->invoke_variable_info_dialog, "activate",
670 G_CALLBACK (variable_info_dialog), de);
672 de->invoke_descriptives_dialog =
673 gtk_action_new ("descriptives-dialog",
675 _("Calculate descriptive statistics (mean, variance, ...)"),
676 "pspp-descriptives");
678 g_signal_connect (de->invoke_descriptives_dialog, "activate",
679 G_CALLBACK (descriptives_dialog), de);
681 e->window = GTK_WINDOW (get_widget_assert (de->xml, "data_editor"));
683 g_signal_connect_swapped (get_widget_assert (de->xml,"file_new_data"),
685 G_CALLBACK (gtk_action_activate),
686 de->action_data_new);
688 g_signal_connect_swapped (get_widget_assert (de->xml,"file_open_data"),
690 G_CALLBACK (gtk_action_activate),
691 de->action_data_open);
694 #if RECENT_LISTS_AVAILABLE
696 GtkRecentManager *rm = gtk_recent_manager_get_default ();
697 GtkWidget *recent_data = get_widget_assert (de->xml, "file_recent-data");
698 GtkWidget *recent_files = get_widget_assert (de->xml, "file_recent-files");
699 GtkWidget *recent_separator = get_widget_assert (de->xml, "file_separator1");
701 GtkWidget *menu = gtk_recent_chooser_menu_new_for_manager (rm);
703 GtkRecentFilter *filter = gtk_recent_filter_new ();
705 gtk_widget_show (recent_data);
706 gtk_widget_show (recent_files);
707 gtk_widget_show (recent_separator);
709 gtk_recent_filter_add_pattern (filter, "*.sav");
710 gtk_recent_filter_add_pattern (filter, "*.SAV");
712 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
714 gtk_widget_set_sensitive (recent_data, TRUE);
715 g_signal_connect (menu, "selection-done",
716 G_CALLBACK (on_recent_data_select), de);
718 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu);
721 filter = gtk_recent_filter_new ();
722 menu = gtk_recent_chooser_menu_new_for_manager (rm);
724 gtk_recent_filter_add_pattern (filter, "*.sps");
725 gtk_recent_filter_add_pattern (filter, "*.SPS");
727 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
729 gtk_widget_set_sensitive (recent_files, TRUE);
730 g_signal_connect (menu, "selection-done",
731 G_CALLBACK (on_recent_files_select), de);
733 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu);
737 g_signal_connect (get_widget_assert (de->xml,"file_new_syntax"),
739 G_CALLBACK (new_syntax_window),
742 g_signal_connect (get_widget_assert (de->xml,"file_open_syntax"),
744 G_CALLBACK (open_syntax_window),
747 g_signal_connect_swapped (get_widget_assert (de->xml,"file_save"),
749 G_CALLBACK (gtk_action_activate),
750 de->action_data_save);
752 g_signal_connect_swapped (get_widget_assert (de->xml,"file_save_as"),
754 G_CALLBACK (gtk_action_activate),
755 de->action_data_save_as);
757 gtk_action_connect_proxy (de->invoke_find_dialog,
758 get_widget_assert (de->xml, "edit_find")
761 gtk_action_connect_proxy (de->invoke_find_dialog,
762 get_widget_assert (de->xml, "button-find")
765 gtk_action_connect_proxy (de->invoke_rank_dialog,
766 get_widget_assert (de->xml, "transform_rank")
769 gtk_action_connect_proxy (de->invoke_recode_same_dialog,
770 get_widget_assert (de->xml,
771 "transform_recode-same")
774 gtk_action_connect_proxy (de->invoke_recode_different_dialog,
775 get_widget_assert (de->xml,
776 "transform_recode-different")
779 gtk_action_connect_proxy (de->invoke_weight_cases_dialog,
780 get_widget_assert (de->xml, "data_weight-cases")
783 gtk_action_connect_proxy (de->invoke_transpose_dialog,
784 get_widget_assert (de->xml, "data_transpose")
787 gtk_action_connect_proxy (de->invoke_split_file_dialog,
788 get_widget_assert (de->xml, "data_split-file")
791 gtk_action_connect_proxy (de->invoke_sort_cases_dialog,
792 get_widget_assert (de->xml, "data_sort-cases")
795 gtk_action_connect_proxy (de->invoke_select_cases_dialog,
796 get_widget_assert (de->xml, "data_select-cases")
799 gtk_action_connect_proxy (de->invoke_compute_dialog,
800 get_widget_assert (de->xml, "transform_compute")
803 gtk_action_connect_proxy (de->invoke_t_test_independent_samples_dialog,
804 get_widget_assert (de->xml,
809 gtk_action_connect_proxy (de->invoke_oneway_anova_dialog,
810 get_widget_assert (de->xml,
815 gtk_action_connect_proxy (de->invoke_comments_dialog,
816 get_widget_assert (de->xml, "utilities_comments")
819 gtk_action_connect_proxy (de->invoke_variable_info_dialog,
820 get_widget_assert (de->xml, "utilities_variables")
823 gtk_action_connect_proxy (de->invoke_descriptives_dialog,
824 get_widget_assert (de->xml, "analyze_descriptives")
827 g_signal_connect (get_widget_assert (de->xml,"help_about"),
829 G_CALLBACK (about_new),
833 g_signal_connect (get_widget_assert (de->xml,"help_reference"),
835 G_CALLBACK (reference_manual),
838 g_signal_connect (data_sheet,
839 "double-click-column",
840 G_CALLBACK (click2column),
843 g_signal_connect (data_sheet,
845 G_CALLBACK (enable_delete_variables),
848 g_signal_connect (data_sheet,
850 G_CALLBACK (enable_delete_cases),
854 g_signal_connect (var_sheet,
856 GTK_SIGNAL_FUNC (click2row),
859 g_signal_connect_after (var_sheet,
861 G_CALLBACK (enable_delete_variables),
864 g_signal_connect (get_widget_assert (de->xml, "notebook"),
866 G_CALLBACK (on_switch_sheet), de);
869 g_signal_connect (get_widget_assert (de->xml, "view_statusbar"),
871 G_CALLBACK (status_bar_activate), de);
874 g_signal_connect (get_widget_assert (de->xml, "view_gridlines"),
876 G_CALLBACK (grid_lines_activate), de);
880 g_signal_connect (get_widget_assert (de->xml, "view_data"),
882 G_CALLBACK (data_sheet_activate), de);
884 g_signal_connect (get_widget_assert (de->xml, "view_variables"),
886 G_CALLBACK (variable_sheet_activate), de);
890 g_signal_connect (get_widget_assert (de->xml, "view_fonts"),
892 G_CALLBACK (fonts_activate), de);
897 gtk_action_connect_proxy (de->action_data_open,
898 get_widget_assert (de->xml, "button-open")
901 gtk_action_connect_proxy (de->action_data_save,
902 get_widget_assert (de->xml, "button-save")
905 gtk_action_connect_proxy (de->invoke_variable_info_dialog,
906 get_widget_assert (de->xml, "button-goto-variable")
909 gtk_action_connect_proxy (de->invoke_weight_cases_dialog,
910 get_widget_assert (de->xml, "button-weight-cases")
913 gtk_action_connect_proxy (de->invoke_split_file_dialog,
914 get_widget_assert (de->xml, "button-split-file")
917 gtk_action_connect_proxy (de->invoke_select_cases_dialog,
918 get_widget_assert (de->xml, "button-select-cases")
922 g_signal_connect (get_widget_assert (de->xml, "file_quit"),
924 G_CALLBACK (file_quit), de);
926 g_signal_connect (get_widget_assert (de->xml, "transform_run-pending"),
928 G_CALLBACK (execute), de);
931 g_signal_connect (get_widget_assert (de->xml, "windows_minimise_all"),
933 G_CALLBACK (minimise_all_windows), NULL);
936 create_data_sheet_variable_popup_menu (de);
937 create_data_sheet_cases_popup_menu (de);
939 g_signal_connect (G_OBJECT (data_sheet), "button-event-column",
940 G_CALLBACK (popup_variable_menu), de);
942 g_signal_connect (G_OBJECT (data_sheet), "button-event-row",
943 G_CALLBACK (popup_cases_menu), de);
949 /* Callback which occurs when the var sheet's row title
950 button is double clicked */
952 click2row (GtkWidget *w, gint row, gpointer data)
954 struct data_editor *de = data;
955 GtkSheetRange visible_range;
957 gint current_row, current_column;
959 GtkWidget *data_sheet = get_widget_assert (de->xml, "data_sheet");
961 data_editor_select_sheet (de, PAGE_DATA_SHEET);
963 gtk_sheet_get_active_cell (GTK_SHEET (data_sheet),
964 ¤t_row, ¤t_column);
966 gtk_sheet_set_active_cell (GTK_SHEET (data_sheet), current_row, row);
968 gtk_sheet_get_visible_range (GTK_SHEET (data_sheet), &visible_range);
970 if ( row < visible_range.col0 || row > visible_range.coli)
972 gtk_sheet_moveto (GTK_SHEET (data_sheet),
973 current_row, row, 0, 0);
980 /* Callback which occurs when the data sheet's column title
983 click2column (GtkWidget *w, gint col, gpointer data)
985 struct data_editor *de = data;
987 gint current_row, current_column;
989 GtkWidget *var_sheet = get_widget_assert (de->xml, "variable_sheet");
991 data_editor_select_sheet (de, PAGE_VAR_SHEET);
993 gtk_sheet_get_active_cell (GTK_SHEET (var_sheet),
994 ¤t_row, ¤t_column);
996 gtk_sheet_set_active_cell (GTK_SHEET (var_sheet), col, current_column);
1003 new_data_window (GtkMenuItem *menuitem, gpointer parent)
1005 window_create (WINDOW_DATA, NULL);
1008 /* Callback for when the datasheet/varsheet is selected */
1010 on_switch_sheet (GtkNotebook *notebook,
1011 GtkNotebookPage *page,
1015 struct data_editor *de = user_data;
1017 GtkWidget *view_data = get_widget_assert (de->xml, "view_data");
1018 GtkWidget *view_variables = get_widget_assert (de->xml, "view_variables");
1022 case PAGE_VAR_SHEET:
1023 gtk_widget_hide (view_variables);
1024 gtk_widget_show (view_data);
1025 gtk_action_set_sensitive (de->insert_variable, TRUE);
1026 gtk_action_set_sensitive (de->insert_case, FALSE);
1027 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
1029 case PAGE_DATA_SHEET:
1030 gtk_widget_show (view_variables);
1031 gtk_widget_show (view_data);
1032 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
1033 gtk_action_set_sensitive (de->insert_case, TRUE);
1036 g_assert_not_reached ();
1040 update_paste_menuitem (de, page_num);
1041 update_cut_copy_menuitem (de, page_num);
1046 data_editor_select_sheet (struct data_editor *de, gint page)
1048 gtk_notebook_set_current_page
1050 GTK_NOTEBOOK (get_widget_assert (de->xml,"notebook")), page
1057 status_bar_activate (GtkCheckMenuItem *menuitem, gpointer data)
1059 struct data_editor *de = data;
1060 GtkWidget *statusbar = get_widget_assert (de->xml, "status-bar");
1062 if ( gtk_check_menu_item_get_active (menuitem) )
1063 gtk_widget_show (statusbar);
1065 gtk_widget_hide (statusbar);
1070 grid_lines_activate (GtkCheckMenuItem *menuitem, gpointer data)
1072 struct data_editor *de = data;
1073 const bool grid_visible = gtk_check_menu_item_get_active (menuitem);
1075 gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml,
1079 gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml, "data_sheet")),
1086 data_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
1088 struct data_editor *de = data;
1090 data_editor_select_sheet (de, PAGE_DATA_SHEET);
1095 variable_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
1097 struct data_editor *de = data;
1099 data_editor_select_sheet (de, PAGE_VAR_SHEET);
1104 fonts_activate (GtkMenuItem *menuitem, gpointer data)
1106 struct data_editor *de = data;
1108 gtk_font_selection_dialog_new (_("Font Selection"));
1110 gtk_window_set_transient_for (GTK_WINDOW (dialog),
1111 GTK_WINDOW (get_widget_assert (de->xml,
1113 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
1115 GtkSheet *data_sheet =
1116 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1118 GtkSheet *var_sheet =
1119 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1121 PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
1122 PsppireVarStore *vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
1124 const gchar *font = gtk_font_selection_dialog_get_font_name
1125 (GTK_FONT_SELECTION_DIALOG (dialog));
1127 PangoFontDescription* font_desc =
1128 pango_font_description_from_string (font);
1130 psppire_var_store_set_font (vs, font_desc);
1131 psppire_data_store_set_font (ds, font_desc);
1134 gtk_widget_hide (dialog);
1139 /* Callback for the value labels action */
1141 toggle_value_labels (GtkToggleAction *ta, gpointer data)
1143 struct data_editor *de = data;
1145 GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1147 PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
1150 psppire_data_store_show_labels (ds,
1151 gtk_toggle_action_get_active (ta));
1156 file_quit (GtkCheckMenuItem *menuitem, gpointer data)
1158 /* FIXME: Need to be more intelligent here.
1159 Give the user the opportunity to save any unsaved data.
1165 delete_cases (GtkAction *action, gpointer data)
1167 struct data_editor *de = data;
1168 GtkSheet *data_sheet =
1169 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1171 GtkSheetRange range;
1173 PsppireDataStore *data_store = PSPPIRE_DATA_STORE
1174 (gtk_sheet_get_model (data_sheet) );
1177 /* This shouldn't be able to happen, because the action
1178 should be disabled */
1179 g_return_if_fail (gtk_sheet_get_state (data_sheet)
1180 == GTK_SHEET_ROW_SELECTED );
1182 gtk_sheet_get_selected_range (data_sheet, &range);
1184 gtk_sheet_unselect_range (data_sheet);
1186 psppire_data_store_delete_cases (data_store, range.row0,
1187 1 + range.rowi - range.row0);
1192 delete_variables (GtkAction *a, gpointer data)
1194 struct data_editor *de = data;
1195 GtkSheetRange range;
1197 GtkNotebook *notebook = GTK_NOTEBOOK (get_widget_assert (de->xml,
1200 const gint page = gtk_notebook_get_current_page (notebook);
1202 GtkSheet *sheet = GTK_SHEET (get_widget_assert (de->xml,
1203 (page == PAGE_VAR_SHEET) ?
1208 gtk_sheet_get_selected_range (sheet, &range);
1212 case PAGE_VAR_SHEET:
1214 PsppireVarStore *vs =
1215 PSPPIRE_VAR_STORE (gtk_sheet_get_model (sheet));
1217 psppire_dict_delete_variables (vs->dict,
1224 case PAGE_DATA_SHEET:
1226 PsppireDataStore *ds =
1227 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1229 psppire_dict_delete_variables (ds->dict,
1238 gtk_sheet_unselect_range (sheet);
1242 insert_case (GtkAction *action, gpointer data)
1245 struct data_editor *de = data;
1247 GtkSheet *data_sheet =
1248 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1250 PsppireDataStore *ds = PSPPIRE_DATA_STORE
1251 (gtk_sheet_get_model (data_sheet) );
1254 gtk_sheet_get_active_cell (data_sheet, ¤t_row, NULL);
1256 if (current_row < 0) current_row = 0;
1258 psppire_data_store_insert_new_case (ds, current_row);
1261 /* Insert a new variable before the current row in the variable sheet,
1262 or before the current column in the data sheet, whichever is selected */
1264 insert_variable (GtkAction *action, gpointer data)
1266 struct data_editor *de = data;
1269 GtkWidget *notebook = get_widget_assert (de->xml, "notebook");
1271 GtkSheet *var_sheet =
1272 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1274 PsppireVarStore *vs = PSPPIRE_VAR_STORE
1275 (gtk_sheet_get_model (var_sheet) );
1277 switch ( gtk_notebook_get_current_page ( GTK_NOTEBOOK (notebook)) )
1279 case PAGE_VAR_SHEET:
1280 posn = var_sheet->active_cell.row;
1282 case PAGE_DATA_SHEET:
1284 GtkSheet *data_sheet =
1285 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1287 if ( data_sheet->state == GTK_SHEET_COLUMN_SELECTED )
1288 posn = data_sheet->range.col0;
1290 posn = data_sheet->active_cell.col;
1294 g_assert_not_reached ();
1297 if ( posn == -1 ) posn = 0;
1299 psppire_dict_insert_variable (vs->dict, posn, NULL);
1302 /* Callback for when the dictionary changes its split variables */
1304 on_split_change (PsppireDict *dict, gpointer data)
1306 struct data_editor *de = data;
1308 size_t n_split_vars = dict_get_split_cnt (dict->dict);
1310 GtkWidget *split_status_area =
1311 get_widget_assert (de->xml, "split-file-status-area");
1313 if ( n_split_vars == 0 )
1315 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
1321 const struct variable *const * split_vars =
1322 dict_get_split_vars (dict->dict);
1324 text = g_string_new (_("Split by "));
1326 for (i = 0 ; i < n_split_vars - 1; ++i )
1328 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
1330 g_string_append (text, var_get_name (split_vars[i]));
1332 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
1334 g_string_free (text, TRUE);
1339 /* Callback for when the dictionary changes its filter variable */
1341 on_filter_change (GObject *o, gint filter_index, gpointer data)
1343 struct data_editor *de = data;
1344 GtkWidget *filter_status_area =
1345 get_widget_assert (de->xml, "filter-use-status-area");
1347 if ( filter_index == -1 )
1349 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter 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 (_("Filter by %s"), var_get_name (var));
1364 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
1370 /* Callback for when the dictionary changes its weights */
1372 on_weight_change (GObject *o, gint weight_index, gpointer data)
1374 struct data_editor *de = data;
1375 GtkWidget *weight_status_area =
1376 get_widget_assert (de->xml, "weight-status-area");
1378 if ( weight_index == -1 )
1380 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
1384 GtkSheet *var_sheet =
1385 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1387 PsppireVarStore *vs = PSPPIRE_VAR_STORE
1388 (gtk_sheet_get_model (var_sheet) );
1390 struct variable *var = psppire_dict_get_variable (vs->dict,
1393 gchar *text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
1395 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
1404 static void data_save_as_dialog (GtkAction *, struct data_editor *de);
1405 static void new_file (GtkAction *, struct editor_window *de);
1406 static void open_data_dialog (GtkAction *, struct data_editor *de);
1407 static void data_save (GtkAction *action, struct data_editor *e);
1410 /* Create the GtkActions and connect to their signals */
1412 register_data_editor_actions (struct data_editor *de)
1414 de->action_data_open =
1415 gtk_action_new ("data-open-dialog",
1417 _("Open a data file"),
1420 g_signal_connect (de->action_data_open, "activate",
1421 G_CALLBACK (open_data_dialog), de);
1424 de->action_data_save = gtk_action_new ("data-save",
1426 _("Save data to file"),
1429 g_signal_connect (de->action_data_save, "activate",
1430 G_CALLBACK (data_save), de);
1434 de->action_data_save_as = gtk_action_new ("data-save-as-dialog",
1436 _("Save data to file"),
1439 g_signal_connect (de->action_data_save_as, "activate",
1440 G_CALLBACK (data_save_as_dialog), de);
1442 de->action_data_new =
1443 gtk_action_new ("data-new",
1448 g_signal_connect (de->action_data_new, "activate",
1449 G_CALLBACK (new_file), de);
1452 /* Returns true if NAME has a suffix which might denote a PSPP file */
1454 name_has_suffix (const gchar *name)
1456 if ( g_str_has_suffix (name, ".sav"))
1458 if ( g_str_has_suffix (name, ".SAV"))
1460 if ( g_str_has_suffix (name, ".por"))
1462 if ( g_str_has_suffix (name, ".POR"))
1468 /* Append SUFFIX to the filename of DE */
1470 append_filename_suffix (struct data_editor *de, const gchar *suffix)
1472 if ( ! name_has_suffix (de->file_name))
1474 gchar *s = de->file_name;
1475 de->file_name = g_strconcat (de->file_name, suffix, NULL);
1480 /* Save DE to file */
1482 save_file (struct data_editor *de)
1484 struct getl_interface *sss;
1485 struct string file_name ;
1487 g_assert (de->file_name);
1489 ds_init_cstr (&file_name, de->file_name);
1490 gen_quoted_string (&file_name);
1492 if ( de->save_as_portable )
1494 append_filename_suffix (de, ".por");
1495 sss = create_syntax_string_source ("EXPORT OUTFILE=%s.",
1496 ds_cstr (&file_name));
1500 append_filename_suffix (de, ".sav");
1501 sss = create_syntax_string_source ("SAVE OUTFILE=%s.",
1502 ds_cstr (&file_name));
1505 ds_destroy (&file_name);
1507 execute_syntax (sss);
1511 /* Callback for data_save action.
1512 If there's an existing file name, then just save,
1513 otherwise prompt for a file name, then save */
1515 data_save (GtkAction *action, struct data_editor *de)
1520 data_save_as_dialog (action, de);
1524 /* Callback for data_save_as action. Prompt for a filename and save */
1526 data_save_as_dialog (GtkAction *action, struct data_editor *de)
1528 struct editor_window *e = (struct editor_window *) de;
1530 GtkWidget *button_sys;
1532 gtk_file_chooser_dialog_new (_("Save"),
1533 GTK_WINDOW (e->window),
1534 GTK_FILE_CHOOSER_ACTION_SAVE,
1535 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1536 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1539 GtkFileFilter *filter = gtk_file_filter_new ();
1540 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
1541 gtk_file_filter_add_pattern (filter, "*.sav");
1542 gtk_file_filter_add_pattern (filter, "*.SAV");
1543 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1545 filter = gtk_file_filter_new ();
1546 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
1547 gtk_file_filter_add_pattern (filter, "*.por");
1548 gtk_file_filter_add_pattern (filter, "*.POR");
1549 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1551 filter = gtk_file_filter_new ();
1552 gtk_file_filter_set_name (filter, _("All Files"));
1553 gtk_file_filter_add_pattern (filter, "*");
1554 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1557 GtkWidget *button_por;
1558 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
1560 gtk_radio_button_new_with_label (NULL, _("System File"));
1563 gtk_radio_button_new_with_label
1564 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
1565 _("Portable File"));
1567 gtk_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
1568 gtk_box_pack_start_defaults (GTK_BOX (vbox), button_por);
1570 gtk_widget_show_all (vbox);
1572 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
1575 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
1577 case GTK_RESPONSE_ACCEPT:
1579 g_free (de->file_name);
1582 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1584 de->save_as_portable =
1585 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
1589 window_set_name_from_filename (e, de->file_name);
1596 gtk_widget_destroy (dialog);
1600 /* Callback for data_new action.
1601 Performs the NEW FILE command */
1603 new_file (GtkAction *action, struct editor_window *e)
1605 struct data_editor *de = (struct data_editor *) e;
1607 struct getl_interface *sss =
1608 create_syntax_string_source ("NEW FILE.");
1610 execute_syntax (sss);
1612 g_free (de->file_name);
1613 de->file_name = NULL;
1615 default_window_name (e);
1620 open_data_file (const gchar *file_name, struct data_editor *de)
1622 struct getl_interface *sss;
1623 struct string filename;
1625 ds_init_cstr (&filename, file_name);
1627 gen_quoted_string (&filename);
1629 sss = create_syntax_string_source ("GET FILE=%s.",
1630 ds_cstr (&filename));
1631 ds_destroy (&filename);
1633 if (execute_syntax (sss) )
1635 window_set_name_from_filename ((struct editor_window *) de, file_name);
1636 add_most_recent (file_name);
1642 /* Callback for the data_open action.
1643 Prompts for a filename and opens it */
1645 open_data_dialog (GtkAction *action, struct data_editor *de)
1647 struct editor_window *e = (struct editor_window *) de;
1650 gtk_file_chooser_dialog_new (_("Open"),
1651 GTK_WINDOW (e->window),
1652 GTK_FILE_CHOOSER_ACTION_OPEN,
1653 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1654 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1657 GtkFileFilter *filter = gtk_file_filter_new ();
1658 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
1659 gtk_file_filter_add_pattern (filter, "*.sav");
1660 gtk_file_filter_add_pattern (filter, "*.SAV");
1661 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1663 filter = gtk_file_filter_new ();
1664 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
1665 gtk_file_filter_add_pattern (filter, "*.por");
1666 gtk_file_filter_add_pattern (filter, "*.POR");
1667 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1669 filter = gtk_file_filter_new ();
1670 gtk_file_filter_set_name (filter, _("All Files"));
1671 gtk_file_filter_add_pattern (filter, "*");
1672 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1677 gchar *dir_name = g_path_get_dirname (de->file_name);
1678 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
1683 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
1685 case GTK_RESPONSE_ACCEPT:
1687 g_free (de->file_name);
1689 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1691 open_data_file (de->file_name, de);
1698 gtk_widget_destroy (dialog);
1703 /* Update the data_ref_entry with the reference of the active cell */
1705 update_data_ref_entry (const GtkSheet *sheet, gint row, gint col, gpointer data)
1707 GladeXML *data_editor_xml = data;
1709 PsppireDataStore *data_store =
1710 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1712 g_return_val_if_fail (data_editor_xml, FALSE);
1716 const struct variable *var =
1717 psppire_dict_get_variable (data_store->dict, col);
1719 /* The entry where the reference to the current cell is displayed */
1720 GtkEntry *cell_ref_entry =
1721 GTK_ENTRY (get_widget_assert (data_editor_xml,
1723 GtkEntry *datum_entry =
1724 GTK_ENTRY (get_widget_assert (data_editor_xml,
1729 gchar *text = g_strdup_printf ("%d: %s", row + FIRST_CASE_NUMBER,
1730 var_get_name (var));
1732 gchar *s = pspp_locale_to_utf8 (text, -1, 0);
1736 gtk_entry_set_text (cell_ref_entry, s);
1741 gtk_entry_set_text (cell_ref_entry, "");
1747 psppire_data_store_get_string (data_store, row,
1748 var_get_dict_index(var));
1751 gtk_entry_set_text (datum_entry, text);
1756 gtk_entry_set_text (datum_entry, "");
1767 do_sort (PsppireDataStore *ds, int var, gboolean descend)
1769 GString *string = g_string_new ("SORT CASES BY ");
1771 const struct variable *v =
1772 psppire_dict_get_variable (ds->dict, var);
1774 g_string_append_printf (string, "%s", var_get_name (v));
1777 g_string_append (string, " (D)");
1779 g_string_append (string, ".");
1781 execute_syntax (create_syntax_string_source (string->str));
1783 g_string_free (string, TRUE);
1788 sort_up (GtkMenuItem *item, gpointer data)
1790 GtkSheet *sheet = data;
1791 GtkSheetRange range;
1792 gtk_sheet_get_selected_range (sheet, &range);
1794 do_sort (PSPPIRE_DATA_STORE (gtk_sheet_get_model(sheet)),
1800 sort_down (GtkMenuItem *item, gpointer data)
1802 GtkSheet *sheet = data;
1803 GtkSheetRange range;
1804 gtk_sheet_get_selected_range (sheet, &range);
1806 do_sort (PSPPIRE_DATA_STORE (gtk_sheet_get_model(sheet)),
1814 create_data_sheet_variable_popup_menu (struct data_editor *de)
1816 GtkSheet *sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1817 GtkWidget *menu = gtk_menu_new ();
1819 GtkWidget *sort_ascending =
1820 gtk_menu_item_new_with_label (_("Sort Ascending"));
1822 GtkWidget *sort_descending =
1823 gtk_menu_item_new_with_label (_("Sort Descending"));
1826 GtkWidget *insert_variable =
1827 gtk_menu_item_new_with_label (_("Insert Variable"));
1829 GtkWidget *clear_variable =
1830 gtk_menu_item_new_with_label (_("Clear"));
1833 gtk_action_connect_proxy (de->insert_variable,
1837 gtk_action_connect_proxy (de->delete_variables,
1841 gtk_menu_shell_append (GTK_MENU_SHELL (menu), insert_variable);
1844 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
1845 gtk_separator_menu_item_new ());
1848 gtk_menu_shell_append (GTK_MENU_SHELL (menu), clear_variable);
1851 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
1852 gtk_separator_menu_item_new ());
1855 g_signal_connect (G_OBJECT (sort_ascending), "activate",
1856 G_CALLBACK (sort_up), sheet);
1858 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sort_ascending);
1861 g_signal_connect (G_OBJECT (sort_descending), "activate",
1862 G_CALLBACK (sort_down), sheet);
1865 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sort_descending);
1867 gtk_widget_show_all (menu);
1870 de->data_sheet_variable_popup_menu = GTK_MENU(menu);
1875 create_data_sheet_cases_popup_menu (struct data_editor *de)
1877 GtkWidget *menu = gtk_menu_new ();
1879 GtkWidget *insert_case =
1880 gtk_menu_item_new_with_label (_("Insert Case"));
1882 GtkWidget *delete_case =
1883 gtk_menu_item_new_with_label (_("Clear"));
1886 gtk_action_connect_proxy (de->insert_case,
1890 gtk_action_connect_proxy (de->delete_cases,
1894 gtk_menu_shell_append (GTK_MENU_SHELL (menu), insert_case);
1897 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
1898 gtk_separator_menu_item_new ());
1901 gtk_menu_shell_append (GTK_MENU_SHELL (menu), delete_case);
1904 gtk_widget_show_all (menu);
1907 de->data_sheet_cases_popup_menu = GTK_MENU (menu);
1912 popup_variable_menu (GtkSheet *sheet, gint column,
1913 GdkEventButton *event, gpointer data)
1915 struct data_editor *de = data;
1917 PsppireDataStore *data_store =
1918 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1920 const struct variable *v =
1921 psppire_dict_get_variable (data_store->dict, column);
1923 if ( v && event->button == 3)
1926 gtk_sheet_select_column (sheet, column);
1928 gtk_menu_popup (GTK_MENU (de->data_sheet_variable_popup_menu),
1929 NULL, NULL, NULL, NULL,
1930 event->button, event->time);
1936 popup_cases_menu (GtkSheet *sheet, gint row,
1937 GdkEventButton *event, gpointer data)
1939 struct data_editor *de = data;
1941 PsppireDataStore *data_store =
1942 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1944 if ( row <= psppire_data_store_get_case_count (data_store) &&
1947 gtk_sheet_select_row (sheet, row);
1949 gtk_menu_popup (GTK_MENU (de->data_sheet_cases_popup_menu),
1950 NULL, NULL, NULL, NULL,
1951 event->button, event->time);
1957 on_edit_paste (GtkAction *a, gpointer data)
1959 GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1961 gtk_clipboard_request_contents (clipboard,
1962 gdk_atom_intern ("UTF8_STRING", TRUE),
1963 data_sheet_contents_received_callback,
1969 on_edit_copy (GtkMenuItem *m, gpointer data)
1971 struct data_editor *de = data;
1973 GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml,
1976 data_sheet_set_clip (data_sheet);
1982 on_edit_cut (GtkMenuItem *m, gpointer data)
1984 struct data_editor *de = data;
1985 gint max_rows, max_columns;
1987 GtkSheetRange range;
1988 PsppireDataStore *ds;
1989 GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml,
1992 data_sheet_set_clip (data_sheet);
1995 /* Now blank all the cells */
1996 gtk_sheet_get_selected_range (data_sheet, &range);
1998 ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
2001 /* If nothing selected, then use active cell */
2002 if ( range.row0 < 0 || range.col0 < 0 )
2005 gtk_sheet_get_active_cell (data_sheet, &row, &col);
2007 range.row0 = range.rowi = row;
2008 range.col0 = range.coli = col;
2011 /* The sheet range can include cells that do not include data.
2012 Exclude them from the range. */
2013 max_rows = psppire_data_store_get_case_count (ds);
2014 if (range.rowi >= max_rows)
2018 range.rowi = max_rows - 1;
2021 max_columns = dict_get_var_cnt (ds->dict->dict);
2022 if (range.coli >= max_columns)
2024 if (max_columns == 0)
2026 range.coli = max_columns - 1;
2029 g_return_if_fail (range.rowi >= range.row0);
2030 g_return_if_fail (range.row0 >= 0);
2031 g_return_if_fail (range.coli >= range.col0);
2032 g_return_if_fail (range.col0 >= 0);
2035 for (r = range.row0; r <= range.rowi ; ++r )
2039 for (c = range.col0 ; c <= range.coli; ++c)
2041 psppire_data_store_set_string (ds, "", r, c);
2045 /* and remove the selection */
2046 gtk_sheet_unselect_range (data_sheet);