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_set_property (GObject *object,
85 static void psppire_data_window_get_property (GObject *object,
90 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
91 static void psppire_data_window_remove_ui (PsppireDataWindow *,
92 GtkUIManager *, guint);
95 psppire_data_window_get_type (void)
97 static GType psppire_data_window_type = 0;
99 if (!psppire_data_window_type)
101 static const GTypeInfo psppire_data_window_info =
103 sizeof (PsppireDataWindowClass),
106 (GClassInitFunc)psppire_data_window_class_init,
107 (GClassFinalizeFunc) NULL,
109 sizeof (PsppireDataWindow),
111 (GInstanceInitFunc) psppire_data_window_init,
114 static const GInterfaceInfo window_interface_info =
116 (GInterfaceInitFunc) psppire_data_window_iface_init,
121 psppire_data_window_type =
122 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
123 &psppire_data_window_info, 0);
126 g_type_add_interface_static (psppire_data_window_type,
127 PSPPIRE_TYPE_WINDOW_MODEL,
128 &window_interface_info);
131 return psppire_data_window_type;
134 static GObjectClass *parent_class ;
141 psppire_data_window_class_init (PsppireDataWindowClass *class)
143 GObjectClass *object_class = G_OBJECT_CLASS (class);
145 parent_class = g_type_class_peek_parent (class);
147 object_class->dispose = psppire_data_window_dispose;
148 object_class->set_property = psppire_data_window_set_property;
149 object_class->get_property = psppire_data_window_get_property;
151 g_object_class_install_property (
152 object_class, PROP_DATASET,
153 g_param_spec_pointer ("dataset", "Dataset",
154 "'struct datset *' represented by the window",
155 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
158 /* Run the EXECUTE command. */
160 execute (PsppireDataWindow *dw)
162 execute_const_syntax_string (dw, "EXECUTE.");
166 transformation_change_callback (bool transformations_pending,
169 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
171 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
173 GtkWidget *menuitem =
174 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
176 GtkWidget *status_label =
177 get_widget_assert (de->builder, "case-counter-area");
179 gtk_widget_set_sensitive (menuitem, transformations_pending);
182 if ( transformations_pending)
183 gtk_label_set_text (GTK_LABEL (status_label),
184 _("Transformations Pending"));
186 gtk_label_set_text (GTK_LABEL (status_label), "");
189 /* Callback for when the dictionary changes its filter variable */
191 on_filter_change (GObject *o, gint filter_index, gpointer data)
193 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
195 GtkWidget *filter_status_area =
196 get_widget_assert (de->builder, "filter-use-status-area");
198 if ( filter_index == -1 )
200 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
204 PsppireDict *dict = NULL;
205 struct variable *var ;
208 g_object_get (de->data_editor, "dictionary", &dict, NULL);
210 var = psppire_dict_get_variable (dict, filter_index);
212 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
214 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
220 /* Callback for when the dictionary changes its split variables */
222 on_split_change (PsppireDict *dict, gpointer data)
224 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
226 size_t n_split_vars = dict_get_split_cnt (dict->dict);
228 GtkWidget *split_status_area =
229 get_widget_assert (de->builder, "split-file-status-area");
231 if ( n_split_vars == 0 )
233 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
239 const struct variable *const * split_vars =
240 dict_get_split_vars (dict->dict);
242 text = g_string_new (_("Split by "));
244 for (i = 0 ; i < n_split_vars - 1; ++i )
246 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
248 g_string_append (text, var_get_name (split_vars[i]));
250 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
252 g_string_free (text, TRUE);
259 /* Callback for when the dictionary changes its weights */
261 on_weight_change (GObject *o, gint weight_index, gpointer data)
263 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
265 GtkWidget *weight_status_area =
266 get_widget_assert (de->builder, "weight-status-area");
268 if ( weight_index == -1 )
270 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
274 struct variable *var ;
275 PsppireDict *dict = NULL;
278 g_object_get (de->data_editor, "dictionary", &dict, NULL);
280 var = psppire_dict_get_variable (dict, weight_index);
282 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
284 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
292 dump_rm (GtkRecentManager *rm)
294 GList *items = gtk_recent_manager_get_items (rm);
298 g_print ("Recent Items:\n");
299 for (i = items; i; i = i->next)
301 GtkRecentInfo *ri = i->data;
303 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
304 gtk_recent_info_get_short_name (ri),
305 gtk_recent_info_get_mime_type (ri),
306 gtk_recent_info_get_description (ri),
307 gtk_recent_info_get_uri (ri)
311 gtk_recent_info_unref (ri);
319 name_has_por_suffix (const gchar *name)
321 size_t length = strlen (name);
322 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
326 name_has_sav_suffix (const gchar *name)
328 size_t length = strlen (name);
329 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
332 /* Returns true if NAME has a suffix which might denote a PSPP file */
334 name_has_suffix (const gchar *name)
336 return name_has_por_suffix (name) || name_has_sav_suffix (name);
340 load_file (PsppireWindow *de, const gchar *file_name)
342 struct string filename;
343 gchar *utf8_file_name;
344 const char *mime_type;
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);
359 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
360 lex_reader_for_string (syntax));
363 mime_type = (name_has_por_suffix (file_name)
364 ? "application/x-spss-por"
365 : "application/x-spss-sav");
367 add_most_recent (file_name, mime_type);
372 /* Save DE to file */
374 save_file (PsppireWindow *w)
376 const gchar *file_name = NULL;
377 gchar *utf8_file_name = NULL;
379 struct string filename ;
380 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
383 file_name = psppire_window_get_filename (w);
385 fnx = g_string_new (file_name);
387 if ( ! name_has_suffix (fnx->str))
389 if ( de->save_as_portable)
390 g_string_append (fnx, ".por");
392 g_string_append (fnx, ".sav");
395 ds_init_empty (&filename);
397 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
399 g_string_free (fnx, TRUE);
401 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
402 g_free (utf8_file_name);
404 syntax = g_strdup_printf ("%s OUTFILE=%s.",
405 de->save_as_portable ? "EXPORT" : "SAVE",
406 ds_cstr (&filename));
408 ds_destroy (&filename);
410 g_free (execute_syntax_string (de, syntax));
415 display_dict (PsppireDataWindow *de)
417 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
421 sysfile_info (PsppireDataWindow *de)
423 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
425 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
427 struct string filename;
429 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
431 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
436 ds_init_empty (&filename);
438 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
440 g_free (utf8_file_name);
442 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
443 g_free (execute_syntax_string (de, syntax));
446 gtk_widget_destroy (dialog);
450 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
452 data_pick_filename (PsppireWindow *window)
454 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
455 GtkFileFilter *filter = gtk_file_filter_new ();
456 GtkWidget *button_sys;
458 gtk_file_chooser_dialog_new (_("Save"),
460 GTK_FILE_CHOOSER_ACTION_SAVE,
461 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
462 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
465 g_object_set (dialog, "local-only", FALSE, NULL);
467 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
468 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
469 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
471 filter = gtk_file_filter_new ();
472 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
473 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
474 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
476 filter = gtk_file_filter_new ();
477 gtk_file_filter_set_name (filter, _("All Files"));
478 gtk_file_filter_add_pattern (filter, "*");
479 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
482 GtkWidget *button_por;
483 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
485 gtk_radio_button_new_with_label (NULL, _("System File"));
488 gtk_radio_button_new_with_label
489 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
492 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
493 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
495 gtk_widget_show_all (vbox);
497 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
500 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
503 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
505 case GTK_RESPONSE_ACCEPT:
510 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
513 de->save_as_portable =
514 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
516 if ( ! name_has_suffix (filename->str))
518 if ( de->save_as_portable)
519 g_string_append (filename, ".por");
521 g_string_append (filename, ".sav");
524 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
526 g_string_free (filename, TRUE);
533 gtk_widget_destroy (dialog);
537 confirm_delete_dataset (PsppireDataWindow *de,
538 const char *old_dataset,
539 const char *new_dataset,
540 const char *existing_dataset)
545 dialog = gtk_message_dialog_new (
546 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
547 _("Delete Existing Dataset?"));
549 gtk_message_dialog_format_secondary_text (
550 GTK_MESSAGE_DIALOG (dialog),
551 _("Renaming \"%s\" to \"%s\" will destroy the existing "
552 "dataset named \"%s\". Are you sure that you want to do this?"),
553 old_dataset, new_dataset, existing_dataset);
555 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
556 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
557 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
560 g_object_set (dialog, "icon-name", "pspp", NULL);
562 result = gtk_dialog_run (GTK_DIALOG (dialog));
564 gtk_widget_destroy (dialog);
566 return result == GTK_RESPONSE_OK;
570 on_rename_dataset (PsppireDataWindow *de)
572 struct dataset *ds = de->dataset;
573 struct session *session = dataset_session (ds);
574 const char *old_name = dataset_name (ds);
575 struct dataset *existing_dataset;
579 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
581 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
585 if (new_name == NULL)
588 existing_dataset = session_lookup_dataset (session, new_name);
589 if (existing_dataset == NULL || existing_dataset == ds
590 || confirm_delete_dataset (de, old_name, new_name,
591 dataset_name (existing_dataset)))
592 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
599 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
601 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
603 if ( gtk_toggle_action_get_active (action))
604 gtk_widget_show (statusbar);
606 gtk_widget_hide (statusbar);
611 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
613 const gboolean grid_visible = gtk_toggle_action_get_active (action);
615 psppire_data_editor_show_grid (de->data_editor, grid_visible);
619 data_view_activate (PsppireDataWindow *de)
621 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
626 variable_view_activate (PsppireDataWindow *de)
628 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
633 fonts_activate (PsppireDataWindow *de)
635 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
636 PangoFontDescription *current_font;
639 gtk_font_selection_dialog_new (_("Font Selection"));
642 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
643 font_name = pango_font_description_to_string (current_font);
645 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
649 gtk_window_set_transient_for (GTK_WINDOW (dialog),
650 GTK_WINDOW (toplevel));
652 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
654 const gchar *font = gtk_font_selection_dialog_get_font_name
655 (GTK_FONT_SELECTION_DIALOG (dialog));
657 PangoFontDescription* font_desc =
658 pango_font_description_from_string (font);
660 psppire_data_editor_set_font (de->data_editor, font_desc);
663 gtk_widget_hide (dialog);
668 /* Callback for the value labels action */
670 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
672 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
676 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
678 psppire_data_editor_split_window (de->data_editor,
679 gtk_toggle_action_get_active (ta));
684 file_quit (PsppireDataWindow *de)
686 /* FIXME: Need to be more intelligent here.
687 Give the user the opportunity to save any unsaved data.
693 on_recent_data_select (GtkMenuShell *menushell,
694 PsppireWindow *window)
699 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
701 file = g_filename_from_uri (uri, NULL, NULL);
705 open_data_window (window, file);
711 charset_from_mime_type (const char *mime_type)
717 if (mime_type == NULL)
720 charset = c_strcasestr (mime_type, "charset=");
728 /* Parse a "quoted-string" as defined by RFC 822. */
729 for (p++; *p != '\0' && *p != '"'; p++)
732 ds_put_byte (&s, *p);
733 else if (*++p != '\0')
734 ds_put_byte (&s, *p);
739 /* Parse a "token" as defined by RFC 2045. */
740 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
741 ds_put_byte (&s, *p++);
743 if (!ds_is_empty (&s))
744 return ds_steal_cstr (&s);
751 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
758 /* Get the file name and its encoding. */
759 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
760 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
761 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
762 gtk_recent_info_unref (item);
764 se = psppire_syntax_window_new (encoding);
768 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
769 gtk_widget_show (se);
771 gtk_widget_destroy (se);
777 set_unsaved (gpointer w)
779 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
783 on_switch_page (PsppireDataEditor *de, GtkNotebookPage *p,
784 gint pagenum, PsppireDataWindow *dw)
786 GtkWidget *page_menu_item;
790 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
792 ? "/ui/menubar/view/view_data"
793 : "/ui/menubar/view/view_variables");
794 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
795 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
799 on_ui_manager_changed (PsppireDataEditor *de,
800 GParamSpec *pspec UNUSED,
801 PsppireDataWindow *dw)
803 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
809 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
810 g_object_unref (dw->uim);
817 g_object_ref (dw->uim);
818 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
822 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
823 Returns a pointer to the action
826 connect_action (PsppireDataWindow *dw, const char *action_name,
829 GtkAction *action = get_action_assert (dw->builder, action_name);
831 g_signal_connect_swapped (action, "activate", handler, dw);
836 /* Initializes as much of a PsppireDataWindow as we can and must before the
837 dataset has been set.
839 In particular, the 'menu' member is required in case the "filename" property
840 is set before the "dataset" property: otherwise PsppireWindow will try to
841 modify the menu as part of the "filename" property_set() function and end up
842 with a Gtk-CRITICAL since 'menu' is NULL. */
844 psppire_data_window_init (PsppireDataWindow *de)
846 de->builder = builder_new ("data-editor.ui");
848 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
850 PSPPIRE_WINDOW (de)->menu =
851 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
858 psppire_data_window_finish_init (PsppireDataWindow *de,
861 static const struct dataset_callbacks cbs =
863 set_unsaved, /* changed */
864 transformation_change_callback, /* transformations_changed */
871 GtkWidget *box = gtk_vbox_new (FALSE, 0);
874 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
875 de->data_store = psppire_data_store_new (de->dict);
876 psppire_data_store_set_reader (de->data_store, NULL);
878 menubar = get_widget_assert (de->builder, "menubar");
879 hb = get_widget_assert (de->builder, "handlebox1");
880 sb = get_widget_assert (de->builder, "status-bar");
886 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
887 g_signal_connect (de->data_editor, "switch-page",
888 G_CALLBACK (on_switch_page), de);
890 g_signal_connect_swapped (de->data_store, "case-changed",
891 G_CALLBACK (set_unsaved), de);
893 g_signal_connect_swapped (de->data_store, "case-inserted",
894 G_CALLBACK (set_unsaved), de);
896 g_signal_connect_swapped (de->data_store, "cases-deleted",
897 G_CALLBACK (set_unsaved), de);
899 dataset_set_callbacks (de->dataset, &cbs, de);
901 connect_help (de->builder);
903 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
904 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
905 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
906 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
908 gtk_container_add (GTK_CONTAINER (de), box);
910 g_signal_connect (de->dict, "weight-changed",
911 G_CALLBACK (on_weight_change),
914 g_signal_connect (de->dict, "filter-changed",
915 G_CALLBACK (on_filter_change),
918 g_signal_connect (de->dict, "split-changed",
919 G_CALLBACK (on_split_change),
923 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
925 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
927 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
929 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
931 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
933 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
935 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
937 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
939 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
941 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
942 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
943 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
944 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
945 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
946 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
947 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
948 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
949 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
950 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
951 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
952 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
953 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
954 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
955 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
956 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
957 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
958 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
959 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
960 connect_action (de, "runs", G_CALLBACK (runs_dialog));
961 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
962 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
963 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
966 GtkWidget *recent_data =
967 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
969 GtkWidget *recent_files =
970 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
973 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
974 gtk_recent_manager_get_default ());
976 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
977 gtk_recent_manager_get_default ());
979 g_object_set (menu_data, "show-tips", TRUE, NULL);
980 g_object_set (menu_files, "show-tips", TRUE, NULL);
983 GtkRecentFilter *filter = gtk_recent_filter_new ();
985 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
986 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
988 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
990 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
993 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
996 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
999 GtkRecentFilter *filter = gtk_recent_filter_new ();
1001 gtk_recent_filter_add_pattern (filter, "*.sps");
1002 gtk_recent_filter_add_pattern (filter, "*.SPS");
1004 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1006 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1009 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1011 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1015 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1018 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1019 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1021 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1023 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1025 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1027 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1029 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1031 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1033 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1035 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1037 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1039 merge_help_menu (de->ui_manager);
1041 g_signal_connect (de->data_editor, "notify::ui-manager",
1042 G_CALLBACK (on_ui_manager_changed), de);
1043 on_ui_manager_changed (de->data_editor, NULL, de);
1045 gtk_widget_show (GTK_WIDGET (de->data_editor));
1046 gtk_widget_show (box);
1048 ll_push_head (&all_data_windows, &de->ll);
1052 psppire_data_window_dispose (GObject *object)
1054 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1056 if (dw->builder != NULL)
1058 g_object_unref (dw->builder);
1064 g_object_unref (dw->dict);
1070 g_object_unref (dw->data_store);
1071 dw->data_store = NULL;
1074 if (dw->ll.next != NULL)
1076 ll_remove (&dw->ll);
1080 if (G_OBJECT_CLASS (parent_class)->dispose)
1081 G_OBJECT_CLASS (parent_class)->dispose (object);
1085 psppire_data_window_set_property (GObject *object,
1087 const GValue *value,
1090 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1095 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1098 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1104 psppire_data_window_get_property (GObject *object,
1109 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1114 g_value_set_pointer (value, window->dataset);
1117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1123 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1129 ui_string = gtk_ui_manager_get_ui (uim);
1130 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1134 g_return_val_if_fail (merge_id != 0, 0);
1136 list = gtk_ui_manager_get_action_groups (uim);
1137 for (; list != NULL; list = list->next)
1139 GtkActionGroup *action_group = list->data;
1140 GList *actions = gtk_action_group_list_actions (action_group);
1143 for (action = actions; action != NULL; action = action->next)
1145 GtkAction *a = action->data;
1147 if (PSPPIRE_IS_DIALOG_ACTION (a))
1148 g_object_set (a, "manager", pdw->ui_manager, NULL);
1151 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1154 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1155 gtk_ui_manager_get_accel_group (uim));
1161 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1162 GtkUIManager *uim, guint merge_id)
1166 g_return_if_fail (merge_id != 0);
1168 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1170 list = gtk_ui_manager_get_action_groups (uim);
1171 for (; list != NULL; list = list->next)
1173 GtkActionGroup *action_group = list->data;
1174 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1177 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1178 gtk_ui_manager_get_accel_group (uim));
1182 psppire_data_window_new (struct dataset *ds)
1186 if (the_session == NULL)
1187 the_session = session_create ();
1191 static int n_datasets;
1194 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1195 ds = dataset_create (the_session, dataset_name);
1196 free (dataset_name);
1198 assert (dataset_session (ds) == the_session);
1202 psppire_data_window_get_type (),
1203 "description", _("Data Editor"),
1207 if (dataset_name (ds) != NULL)
1208 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1214 psppire_data_window_is_empty (PsppireDataWindow *dw)
1216 return psppire_dict_get_var_cnt (dw->dict) == 0;
1220 psppire_data_window_iface_init (PsppireWindowIface *iface)
1222 iface->save = save_file;
1223 iface->pick_filename = data_pick_filename;
1224 iface->load = load_file;
1228 psppire_default_data_window (void)
1230 if (ll_is_empty (&all_data_windows))
1231 create_data_window ();
1232 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1236 psppire_data_window_set_default (PsppireDataWindow *pdw)
1238 ll_remove (&pdw->ll);
1239 ll_push_head (&all_data_windows, &pdw->ll);
1243 psppire_data_window_undefault (PsppireDataWindow *pdw)
1245 ll_remove (&pdw->ll);
1246 ll_push_tail (&all_data_windows, &pdw->ll);
1250 psppire_data_window_for_dataset (struct dataset *ds)
1252 PsppireDataWindow *pdw;
1254 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1255 if (pdw->dataset == ds)
1262 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1264 PsppireDataWindow *pdw;
1266 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1267 if (pdw->data_store == data_store)
1274 create_data_window (void)
1276 gtk_widget_show (psppire_data_window_new (NULL));
1280 open_data_window (PsppireWindow *victim, const char *file_name)
1284 if (PSPPIRE_IS_DATA_WINDOW (victim)
1285 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1287 window = GTK_WIDGET (victim);
1288 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1291 window = psppire_data_window_new (NULL);
1293 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1294 gtk_widget_show_all (window);