1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/builder-wrapper.h"
30 #include "ui/gui/comments-dialog.h"
31 #include "ui/gui/compute-dialog.h"
32 #include "ui/gui/count-dialog.h"
33 #include "ui/gui/entry-dialog.h"
34 #include "ui/gui/executor.h"
35 #include "ui/gui/help-menu.h"
36 #include "ui/gui/helper.h"
37 #include "ui/gui/helper.h"
38 #include "ui/gui/k-related-dialog.h"
39 #include "ui/gui/npar-two-sample-related.h"
40 #include "ui/gui/oneway-anova-dialog.h"
41 #include "ui/gui/psppire-data-window.h"
42 #include "ui/gui/psppire-dialog-action.h"
43 #include "ui/gui/psppire-syntax-window.h"
44 #include "ui/gui/psppire-window.h"
45 #include "ui/gui/psppire.h"
46 #include "ui/gui/recode-dialog.h"
47 #include "ui/gui/select-cases-dialog.h"
48 #include "ui/gui/split-file-dialog.h"
49 #include "ui/gui/t-test-one-sample.h"
50 #include "ui/gui/t-test-paired-samples.h"
51 #include "ui/gui/text-data-import-dialog.h"
52 #include "ui/gui/weight-cases-dialog.h"
53 #include "ui/syntax-gen.h"
55 #include "gl/c-strcase.h"
56 #include "gl/c-strcasestr.h"
57 #include "gl/xvasprintf.h"
60 #define _(msgid) gettext (msgid)
61 #define N_(msgid) msgid
63 struct session *the_session;
64 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
66 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
67 static void psppire_data_window_init (PsppireDataWindow *data_editor);
70 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
72 static void psppire_data_window_dispose (GObject *object);
73 static void psppire_data_window_finalize (GObject *object);
74 static void psppire_data_window_set_property (GObject *object,
78 static void psppire_data_window_get_property (GObject *object,
83 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
84 static void psppire_data_window_remove_ui (PsppireDataWindow *,
85 GtkUIManager *, guint);
88 psppire_data_window_get_type (void)
90 static GType psppire_data_window_type = 0;
92 if (!psppire_data_window_type)
94 static const GTypeInfo psppire_data_window_info =
96 sizeof (PsppireDataWindowClass),
99 (GClassInitFunc)psppire_data_window_class_init,
100 (GClassFinalizeFunc) NULL,
102 sizeof (PsppireDataWindow),
104 (GInstanceInitFunc) psppire_data_window_init,
107 static const GInterfaceInfo window_interface_info =
109 (GInterfaceInitFunc) psppire_data_window_iface_init,
114 psppire_data_window_type =
115 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
116 &psppire_data_window_info, 0);
119 g_type_add_interface_static (psppire_data_window_type,
120 PSPPIRE_TYPE_WINDOW_MODEL,
121 &window_interface_info);
124 return psppire_data_window_type;
127 static GObjectClass *parent_class ;
134 psppire_data_window_class_init (PsppireDataWindowClass *class)
136 GObjectClass *object_class = G_OBJECT_CLASS (class);
138 parent_class = g_type_class_peek_parent (class);
140 object_class->dispose = psppire_data_window_dispose;
141 object_class->finalize = psppire_data_window_finalize;
142 object_class->set_property = psppire_data_window_set_property;
143 object_class->get_property = psppire_data_window_get_property;
145 g_object_class_install_property (
146 object_class, PROP_DATASET,
147 g_param_spec_pointer ("dataset", "Dataset",
148 "'struct datset *' represented by the window",
149 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
152 /* Run the EXECUTE command. */
154 execute (PsppireDataWindow *dw)
156 execute_const_syntax_string (dw, "EXECUTE.");
160 transformation_change_callback (bool transformations_pending,
163 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
165 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
167 GtkWidget *menuitem =
168 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
170 GtkWidget *status_label =
171 get_widget_assert (de->builder, "case-counter-area");
173 gtk_widget_set_sensitive (menuitem, transformations_pending);
176 if ( transformations_pending)
177 gtk_label_set_text (GTK_LABEL (status_label),
178 _("Transformations Pending"));
180 gtk_label_set_text (GTK_LABEL (status_label), "");
183 /* Callback for when the dictionary changes its filter variable */
185 on_filter_change (GObject *o, gint filter_index, gpointer data)
187 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
189 GtkWidget *filter_status_area =
190 get_widget_assert (de->builder, "filter-use-status-area");
192 if ( filter_index == -1 )
194 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
198 PsppireDict *dict = NULL;
199 struct variable *var ;
202 g_object_get (de->data_editor, "dictionary", &dict, NULL);
204 var = psppire_dict_get_variable (dict, filter_index);
206 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
208 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
214 /* Callback for when the dictionary changes its split variables */
216 on_split_change (PsppireDict *dict, gpointer data)
218 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
220 size_t n_split_vars = dict_get_split_cnt (dict->dict);
222 GtkWidget *split_status_area =
223 get_widget_assert (de->builder, "split-file-status-area");
225 if ( n_split_vars == 0 )
227 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
233 const struct variable *const * split_vars =
234 dict_get_split_vars (dict->dict);
236 text = g_string_new (_("Split by "));
238 for (i = 0 ; i < n_split_vars - 1; ++i )
240 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
242 g_string_append (text, var_get_name (split_vars[i]));
244 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
246 g_string_free (text, TRUE);
253 /* Callback for when the dictionary changes its weights */
255 on_weight_change (GObject *o, gint weight_index, gpointer data)
257 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
259 GtkWidget *weight_status_area =
260 get_widget_assert (de->builder, "weight-status-area");
262 if ( weight_index == -1 )
264 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
268 struct variable *var ;
269 PsppireDict *dict = NULL;
272 g_object_get (de->data_editor, "dictionary", &dict, NULL);
274 var = psppire_dict_get_variable (dict, weight_index);
276 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
278 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
286 dump_rm (GtkRecentManager *rm)
288 GList *items = gtk_recent_manager_get_items (rm);
292 g_print ("Recent Items:\n");
293 for (i = items; i; i = i->next)
295 GtkRecentInfo *ri = i->data;
297 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
298 gtk_recent_info_get_short_name (ri),
299 gtk_recent_info_get_mime_type (ri),
300 gtk_recent_info_get_description (ri),
301 gtk_recent_info_get_uri (ri)
305 gtk_recent_info_unref (ri);
313 name_has_por_suffix (const gchar *name)
315 size_t length = strlen (name);
316 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
320 name_has_sav_suffix (const gchar *name)
322 size_t length = strlen (name);
323 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
326 /* Returns true if NAME has a suffix which might denote a PSPP file */
328 name_has_suffix (const gchar *name)
330 return name_has_por_suffix (name) || name_has_sav_suffix (name);
334 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
336 const char *mime_type = NULL;
337 gchar *syntax = NULL;
342 gchar *utf8_file_name;
343 struct string filename;
344 ds_init_empty (&filename);
346 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
348 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
350 g_free (utf8_file_name);
352 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
353 ds_destroy (&filename);
361 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
362 lex_reader_for_string (syntax));
365 if (ok && syn == NULL)
367 if (name_has_por_suffix (file_name))
368 mime_type = "application/x-spss-por";
369 else if (name_has_sav_suffix (file_name))
370 mime_type = "application/x-spss-sav";
372 add_most_recent (file_name, mime_type);
378 /* Save DE to file */
380 save_file (PsppireWindow *w)
382 const gchar *file_name = NULL;
383 gchar *utf8_file_name = NULL;
385 struct string filename ;
386 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
389 file_name = psppire_window_get_filename (w);
391 fnx = g_string_new (file_name);
393 if ( ! name_has_suffix (fnx->str))
395 if ( de->save_as_portable)
396 g_string_append (fnx, ".por");
398 g_string_append (fnx, ".sav");
401 ds_init_empty (&filename);
403 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
405 g_string_free (fnx, TRUE);
407 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
408 g_free (utf8_file_name);
410 syntax = g_strdup_printf ("%s OUTFILE=%s.",
411 de->save_as_portable ? "EXPORT" : "SAVE",
412 ds_cstr (&filename));
414 ds_destroy (&filename);
416 g_free (execute_syntax_string (de, syntax));
421 display_dict (PsppireDataWindow *de)
423 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
427 sysfile_info (PsppireDataWindow *de)
429 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
431 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
433 struct string filename;
435 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
437 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
442 ds_init_empty (&filename);
444 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
446 g_free (utf8_file_name);
448 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
449 g_free (execute_syntax_string (de, syntax));
452 gtk_widget_destroy (dialog);
456 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
458 data_pick_filename (PsppireWindow *window)
460 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
461 GtkFileFilter *filter = gtk_file_filter_new ();
462 GtkWidget *button_sys;
464 gtk_file_chooser_dialog_new (_("Save"),
466 GTK_FILE_CHOOSER_ACTION_SAVE,
467 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
468 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
471 g_object_set (dialog, "local-only", FALSE, NULL);
473 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
474 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
475 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
477 filter = gtk_file_filter_new ();
478 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
479 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
480 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
482 filter = gtk_file_filter_new ();
483 gtk_file_filter_set_name (filter, _("All Files"));
484 gtk_file_filter_add_pattern (filter, "*");
485 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
488 GtkWidget *button_por;
489 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
491 gtk_radio_button_new_with_label (NULL, _("System File"));
494 gtk_radio_button_new_with_label
495 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
498 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
499 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
501 gtk_widget_show_all (vbox);
503 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
506 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
509 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
511 case GTK_RESPONSE_ACCEPT:
516 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
519 de->save_as_portable =
520 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
522 if ( ! name_has_suffix (filename->str))
524 if ( de->save_as_portable)
525 g_string_append (filename, ".por");
527 g_string_append (filename, ".sav");
530 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
532 g_string_free (filename, TRUE);
539 gtk_widget_destroy (dialog);
543 confirm_delete_dataset (PsppireDataWindow *de,
544 const char *old_dataset,
545 const char *new_dataset,
546 const char *existing_dataset)
551 dialog = gtk_message_dialog_new (
552 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
553 _("Delete Existing Dataset?"));
555 gtk_message_dialog_format_secondary_text (
556 GTK_MESSAGE_DIALOG (dialog),
557 _("Renaming \"%s\" to \"%s\" will destroy the existing "
558 "dataset named \"%s\". Are you sure that you want to do this?"),
559 old_dataset, new_dataset, existing_dataset);
561 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
562 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
563 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
566 g_object_set (dialog, "icon-name", "pspp", NULL);
568 result = gtk_dialog_run (GTK_DIALOG (dialog));
570 gtk_widget_destroy (dialog);
572 return result == GTK_RESPONSE_OK;
576 on_rename_dataset (PsppireDataWindow *de)
578 struct dataset *ds = de->dataset;
579 struct session *session = dataset_session (ds);
580 const char *old_name = dataset_name (ds);
581 struct dataset *existing_dataset;
585 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
587 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
591 if (new_name == NULL)
594 existing_dataset = session_lookup_dataset (session, new_name);
595 if (existing_dataset == NULL || existing_dataset == ds
596 || confirm_delete_dataset (de, old_name, new_name,
597 dataset_name (existing_dataset)))
598 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
605 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
607 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
609 if ( gtk_toggle_action_get_active (action))
610 gtk_widget_show (statusbar);
612 gtk_widget_hide (statusbar);
617 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
619 const gboolean grid_visible = gtk_toggle_action_get_active (action);
621 psppire_data_editor_show_grid (de->data_editor, grid_visible);
625 data_view_activate (PsppireDataWindow *de)
627 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
632 variable_view_activate (PsppireDataWindow *de)
634 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
639 fonts_activate (PsppireDataWindow *de)
641 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
642 PangoFontDescription *current_font;
645 gtk_font_selection_dialog_new (_("Font Selection"));
648 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
649 font_name = pango_font_description_to_string (current_font);
651 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
655 gtk_window_set_transient_for (GTK_WINDOW (dialog),
656 GTK_WINDOW (toplevel));
658 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
660 const gchar *font = gtk_font_selection_dialog_get_font_name
661 (GTK_FONT_SELECTION_DIALOG (dialog));
663 PangoFontDescription* font_desc =
664 pango_font_description_from_string (font);
666 psppire_data_editor_set_font (de->data_editor, font_desc);
669 gtk_widget_hide (dialog);
674 /* Callback for the value labels action */
676 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
678 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
682 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
684 psppire_data_editor_split_window (de->data_editor,
685 gtk_toggle_action_get_active (ta));
690 file_quit (PsppireDataWindow *de)
692 /* FIXME: Need to be more intelligent here.
693 Give the user the opportunity to save any unsaved data.
699 on_recent_data_select (GtkMenuShell *menushell,
700 PsppireWindow *window)
705 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
707 file = g_filename_from_uri (uri, NULL, NULL);
711 open_data_window (window, file, NULL);
717 charset_from_mime_type (const char *mime_type)
723 if (mime_type == NULL)
726 charset = c_strcasestr (mime_type, "charset=");
734 /* Parse a "quoted-string" as defined by RFC 822. */
735 for (p++; *p != '\0' && *p != '"'; p++)
738 ds_put_byte (&s, *p);
739 else if (*++p != '\0')
740 ds_put_byte (&s, *p);
745 /* Parse a "token" as defined by RFC 2045. */
746 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
747 ds_put_byte (&s, *p++);
749 if (!ds_is_empty (&s))
750 return ds_steal_cstr (&s);
757 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
764 /* Get the file name and its encoding. */
765 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
766 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
767 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
768 gtk_recent_info_unref (item);
770 se = psppire_syntax_window_new (encoding);
774 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
775 gtk_widget_show (se);
777 gtk_widget_destroy (se);
783 set_unsaved (gpointer w)
785 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
789 on_switch_page (PsppireDataEditor *de, gpointer p,
790 gint pagenum, PsppireDataWindow *dw)
792 GtkWidget *page_menu_item;
796 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
798 ? "/ui/menubar/view/view_data"
799 : "/ui/menubar/view/view_variables");
800 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
801 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
805 on_ui_manager_changed (PsppireDataEditor *de,
806 GParamSpec *pspec UNUSED,
807 PsppireDataWindow *dw)
809 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
815 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
816 g_object_unref (dw->uim);
823 g_object_ref (dw->uim);
824 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
828 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
829 Returns a pointer to the action
832 connect_action (PsppireDataWindow *dw, const char *action_name,
835 GtkAction *action = get_action_assert (dw->builder, action_name);
837 g_signal_connect_swapped (action, "activate", handler, dw);
842 /* Only a data file with at least one variable can be saved. */
844 enable_save (PsppireDataWindow *dw)
846 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
848 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
850 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
854 /* Initializes as much of a PsppireDataWindow as we can and must before the
855 dataset has been set.
857 In particular, the 'menu' member is required in case the "filename" property
858 is set before the "dataset" property: otherwise PsppireWindow will try to
859 modify the menu as part of the "filename" property_set() function and end up
860 with a Gtk-CRITICAL since 'menu' is NULL. */
862 psppire_data_window_init (PsppireDataWindow *de)
864 de->builder = builder_new ("data-editor.ui");
866 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
868 PSPPIRE_WINDOW (de)->menu =
869 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
876 psppire_data_window_finish_init (PsppireDataWindow *de,
879 static const struct dataset_callbacks cbs =
881 set_unsaved, /* changed */
882 transformation_change_callback, /* transformations_changed */
889 GtkWidget *box = gtk_vbox_new (FALSE, 0);
892 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
893 de->data_store = psppire_data_store_new (de->dict);
894 psppire_data_store_set_reader (de->data_store, NULL);
896 menubar = get_widget_assert (de->builder, "menubar");
897 hb = get_widget_assert (de->builder, "handlebox1");
898 sb = get_widget_assert (de->builder, "status-bar");
904 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
905 g_signal_connect (de->data_editor, "switch-page",
906 G_CALLBACK (on_switch_page), de);
908 g_signal_connect_swapped (de->data_store, "case-changed",
909 G_CALLBACK (set_unsaved), de);
911 g_signal_connect_swapped (de->data_store, "case-inserted",
912 G_CALLBACK (set_unsaved), de);
914 g_signal_connect_swapped (de->data_store, "cases-deleted",
915 G_CALLBACK (set_unsaved), de);
917 dataset_set_callbacks (de->dataset, &cbs, de);
919 connect_help (de->builder);
921 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
922 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
923 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
924 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
926 gtk_container_add (GTK_CONTAINER (de), box);
928 g_signal_connect (de->dict, "weight-changed",
929 G_CALLBACK (on_weight_change),
932 g_signal_connect (de->dict, "filter-changed",
933 G_CALLBACK (on_filter_change),
936 g_signal_connect (de->dict, "split-changed",
937 G_CALLBACK (on_split_change),
940 g_signal_connect_swapped (de->dict, "backend-changed",
941 G_CALLBACK (enable_save), de);
942 g_signal_connect_swapped (de->dict, "variable-inserted",
943 G_CALLBACK (enable_save), de);
944 g_signal_connect_swapped (de->dict, "variable-deleted",
945 G_CALLBACK (enable_save), de);
948 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
949 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
950 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
951 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
952 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
953 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
954 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
955 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
957 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
959 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
960 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
961 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
962 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
963 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
964 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
965 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
966 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
967 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
968 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
969 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
970 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
971 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
972 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
973 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
976 GtkWidget *recent_data =
977 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
979 GtkWidget *recent_files =
980 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
983 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
984 gtk_recent_manager_get_default ());
986 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
987 gtk_recent_manager_get_default ());
989 g_object_set (menu_data, "show-tips", TRUE, NULL);
990 g_object_set (menu_files, "show-tips", TRUE, NULL);
993 GtkRecentFilter *filter = gtk_recent_filter_new ();
995 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
996 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
998 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1000 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1003 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1006 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1009 GtkRecentFilter *filter = gtk_recent_filter_new ();
1011 gtk_recent_filter_add_pattern (filter, "*.sps");
1012 gtk_recent_filter_add_pattern (filter, "*.SPS");
1014 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1016 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1019 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1021 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1025 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1028 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1029 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1031 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1033 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1035 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1037 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1039 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1041 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1043 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1045 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1047 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1049 merge_help_menu (de->ui_manager);
1051 g_signal_connect (de->data_editor, "notify::ui-manager",
1052 G_CALLBACK (on_ui_manager_changed), de);
1053 on_ui_manager_changed (de->data_editor, NULL, de);
1055 gtk_widget_show (GTK_WIDGET (de->data_editor));
1056 gtk_widget_show (box);
1058 ll_push_head (&all_data_windows, &de->ll);
1062 psppire_data_window_dispose (GObject *object)
1064 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1068 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1069 g_object_unref (dw->uim);
1073 if (dw->builder != NULL)
1075 g_object_unref (dw->builder);
1081 g_signal_handlers_disconnect_by_func (dw->dict,
1082 G_CALLBACK (enable_save), dw);
1083 g_signal_handlers_disconnect_by_func (dw->dict,
1084 G_CALLBACK (on_weight_change), dw);
1085 g_signal_handlers_disconnect_by_func (dw->dict,
1086 G_CALLBACK (on_filter_change), dw);
1087 g_signal_handlers_disconnect_by_func (dw->dict,
1088 G_CALLBACK (on_split_change), dw);
1090 g_object_unref (dw->dict);
1096 g_object_unref (dw->data_store);
1097 dw->data_store = NULL;
1100 if (dw->ll.next != NULL)
1102 ll_remove (&dw->ll);
1106 if (G_OBJECT_CLASS (parent_class)->dispose)
1107 G_OBJECT_CLASS (parent_class)->dispose (object);
1111 psppire_data_window_finalize (GObject *object)
1113 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1117 struct dataset *dataset = dw->dataset;
1118 struct session *session = dataset_session (dataset);
1122 dataset_set_callbacks (dataset, NULL, NULL);
1123 session_set_active_dataset (session, NULL);
1124 dataset_destroy (dataset);
1127 if (G_OBJECT_CLASS (parent_class)->finalize)
1128 G_OBJECT_CLASS (parent_class)->finalize (object);
1132 psppire_data_window_set_property (GObject *object,
1134 const GValue *value,
1137 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1142 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1145 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1151 psppire_data_window_get_property (GObject *object,
1156 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1161 g_value_set_pointer (value, window->dataset);
1164 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1170 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1176 ui_string = gtk_ui_manager_get_ui (uim);
1177 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1181 g_return_val_if_fail (merge_id != 0, 0);
1183 list = gtk_ui_manager_get_action_groups (uim);
1184 for (; list != NULL; list = list->next)
1186 GtkActionGroup *action_group = list->data;
1187 GList *actions = gtk_action_group_list_actions (action_group);
1190 for (action = actions; action != NULL; action = action->next)
1192 GtkAction *a = action->data;
1194 if (PSPPIRE_IS_DIALOG_ACTION (a))
1195 g_object_set (a, "manager", pdw->ui_manager, NULL);
1198 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1201 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1202 gtk_ui_manager_get_accel_group (uim));
1208 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1209 GtkUIManager *uim, guint merge_id)
1213 g_return_if_fail (merge_id != 0);
1215 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1217 list = gtk_ui_manager_get_action_groups (uim);
1218 for (; list != NULL; list = list->next)
1220 GtkActionGroup *action_group = list->data;
1221 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1224 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1225 gtk_ui_manager_get_accel_group (uim));
1229 psppire_data_window_new (struct dataset *ds)
1233 if (the_session == NULL)
1234 the_session = session_create (NULL);
1238 char *dataset_name = session_generate_dataset_name (the_session);
1239 ds = dataset_create (the_session, dataset_name);
1240 free (dataset_name);
1242 assert (dataset_session (ds) == the_session);
1246 psppire_data_window_get_type (),
1247 "description", _("Data Editor"),
1251 if (dataset_name (ds) != NULL)
1252 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1258 psppire_data_window_is_empty (PsppireDataWindow *dw)
1260 return psppire_dict_get_var_cnt (dw->dict) == 0;
1264 psppire_data_window_iface_init (PsppireWindowIface *iface)
1266 iface->save = save_file;
1267 iface->pick_filename = data_pick_filename;
1268 iface->load = load_file;
1272 psppire_default_data_window (void)
1274 if (ll_is_empty (&all_data_windows))
1275 create_data_window ();
1276 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1280 psppire_data_window_set_default (PsppireDataWindow *pdw)
1282 ll_remove (&pdw->ll);
1283 ll_push_head (&all_data_windows, &pdw->ll);
1287 psppire_data_window_undefault (PsppireDataWindow *pdw)
1289 ll_remove (&pdw->ll);
1290 ll_push_tail (&all_data_windows, &pdw->ll);
1294 psppire_data_window_for_dataset (struct dataset *ds)
1296 PsppireDataWindow *pdw;
1298 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1299 if (pdw->dataset == ds)
1306 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1308 PsppireDataWindow *pdw;
1310 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1311 if (pdw->data_store == data_store)
1318 create_data_window (void)
1320 gtk_widget_show (psppire_data_window_new (NULL));
1324 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1328 if (PSPPIRE_IS_DATA_WINDOW (victim)
1329 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1331 window = GTK_WIDGET (victim);
1332 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1335 window = psppire_data_window_new (NULL);
1337 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1338 gtk_widget_show_all (window);