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/runs-dialog.h"
48 #include "ui/gui/ks-one-sample-dialog.h"
49 #include "ui/gui/recode-dialog.h"
50 #include "ui/gui/select-cases-dialog.h"
51 #include "ui/gui/split-file-dialog.h"
52 #include "ui/gui/t-test-one-sample.h"
53 #include "ui/gui/t-test-paired-samples.h"
54 #include "ui/gui/text-data-import-dialog.h"
55 #include "ui/gui/transpose-dialog.h"
56 #include "ui/gui/univariate-dialog.h"
57 #include "ui/gui/weight-cases-dialog.h"
58 #include "ui/syntax-gen.h"
60 #include "gl/c-strcase.h"
61 #include "gl/c-strcasestr.h"
62 #include "gl/xvasprintf.h"
65 #define _(msgid) gettext (msgid)
66 #define N_(msgid) msgid
68 struct session *the_session;
69 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
71 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
72 static void psppire_data_window_init (PsppireDataWindow *data_editor);
75 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
77 static void psppire_data_window_dispose (GObject *object);
78 static void psppire_data_window_finalize (GObject *object);
79 static void psppire_data_window_set_property (GObject *object,
83 static void psppire_data_window_get_property (GObject *object,
88 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
89 static void psppire_data_window_remove_ui (PsppireDataWindow *,
90 GtkUIManager *, guint);
93 psppire_data_window_get_type (void)
95 static GType psppire_data_window_type = 0;
97 if (!psppire_data_window_type)
99 static const GTypeInfo psppire_data_window_info =
101 sizeof (PsppireDataWindowClass),
104 (GClassInitFunc)psppire_data_window_class_init,
105 (GClassFinalizeFunc) NULL,
107 sizeof (PsppireDataWindow),
109 (GInstanceInitFunc) psppire_data_window_init,
112 static const GInterfaceInfo window_interface_info =
114 (GInterfaceInitFunc) psppire_data_window_iface_init,
119 psppire_data_window_type =
120 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
121 &psppire_data_window_info, 0);
124 g_type_add_interface_static (psppire_data_window_type,
125 PSPPIRE_TYPE_WINDOW_MODEL,
126 &window_interface_info);
129 return psppire_data_window_type;
132 static GObjectClass *parent_class ;
139 psppire_data_window_class_init (PsppireDataWindowClass *class)
141 GObjectClass *object_class = G_OBJECT_CLASS (class);
143 parent_class = g_type_class_peek_parent (class);
145 object_class->dispose = psppire_data_window_dispose;
146 object_class->finalize = psppire_data_window_finalize;
147 object_class->set_property = psppire_data_window_set_property;
148 object_class->get_property = psppire_data_window_get_property;
150 g_object_class_install_property (
151 object_class, PROP_DATASET,
152 g_param_spec_pointer ("dataset", "Dataset",
153 "'struct datset *' represented by the window",
154 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
157 /* Run the EXECUTE command. */
159 execute (PsppireDataWindow *dw)
161 execute_const_syntax_string (dw, "EXECUTE.");
165 transformation_change_callback (bool transformations_pending,
168 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
170 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
172 GtkWidget *menuitem =
173 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
175 GtkWidget *status_label =
176 get_widget_assert (de->builder, "case-counter-area");
178 gtk_widget_set_sensitive (menuitem, transformations_pending);
181 if ( transformations_pending)
182 gtk_label_set_text (GTK_LABEL (status_label),
183 _("Transformations Pending"));
185 gtk_label_set_text (GTK_LABEL (status_label), "");
188 /* Callback for when the dictionary changes its filter variable */
190 on_filter_change (GObject *o, gint filter_index, gpointer data)
192 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
194 GtkWidget *filter_status_area =
195 get_widget_assert (de->builder, "filter-use-status-area");
197 if ( filter_index == -1 )
199 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
203 PsppireDict *dict = NULL;
204 struct variable *var ;
207 g_object_get (de->data_editor, "dictionary", &dict, NULL);
209 var = psppire_dict_get_variable (dict, filter_index);
211 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
213 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
219 /* Callback for when the dictionary changes its split variables */
221 on_split_change (PsppireDict *dict, gpointer data)
223 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
225 size_t n_split_vars = dict_get_split_cnt (dict->dict);
227 GtkWidget *split_status_area =
228 get_widget_assert (de->builder, "split-file-status-area");
230 if ( n_split_vars == 0 )
232 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
238 const struct variable *const * split_vars =
239 dict_get_split_vars (dict->dict);
241 text = g_string_new (_("Split by "));
243 for (i = 0 ; i < n_split_vars - 1; ++i )
245 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
247 g_string_append (text, var_get_name (split_vars[i]));
249 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
251 g_string_free (text, TRUE);
258 /* Callback for when the dictionary changes its weights */
260 on_weight_change (GObject *o, gint weight_index, gpointer data)
262 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
264 GtkWidget *weight_status_area =
265 get_widget_assert (de->builder, "weight-status-area");
267 if ( weight_index == -1 )
269 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
273 struct variable *var ;
274 PsppireDict *dict = NULL;
277 g_object_get (de->data_editor, "dictionary", &dict, NULL);
279 var = psppire_dict_get_variable (dict, weight_index);
281 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
283 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
291 dump_rm (GtkRecentManager *rm)
293 GList *items = gtk_recent_manager_get_items (rm);
297 g_print ("Recent Items:\n");
298 for (i = items; i; i = i->next)
300 GtkRecentInfo *ri = i->data;
302 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
303 gtk_recent_info_get_short_name (ri),
304 gtk_recent_info_get_mime_type (ri),
305 gtk_recent_info_get_description (ri),
306 gtk_recent_info_get_uri (ri)
310 gtk_recent_info_unref (ri);
318 name_has_por_suffix (const gchar *name)
320 size_t length = strlen (name);
321 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
325 name_has_sav_suffix (const gchar *name)
327 size_t length = strlen (name);
328 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
331 /* Returns true if NAME has a suffix which might denote a PSPP file */
333 name_has_suffix (const gchar *name)
335 return name_has_por_suffix (name) || name_has_sav_suffix (name);
339 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
341 const char *mime_type = NULL;
342 gchar *syntax = NULL;
347 gchar *utf8_file_name;
348 struct string filename;
349 ds_init_empty (&filename);
351 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
353 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
355 g_free (utf8_file_name);
357 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
358 ds_destroy (&filename);
366 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
367 lex_reader_for_string (syntax));
370 if (ok && syn == NULL)
372 if (name_has_por_suffix (file_name))
373 mime_type = "application/x-spss-por";
374 else if (name_has_sav_suffix (file_name))
375 mime_type = "application/x-spss-sav";
377 add_most_recent (file_name, mime_type);
383 /* Save DE to file */
385 save_file (PsppireWindow *w)
387 const gchar *file_name = NULL;
388 gchar *utf8_file_name = NULL;
390 struct string filename ;
391 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
394 file_name = psppire_window_get_filename (w);
396 fnx = g_string_new (file_name);
398 if ( ! name_has_suffix (fnx->str))
400 if ( de->save_as_portable)
401 g_string_append (fnx, ".por");
403 g_string_append (fnx, ".sav");
406 ds_init_empty (&filename);
408 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
410 g_string_free (fnx, TRUE);
412 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
413 g_free (utf8_file_name);
415 syntax = g_strdup_printf ("%s OUTFILE=%s.",
416 de->save_as_portable ? "EXPORT" : "SAVE",
417 ds_cstr (&filename));
419 ds_destroy (&filename);
421 g_free (execute_syntax_string (de, syntax));
426 display_dict (PsppireDataWindow *de)
428 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
432 sysfile_info (PsppireDataWindow *de)
434 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
436 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
438 struct string filename;
440 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
442 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
447 ds_init_empty (&filename);
449 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
451 g_free (utf8_file_name);
453 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
454 g_free (execute_syntax_string (de, syntax));
457 gtk_widget_destroy (dialog);
461 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
463 data_pick_filename (PsppireWindow *window)
465 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
466 GtkFileFilter *filter = gtk_file_filter_new ();
467 GtkWidget *button_sys;
469 gtk_file_chooser_dialog_new (_("Save"),
471 GTK_FILE_CHOOSER_ACTION_SAVE,
472 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
473 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
476 g_object_set (dialog, "local-only", FALSE, NULL);
478 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
479 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
480 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
482 filter = gtk_file_filter_new ();
483 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
484 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
485 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
487 filter = gtk_file_filter_new ();
488 gtk_file_filter_set_name (filter, _("All Files"));
489 gtk_file_filter_add_pattern (filter, "*");
490 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
493 GtkWidget *button_por;
494 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
496 gtk_radio_button_new_with_label (NULL, _("System File"));
499 gtk_radio_button_new_with_label
500 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
503 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
504 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
506 gtk_widget_show_all (vbox);
508 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
511 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
514 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
516 case GTK_RESPONSE_ACCEPT:
521 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
524 de->save_as_portable =
525 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
527 if ( ! name_has_suffix (filename->str))
529 if ( de->save_as_portable)
530 g_string_append (filename, ".por");
532 g_string_append (filename, ".sav");
535 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
537 g_string_free (filename, TRUE);
544 gtk_widget_destroy (dialog);
548 confirm_delete_dataset (PsppireDataWindow *de,
549 const char *old_dataset,
550 const char *new_dataset,
551 const char *existing_dataset)
556 dialog = gtk_message_dialog_new (
557 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
558 _("Delete Existing Dataset?"));
560 gtk_message_dialog_format_secondary_text (
561 GTK_MESSAGE_DIALOG (dialog),
562 _("Renaming \"%s\" to \"%s\" will destroy the existing "
563 "dataset named \"%s\". Are you sure that you want to do this?"),
564 old_dataset, new_dataset, existing_dataset);
566 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
567 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
568 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
571 g_object_set (dialog, "icon-name", "pspp", NULL);
573 result = gtk_dialog_run (GTK_DIALOG (dialog));
575 gtk_widget_destroy (dialog);
577 return result == GTK_RESPONSE_OK;
581 on_rename_dataset (PsppireDataWindow *de)
583 struct dataset *ds = de->dataset;
584 struct session *session = dataset_session (ds);
585 const char *old_name = dataset_name (ds);
586 struct dataset *existing_dataset;
590 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
592 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
596 if (new_name == NULL)
599 existing_dataset = session_lookup_dataset (session, new_name);
600 if (existing_dataset == NULL || existing_dataset == ds
601 || confirm_delete_dataset (de, old_name, new_name,
602 dataset_name (existing_dataset)))
603 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
610 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
612 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
614 if ( gtk_toggle_action_get_active (action))
615 gtk_widget_show (statusbar);
617 gtk_widget_hide (statusbar);
622 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
624 const gboolean grid_visible = gtk_toggle_action_get_active (action);
626 psppire_data_editor_show_grid (de->data_editor, grid_visible);
630 data_view_activate (PsppireDataWindow *de)
632 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
637 variable_view_activate (PsppireDataWindow *de)
639 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
644 fonts_activate (PsppireDataWindow *de)
646 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
647 PangoFontDescription *current_font;
650 gtk_font_selection_dialog_new (_("Font Selection"));
653 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
654 font_name = pango_font_description_to_string (current_font);
656 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
660 gtk_window_set_transient_for (GTK_WINDOW (dialog),
661 GTK_WINDOW (toplevel));
663 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
665 const gchar *font = gtk_font_selection_dialog_get_font_name
666 (GTK_FONT_SELECTION_DIALOG (dialog));
668 PangoFontDescription* font_desc =
669 pango_font_description_from_string (font);
671 psppire_data_editor_set_font (de->data_editor, font_desc);
674 gtk_widget_hide (dialog);
679 /* Callback for the value labels action */
681 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
683 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
687 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
689 psppire_data_editor_split_window (de->data_editor,
690 gtk_toggle_action_get_active (ta));
695 file_quit (PsppireDataWindow *de)
697 /* FIXME: Need to be more intelligent here.
698 Give the user the opportunity to save any unsaved data.
704 on_recent_data_select (GtkMenuShell *menushell,
705 PsppireWindow *window)
710 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
712 file = g_filename_from_uri (uri, NULL, NULL);
716 open_data_window (window, file, NULL);
722 charset_from_mime_type (const char *mime_type)
728 if (mime_type == NULL)
731 charset = c_strcasestr (mime_type, "charset=");
739 /* Parse a "quoted-string" as defined by RFC 822. */
740 for (p++; *p != '\0' && *p != '"'; p++)
743 ds_put_byte (&s, *p);
744 else if (*++p != '\0')
745 ds_put_byte (&s, *p);
750 /* Parse a "token" as defined by RFC 2045. */
751 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
752 ds_put_byte (&s, *p++);
754 if (!ds_is_empty (&s))
755 return ds_steal_cstr (&s);
762 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
769 /* Get the file name and its encoding. */
770 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
771 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
772 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
773 gtk_recent_info_unref (item);
775 se = psppire_syntax_window_new (encoding);
779 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
780 gtk_widget_show (se);
782 gtk_widget_destroy (se);
788 set_unsaved (gpointer w)
790 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
794 on_switch_page (PsppireDataEditor *de, gpointer p,
795 gint pagenum, PsppireDataWindow *dw)
797 GtkWidget *page_menu_item;
801 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
803 ? "/ui/menubar/view/view_data"
804 : "/ui/menubar/view/view_variables");
805 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
806 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
810 on_ui_manager_changed (PsppireDataEditor *de,
811 GParamSpec *pspec UNUSED,
812 PsppireDataWindow *dw)
814 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
820 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
821 g_object_unref (dw->uim);
828 g_object_ref (dw->uim);
829 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
833 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
834 Returns a pointer to the action
837 connect_action (PsppireDataWindow *dw, const char *action_name,
840 GtkAction *action = get_action_assert (dw->builder, action_name);
842 g_signal_connect_swapped (action, "activate", handler, dw);
847 /* Only a data file with at least one variable can be saved. */
849 enable_save (PsppireDataWindow *dw)
851 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
853 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
855 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
859 /* Initializes as much of a PsppireDataWindow as we can and must before the
860 dataset has been set.
862 In particular, the 'menu' member is required in case the "filename" property
863 is set before the "dataset" property: otherwise PsppireWindow will try to
864 modify the menu as part of the "filename" property_set() function and end up
865 with a Gtk-CRITICAL since 'menu' is NULL. */
867 psppire_data_window_init (PsppireDataWindow *de)
869 de->builder = builder_new ("data-editor.ui");
871 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
873 PSPPIRE_WINDOW (de)->menu =
874 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
881 psppire_data_window_finish_init (PsppireDataWindow *de,
884 static const struct dataset_callbacks cbs =
886 set_unsaved, /* changed */
887 transformation_change_callback, /* transformations_changed */
894 GtkWidget *box = gtk_vbox_new (FALSE, 0);
897 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
898 de->data_store = psppire_data_store_new (de->dict);
899 psppire_data_store_set_reader (de->data_store, NULL);
901 menubar = get_widget_assert (de->builder, "menubar");
902 hb = get_widget_assert (de->builder, "handlebox1");
903 sb = get_widget_assert (de->builder, "status-bar");
909 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
910 g_signal_connect (de->data_editor, "switch-page",
911 G_CALLBACK (on_switch_page), de);
913 g_signal_connect_swapped (de->data_store, "case-changed",
914 G_CALLBACK (set_unsaved), de);
916 g_signal_connect_swapped (de->data_store, "case-inserted",
917 G_CALLBACK (set_unsaved), de);
919 g_signal_connect_swapped (de->data_store, "cases-deleted",
920 G_CALLBACK (set_unsaved), de);
922 dataset_set_callbacks (de->dataset, &cbs, de);
924 connect_help (de->builder);
926 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
927 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
928 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
929 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
931 gtk_container_add (GTK_CONTAINER (de), box);
933 g_signal_connect (de->dict, "weight-changed",
934 G_CALLBACK (on_weight_change),
937 g_signal_connect (de->dict, "filter-changed",
938 G_CALLBACK (on_filter_change),
941 g_signal_connect (de->dict, "split-changed",
942 G_CALLBACK (on_split_change),
945 g_signal_connect_swapped (de->dict, "backend-changed",
946 G_CALLBACK (enable_save), de);
947 g_signal_connect_swapped (de->dict, "variable-inserted",
948 G_CALLBACK (enable_save), de);
949 g_signal_connect_swapped (de->dict, "variable-deleted",
950 G_CALLBACK (enable_save), de);
953 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
955 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
957 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
959 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
961 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
963 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
965 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
967 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
969 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
971 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
972 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
973 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
974 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
975 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
976 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
977 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
978 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
979 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
980 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
981 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
982 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
983 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
984 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
985 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
986 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
987 connect_action (de, "runs", G_CALLBACK (runs_dialog));
988 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
989 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
990 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
993 GtkWidget *recent_data =
994 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
996 GtkWidget *recent_files =
997 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
1000 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1001 gtk_recent_manager_get_default ());
1003 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1004 gtk_recent_manager_get_default ());
1006 g_object_set (menu_data, "show-tips", TRUE, NULL);
1007 g_object_set (menu_files, "show-tips", TRUE, NULL);
1010 GtkRecentFilter *filter = gtk_recent_filter_new ();
1012 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1013 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1015 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1017 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1020 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1023 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1026 GtkRecentFilter *filter = gtk_recent_filter_new ();
1028 gtk_recent_filter_add_pattern (filter, "*.sps");
1029 gtk_recent_filter_add_pattern (filter, "*.SPS");
1031 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1033 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1036 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1038 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1042 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1045 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1046 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1048 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1050 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1052 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1054 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1056 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1058 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1060 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1062 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1064 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1066 merge_help_menu (de->ui_manager);
1068 g_signal_connect (de->data_editor, "notify::ui-manager",
1069 G_CALLBACK (on_ui_manager_changed), de);
1070 on_ui_manager_changed (de->data_editor, NULL, de);
1072 gtk_widget_show (GTK_WIDGET (de->data_editor));
1073 gtk_widget_show (box);
1075 ll_push_head (&all_data_windows, &de->ll);
1079 psppire_data_window_dispose (GObject *object)
1081 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1085 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1086 g_object_unref (dw->uim);
1090 if (dw->builder != NULL)
1092 g_object_unref (dw->builder);
1098 g_signal_handlers_disconnect_by_func (dw->dict,
1099 G_CALLBACK (enable_save), dw);
1100 g_signal_handlers_disconnect_by_func (dw->dict,
1101 G_CALLBACK (on_weight_change), dw);
1102 g_signal_handlers_disconnect_by_func (dw->dict,
1103 G_CALLBACK (on_filter_change), dw);
1104 g_signal_handlers_disconnect_by_func (dw->dict,
1105 G_CALLBACK (on_split_change), dw);
1107 g_object_unref (dw->dict);
1113 g_object_unref (dw->data_store);
1114 dw->data_store = NULL;
1117 if (dw->ll.next != NULL)
1119 ll_remove (&dw->ll);
1123 if (G_OBJECT_CLASS (parent_class)->dispose)
1124 G_OBJECT_CLASS (parent_class)->dispose (object);
1128 psppire_data_window_finalize (GObject *object)
1130 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1134 struct dataset *dataset = dw->dataset;
1135 struct session *session = dataset_session (dataset);
1139 dataset_set_callbacks (dataset, NULL, NULL);
1140 session_set_active_dataset (session, NULL);
1141 dataset_destroy (dataset);
1144 if (G_OBJECT_CLASS (parent_class)->finalize)
1145 G_OBJECT_CLASS (parent_class)->finalize (object);
1149 psppire_data_window_set_property (GObject *object,
1151 const GValue *value,
1154 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1159 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1162 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1168 psppire_data_window_get_property (GObject *object,
1173 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1178 g_value_set_pointer (value, window->dataset);
1181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1187 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1193 ui_string = gtk_ui_manager_get_ui (uim);
1194 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1198 g_return_val_if_fail (merge_id != 0, 0);
1200 list = gtk_ui_manager_get_action_groups (uim);
1201 for (; list != NULL; list = list->next)
1203 GtkActionGroup *action_group = list->data;
1204 GList *actions = gtk_action_group_list_actions (action_group);
1207 for (action = actions; action != NULL; action = action->next)
1209 GtkAction *a = action->data;
1211 if (PSPPIRE_IS_DIALOG_ACTION (a))
1212 g_object_set (a, "manager", pdw->ui_manager, NULL);
1215 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1218 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1219 gtk_ui_manager_get_accel_group (uim));
1225 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1226 GtkUIManager *uim, guint merge_id)
1230 g_return_if_fail (merge_id != 0);
1232 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1234 list = gtk_ui_manager_get_action_groups (uim);
1235 for (; list != NULL; list = list->next)
1237 GtkActionGroup *action_group = list->data;
1238 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1241 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1242 gtk_ui_manager_get_accel_group (uim));
1246 psppire_data_window_new (struct dataset *ds)
1250 if (the_session == NULL)
1251 the_session = session_create (NULL);
1255 char *dataset_name = session_generate_dataset_name (the_session);
1256 ds = dataset_create (the_session, dataset_name);
1257 free (dataset_name);
1259 assert (dataset_session (ds) == the_session);
1263 psppire_data_window_get_type (),
1264 "description", _("Data Editor"),
1268 if (dataset_name (ds) != NULL)
1269 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1275 psppire_data_window_is_empty (PsppireDataWindow *dw)
1277 return psppire_dict_get_var_cnt (dw->dict) == 0;
1281 psppire_data_window_iface_init (PsppireWindowIface *iface)
1283 iface->save = save_file;
1284 iface->pick_filename = data_pick_filename;
1285 iface->load = load_file;
1289 psppire_default_data_window (void)
1291 if (ll_is_empty (&all_data_windows))
1292 create_data_window ();
1293 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1297 psppire_data_window_set_default (PsppireDataWindow *pdw)
1299 ll_remove (&pdw->ll);
1300 ll_push_head (&all_data_windows, &pdw->ll);
1304 psppire_data_window_undefault (PsppireDataWindow *pdw)
1306 ll_remove (&pdw->ll);
1307 ll_push_tail (&all_data_windows, &pdw->ll);
1311 psppire_data_window_for_dataset (struct dataset *ds)
1313 PsppireDataWindow *pdw;
1315 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1316 if (pdw->dataset == ds)
1323 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1325 PsppireDataWindow *pdw;
1327 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1328 if (pdw->data_store == data_store)
1335 create_data_window (void)
1337 gtk_widget_show (psppire_data_window_new (NULL));
1341 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1345 if (PSPPIRE_IS_DATA_WINDOW (victim)
1346 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1348 window = GTK_WIDGET (victim);
1349 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1352 window = psppire_data_window_new (NULL);
1354 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1355 gtk_widget_show_all (window);