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/entry-dialog.h"
32 #include "ui/gui/executor.h"
33 #include "ui/gui/help-menu.h"
34 #include "ui/gui/helper.h"
35 #include "ui/gui/helper.h"
36 #include "ui/gui/npar-two-sample-related.h"
37 #include "ui/gui/oneway-anova-dialog.h"
38 #include "ui/gui/psppire-data-window.h"
39 #include "ui/gui/psppire-dialog-action.h"
40 #include "ui/gui/psppire-syntax-window.h"
41 #include "ui/gui/psppire-window.h"
42 #include "ui/gui/psppire.h"
43 #include "ui/gui/recode-dialog.h"
44 #include "ui/gui/select-cases-dialog.h"
45 #include "ui/gui/split-file-dialog.h"
46 #include "ui/gui/t-test-paired-samples.h"
47 #include "ui/gui/text-data-import-dialog.h"
48 #include "ui/gui/weight-cases-dialog.h"
49 #include "ui/syntax-gen.h"
51 #include "gl/c-strcase.h"
52 #include "gl/c-strcasestr.h"
53 #include "gl/xvasprintf.h"
56 #define _(msgid) gettext (msgid)
57 #define N_(msgid) msgid
59 struct session *the_session;
60 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
62 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
63 static void psppire_data_window_init (PsppireDataWindow *data_editor);
66 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
68 static void psppire_data_window_dispose (GObject *object);
69 static void psppire_data_window_finalize (GObject *object);
70 static void psppire_data_window_set_property (GObject *object,
74 static void psppire_data_window_get_property (GObject *object,
79 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
80 static void psppire_data_window_remove_ui (PsppireDataWindow *,
81 GtkUIManager *, guint);
84 psppire_data_window_get_type (void)
86 static GType psppire_data_window_type = 0;
88 if (!psppire_data_window_type)
90 static const GTypeInfo psppire_data_window_info =
92 sizeof (PsppireDataWindowClass),
95 (GClassInitFunc)psppire_data_window_class_init,
96 (GClassFinalizeFunc) NULL,
98 sizeof (PsppireDataWindow),
100 (GInstanceInitFunc) psppire_data_window_init,
103 static const GInterfaceInfo window_interface_info =
105 (GInterfaceInitFunc) psppire_data_window_iface_init,
110 psppire_data_window_type =
111 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
112 &psppire_data_window_info, 0);
115 g_type_add_interface_static (psppire_data_window_type,
116 PSPPIRE_TYPE_WINDOW_MODEL,
117 &window_interface_info);
120 return psppire_data_window_type;
123 static GObjectClass *parent_class ;
130 psppire_data_window_class_init (PsppireDataWindowClass *class)
132 GObjectClass *object_class = G_OBJECT_CLASS (class);
134 parent_class = g_type_class_peek_parent (class);
136 object_class->dispose = psppire_data_window_dispose;
137 object_class->finalize = psppire_data_window_finalize;
138 object_class->set_property = psppire_data_window_set_property;
139 object_class->get_property = psppire_data_window_get_property;
141 g_object_class_install_property (
142 object_class, PROP_DATASET,
143 g_param_spec_pointer ("dataset", "Dataset",
144 "'struct datset *' represented by the window",
145 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
148 /* Run the EXECUTE command. */
150 execute (PsppireDataWindow *dw)
152 execute_const_syntax_string (dw, "EXECUTE.");
156 transformation_change_callback (bool transformations_pending,
159 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
161 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
163 GtkWidget *menuitem =
164 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
166 GtkWidget *status_label =
167 get_widget_assert (de->builder, "case-counter-area");
169 gtk_widget_set_sensitive (menuitem, transformations_pending);
172 if ( transformations_pending)
173 gtk_label_set_text (GTK_LABEL (status_label),
174 _("Transformations Pending"));
176 gtk_label_set_text (GTK_LABEL (status_label), "");
179 /* Callback for when the dictionary changes its filter variable */
181 on_filter_change (GObject *o, gint filter_index, gpointer data)
183 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
185 GtkWidget *filter_status_area =
186 get_widget_assert (de->builder, "filter-use-status-area");
188 if ( filter_index == -1 )
190 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
194 PsppireDict *dict = NULL;
195 struct variable *var ;
198 g_object_get (de->data_editor, "dictionary", &dict, NULL);
200 var = psppire_dict_get_variable (dict, filter_index);
202 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
204 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
210 /* Callback for when the dictionary changes its split variables */
212 on_split_change (PsppireDict *dict, gpointer data)
214 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
216 size_t n_split_vars = dict_get_split_cnt (dict->dict);
218 GtkWidget *split_status_area =
219 get_widget_assert (de->builder, "split-file-status-area");
221 if ( n_split_vars == 0 )
223 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
229 const struct variable *const * split_vars =
230 dict_get_split_vars (dict->dict);
232 text = g_string_new (_("Split by "));
234 for (i = 0 ; i < n_split_vars - 1; ++i )
236 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
238 g_string_append (text, var_get_name (split_vars[i]));
240 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
242 g_string_free (text, TRUE);
249 /* Callback for when the dictionary changes its weights */
251 on_weight_change (GObject *o, gint weight_index, gpointer data)
253 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
255 GtkWidget *weight_status_area =
256 get_widget_assert (de->builder, "weight-status-area");
258 if ( weight_index == -1 )
260 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
264 struct variable *var ;
265 PsppireDict *dict = NULL;
268 g_object_get (de->data_editor, "dictionary", &dict, NULL);
270 var = psppire_dict_get_variable (dict, weight_index);
272 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
274 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
282 dump_rm (GtkRecentManager *rm)
284 GList *items = gtk_recent_manager_get_items (rm);
288 g_print ("Recent Items:\n");
289 for (i = items; i; i = i->next)
291 GtkRecentInfo *ri = i->data;
293 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
294 gtk_recent_info_get_short_name (ri),
295 gtk_recent_info_get_mime_type (ri),
296 gtk_recent_info_get_description (ri),
297 gtk_recent_info_get_uri (ri)
301 gtk_recent_info_unref (ri);
309 name_has_por_suffix (const gchar *name)
311 size_t length = strlen (name);
312 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
316 name_has_sav_suffix (const gchar *name)
318 size_t length = strlen (name);
319 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
322 /* Returns true if NAME has a suffix which might denote a PSPP file */
324 name_has_suffix (const gchar *name)
326 return name_has_por_suffix (name) || name_has_sav_suffix (name);
330 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
332 const char *mime_type = NULL;
333 gchar *syntax = NULL;
338 gchar *utf8_file_name;
339 struct string filename;
340 ds_init_empty (&filename);
342 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
344 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
346 g_free (utf8_file_name);
348 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
349 ds_destroy (&filename);
357 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
358 lex_reader_for_string (syntax));
361 if (ok && syn == NULL)
363 if (name_has_por_suffix (file_name))
364 mime_type = "application/x-spss-por";
365 else if (name_has_sav_suffix (file_name))
366 mime_type = "application/x-spss-sav";
368 add_most_recent (file_name, mime_type);
374 /* Save DE to file */
376 save_file (PsppireWindow *w)
378 const gchar *file_name = NULL;
379 gchar *utf8_file_name = NULL;
381 struct string filename ;
382 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
385 file_name = psppire_window_get_filename (w);
387 fnx = g_string_new (file_name);
389 if ( ! name_has_suffix (fnx->str))
391 if ( de->save_as_portable)
392 g_string_append (fnx, ".por");
394 g_string_append (fnx, ".sav");
397 ds_init_empty (&filename);
399 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
401 g_string_free (fnx, TRUE);
403 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
404 g_free (utf8_file_name);
406 syntax = g_strdup_printf ("%s OUTFILE=%s.",
407 de->save_as_portable ? "EXPORT" : "SAVE",
408 ds_cstr (&filename));
410 ds_destroy (&filename);
412 g_free (execute_syntax_string (de, syntax));
417 display_dict (PsppireDataWindow *de)
419 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
423 sysfile_info (PsppireDataWindow *de)
425 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
427 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
429 struct string filename;
431 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
433 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
438 ds_init_empty (&filename);
440 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
442 g_free (utf8_file_name);
444 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
445 g_free (execute_syntax_string (de, syntax));
448 gtk_widget_destroy (dialog);
452 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
454 data_pick_filename (PsppireWindow *window)
456 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
457 GtkFileFilter *filter = gtk_file_filter_new ();
458 GtkWidget *button_sys;
460 gtk_file_chooser_dialog_new (_("Save"),
462 GTK_FILE_CHOOSER_ACTION_SAVE,
463 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
464 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
467 g_object_set (dialog, "local-only", FALSE, NULL);
469 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
470 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
471 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
473 filter = gtk_file_filter_new ();
474 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
475 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
476 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
478 filter = gtk_file_filter_new ();
479 gtk_file_filter_set_name (filter, _("All Files"));
480 gtk_file_filter_add_pattern (filter, "*");
481 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
484 GtkWidget *button_por;
485 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
487 gtk_radio_button_new_with_label (NULL, _("System File"));
490 gtk_radio_button_new_with_label
491 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
494 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
495 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
497 gtk_widget_show_all (vbox);
499 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
502 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
505 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
507 case GTK_RESPONSE_ACCEPT:
512 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
515 de->save_as_portable =
516 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
518 if ( ! name_has_suffix (filename->str))
520 if ( de->save_as_portable)
521 g_string_append (filename, ".por");
523 g_string_append (filename, ".sav");
526 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
528 g_string_free (filename, TRUE);
535 gtk_widget_destroy (dialog);
539 confirm_delete_dataset (PsppireDataWindow *de,
540 const char *old_dataset,
541 const char *new_dataset,
542 const char *existing_dataset)
547 dialog = gtk_message_dialog_new (
548 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
549 _("Delete Existing Dataset?"));
551 gtk_message_dialog_format_secondary_text (
552 GTK_MESSAGE_DIALOG (dialog),
553 _("Renaming \"%s\" to \"%s\" will destroy the existing "
554 "dataset named \"%s\". Are you sure that you want to do this?"),
555 old_dataset, new_dataset, existing_dataset);
557 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
558 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
559 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
562 g_object_set (dialog, "icon-name", "pspp", NULL);
564 result = gtk_dialog_run (GTK_DIALOG (dialog));
566 gtk_widget_destroy (dialog);
568 return result == GTK_RESPONSE_OK;
572 on_rename_dataset (PsppireDataWindow *de)
574 struct dataset *ds = de->dataset;
575 struct session *session = dataset_session (ds);
576 const char *old_name = dataset_name (ds);
577 struct dataset *existing_dataset;
581 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
583 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
587 if (new_name == NULL)
590 existing_dataset = session_lookup_dataset (session, new_name);
591 if (existing_dataset == NULL || existing_dataset == ds
592 || confirm_delete_dataset (de, old_name, new_name,
593 dataset_name (existing_dataset)))
594 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
601 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
603 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
605 if ( gtk_toggle_action_get_active (action))
606 gtk_widget_show (statusbar);
608 gtk_widget_hide (statusbar);
613 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
615 const gboolean grid_visible = gtk_toggle_action_get_active (action);
617 psppire_data_editor_show_grid (de->data_editor, grid_visible);
621 data_view_activate (PsppireDataWindow *de)
623 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
628 variable_view_activate (PsppireDataWindow *de)
630 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
635 fonts_activate (PsppireDataWindow *de)
637 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
638 PangoFontDescription *current_font;
641 gtk_font_selection_dialog_new (_("Font Selection"));
644 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
645 font_name = pango_font_description_to_string (current_font);
647 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
651 gtk_window_set_transient_for (GTK_WINDOW (dialog),
652 GTK_WINDOW (toplevel));
654 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
656 const gchar *font = gtk_font_selection_dialog_get_font_name
657 (GTK_FONT_SELECTION_DIALOG (dialog));
659 PangoFontDescription* font_desc =
660 pango_font_description_from_string (font);
662 psppire_data_editor_set_font (de->data_editor, font_desc);
665 gtk_widget_hide (dialog);
670 /* Callback for the value labels action */
672 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
674 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
678 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
680 psppire_data_editor_split_window (de->data_editor,
681 gtk_toggle_action_get_active (ta));
686 file_quit (PsppireDataWindow *de)
688 /* FIXME: Need to be more intelligent here.
689 Give the user the opportunity to save any unsaved data.
695 on_recent_data_select (GtkMenuShell *menushell,
696 PsppireWindow *window)
701 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
703 file = g_filename_from_uri (uri, NULL, NULL);
707 open_data_window (window, file, NULL);
713 charset_from_mime_type (const char *mime_type)
719 if (mime_type == NULL)
722 charset = c_strcasestr (mime_type, "charset=");
730 /* Parse a "quoted-string" as defined by RFC 822. */
731 for (p++; *p != '\0' && *p != '"'; p++)
734 ds_put_byte (&s, *p);
735 else if (*++p != '\0')
736 ds_put_byte (&s, *p);
741 /* Parse a "token" as defined by RFC 2045. */
742 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
743 ds_put_byte (&s, *p++);
745 if (!ds_is_empty (&s))
746 return ds_steal_cstr (&s);
753 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
760 /* Get the file name and its encoding. */
761 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
762 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
763 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
764 gtk_recent_info_unref (item);
766 se = psppire_syntax_window_new (encoding);
770 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
771 gtk_widget_show (se);
773 gtk_widget_destroy (se);
779 set_unsaved (gpointer w)
781 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
785 on_switch_page (PsppireDataEditor *de, gpointer p,
786 gint pagenum, PsppireDataWindow *dw)
788 GtkWidget *page_menu_item;
792 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
794 ? "/ui/menubar/view/view_data"
795 : "/ui/menubar/view/view_variables");
796 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
797 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
801 on_ui_manager_changed (PsppireDataEditor *de,
802 GParamSpec *pspec UNUSED,
803 PsppireDataWindow *dw)
805 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
811 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
812 g_object_unref (dw->uim);
819 g_object_ref (dw->uim);
820 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
824 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
825 Returns a pointer to the action
828 connect_action (PsppireDataWindow *dw, const char *action_name,
831 GtkAction *action = get_action_assert (dw->builder, action_name);
833 g_signal_connect_swapped (action, "activate", handler, dw);
838 /* Only a data file with at least one variable can be saved. */
840 enable_save (PsppireDataWindow *dw)
842 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
844 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
846 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
850 /* Initializes as much of a PsppireDataWindow as we can and must before the
851 dataset has been set.
853 In particular, the 'menu' member is required in case the "filename" property
854 is set before the "dataset" property: otherwise PsppireWindow will try to
855 modify the menu as part of the "filename" property_set() function and end up
856 with a Gtk-CRITICAL since 'menu' is NULL. */
858 psppire_data_window_init (PsppireDataWindow *de)
860 de->builder = builder_new ("data-editor.ui");
862 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
864 PSPPIRE_WINDOW (de)->menu =
865 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
872 psppire_data_window_finish_init (PsppireDataWindow *de,
875 static const struct dataset_callbacks cbs =
877 set_unsaved, /* changed */
878 transformation_change_callback, /* transformations_changed */
885 GtkWidget *box = gtk_vbox_new (FALSE, 0);
888 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
889 de->data_store = psppire_data_store_new (de->dict);
890 psppire_data_store_set_reader (de->data_store, NULL);
892 menubar = get_widget_assert (de->builder, "menubar");
893 hb = get_widget_assert (de->builder, "handlebox1");
894 sb = get_widget_assert (de->builder, "status-bar");
900 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
901 g_signal_connect (de->data_editor, "switch-page",
902 G_CALLBACK (on_switch_page), de);
904 g_signal_connect_swapped (de->data_store, "case-changed",
905 G_CALLBACK (set_unsaved), de);
907 g_signal_connect_swapped (de->data_store, "case-inserted",
908 G_CALLBACK (set_unsaved), de);
910 g_signal_connect_swapped (de->data_store, "cases-deleted",
911 G_CALLBACK (set_unsaved), de);
913 dataset_set_callbacks (de->dataset, &cbs, de);
915 connect_help (de->builder);
917 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
918 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
919 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
920 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
922 gtk_container_add (GTK_CONTAINER (de), box);
924 g_signal_connect (de->dict, "weight-changed",
925 G_CALLBACK (on_weight_change),
928 g_signal_connect (de->dict, "filter-changed",
929 G_CALLBACK (on_filter_change),
932 g_signal_connect (de->dict, "split-changed",
933 G_CALLBACK (on_split_change),
936 g_signal_connect_swapped (de->dict, "backend-changed",
937 G_CALLBACK (enable_save), de);
938 g_signal_connect_swapped (de->dict, "variable-inserted",
939 G_CALLBACK (enable_save), de);
940 g_signal_connect_swapped (de->dict, "variable-deleted",
941 G_CALLBACK (enable_save), de);
944 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
945 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
946 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
947 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
948 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
949 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
950 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
951 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
953 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
955 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
956 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
957 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
958 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
959 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
960 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
961 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
962 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
963 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
964 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
965 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
968 GtkWidget *recent_data =
969 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
971 GtkWidget *recent_files =
972 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
975 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
976 gtk_recent_manager_get_default ());
978 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
979 gtk_recent_manager_get_default ());
981 g_object_set (menu_data, "show-tips", TRUE, NULL);
982 g_object_set (menu_files, "show-tips", TRUE, NULL);
985 GtkRecentFilter *filter = gtk_recent_filter_new ();
987 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
988 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
990 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
992 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
995 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
998 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1001 GtkRecentFilter *filter = gtk_recent_filter_new ();
1003 gtk_recent_filter_add_pattern (filter, "*.sps");
1004 gtk_recent_filter_add_pattern (filter, "*.SPS");
1006 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1008 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1011 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1013 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1017 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1020 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1021 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1023 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1025 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1027 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1029 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1031 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1033 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1035 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1037 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1039 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1041 merge_help_menu (de->ui_manager);
1043 g_signal_connect (de->data_editor, "notify::ui-manager",
1044 G_CALLBACK (on_ui_manager_changed), de);
1045 on_ui_manager_changed (de->data_editor, NULL, de);
1047 gtk_widget_show (GTK_WIDGET (de->data_editor));
1048 gtk_widget_show (box);
1050 ll_push_head (&all_data_windows, &de->ll);
1054 psppire_data_window_dispose (GObject *object)
1056 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1060 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1061 g_object_unref (dw->uim);
1065 if (dw->builder != NULL)
1067 g_object_unref (dw->builder);
1073 g_signal_handlers_disconnect_by_func (dw->dict,
1074 G_CALLBACK (enable_save), dw);
1075 g_signal_handlers_disconnect_by_func (dw->dict,
1076 G_CALLBACK (on_weight_change), dw);
1077 g_signal_handlers_disconnect_by_func (dw->dict,
1078 G_CALLBACK (on_filter_change), dw);
1079 g_signal_handlers_disconnect_by_func (dw->dict,
1080 G_CALLBACK (on_split_change), dw);
1082 g_object_unref (dw->dict);
1088 g_object_unref (dw->data_store);
1089 dw->data_store = NULL;
1092 if (dw->ll.next != NULL)
1094 ll_remove (&dw->ll);
1098 if (G_OBJECT_CLASS (parent_class)->dispose)
1099 G_OBJECT_CLASS (parent_class)->dispose (object);
1103 psppire_data_window_finalize (GObject *object)
1105 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1109 struct dataset *dataset = dw->dataset;
1110 struct session *session = dataset_session (dataset);
1114 dataset_set_callbacks (dataset, NULL, NULL);
1115 session_set_active_dataset (session, NULL);
1116 dataset_destroy (dataset);
1119 if (G_OBJECT_CLASS (parent_class)->finalize)
1120 G_OBJECT_CLASS (parent_class)->finalize (object);
1124 psppire_data_window_set_property (GObject *object,
1126 const GValue *value,
1129 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1134 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1137 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1143 psppire_data_window_get_property (GObject *object,
1148 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1153 g_value_set_pointer (value, window->dataset);
1156 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1162 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1168 ui_string = gtk_ui_manager_get_ui (uim);
1169 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1173 g_return_val_if_fail (merge_id != 0, 0);
1175 list = gtk_ui_manager_get_action_groups (uim);
1176 for (; list != NULL; list = list->next)
1178 GtkActionGroup *action_group = list->data;
1179 GList *actions = gtk_action_group_list_actions (action_group);
1182 for (action = actions; action != NULL; action = action->next)
1184 GtkAction *a = action->data;
1186 if (PSPPIRE_IS_DIALOG_ACTION (a))
1187 g_object_set (a, "manager", pdw->ui_manager, NULL);
1190 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1193 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1194 gtk_ui_manager_get_accel_group (uim));
1200 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1201 GtkUIManager *uim, guint merge_id)
1205 g_return_if_fail (merge_id != 0);
1207 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1209 list = gtk_ui_manager_get_action_groups (uim);
1210 for (; list != NULL; list = list->next)
1212 GtkActionGroup *action_group = list->data;
1213 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1216 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1217 gtk_ui_manager_get_accel_group (uim));
1221 psppire_data_window_new (struct dataset *ds)
1225 if (the_session == NULL)
1226 the_session = session_create (NULL);
1230 char *dataset_name = session_generate_dataset_name (the_session);
1231 ds = dataset_create (the_session, dataset_name);
1232 free (dataset_name);
1234 assert (dataset_session (ds) == the_session);
1238 psppire_data_window_get_type (),
1239 "description", _("Data Editor"),
1243 if (dataset_name (ds) != NULL)
1244 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1250 psppire_data_window_is_empty (PsppireDataWindow *dw)
1252 return psppire_dict_get_var_cnt (dw->dict) == 0;
1256 psppire_data_window_iface_init (PsppireWindowIface *iface)
1258 iface->save = save_file;
1259 iface->pick_filename = data_pick_filename;
1260 iface->load = load_file;
1264 psppire_default_data_window (void)
1266 if (ll_is_empty (&all_data_windows))
1267 create_data_window ();
1268 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1272 psppire_data_window_set_default (PsppireDataWindow *pdw)
1274 ll_remove (&pdw->ll);
1275 ll_push_head (&all_data_windows, &pdw->ll);
1279 psppire_data_window_undefault (PsppireDataWindow *pdw)
1281 ll_remove (&pdw->ll);
1282 ll_push_tail (&all_data_windows, &pdw->ll);
1286 psppire_data_window_for_dataset (struct dataset *ds)
1288 PsppireDataWindow *pdw;
1290 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1291 if (pdw->dataset == ds)
1298 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1300 PsppireDataWindow *pdw;
1302 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1303 if (pdw->data_store == data_store)
1310 create_data_window (void)
1312 gtk_widget_show (psppire_data_window_new (NULL));
1316 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1320 if (PSPPIRE_IS_DATA_WINDOW (victim)
1321 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1323 window = GTK_WIDGET (victim);
1324 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1327 window = psppire_data_window_new (NULL);
1329 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1330 gtk_widget_show_all (window);