1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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/builder-wrapper.h"
30 #include "ui/gui/comments-dialog.h"
31 #include "ui/gui/compute-dialog.h"
32 #include "ui/gui/count-dialog.h"
33 #include "ui/gui/entry-dialog.h"
34 #include "ui/gui/executor.h"
35 #include "ui/gui/help-menu.h"
36 #include "ui/gui/helper.h"
37 #include "ui/gui/helper.h"
38 #include "ui/gui/k-related-dialog.h"
39 #include "ui/gui/npar-two-sample-related.h"
40 #include "ui/gui/oneway-anova-dialog.h"
41 #include "ui/gui/psppire-data-window.h"
42 #include "ui/gui/psppire-dialog-action.h"
43 #include "ui/gui/psppire-syntax-window.h"
44 #include "ui/gui/psppire-window.h"
45 #include "ui/gui/psppire.h"
46 #include "ui/gui/ks-one-sample-dialog.h"
47 #include "ui/gui/recode-dialog.h"
48 #include "ui/gui/select-cases-dialog.h"
49 #include "ui/gui/split-file-dialog.h"
50 #include "ui/gui/t-test-one-sample.h"
51 #include "ui/gui/t-test-paired-samples.h"
52 #include "ui/gui/text-data-import-dialog.h"
53 #include "ui/gui/univariate-dialog.h"
54 #include "ui/gui/weight-cases-dialog.h"
55 #include "ui/syntax-gen.h"
57 #include "gl/c-strcase.h"
58 #include "gl/c-strcasestr.h"
59 #include "gl/xvasprintf.h"
62 #define _(msgid) gettext (msgid)
63 #define N_(msgid) msgid
65 struct session *the_session;
66 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
68 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
69 static void psppire_data_window_init (PsppireDataWindow *data_editor);
72 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
74 static void psppire_data_window_dispose (GObject *object);
75 static void psppire_data_window_finalize (GObject *object);
76 static void psppire_data_window_set_property (GObject *object,
80 static void psppire_data_window_get_property (GObject *object,
85 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
86 static void psppire_data_window_remove_ui (PsppireDataWindow *,
87 GtkUIManager *, guint);
90 psppire_data_window_get_type (void)
92 static GType psppire_data_window_type = 0;
94 if (!psppire_data_window_type)
96 static const GTypeInfo psppire_data_window_info =
98 sizeof (PsppireDataWindowClass),
101 (GClassInitFunc)psppire_data_window_class_init,
102 (GClassFinalizeFunc) NULL,
104 sizeof (PsppireDataWindow),
106 (GInstanceInitFunc) psppire_data_window_init,
109 static const GInterfaceInfo window_interface_info =
111 (GInterfaceInitFunc) psppire_data_window_iface_init,
116 psppire_data_window_type =
117 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
118 &psppire_data_window_info, 0);
121 g_type_add_interface_static (psppire_data_window_type,
122 PSPPIRE_TYPE_WINDOW_MODEL,
123 &window_interface_info);
126 return psppire_data_window_type;
129 static GObjectClass *parent_class ;
136 psppire_data_window_class_init (PsppireDataWindowClass *class)
138 GObjectClass *object_class = G_OBJECT_CLASS (class);
140 parent_class = g_type_class_peek_parent (class);
142 object_class->dispose = psppire_data_window_dispose;
143 object_class->finalize = psppire_data_window_finalize;
144 object_class->set_property = psppire_data_window_set_property;
145 object_class->get_property = psppire_data_window_get_property;
147 g_object_class_install_property (
148 object_class, PROP_DATASET,
149 g_param_spec_pointer ("dataset", "Dataset",
150 "'struct datset *' represented by the window",
151 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
154 /* Run the EXECUTE command. */
156 execute (PsppireDataWindow *dw)
158 execute_const_syntax_string (dw, "EXECUTE.");
162 transformation_change_callback (bool transformations_pending,
165 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
167 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
169 GtkWidget *menuitem =
170 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
172 GtkWidget *status_label =
173 get_widget_assert (de->builder, "case-counter-area");
175 gtk_widget_set_sensitive (menuitem, transformations_pending);
178 if ( transformations_pending)
179 gtk_label_set_text (GTK_LABEL (status_label),
180 _("Transformations Pending"));
182 gtk_label_set_text (GTK_LABEL (status_label), "");
185 /* Callback for when the dictionary changes its filter variable */
187 on_filter_change (GObject *o, gint filter_index, gpointer data)
189 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
191 GtkWidget *filter_status_area =
192 get_widget_assert (de->builder, "filter-use-status-area");
194 if ( filter_index == -1 )
196 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
200 PsppireDict *dict = NULL;
201 struct variable *var ;
204 g_object_get (de->data_editor, "dictionary", &dict, NULL);
206 var = psppire_dict_get_variable (dict, filter_index);
208 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
210 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
216 /* Callback for when the dictionary changes its split variables */
218 on_split_change (PsppireDict *dict, gpointer data)
220 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
222 size_t n_split_vars = dict_get_split_cnt (dict->dict);
224 GtkWidget *split_status_area =
225 get_widget_assert (de->builder, "split-file-status-area");
227 if ( n_split_vars == 0 )
229 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
235 const struct variable *const * split_vars =
236 dict_get_split_vars (dict->dict);
238 text = g_string_new (_("Split by "));
240 for (i = 0 ; i < n_split_vars - 1; ++i )
242 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
244 g_string_append (text, var_get_name (split_vars[i]));
246 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
248 g_string_free (text, TRUE);
255 /* Callback for when the dictionary changes its weights */
257 on_weight_change (GObject *o, gint weight_index, gpointer data)
259 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
261 GtkWidget *weight_status_area =
262 get_widget_assert (de->builder, "weight-status-area");
264 if ( weight_index == -1 )
266 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
270 struct variable *var ;
271 PsppireDict *dict = NULL;
274 g_object_get (de->data_editor, "dictionary", &dict, NULL);
276 var = psppire_dict_get_variable (dict, weight_index);
278 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
280 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
288 dump_rm (GtkRecentManager *rm)
290 GList *items = gtk_recent_manager_get_items (rm);
294 g_print ("Recent Items:\n");
295 for (i = items; i; i = i->next)
297 GtkRecentInfo *ri = i->data;
299 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
300 gtk_recent_info_get_short_name (ri),
301 gtk_recent_info_get_mime_type (ri),
302 gtk_recent_info_get_description (ri),
303 gtk_recent_info_get_uri (ri)
307 gtk_recent_info_unref (ri);
315 name_has_por_suffix (const gchar *name)
317 size_t length = strlen (name);
318 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
322 name_has_sav_suffix (const gchar *name)
324 size_t length = strlen (name);
325 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
328 /* Returns true if NAME has a suffix which might denote a PSPP file */
330 name_has_suffix (const gchar *name)
332 return name_has_por_suffix (name) || name_has_sav_suffix (name);
336 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
338 const char *mime_type = NULL;
339 gchar *syntax = NULL;
344 gchar *utf8_file_name;
345 struct string filename;
346 ds_init_empty (&filename);
348 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
350 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
352 g_free (utf8_file_name);
354 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
355 ds_destroy (&filename);
363 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
364 lex_reader_for_string (syntax));
367 if (ok && syn == NULL)
369 if (name_has_por_suffix (file_name))
370 mime_type = "application/x-spss-por";
371 else if (name_has_sav_suffix (file_name))
372 mime_type = "application/x-spss-sav";
374 add_most_recent (file_name, mime_type);
380 /* Save DE to file */
382 save_file (PsppireWindow *w)
384 const gchar *file_name = NULL;
385 gchar *utf8_file_name = NULL;
387 struct string filename ;
388 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
391 file_name = psppire_window_get_filename (w);
393 fnx = g_string_new (file_name);
395 if ( ! name_has_suffix (fnx->str))
397 if ( de->save_as_portable)
398 g_string_append (fnx, ".por");
400 g_string_append (fnx, ".sav");
403 ds_init_empty (&filename);
405 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
407 g_string_free (fnx, TRUE);
409 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
410 g_free (utf8_file_name);
412 syntax = g_strdup_printf ("%s OUTFILE=%s.",
413 de->save_as_portable ? "EXPORT" : "SAVE",
414 ds_cstr (&filename));
416 ds_destroy (&filename);
418 g_free (execute_syntax_string (de, syntax));
423 display_dict (PsppireDataWindow *de)
425 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
429 sysfile_info (PsppireDataWindow *de)
431 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
433 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
435 struct string filename;
437 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
439 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
444 ds_init_empty (&filename);
446 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
448 g_free (utf8_file_name);
450 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
451 g_free (execute_syntax_string (de, syntax));
454 gtk_widget_destroy (dialog);
458 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
460 data_pick_filename (PsppireWindow *window)
462 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
463 GtkFileFilter *filter = gtk_file_filter_new ();
464 GtkWidget *button_sys;
466 gtk_file_chooser_dialog_new (_("Save"),
468 GTK_FILE_CHOOSER_ACTION_SAVE,
469 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
470 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
473 g_object_set (dialog, "local-only", FALSE, NULL);
475 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
476 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
477 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
479 filter = gtk_file_filter_new ();
480 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
481 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
482 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
484 filter = gtk_file_filter_new ();
485 gtk_file_filter_set_name (filter, _("All Files"));
486 gtk_file_filter_add_pattern (filter, "*");
487 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
490 GtkWidget *button_por;
491 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
493 gtk_radio_button_new_with_label (NULL, _("System File"));
496 gtk_radio_button_new_with_label
497 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
500 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
501 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
503 gtk_widget_show_all (vbox);
505 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
508 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
511 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
513 case GTK_RESPONSE_ACCEPT:
518 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
521 de->save_as_portable =
522 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
524 if ( ! name_has_suffix (filename->str))
526 if ( de->save_as_portable)
527 g_string_append (filename, ".por");
529 g_string_append (filename, ".sav");
532 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
534 g_string_free (filename, TRUE);
541 gtk_widget_destroy (dialog);
545 confirm_delete_dataset (PsppireDataWindow *de,
546 const char *old_dataset,
547 const char *new_dataset,
548 const char *existing_dataset)
553 dialog = gtk_message_dialog_new (
554 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
555 _("Delete Existing Dataset?"));
557 gtk_message_dialog_format_secondary_text (
558 GTK_MESSAGE_DIALOG (dialog),
559 _("Renaming \"%s\" to \"%s\" will destroy the existing "
560 "dataset named \"%s\". Are you sure that you want to do this?"),
561 old_dataset, new_dataset, existing_dataset);
563 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
564 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
565 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
568 g_object_set (dialog, "icon-name", "pspp", NULL);
570 result = gtk_dialog_run (GTK_DIALOG (dialog));
572 gtk_widget_destroy (dialog);
574 return result == GTK_RESPONSE_OK;
578 on_rename_dataset (PsppireDataWindow *de)
580 struct dataset *ds = de->dataset;
581 struct session *session = dataset_session (ds);
582 const char *old_name = dataset_name (ds);
583 struct dataset *existing_dataset;
587 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
589 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
593 if (new_name == NULL)
596 existing_dataset = session_lookup_dataset (session, new_name);
597 if (existing_dataset == NULL || existing_dataset == ds
598 || confirm_delete_dataset (de, old_name, new_name,
599 dataset_name (existing_dataset)))
600 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
607 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
609 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
611 if ( gtk_toggle_action_get_active (action))
612 gtk_widget_show (statusbar);
614 gtk_widget_hide (statusbar);
619 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
621 const gboolean grid_visible = gtk_toggle_action_get_active (action);
623 psppire_data_editor_show_grid (de->data_editor, grid_visible);
627 data_view_activate (PsppireDataWindow *de)
629 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
634 variable_view_activate (PsppireDataWindow *de)
636 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
641 fonts_activate (PsppireDataWindow *de)
643 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
644 PangoFontDescription *current_font;
647 gtk_font_selection_dialog_new (_("Font Selection"));
650 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
651 font_name = pango_font_description_to_string (current_font);
653 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
657 gtk_window_set_transient_for (GTK_WINDOW (dialog),
658 GTK_WINDOW (toplevel));
660 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
662 const gchar *font = gtk_font_selection_dialog_get_font_name
663 (GTK_FONT_SELECTION_DIALOG (dialog));
665 PangoFontDescription* font_desc =
666 pango_font_description_from_string (font);
668 psppire_data_editor_set_font (de->data_editor, font_desc);
671 gtk_widget_hide (dialog);
676 /* Callback for the value labels action */
678 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
680 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
684 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
686 psppire_data_editor_split_window (de->data_editor,
687 gtk_toggle_action_get_active (ta));
692 file_quit (PsppireDataWindow *de)
694 /* FIXME: Need to be more intelligent here.
695 Give the user the opportunity to save any unsaved data.
701 on_recent_data_select (GtkMenuShell *menushell,
702 PsppireWindow *window)
707 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
709 file = g_filename_from_uri (uri, NULL, NULL);
713 open_data_window (window, file, NULL);
719 charset_from_mime_type (const char *mime_type)
725 if (mime_type == NULL)
728 charset = c_strcasestr (mime_type, "charset=");
736 /* Parse a "quoted-string" as defined by RFC 822. */
737 for (p++; *p != '\0' && *p != '"'; p++)
740 ds_put_byte (&s, *p);
741 else if (*++p != '\0')
742 ds_put_byte (&s, *p);
747 /* Parse a "token" as defined by RFC 2045. */
748 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
749 ds_put_byte (&s, *p++);
751 if (!ds_is_empty (&s))
752 return ds_steal_cstr (&s);
759 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
766 /* Get the file name and its encoding. */
767 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
768 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
769 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
770 gtk_recent_info_unref (item);
772 se = psppire_syntax_window_new (encoding);
776 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
777 gtk_widget_show (se);
779 gtk_widget_destroy (se);
785 set_unsaved (gpointer w)
787 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
791 on_switch_page (PsppireDataEditor *de, gpointer p,
792 gint pagenum, PsppireDataWindow *dw)
794 GtkWidget *page_menu_item;
798 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
800 ? "/ui/menubar/view/view_data"
801 : "/ui/menubar/view/view_variables");
802 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
803 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
807 on_ui_manager_changed (PsppireDataEditor *de,
808 GParamSpec *pspec UNUSED,
809 PsppireDataWindow *dw)
811 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
817 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
818 g_object_unref (dw->uim);
825 g_object_ref (dw->uim);
826 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
830 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
831 Returns a pointer to the action
834 connect_action (PsppireDataWindow *dw, const char *action_name,
837 GtkAction *action = get_action_assert (dw->builder, action_name);
839 g_signal_connect_swapped (action, "activate", handler, dw);
844 /* Only a data file with at least one variable can be saved. */
846 enable_save (PsppireDataWindow *dw)
848 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
850 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
852 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
856 /* Initializes as much of a PsppireDataWindow as we can and must before the
857 dataset has been set.
859 In particular, the 'menu' member is required in case the "filename" property
860 is set before the "dataset" property: otherwise PsppireWindow will try to
861 modify the menu as part of the "filename" property_set() function and end up
862 with a Gtk-CRITICAL since 'menu' is NULL. */
864 psppire_data_window_init (PsppireDataWindow *de)
866 de->builder = builder_new ("data-editor.ui");
868 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
870 PSPPIRE_WINDOW (de)->menu =
871 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
878 psppire_data_window_finish_init (PsppireDataWindow *de,
881 static const struct dataset_callbacks cbs =
883 set_unsaved, /* changed */
884 transformation_change_callback, /* transformations_changed */
891 GtkWidget *box = gtk_vbox_new (FALSE, 0);
894 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
895 de->data_store = psppire_data_store_new (de->dict);
896 psppire_data_store_set_reader (de->data_store, NULL);
898 menubar = get_widget_assert (de->builder, "menubar");
899 hb = get_widget_assert (de->builder, "handlebox1");
900 sb = get_widget_assert (de->builder, "status-bar");
906 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
907 g_signal_connect (de->data_editor, "switch-page",
908 G_CALLBACK (on_switch_page), de);
910 g_signal_connect_swapped (de->data_store, "case-changed",
911 G_CALLBACK (set_unsaved), de);
913 g_signal_connect_swapped (de->data_store, "case-inserted",
914 G_CALLBACK (set_unsaved), de);
916 g_signal_connect_swapped (de->data_store, "cases-deleted",
917 G_CALLBACK (set_unsaved), de);
919 dataset_set_callbacks (de->dataset, &cbs, de);
921 connect_help (de->builder);
923 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
924 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
925 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
926 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
928 gtk_container_add (GTK_CONTAINER (de), box);
930 g_signal_connect (de->dict, "weight-changed",
931 G_CALLBACK (on_weight_change),
934 g_signal_connect (de->dict, "filter-changed",
935 G_CALLBACK (on_filter_change),
938 g_signal_connect (de->dict, "split-changed",
939 G_CALLBACK (on_split_change),
942 g_signal_connect_swapped (de->dict, "backend-changed",
943 G_CALLBACK (enable_save), de);
944 g_signal_connect_swapped (de->dict, "variable-inserted",
945 G_CALLBACK (enable_save), de);
946 g_signal_connect_swapped (de->dict, "variable-deleted",
947 G_CALLBACK (enable_save), de);
950 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
952 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
954 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
956 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
958 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
960 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
962 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
964 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
966 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
968 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
969 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
970 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
971 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
972 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
973 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
974 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
975 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
976 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
977 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
978 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
979 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
980 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
981 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
982 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
983 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
984 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
987 GtkWidget *recent_data =
988 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
990 GtkWidget *recent_files =
991 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
994 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
995 gtk_recent_manager_get_default ());
997 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
998 gtk_recent_manager_get_default ());
1000 g_object_set (menu_data, "show-tips", TRUE, NULL);
1001 g_object_set (menu_files, "show-tips", TRUE, NULL);
1004 GtkRecentFilter *filter = gtk_recent_filter_new ();
1006 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1007 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1009 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1011 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1014 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1017 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1020 GtkRecentFilter *filter = gtk_recent_filter_new ();
1022 gtk_recent_filter_add_pattern (filter, "*.sps");
1023 gtk_recent_filter_add_pattern (filter, "*.SPS");
1025 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1027 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1030 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1032 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1036 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1039 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1040 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1042 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1044 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1046 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1048 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1050 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1052 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1054 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1056 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1058 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1060 merge_help_menu (de->ui_manager);
1062 g_signal_connect (de->data_editor, "notify::ui-manager",
1063 G_CALLBACK (on_ui_manager_changed), de);
1064 on_ui_manager_changed (de->data_editor, NULL, de);
1066 gtk_widget_show (GTK_WIDGET (de->data_editor));
1067 gtk_widget_show (box);
1069 ll_push_head (&all_data_windows, &de->ll);
1073 psppire_data_window_dispose (GObject *object)
1075 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1079 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1080 g_object_unref (dw->uim);
1084 if (dw->builder != NULL)
1086 g_object_unref (dw->builder);
1092 g_signal_handlers_disconnect_by_func (dw->dict,
1093 G_CALLBACK (enable_save), dw);
1094 g_signal_handlers_disconnect_by_func (dw->dict,
1095 G_CALLBACK (on_weight_change), dw);
1096 g_signal_handlers_disconnect_by_func (dw->dict,
1097 G_CALLBACK (on_filter_change), dw);
1098 g_signal_handlers_disconnect_by_func (dw->dict,
1099 G_CALLBACK (on_split_change), dw);
1101 g_object_unref (dw->dict);
1107 g_object_unref (dw->data_store);
1108 dw->data_store = NULL;
1111 if (dw->ll.next != NULL)
1113 ll_remove (&dw->ll);
1117 if (G_OBJECT_CLASS (parent_class)->dispose)
1118 G_OBJECT_CLASS (parent_class)->dispose (object);
1122 psppire_data_window_finalize (GObject *object)
1124 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1128 struct dataset *dataset = dw->dataset;
1129 struct session *session = dataset_session (dataset);
1133 dataset_set_callbacks (dataset, NULL, NULL);
1134 session_set_active_dataset (session, NULL);
1135 dataset_destroy (dataset);
1138 if (G_OBJECT_CLASS (parent_class)->finalize)
1139 G_OBJECT_CLASS (parent_class)->finalize (object);
1143 psppire_data_window_set_property (GObject *object,
1145 const GValue *value,
1148 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1153 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1156 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1162 psppire_data_window_get_property (GObject *object,
1167 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1172 g_value_set_pointer (value, window->dataset);
1175 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1181 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1187 ui_string = gtk_ui_manager_get_ui (uim);
1188 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1192 g_return_val_if_fail (merge_id != 0, 0);
1194 list = gtk_ui_manager_get_action_groups (uim);
1195 for (; list != NULL; list = list->next)
1197 GtkActionGroup *action_group = list->data;
1198 GList *actions = gtk_action_group_list_actions (action_group);
1201 for (action = actions; action != NULL; action = action->next)
1203 GtkAction *a = action->data;
1205 if (PSPPIRE_IS_DIALOG_ACTION (a))
1206 g_object_set (a, "manager", pdw->ui_manager, NULL);
1209 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1212 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1213 gtk_ui_manager_get_accel_group (uim));
1219 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1220 GtkUIManager *uim, guint merge_id)
1224 g_return_if_fail (merge_id != 0);
1226 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1228 list = gtk_ui_manager_get_action_groups (uim);
1229 for (; list != NULL; list = list->next)
1231 GtkActionGroup *action_group = list->data;
1232 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1235 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1236 gtk_ui_manager_get_accel_group (uim));
1240 psppire_data_window_new (struct dataset *ds)
1244 if (the_session == NULL)
1245 the_session = session_create (NULL);
1249 char *dataset_name = session_generate_dataset_name (the_session);
1250 ds = dataset_create (the_session, dataset_name);
1251 free (dataset_name);
1253 assert (dataset_session (ds) == the_session);
1257 psppire_data_window_get_type (),
1258 "description", _("Data Editor"),
1262 if (dataset_name (ds) != NULL)
1263 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1269 psppire_data_window_is_empty (PsppireDataWindow *dw)
1271 return psppire_dict_get_var_cnt (dw->dict) == 0;
1275 psppire_data_window_iface_init (PsppireWindowIface *iface)
1277 iface->save = save_file;
1278 iface->pick_filename = data_pick_filename;
1279 iface->load = load_file;
1283 psppire_default_data_window (void)
1285 if (ll_is_empty (&all_data_windows))
1286 create_data_window ();
1287 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1291 psppire_data_window_set_default (PsppireDataWindow *pdw)
1293 ll_remove (&pdw->ll);
1294 ll_push_head (&all_data_windows, &pdw->ll);
1298 psppire_data_window_undefault (PsppireDataWindow *pdw)
1300 ll_remove (&pdw->ll);
1301 ll_push_tail (&all_data_windows, &pdw->ll);
1305 psppire_data_window_for_dataset (struct dataset *ds)
1307 PsppireDataWindow *pdw;
1309 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1310 if (pdw->dataset == ds)
1317 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1319 PsppireDataWindow *pdw;
1321 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1322 if (pdw->data_store == data_store)
1329 create_data_window (void)
1331 gtk_widget_show (psppire_data_window_new (NULL));
1335 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1339 if (PSPPIRE_IS_DATA_WINDOW (victim)
1340 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1342 window = GTK_WIDGET (victim);
1343 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1346 window = psppire_data_window_new (NULL);
1348 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1349 gtk_widget_show_all (window);