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/npar-two-sample-related.h"
39 #include "ui/gui/oneway-anova-dialog.h"
40 #include "ui/gui/psppire-data-window.h"
41 #include "ui/gui/psppire-dialog-action.h"
42 #include "ui/gui/psppire-syntax-window.h"
43 #include "ui/gui/psppire-window.h"
44 #include "ui/gui/psppire.h"
45 #include "ui/gui/recode-dialog.h"
46 #include "ui/gui/select-cases-dialog.h"
47 #include "ui/gui/split-file-dialog.h"
48 #include "ui/gui/t-test-paired-samples.h"
49 #include "ui/gui/text-data-import-dialog.h"
50 #include "ui/gui/weight-cases-dialog.h"
51 #include "ui/syntax-gen.h"
53 #include "gl/c-strcase.h"
54 #include "gl/c-strcasestr.h"
55 #include "gl/xvasprintf.h"
58 #define _(msgid) gettext (msgid)
59 #define N_(msgid) msgid
61 struct session *the_session;
62 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
64 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
65 static void psppire_data_window_init (PsppireDataWindow *data_editor);
68 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
70 static void psppire_data_window_dispose (GObject *object);
71 static void psppire_data_window_finalize (GObject *object);
72 static void psppire_data_window_set_property (GObject *object,
76 static void psppire_data_window_get_property (GObject *object,
81 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
82 static void psppire_data_window_remove_ui (PsppireDataWindow *,
83 GtkUIManager *, guint);
86 psppire_data_window_get_type (void)
88 static GType psppire_data_window_type = 0;
90 if (!psppire_data_window_type)
92 static const GTypeInfo psppire_data_window_info =
94 sizeof (PsppireDataWindowClass),
97 (GClassInitFunc)psppire_data_window_class_init,
98 (GClassFinalizeFunc) NULL,
100 sizeof (PsppireDataWindow),
102 (GInstanceInitFunc) psppire_data_window_init,
105 static const GInterfaceInfo window_interface_info =
107 (GInterfaceInitFunc) psppire_data_window_iface_init,
112 psppire_data_window_type =
113 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
114 &psppire_data_window_info, 0);
117 g_type_add_interface_static (psppire_data_window_type,
118 PSPPIRE_TYPE_WINDOW_MODEL,
119 &window_interface_info);
122 return psppire_data_window_type;
125 static GObjectClass *parent_class ;
132 psppire_data_window_class_init (PsppireDataWindowClass *class)
134 GObjectClass *object_class = G_OBJECT_CLASS (class);
136 parent_class = g_type_class_peek_parent (class);
138 object_class->dispose = psppire_data_window_dispose;
139 object_class->finalize = psppire_data_window_finalize;
140 object_class->set_property = psppire_data_window_set_property;
141 object_class->get_property = psppire_data_window_get_property;
143 g_object_class_install_property (
144 object_class, PROP_DATASET,
145 g_param_spec_pointer ("dataset", "Dataset",
146 "'struct datset *' represented by the window",
147 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
150 /* Run the EXECUTE command. */
152 execute (PsppireDataWindow *dw)
154 execute_const_syntax_string (dw, "EXECUTE.");
158 transformation_change_callback (bool transformations_pending,
161 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
163 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
165 GtkWidget *menuitem =
166 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
168 GtkWidget *status_label =
169 get_widget_assert (de->builder, "case-counter-area");
171 gtk_widget_set_sensitive (menuitem, transformations_pending);
174 if ( transformations_pending)
175 gtk_label_set_text (GTK_LABEL (status_label),
176 _("Transformations Pending"));
178 gtk_label_set_text (GTK_LABEL (status_label), "");
181 /* Callback for when the dictionary changes its filter variable */
183 on_filter_change (GObject *o, gint filter_index, gpointer data)
185 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
187 GtkWidget *filter_status_area =
188 get_widget_assert (de->builder, "filter-use-status-area");
190 if ( filter_index == -1 )
192 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
196 PsppireDict *dict = NULL;
197 struct variable *var ;
200 g_object_get (de->data_editor, "dictionary", &dict, NULL);
202 var = psppire_dict_get_variable (dict, filter_index);
204 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
206 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
212 /* Callback for when the dictionary changes its split variables */
214 on_split_change (PsppireDict *dict, gpointer data)
216 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
218 size_t n_split_vars = dict_get_split_cnt (dict->dict);
220 GtkWidget *split_status_area =
221 get_widget_assert (de->builder, "split-file-status-area");
223 if ( n_split_vars == 0 )
225 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
231 const struct variable *const * split_vars =
232 dict_get_split_vars (dict->dict);
234 text = g_string_new (_("Split by "));
236 for (i = 0 ; i < n_split_vars - 1; ++i )
238 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
240 g_string_append (text, var_get_name (split_vars[i]));
242 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
244 g_string_free (text, TRUE);
251 /* Callback for when the dictionary changes its weights */
253 on_weight_change (GObject *o, gint weight_index, gpointer data)
255 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
257 GtkWidget *weight_status_area =
258 get_widget_assert (de->builder, "weight-status-area");
260 if ( weight_index == -1 )
262 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
266 struct variable *var ;
267 PsppireDict *dict = NULL;
270 g_object_get (de->data_editor, "dictionary", &dict, NULL);
272 var = psppire_dict_get_variable (dict, weight_index);
274 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
276 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
284 dump_rm (GtkRecentManager *rm)
286 GList *items = gtk_recent_manager_get_items (rm);
290 g_print ("Recent Items:\n");
291 for (i = items; i; i = i->next)
293 GtkRecentInfo *ri = i->data;
295 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
296 gtk_recent_info_get_short_name (ri),
297 gtk_recent_info_get_mime_type (ri),
298 gtk_recent_info_get_description (ri),
299 gtk_recent_info_get_uri (ri)
303 gtk_recent_info_unref (ri);
311 name_has_por_suffix (const gchar *name)
313 size_t length = strlen (name);
314 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
318 name_has_sav_suffix (const gchar *name)
320 size_t length = strlen (name);
321 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
324 /* Returns true if NAME has a suffix which might denote a PSPP file */
326 name_has_suffix (const gchar *name)
328 return name_has_por_suffix (name) || name_has_sav_suffix (name);
332 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
334 const char *mime_type = NULL;
335 gchar *syntax = NULL;
340 gchar *utf8_file_name;
341 struct string filename;
342 ds_init_empty (&filename);
344 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
346 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
348 g_free (utf8_file_name);
350 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
351 ds_destroy (&filename);
359 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
360 lex_reader_for_string (syntax));
363 if (ok && syn == NULL)
365 if (name_has_por_suffix (file_name))
366 mime_type = "application/x-spss-por";
367 else if (name_has_sav_suffix (file_name))
368 mime_type = "application/x-spss-sav";
370 add_most_recent (file_name, mime_type);
376 /* Save DE to file */
378 save_file (PsppireWindow *w)
380 const gchar *file_name = NULL;
381 gchar *utf8_file_name = NULL;
383 struct string filename ;
384 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
387 file_name = psppire_window_get_filename (w);
389 fnx = g_string_new (file_name);
391 if ( ! name_has_suffix (fnx->str))
393 if ( de->save_as_portable)
394 g_string_append (fnx, ".por");
396 g_string_append (fnx, ".sav");
399 ds_init_empty (&filename);
401 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
403 g_string_free (fnx, TRUE);
405 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
406 g_free (utf8_file_name);
408 syntax = g_strdup_printf ("%s OUTFILE=%s.",
409 de->save_as_portable ? "EXPORT" : "SAVE",
410 ds_cstr (&filename));
412 ds_destroy (&filename);
414 g_free (execute_syntax_string (de, syntax));
419 display_dict (PsppireDataWindow *de)
421 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
425 sysfile_info (PsppireDataWindow *de)
427 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
429 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
431 struct string filename;
433 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
435 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
440 ds_init_empty (&filename);
442 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
444 g_free (utf8_file_name);
446 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
447 g_free (execute_syntax_string (de, syntax));
450 gtk_widget_destroy (dialog);
454 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
456 data_pick_filename (PsppireWindow *window)
458 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
459 GtkFileFilter *filter = gtk_file_filter_new ();
460 GtkWidget *button_sys;
462 gtk_file_chooser_dialog_new (_("Save"),
464 GTK_FILE_CHOOSER_ACTION_SAVE,
465 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
466 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
469 g_object_set (dialog, "local-only", FALSE, NULL);
471 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
472 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
473 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
475 filter = gtk_file_filter_new ();
476 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
477 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
478 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
480 filter = gtk_file_filter_new ();
481 gtk_file_filter_set_name (filter, _("All Files"));
482 gtk_file_filter_add_pattern (filter, "*");
483 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
486 GtkWidget *button_por;
487 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
489 gtk_radio_button_new_with_label (NULL, _("System File"));
492 gtk_radio_button_new_with_label
493 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
496 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
497 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
499 gtk_widget_show_all (vbox);
501 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
504 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
507 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
509 case GTK_RESPONSE_ACCEPT:
514 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
517 de->save_as_portable =
518 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
520 if ( ! name_has_suffix (filename->str))
522 if ( de->save_as_portable)
523 g_string_append (filename, ".por");
525 g_string_append (filename, ".sav");
528 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
530 g_string_free (filename, TRUE);
537 gtk_widget_destroy (dialog);
541 confirm_delete_dataset (PsppireDataWindow *de,
542 const char *old_dataset,
543 const char *new_dataset,
544 const char *existing_dataset)
549 dialog = gtk_message_dialog_new (
550 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
551 _("Delete Existing Dataset?"));
553 gtk_message_dialog_format_secondary_text (
554 GTK_MESSAGE_DIALOG (dialog),
555 _("Renaming \"%s\" to \"%s\" will destroy the existing "
556 "dataset named \"%s\". Are you sure that you want to do this?"),
557 old_dataset, new_dataset, existing_dataset);
559 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
560 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
561 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
564 g_object_set (dialog, "icon-name", "pspp", NULL);
566 result = gtk_dialog_run (GTK_DIALOG (dialog));
568 gtk_widget_destroy (dialog);
570 return result == GTK_RESPONSE_OK;
574 on_rename_dataset (PsppireDataWindow *de)
576 struct dataset *ds = de->dataset;
577 struct session *session = dataset_session (ds);
578 const char *old_name = dataset_name (ds);
579 struct dataset *existing_dataset;
583 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
585 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
589 if (new_name == NULL)
592 existing_dataset = session_lookup_dataset (session, new_name);
593 if (existing_dataset == NULL || existing_dataset == ds
594 || confirm_delete_dataset (de, old_name, new_name,
595 dataset_name (existing_dataset)))
596 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
603 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
605 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
607 if ( gtk_toggle_action_get_active (action))
608 gtk_widget_show (statusbar);
610 gtk_widget_hide (statusbar);
615 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
617 const gboolean grid_visible = gtk_toggle_action_get_active (action);
619 psppire_data_editor_show_grid (de->data_editor, grid_visible);
623 data_view_activate (PsppireDataWindow *de)
625 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
630 variable_view_activate (PsppireDataWindow *de)
632 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
637 fonts_activate (PsppireDataWindow *de)
639 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
640 PangoFontDescription *current_font;
643 gtk_font_selection_dialog_new (_("Font Selection"));
646 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
647 font_name = pango_font_description_to_string (current_font);
649 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
653 gtk_window_set_transient_for (GTK_WINDOW (dialog),
654 GTK_WINDOW (toplevel));
656 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
658 const gchar *font = gtk_font_selection_dialog_get_font_name
659 (GTK_FONT_SELECTION_DIALOG (dialog));
661 PangoFontDescription* font_desc =
662 pango_font_description_from_string (font);
664 psppire_data_editor_set_font (de->data_editor, font_desc);
667 gtk_widget_hide (dialog);
672 /* Callback for the value labels action */
674 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
676 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
680 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
682 psppire_data_editor_split_window (de->data_editor,
683 gtk_toggle_action_get_active (ta));
688 file_quit (PsppireDataWindow *de)
690 /* FIXME: Need to be more intelligent here.
691 Give the user the opportunity to save any unsaved data.
697 on_recent_data_select (GtkMenuShell *menushell,
698 PsppireWindow *window)
703 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
705 file = g_filename_from_uri (uri, NULL, NULL);
709 open_data_window (window, file, NULL);
715 charset_from_mime_type (const char *mime_type)
721 if (mime_type == NULL)
724 charset = c_strcasestr (mime_type, "charset=");
732 /* Parse a "quoted-string" as defined by RFC 822. */
733 for (p++; *p != '\0' && *p != '"'; p++)
736 ds_put_byte (&s, *p);
737 else if (*++p != '\0')
738 ds_put_byte (&s, *p);
743 /* Parse a "token" as defined by RFC 2045. */
744 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
745 ds_put_byte (&s, *p++);
747 if (!ds_is_empty (&s))
748 return ds_steal_cstr (&s);
755 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
762 /* Get the file name and its encoding. */
763 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
764 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
765 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
766 gtk_recent_info_unref (item);
768 se = psppire_syntax_window_new (encoding);
772 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
773 gtk_widget_show (se);
775 gtk_widget_destroy (se);
781 set_unsaved (gpointer w)
783 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
787 on_switch_page (PsppireDataEditor *de, gpointer p,
788 gint pagenum, PsppireDataWindow *dw)
790 GtkWidget *page_menu_item;
794 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
796 ? "/ui/menubar/view/view_data"
797 : "/ui/menubar/view/view_variables");
798 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
799 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
803 on_ui_manager_changed (PsppireDataEditor *de,
804 GParamSpec *pspec UNUSED,
805 PsppireDataWindow *dw)
807 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
813 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
814 g_object_unref (dw->uim);
821 g_object_ref (dw->uim);
822 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
826 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
827 Returns a pointer to the action
830 connect_action (PsppireDataWindow *dw, const char *action_name,
833 GtkAction *action = get_action_assert (dw->builder, action_name);
835 g_signal_connect_swapped (action, "activate", handler, dw);
840 /* Only a data file with at least one variable can be saved. */
842 enable_save (PsppireDataWindow *dw)
844 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
846 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
848 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
852 /* Initializes as much of a PsppireDataWindow as we can and must before the
853 dataset has been set.
855 In particular, the 'menu' member is required in case the "filename" property
856 is set before the "dataset" property: otherwise PsppireWindow will try to
857 modify the menu as part of the "filename" property_set() function and end up
858 with a Gtk-CRITICAL since 'menu' is NULL. */
860 psppire_data_window_init (PsppireDataWindow *de)
862 de->builder = builder_new ("data-editor.ui");
864 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
866 PSPPIRE_WINDOW (de)->menu =
867 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
874 psppire_data_window_finish_init (PsppireDataWindow *de,
877 static const struct dataset_callbacks cbs =
879 set_unsaved, /* changed */
880 transformation_change_callback, /* transformations_changed */
887 GtkWidget *box = gtk_vbox_new (FALSE, 0);
890 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
891 de->data_store = psppire_data_store_new (de->dict);
892 psppire_data_store_set_reader (de->data_store, NULL);
894 menubar = get_widget_assert (de->builder, "menubar");
895 hb = get_widget_assert (de->builder, "handlebox1");
896 sb = get_widget_assert (de->builder, "status-bar");
902 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
903 g_signal_connect (de->data_editor, "switch-page",
904 G_CALLBACK (on_switch_page), de);
906 g_signal_connect_swapped (de->data_store, "case-changed",
907 G_CALLBACK (set_unsaved), de);
909 g_signal_connect_swapped (de->data_store, "case-inserted",
910 G_CALLBACK (set_unsaved), de);
912 g_signal_connect_swapped (de->data_store, "cases-deleted",
913 G_CALLBACK (set_unsaved), de);
915 dataset_set_callbacks (de->dataset, &cbs, de);
917 connect_help (de->builder);
919 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
920 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
921 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
922 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
924 gtk_container_add (GTK_CONTAINER (de), box);
926 g_signal_connect (de->dict, "weight-changed",
927 G_CALLBACK (on_weight_change),
930 g_signal_connect (de->dict, "filter-changed",
931 G_CALLBACK (on_filter_change),
934 g_signal_connect (de->dict, "split-changed",
935 G_CALLBACK (on_split_change),
938 g_signal_connect_swapped (de->dict, "backend-changed",
939 G_CALLBACK (enable_save), de);
940 g_signal_connect_swapped (de->dict, "variable-inserted",
941 G_CALLBACK (enable_save), de);
942 g_signal_connect_swapped (de->dict, "variable-deleted",
943 G_CALLBACK (enable_save), de);
946 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
947 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
948 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
949 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
950 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
951 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
952 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
953 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
955 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
957 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
958 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
959 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
960 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
961 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
962 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
963 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
964 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
965 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
966 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
967 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
968 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
969 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
972 GtkWidget *recent_data =
973 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
975 GtkWidget *recent_files =
976 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
979 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
980 gtk_recent_manager_get_default ());
982 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
983 gtk_recent_manager_get_default ());
985 g_object_set (menu_data, "show-tips", TRUE, NULL);
986 g_object_set (menu_files, "show-tips", TRUE, NULL);
989 GtkRecentFilter *filter = gtk_recent_filter_new ();
991 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
992 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
994 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
996 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
999 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1002 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1005 GtkRecentFilter *filter = gtk_recent_filter_new ();
1007 gtk_recent_filter_add_pattern (filter, "*.sps");
1008 gtk_recent_filter_add_pattern (filter, "*.SPS");
1010 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1012 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1015 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1017 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1021 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1024 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1025 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1027 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1029 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1031 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1033 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1035 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1037 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1039 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1041 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1043 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1045 merge_help_menu (de->ui_manager);
1047 g_signal_connect (de->data_editor, "notify::ui-manager",
1048 G_CALLBACK (on_ui_manager_changed), de);
1049 on_ui_manager_changed (de->data_editor, NULL, de);
1051 gtk_widget_show (GTK_WIDGET (de->data_editor));
1052 gtk_widget_show (box);
1054 ll_push_head (&all_data_windows, &de->ll);
1058 psppire_data_window_dispose (GObject *object)
1060 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1064 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1065 g_object_unref (dw->uim);
1069 if (dw->builder != NULL)
1071 g_object_unref (dw->builder);
1077 g_signal_handlers_disconnect_by_func (dw->dict,
1078 G_CALLBACK (enable_save), dw);
1079 g_signal_handlers_disconnect_by_func (dw->dict,
1080 G_CALLBACK (on_weight_change), dw);
1081 g_signal_handlers_disconnect_by_func (dw->dict,
1082 G_CALLBACK (on_filter_change), dw);
1083 g_signal_handlers_disconnect_by_func (dw->dict,
1084 G_CALLBACK (on_split_change), dw);
1086 g_object_unref (dw->dict);
1092 g_object_unref (dw->data_store);
1093 dw->data_store = NULL;
1096 if (dw->ll.next != NULL)
1098 ll_remove (&dw->ll);
1102 if (G_OBJECT_CLASS (parent_class)->dispose)
1103 G_OBJECT_CLASS (parent_class)->dispose (object);
1107 psppire_data_window_finalize (GObject *object)
1109 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1113 struct dataset *dataset = dw->dataset;
1114 struct session *session = dataset_session (dataset);
1118 dataset_set_callbacks (dataset, NULL, NULL);
1119 session_set_active_dataset (session, NULL);
1120 dataset_destroy (dataset);
1123 if (G_OBJECT_CLASS (parent_class)->finalize)
1124 G_OBJECT_CLASS (parent_class)->finalize (object);
1128 psppire_data_window_set_property (GObject *object,
1130 const GValue *value,
1133 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1138 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1141 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1147 psppire_data_window_get_property (GObject *object,
1152 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1157 g_value_set_pointer (value, window->dataset);
1160 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1166 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1172 ui_string = gtk_ui_manager_get_ui (uim);
1173 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1177 g_return_val_if_fail (merge_id != 0, 0);
1179 list = gtk_ui_manager_get_action_groups (uim);
1180 for (; list != NULL; list = list->next)
1182 GtkActionGroup *action_group = list->data;
1183 GList *actions = gtk_action_group_list_actions (action_group);
1186 for (action = actions; action != NULL; action = action->next)
1188 GtkAction *a = action->data;
1190 if (PSPPIRE_IS_DIALOG_ACTION (a))
1191 g_object_set (a, "manager", pdw->ui_manager, NULL);
1194 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1197 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1198 gtk_ui_manager_get_accel_group (uim));
1204 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1205 GtkUIManager *uim, guint merge_id)
1209 g_return_if_fail (merge_id != 0);
1211 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1213 list = gtk_ui_manager_get_action_groups (uim);
1214 for (; list != NULL; list = list->next)
1216 GtkActionGroup *action_group = list->data;
1217 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1220 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1221 gtk_ui_manager_get_accel_group (uim));
1225 psppire_data_window_new (struct dataset *ds)
1229 if (the_session == NULL)
1230 the_session = session_create (NULL);
1234 char *dataset_name = session_generate_dataset_name (the_session);
1235 ds = dataset_create (the_session, dataset_name);
1236 free (dataset_name);
1238 assert (dataset_session (ds) == the_session);
1242 psppire_data_window_get_type (),
1243 "description", _("Data Editor"),
1247 if (dataset_name (ds) != NULL)
1248 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1254 psppire_data_window_is_empty (PsppireDataWindow *dw)
1256 return psppire_dict_get_var_cnt (dw->dict) == 0;
1260 psppire_data_window_iface_init (PsppireWindowIface *iface)
1262 iface->save = save_file;
1263 iface->pick_filename = data_pick_filename;
1264 iface->load = load_file;
1268 psppire_default_data_window (void)
1270 if (ll_is_empty (&all_data_windows))
1271 create_data_window ();
1272 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1276 psppire_data_window_set_default (PsppireDataWindow *pdw)
1278 ll_remove (&pdw->ll);
1279 ll_push_head (&all_data_windows, &pdw->ll);
1283 psppire_data_window_undefault (PsppireDataWindow *pdw)
1285 ll_remove (&pdw->ll);
1286 ll_push_tail (&all_data_windows, &pdw->ll);
1290 psppire_data_window_for_dataset (struct dataset *ds)
1292 PsppireDataWindow *pdw;
1294 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1295 if (pdw->dataset == ds)
1302 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1304 PsppireDataWindow *pdw;
1306 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1307 if (pdw->data_store == data_store)
1314 create_data_window (void)
1316 gtk_widget_show (psppire_data_window_new (NULL));
1320 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1324 if (PSPPIRE_IS_DATA_WINDOW (victim)
1325 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1327 window = GTK_WIDGET (victim);
1328 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1331 window = psppire_data_window_new (NULL);
1333 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1334 gtk_widget_show_all (window);