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/chi-square-dialog.h"
31 #include "ui/gui/comments-dialog.h"
32 #include "ui/gui/compute-dialog.h"
33 #include "ui/gui/count-dialog.h"
34 #include "ui/gui/entry-dialog.h"
35 #include "ui/gui/executor.h"
36 #include "ui/gui/help-menu.h"
37 #include "ui/gui/helper.h"
38 #include "ui/gui/helper.h"
39 #include "ui/gui/k-related-dialog.h"
40 #include "ui/gui/npar-two-sample-related.h"
41 #include "ui/gui/oneway-anova-dialog.h"
42 #include "ui/gui/psppire-data-window.h"
43 #include "ui/gui/psppire-dialog-action.h"
44 #include "ui/gui/psppire-syntax-window.h"
45 #include "ui/gui/psppire-window.h"
46 #include "ui/gui/psppire.h"
47 #include "ui/gui/ks-one-sample-dialog.h"
48 #include "ui/gui/recode-dialog.h"
49 #include "ui/gui/select-cases-dialog.h"
50 #include "ui/gui/split-file-dialog.h"
51 #include "ui/gui/t-test-one-sample.h"
52 #include "ui/gui/t-test-paired-samples.h"
53 #include "ui/gui/text-data-import-dialog.h"
54 #include "ui/gui/univariate-dialog.h"
55 #include "ui/gui/weight-cases-dialog.h"
56 #include "ui/syntax-gen.h"
58 #include "gl/c-strcase.h"
59 #include "gl/c-strcasestr.h"
60 #include "gl/xvasprintf.h"
63 #define _(msgid) gettext (msgid)
64 #define N_(msgid) msgid
66 struct session *the_session;
67 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
69 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
70 static void psppire_data_window_init (PsppireDataWindow *data_editor);
73 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
75 static void psppire_data_window_dispose (GObject *object);
76 static void psppire_data_window_finalize (GObject *object);
77 static void psppire_data_window_set_property (GObject *object,
81 static void psppire_data_window_get_property (GObject *object,
86 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
87 static void psppire_data_window_remove_ui (PsppireDataWindow *,
88 GtkUIManager *, guint);
91 psppire_data_window_get_type (void)
93 static GType psppire_data_window_type = 0;
95 if (!psppire_data_window_type)
97 static const GTypeInfo psppire_data_window_info =
99 sizeof (PsppireDataWindowClass),
102 (GClassInitFunc)psppire_data_window_class_init,
103 (GClassFinalizeFunc) NULL,
105 sizeof (PsppireDataWindow),
107 (GInstanceInitFunc) psppire_data_window_init,
110 static const GInterfaceInfo window_interface_info =
112 (GInterfaceInitFunc) psppire_data_window_iface_init,
117 psppire_data_window_type =
118 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
119 &psppire_data_window_info, 0);
122 g_type_add_interface_static (psppire_data_window_type,
123 PSPPIRE_TYPE_WINDOW_MODEL,
124 &window_interface_info);
127 return psppire_data_window_type;
130 static GObjectClass *parent_class ;
137 psppire_data_window_class_init (PsppireDataWindowClass *class)
139 GObjectClass *object_class = G_OBJECT_CLASS (class);
141 parent_class = g_type_class_peek_parent (class);
143 object_class->dispose = psppire_data_window_dispose;
144 object_class->finalize = psppire_data_window_finalize;
145 object_class->set_property = psppire_data_window_set_property;
146 object_class->get_property = psppire_data_window_get_property;
148 g_object_class_install_property (
149 object_class, PROP_DATASET,
150 g_param_spec_pointer ("dataset", "Dataset",
151 "'struct datset *' represented by the window",
152 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
155 /* Run the EXECUTE command. */
157 execute (PsppireDataWindow *dw)
159 execute_const_syntax_string (dw, "EXECUTE.");
163 transformation_change_callback (bool transformations_pending,
166 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
168 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
170 GtkWidget *menuitem =
171 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
173 GtkWidget *status_label =
174 get_widget_assert (de->builder, "case-counter-area");
176 gtk_widget_set_sensitive (menuitem, transformations_pending);
179 if ( transformations_pending)
180 gtk_label_set_text (GTK_LABEL (status_label),
181 _("Transformations Pending"));
183 gtk_label_set_text (GTK_LABEL (status_label), "");
186 /* Callback for when the dictionary changes its filter variable */
188 on_filter_change (GObject *o, gint filter_index, gpointer data)
190 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
192 GtkWidget *filter_status_area =
193 get_widget_assert (de->builder, "filter-use-status-area");
195 if ( filter_index == -1 )
197 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
201 PsppireDict *dict = NULL;
202 struct variable *var ;
205 g_object_get (de->data_editor, "dictionary", &dict, NULL);
207 var = psppire_dict_get_variable (dict, filter_index);
209 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
211 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
217 /* Callback for when the dictionary changes its split variables */
219 on_split_change (PsppireDict *dict, gpointer data)
221 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
223 size_t n_split_vars = dict_get_split_cnt (dict->dict);
225 GtkWidget *split_status_area =
226 get_widget_assert (de->builder, "split-file-status-area");
228 if ( n_split_vars == 0 )
230 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
236 const struct variable *const * split_vars =
237 dict_get_split_vars (dict->dict);
239 text = g_string_new (_("Split by "));
241 for (i = 0 ; i < n_split_vars - 1; ++i )
243 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
245 g_string_append (text, var_get_name (split_vars[i]));
247 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
249 g_string_free (text, TRUE);
256 /* Callback for when the dictionary changes its weights */
258 on_weight_change (GObject *o, gint weight_index, gpointer data)
260 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
262 GtkWidget *weight_status_area =
263 get_widget_assert (de->builder, "weight-status-area");
265 if ( weight_index == -1 )
267 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
271 struct variable *var ;
272 PsppireDict *dict = NULL;
275 g_object_get (de->data_editor, "dictionary", &dict, NULL);
277 var = psppire_dict_get_variable (dict, weight_index);
279 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
281 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
289 dump_rm (GtkRecentManager *rm)
291 GList *items = gtk_recent_manager_get_items (rm);
295 g_print ("Recent Items:\n");
296 for (i = items; i; i = i->next)
298 GtkRecentInfo *ri = i->data;
300 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
301 gtk_recent_info_get_short_name (ri),
302 gtk_recent_info_get_mime_type (ri),
303 gtk_recent_info_get_description (ri),
304 gtk_recent_info_get_uri (ri)
308 gtk_recent_info_unref (ri);
316 name_has_por_suffix (const gchar *name)
318 size_t length = strlen (name);
319 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
323 name_has_sav_suffix (const gchar *name)
325 size_t length = strlen (name);
326 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
329 /* Returns true if NAME has a suffix which might denote a PSPP file */
331 name_has_suffix (const gchar *name)
333 return name_has_por_suffix (name) || name_has_sav_suffix (name);
337 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
339 const char *mime_type = NULL;
340 gchar *syntax = NULL;
345 gchar *utf8_file_name;
346 struct string filename;
347 ds_init_empty (&filename);
349 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
351 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
353 g_free (utf8_file_name);
355 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
356 ds_destroy (&filename);
364 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
365 lex_reader_for_string (syntax));
368 if (ok && syn == NULL)
370 if (name_has_por_suffix (file_name))
371 mime_type = "application/x-spss-por";
372 else if (name_has_sav_suffix (file_name))
373 mime_type = "application/x-spss-sav";
375 add_most_recent (file_name, mime_type);
381 /* Save DE to file */
383 save_file (PsppireWindow *w)
385 const gchar *file_name = NULL;
386 gchar *utf8_file_name = NULL;
388 struct string filename ;
389 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
392 file_name = psppire_window_get_filename (w);
394 fnx = g_string_new (file_name);
396 if ( ! name_has_suffix (fnx->str))
398 if ( de->save_as_portable)
399 g_string_append (fnx, ".por");
401 g_string_append (fnx, ".sav");
404 ds_init_empty (&filename);
406 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
408 g_string_free (fnx, TRUE);
410 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
411 g_free (utf8_file_name);
413 syntax = g_strdup_printf ("%s OUTFILE=%s.",
414 de->save_as_portable ? "EXPORT" : "SAVE",
415 ds_cstr (&filename));
417 ds_destroy (&filename);
419 g_free (execute_syntax_string (de, syntax));
424 display_dict (PsppireDataWindow *de)
426 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
430 sysfile_info (PsppireDataWindow *de)
432 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
434 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
436 struct string filename;
438 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
440 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
445 ds_init_empty (&filename);
447 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
449 g_free (utf8_file_name);
451 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
452 g_free (execute_syntax_string (de, syntax));
455 gtk_widget_destroy (dialog);
459 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
461 data_pick_filename (PsppireWindow *window)
463 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
464 GtkFileFilter *filter = gtk_file_filter_new ();
465 GtkWidget *button_sys;
467 gtk_file_chooser_dialog_new (_("Save"),
469 GTK_FILE_CHOOSER_ACTION_SAVE,
470 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
471 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
474 g_object_set (dialog, "local-only", FALSE, NULL);
476 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
477 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
478 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
480 filter = gtk_file_filter_new ();
481 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
482 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
483 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
485 filter = gtk_file_filter_new ();
486 gtk_file_filter_set_name (filter, _("All Files"));
487 gtk_file_filter_add_pattern (filter, "*");
488 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
491 GtkWidget *button_por;
492 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
494 gtk_radio_button_new_with_label (NULL, _("System File"));
497 gtk_radio_button_new_with_label
498 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
501 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
502 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
504 gtk_widget_show_all (vbox);
506 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
509 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
512 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
514 case GTK_RESPONSE_ACCEPT:
519 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
522 de->save_as_portable =
523 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
525 if ( ! name_has_suffix (filename->str))
527 if ( de->save_as_portable)
528 g_string_append (filename, ".por");
530 g_string_append (filename, ".sav");
533 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
535 g_string_free (filename, TRUE);
542 gtk_widget_destroy (dialog);
546 confirm_delete_dataset (PsppireDataWindow *de,
547 const char *old_dataset,
548 const char *new_dataset,
549 const char *existing_dataset)
554 dialog = gtk_message_dialog_new (
555 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
556 _("Delete Existing Dataset?"));
558 gtk_message_dialog_format_secondary_text (
559 GTK_MESSAGE_DIALOG (dialog),
560 _("Renaming \"%s\" to \"%s\" will destroy the existing "
561 "dataset named \"%s\". Are you sure that you want to do this?"),
562 old_dataset, new_dataset, existing_dataset);
564 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
565 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
566 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
569 g_object_set (dialog, "icon-name", "pspp", NULL);
571 result = gtk_dialog_run (GTK_DIALOG (dialog));
573 gtk_widget_destroy (dialog);
575 return result == GTK_RESPONSE_OK;
579 on_rename_dataset (PsppireDataWindow *de)
581 struct dataset *ds = de->dataset;
582 struct session *session = dataset_session (ds);
583 const char *old_name = dataset_name (ds);
584 struct dataset *existing_dataset;
588 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
590 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
594 if (new_name == NULL)
597 existing_dataset = session_lookup_dataset (session, new_name);
598 if (existing_dataset == NULL || existing_dataset == ds
599 || confirm_delete_dataset (de, old_name, new_name,
600 dataset_name (existing_dataset)))
601 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
608 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
610 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
612 if ( gtk_toggle_action_get_active (action))
613 gtk_widget_show (statusbar);
615 gtk_widget_hide (statusbar);
620 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
622 const gboolean grid_visible = gtk_toggle_action_get_active (action);
624 psppire_data_editor_show_grid (de->data_editor, grid_visible);
628 data_view_activate (PsppireDataWindow *de)
630 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
635 variable_view_activate (PsppireDataWindow *de)
637 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
642 fonts_activate (PsppireDataWindow *de)
644 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
645 PangoFontDescription *current_font;
648 gtk_font_selection_dialog_new (_("Font Selection"));
651 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
652 font_name = pango_font_description_to_string (current_font);
654 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
658 gtk_window_set_transient_for (GTK_WINDOW (dialog),
659 GTK_WINDOW (toplevel));
661 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
663 const gchar *font = gtk_font_selection_dialog_get_font_name
664 (GTK_FONT_SELECTION_DIALOG (dialog));
666 PangoFontDescription* font_desc =
667 pango_font_description_from_string (font);
669 psppire_data_editor_set_font (de->data_editor, font_desc);
672 gtk_widget_hide (dialog);
677 /* Callback for the value labels action */
679 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
681 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
685 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
687 psppire_data_editor_split_window (de->data_editor,
688 gtk_toggle_action_get_active (ta));
693 file_quit (PsppireDataWindow *de)
695 /* FIXME: Need to be more intelligent here.
696 Give the user the opportunity to save any unsaved data.
702 on_recent_data_select (GtkMenuShell *menushell,
703 PsppireWindow *window)
708 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
710 file = g_filename_from_uri (uri, NULL, NULL);
714 open_data_window (window, file, NULL);
720 charset_from_mime_type (const char *mime_type)
726 if (mime_type == NULL)
729 charset = c_strcasestr (mime_type, "charset=");
737 /* Parse a "quoted-string" as defined by RFC 822. */
738 for (p++; *p != '\0' && *p != '"'; p++)
741 ds_put_byte (&s, *p);
742 else if (*++p != '\0')
743 ds_put_byte (&s, *p);
748 /* Parse a "token" as defined by RFC 2045. */
749 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
750 ds_put_byte (&s, *p++);
752 if (!ds_is_empty (&s))
753 return ds_steal_cstr (&s);
760 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
767 /* Get the file name and its encoding. */
768 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
769 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
770 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
771 gtk_recent_info_unref (item);
773 se = psppire_syntax_window_new (encoding);
777 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
778 gtk_widget_show (se);
780 gtk_widget_destroy (se);
786 set_unsaved (gpointer w)
788 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
792 on_switch_page (PsppireDataEditor *de, gpointer p,
793 gint pagenum, PsppireDataWindow *dw)
795 GtkWidget *page_menu_item;
799 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
801 ? "/ui/menubar/view/view_data"
802 : "/ui/menubar/view/view_variables");
803 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
804 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
808 on_ui_manager_changed (PsppireDataEditor *de,
809 GParamSpec *pspec UNUSED,
810 PsppireDataWindow *dw)
812 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
818 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
819 g_object_unref (dw->uim);
826 g_object_ref (dw->uim);
827 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
831 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
832 Returns a pointer to the action
835 connect_action (PsppireDataWindow *dw, const char *action_name,
838 GtkAction *action = get_action_assert (dw->builder, action_name);
840 g_signal_connect_swapped (action, "activate", handler, dw);
845 /* Only a data file with at least one variable can be saved. */
847 enable_save (PsppireDataWindow *dw)
849 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
851 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
853 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
857 /* Initializes as much of a PsppireDataWindow as we can and must before the
858 dataset has been set.
860 In particular, the 'menu' member is required in case the "filename" property
861 is set before the "dataset" property: otherwise PsppireWindow will try to
862 modify the menu as part of the "filename" property_set() function and end up
863 with a Gtk-CRITICAL since 'menu' is NULL. */
865 psppire_data_window_init (PsppireDataWindow *de)
867 de->builder = builder_new ("data-editor.ui");
869 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
871 PSPPIRE_WINDOW (de)->menu =
872 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
879 psppire_data_window_finish_init (PsppireDataWindow *de,
882 static const struct dataset_callbacks cbs =
884 set_unsaved, /* changed */
885 transformation_change_callback, /* transformations_changed */
892 GtkWidget *box = gtk_vbox_new (FALSE, 0);
895 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
896 de->data_store = psppire_data_store_new (de->dict);
897 psppire_data_store_set_reader (de->data_store, NULL);
899 menubar = get_widget_assert (de->builder, "menubar");
900 hb = get_widget_assert (de->builder, "handlebox1");
901 sb = get_widget_assert (de->builder, "status-bar");
907 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
908 g_signal_connect (de->data_editor, "switch-page",
909 G_CALLBACK (on_switch_page), de);
911 g_signal_connect_swapped (de->data_store, "case-changed",
912 G_CALLBACK (set_unsaved), de);
914 g_signal_connect_swapped (de->data_store, "case-inserted",
915 G_CALLBACK (set_unsaved), de);
917 g_signal_connect_swapped (de->data_store, "cases-deleted",
918 G_CALLBACK (set_unsaved), de);
920 dataset_set_callbacks (de->dataset, &cbs, de);
922 connect_help (de->builder);
924 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
925 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
926 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
927 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
929 gtk_container_add (GTK_CONTAINER (de), box);
931 g_signal_connect (de->dict, "weight-changed",
932 G_CALLBACK (on_weight_change),
935 g_signal_connect (de->dict, "filter-changed",
936 G_CALLBACK (on_filter_change),
939 g_signal_connect (de->dict, "split-changed",
940 G_CALLBACK (on_split_change),
943 g_signal_connect_swapped (de->dict, "backend-changed",
944 G_CALLBACK (enable_save), de);
945 g_signal_connect_swapped (de->dict, "variable-inserted",
946 G_CALLBACK (enable_save), de);
947 g_signal_connect_swapped (de->dict, "variable-deleted",
948 G_CALLBACK (enable_save), de);
951 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
953 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
955 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
957 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
959 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
961 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
963 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
965 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
967 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
969 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
970 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
971 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
972 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
973 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
974 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
975 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
976 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
977 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
978 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
979 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
980 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
981 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
982 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
983 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
984 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
985 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
986 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
989 GtkWidget *recent_data =
990 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
992 GtkWidget *recent_files =
993 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
996 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
997 gtk_recent_manager_get_default ());
999 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1000 gtk_recent_manager_get_default ());
1002 g_object_set (menu_data, "show-tips", TRUE, NULL);
1003 g_object_set (menu_files, "show-tips", TRUE, NULL);
1006 GtkRecentFilter *filter = gtk_recent_filter_new ();
1008 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1009 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1011 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1013 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1016 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1019 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1022 GtkRecentFilter *filter = gtk_recent_filter_new ();
1024 gtk_recent_filter_add_pattern (filter, "*.sps");
1025 gtk_recent_filter_add_pattern (filter, "*.SPS");
1027 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1029 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1032 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1034 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1038 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1041 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1042 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1044 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1046 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1048 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1050 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1052 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1054 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1056 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1058 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1060 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1062 merge_help_menu (de->ui_manager);
1064 g_signal_connect (de->data_editor, "notify::ui-manager",
1065 G_CALLBACK (on_ui_manager_changed), de);
1066 on_ui_manager_changed (de->data_editor, NULL, de);
1068 gtk_widget_show (GTK_WIDGET (de->data_editor));
1069 gtk_widget_show (box);
1071 ll_push_head (&all_data_windows, &de->ll);
1075 psppire_data_window_dispose (GObject *object)
1077 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1081 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1082 g_object_unref (dw->uim);
1086 if (dw->builder != NULL)
1088 g_object_unref (dw->builder);
1094 g_signal_handlers_disconnect_by_func (dw->dict,
1095 G_CALLBACK (enable_save), dw);
1096 g_signal_handlers_disconnect_by_func (dw->dict,
1097 G_CALLBACK (on_weight_change), dw);
1098 g_signal_handlers_disconnect_by_func (dw->dict,
1099 G_CALLBACK (on_filter_change), dw);
1100 g_signal_handlers_disconnect_by_func (dw->dict,
1101 G_CALLBACK (on_split_change), dw);
1103 g_object_unref (dw->dict);
1109 g_object_unref (dw->data_store);
1110 dw->data_store = NULL;
1113 if (dw->ll.next != NULL)
1115 ll_remove (&dw->ll);
1119 if (G_OBJECT_CLASS (parent_class)->dispose)
1120 G_OBJECT_CLASS (parent_class)->dispose (object);
1124 psppire_data_window_finalize (GObject *object)
1126 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1130 struct dataset *dataset = dw->dataset;
1131 struct session *session = dataset_session (dataset);
1135 dataset_set_callbacks (dataset, NULL, NULL);
1136 session_set_active_dataset (session, NULL);
1137 dataset_destroy (dataset);
1140 if (G_OBJECT_CLASS (parent_class)->finalize)
1141 G_OBJECT_CLASS (parent_class)->finalize (object);
1145 psppire_data_window_set_property (GObject *object,
1147 const GValue *value,
1150 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1155 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1158 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1164 psppire_data_window_get_property (GObject *object,
1169 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1174 g_value_set_pointer (value, window->dataset);
1177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1183 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1189 ui_string = gtk_ui_manager_get_ui (uim);
1190 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1194 g_return_val_if_fail (merge_id != 0, 0);
1196 list = gtk_ui_manager_get_action_groups (uim);
1197 for (; list != NULL; list = list->next)
1199 GtkActionGroup *action_group = list->data;
1200 GList *actions = gtk_action_group_list_actions (action_group);
1203 for (action = actions; action != NULL; action = action->next)
1205 GtkAction *a = action->data;
1207 if (PSPPIRE_IS_DIALOG_ACTION (a))
1208 g_object_set (a, "manager", pdw->ui_manager, NULL);
1211 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1214 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1215 gtk_ui_manager_get_accel_group (uim));
1221 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1222 GtkUIManager *uim, guint merge_id)
1226 g_return_if_fail (merge_id != 0);
1228 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1230 list = gtk_ui_manager_get_action_groups (uim);
1231 for (; list != NULL; list = list->next)
1233 GtkActionGroup *action_group = list->data;
1234 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1237 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1238 gtk_ui_manager_get_accel_group (uim));
1242 psppire_data_window_new (struct dataset *ds)
1246 if (the_session == NULL)
1247 the_session = session_create (NULL);
1251 char *dataset_name = session_generate_dataset_name (the_session);
1252 ds = dataset_create (the_session, dataset_name);
1253 free (dataset_name);
1255 assert (dataset_session (ds) == the_session);
1259 psppire_data_window_get_type (),
1260 "description", _("Data Editor"),
1264 if (dataset_name (ds) != NULL)
1265 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1271 psppire_data_window_is_empty (PsppireDataWindow *dw)
1273 return psppire_dict_get_var_cnt (dw->dict) == 0;
1277 psppire_data_window_iface_init (PsppireWindowIface *iface)
1279 iface->save = save_file;
1280 iface->pick_filename = data_pick_filename;
1281 iface->load = load_file;
1285 psppire_default_data_window (void)
1287 if (ll_is_empty (&all_data_windows))
1288 create_data_window ();
1289 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1293 psppire_data_window_set_default (PsppireDataWindow *pdw)
1295 ll_remove (&pdw->ll);
1296 ll_push_head (&all_data_windows, &pdw->ll);
1300 psppire_data_window_undefault (PsppireDataWindow *pdw)
1302 ll_remove (&pdw->ll);
1303 ll_push_tail (&all_data_windows, &pdw->ll);
1307 psppire_data_window_for_dataset (struct dataset *ds)
1309 PsppireDataWindow *pdw;
1311 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1312 if (pdw->dataset == ds)
1319 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1321 PsppireDataWindow *pdw;
1323 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1324 if (pdw->data_store == data_store)
1331 create_data_window (void)
1333 gtk_widget_show (psppire_data_window_new (NULL));
1337 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1341 if (PSPPIRE_IS_DATA_WINDOW (victim)
1342 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1344 window = GTK_WIDGET (victim);
1345 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1348 window = psppire_data_window_new (NULL);
1350 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1351 gtk_widget_show_all (window);