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 "frequencies-dialog.h"
46 #include "dict-display.h"
47 #include "clipboard.h"
50 #include "oneway-anova-dialog.h"
51 #include "t-test-independent-samples-dialog.h"
52 #include "t-test-one-sample.h"
54 #define _(msgid) gettext (msgid)
55 #define N_(msgid) msgid
57 #include "data-editor.h"
58 #include "syntax-editor.h"
59 #include <language/syntax-string-source.h>
60 #include <language/command.h>
61 #include <libpspp/syntax-gen.h>
62 #include "window-manager.h"
64 #include "psppire-data-store.h"
65 #include "psppire-var-store.h"
67 static void on_edit_copy (GtkMenuItem *, gpointer);
68 static void on_edit_cut (GtkMenuItem *, gpointer);
69 static void on_edit_paste (GtkAction *a, gpointer data);
72 static void create_data_sheet_variable_popup_menu (struct data_editor *);
73 static void create_data_sheet_cases_popup_menu (struct data_editor *);
75 static void popup_variable_menu (GtkSheet *, gint,
76 GdkEventButton *, gpointer data);
78 static void popup_cases_menu (GtkSheet *, gint,
79 GdkEventButton *, gpointer data);
81 /* Update the data_ref_entry with the reference of the active cell */
82 static gint update_data_ref_entry (const GtkSheet *sheet,
83 gint row, gint col, gpointer data);
85 static void register_data_editor_actions (struct data_editor *de);
87 static void insert_variable (GtkAction *, gpointer data);
88 static void insert_case (GtkAction *a, gpointer data);
89 static void delete_cases (GtkAction *a, gpointer data);
90 static void delete_variables (GtkAction *a, gpointer data);
92 static void toggle_value_labels (GtkToggleAction *a, gpointer data);
94 /* Switch between the VAR SHEET and the DATA SHEET */
96 static gboolean click2column (GtkWidget *w, gint col, gpointer data);
97 static gboolean click2row (GtkWidget *w, gint row, gpointer data);
100 /* Callback for when the dictionary changes properties*/
101 static void on_weight_change (GObject *, gint, gpointer);
102 static void on_filter_change (GObject *, gint, gpointer);
103 static void on_split_change (PsppireDict *, gpointer);
105 static void on_switch_sheet (GtkNotebook *notebook,
106 GtkNotebookPage *page,
110 static void status_bar_activate (GtkCheckMenuItem *, gpointer);
112 static void grid_lines_activate (GtkCheckMenuItem *, gpointer);
114 static void data_sheet_activate (GtkCheckMenuItem *, gpointer);
116 static void variable_sheet_activate (GtkCheckMenuItem *, gpointer );
118 static void fonts_activate (GtkMenuItem *, gpointer);
120 static void file_quit (GtkCheckMenuItem *, gpointer );
123 enable_delete_cases (GtkWidget *w, gint var, gpointer data)
125 struct data_editor *de = data;
127 gtk_action_set_visible (de->delete_cases, var != -1);
132 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
134 struct data_editor *de = data;
136 gtk_action_set_visible (de->delete_variables, var != -1);
141 /* Run the EXECUTE command. */
143 execute (GtkMenuItem *mi, gpointer data)
145 struct getl_interface *sss = create_syntax_string_source ("EXECUTE.");
147 execute_syntax (sss);
151 transformation_change_callback (bool transformations_pending,
154 struct data_editor *de = data;
155 GtkWidget *menuitem =
156 get_widget_assert (de->xml, "transform_run-pending");
157 GtkWidget *status_label =
158 get_widget_assert (de->xml, "case-counter-area");
160 gtk_widget_set_sensitive (menuitem, transformations_pending);
163 if ( transformations_pending)
164 gtk_label_set_text (GTK_LABEL (status_label),
165 _("Transformations Pending"));
167 gtk_label_set_text (GTK_LABEL (status_label), "");
171 static void open_data_file (const gchar *, struct data_editor *);
174 /* Puts FILE_NAME into the recent list.
175 If it's already in the list, it moves it to the top
178 add_most_recent (const char *file_name)
180 #if RECENT_LISTS_AVAILABLE
182 GtkRecentManager *manager = gtk_recent_manager_get_default();
183 gchar *uri = g_filename_to_uri (file_name, NULL, NULL);
185 gtk_recent_manager_remove_item (manager, uri, NULL);
187 if ( ! gtk_recent_manager_add_item (manager, uri))
188 g_warning ("Could not add item %s to recent list\n",uri);
196 #if RECENT_LISTS_AVAILABLE
199 on_recent_data_select (GtkMenuShell *menushell, gpointer user_data)
202 struct data_editor *de = user_data;
205 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
207 file = g_filename_from_uri (uri, NULL, NULL);
211 open_data_file (file, de);
217 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
221 struct syntax_editor *se ;
224 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
226 file = g_filename_from_uri (uri, NULL, NULL);
230 se = (struct syntax_editor *)
231 window_create (WINDOW_SYNTAX, file);
233 load_editor_from_file (se, file, NULL);
241 datum_entry_activate (GtkEntry *entry, gpointer data)
244 GtkSheet *data_sheet = GTK_SHEET (data);
245 PsppireDataStore *store = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
247 const char *text = gtk_entry_get_text (entry);
249 gtk_sheet_get_active_cell (data_sheet, &row, &column);
251 if ( row == -1 || column == -1)
254 psppire_data_store_set_string (store, text, row, column);
258 /* Update the Edit->Paste menuitem
259 If PAGE is not -1 , then it should be set to the current page of
260 the data editors notebook widget.
261 If -1, then it'll be queried.
264 update_paste_menuitem (struct data_editor *de, gint page)
266 GtkWidget * edit_paste = get_widget_assert (de->xml, "edit_paste");
267 GtkWidget *notebook = get_widget_assert (de->xml, "notebook");
268 GtkSheet * data_sheet ;
272 page = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
275 if ( PAGE_VAR_SHEET == page )
277 /* We don't yet support pasting to the var sheet */
278 gtk_widget_set_sensitive (edit_paste, FALSE);
282 data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
284 gtk_sheet_get_active_cell (data_sheet, &row, &column);
286 if ( row < 0 || column < 0 )
287 gtk_widget_set_sensitive (edit_paste, FALSE);
289 gtk_widget_set_sensitive (edit_paste, TRUE);
292 /* Update the Edit->Cut and Edit->Copy menuitems
293 If PAGE is not -1 , then it should be set to the current page of
294 the data editors notebook widget.
295 If -1, then it'll be queried.
298 update_cut_copy_menuitem (struct data_editor *de, gint page)
300 GtkWidget * edit_copy = get_widget_assert (de->xml, "edit_copy");
301 GtkWidget * edit_cut = get_widget_assert (de->xml, "edit_cut");
302 GtkWidget *notebook = get_widget_assert (de->xml, "notebook");
303 GtkSheet * data_sheet ;
307 page = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
310 if ( PAGE_VAR_SHEET == page )
312 /* We don't yet support copying from the var sheet */
313 gtk_widget_set_sensitive (edit_copy, FALSE);
314 gtk_widget_set_sensitive (edit_cut, FALSE);
318 data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
320 gtk_sheet_get_active_cell (data_sheet, &row, &column);
322 if ( row < 0 || column < 0 )
324 gtk_widget_set_sensitive (edit_copy, FALSE);
325 gtk_widget_set_sensitive (edit_cut, FALSE);
329 gtk_widget_set_sensitive (edit_copy, TRUE);
330 gtk_widget_set_sensitive (edit_cut, TRUE);
334 /* Callback for when the datasheet's active cell becomes active/inactive */
336 on_data_sheet_activate_change (GtkSheet *sheet,
337 gint row, gint column, gpointer data)
339 struct data_editor *de = data;
341 update_paste_menuitem (de, -1);
342 update_cut_copy_menuitem (de, -1);
347 extern struct dataset *the_dataset;
350 Create a new data editor.
353 new_data_editor (void)
355 struct data_editor *de ;
356 struct editor_window *e;
357 GtkSheet *var_sheet ;
358 GtkSheet *data_sheet ;
360 GtkWidget *datum_entry;
362 de = g_malloc0 (sizeof (*de));
364 e = (struct editor_window *) de;
366 de->xml = XML_NEW ("data-editor.glade");
369 dataset_add_transform_change_callback (the_dataset,
370 transformation_change_callback,
373 var_sheet = GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
374 data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
377 g_signal_connect (G_OBJECT (data_sheet), "activate",
378 G_CALLBACK (on_data_sheet_activate_change), de);
380 g_signal_connect (G_OBJECT (data_sheet), "deactivate",
381 G_CALLBACK (on_data_sheet_activate_change), de);
384 vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
386 g_assert(vs); /* Traps a possible bug in win32 build */
388 g_signal_connect (G_OBJECT (data_sheet), "activate",
389 G_CALLBACK (update_data_ref_entry),
392 datum_entry = get_widget_assert (de->xml, "datum_entry");
394 g_signal_connect (G_OBJECT (datum_entry), "activate",
395 G_CALLBACK (datum_entry_activate),
398 g_signal_connect (vs->dict, "weight-changed",
399 G_CALLBACK (on_weight_change),
402 g_signal_connect (vs->dict, "filter-changed",
403 G_CALLBACK (on_filter_change),
406 g_signal_connect (vs->dict, "split-changed",
407 G_CALLBACK (on_split_change),
410 connect_help (de->xml);
414 g_signal_connect (get_widget_assert (de->xml, "edit_copy"),
416 G_CALLBACK (on_edit_copy), de);
418 g_signal_connect (get_widget_assert (de->xml, "edit_cut"),
420 G_CALLBACK (on_edit_cut), de);
423 register_data_editor_actions (de);
425 de->toggle_value_labels =
426 gtk_toggle_action_new ("toggle-value-labels",
428 _("Show/hide value labels"),
429 "pspp-value-labels");
431 g_signal_connect (de->toggle_value_labels, "activate",
432 G_CALLBACK (toggle_value_labels), de);
435 gtk_action_connect_proxy (GTK_ACTION (de->toggle_value_labels),
436 get_widget_assert (de->xml,
437 "togglebutton-value-labels"));
440 gtk_action_connect_proxy (GTK_ACTION (de->toggle_value_labels),
441 get_widget_assert (de->xml,
442 "view_value-labels"));
445 gtk_action_new ("clear-cases",
447 _("Delete the cases at the selected position(s)"),
450 g_signal_connect (de->delete_cases, "activate",
451 G_CALLBACK (delete_cases), de);
453 gtk_action_connect_proxy (de->delete_cases,
454 get_widget_assert (de->xml, "edit_clear-cases"));
456 g_signal_connect (get_widget_assert (de->xml, "edit_paste"), "activate",
457 G_CALLBACK (on_edit_paste), de);
459 gtk_action_set_visible (de->delete_cases, FALSE);
461 de->delete_variables =
462 gtk_action_new ("clear-variables",
464 _("Delete the variables at the selected position(s)"),
465 "pspp-clear-variables");
467 g_signal_connect (de->delete_variables, "activate",
468 G_CALLBACK (delete_variables), de);
470 gtk_action_connect_proxy (de->delete_variables,
471 get_widget_assert (de->xml, "edit_clear-variables")
474 gtk_action_set_visible (de->delete_variables, FALSE);
476 de->insert_variable =
477 gtk_action_new ("insert-variable",
478 _("Insert Variable"),
479 _("Create a new variable at the current position"),
480 "pspp-insert-variable");
482 g_signal_connect (de->insert_variable, "activate",
483 G_CALLBACK (insert_variable), de);
486 gtk_action_connect_proxy (de->insert_variable,
487 get_widget_assert (de->xml, "button-insert-variable")
490 gtk_action_connect_proxy (de->insert_variable,
491 get_widget_assert (de->xml, "edit_insert-variable")
496 gtk_action_new ("insert-case",
498 _("Create a new case at the current position"),
501 g_signal_connect (de->insert_case, "activate",
502 G_CALLBACK (insert_case), de);
505 gtk_action_connect_proxy (de->insert_case,
506 get_widget_assert (de->xml, "button-insert-case")
510 gtk_action_connect_proxy (de->insert_case,
511 get_widget_assert (de->xml, "edit_insert-case")
516 de->invoke_goto_dialog =
517 gtk_action_new ("goto-case-dialog",
519 _("Jump to a Case in the Data Sheet"),
523 gtk_action_connect_proxy (de->invoke_goto_dialog,
524 get_widget_assert (de->xml, "button-goto-case")
527 gtk_action_connect_proxy (de->invoke_goto_dialog,
528 get_widget_assert (de->xml, "edit_goto-case")
532 g_signal_connect (de->invoke_goto_dialog, "activate",
533 G_CALLBACK (goto_case_dialog), de);
536 de->invoke_weight_cases_dialog =
537 gtk_action_new ("weight-cases-dialog",
539 _("Weight cases by variable"),
540 "pspp-weight-cases");
542 g_signal_connect (de->invoke_weight_cases_dialog, "activate",
543 G_CALLBACK (weight_cases_dialog), de);
546 de->invoke_transpose_dialog =
547 gtk_action_new ("transpose-dialog",
549 _("Transpose the cases with the variables"),
553 g_signal_connect (de->invoke_transpose_dialog, "activate",
554 G_CALLBACK (transpose_dialog), de);
558 de->invoke_split_file_dialog =
559 gtk_action_new ("split-file-dialog",
561 _("Split the active file"),
564 g_signal_connect (de->invoke_split_file_dialog, "activate",
565 G_CALLBACK (split_file_dialog), de);
569 de->invoke_sort_cases_dialog =
570 gtk_action_new ("sort-cases-dialog",
572 _("Sort cases in the active file"),
575 g_signal_connect (de->invoke_sort_cases_dialog, "activate",
576 G_CALLBACK (sort_cases_dialog), de);
578 de->invoke_select_cases_dialog =
579 gtk_action_new ("select-cases-dialog",
581 _("Select cases from the active file"),
582 "pspp-select-cases");
584 g_signal_connect (de->invoke_select_cases_dialog, "activate",
585 G_CALLBACK (select_cases_dialog), de);
588 de->invoke_compute_dialog =
589 gtk_action_new ("compute-dialog",
591 _("Compute new values for a variable"),
594 g_signal_connect (de->invoke_compute_dialog, "activate",
595 G_CALLBACK (compute_dialog), de);
597 de->invoke_oneway_anova_dialog =
598 gtk_action_new ("oneway-anova",
600 _("Perform one way analysis of variance"),
603 g_signal_connect (de->invoke_oneway_anova_dialog, "activate",
604 G_CALLBACK (oneway_anova_dialog), de);
606 de->invoke_t_test_independent_samples_dialog =
607 gtk_action_new ("t-test-independent-samples",
608 _("_Independent Samples T Test"),
609 _("Calculate T Test for samples from independent groups"),
612 g_signal_connect (de->invoke_t_test_independent_samples_dialog, "activate",
613 G_CALLBACK (t_test_independent_samples_dialog), de);
616 de->invoke_t_test_one_sample_dialog =
617 gtk_action_new ("t-test-one-sample",
618 _("One _Sample T Test"),
619 _("Calculate T Test for sample from a single distribution"),
622 g_signal_connect (de->invoke_t_test_one_sample_dialog, "activate",
623 G_CALLBACK (t_test_one_sample_dialog), de);
626 de->invoke_comments_dialog =
627 gtk_action_new ("commments-dialog",
628 _("Data File Comments"),
629 _("Commentary text for the data file"),
632 g_signal_connect (de->invoke_comments_dialog, "activate",
633 G_CALLBACK (comments_dialog), de);
635 de->invoke_find_dialog =
636 gtk_action_new ("find-dialog",
641 g_signal_connect (de->invoke_find_dialog, "activate",
642 G_CALLBACK (find_dialog), de);
645 de->invoke_rank_dialog =
646 gtk_action_new ("rank-dialog",
651 g_signal_connect (de->invoke_rank_dialog, "activate",
652 G_CALLBACK (rank_dialog), de);
655 de->invoke_recode_same_dialog =
656 gtk_action_new ("recode-same-dialog",
657 _("Recode into _Same Variables"),
658 _("Recode values into the same Variables"),
661 g_signal_connect (de->invoke_recode_same_dialog, "activate",
662 G_CALLBACK (recode_same_dialog), de);
665 de->invoke_recode_different_dialog =
666 gtk_action_new ("recode-different-dialog",
667 _("Recode into _Different Variables"),
668 _("Recode values into different Variables"),
669 "pspp-recode-different");
671 g_signal_connect (de->invoke_recode_different_dialog, "activate",
672 G_CALLBACK (recode_different_dialog), de);
675 de->invoke_variable_info_dialog =
676 gtk_action_new ("variable-info-dialog",
678 _("Jump to Variable"),
679 "pspp-goto-variable");
681 g_signal_connect (de->invoke_variable_info_dialog, "activate",
682 G_CALLBACK (variable_info_dialog), de);
684 de->invoke_descriptives_dialog =
685 gtk_action_new ("descriptives-dialog",
687 _("Calculate descriptive statistics (mean, variance, ...)"),
688 "pspp-descriptives");
690 g_signal_connect (de->invoke_descriptives_dialog, "activate",
691 G_CALLBACK (descriptives_dialog), de);
694 de->invoke_frequencies_dialog =
695 gtk_action_new ("frequencies-dialog",
697 _("Generate frequency statistics"),
700 g_signal_connect (de->invoke_frequencies_dialog, "activate",
701 G_CALLBACK (frequencies_dialog), de);
704 e->window = GTK_WINDOW (get_widget_assert (de->xml, "data_editor"));
706 g_signal_connect_swapped (get_widget_assert (de->xml,"file_new_data"),
708 G_CALLBACK (gtk_action_activate),
709 de->action_data_new);
711 g_signal_connect_swapped (get_widget_assert (de->xml,"file_open_data"),
713 G_CALLBACK (gtk_action_activate),
714 de->action_data_open);
717 #if RECENT_LISTS_AVAILABLE
719 GtkRecentManager *rm = gtk_recent_manager_get_default ();
720 GtkWidget *recent_data = get_widget_assert (de->xml, "file_recent-data");
721 GtkWidget *recent_files = get_widget_assert (de->xml, "file_recent-files");
722 GtkWidget *recent_separator = get_widget_assert (de->xml, "file_separator1");
724 GtkWidget *menu = gtk_recent_chooser_menu_new_for_manager (rm);
726 GtkRecentFilter *filter = gtk_recent_filter_new ();
728 gtk_widget_show (recent_data);
729 gtk_widget_show (recent_files);
730 gtk_widget_show (recent_separator);
732 gtk_recent_filter_add_pattern (filter, "*.sav");
733 gtk_recent_filter_add_pattern (filter, "*.SAV");
735 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
737 gtk_widget_set_sensitive (recent_data, TRUE);
738 g_signal_connect (menu, "selection-done",
739 G_CALLBACK (on_recent_data_select), de);
741 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu);
744 filter = gtk_recent_filter_new ();
745 menu = gtk_recent_chooser_menu_new_for_manager (rm);
747 gtk_recent_filter_add_pattern (filter, "*.sps");
748 gtk_recent_filter_add_pattern (filter, "*.SPS");
750 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
752 gtk_widget_set_sensitive (recent_files, TRUE);
753 g_signal_connect (menu, "selection-done",
754 G_CALLBACK (on_recent_files_select), de);
756 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu);
760 g_signal_connect (get_widget_assert (de->xml,"file_new_syntax"),
762 G_CALLBACK (new_syntax_window),
765 g_signal_connect (get_widget_assert (de->xml,"file_open_syntax"),
767 G_CALLBACK (open_syntax_window),
770 g_signal_connect_swapped (get_widget_assert (de->xml,"file_save"),
772 G_CALLBACK (gtk_action_activate),
773 de->action_data_save);
775 g_signal_connect_swapped (get_widget_assert (de->xml,"file_save_as"),
777 G_CALLBACK (gtk_action_activate),
778 de->action_data_save_as);
780 gtk_action_connect_proxy (de->invoke_find_dialog,
781 get_widget_assert (de->xml, "edit_find")
784 gtk_action_connect_proxy (de->invoke_find_dialog,
785 get_widget_assert (de->xml, "button-find")
788 gtk_action_connect_proxy (de->invoke_rank_dialog,
789 get_widget_assert (de->xml, "transform_rank")
792 gtk_action_connect_proxy (de->invoke_recode_same_dialog,
793 get_widget_assert (de->xml,
794 "transform_recode-same")
797 gtk_action_connect_proxy (de->invoke_recode_different_dialog,
798 get_widget_assert (de->xml,
799 "transform_recode-different")
802 gtk_action_connect_proxy (de->invoke_weight_cases_dialog,
803 get_widget_assert (de->xml, "data_weight-cases")
806 gtk_action_connect_proxy (de->invoke_transpose_dialog,
807 get_widget_assert (de->xml, "data_transpose")
810 gtk_action_connect_proxy (de->invoke_split_file_dialog,
811 get_widget_assert (de->xml, "data_split-file")
814 gtk_action_connect_proxy (de->invoke_sort_cases_dialog,
815 get_widget_assert (de->xml, "data_sort-cases")
818 gtk_action_connect_proxy (de->invoke_select_cases_dialog,
819 get_widget_assert (de->xml, "data_select-cases")
822 gtk_action_connect_proxy (de->invoke_compute_dialog,
823 get_widget_assert (de->xml, "transform_compute")
826 gtk_action_connect_proxy (de->invoke_t_test_independent_samples_dialog,
827 get_widget_assert (de->xml,
832 gtk_action_connect_proxy (de->invoke_t_test_one_sample_dialog,
833 get_widget_assert (de->xml,
838 gtk_action_connect_proxy (de->invoke_oneway_anova_dialog,
839 get_widget_assert (de->xml,
844 gtk_action_connect_proxy (de->invoke_comments_dialog,
845 get_widget_assert (de->xml, "utilities_comments")
848 gtk_action_connect_proxy (de->invoke_variable_info_dialog,
849 get_widget_assert (de->xml, "utilities_variables")
852 gtk_action_connect_proxy (de->invoke_descriptives_dialog,
853 get_widget_assert (de->xml, "analyze_descriptives")
856 gtk_action_connect_proxy (de->invoke_frequencies_dialog,
857 get_widget_assert (de->xml, "analyze_frequencies")
860 g_signal_connect (get_widget_assert (de->xml,"help_about"),
862 G_CALLBACK (about_new),
866 g_signal_connect (get_widget_assert (de->xml,"help_reference"),
868 G_CALLBACK (reference_manual),
871 g_signal_connect (data_sheet,
872 "double-click-column",
873 G_CALLBACK (click2column),
876 g_signal_connect (data_sheet,
878 G_CALLBACK (enable_delete_variables),
881 g_signal_connect (data_sheet,
883 G_CALLBACK (enable_delete_cases),
887 g_signal_connect (var_sheet,
889 GTK_SIGNAL_FUNC (click2row),
892 g_signal_connect_after (var_sheet,
894 G_CALLBACK (enable_delete_variables),
897 g_signal_connect (get_widget_assert (de->xml, "notebook"),
899 G_CALLBACK (on_switch_sheet), de);
902 g_signal_connect (get_widget_assert (de->xml, "view_statusbar"),
904 G_CALLBACK (status_bar_activate), de);
907 g_signal_connect (get_widget_assert (de->xml, "view_gridlines"),
909 G_CALLBACK (grid_lines_activate), de);
913 g_signal_connect (get_widget_assert (de->xml, "view_data"),
915 G_CALLBACK (data_sheet_activate), de);
917 g_signal_connect (get_widget_assert (de->xml, "view_variables"),
919 G_CALLBACK (variable_sheet_activate), de);
923 g_signal_connect (get_widget_assert (de->xml, "view_fonts"),
925 G_CALLBACK (fonts_activate), de);
930 gtk_action_connect_proxy (de->action_data_open,
931 get_widget_assert (de->xml, "button-open")
934 gtk_action_connect_proxy (de->action_data_save,
935 get_widget_assert (de->xml, "button-save")
938 gtk_action_connect_proxy (de->invoke_variable_info_dialog,
939 get_widget_assert (de->xml, "button-goto-variable")
942 gtk_action_connect_proxy (de->invoke_weight_cases_dialog,
943 get_widget_assert (de->xml, "button-weight-cases")
946 gtk_action_connect_proxy (de->invoke_split_file_dialog,
947 get_widget_assert (de->xml, "button-split-file")
950 gtk_action_connect_proxy (de->invoke_select_cases_dialog,
951 get_widget_assert (de->xml, "button-select-cases")
955 g_signal_connect (get_widget_assert (de->xml, "file_quit"),
957 G_CALLBACK (file_quit), de);
959 g_signal_connect (get_widget_assert (de->xml, "transform_run-pending"),
961 G_CALLBACK (execute), de);
964 g_signal_connect (get_widget_assert (de->xml, "windows_minimise_all"),
966 G_CALLBACK (minimise_all_windows), NULL);
969 create_data_sheet_variable_popup_menu (de);
970 create_data_sheet_cases_popup_menu (de);
972 g_signal_connect (G_OBJECT (data_sheet), "button-event-column",
973 G_CALLBACK (popup_variable_menu), de);
975 g_signal_connect (G_OBJECT (data_sheet), "button-event-row",
976 G_CALLBACK (popup_cases_menu), de);
982 /* Callback which occurs when the var sheet's row title
983 button is double clicked */
985 click2row (GtkWidget *w, gint row, gpointer data)
987 struct data_editor *de = data;
988 GtkSheetRange visible_range;
990 gint current_row, current_column;
992 GtkWidget *data_sheet = get_widget_assert (de->xml, "data_sheet");
994 data_editor_select_sheet (de, PAGE_DATA_SHEET);
996 gtk_sheet_get_active_cell (GTK_SHEET (data_sheet),
997 ¤t_row, ¤t_column);
999 gtk_sheet_set_active_cell (GTK_SHEET (data_sheet), current_row, row);
1001 gtk_sheet_get_visible_range (GTK_SHEET (data_sheet), &visible_range);
1003 if ( row < visible_range.col0 || row > visible_range.coli)
1005 gtk_sheet_moveto (GTK_SHEET (data_sheet),
1006 current_row, row, 0, 0);
1013 /* Callback which occurs when the data sheet's column title
1014 is double clicked */
1016 click2column (GtkWidget *w, gint col, gpointer data)
1018 struct data_editor *de = data;
1020 gint current_row, current_column;
1022 GtkWidget *var_sheet = get_widget_assert (de->xml, "variable_sheet");
1024 data_editor_select_sheet (de, PAGE_VAR_SHEET);
1026 gtk_sheet_get_active_cell (GTK_SHEET (var_sheet),
1027 ¤t_row, ¤t_column);
1029 gtk_sheet_set_active_cell (GTK_SHEET (var_sheet), col, current_column);
1036 new_data_window (GtkMenuItem *menuitem, gpointer parent)
1038 window_create (WINDOW_DATA, NULL);
1041 /* Callback for when the datasheet/varsheet is selected */
1043 on_switch_sheet (GtkNotebook *notebook,
1044 GtkNotebookPage *page,
1048 struct data_editor *de = user_data;
1050 GtkWidget *view_data = get_widget_assert (de->xml, "view_data");
1051 GtkWidget *view_variables = get_widget_assert (de->xml, "view_variables");
1055 case PAGE_VAR_SHEET:
1056 gtk_widget_hide (view_variables);
1057 gtk_widget_show (view_data);
1058 gtk_action_set_sensitive (de->insert_variable, TRUE);
1059 gtk_action_set_sensitive (de->insert_case, FALSE);
1060 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
1062 case PAGE_DATA_SHEET:
1063 gtk_widget_show (view_variables);
1064 gtk_widget_show (view_data);
1065 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
1066 gtk_action_set_sensitive (de->insert_case, TRUE);
1069 g_assert_not_reached ();
1073 update_paste_menuitem (de, page_num);
1074 update_cut_copy_menuitem (de, page_num);
1079 data_editor_select_sheet (struct data_editor *de, gint page)
1081 gtk_notebook_set_current_page
1083 GTK_NOTEBOOK (get_widget_assert (de->xml,"notebook")), page
1090 status_bar_activate (GtkCheckMenuItem *menuitem, gpointer data)
1092 struct data_editor *de = data;
1093 GtkWidget *statusbar = get_widget_assert (de->xml, "status-bar");
1095 if ( gtk_check_menu_item_get_active (menuitem) )
1096 gtk_widget_show (statusbar);
1098 gtk_widget_hide (statusbar);
1103 grid_lines_activate (GtkCheckMenuItem *menuitem, gpointer data)
1105 struct data_editor *de = data;
1106 const bool grid_visible = gtk_check_menu_item_get_active (menuitem);
1108 gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml,
1112 gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml, "data_sheet")),
1119 data_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
1121 struct data_editor *de = data;
1123 data_editor_select_sheet (de, PAGE_DATA_SHEET);
1128 variable_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
1130 struct data_editor *de = data;
1132 data_editor_select_sheet (de, PAGE_VAR_SHEET);
1137 fonts_activate (GtkMenuItem *menuitem, gpointer data)
1139 struct data_editor *de = data;
1141 gtk_font_selection_dialog_new (_("Font Selection"));
1143 gtk_window_set_transient_for (GTK_WINDOW (dialog),
1144 GTK_WINDOW (get_widget_assert (de->xml,
1146 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
1148 GtkSheet *data_sheet =
1149 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1151 GtkSheet *var_sheet =
1152 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1154 PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
1155 PsppireVarStore *vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
1157 const gchar *font = gtk_font_selection_dialog_get_font_name
1158 (GTK_FONT_SELECTION_DIALOG (dialog));
1160 PangoFontDescription* font_desc =
1161 pango_font_description_from_string (font);
1163 psppire_var_store_set_font (vs, font_desc);
1164 psppire_data_store_set_font (ds, font_desc);
1167 gtk_widget_hide (dialog);
1172 /* Callback for the value labels action */
1174 toggle_value_labels (GtkToggleAction *ta, gpointer data)
1176 struct data_editor *de = data;
1178 GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1180 PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
1183 psppire_data_store_show_labels (ds,
1184 gtk_toggle_action_get_active (ta));
1189 file_quit (GtkCheckMenuItem *menuitem, gpointer data)
1191 /* FIXME: Need to be more intelligent here.
1192 Give the user the opportunity to save any unsaved data.
1198 delete_cases (GtkAction *action, gpointer data)
1200 struct data_editor *de = data;
1201 GtkSheet *data_sheet =
1202 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1204 GtkSheetRange range;
1206 PsppireDataStore *data_store = PSPPIRE_DATA_STORE
1207 (gtk_sheet_get_model (data_sheet) );
1210 /* This shouldn't be able to happen, because the action
1211 should be disabled */
1212 g_return_if_fail (gtk_sheet_get_state (data_sheet)
1213 == GTK_SHEET_ROW_SELECTED );
1215 gtk_sheet_get_selected_range (data_sheet, &range);
1217 gtk_sheet_unselect_range (data_sheet);
1219 psppire_data_store_delete_cases (data_store, range.row0,
1220 1 + range.rowi - range.row0);
1225 delete_variables (GtkAction *a, gpointer data)
1227 struct data_editor *de = data;
1228 GtkSheetRange range;
1230 GtkNotebook *notebook = GTK_NOTEBOOK (get_widget_assert (de->xml,
1233 const gint page = gtk_notebook_get_current_page (notebook);
1235 GtkSheet *sheet = GTK_SHEET (get_widget_assert (de->xml,
1236 (page == PAGE_VAR_SHEET) ?
1241 gtk_sheet_get_selected_range (sheet, &range);
1245 case PAGE_VAR_SHEET:
1247 PsppireVarStore *vs =
1248 PSPPIRE_VAR_STORE (gtk_sheet_get_model (sheet));
1250 psppire_dict_delete_variables (vs->dict,
1257 case PAGE_DATA_SHEET:
1259 PsppireDataStore *ds =
1260 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1262 psppire_dict_delete_variables (ds->dict,
1271 gtk_sheet_unselect_range (sheet);
1275 insert_case (GtkAction *action, gpointer data)
1278 struct data_editor *de = data;
1280 GtkSheet *data_sheet =
1281 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1283 PsppireDataStore *ds = PSPPIRE_DATA_STORE
1284 (gtk_sheet_get_model (data_sheet) );
1287 gtk_sheet_get_active_cell (data_sheet, ¤t_row, NULL);
1289 if (current_row < 0) current_row = 0;
1291 psppire_data_store_insert_new_case (ds, current_row);
1294 /* Insert a new variable before the current row in the variable sheet,
1295 or before the current column in the data sheet, whichever is selected */
1297 insert_variable (GtkAction *action, gpointer data)
1299 struct data_editor *de = data;
1302 GtkWidget *notebook = get_widget_assert (de->xml, "notebook");
1304 GtkSheet *var_sheet =
1305 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1307 PsppireVarStore *vs = PSPPIRE_VAR_STORE
1308 (gtk_sheet_get_model (var_sheet) );
1310 switch ( gtk_notebook_get_current_page ( GTK_NOTEBOOK (notebook)) )
1312 case PAGE_VAR_SHEET:
1313 posn = var_sheet->active_cell.row;
1315 case PAGE_DATA_SHEET:
1317 GtkSheet *data_sheet =
1318 GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1320 if ( data_sheet->state == GTK_SHEET_COLUMN_SELECTED )
1321 posn = data_sheet->range.col0;
1323 posn = data_sheet->active_cell.col;
1327 g_assert_not_reached ();
1330 if ( posn == -1 ) posn = 0;
1332 psppire_dict_insert_variable (vs->dict, posn, NULL);
1335 /* Callback for when the dictionary changes its split variables */
1337 on_split_change (PsppireDict *dict, gpointer data)
1339 struct data_editor *de = data;
1341 size_t n_split_vars = dict_get_split_cnt (dict->dict);
1343 GtkWidget *split_status_area =
1344 get_widget_assert (de->xml, "split-file-status-area");
1346 if ( n_split_vars == 0 )
1348 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
1354 const struct variable *const * split_vars =
1355 dict_get_split_vars (dict->dict);
1357 text = g_string_new (_("Split by "));
1359 for (i = 0 ; i < n_split_vars - 1; ++i )
1361 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
1363 g_string_append (text, var_get_name (split_vars[i]));
1365 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
1367 g_string_free (text, TRUE);
1372 /* Callback for when the dictionary changes its filter variable */
1374 on_filter_change (GObject *o, gint filter_index, gpointer data)
1376 struct data_editor *de = data;
1377 GtkWidget *filter_status_area =
1378 get_widget_assert (de->xml, "filter-use-status-area");
1380 if ( filter_index == -1 )
1382 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
1386 GtkSheet *var_sheet =
1387 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1389 PsppireVarStore *vs = PSPPIRE_VAR_STORE
1390 (gtk_sheet_get_model (var_sheet) );
1392 struct variable *var = psppire_dict_get_variable (vs->dict,
1395 gchar *text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
1397 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
1403 /* Callback for when the dictionary changes its weights */
1405 on_weight_change (GObject *o, gint weight_index, gpointer data)
1407 struct data_editor *de = data;
1408 GtkWidget *weight_status_area =
1409 get_widget_assert (de->xml, "weight-status-area");
1411 if ( weight_index == -1 )
1413 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
1417 GtkSheet *var_sheet =
1418 GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
1420 PsppireVarStore *vs = PSPPIRE_VAR_STORE
1421 (gtk_sheet_get_model (var_sheet) );
1423 struct variable *var = psppire_dict_get_variable (vs->dict,
1426 gchar *text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
1428 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
1437 static void data_save_as_dialog (GtkAction *, struct data_editor *de);
1438 static void new_file (GtkAction *, struct editor_window *de);
1439 static void open_data_dialog (GtkAction *, struct data_editor *de);
1440 static void data_save (GtkAction *action, struct data_editor *e);
1443 /* Create the GtkActions and connect to their signals */
1445 register_data_editor_actions (struct data_editor *de)
1447 de->action_data_open =
1448 gtk_action_new ("data-open-dialog",
1450 _("Open a data file"),
1453 g_signal_connect (de->action_data_open, "activate",
1454 G_CALLBACK (open_data_dialog), de);
1457 de->action_data_save = gtk_action_new ("data-save",
1459 _("Save data to file"),
1462 g_signal_connect (de->action_data_save, "activate",
1463 G_CALLBACK (data_save), de);
1467 de->action_data_save_as = gtk_action_new ("data-save-as-dialog",
1469 _("Save data to file"),
1472 g_signal_connect (de->action_data_save_as, "activate",
1473 G_CALLBACK (data_save_as_dialog), de);
1475 de->action_data_new =
1476 gtk_action_new ("data-new",
1481 g_signal_connect (de->action_data_new, "activate",
1482 G_CALLBACK (new_file), de);
1485 /* Returns true if NAME has a suffix which might denote a PSPP file */
1487 name_has_suffix (const gchar *name)
1489 if ( g_str_has_suffix (name, ".sav"))
1491 if ( g_str_has_suffix (name, ".SAV"))
1493 if ( g_str_has_suffix (name, ".por"))
1495 if ( g_str_has_suffix (name, ".POR"))
1501 /* Append SUFFIX to the filename of DE */
1503 append_filename_suffix (struct data_editor *de, const gchar *suffix)
1505 if ( ! name_has_suffix (de->file_name))
1507 gchar *s = de->file_name;
1508 de->file_name = g_strconcat (de->file_name, suffix, NULL);
1513 /* Save DE to file */
1515 save_file (struct data_editor *de)
1517 struct getl_interface *sss;
1518 struct string file_name ;
1520 g_assert (de->file_name);
1522 ds_init_cstr (&file_name, de->file_name);
1523 gen_quoted_string (&file_name);
1525 if ( de->save_as_portable )
1527 append_filename_suffix (de, ".por");
1528 sss = create_syntax_string_source ("EXPORT OUTFILE=%s.",
1529 ds_cstr (&file_name));
1533 append_filename_suffix (de, ".sav");
1534 sss = create_syntax_string_source ("SAVE OUTFILE=%s.",
1535 ds_cstr (&file_name));
1538 ds_destroy (&file_name);
1540 execute_syntax (sss);
1544 /* Callback for data_save action.
1545 If there's an existing file name, then just save,
1546 otherwise prompt for a file name, then save */
1548 data_save (GtkAction *action, struct data_editor *de)
1553 data_save_as_dialog (action, de);
1557 /* Callback for data_save_as action. Prompt for a filename and save */
1559 data_save_as_dialog (GtkAction *action, struct data_editor *de)
1561 struct editor_window *e = (struct editor_window *) de;
1563 GtkWidget *button_sys;
1565 gtk_file_chooser_dialog_new (_("Save"),
1566 GTK_WINDOW (e->window),
1567 GTK_FILE_CHOOSER_ACTION_SAVE,
1568 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1569 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1572 GtkFileFilter *filter = gtk_file_filter_new ();
1573 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
1574 gtk_file_filter_add_pattern (filter, "*.sav");
1575 gtk_file_filter_add_pattern (filter, "*.SAV");
1576 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1578 filter = gtk_file_filter_new ();
1579 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
1580 gtk_file_filter_add_pattern (filter, "*.por");
1581 gtk_file_filter_add_pattern (filter, "*.POR");
1582 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1584 filter = gtk_file_filter_new ();
1585 gtk_file_filter_set_name (filter, _("All Files"));
1586 gtk_file_filter_add_pattern (filter, "*");
1587 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1590 GtkWidget *button_por;
1591 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
1593 gtk_radio_button_new_with_label (NULL, _("System File"));
1596 gtk_radio_button_new_with_label
1597 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
1598 _("Portable File"));
1600 gtk_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
1601 gtk_box_pack_start_defaults (GTK_BOX (vbox), button_por);
1603 gtk_widget_show_all (vbox);
1605 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
1608 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
1610 case GTK_RESPONSE_ACCEPT:
1612 g_free (de->file_name);
1615 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1617 de->save_as_portable =
1618 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
1622 window_set_name_from_filename (e, de->file_name);
1629 gtk_widget_destroy (dialog);
1633 /* Callback for data_new action.
1634 Performs the NEW FILE command */
1636 new_file (GtkAction *action, struct editor_window *e)
1638 struct data_editor *de = (struct data_editor *) e;
1640 struct getl_interface *sss =
1641 create_syntax_string_source ("NEW FILE.");
1643 execute_syntax (sss);
1645 g_free (de->file_name);
1646 de->file_name = NULL;
1648 default_window_name (e);
1653 open_data_file (const gchar *file_name, struct data_editor *de)
1655 struct getl_interface *sss;
1656 struct string filename;
1658 ds_init_cstr (&filename, file_name);
1660 gen_quoted_string (&filename);
1662 sss = create_syntax_string_source ("GET FILE=%s.",
1663 ds_cstr (&filename));
1664 ds_destroy (&filename);
1666 if (execute_syntax (sss) )
1668 window_set_name_from_filename ((struct editor_window *) de, file_name);
1669 add_most_recent (file_name);
1675 /* Callback for the data_open action.
1676 Prompts for a filename and opens it */
1678 open_data_dialog (GtkAction *action, struct data_editor *de)
1680 struct editor_window *e = (struct editor_window *) de;
1683 gtk_file_chooser_dialog_new (_("Open"),
1684 GTK_WINDOW (e->window),
1685 GTK_FILE_CHOOSER_ACTION_OPEN,
1686 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1687 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1690 GtkFileFilter *filter = gtk_file_filter_new ();
1691 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
1692 gtk_file_filter_add_pattern (filter, "*.sav");
1693 gtk_file_filter_add_pattern (filter, "*.SAV");
1694 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1696 filter = gtk_file_filter_new ();
1697 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
1698 gtk_file_filter_add_pattern (filter, "*.por");
1699 gtk_file_filter_add_pattern (filter, "*.POR");
1700 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1702 filter = gtk_file_filter_new ();
1703 gtk_file_filter_set_name (filter, _("All Files"));
1704 gtk_file_filter_add_pattern (filter, "*");
1705 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1710 gchar *dir_name = g_path_get_dirname (de->file_name);
1711 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
1716 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
1718 case GTK_RESPONSE_ACCEPT:
1720 g_free (de->file_name);
1722 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1724 open_data_file (de->file_name, de);
1731 gtk_widget_destroy (dialog);
1736 /* Update the data_ref_entry with the reference of the active cell */
1738 update_data_ref_entry (const GtkSheet *sheet, gint row, gint col, gpointer data)
1740 GladeXML *data_editor_xml = data;
1742 PsppireDataStore *data_store =
1743 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1745 g_return_val_if_fail (data_editor_xml, FALSE);
1749 const struct variable *var =
1750 psppire_dict_get_variable (data_store->dict, col);
1752 /* The entry where the reference to the current cell is displayed */
1753 GtkEntry *cell_ref_entry =
1754 GTK_ENTRY (get_widget_assert (data_editor_xml,
1756 GtkEntry *datum_entry =
1757 GTK_ENTRY (get_widget_assert (data_editor_xml,
1762 gchar *text = g_strdup_printf ("%d: %s", row + FIRST_CASE_NUMBER,
1763 var_get_name (var));
1765 gchar *s = pspp_locale_to_utf8 (text, -1, 0);
1769 gtk_entry_set_text (cell_ref_entry, s);
1774 gtk_entry_set_text (cell_ref_entry, "");
1780 psppire_data_store_get_string (data_store, row,
1781 var_get_dict_index(var));
1784 gtk_entry_set_text (datum_entry, text);
1789 gtk_entry_set_text (datum_entry, "");
1800 do_sort (PsppireDataStore *ds, int var, gboolean descend)
1802 GString *string = g_string_new ("SORT CASES BY ");
1804 const struct variable *v =
1805 psppire_dict_get_variable (ds->dict, var);
1807 g_string_append_printf (string, "%s", var_get_name (v));
1810 g_string_append (string, " (D)");
1812 g_string_append (string, ".");
1814 execute_syntax (create_syntax_string_source (string->str));
1816 g_string_free (string, TRUE);
1821 sort_up (GtkMenuItem *item, gpointer data)
1823 GtkSheet *sheet = data;
1824 GtkSheetRange range;
1825 gtk_sheet_get_selected_range (sheet, &range);
1827 do_sort (PSPPIRE_DATA_STORE (gtk_sheet_get_model(sheet)),
1833 sort_down (GtkMenuItem *item, gpointer data)
1835 GtkSheet *sheet = data;
1836 GtkSheetRange range;
1837 gtk_sheet_get_selected_range (sheet, &range);
1839 do_sort (PSPPIRE_DATA_STORE (gtk_sheet_get_model(sheet)),
1847 create_data_sheet_variable_popup_menu (struct data_editor *de)
1849 GtkSheet *sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
1850 GtkWidget *menu = gtk_menu_new ();
1852 GtkWidget *sort_ascending =
1853 gtk_menu_item_new_with_label (_("Sort Ascending"));
1855 GtkWidget *sort_descending =
1856 gtk_menu_item_new_with_label (_("Sort Descending"));
1859 GtkWidget *insert_variable =
1860 gtk_menu_item_new_with_label (_("Insert Variable"));
1862 GtkWidget *clear_variable =
1863 gtk_menu_item_new_with_label (_("Clear"));
1866 gtk_action_connect_proxy (de->insert_variable,
1870 gtk_action_connect_proxy (de->delete_variables,
1874 gtk_menu_shell_append (GTK_MENU_SHELL (menu), insert_variable);
1877 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
1878 gtk_separator_menu_item_new ());
1881 gtk_menu_shell_append (GTK_MENU_SHELL (menu), clear_variable);
1884 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
1885 gtk_separator_menu_item_new ());
1888 g_signal_connect (G_OBJECT (sort_ascending), "activate",
1889 G_CALLBACK (sort_up), sheet);
1891 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sort_ascending);
1894 g_signal_connect (G_OBJECT (sort_descending), "activate",
1895 G_CALLBACK (sort_down), sheet);
1898 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sort_descending);
1900 gtk_widget_show_all (menu);
1903 de->data_sheet_variable_popup_menu = GTK_MENU(menu);
1908 create_data_sheet_cases_popup_menu (struct data_editor *de)
1910 GtkWidget *menu = gtk_menu_new ();
1912 GtkWidget *insert_case =
1913 gtk_menu_item_new_with_label (_("Insert Case"));
1915 GtkWidget *delete_case =
1916 gtk_menu_item_new_with_label (_("Clear"));
1919 gtk_action_connect_proxy (de->insert_case,
1923 gtk_action_connect_proxy (de->delete_cases,
1927 gtk_menu_shell_append (GTK_MENU_SHELL (menu), insert_case);
1930 gtk_menu_shell_append (GTK_MENU_SHELL (menu),
1931 gtk_separator_menu_item_new ());
1934 gtk_menu_shell_append (GTK_MENU_SHELL (menu), delete_case);
1937 gtk_widget_show_all (menu);
1940 de->data_sheet_cases_popup_menu = GTK_MENU (menu);
1945 popup_variable_menu (GtkSheet *sheet, gint column,
1946 GdkEventButton *event, gpointer data)
1948 struct data_editor *de = data;
1950 PsppireDataStore *data_store =
1951 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1953 const struct variable *v =
1954 psppire_dict_get_variable (data_store->dict, column);
1956 if ( v && event->button == 3)
1959 gtk_sheet_select_column (sheet, column);
1961 gtk_menu_popup (GTK_MENU (de->data_sheet_variable_popup_menu),
1962 NULL, NULL, NULL, NULL,
1963 event->button, event->time);
1969 popup_cases_menu (GtkSheet *sheet, gint row,
1970 GdkEventButton *event, gpointer data)
1972 struct data_editor *de = data;
1974 PsppireDataStore *data_store =
1975 PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
1977 if ( row <= psppire_data_store_get_case_count (data_store) &&
1980 gtk_sheet_select_row (sheet, row);
1982 gtk_menu_popup (GTK_MENU (de->data_sheet_cases_popup_menu),
1983 NULL, NULL, NULL, NULL,
1984 event->button, event->time);
1990 on_edit_paste (GtkAction *a, gpointer data)
1992 GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1994 gtk_clipboard_request_contents (clipboard,
1995 gdk_atom_intern ("UTF8_STRING", TRUE),
1996 data_sheet_contents_received_callback,
2002 on_edit_copy (GtkMenuItem *m, gpointer data)
2004 struct data_editor *de = data;
2006 GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml,
2009 data_sheet_set_clip (data_sheet);
2015 on_edit_cut (GtkMenuItem *m, gpointer data)
2017 struct data_editor *de = data;
2018 gint max_rows, max_columns;
2020 GtkSheetRange range;
2021 PsppireDataStore *ds;
2022 GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml,
2025 data_sheet_set_clip (data_sheet);
2028 /* Now blank all the cells */
2029 gtk_sheet_get_selected_range (data_sheet, &range);
2031 ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
2034 /* If nothing selected, then use active cell */
2035 if ( range.row0 < 0 || range.col0 < 0 )
2038 gtk_sheet_get_active_cell (data_sheet, &row, &col);
2040 range.row0 = range.rowi = row;
2041 range.col0 = range.coli = col;
2044 /* The sheet range can include cells that do not include data.
2045 Exclude them from the range. */
2046 max_rows = psppire_data_store_get_case_count (ds);
2047 if (range.rowi >= max_rows)
2051 range.rowi = max_rows - 1;
2054 max_columns = dict_get_var_cnt (ds->dict->dict);
2055 if (range.coli >= max_columns)
2057 if (max_columns == 0)
2059 range.coli = max_columns - 1;
2062 g_return_if_fail (range.rowi >= range.row0);
2063 g_return_if_fail (range.row0 >= 0);
2064 g_return_if_fail (range.coli >= range.col0);
2065 g_return_if_fail (range.col0 >= 0);
2068 for (r = range.row0; r <= range.rowi ; ++r )
2072 for (c = range.col0 ; c <= range.coli; ++c)
2074 psppire_data_store_set_string (ds, "", r, c);
2078 /* and remove the selection */
2079 gtk_sheet_unselect_range (data_sheet);