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/frequencies-dialog.h"
39 #include "ui/gui/help-menu.h"
40 #include "ui/gui/helper.h"
41 #include "ui/gui/helper.h"
42 #include "ui/gui/k-related-dialog.h"
43 #include "ui/gui/npar-two-sample-related.h"
44 #include "ui/gui/oneway-anova-dialog.h"
45 #include "ui/gui/psppire-data-window.h"
46 #include "ui/gui/psppire-dialog-action.h"
47 #include "ui/gui/psppire-syntax-window.h"
48 #include "ui/gui/psppire-window.h"
49 #include "ui/gui/psppire.h"
50 #include "ui/gui/runs-dialog.h"
51 #include "ui/gui/ks-one-sample-dialog.h"
52 #include "ui/gui/recode-dialog.h"
53 #include "ui/gui/select-cases-dialog.h"
54 #include "ui/gui/split-file-dialog.h"
55 #include "ui/gui/t-test-one-sample.h"
56 #include "ui/gui/t-test-paired-samples.h"
57 #include "ui/gui/text-data-import-dialog.h"
58 #include "ui/gui/transpose-dialog.h"
59 #include "ui/gui/univariate-dialog.h"
60 #include "ui/gui/weight-cases-dialog.h"
61 #include "ui/syntax-gen.h"
63 #include "gl/c-strcase.h"
64 #include "gl/c-strcasestr.h"
65 #include "gl/xvasprintf.h"
68 #define _(msgid) gettext (msgid)
69 #define N_(msgid) msgid
71 struct session *the_session;
72 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
74 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
75 static void psppire_data_window_init (PsppireDataWindow *data_editor);
78 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
80 static void psppire_data_window_dispose (GObject *object);
81 static void psppire_data_window_set_property (GObject *object,
85 static void psppire_data_window_get_property (GObject *object,
90 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
91 static void psppire_data_window_remove_ui (PsppireDataWindow *,
92 GtkUIManager *, guint);
95 psppire_data_window_get_type (void)
97 static GType psppire_data_window_type = 0;
99 if (!psppire_data_window_type)
101 static const GTypeInfo psppire_data_window_info =
103 sizeof (PsppireDataWindowClass),
106 (GClassInitFunc)psppire_data_window_class_init,
107 (GClassFinalizeFunc) NULL,
109 sizeof (PsppireDataWindow),
111 (GInstanceInitFunc) psppire_data_window_init,
114 static const GInterfaceInfo window_interface_info =
116 (GInterfaceInitFunc) psppire_data_window_iface_init,
121 psppire_data_window_type =
122 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
123 &psppire_data_window_info, 0);
126 g_type_add_interface_static (psppire_data_window_type,
127 PSPPIRE_TYPE_WINDOW_MODEL,
128 &window_interface_info);
131 return psppire_data_window_type;
134 static GObjectClass *parent_class ;
141 psppire_data_window_class_init (PsppireDataWindowClass *class)
143 GObjectClass *object_class = G_OBJECT_CLASS (class);
145 parent_class = g_type_class_peek_parent (class);
147 object_class->dispose = psppire_data_window_dispose;
148 object_class->set_property = psppire_data_window_set_property;
149 object_class->get_property = psppire_data_window_get_property;
151 g_object_class_install_property (
152 object_class, PROP_DATASET,
153 g_param_spec_pointer ("dataset", "Dataset",
154 "'struct datset *' represented by the window",
155 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
158 /* Run the EXECUTE command. */
160 execute (PsppireDataWindow *dw)
162 execute_const_syntax_string (dw, "EXECUTE.");
166 transformation_change_callback (bool transformations_pending,
169 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
171 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
173 GtkWidget *menuitem =
174 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
176 GtkWidget *status_label =
177 get_widget_assert (de->builder, "case-counter-area");
179 gtk_widget_set_sensitive (menuitem, transformations_pending);
182 if ( transformations_pending)
183 gtk_label_set_text (GTK_LABEL (status_label),
184 _("Transformations Pending"));
186 gtk_label_set_text (GTK_LABEL (status_label), "");
189 /* Callback for when the dictionary changes its filter variable */
191 on_filter_change (GObject *o, gint filter_index, gpointer data)
193 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
195 GtkWidget *filter_status_area =
196 get_widget_assert (de->builder, "filter-use-status-area");
198 if ( filter_index == -1 )
200 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
204 PsppireVarStore *vs = NULL;
205 PsppireDict *dict = NULL;
206 struct variable *var ;
209 g_object_get (de->data_editor, "var-store", &vs, NULL);
210 g_object_get (vs, "dictionary", &dict, NULL);
212 var = psppire_dict_get_variable (dict, filter_index);
214 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
216 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
222 /* Callback for when the dictionary changes its split variables */
224 on_split_change (PsppireDict *dict, gpointer data)
226 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
228 size_t n_split_vars = dict_get_split_cnt (dict->dict);
230 GtkWidget *split_status_area =
231 get_widget_assert (de->builder, "split-file-status-area");
233 if ( n_split_vars == 0 )
235 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
241 const struct variable *const * split_vars =
242 dict_get_split_vars (dict->dict);
244 text = g_string_new (_("Split by "));
246 for (i = 0 ; i < n_split_vars - 1; ++i )
248 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
250 g_string_append (text, var_get_name (split_vars[i]));
252 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
254 g_string_free (text, TRUE);
261 /* Callback for when the dictionary changes its weights */
263 on_weight_change (GObject *o, gint weight_index, gpointer data)
265 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
267 GtkWidget *weight_status_area =
268 get_widget_assert (de->builder, "weight-status-area");
270 if ( weight_index == -1 )
272 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
276 struct variable *var ;
277 PsppireVarStore *vs = NULL;
278 PsppireDict *dict = NULL;
281 g_object_get (de->data_editor, "var-store", &vs, NULL);
282 g_object_get (vs, "dictionary", &dict, NULL);
284 var = psppire_dict_get_variable (dict, weight_index);
286 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
288 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
296 dump_rm (GtkRecentManager *rm)
298 GList *items = gtk_recent_manager_get_items (rm);
302 g_print ("Recent Items:\n");
303 for (i = items; i; i = i->next)
305 GtkRecentInfo *ri = i->data;
307 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
308 gtk_recent_info_get_short_name (ri),
309 gtk_recent_info_get_mime_type (ri),
310 gtk_recent_info_get_description (ri),
311 gtk_recent_info_get_uri (ri)
315 gtk_recent_info_unref (ri);
323 name_has_por_suffix (const gchar *name)
325 size_t length = strlen (name);
326 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
330 name_has_sav_suffix (const gchar *name)
332 size_t length = strlen (name);
333 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
336 /* Returns true if NAME has a suffix which might denote a PSPP file */
338 name_has_suffix (const gchar *name)
340 return name_has_por_suffix (name) || name_has_sav_suffix (name);
344 load_file (PsppireWindow *de, const gchar *file_name)
346 struct string filename;
347 gchar *utf8_file_name;
348 const char *mime_type;
352 ds_init_empty (&filename);
354 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
356 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
358 g_free (utf8_file_name);
360 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
361 ds_destroy (&filename);
363 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
364 lex_reader_for_string (syntax));
367 mime_type = (name_has_por_suffix (file_name)
368 ? "application/x-spss-por"
369 : "application/x-spss-sav");
371 add_most_recent (file_name, mime_type);
376 /* Save DE to file */
378 save_file (PsppireWindow *w)
380 const gchar *file_name = NULL;
381 gchar *utf8_file_name = NULL;
383 struct string filename ;
384 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
387 file_name = psppire_window_get_filename (w);
389 fnx = g_string_new (file_name);
391 if ( ! name_has_suffix (fnx->str))
393 if ( de->save_as_portable)
394 g_string_append (fnx, ".por");
396 g_string_append (fnx, ".sav");
399 ds_init_empty (&filename);
401 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
403 g_string_free (fnx, TRUE);
405 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
406 g_free (utf8_file_name);
408 syntax = g_strdup_printf ("%s OUTFILE=%s.",
409 de->save_as_portable ? "EXPORT" : "SAVE",
410 ds_cstr (&filename));
412 ds_destroy (&filename);
414 g_free (execute_syntax_string (de, syntax));
419 display_dict (PsppireDataWindow *de)
421 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
425 sysfile_info (PsppireDataWindow *de)
427 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
429 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
431 struct string filename;
433 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
435 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
440 ds_init_empty (&filename);
442 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
444 g_free (utf8_file_name);
446 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
447 g_free (execute_syntax_string (de, syntax));
450 gtk_widget_destroy (dialog);
454 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
456 data_pick_filename (PsppireWindow *window)
458 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
459 GtkFileFilter *filter = gtk_file_filter_new ();
460 GtkWidget *button_sys;
462 gtk_file_chooser_dialog_new (_("Save"),
464 GTK_FILE_CHOOSER_ACTION_SAVE,
465 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
466 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
469 g_object_set (dialog, "local-only", FALSE, NULL);
471 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
472 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
473 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
475 filter = gtk_file_filter_new ();
476 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
477 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
478 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
480 filter = gtk_file_filter_new ();
481 gtk_file_filter_set_name (filter, _("All Files"));
482 gtk_file_filter_add_pattern (filter, "*");
483 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
486 GtkWidget *button_por;
487 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
489 gtk_radio_button_new_with_label (NULL, _("System File"));
492 gtk_radio_button_new_with_label
493 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
496 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
497 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
499 gtk_widget_show_all (vbox);
501 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
504 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
507 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
509 case GTK_RESPONSE_ACCEPT:
514 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
517 de->save_as_portable =
518 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
520 if ( ! name_has_suffix (filename->str))
522 if ( de->save_as_portable)
523 g_string_append (filename, ".por");
525 g_string_append (filename, ".sav");
528 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
530 g_string_free (filename, TRUE);
537 gtk_widget_destroy (dialog);
541 confirm_delete_dataset (PsppireDataWindow *de,
542 const char *old_dataset,
543 const char *new_dataset,
544 const char *existing_dataset)
549 dialog = gtk_message_dialog_new (
550 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
551 _("Delete Existing Dataset?"));
553 gtk_message_dialog_format_secondary_text (
554 GTK_MESSAGE_DIALOG (dialog),
555 _("Renaming \"%s\" to \"%s\" will destroy the existing "
556 "dataset named \"%s\". Are you sure that you want to do this?"),
557 old_dataset, new_dataset, existing_dataset);
559 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
560 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
561 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
564 g_object_set (dialog, "icon-name", "pspp", NULL);
566 result = gtk_dialog_run (GTK_DIALOG (dialog));
568 gtk_widget_destroy (dialog);
570 return result == GTK_RESPONSE_OK;
574 on_rename_dataset (PsppireDataWindow *de)
576 struct dataset *ds = de->dataset;
577 struct session *session = dataset_session (ds);
578 const char *old_name = dataset_name (ds);
579 struct dataset *existing_dataset;
583 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
585 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
589 if (new_name == NULL)
592 existing_dataset = session_lookup_dataset (session, new_name);
593 if (existing_dataset == NULL || existing_dataset == ds
594 || confirm_delete_dataset (de, old_name, new_name,
595 dataset_name (existing_dataset)))
596 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
603 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
605 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
607 if ( gtk_toggle_action_get_active (action))
608 gtk_widget_show (statusbar);
610 gtk_widget_hide (statusbar);
615 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
617 const gboolean grid_visible = gtk_toggle_action_get_active (action);
619 psppire_data_editor_show_grid (de->data_editor, grid_visible);
623 data_view_activate (PsppireDataWindow *de)
625 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
630 variable_view_activate (PsppireDataWindow *de)
632 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
637 fonts_activate (PsppireDataWindow *de)
639 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
640 PangoFontDescription *current_font;
643 gtk_font_selection_dialog_new (_("Font Selection"));
646 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
647 font_name = pango_font_description_to_string (current_font);
649 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
653 gtk_window_set_transient_for (GTK_WINDOW (dialog),
654 GTK_WINDOW (toplevel));
656 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
658 const gchar *font = gtk_font_selection_dialog_get_font_name
659 (GTK_FONT_SELECTION_DIALOG (dialog));
661 PangoFontDescription* font_desc =
662 pango_font_description_from_string (font);
664 psppire_data_editor_set_font (de->data_editor, font_desc);
667 gtk_widget_hide (dialog);
672 /* Callback for the value labels action */
674 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
676 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
680 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
682 psppire_data_editor_split_window (de->data_editor,
683 gtk_toggle_action_get_active (ta));
688 file_quit (PsppireDataWindow *de)
690 /* FIXME: Need to be more intelligent here.
691 Give the user the opportunity to save any unsaved data.
697 on_recent_data_select (GtkMenuShell *menushell,
698 PsppireWindow *window)
703 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
705 file = g_filename_from_uri (uri, NULL, NULL);
709 open_data_window (window, file);
715 charset_from_mime_type (const char *mime_type)
721 if (mime_type == NULL)
724 charset = c_strcasestr (mime_type, "charset=");
732 /* Parse a "quoted-string" as defined by RFC 822. */
733 for (p++; *p != '\0' && *p != '"'; p++)
736 ds_put_byte (&s, *p);
737 else if (*++p != '\0')
738 ds_put_byte (&s, *p);
743 /* Parse a "token" as defined by RFC 2045. */
744 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
745 ds_put_byte (&s, *p++);
747 if (!ds_is_empty (&s))
748 return ds_steal_cstr (&s);
755 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
762 /* Get the file name and its encoding. */
763 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
764 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
765 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
766 gtk_recent_info_unref (item);
768 se = psppire_syntax_window_new (encoding);
772 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
773 gtk_widget_show (se);
775 gtk_widget_destroy (se);
781 set_unsaved (gpointer w)
783 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
787 on_switch_page (PsppireDataEditor *de, GtkNotebookPage *p,
788 gint pagenum, PsppireDataWindow *dw)
790 GtkWidget *page_menu_item;
794 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
796 ? "/ui/menubar/view/view_data"
797 : "/ui/menubar/view/view_variables");
798 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
799 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
803 on_ui_manager_changed (PsppireDataEditor *de,
804 GParamSpec *pspec UNUSED,
805 PsppireDataWindow *dw)
807 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
813 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
814 g_object_unref (dw->uim);
821 g_object_ref (dw->uim);
822 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
826 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
827 Returns a pointer to the action
830 connect_action (PsppireDataWindow *dw, const char *action_name,
833 GtkAction *action = get_action_assert (dw->builder, action_name);
835 g_signal_connect_swapped (action, "activate", handler, dw);
840 /* Initializes as much of a PsppireDataWindow as we can and must before the
841 dataset has been set.
843 In particular, the 'menu' member is required in case the "filename" property
844 is set before the "dataset" property: otherwise PsppireWindow will try to
845 modify the menu as part of the "filename" property_set() function and end up
846 with a Gtk-CRITICAL since 'menu' is NULL. */
848 psppire_data_window_init (PsppireDataWindow *de)
850 de->builder = builder_new ("data-editor.ui");
852 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
854 PSPPIRE_WINDOW (de)->menu =
855 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
862 psppire_data_window_finish_init (PsppireDataWindow *de,
865 static const struct dataset_callbacks cbs =
867 set_unsaved, /* changed */
868 transformation_change_callback, /* transformations_changed */
877 GtkWidget *box = gtk_vbox_new (FALSE, 0);
880 dict = psppire_dict_new_from_dict (dataset_dict (ds));
881 de->var_store = psppire_var_store_new (dict);
882 de->data_store = psppire_data_store_new (dict);
883 psppire_data_store_set_reader (de->data_store, NULL);
885 menubar = get_widget_assert (de->builder, "menubar");
886 hb = get_widget_assert (de->builder, "handlebox1");
887 sb = get_widget_assert (de->builder, "status-bar");
893 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->var_store,
895 g_signal_connect (de->data_editor, "switch-page",
896 G_CALLBACK (on_switch_page), de);
898 g_signal_connect_swapped (de->data_store, "case-changed",
899 G_CALLBACK (set_unsaved), de);
901 g_signal_connect_swapped (de->data_store, "case-inserted",
902 G_CALLBACK (set_unsaved), de);
904 g_signal_connect_swapped (de->data_store, "cases-deleted",
905 G_CALLBACK (set_unsaved), de);
907 dataset_set_callbacks (de->dataset, &cbs, de);
909 connect_help (de->builder);
911 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
912 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
913 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
914 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
916 gtk_container_add (GTK_CONTAINER (de), box);
918 g_signal_connect (dict, "weight-changed",
919 G_CALLBACK (on_weight_change),
922 g_signal_connect (dict, "filter-changed",
923 G_CALLBACK (on_filter_change),
926 g_signal_connect (dict, "split-changed",
927 G_CALLBACK (on_split_change),
931 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
933 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
935 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
937 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
939 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
941 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
943 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
945 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
947 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
949 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
950 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
951 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
952 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
953 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
954 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
955 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
956 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
957 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
958 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
959 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
960 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
961 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
962 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
963 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
964 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
965 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
966 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
967 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
968 connect_action (de, "runs", G_CALLBACK (runs_dialog));
969 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
970 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
971 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
974 GtkWidget *recent_data =
975 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
977 GtkWidget *recent_files =
978 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
981 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
982 gtk_recent_manager_get_default ());
984 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
985 gtk_recent_manager_get_default ());
987 g_object_set (menu_data, "show-tips", TRUE, NULL);
988 g_object_set (menu_files, "show-tips", TRUE, NULL);
991 GtkRecentFilter *filter = gtk_recent_filter_new ();
993 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
994 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
996 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
998 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1001 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1004 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1007 GtkRecentFilter *filter = gtk_recent_filter_new ();
1009 gtk_recent_filter_add_pattern (filter, "*.sps");
1010 gtk_recent_filter_add_pattern (filter, "*.SPS");
1012 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1014 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1017 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1019 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1023 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1026 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1027 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1029 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1031 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1033 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1035 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1037 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1039 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1041 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1043 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1045 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1047 merge_help_menu (de->ui_manager);
1049 g_signal_connect (de->data_editor, "notify::ui-manager",
1050 G_CALLBACK (on_ui_manager_changed), de);
1051 on_ui_manager_changed (de->data_editor, NULL, de);
1053 gtk_widget_show (GTK_WIDGET (de->data_editor));
1054 gtk_widget_show (box);
1056 ll_push_head (&all_data_windows, &de->ll);
1060 psppire_data_window_dispose (GObject *object)
1062 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1064 if (dw->builder != NULL)
1066 g_object_unref (dw->builder);
1072 g_object_unref (dw->var_store);
1073 dw->var_store = NULL;
1078 g_object_unref (dw->data_store);
1079 dw->data_store = NULL;
1082 if (dw->ll.next != NULL)
1084 ll_remove (&dw->ll);
1088 if (G_OBJECT_CLASS (parent_class)->dispose)
1089 G_OBJECT_CLASS (parent_class)->dispose (object);
1093 psppire_data_window_set_property (GObject *object,
1095 const GValue *value,
1098 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1103 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1106 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1112 psppire_data_window_get_property (GObject *object,
1117 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1122 g_value_set_pointer (value, window->dataset);
1125 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1131 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1137 ui_string = gtk_ui_manager_get_ui (uim);
1138 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1142 g_return_val_if_fail (merge_id != 0, 0);
1144 list = gtk_ui_manager_get_action_groups (uim);
1145 for (; list != NULL; list = list->next)
1147 GtkActionGroup *action_group = list->data;
1148 GList *actions = gtk_action_group_list_actions (action_group);
1151 for (action = actions; action != NULL; action = action->next)
1153 GtkAction *a = action->data;
1155 if (PSPPIRE_IS_DIALOG_ACTION (a))
1156 g_object_set (a, "manager", pdw->ui_manager, NULL);
1159 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1162 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1163 gtk_ui_manager_get_accel_group (uim));
1169 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1170 GtkUIManager *uim, guint merge_id)
1174 g_return_if_fail (merge_id != 0);
1176 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1178 list = gtk_ui_manager_get_action_groups (uim);
1179 for (; list != NULL; list = list->next)
1181 GtkActionGroup *action_group = list->data;
1182 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1185 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1186 gtk_ui_manager_get_accel_group (uim));
1188 /* Our caller unrefs 'uim', possibly causing 'uim' to be freed. The
1189 following call appears to be necessary to ensure that pdw->ui_manager
1190 drops all references to 'uim'. Otherwise, I get valgrind complaints about
1191 access to freed memory (and segfaults) on e.g. Windows|Split View. */
1192 gtk_ui_manager_ensure_update (pdw->ui_manager);
1196 psppire_data_window_new (struct dataset *ds)
1200 if (the_session == NULL)
1201 the_session = session_create ();
1205 static int n_datasets;
1208 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1209 ds = dataset_create (the_session, dataset_name);
1210 free (dataset_name);
1212 assert (dataset_session (ds) == the_session);
1216 psppire_data_window_get_type (),
1217 "description", _("Data Editor"),
1221 if (dataset_name (ds) != NULL)
1222 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1228 psppire_data_window_is_empty (PsppireDataWindow *dw)
1230 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1234 psppire_data_window_iface_init (PsppireWindowIface *iface)
1236 iface->save = save_file;
1237 iface->pick_filename = data_pick_filename;
1238 iface->load = load_file;
1242 psppire_default_data_window (void)
1244 if (ll_is_empty (&all_data_windows))
1245 create_data_window ();
1246 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1250 psppire_data_window_set_default (PsppireDataWindow *pdw)
1252 ll_remove (&pdw->ll);
1253 ll_push_head (&all_data_windows, &pdw->ll);
1257 psppire_data_window_undefault (PsppireDataWindow *pdw)
1259 ll_remove (&pdw->ll);
1260 ll_push_tail (&all_data_windows, &pdw->ll);
1264 psppire_data_window_for_dataset (struct dataset *ds)
1266 PsppireDataWindow *pdw;
1268 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1269 if (pdw->dataset == ds)
1276 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1278 PsppireDataWindow *pdw;
1280 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1281 if (pdw->data_store == data_store)
1288 create_data_window (void)
1290 gtk_widget_show (psppire_data_window_new (NULL));
1294 open_data_window (PsppireWindow *victim, const char *file_name)
1298 if (PSPPIRE_IS_DATA_WINDOW (victim)
1299 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1301 window = GTK_WIDGET (victim);
1302 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1305 window = psppire_data_window_new (NULL);
1307 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1308 gtk_widget_show_all (window);