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_object_unref (dw->dict);
1104 g_object_unref (dw->data_store);
1105 dw->data_store = NULL;
1108 if (dw->ll.next != NULL)
1110 ll_remove (&dw->ll);
1114 if (G_OBJECT_CLASS (parent_class)->dispose)
1115 G_OBJECT_CLASS (parent_class)->dispose (object);
1119 psppire_data_window_finalize (GObject *object)
1121 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1125 struct dataset *dataset = dw->dataset;
1126 struct session *session = dataset_session (dataset);
1130 dataset_set_callbacks (dataset, NULL, NULL);
1131 session_set_active_dataset (session, NULL);
1132 dataset_destroy (dataset);
1135 if (G_OBJECT_CLASS (parent_class)->finalize)
1136 G_OBJECT_CLASS (parent_class)->finalize (object);
1140 psppire_data_window_set_property (GObject *object,
1142 const GValue *value,
1145 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1150 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1153 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1159 psppire_data_window_get_property (GObject *object,
1164 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1169 g_value_set_pointer (value, window->dataset);
1172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1178 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1184 ui_string = gtk_ui_manager_get_ui (uim);
1185 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1189 g_return_val_if_fail (merge_id != 0, 0);
1191 list = gtk_ui_manager_get_action_groups (uim);
1192 for (; list != NULL; list = list->next)
1194 GtkActionGroup *action_group = list->data;
1195 GList *actions = gtk_action_group_list_actions (action_group);
1198 for (action = actions; action != NULL; action = action->next)
1200 GtkAction *a = action->data;
1202 if (PSPPIRE_IS_DIALOG_ACTION (a))
1203 g_object_set (a, "manager", pdw->ui_manager, NULL);
1206 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1209 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1210 gtk_ui_manager_get_accel_group (uim));
1216 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1217 GtkUIManager *uim, guint merge_id)
1221 g_return_if_fail (merge_id != 0);
1223 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1225 list = gtk_ui_manager_get_action_groups (uim);
1226 for (; list != NULL; list = list->next)
1228 GtkActionGroup *action_group = list->data;
1229 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1232 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1233 gtk_ui_manager_get_accel_group (uim));
1237 psppire_data_window_new (struct dataset *ds)
1241 if (the_session == NULL)
1242 the_session = session_create (NULL);
1246 char *dataset_name = session_generate_dataset_name (the_session);
1247 ds = dataset_create (the_session, dataset_name);
1248 free (dataset_name);
1250 assert (dataset_session (ds) == the_session);
1254 psppire_data_window_get_type (),
1255 "description", _("Data Editor"),
1259 if (dataset_name (ds) != NULL)
1260 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1266 psppire_data_window_is_empty (PsppireDataWindow *dw)
1268 return psppire_dict_get_var_cnt (dw->dict) == 0;
1272 psppire_data_window_iface_init (PsppireWindowIface *iface)
1274 iface->save = save_file;
1275 iface->pick_filename = data_pick_filename;
1276 iface->load = load_file;
1280 psppire_default_data_window (void)
1282 if (ll_is_empty (&all_data_windows))
1283 create_data_window ();
1284 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1288 psppire_data_window_set_default (PsppireDataWindow *pdw)
1290 ll_remove (&pdw->ll);
1291 ll_push_head (&all_data_windows, &pdw->ll);
1295 psppire_data_window_undefault (PsppireDataWindow *pdw)
1297 ll_remove (&pdw->ll);
1298 ll_push_tail (&all_data_windows, &pdw->ll);
1302 psppire_data_window_for_dataset (struct dataset *ds)
1304 PsppireDataWindow *pdw;
1306 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1307 if (pdw->dataset == ds)
1314 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1316 PsppireDataWindow *pdw;
1318 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1319 if (pdw->data_store == data_store)
1326 create_data_window (void)
1328 gtk_widget_show (psppire_data_window_new (NULL));
1332 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1336 if (PSPPIRE_IS_DATA_WINDOW (victim)
1337 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1339 window = GTK_WIDGET (victim);
1340 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1343 window = psppire_data_window_new (NULL);
1345 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1346 gtk_widget_show_all (window);