1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012 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/binomial-dialog.h"
30 #include "ui/gui/builder-wrapper.h"
31 #include "ui/gui/chi-square-dialog.h"
32 #include "ui/gui/comments-dialog.h"
33 #include "ui/gui/compute-dialog.h"
34 #include "ui/gui/count-dialog.h"
35 #include "ui/gui/crosstabs-dialog.h"
36 #include "ui/gui/entry-dialog.h"
37 #include "ui/gui/executor.h"
38 #include "ui/gui/frequencies-dialog.h"
39 #include "ui/gui/help-menu.h"
40 #include "ui/gui/helper.h"
41 #include "ui/gui/helper.h"
42 #include "ui/gui/k-related-dialog.h"
43 #include "ui/gui/npar-two-sample-related.h"
44 #include "ui/gui/oneway-anova-dialog.h"
45 #include "ui/gui/psppire-data-window.h"
46 #include "ui/gui/psppire-dialog-action.h"
47 #include "ui/gui/psppire-syntax-window.h"
48 #include "ui/gui/psppire-window.h"
49 #include "ui/gui/psppire.h"
50 #include "ui/gui/runs-dialog.h"
51 #include "ui/gui/ks-one-sample-dialog.h"
52 #include "ui/gui/recode-dialog.h"
53 #include "ui/gui/select-cases-dialog.h"
54 #include "ui/gui/split-file-dialog.h"
55 #include "ui/gui/t-test-one-sample.h"
56 #include "ui/gui/t-test-paired-samples.h"
57 #include "ui/gui/text-data-import-dialog.h"
58 #include "ui/gui/transpose-dialog.h"
59 #include "ui/gui/univariate-dialog.h"
60 #include "ui/gui/weight-cases-dialog.h"
61 #include "ui/syntax-gen.h"
63 #include "gl/c-strcase.h"
64 #include "gl/c-strcasestr.h"
65 #include "gl/xvasprintf.h"
68 #define _(msgid) gettext (msgid)
69 #define N_(msgid) msgid
71 struct session *the_session;
72 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
74 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
75 static void psppire_data_window_init (PsppireDataWindow *data_editor);
78 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
80 static void psppire_data_window_dispose (GObject *object);
81 static void psppire_data_window_finalize (GObject *object);
82 static void psppire_data_window_set_property (GObject *object,
86 static void psppire_data_window_get_property (GObject *object,
91 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
92 static void psppire_data_window_remove_ui (PsppireDataWindow *,
93 GtkUIManager *, guint);
96 psppire_data_window_get_type (void)
98 static GType psppire_data_window_type = 0;
100 if (!psppire_data_window_type)
102 static const GTypeInfo psppire_data_window_info =
104 sizeof (PsppireDataWindowClass),
107 (GClassInitFunc)psppire_data_window_class_init,
108 (GClassFinalizeFunc) NULL,
110 sizeof (PsppireDataWindow),
112 (GInstanceInitFunc) psppire_data_window_init,
115 static const GInterfaceInfo window_interface_info =
117 (GInterfaceInitFunc) psppire_data_window_iface_init,
122 psppire_data_window_type =
123 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
124 &psppire_data_window_info, 0);
127 g_type_add_interface_static (psppire_data_window_type,
128 PSPPIRE_TYPE_WINDOW_MODEL,
129 &window_interface_info);
132 return psppire_data_window_type;
135 static GObjectClass *parent_class ;
142 psppire_data_window_class_init (PsppireDataWindowClass *class)
144 GObjectClass *object_class = G_OBJECT_CLASS (class);
146 parent_class = g_type_class_peek_parent (class);
148 object_class->dispose = psppire_data_window_dispose;
149 object_class->finalize = psppire_data_window_finalize;
150 object_class->set_property = psppire_data_window_set_property;
151 object_class->get_property = psppire_data_window_get_property;
153 g_object_class_install_property (
154 object_class, PROP_DATASET,
155 g_param_spec_pointer ("dataset", "Dataset",
156 "'struct datset *' represented by the window",
157 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
160 /* Run the EXECUTE command. */
162 execute (PsppireDataWindow *dw)
164 execute_const_syntax_string (dw, "EXECUTE.");
168 transformation_change_callback (bool transformations_pending,
171 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
173 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
175 GtkWidget *menuitem =
176 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
178 GtkWidget *status_label =
179 get_widget_assert (de->builder, "case-counter-area");
181 gtk_widget_set_sensitive (menuitem, transformations_pending);
184 if ( transformations_pending)
185 gtk_label_set_text (GTK_LABEL (status_label),
186 _("Transformations Pending"));
188 gtk_label_set_text (GTK_LABEL (status_label), "");
191 /* Callback for when the dictionary changes its filter variable */
193 on_filter_change (GObject *o, gint filter_index, gpointer data)
195 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
197 GtkWidget *filter_status_area =
198 get_widget_assert (de->builder, "filter-use-status-area");
200 if ( filter_index == -1 )
202 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
206 PsppireDict *dict = NULL;
207 struct variable *var ;
210 g_object_get (de->data_editor, "dictionary", &dict, NULL);
212 var = psppire_dict_get_variable (dict, filter_index);
214 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
216 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
222 /* Callback for when the dictionary changes its split variables */
224 on_split_change (PsppireDict *dict, gpointer data)
226 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
228 size_t n_split_vars = dict_get_split_cnt (dict->dict);
230 GtkWidget *split_status_area =
231 get_widget_assert (de->builder, "split-file-status-area");
233 if ( n_split_vars == 0 )
235 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
241 const struct variable *const * split_vars =
242 dict_get_split_vars (dict->dict);
244 text = g_string_new (_("Split by "));
246 for (i = 0 ; i < n_split_vars - 1; ++i )
248 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
250 g_string_append (text, var_get_name (split_vars[i]));
252 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
254 g_string_free (text, TRUE);
261 /* Callback for when the dictionary changes its weights */
263 on_weight_change (GObject *o, gint weight_index, gpointer data)
265 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
267 GtkWidget *weight_status_area =
268 get_widget_assert (de->builder, "weight-status-area");
270 if ( weight_index == -1 )
272 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
276 struct variable *var ;
277 PsppireDict *dict = NULL;
280 g_object_get (de->data_editor, "dictionary", &dict, NULL);
282 var = psppire_dict_get_variable (dict, weight_index);
284 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
286 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
294 dump_rm (GtkRecentManager *rm)
296 GList *items = gtk_recent_manager_get_items (rm);
300 g_print ("Recent Items:\n");
301 for (i = items; i; i = i->next)
303 GtkRecentInfo *ri = i->data;
305 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
306 gtk_recent_info_get_short_name (ri),
307 gtk_recent_info_get_mime_type (ri),
308 gtk_recent_info_get_description (ri),
309 gtk_recent_info_get_uri (ri)
313 gtk_recent_info_unref (ri);
321 name_has_por_suffix (const gchar *name)
323 size_t length = strlen (name);
324 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
328 name_has_sav_suffix (const gchar *name)
330 size_t length = strlen (name);
331 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
334 /* Returns true if NAME has a suffix which might denote a PSPP file */
336 name_has_suffix (const gchar *name)
338 return name_has_por_suffix (name) || name_has_sav_suffix (name);
342 load_file (PsppireWindow *de, const gchar *file_name)
344 struct string filename;
345 gchar *utf8_file_name;
346 const char *mime_type;
350 ds_init_empty (&filename);
352 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
354 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
356 g_free (utf8_file_name);
358 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
359 ds_destroy (&filename);
361 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
362 lex_reader_for_string (syntax));
365 mime_type = (name_has_por_suffix (file_name)
366 ? "application/x-spss-por"
367 : "application/x-spss-sav");
369 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);
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) )
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, GtkNotebookPage *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 /* Initializes as much of a PsppireDataWindow as we can and must before the
839 dataset has been set.
841 In particular, the 'menu' member is required in case the "filename" property
842 is set before the "dataset" property: otherwise PsppireWindow will try to
843 modify the menu as part of the "filename" property_set() function and end up
844 with a Gtk-CRITICAL since 'menu' is NULL. */
846 psppire_data_window_init (PsppireDataWindow *de)
848 de->builder = builder_new ("data-editor.ui");
850 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
852 PSPPIRE_WINDOW (de)->menu =
853 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
860 psppire_data_window_finish_init (PsppireDataWindow *de,
863 static const struct dataset_callbacks cbs =
865 set_unsaved, /* changed */
866 transformation_change_callback, /* transformations_changed */
873 GtkWidget *box = gtk_vbox_new (FALSE, 0);
876 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
877 de->data_store = psppire_data_store_new (de->dict);
878 psppire_data_store_set_reader (de->data_store, NULL);
880 menubar = get_widget_assert (de->builder, "menubar");
881 hb = get_widget_assert (de->builder, "handlebox1");
882 sb = get_widget_assert (de->builder, "status-bar");
888 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
889 g_signal_connect (de->data_editor, "switch-page",
890 G_CALLBACK (on_switch_page), de);
892 g_signal_connect_swapped (de->data_store, "case-changed",
893 G_CALLBACK (set_unsaved), de);
895 g_signal_connect_swapped (de->data_store, "case-inserted",
896 G_CALLBACK (set_unsaved), de);
898 g_signal_connect_swapped (de->data_store, "cases-deleted",
899 G_CALLBACK (set_unsaved), de);
901 dataset_set_callbacks (de->dataset, &cbs, de);
903 connect_help (de->builder);
905 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
906 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
907 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
908 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
910 gtk_container_add (GTK_CONTAINER (de), box);
912 g_signal_connect (de->dict, "weight-changed",
913 G_CALLBACK (on_weight_change),
916 g_signal_connect (de->dict, "filter-changed",
917 G_CALLBACK (on_filter_change),
920 g_signal_connect (de->dict, "split-changed",
921 G_CALLBACK (on_split_change),
925 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
927 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
929 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
931 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
933 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
935 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
937 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
939 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
941 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
943 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
944 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
945 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
946 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
947 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
948 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
949 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
950 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
951 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
952 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
953 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
954 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
955 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
956 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
957 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
958 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
959 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
960 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
961 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
962 connect_action (de, "runs", G_CALLBACK (runs_dialog));
963 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
964 connect_action (de, "k-related-samples", G_CALLBACK (k_related_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_object_unref (dw->dict);
1079 g_object_unref (dw->data_store);
1080 dw->data_store = NULL;
1083 if (dw->ll.next != NULL)
1085 ll_remove (&dw->ll);
1089 if (G_OBJECT_CLASS (parent_class)->dispose)
1090 G_OBJECT_CLASS (parent_class)->dispose (object);
1094 psppire_data_window_finalize (GObject *object)
1096 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1100 struct dataset *dataset = dw->dataset;
1101 struct session *session = dataset_session (dataset);
1105 dataset_set_callbacks (dataset, NULL, NULL);
1106 session_set_active_dataset (session, NULL);
1107 dataset_destroy (dataset);
1110 if (G_OBJECT_CLASS (parent_class)->finalize)
1111 G_OBJECT_CLASS (parent_class)->finalize (object);
1115 psppire_data_window_set_property (GObject *object,
1117 const GValue *value,
1120 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1125 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1128 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1134 psppire_data_window_get_property (GObject *object,
1139 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1144 g_value_set_pointer (value, window->dataset);
1147 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1153 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1159 ui_string = gtk_ui_manager_get_ui (uim);
1160 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1164 g_return_val_if_fail (merge_id != 0, 0);
1166 list = gtk_ui_manager_get_action_groups (uim);
1167 for (; list != NULL; list = list->next)
1169 GtkActionGroup *action_group = list->data;
1170 GList *actions = gtk_action_group_list_actions (action_group);
1173 for (action = actions; action != NULL; action = action->next)
1175 GtkAction *a = action->data;
1177 if (PSPPIRE_IS_DIALOG_ACTION (a))
1178 g_object_set (a, "manager", pdw->ui_manager, NULL);
1181 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1184 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1185 gtk_ui_manager_get_accel_group (uim));
1191 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1192 GtkUIManager *uim, guint merge_id)
1196 g_return_if_fail (merge_id != 0);
1198 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1200 list = gtk_ui_manager_get_action_groups (uim);
1201 for (; list != NULL; list = list->next)
1203 GtkActionGroup *action_group = list->data;
1204 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1207 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1208 gtk_ui_manager_get_accel_group (uim));
1212 psppire_data_window_new (struct dataset *ds)
1216 if (the_session == NULL)
1217 the_session = session_create ();
1221 char *dataset_name = session_generate_dataset_name (the_session);
1222 ds = dataset_create (the_session, dataset_name);
1223 free (dataset_name);
1225 assert (dataset_session (ds) == the_session);
1229 psppire_data_window_get_type (),
1230 "description", _("Data Editor"),
1234 if (dataset_name (ds) != NULL)
1235 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1241 psppire_data_window_is_empty (PsppireDataWindow *dw)
1243 return psppire_dict_get_var_cnt (dw->dict) == 0;
1247 psppire_data_window_iface_init (PsppireWindowIface *iface)
1249 iface->save = save_file;
1250 iface->pick_filename = data_pick_filename;
1251 iface->load = load_file;
1255 psppire_default_data_window (void)
1257 if (ll_is_empty (&all_data_windows))
1258 create_data_window ();
1259 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1263 psppire_data_window_set_default (PsppireDataWindow *pdw)
1265 ll_remove (&pdw->ll);
1266 ll_push_head (&all_data_windows, &pdw->ll);
1270 psppire_data_window_undefault (PsppireDataWindow *pdw)
1272 ll_remove (&pdw->ll);
1273 ll_push_tail (&all_data_windows, &pdw->ll);
1277 psppire_data_window_for_dataset (struct dataset *ds)
1279 PsppireDataWindow *pdw;
1281 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1282 if (pdw->dataset == ds)
1289 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1291 PsppireDataWindow *pdw;
1293 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1294 if (pdw->data_store == data_store)
1301 create_data_window (void)
1303 gtk_widget_show (psppire_data_window_new (NULL));
1307 open_data_window (PsppireWindow *victim, const char *file_name)
1311 if (PSPPIRE_IS_DATA_WINDOW (victim)
1312 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1314 window = GTK_WIDGET (victim);
1315 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1318 window = psppire_data_window_new (NULL);
1320 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1321 gtk_widget_show_all (window);