1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/builder-wrapper.h"
30 #include "ui/gui/chi-square-dialog.h"
31 #include "ui/gui/comments-dialog.h"
32 #include "ui/gui/compute-dialog.h"
33 #include "ui/gui/count-dialog.h"
34 #include "ui/gui/entry-dialog.h"
35 #include "ui/gui/executor.h"
36 #include "ui/gui/help-menu.h"
37 #include "ui/gui/helper.h"
38 #include "ui/gui/helper.h"
39 #include "ui/gui/k-related-dialog.h"
40 #include "ui/gui/npar-two-sample-related.h"
41 #include "ui/gui/oneway-anova-dialog.h"
42 #include "ui/gui/psppire-data-window.h"
43 #include "ui/gui/psppire-dialog-action.h"
44 #include "ui/gui/psppire-syntax-window.h"
45 #include "ui/gui/psppire-window.h"
46 #include "ui/gui/psppire.h"
47 #include "ui/gui/ks-one-sample-dialog.h"
48 #include "ui/gui/recode-dialog.h"
49 #include "ui/gui/select-cases-dialog.h"
50 #include "ui/gui/split-file-dialog.h"
51 #include "ui/gui/t-test-one-sample.h"
52 #include "ui/gui/t-test-paired-samples.h"
53 #include "ui/gui/text-data-import-dialog.h"
54 #include "ui/gui/transpose-dialog.h"
55 #include "ui/gui/univariate-dialog.h"
56 #include "ui/gui/weight-cases-dialog.h"
57 #include "ui/syntax-gen.h"
59 #include "gl/c-strcase.h"
60 #include "gl/c-strcasestr.h"
61 #include "gl/xvasprintf.h"
64 #define _(msgid) gettext (msgid)
65 #define N_(msgid) msgid
67 struct session *the_session;
68 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
70 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
71 static void psppire_data_window_init (PsppireDataWindow *data_editor);
74 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
76 static void psppire_data_window_dispose (GObject *object);
77 static void psppire_data_window_finalize (GObject *object);
78 static void psppire_data_window_set_property (GObject *object,
82 static void psppire_data_window_get_property (GObject *object,
87 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
88 static void psppire_data_window_remove_ui (PsppireDataWindow *,
89 GtkUIManager *, guint);
92 psppire_data_window_get_type (void)
94 static GType psppire_data_window_type = 0;
96 if (!psppire_data_window_type)
98 static const GTypeInfo psppire_data_window_info =
100 sizeof (PsppireDataWindowClass),
103 (GClassInitFunc)psppire_data_window_class_init,
104 (GClassFinalizeFunc) NULL,
106 sizeof (PsppireDataWindow),
108 (GInstanceInitFunc) psppire_data_window_init,
111 static const GInterfaceInfo window_interface_info =
113 (GInterfaceInitFunc) psppire_data_window_iface_init,
118 psppire_data_window_type =
119 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
120 &psppire_data_window_info, 0);
123 g_type_add_interface_static (psppire_data_window_type,
124 PSPPIRE_TYPE_WINDOW_MODEL,
125 &window_interface_info);
128 return psppire_data_window_type;
131 static GObjectClass *parent_class ;
138 psppire_data_window_class_init (PsppireDataWindowClass *class)
140 GObjectClass *object_class = G_OBJECT_CLASS (class);
142 parent_class = g_type_class_peek_parent (class);
144 object_class->dispose = psppire_data_window_dispose;
145 object_class->finalize = psppire_data_window_finalize;
146 object_class->set_property = psppire_data_window_set_property;
147 object_class->get_property = psppire_data_window_get_property;
149 g_object_class_install_property (
150 object_class, PROP_DATASET,
151 g_param_spec_pointer ("dataset", "Dataset",
152 "'struct datset *' represented by the window",
153 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
156 /* Run the EXECUTE command. */
158 execute (PsppireDataWindow *dw)
160 execute_const_syntax_string (dw, "EXECUTE.");
164 transformation_change_callback (bool transformations_pending,
167 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
169 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
171 GtkWidget *menuitem =
172 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
174 GtkWidget *status_label =
175 get_widget_assert (de->builder, "case-counter-area");
177 gtk_widget_set_sensitive (menuitem, transformations_pending);
180 if ( transformations_pending)
181 gtk_label_set_text (GTK_LABEL (status_label),
182 _("Transformations Pending"));
184 gtk_label_set_text (GTK_LABEL (status_label), "");
187 /* Callback for when the dictionary changes its filter variable */
189 on_filter_change (GObject *o, gint filter_index, gpointer data)
191 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
193 GtkWidget *filter_status_area =
194 get_widget_assert (de->builder, "filter-use-status-area");
196 if ( filter_index == -1 )
198 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
202 PsppireDict *dict = NULL;
203 struct variable *var ;
206 g_object_get (de->data_editor, "dictionary", &dict, NULL);
208 var = psppire_dict_get_variable (dict, filter_index);
210 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
212 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
218 /* Callback for when the dictionary changes its split variables */
220 on_split_change (PsppireDict *dict, gpointer data)
222 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
224 size_t n_split_vars = dict_get_split_cnt (dict->dict);
226 GtkWidget *split_status_area =
227 get_widget_assert (de->builder, "split-file-status-area");
229 if ( n_split_vars == 0 )
231 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
237 const struct variable *const * split_vars =
238 dict_get_split_vars (dict->dict);
240 text = g_string_new (_("Split by "));
242 for (i = 0 ; i < n_split_vars - 1; ++i )
244 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
246 g_string_append (text, var_get_name (split_vars[i]));
248 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
250 g_string_free (text, TRUE);
257 /* Callback for when the dictionary changes its weights */
259 on_weight_change (GObject *o, gint weight_index, gpointer data)
261 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
263 GtkWidget *weight_status_area =
264 get_widget_assert (de->builder, "weight-status-area");
266 if ( weight_index == -1 )
268 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
272 struct variable *var ;
273 PsppireDict *dict = NULL;
276 g_object_get (de->data_editor, "dictionary", &dict, NULL);
278 var = psppire_dict_get_variable (dict, weight_index);
280 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
282 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
290 dump_rm (GtkRecentManager *rm)
292 GList *items = gtk_recent_manager_get_items (rm);
296 g_print ("Recent Items:\n");
297 for (i = items; i; i = i->next)
299 GtkRecentInfo *ri = i->data;
301 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
302 gtk_recent_info_get_short_name (ri),
303 gtk_recent_info_get_mime_type (ri),
304 gtk_recent_info_get_description (ri),
305 gtk_recent_info_get_uri (ri)
309 gtk_recent_info_unref (ri);
317 name_has_por_suffix (const gchar *name)
319 size_t length = strlen (name);
320 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
324 name_has_sav_suffix (const gchar *name)
326 size_t length = strlen (name);
327 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
330 /* Returns true if NAME has a suffix which might denote a PSPP file */
332 name_has_suffix (const gchar *name)
334 return name_has_por_suffix (name) || name_has_sav_suffix (name);
338 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
340 const char *mime_type = NULL;
341 gchar *syntax = NULL;
346 gchar *utf8_file_name;
347 struct string filename;
348 ds_init_empty (&filename);
350 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
352 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
354 g_free (utf8_file_name);
356 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
357 ds_destroy (&filename);
365 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
366 lex_reader_for_string (syntax));
369 if (ok && syn == NULL)
371 if (name_has_por_suffix (file_name))
372 mime_type = "application/x-spss-por";
373 else if (name_has_sav_suffix (file_name))
374 mime_type = "application/x-spss-sav";
376 add_most_recent (file_name, mime_type);
382 /* Save DE to file */
384 save_file (PsppireWindow *w)
386 const gchar *file_name = NULL;
387 gchar *utf8_file_name = NULL;
389 struct string filename ;
390 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
393 file_name = psppire_window_get_filename (w);
395 fnx = g_string_new (file_name);
397 if ( ! name_has_suffix (fnx->str))
399 if ( de->save_as_portable)
400 g_string_append (fnx, ".por");
402 g_string_append (fnx, ".sav");
405 ds_init_empty (&filename);
407 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
409 g_string_free (fnx, TRUE);
411 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
412 g_free (utf8_file_name);
414 syntax = g_strdup_printf ("%s OUTFILE=%s.",
415 de->save_as_portable ? "EXPORT" : "SAVE",
416 ds_cstr (&filename));
418 ds_destroy (&filename);
420 g_free (execute_syntax_string (de, syntax));
425 display_dict (PsppireDataWindow *de)
427 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
431 sysfile_info (PsppireDataWindow *de)
433 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
435 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
437 struct string filename;
439 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
441 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
446 ds_init_empty (&filename);
448 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
450 g_free (utf8_file_name);
452 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
453 g_free (execute_syntax_string (de, syntax));
456 gtk_widget_destroy (dialog);
460 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
462 data_pick_filename (PsppireWindow *window)
464 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
465 GtkFileFilter *filter = gtk_file_filter_new ();
466 GtkWidget *button_sys;
468 gtk_file_chooser_dialog_new (_("Save"),
470 GTK_FILE_CHOOSER_ACTION_SAVE,
471 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
472 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
475 g_object_set (dialog, "local-only", FALSE, NULL);
477 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
478 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
479 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
481 filter = gtk_file_filter_new ();
482 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
483 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
484 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
486 filter = gtk_file_filter_new ();
487 gtk_file_filter_set_name (filter, _("All Files"));
488 gtk_file_filter_add_pattern (filter, "*");
489 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
492 GtkWidget *button_por;
493 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
495 gtk_radio_button_new_with_label (NULL, _("System File"));
498 gtk_radio_button_new_with_label
499 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
502 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
503 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
505 gtk_widget_show_all (vbox);
507 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
510 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
513 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
515 case GTK_RESPONSE_ACCEPT:
520 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
523 de->save_as_portable =
524 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
526 if ( ! name_has_suffix (filename->str))
528 if ( de->save_as_portable)
529 g_string_append (filename, ".por");
531 g_string_append (filename, ".sav");
534 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
536 g_string_free (filename, TRUE);
543 gtk_widget_destroy (dialog);
547 confirm_delete_dataset (PsppireDataWindow *de,
548 const char *old_dataset,
549 const char *new_dataset,
550 const char *existing_dataset)
555 dialog = gtk_message_dialog_new (
556 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
557 _("Delete Existing Dataset?"));
559 gtk_message_dialog_format_secondary_text (
560 GTK_MESSAGE_DIALOG (dialog),
561 _("Renaming \"%s\" to \"%s\" will destroy the existing "
562 "dataset named \"%s\". Are you sure that you want to do this?"),
563 old_dataset, new_dataset, existing_dataset);
565 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
566 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
567 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
570 g_object_set (dialog, "icon-name", "pspp", NULL);
572 result = gtk_dialog_run (GTK_DIALOG (dialog));
574 gtk_widget_destroy (dialog);
576 return result == GTK_RESPONSE_OK;
580 on_rename_dataset (PsppireDataWindow *de)
582 struct dataset *ds = de->dataset;
583 struct session *session = dataset_session (ds);
584 const char *old_name = dataset_name (ds);
585 struct dataset *existing_dataset;
589 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
591 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
595 if (new_name == NULL)
598 existing_dataset = session_lookup_dataset (session, new_name);
599 if (existing_dataset == NULL || existing_dataset == ds
600 || confirm_delete_dataset (de, old_name, new_name,
601 dataset_name (existing_dataset)))
602 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
609 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
611 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
613 if ( gtk_toggle_action_get_active (action))
614 gtk_widget_show (statusbar);
616 gtk_widget_hide (statusbar);
621 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
623 const gboolean grid_visible = gtk_toggle_action_get_active (action);
625 psppire_data_editor_show_grid (de->data_editor, grid_visible);
629 data_view_activate (PsppireDataWindow *de)
631 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
636 variable_view_activate (PsppireDataWindow *de)
638 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
643 fonts_activate (PsppireDataWindow *de)
645 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
646 PangoFontDescription *current_font;
649 gtk_font_selection_dialog_new (_("Font Selection"));
652 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
653 font_name = pango_font_description_to_string (current_font);
655 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
659 gtk_window_set_transient_for (GTK_WINDOW (dialog),
660 GTK_WINDOW (toplevel));
662 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
664 const gchar *font = gtk_font_selection_dialog_get_font_name
665 (GTK_FONT_SELECTION_DIALOG (dialog));
667 PangoFontDescription* font_desc =
668 pango_font_description_from_string (font);
670 psppire_data_editor_set_font (de->data_editor, font_desc);
673 gtk_widget_hide (dialog);
678 /* Callback for the value labels action */
680 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
682 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
686 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
688 psppire_data_editor_split_window (de->data_editor,
689 gtk_toggle_action_get_active (ta));
694 file_quit (PsppireDataWindow *de)
696 /* FIXME: Need to be more intelligent here.
697 Give the user the opportunity to save any unsaved data.
703 on_recent_data_select (GtkMenuShell *menushell,
704 PsppireWindow *window)
709 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
711 file = g_filename_from_uri (uri, NULL, NULL);
715 open_data_window (window, file, NULL);
721 charset_from_mime_type (const char *mime_type)
727 if (mime_type == NULL)
730 charset = c_strcasestr (mime_type, "charset=");
738 /* Parse a "quoted-string" as defined by RFC 822. */
739 for (p++; *p != '\0' && *p != '"'; p++)
742 ds_put_byte (&s, *p);
743 else if (*++p != '\0')
744 ds_put_byte (&s, *p);
749 /* Parse a "token" as defined by RFC 2045. */
750 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
751 ds_put_byte (&s, *p++);
753 if (!ds_is_empty (&s))
754 return ds_steal_cstr (&s);
761 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
768 /* Get the file name and its encoding. */
769 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
770 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
771 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
772 gtk_recent_info_unref (item);
774 se = psppire_syntax_window_new (encoding);
778 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
779 gtk_widget_show (se);
781 gtk_widget_destroy (se);
787 set_unsaved (gpointer w)
789 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
793 on_switch_page (PsppireDataEditor *de, gpointer p,
794 gint pagenum, PsppireDataWindow *dw)
796 GtkWidget *page_menu_item;
800 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
802 ? "/ui/menubar/view/view_data"
803 : "/ui/menubar/view/view_variables");
804 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
805 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
809 on_ui_manager_changed (PsppireDataEditor *de,
810 GParamSpec *pspec UNUSED,
811 PsppireDataWindow *dw)
813 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
819 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
820 g_object_unref (dw->uim);
827 g_object_ref (dw->uim);
828 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
832 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
833 Returns a pointer to the action
836 connect_action (PsppireDataWindow *dw, const char *action_name,
839 GtkAction *action = get_action_assert (dw->builder, action_name);
841 g_signal_connect_swapped (action, "activate", handler, dw);
846 /* Only a data file with at least one variable can be saved. */
848 enable_save (PsppireDataWindow *dw)
850 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
852 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
854 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
858 /* Initializes as much of a PsppireDataWindow as we can and must before the
859 dataset has been set.
861 In particular, the 'menu' member is required in case the "filename" property
862 is set before the "dataset" property: otherwise PsppireWindow will try to
863 modify the menu as part of the "filename" property_set() function and end up
864 with a Gtk-CRITICAL since 'menu' is NULL. */
866 psppire_data_window_init (PsppireDataWindow *de)
868 de->builder = builder_new ("data-editor.ui");
870 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
872 PSPPIRE_WINDOW (de)->menu =
873 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
880 psppire_data_window_finish_init (PsppireDataWindow *de,
883 static const struct dataset_callbacks cbs =
885 set_unsaved, /* changed */
886 transformation_change_callback, /* transformations_changed */
893 GtkWidget *box = gtk_vbox_new (FALSE, 0);
896 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
897 de->data_store = psppire_data_store_new (de->dict);
898 psppire_data_store_set_reader (de->data_store, NULL);
900 menubar = get_widget_assert (de->builder, "menubar");
901 hb = get_widget_assert (de->builder, "handlebox1");
902 sb = get_widget_assert (de->builder, "status-bar");
908 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
909 g_signal_connect (de->data_editor, "switch-page",
910 G_CALLBACK (on_switch_page), de);
912 g_signal_connect_swapped (de->data_store, "case-changed",
913 G_CALLBACK (set_unsaved), de);
915 g_signal_connect_swapped (de->data_store, "case-inserted",
916 G_CALLBACK (set_unsaved), de);
918 g_signal_connect_swapped (de->data_store, "cases-deleted",
919 G_CALLBACK (set_unsaved), de);
921 dataset_set_callbacks (de->dataset, &cbs, de);
923 connect_help (de->builder);
925 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
926 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
927 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
928 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
930 gtk_container_add (GTK_CONTAINER (de), box);
932 g_signal_connect (de->dict, "weight-changed",
933 G_CALLBACK (on_weight_change),
936 g_signal_connect (de->dict, "filter-changed",
937 G_CALLBACK (on_filter_change),
940 g_signal_connect (de->dict, "split-changed",
941 G_CALLBACK (on_split_change),
944 g_signal_connect_swapped (de->dict, "backend-changed",
945 G_CALLBACK (enable_save), de);
946 g_signal_connect_swapped (de->dict, "variable-inserted",
947 G_CALLBACK (enable_save), de);
948 g_signal_connect_swapped (de->dict, "variable-deleted",
949 G_CALLBACK (enable_save), de);
952 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
954 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
956 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
958 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
960 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
962 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
964 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
966 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
968 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
970 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
971 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
972 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
973 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
974 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
975 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
976 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
977 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
978 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
979 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
980 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
981 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
982 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
983 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
984 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
985 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
986 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
987 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
988 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
991 GtkWidget *recent_data =
992 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
994 GtkWidget *recent_files =
995 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
998 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
999 gtk_recent_manager_get_default ());
1001 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1002 gtk_recent_manager_get_default ());
1004 g_object_set (menu_data, "show-tips", TRUE, NULL);
1005 g_object_set (menu_files, "show-tips", TRUE, NULL);
1008 GtkRecentFilter *filter = gtk_recent_filter_new ();
1010 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1011 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1013 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1015 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1018 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1021 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1024 GtkRecentFilter *filter = gtk_recent_filter_new ();
1026 gtk_recent_filter_add_pattern (filter, "*.sps");
1027 gtk_recent_filter_add_pattern (filter, "*.SPS");
1029 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1031 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1034 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1036 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1040 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1043 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1044 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1046 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1048 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1050 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1052 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1054 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1056 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1058 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1060 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1062 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1064 merge_help_menu (de->ui_manager);
1066 g_signal_connect (de->data_editor, "notify::ui-manager",
1067 G_CALLBACK (on_ui_manager_changed), de);
1068 on_ui_manager_changed (de->data_editor, NULL, de);
1070 gtk_widget_show (GTK_WIDGET (de->data_editor));
1071 gtk_widget_show (box);
1073 ll_push_head (&all_data_windows, &de->ll);
1077 psppire_data_window_dispose (GObject *object)
1079 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1083 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1084 g_object_unref (dw->uim);
1088 if (dw->builder != NULL)
1090 g_object_unref (dw->builder);
1096 g_signal_handlers_disconnect_by_func (dw->dict,
1097 G_CALLBACK (enable_save), dw);
1098 g_signal_handlers_disconnect_by_func (dw->dict,
1099 G_CALLBACK (on_weight_change), dw);
1100 g_signal_handlers_disconnect_by_func (dw->dict,
1101 G_CALLBACK (on_filter_change), dw);
1102 g_signal_handlers_disconnect_by_func (dw->dict,
1103 G_CALLBACK (on_split_change), dw);
1105 g_object_unref (dw->dict);
1111 g_object_unref (dw->data_store);
1112 dw->data_store = NULL;
1115 if (dw->ll.next != NULL)
1117 ll_remove (&dw->ll);
1121 if (G_OBJECT_CLASS (parent_class)->dispose)
1122 G_OBJECT_CLASS (parent_class)->dispose (object);
1126 psppire_data_window_finalize (GObject *object)
1128 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1132 struct dataset *dataset = dw->dataset;
1133 struct session *session = dataset_session (dataset);
1137 dataset_set_callbacks (dataset, NULL, NULL);
1138 session_set_active_dataset (session, NULL);
1139 dataset_destroy (dataset);
1142 if (G_OBJECT_CLASS (parent_class)->finalize)
1143 G_OBJECT_CLASS (parent_class)->finalize (object);
1147 psppire_data_window_set_property (GObject *object,
1149 const GValue *value,
1152 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1157 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1160 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1166 psppire_data_window_get_property (GObject *object,
1171 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1176 g_value_set_pointer (value, window->dataset);
1179 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1185 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1191 ui_string = gtk_ui_manager_get_ui (uim);
1192 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1196 g_return_val_if_fail (merge_id != 0, 0);
1198 list = gtk_ui_manager_get_action_groups (uim);
1199 for (; list != NULL; list = list->next)
1201 GtkActionGroup *action_group = list->data;
1202 GList *actions = gtk_action_group_list_actions (action_group);
1205 for (action = actions; action != NULL; action = action->next)
1207 GtkAction *a = action->data;
1209 if (PSPPIRE_IS_DIALOG_ACTION (a))
1210 g_object_set (a, "manager", pdw->ui_manager, NULL);
1213 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1216 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1217 gtk_ui_manager_get_accel_group (uim));
1223 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1224 GtkUIManager *uim, guint merge_id)
1228 g_return_if_fail (merge_id != 0);
1230 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1232 list = gtk_ui_manager_get_action_groups (uim);
1233 for (; list != NULL; list = list->next)
1235 GtkActionGroup *action_group = list->data;
1236 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1239 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1240 gtk_ui_manager_get_accel_group (uim));
1244 psppire_data_window_new (struct dataset *ds)
1248 if (the_session == NULL)
1249 the_session = session_create (NULL);
1253 char *dataset_name = session_generate_dataset_name (the_session);
1254 ds = dataset_create (the_session, dataset_name);
1255 free (dataset_name);
1257 assert (dataset_session (ds) == the_session);
1261 psppire_data_window_get_type (),
1262 "description", _("Data Editor"),
1266 if (dataset_name (ds) != NULL)
1267 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1273 psppire_data_window_is_empty (PsppireDataWindow *dw)
1275 return psppire_dict_get_var_cnt (dw->dict) == 0;
1279 psppire_data_window_iface_init (PsppireWindowIface *iface)
1281 iface->save = save_file;
1282 iface->pick_filename = data_pick_filename;
1283 iface->load = load_file;
1287 psppire_default_data_window (void)
1289 if (ll_is_empty (&all_data_windows))
1290 create_data_window ();
1291 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1295 psppire_data_window_set_default (PsppireDataWindow *pdw)
1297 ll_remove (&pdw->ll);
1298 ll_push_head (&all_data_windows, &pdw->ll);
1302 psppire_data_window_undefault (PsppireDataWindow *pdw)
1304 ll_remove (&pdw->ll);
1305 ll_push_tail (&all_data_windows, &pdw->ll);
1309 psppire_data_window_for_dataset (struct dataset *ds)
1311 PsppireDataWindow *pdw;
1313 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1314 if (pdw->dataset == ds)
1321 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1323 PsppireDataWindow *pdw;
1325 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1326 if (pdw->data_store == data_store)
1333 create_data_window (void)
1335 gtk_widget_show (psppire_data_window_new (NULL));
1339 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1343 if (PSPPIRE_IS_DATA_WINDOW (victim)
1344 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1346 window = GTK_WIDGET (victim);
1347 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1350 window = psppire_data_window_new (NULL);
1352 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1353 gtk_widget_show_all (window);