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/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/runs-dialog.h"
48 #include "ui/gui/ks-one-sample-dialog.h"
49 #include "ui/gui/recode-dialog.h"
50 #include "ui/gui/select-cases-dialog.h"
51 #include "ui/gui/split-file-dialog.h"
52 #include "ui/gui/t-test-one-sample.h"
53 #include "ui/gui/t-test-paired-samples.h"
54 #include "ui/gui/text-data-import-dialog.h"
55 #include "ui/gui/transpose-dialog.h"
56 #include "ui/gui/univariate-dialog.h"
57 #include "ui/gui/weight-cases-dialog.h"
58 #include "ui/syntax-gen.h"
60 #include "gl/c-strcase.h"
61 #include "gl/c-strcasestr.h"
62 #include "gl/xvasprintf.h"
65 #define _(msgid) gettext (msgid)
66 #define N_(msgid) msgid
68 struct session *the_session;
69 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
71 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
72 static void psppire_data_window_init (PsppireDataWindow *data_editor);
75 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
77 static void psppire_data_window_dispose (GObject *object);
78 static void psppire_data_window_finalize (GObject *object);
79 static void psppire_data_window_set_property (GObject *object,
83 static void psppire_data_window_get_property (GObject *object,
88 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
89 static void psppire_data_window_remove_ui (PsppireDataWindow *,
90 GtkUIManager *, guint);
93 psppire_data_window_get_type (void)
95 static GType psppire_data_window_type = 0;
97 if (!psppire_data_window_type)
99 static const GTypeInfo psppire_data_window_info =
101 sizeof (PsppireDataWindowClass),
104 (GClassInitFunc)psppire_data_window_class_init,
105 (GClassFinalizeFunc) NULL,
107 sizeof (PsppireDataWindow),
109 (GInstanceInitFunc) psppire_data_window_init,
112 static const GInterfaceInfo window_interface_info =
114 (GInterfaceInitFunc) psppire_data_window_iface_init,
119 psppire_data_window_type =
120 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
121 &psppire_data_window_info, 0);
124 g_type_add_interface_static (psppire_data_window_type,
125 PSPPIRE_TYPE_WINDOW_MODEL,
126 &window_interface_info);
129 return psppire_data_window_type;
132 static GObjectClass *parent_class ;
139 psppire_data_window_class_init (PsppireDataWindowClass *class)
141 GObjectClass *object_class = G_OBJECT_CLASS (class);
143 parent_class = g_type_class_peek_parent (class);
145 object_class->dispose = psppire_data_window_dispose;
146 object_class->finalize = psppire_data_window_finalize;
147 object_class->set_property = psppire_data_window_set_property;
148 object_class->get_property = psppire_data_window_get_property;
150 g_object_class_install_property (
151 object_class, PROP_DATASET,
152 g_param_spec_pointer ("dataset", "Dataset",
153 "'struct datset *' represented by the window",
154 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
157 /* Run the EXECUTE command. */
159 execute (PsppireDataWindow *dw)
161 execute_const_syntax_string (dw, "EXECUTE.");
165 transformation_change_callback (bool transformations_pending,
168 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
170 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
172 GtkWidget *menuitem =
173 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
175 GtkWidget *status_label =
176 get_widget_assert (de->builder, "case-counter-area");
178 gtk_widget_set_sensitive (menuitem, transformations_pending);
181 if ( transformations_pending)
182 gtk_label_set_text (GTK_LABEL (status_label),
183 _("Transformations Pending"));
185 gtk_label_set_text (GTK_LABEL (status_label), "");
188 /* Callback for when the dictionary changes its filter variable */
190 on_filter_change (GObject *o, gint filter_index, gpointer data)
192 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
194 GtkWidget *filter_status_area =
195 get_widget_assert (de->builder, "filter-use-status-area");
197 if ( filter_index == -1 )
199 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
203 PsppireDict *dict = NULL;
204 struct variable *var ;
207 g_object_get (de->data_editor, "dictionary", &dict, NULL);
209 var = psppire_dict_get_variable (dict, filter_index);
211 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
213 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
219 /* Callback for when the dictionary changes its split variables */
221 on_split_change (PsppireDict *dict, gpointer data)
223 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
225 size_t n_split_vars = dict_get_split_cnt (dict->dict);
227 GtkWidget *split_status_area =
228 get_widget_assert (de->builder, "split-file-status-area");
230 if ( n_split_vars == 0 )
232 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
238 const struct variable *const * split_vars =
239 dict_get_split_vars (dict->dict);
241 text = g_string_new (_("Split by "));
243 for (i = 0 ; i < n_split_vars - 1; ++i )
245 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
247 g_string_append (text, var_get_name (split_vars[i]));
249 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
251 g_string_free (text, TRUE);
258 /* Callback for when the dictionary changes its weights */
260 on_weight_change (GObject *o, gint weight_index, gpointer data)
262 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
264 GtkWidget *weight_status_area =
265 get_widget_assert (de->builder, "weight-status-area");
267 if ( weight_index == -1 )
269 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
273 struct variable *var ;
274 PsppireDict *dict = NULL;
277 g_object_get (de->data_editor, "dictionary", &dict, NULL);
279 var = psppire_dict_get_variable (dict, weight_index);
281 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
283 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
291 dump_rm (GtkRecentManager *rm)
293 GList *items = gtk_recent_manager_get_items (rm);
297 g_print ("Recent Items:\n");
298 for (i = items; i; i = i->next)
300 GtkRecentInfo *ri = i->data;
302 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
303 gtk_recent_info_get_short_name (ri),
304 gtk_recent_info_get_mime_type (ri),
305 gtk_recent_info_get_description (ri),
306 gtk_recent_info_get_uri (ri)
310 gtk_recent_info_unref (ri);
318 name_has_por_suffix (const gchar *name)
320 size_t length = strlen (name);
321 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
325 name_has_sav_suffix (const gchar *name)
327 size_t length = strlen (name);
328 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
331 /* Returns true if NAME has a suffix which might denote a PSPP file */
333 name_has_suffix (const gchar *name)
335 return name_has_por_suffix (name) || name_has_sav_suffix (name);
339 load_file (PsppireWindow *de, const gchar *file_name)
341 struct string filename;
342 gchar *utf8_file_name;
343 const char *mime_type;
347 ds_init_empty (&filename);
349 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
351 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
353 g_free (utf8_file_name);
355 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
356 ds_destroy (&filename);
358 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
359 lex_reader_for_string (syntax));
362 mime_type = (name_has_por_suffix (file_name)
363 ? "application/x-spss-por"
364 : "application/x-spss-sav");
366 add_most_recent (file_name, mime_type);
371 /* Save DE to file */
373 save_file (PsppireWindow *w)
375 const gchar *file_name = NULL;
376 gchar *utf8_file_name = NULL;
378 struct string filename ;
379 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
382 file_name = psppire_window_get_filename (w);
384 fnx = g_string_new (file_name);
386 if ( ! name_has_suffix (fnx->str))
388 if ( de->save_as_portable)
389 g_string_append (fnx, ".por");
391 g_string_append (fnx, ".sav");
394 ds_init_empty (&filename);
396 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
398 g_string_free (fnx, TRUE);
400 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
401 g_free (utf8_file_name);
403 syntax = g_strdup_printf ("%s OUTFILE=%s.",
404 de->save_as_portable ? "EXPORT" : "SAVE",
405 ds_cstr (&filename));
407 ds_destroy (&filename);
409 g_free (execute_syntax_string (de, syntax));
414 display_dict (PsppireDataWindow *de)
416 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
420 sysfile_info (PsppireDataWindow *de)
422 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
424 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
426 struct string filename;
428 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
430 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
435 ds_init_empty (&filename);
437 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
439 g_free (utf8_file_name);
441 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
442 g_free (execute_syntax_string (de, syntax));
445 gtk_widget_destroy (dialog);
449 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
451 data_pick_filename (PsppireWindow *window)
453 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
454 GtkFileFilter *filter = gtk_file_filter_new ();
455 GtkWidget *button_sys;
457 gtk_file_chooser_dialog_new (_("Save"),
459 GTK_FILE_CHOOSER_ACTION_SAVE,
460 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
461 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
464 g_object_set (dialog, "local-only", FALSE, NULL);
466 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
467 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
468 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
470 filter = gtk_file_filter_new ();
471 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
472 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
473 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
475 filter = gtk_file_filter_new ();
476 gtk_file_filter_set_name (filter, _("All Files"));
477 gtk_file_filter_add_pattern (filter, "*");
478 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
481 GtkWidget *button_por;
482 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
484 gtk_radio_button_new_with_label (NULL, _("System File"));
487 gtk_radio_button_new_with_label
488 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
491 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
492 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
494 gtk_widget_show_all (vbox);
496 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
499 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
502 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
504 case GTK_RESPONSE_ACCEPT:
509 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
512 de->save_as_portable =
513 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
515 if ( ! name_has_suffix (filename->str))
517 if ( de->save_as_portable)
518 g_string_append (filename, ".por");
520 g_string_append (filename, ".sav");
523 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
525 g_string_free (filename, TRUE);
532 gtk_widget_destroy (dialog);
536 confirm_delete_dataset (PsppireDataWindow *de,
537 const char *old_dataset,
538 const char *new_dataset,
539 const char *existing_dataset)
544 dialog = gtk_message_dialog_new (
545 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
546 _("Delete Existing Dataset?"));
548 gtk_message_dialog_format_secondary_text (
549 GTK_MESSAGE_DIALOG (dialog),
550 _("Renaming \"%s\" to \"%s\" will destroy the existing "
551 "dataset named \"%s\". Are you sure that you want to do this?"),
552 old_dataset, new_dataset, existing_dataset);
554 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
555 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
556 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
559 g_object_set (dialog, "icon-name", "pspp", NULL);
561 result = gtk_dialog_run (GTK_DIALOG (dialog));
563 gtk_widget_destroy (dialog);
565 return result == GTK_RESPONSE_OK;
569 on_rename_dataset (PsppireDataWindow *de)
571 struct dataset *ds = de->dataset;
572 struct session *session = dataset_session (ds);
573 const char *old_name = dataset_name (ds);
574 struct dataset *existing_dataset;
578 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
580 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
584 if (new_name == NULL)
587 existing_dataset = session_lookup_dataset (session, new_name);
588 if (existing_dataset == NULL || existing_dataset == ds
589 || confirm_delete_dataset (de, old_name, new_name,
590 dataset_name (existing_dataset)))
591 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
598 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
600 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
602 if ( gtk_toggle_action_get_active (action))
603 gtk_widget_show (statusbar);
605 gtk_widget_hide (statusbar);
610 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
612 const gboolean grid_visible = gtk_toggle_action_get_active (action);
614 psppire_data_editor_show_grid (de->data_editor, grid_visible);
618 data_view_activate (PsppireDataWindow *de)
620 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
625 variable_view_activate (PsppireDataWindow *de)
627 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
632 fonts_activate (PsppireDataWindow *de)
634 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
635 PangoFontDescription *current_font;
638 gtk_font_selection_dialog_new (_("Font Selection"));
641 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
642 font_name = pango_font_description_to_string (current_font);
644 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
648 gtk_window_set_transient_for (GTK_WINDOW (dialog),
649 GTK_WINDOW (toplevel));
651 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
653 const gchar *font = gtk_font_selection_dialog_get_font_name
654 (GTK_FONT_SELECTION_DIALOG (dialog));
656 PangoFontDescription* font_desc =
657 pango_font_description_from_string (font);
659 psppire_data_editor_set_font (de->data_editor, font_desc);
662 gtk_widget_hide (dialog);
667 /* Callback for the value labels action */
669 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
671 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
675 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
677 psppire_data_editor_split_window (de->data_editor,
678 gtk_toggle_action_get_active (ta));
683 file_quit (PsppireDataWindow *de)
685 /* FIXME: Need to be more intelligent here.
686 Give the user the opportunity to save any unsaved data.
692 on_recent_data_select (GtkMenuShell *menushell,
693 PsppireWindow *window)
698 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
700 file = g_filename_from_uri (uri, NULL, NULL);
704 open_data_window (window, file);
710 charset_from_mime_type (const char *mime_type)
716 if (mime_type == NULL)
719 charset = c_strcasestr (mime_type, "charset=");
727 /* Parse a "quoted-string" as defined by RFC 822. */
728 for (p++; *p != '\0' && *p != '"'; p++)
731 ds_put_byte (&s, *p);
732 else if (*++p != '\0')
733 ds_put_byte (&s, *p);
738 /* Parse a "token" as defined by RFC 2045. */
739 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
740 ds_put_byte (&s, *p++);
742 if (!ds_is_empty (&s))
743 return ds_steal_cstr (&s);
750 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
757 /* Get the file name and its encoding. */
758 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
759 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
760 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
761 gtk_recent_info_unref (item);
763 se = psppire_syntax_window_new (encoding);
767 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
768 gtk_widget_show (se);
770 gtk_widget_destroy (se);
776 set_unsaved (gpointer w)
778 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
782 on_switch_page (PsppireDataEditor *de, GtkNotebookPage *p,
783 gint pagenum, PsppireDataWindow *dw)
785 GtkWidget *page_menu_item;
789 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
791 ? "/ui/menubar/view/view_data"
792 : "/ui/menubar/view/view_variables");
793 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
794 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
798 on_ui_manager_changed (PsppireDataEditor *de,
799 GParamSpec *pspec UNUSED,
800 PsppireDataWindow *dw)
802 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
808 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
809 g_object_unref (dw->uim);
816 g_object_ref (dw->uim);
817 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
821 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
822 Returns a pointer to the action
825 connect_action (PsppireDataWindow *dw, const char *action_name,
828 GtkAction *action = get_action_assert (dw->builder, action_name);
830 g_signal_connect_swapped (action, "activate", handler, dw);
835 /* Only a data file with at least one variable can be saved. */
837 enable_save (PsppireDataWindow *dw)
839 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
841 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
843 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
847 /* Initializes as much of a PsppireDataWindow as we can and must before the
848 dataset has been set.
850 In particular, the 'menu' member is required in case the "filename" property
851 is set before the "dataset" property: otherwise PsppireWindow will try to
852 modify the menu as part of the "filename" property_set() function and end up
853 with a Gtk-CRITICAL since 'menu' is NULL. */
855 psppire_data_window_init (PsppireDataWindow *de)
857 de->builder = builder_new ("data-editor.ui");
859 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
861 PSPPIRE_WINDOW (de)->menu =
862 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
869 psppire_data_window_finish_init (PsppireDataWindow *de,
872 static const struct dataset_callbacks cbs =
874 set_unsaved, /* changed */
875 transformation_change_callback, /* transformations_changed */
882 GtkWidget *box = gtk_vbox_new (FALSE, 0);
885 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
886 de->data_store = psppire_data_store_new (de->dict);
887 psppire_data_store_set_reader (de->data_store, NULL);
889 menubar = get_widget_assert (de->builder, "menubar");
890 hb = get_widget_assert (de->builder, "handlebox1");
891 sb = get_widget_assert (de->builder, "status-bar");
897 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
898 g_signal_connect (de->data_editor, "switch-page",
899 G_CALLBACK (on_switch_page), de);
901 g_signal_connect_swapped (de->data_store, "case-changed",
902 G_CALLBACK (set_unsaved), de);
904 g_signal_connect_swapped (de->data_store, "case-inserted",
905 G_CALLBACK (set_unsaved), de);
907 g_signal_connect_swapped (de->data_store, "cases-deleted",
908 G_CALLBACK (set_unsaved), de);
910 dataset_set_callbacks (de->dataset, &cbs, de);
912 connect_help (de->builder);
914 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
915 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
916 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
917 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
919 gtk_container_add (GTK_CONTAINER (de), box);
921 g_signal_connect (de->dict, "weight-changed",
922 G_CALLBACK (on_weight_change),
925 g_signal_connect (de->dict, "filter-changed",
926 G_CALLBACK (on_filter_change),
929 g_signal_connect (de->dict, "split-changed",
930 G_CALLBACK (on_split_change),
933 g_signal_connect_swapped (de->dict, "backend-changed",
934 G_CALLBACK (enable_save), de);
935 g_signal_connect_swapped (de->dict, "variable-inserted",
936 G_CALLBACK (enable_save), de);
937 g_signal_connect_swapped (de->dict, "variable-deleted",
938 G_CALLBACK (enable_save), de);
941 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
943 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
945 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
947 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
949 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
951 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
953 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
955 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
957 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
959 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
960 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
961 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
962 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
963 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
964 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
965 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
966 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
967 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
968 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
969 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
970 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
971 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
972 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
973 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
974 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
975 connect_action (de, "runs", G_CALLBACK (runs_dialog));
976 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
977 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
978 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
981 GtkWidget *recent_data =
982 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
984 GtkWidget *recent_files =
985 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
988 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
989 gtk_recent_manager_get_default ());
991 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
992 gtk_recent_manager_get_default ());
994 g_object_set (menu_data, "show-tips", TRUE, NULL);
995 g_object_set (menu_files, "show-tips", TRUE, NULL);
998 GtkRecentFilter *filter = gtk_recent_filter_new ();
1000 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1001 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1003 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1005 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1008 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1011 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1014 GtkRecentFilter *filter = gtk_recent_filter_new ();
1016 gtk_recent_filter_add_pattern (filter, "*.sps");
1017 gtk_recent_filter_add_pattern (filter, "*.SPS");
1019 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1021 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1024 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1026 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1030 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1033 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1034 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1036 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1038 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1040 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1042 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1044 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1046 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1048 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1050 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1052 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1054 merge_help_menu (de->ui_manager);
1056 g_signal_connect (de->data_editor, "notify::ui-manager",
1057 G_CALLBACK (on_ui_manager_changed), de);
1058 on_ui_manager_changed (de->data_editor, NULL, de);
1060 gtk_widget_show (GTK_WIDGET (de->data_editor));
1061 gtk_widget_show (box);
1063 ll_push_head (&all_data_windows, &de->ll);
1067 psppire_data_window_dispose (GObject *object)
1069 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1073 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1074 g_object_unref (dw->uim);
1078 if (dw->builder != NULL)
1080 g_object_unref (dw->builder);
1086 g_object_unref (dw->dict);
1092 g_object_unref (dw->data_store);
1093 dw->data_store = NULL;
1096 if (dw->ll.next != NULL)
1098 ll_remove (&dw->ll);
1102 if (G_OBJECT_CLASS (parent_class)->dispose)
1103 G_OBJECT_CLASS (parent_class)->dispose (object);
1107 psppire_data_window_finalize (GObject *object)
1109 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1113 struct dataset *dataset = dw->dataset;
1114 struct session *session = dataset_session (dataset);
1118 dataset_set_callbacks (dataset, NULL, NULL);
1119 session_set_active_dataset (session, NULL);
1120 dataset_destroy (dataset);
1123 if (G_OBJECT_CLASS (parent_class)->finalize)
1124 G_OBJECT_CLASS (parent_class)->finalize (object);
1128 psppire_data_window_set_property (GObject *object,
1130 const GValue *value,
1133 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1138 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1141 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1147 psppire_data_window_get_property (GObject *object,
1152 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1157 g_value_set_pointer (value, window->dataset);
1160 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1166 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1172 ui_string = gtk_ui_manager_get_ui (uim);
1173 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1177 g_return_val_if_fail (merge_id != 0, 0);
1179 list = gtk_ui_manager_get_action_groups (uim);
1180 for (; list != NULL; list = list->next)
1182 GtkActionGroup *action_group = list->data;
1183 GList *actions = gtk_action_group_list_actions (action_group);
1186 for (action = actions; action != NULL; action = action->next)
1188 GtkAction *a = action->data;
1190 if (PSPPIRE_IS_DIALOG_ACTION (a))
1191 g_object_set (a, "manager", pdw->ui_manager, NULL);
1194 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1197 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1198 gtk_ui_manager_get_accel_group (uim));
1204 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1205 GtkUIManager *uim, guint merge_id)
1209 g_return_if_fail (merge_id != 0);
1211 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1213 list = gtk_ui_manager_get_action_groups (uim);
1214 for (; list != NULL; list = list->next)
1216 GtkActionGroup *action_group = list->data;
1217 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1220 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1221 gtk_ui_manager_get_accel_group (uim));
1225 psppire_data_window_new (struct dataset *ds)
1229 if (the_session == NULL)
1230 the_session = session_create ();
1234 char *dataset_name = session_generate_dataset_name (the_session);
1235 ds = dataset_create (the_session, dataset_name);
1236 free (dataset_name);
1238 assert (dataset_session (ds) == the_session);
1242 psppire_data_window_get_type (),
1243 "description", _("Data Editor"),
1247 if (dataset_name (ds) != NULL)
1248 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1254 psppire_data_window_is_empty (PsppireDataWindow *dw)
1256 return psppire_dict_get_var_cnt (dw->dict) == 0;
1260 psppire_data_window_iface_init (PsppireWindowIface *iface)
1262 iface->save = save_file;
1263 iface->pick_filename = data_pick_filename;
1264 iface->load = load_file;
1268 psppire_default_data_window (void)
1270 if (ll_is_empty (&all_data_windows))
1271 create_data_window ();
1272 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1276 psppire_data_window_set_default (PsppireDataWindow *pdw)
1278 ll_remove (&pdw->ll);
1279 ll_push_head (&all_data_windows, &pdw->ll);
1283 psppire_data_window_undefault (PsppireDataWindow *pdw)
1285 ll_remove (&pdw->ll);
1286 ll_push_tail (&all_data_windows, &pdw->ll);
1290 psppire_data_window_for_dataset (struct dataset *ds)
1292 PsppireDataWindow *pdw;
1294 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1295 if (pdw->dataset == ds)
1302 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1304 PsppireDataWindow *pdw;
1306 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1307 if (pdw->data_store == data_store)
1314 create_data_window (void)
1316 gtk_widget_show (psppire_data_window_new (NULL));
1320 open_data_window (PsppireWindow *victim, const char *file_name)
1324 if (PSPPIRE_IS_DATA_WINDOW (victim)
1325 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1327 window = GTK_WIDGET (victim);
1328 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1331 window = psppire_data_window_new (NULL);
1333 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1334 gtk_widget_show_all (window);