1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012 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/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/binomial-dialog.h"
30 #include "ui/gui/builder-wrapper.h"
31 #include "ui/gui/chi-square-dialog.h"
32 #include "ui/gui/comments-dialog.h"
33 #include "ui/gui/compute-dialog.h"
34 #include "ui/gui/count-dialog.h"
35 #include "ui/gui/crosstabs-dialog.h"
36 #include "ui/gui/entry-dialog.h"
37 #include "ui/gui/executor.h"
38 #include "ui/gui/factor-dialog.h"
39 #include "ui/gui/find-dialog.h"
40 #include "ui/gui/frequencies-dialog.h"
41 #include "ui/gui/goto-case-dialog.h"
42 #include "ui/gui/help-menu.h"
43 #include "ui/gui/helper.h"
44 #include "ui/gui/helper.h"
45 #include "ui/gui/k-related-dialog.h"
46 #include "ui/gui/npar-two-sample-related.h"
47 #include "ui/gui/oneway-anova-dialog.h"
48 #include "ui/gui/psppire-data-window.h"
49 #include "ui/gui/psppire-syntax-window.h"
50 #include "ui/gui/psppire-window.h"
51 #include "ui/gui/psppire.h"
52 #include "ui/gui/rank-dialog.h"
53 #include "ui/gui/runs-dialog.h"
54 #include "ui/gui/ks-one-sample-dialog.h"
55 #include "ui/gui/recode-dialog.h"
56 #include "ui/gui/regression-dialog.h"
57 #include "ui/gui/select-cases-dialog.h"
58 #include "ui/gui/split-file-dialog.h"
59 #include "ui/gui/t-test-independent-samples-dialog.h"
60 #include "ui/gui/t-test-one-sample.h"
61 #include "ui/gui/t-test-paired-samples.h"
62 #include "ui/gui/text-data-import-dialog.h"
63 #include "ui/gui/transpose-dialog.h"
64 #include "ui/gui/univariate-dialog.h"
65 #include "ui/gui/weight-cases-dialog.h"
66 #include "ui/syntax-gen.h"
68 #include "gl/c-strcase.h"
69 #include "gl/c-strcasestr.h"
70 #include "gl/xvasprintf.h"
73 #define _(msgid) gettext (msgid)
74 #define N_(msgid) msgid
76 struct session *the_session;
77 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
79 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
80 static void psppire_data_window_init (PsppireDataWindow *data_editor);
83 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
85 static void psppire_data_window_dispose (GObject *object);
86 static void psppire_data_window_set_property (GObject *object,
90 static void psppire_data_window_get_property (GObject *object,
96 psppire_data_window_get_type (void)
98 static GType psppire_data_window_type = 0;
100 if (!psppire_data_window_type)
102 static const GTypeInfo psppire_data_window_info =
104 sizeof (PsppireDataWindowClass),
107 (GClassInitFunc)psppire_data_window_class_init,
108 (GClassFinalizeFunc) NULL,
110 sizeof (PsppireDataWindow),
112 (GInstanceInitFunc) psppire_data_window_init,
115 static const GInterfaceInfo window_interface_info =
117 (GInterfaceInitFunc) psppire_data_window_iface_init,
122 psppire_data_window_type =
123 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
124 &psppire_data_window_info, 0);
127 g_type_add_interface_static (psppire_data_window_type,
128 PSPPIRE_TYPE_WINDOW_MODEL,
129 &window_interface_info);
132 return psppire_data_window_type;
135 static GObjectClass *parent_class ;
142 psppire_data_window_class_init (PsppireDataWindowClass *class)
144 GObjectClass *object_class = G_OBJECT_CLASS (class);
146 parent_class = g_type_class_peek_parent (class);
148 object_class->dispose = psppire_data_window_dispose;
149 object_class->set_property = psppire_data_window_set_property;
150 object_class->get_property = psppire_data_window_get_property;
152 g_object_class_install_property (
153 object_class, PROP_DATASET,
154 g_param_spec_pointer ("dataset", "Dataset",
155 "'struct datset *' represented by the window",
156 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
160 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
162 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
164 gtk_action_set_sensitive (edit_paste, x);
168 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
170 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
171 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
173 gtk_action_set_sensitive (edit_copy, x);
174 gtk_action_set_sensitive (edit_cut, x);
177 /* Run the EXECUTE command. */
179 execute (PsppireDataWindow *dw)
181 execute_const_syntax_string (dw, "EXECUTE.");
185 transformation_change_callback (bool transformations_pending,
188 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
190 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
192 GtkWidget *menuitem =
193 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
195 GtkWidget *status_label =
196 get_widget_assert (de->builder, "case-counter-area");
198 gtk_widget_set_sensitive (menuitem, transformations_pending);
201 if ( transformations_pending)
202 gtk_label_set_text (GTK_LABEL (status_label),
203 _("Transformations Pending"));
205 gtk_label_set_text (GTK_LABEL (status_label), "");
208 /* Callback for when the dictionary changes its filter variable */
210 on_filter_change (GObject *o, gint filter_index, gpointer data)
212 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
214 GtkWidget *filter_status_area =
215 get_widget_assert (de->builder, "filter-use-status-area");
217 if ( filter_index == -1 )
219 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
223 PsppireVarStore *vs = NULL;
224 PsppireDict *dict = NULL;
225 struct variable *var ;
228 g_object_get (de->data_editor, "var-store", &vs, NULL);
229 g_object_get (vs, "dictionary", &dict, NULL);
231 var = psppire_dict_get_variable (dict, filter_index);
233 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
235 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
241 /* Callback for when the dictionary changes its split variables */
243 on_split_change (PsppireDict *dict, gpointer data)
245 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
247 size_t n_split_vars = dict_get_split_cnt (dict->dict);
249 GtkWidget *split_status_area =
250 get_widget_assert (de->builder, "split-file-status-area");
252 if ( n_split_vars == 0 )
254 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
260 const struct variable *const * split_vars =
261 dict_get_split_vars (dict->dict);
263 text = g_string_new (_("Split by "));
265 for (i = 0 ; i < n_split_vars - 1; ++i )
267 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
269 g_string_append (text, var_get_name (split_vars[i]));
271 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
273 g_string_free (text, TRUE);
280 /* Callback for when the dictionary changes its weights */
282 on_weight_change (GObject *o, gint weight_index, gpointer data)
284 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
286 GtkWidget *weight_status_area =
287 get_widget_assert (de->builder, "weight-status-area");
289 if ( weight_index == -1 )
291 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
295 struct variable *var ;
296 PsppireVarStore *vs = NULL;
297 PsppireDict *dict = NULL;
300 g_object_get (de->data_editor, "var-store", &vs, NULL);
301 g_object_get (vs, "dictionary", &dict, NULL);
303 var = psppire_dict_get_variable (dict, weight_index);
305 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
307 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
315 dump_rm (GtkRecentManager *rm)
317 GList *items = gtk_recent_manager_get_items (rm);
321 g_print ("Recent Items:\n");
322 for (i = items; i; i = i->next)
324 GtkRecentInfo *ri = i->data;
326 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
327 gtk_recent_info_get_short_name (ri),
328 gtk_recent_info_get_mime_type (ri),
329 gtk_recent_info_get_description (ri),
330 gtk_recent_info_get_uri (ri)
334 gtk_recent_info_unref (ri);
342 name_has_por_suffix (const gchar *name)
344 size_t length = strlen (name);
345 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
349 name_has_sav_suffix (const gchar *name)
351 size_t length = strlen (name);
352 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
355 /* Returns true if NAME has a suffix which might denote a PSPP file */
357 name_has_suffix (const gchar *name)
359 return name_has_por_suffix (name) || name_has_sav_suffix (name);
363 load_file (PsppireWindow *de, const gchar *file_name)
365 struct string filename;
366 gchar *utf8_file_name;
367 const char *mime_type;
371 ds_init_empty (&filename);
373 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
375 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
377 g_free (utf8_file_name);
379 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
380 ds_destroy (&filename);
382 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
383 lex_reader_for_string (syntax));
386 mime_type = (name_has_por_suffix (file_name)
387 ? "application/x-spss-por"
388 : "application/x-spss-sav");
390 add_most_recent (file_name, mime_type);
395 /* Save DE to file */
397 save_file (PsppireWindow *w)
399 const gchar *file_name = NULL;
400 gchar *utf8_file_name = NULL;
402 struct string filename ;
403 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
406 file_name = psppire_window_get_filename (w);
408 fnx = g_string_new (file_name);
410 if ( ! name_has_suffix (fnx->str))
412 if ( de->save_as_portable)
413 g_string_append (fnx, ".por");
415 g_string_append (fnx, ".sav");
418 ds_init_empty (&filename);
420 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
422 g_string_free (fnx, TRUE);
424 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
425 g_free (utf8_file_name);
427 syntax = g_strdup_printf ("%s OUTFILE=%s.",
428 de->save_as_portable ? "EXPORT" : "SAVE",
429 ds_cstr (&filename));
431 ds_destroy (&filename);
433 g_free (execute_syntax_string (de, syntax));
438 insert_case (PsppireDataWindow *dw)
440 psppire_data_editor_insert_case (dw->data_editor);
444 on_insert_variable (PsppireDataWindow *dw)
446 psppire_data_editor_insert_variable (dw->data_editor);
451 display_dict (PsppireDataWindow *de)
453 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
457 sysfile_info (PsppireDataWindow *de)
459 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
461 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
463 struct string filename;
465 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
467 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
472 ds_init_empty (&filename);
474 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
476 g_free (utf8_file_name);
478 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
479 g_free (execute_syntax_string (de, syntax));
482 gtk_widget_destroy (dialog);
486 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
488 data_pick_filename (PsppireWindow *window)
490 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
491 GtkFileFilter *filter = gtk_file_filter_new ();
492 GtkWidget *button_sys;
494 gtk_file_chooser_dialog_new (_("Save"),
496 GTK_FILE_CHOOSER_ACTION_SAVE,
497 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
498 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
501 g_object_set (dialog, "local-only", FALSE, NULL);
503 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
504 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
505 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
507 filter = gtk_file_filter_new ();
508 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
509 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
510 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
512 filter = gtk_file_filter_new ();
513 gtk_file_filter_set_name (filter, _("All Files"));
514 gtk_file_filter_add_pattern (filter, "*");
515 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
518 GtkWidget *button_por;
519 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
521 gtk_radio_button_new_with_label (NULL, _("System File"));
524 gtk_radio_button_new_with_label
525 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
528 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
529 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
531 gtk_widget_show_all (vbox);
533 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
536 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
539 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
541 case GTK_RESPONSE_ACCEPT:
546 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
549 de->save_as_portable =
550 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
552 if ( ! name_has_suffix (filename->str))
554 if ( de->save_as_portable)
555 g_string_append (filename, ".por");
557 g_string_append (filename, ".sav");
560 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
562 g_string_free (filename, TRUE);
569 gtk_widget_destroy (dialog);
573 confirm_delete_dataset (PsppireDataWindow *de,
574 const char *old_dataset,
575 const char *new_dataset,
576 const char *existing_dataset)
581 dialog = gtk_message_dialog_new (
582 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
583 _("Delete Existing Dataset?"));
585 gtk_message_dialog_format_secondary_text (
586 GTK_MESSAGE_DIALOG (dialog),
587 _("Renaming \"%s\" to \"%s\" will destroy the existing "
588 "dataset named \"%s\". Are you sure that you want to do this?"),
589 old_dataset, new_dataset, existing_dataset);
591 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
592 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
593 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
596 g_object_set (dialog, "icon-name", "pspp", NULL);
598 result = gtk_dialog_run (GTK_DIALOG (dialog));
600 gtk_widget_destroy (dialog);
602 return result == GTK_RESPONSE_OK;
606 on_rename_dataset (PsppireDataWindow *de)
608 struct dataset *ds = de->dataset;
609 struct session *session = dataset_session (ds);
610 const char *old_name = dataset_name (ds);
611 struct dataset *existing_dataset;
615 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
617 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
621 if (new_name == NULL)
624 existing_dataset = session_lookup_dataset (session, new_name);
625 if (existing_dataset == NULL || existing_dataset == ds
626 || confirm_delete_dataset (de, old_name, new_name,
627 dataset_name (existing_dataset)))
628 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
635 on_edit_paste (PsppireDataWindow *de)
637 psppire_data_editor_clip_paste (de->data_editor);
641 on_edit_copy (PsppireDataWindow *de)
643 psppire_data_editor_clip_copy (de->data_editor);
649 on_edit_cut (PsppireDataWindow *de)
651 psppire_data_editor_clip_cut (de->data_editor);
656 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
658 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
660 if ( gtk_toggle_action_get_active (action))
661 gtk_widget_show (statusbar);
663 gtk_widget_hide (statusbar);
668 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
670 const gboolean grid_visible = gtk_toggle_action_get_active (action);
672 psppire_data_editor_show_grid (de->data_editor, grid_visible);
676 data_view_activate (PsppireDataWindow *de)
678 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
683 variable_view_activate (PsppireDataWindow *de)
685 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
690 fonts_activate (PsppireDataWindow *de)
692 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
693 PangoFontDescription *current_font;
696 gtk_font_selection_dialog_new (_("Font Selection"));
699 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
700 font_name = pango_font_description_to_string (current_font);
702 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
706 gtk_window_set_transient_for (GTK_WINDOW (dialog),
707 GTK_WINDOW (toplevel));
709 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
711 const gchar *font = gtk_font_selection_dialog_get_font_name
712 (GTK_FONT_SELECTION_DIALOG (dialog));
714 PangoFontDescription* font_desc =
715 pango_font_description_from_string (font);
717 psppire_data_editor_set_font (de->data_editor, font_desc);
720 gtk_widget_hide (dialog);
725 /* Callback for the value labels action */
727 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
729 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
733 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
735 psppire_data_editor_split_window (de->data_editor,
736 gtk_toggle_action_get_active (ta));
741 file_quit (PsppireDataWindow *de)
743 /* FIXME: Need to be more intelligent here.
744 Give the user the opportunity to save any unsaved data.
751 on_recent_data_select (GtkMenuShell *menushell,
752 PsppireWindow *window)
757 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
759 file = g_filename_from_uri (uri, NULL, NULL);
763 open_data_window (window, file);
769 charset_from_mime_type (const char *mime_type)
775 if (mime_type == NULL)
778 charset = c_strcasestr (mime_type, "charset=");
786 /* Parse a "quoted-string" as defined by RFC 822. */
787 for (p++; *p != '\0' && *p != '"'; p++)
790 ds_put_byte (&s, *p);
791 else if (*++p != '\0')
792 ds_put_byte (&s, *p);
797 /* Parse a "token" as defined by RFC 2045. */
798 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
799 ds_put_byte (&s, *p++);
801 if (!ds_is_empty (&s))
802 return ds_steal_cstr (&s);
809 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
816 /* Get the file name and its encoding. */
817 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
818 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
819 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
820 gtk_recent_info_unref (item);
822 se = psppire_syntax_window_new (encoding);
826 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
827 gtk_widget_show (se);
829 gtk_widget_destroy (se);
837 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
839 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
841 gtk_action_set_visible (de->delete_cases, case_num != -1);
846 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
848 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
850 gtk_action_set_visible (de->delete_variables, var != -1);
853 /* Callback for when the datasheet/varsheet is selected */
855 on_switch_sheet (GtkNotebook *notebook,
856 GtkNotebookPage *page,
860 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
862 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
864 GtkWidget *view_data =
865 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
867 GtkWidget *view_variables =
868 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
872 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
873 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
875 gtk_action_set_sensitive (de->insert_variable, TRUE);
876 gtk_action_set_sensitive (de->insert_case, FALSE);
877 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
879 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
880 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
881 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
882 gtk_action_set_sensitive (de->insert_case, TRUE);
885 g_assert_not_reached ();
890 update_paste_menuitem (de, page_num);
897 set_unsaved (gpointer w)
899 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
903 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
904 Returns a pointer to the action
907 connect_action (PsppireDataWindow *dw, const char *action_name,
910 GtkAction *action = get_action_assert (dw->builder, action_name);
912 g_signal_connect_swapped (action, "activate", handler, dw);
917 /* Initializes as much of a PsppireDataWindow as we can and must before the
918 dataset has been set.
920 In particular, the 'menu' member is required in case the "filename" property
921 is set before the "dataset" property: otherwise PsppireWindow will try to
922 modify the menu as part of the "filename" property_set() function and end up
923 with a Gtk-CRITICAL since 'menu' is NULL. */
925 psppire_data_window_init (PsppireDataWindow *de)
929 de->builder = builder_new ("data-editor.ui");
931 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
933 PSPPIRE_WINDOW (de)->menu =
934 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
938 psppire_data_window_finish_init (PsppireDataWindow *de,
941 static const struct dataset_callbacks cbs =
943 set_unsaved, /* changed */
944 transformation_change_callback, /* transformations_changed */
953 GtkWidget *box = gtk_vbox_new (FALSE, 0);
956 dict = psppire_dict_new_from_dict (dataset_dict (ds));
957 de->var_store = psppire_var_store_new (dict);
958 de->data_store = psppire_data_store_new (dict);
959 psppire_data_store_set_reader (de->data_store, NULL);
961 menubar = get_widget_assert (de->builder, "menubar");
962 hb = get_widget_assert (de->builder, "handlebox1");
963 sb = get_widget_assert (de->builder, "status-bar");
966 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
969 g_signal_connect_swapped (de->data_store, "case-changed",
970 G_CALLBACK (set_unsaved), de);
972 g_signal_connect_swapped (de->data_store, "case-inserted",
973 G_CALLBACK (set_unsaved), de);
975 g_signal_connect_swapped (de->data_store, "cases-deleted",
976 G_CALLBACK (set_unsaved), de);
978 dataset_set_callbacks (de->dataset, &cbs, de);
980 connect_help (de->builder);
982 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
983 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
984 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
985 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
987 gtk_container_add (GTK_CONTAINER (de), box);
989 set_cut_copy_menuitem_sensitivity (de, FALSE);
991 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
992 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
995 set_paste_menuitem_sensitivity (de, FALSE);
997 g_signal_connect_swapped (de->data_editor, "data-available-changed",
998 G_CALLBACK (set_paste_menuitem_sensitivity), de);
1000 g_signal_connect (dict, "weight-changed",
1001 G_CALLBACK (on_weight_change),
1004 g_signal_connect (dict, "filter-changed",
1005 G_CALLBACK (on_filter_change),
1008 g_signal_connect (dict, "split-changed",
1009 G_CALLBACK (on_split_change),
1013 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1015 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1017 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1019 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1021 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1023 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1025 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1027 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1029 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1031 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1033 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1035 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1037 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1039 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1041 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1044 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1046 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1048 gtk_action_set_visible (de->delete_cases, FALSE);
1053 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1055 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1057 gtk_action_set_visible (de->delete_variables, FALSE);
1061 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1063 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1065 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1067 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1069 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1071 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1073 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1075 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1077 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1079 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1081 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1083 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1085 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1087 connect_action (de, "transform_rank", G_CALLBACK (rank_dialog));
1089 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1091 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1093 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1095 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1097 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1098 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1100 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1102 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1104 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1105 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1106 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1107 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1108 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1109 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1113 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1115 GtkWidget *recent_data =
1116 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1118 GtkWidget *recent_files =
1119 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1122 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1123 gtk_recent_manager_get_default ());
1125 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1126 gtk_recent_manager_get_default ());
1128 g_object_set (menu_data, "show-tips", TRUE, NULL);
1129 g_object_set (menu_files, "show-tips", TRUE, NULL);
1132 GtkRecentFilter *filter = gtk_recent_filter_new ();
1134 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1135 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1137 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1139 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1142 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1145 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1148 GtkRecentFilter *filter = gtk_recent_filter_new ();
1150 gtk_recent_filter_add_pattern (filter, "*.sps");
1151 gtk_recent_filter_add_pattern (filter, "*.SPS");
1153 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1155 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1158 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1160 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1164 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1167 g_signal_connect (de->data_editor,
1169 G_CALLBACK (enable_delete_cases),
1172 g_signal_connect (de->data_editor,
1173 "variables-selected",
1174 G_CALLBACK (enable_delete_variables),
1178 g_signal_connect (de->data_editor,
1180 G_CALLBACK (on_switch_sheet), de);
1182 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1183 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1185 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1187 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1189 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1191 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1193 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1195 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1197 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1199 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1201 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1204 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1206 merge_help_menu (uim);
1210 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1211 "datasheet-cases-popup");
1213 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1214 "varsheet-variable-popup");
1216 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1217 "datasheet-variable-popup");
1219 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1220 G_CALLBACK (psppire_data_editor_sort_ascending),
1223 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1224 G_CALLBACK (psppire_data_editor_sort_descending),
1227 g_object_set (de->data_editor,
1228 "datasheet-column-menu", data_sheet_variable_popup_menu,
1229 "datasheet-row-menu", data_sheet_cases_popup_menu,
1230 "varsheet-row-menu", var_sheet_variable_popup_menu,
1234 gtk_widget_show (GTK_WIDGET (de->data_editor));
1235 gtk_widget_show (box);
1237 ll_push_head (&all_data_windows, &de->ll);
1241 psppire_data_window_dispose (GObject *object)
1243 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1245 if (dw->builder != NULL)
1247 g_object_unref (dw->builder);
1253 g_object_unref (dw->var_store);
1254 dw->var_store = NULL;
1259 g_object_unref (dw->data_store);
1260 dw->data_store = NULL;
1263 if (dw->ll.next != NULL)
1265 ll_remove (&dw->ll);
1269 if (G_OBJECT_CLASS (parent_class)->dispose)
1270 G_OBJECT_CLASS (parent_class)->dispose (object);
1274 psppire_data_window_set_property (GObject *object,
1276 const GValue *value,
1279 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1284 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1287 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1293 psppire_data_window_get_property (GObject *object,
1298 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1303 g_value_set_pointer (value, window->dataset);
1306 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1312 psppire_data_window_new (struct dataset *ds)
1316 if (the_session == NULL)
1317 the_session = session_create ();
1321 static int n_datasets;
1324 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1325 ds = dataset_create (the_session, dataset_name);
1326 free (dataset_name);
1328 assert (dataset_session (ds) == the_session);
1332 psppire_data_window_get_type (),
1333 "description", _("Data Editor"),
1337 if (dataset_name (ds) != NULL)
1338 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1344 psppire_data_window_is_empty (PsppireDataWindow *dw)
1346 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1350 psppire_data_window_iface_init (PsppireWindowIface *iface)
1352 iface->save = save_file;
1353 iface->pick_filename = data_pick_filename;
1354 iface->load = load_file;
1358 psppire_default_data_window (void)
1360 if (ll_is_empty (&all_data_windows))
1361 create_data_window ();
1362 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1366 psppire_data_window_set_default (PsppireDataWindow *pdw)
1368 ll_remove (&pdw->ll);
1369 ll_push_head (&all_data_windows, &pdw->ll);
1373 psppire_data_window_undefault (PsppireDataWindow *pdw)
1375 ll_remove (&pdw->ll);
1376 ll_push_tail (&all_data_windows, &pdw->ll);
1380 psppire_data_window_for_dataset (struct dataset *ds)
1382 PsppireDataWindow *pdw;
1384 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1385 if (pdw->dataset == ds)
1392 create_data_window (void)
1394 gtk_widget_show (psppire_data_window_new (NULL));
1398 open_data_window (PsppireWindow *victim, const char *file_name)
1402 if (PSPPIRE_IS_DATA_WINDOW (victim)
1403 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1404 window = GTK_WIDGET (victim);
1406 window = psppire_data_window_new (NULL);
1408 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1409 gtk_widget_show (window);