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, gpointer syn)
341 const char *mime_type = NULL;
342 gchar *syntax = NULL;
347 gchar *utf8_file_name;
348 struct string filename;
349 ds_init_empty (&filename);
351 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
353 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
355 g_free (utf8_file_name);
357 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
358 ds_destroy (&filename);
366 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
367 lex_reader_for_string (syntax));
370 if (ok && syn == NULL)
372 if (name_has_por_suffix (file_name))
373 mime_type = "application/x-spss-por";
374 else if (name_has_sav_suffix (file_name))
375 mime_type = "application/x-spss-sav";
377 add_most_recent (file_name, mime_type);
383 /* Save DE to file */
385 save_file (PsppireWindow *w)
387 const gchar *file_name = NULL;
388 gchar *utf8_file_name = NULL;
390 struct string filename ;
391 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
394 file_name = psppire_window_get_filename (w);
396 fnx = g_string_new (file_name);
398 if ( ! name_has_suffix (fnx->str))
400 if ( de->save_as_portable)
401 g_string_append (fnx, ".por");
403 g_string_append (fnx, ".sav");
406 ds_init_empty (&filename);
408 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
410 g_string_free (fnx, TRUE);
412 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
413 g_free (utf8_file_name);
415 syntax = g_strdup_printf ("%s OUTFILE=%s.",
416 de->save_as_portable ? "EXPORT" : "SAVE",
417 ds_cstr (&filename));
419 ds_destroy (&filename);
421 g_free (execute_syntax_string (de, syntax));
426 display_dict (PsppireDataWindow *de)
428 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
432 sysfile_info (PsppireDataWindow *de)
434 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
436 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
438 struct string filename;
440 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
442 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
447 ds_init_empty (&filename);
449 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
451 g_free (utf8_file_name);
453 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
454 g_free (execute_syntax_string (de, syntax));
457 gtk_widget_destroy (dialog);
461 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
463 data_pick_filename (PsppireWindow *window)
465 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
466 GtkFileFilter *filter = gtk_file_filter_new ();
467 GtkWidget *button_sys;
469 gtk_file_chooser_dialog_new (_("Save"),
471 GTK_FILE_CHOOSER_ACTION_SAVE,
472 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
473 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
476 g_object_set (dialog, "local-only", FALSE, NULL);
478 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
479 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
480 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
482 filter = gtk_file_filter_new ();
483 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
484 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
485 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
487 filter = gtk_file_filter_new ();
488 gtk_file_filter_set_name (filter, _("All Files"));
489 gtk_file_filter_add_pattern (filter, "*");
490 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
493 GtkWidget *button_por;
494 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
496 gtk_radio_button_new_with_label (NULL, _("System File"));
499 gtk_radio_button_new_with_label
500 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
503 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
504 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
506 gtk_widget_show_all (vbox);
508 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
511 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
514 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
516 case GTK_RESPONSE_ACCEPT:
521 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
524 de->save_as_portable =
525 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
527 if ( ! name_has_suffix (filename->str))
529 if ( de->save_as_portable)
530 g_string_append (filename, ".por");
532 g_string_append (filename, ".sav");
535 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
537 g_string_free (filename, TRUE);
544 gtk_widget_destroy (dialog);
548 confirm_delete_dataset (PsppireDataWindow *de,
549 const char *old_dataset,
550 const char *new_dataset,
551 const char *existing_dataset)
556 dialog = gtk_message_dialog_new (
557 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
558 _("Delete Existing Dataset?"));
560 gtk_message_dialog_format_secondary_text (
561 GTK_MESSAGE_DIALOG (dialog),
562 _("Renaming \"%s\" to \"%s\" will destroy the existing "
563 "dataset named \"%s\". Are you sure that you want to do this?"),
564 old_dataset, new_dataset, existing_dataset);
566 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
567 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
568 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
571 g_object_set (dialog, "icon-name", "pspp", NULL);
573 result = gtk_dialog_run (GTK_DIALOG (dialog));
575 gtk_widget_destroy (dialog);
577 return result == GTK_RESPONSE_OK;
581 on_rename_dataset (PsppireDataWindow *de)
583 struct dataset *ds = de->dataset;
584 struct session *session = dataset_session (ds);
585 const char *old_name = dataset_name (ds);
586 struct dataset *existing_dataset;
590 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
592 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
596 if (new_name == NULL)
599 existing_dataset = session_lookup_dataset (session, new_name);
600 if (existing_dataset == NULL || existing_dataset == ds
601 || confirm_delete_dataset (de, old_name, new_name,
602 dataset_name (existing_dataset)))
603 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
610 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
612 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
614 if ( gtk_toggle_action_get_active (action))
615 gtk_widget_show (statusbar);
617 gtk_widget_hide (statusbar);
622 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
624 const gboolean grid_visible = gtk_toggle_action_get_active (action);
626 psppire_data_editor_show_grid (de->data_editor, grid_visible);
630 data_view_activate (PsppireDataWindow *de)
632 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
637 variable_view_activate (PsppireDataWindow *de)
639 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
644 fonts_activate (PsppireDataWindow *de)
646 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
647 GtkWidget *dialog = gtk_font_selection_dialog_new (_("Font Selection"));
648 GtkStyle *style = gtk_widget_get_style (GTK_WIDGET(de->data_editor));
649 PangoFontDescription *current_font = style->font_desc;
650 gchar *font_name = pango_font_description_to_string (current_font);
652 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
656 gtk_window_set_transient_for (GTK_WINDOW (dialog),
657 GTK_WINDOW (toplevel));
659 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
661 const gchar *font = gtk_font_selection_dialog_get_font_name
662 (GTK_FONT_SELECTION_DIALOG (dialog));
664 PangoFontDescription* font_desc =
665 pango_font_description_from_string (font);
667 psppire_data_editor_set_font (de->data_editor, font_desc);
670 gtk_widget_hide (dialog);
675 /* Callback for the value labels action */
677 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
679 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
683 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
685 psppire_data_editor_split_window (de->data_editor,
686 gtk_toggle_action_get_active (ta));
691 file_quit (PsppireDataWindow *de)
693 /* FIXME: Need to be more intelligent here.
694 Give the user the opportunity to save any unsaved data.
700 on_recent_data_select (GtkMenuShell *menushell,
701 PsppireWindow *window)
706 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
708 file = g_filename_from_uri (uri, NULL, NULL);
712 open_data_window (window, file, NULL);
718 charset_from_mime_type (const char *mime_type)
724 if (mime_type == NULL)
727 charset = c_strcasestr (mime_type, "charset=");
735 /* Parse a "quoted-string" as defined by RFC 822. */
736 for (p++; *p != '\0' && *p != '"'; p++)
739 ds_put_byte (&s, *p);
740 else if (*++p != '\0')
741 ds_put_byte (&s, *p);
746 /* Parse a "token" as defined by RFC 2045. */
747 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
748 ds_put_byte (&s, *p++);
750 if (!ds_is_empty (&s))
751 return ds_steal_cstr (&s);
758 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
765 /* Get the file name and its encoding. */
766 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
767 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
768 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
769 gtk_recent_info_unref (item);
771 se = psppire_syntax_window_new (encoding);
775 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
776 gtk_widget_show (se);
778 gtk_widget_destroy (se);
784 set_unsaved (gpointer w)
786 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
790 on_switch_page (PsppireDataEditor *de, gpointer p,
791 gint pagenum, PsppireDataWindow *dw)
793 GtkWidget *page_menu_item;
797 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
799 ? "/ui/menubar/view/view_data"
800 : "/ui/menubar/view/view_variables");
801 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
802 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
806 on_ui_manager_changed (PsppireDataEditor *de,
807 GParamSpec *pspec UNUSED,
808 PsppireDataWindow *dw)
810 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
816 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
817 g_object_unref (dw->uim);
824 g_object_ref (dw->uim);
825 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
829 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
830 Returns a pointer to the action
833 connect_action (PsppireDataWindow *dw, const char *action_name,
836 GtkAction *action = get_action_assert (dw->builder, action_name);
838 g_signal_connect_swapped (action, "activate", handler, dw);
843 /* Only a data file with at least one variable can be saved. */
845 enable_save (PsppireDataWindow *dw)
847 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
849 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
851 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
855 /* Initializes as much of a PsppireDataWindow as we can and must before the
856 dataset has been set.
858 In particular, the 'menu' member is required in case the "filename" property
859 is set before the "dataset" property: otherwise PsppireWindow will try to
860 modify the menu as part of the "filename" property_set() function and end up
861 with a Gtk-CRITICAL since 'menu' is NULL. */
863 psppire_data_window_init (PsppireDataWindow *de)
866 de->builder = builder_new ("data-editor.ui");
868 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
870 w = gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all");
872 PSPPIRE_WINDOW (de)->menu = GTK_MENU_SHELL (gtk_widget_get_parent (w));
879 psppire_data_window_finish_init (PsppireDataWindow *de,
882 static const struct dataset_callbacks cbs =
884 set_unsaved, /* changed */
885 transformation_change_callback, /* transformations_changed */
892 GtkWidget *box = gtk_vbox_new (FALSE, 0);
895 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
896 de->data_store = psppire_data_store_new (de->dict);
897 psppire_data_store_set_reader (de->data_store, NULL);
899 menubar = get_widget_assert (de->builder, "menubar");
900 hb = get_widget_assert (de->builder, "handlebox1");
901 sb = get_widget_assert (de->builder, "status-bar");
907 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
908 g_signal_connect (de->data_editor, "switch-page",
909 G_CALLBACK (on_switch_page), de);
911 g_signal_connect_swapped (de->data_store, "case-changed",
912 G_CALLBACK (set_unsaved), de);
914 g_signal_connect_swapped (de->data_store, "case-inserted",
915 G_CALLBACK (set_unsaved), de);
917 g_signal_connect_swapped (de->data_store, "cases-deleted",
918 G_CALLBACK (set_unsaved), de);
920 dataset_set_callbacks (de->dataset, &cbs, de);
922 connect_help (de->builder);
924 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
925 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
926 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
927 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
929 gtk_container_add (GTK_CONTAINER (de), box);
931 g_signal_connect (de->dict, "weight-changed",
932 G_CALLBACK (on_weight_change),
935 g_signal_connect (de->dict, "filter-changed",
936 G_CALLBACK (on_filter_change),
939 g_signal_connect (de->dict, "split-changed",
940 G_CALLBACK (on_split_change),
943 g_signal_connect_swapped (de->dict, "backend-changed",
944 G_CALLBACK (enable_save), de);
945 g_signal_connect_swapped (de->dict, "variable-inserted",
946 G_CALLBACK (enable_save), de);
947 g_signal_connect_swapped (de->dict, "variable-deleted",
948 G_CALLBACK (enable_save), de);
951 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
953 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
955 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
957 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
959 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
961 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
963 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
965 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
967 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
969 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
970 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
971 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
972 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
973 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
974 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
975 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
976 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
977 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
978 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
979 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
980 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
981 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
982 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
983 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
984 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
985 connect_action (de, "runs", G_CALLBACK (runs_dialog));
986 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
987 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
988 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
991 GtkWidget *recent_data =
992 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
994 GtkWidget *recent_files =
995 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
998 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
999 gtk_recent_manager_get_default ());
1001 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1002 gtk_recent_manager_get_default ());
1004 g_object_set (menu_data, "show-tips", TRUE, NULL);
1005 g_object_set (menu_files, "show-tips", TRUE, NULL);
1008 GtkRecentFilter *filter = gtk_recent_filter_new ();
1010 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1011 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1013 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1015 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1018 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1021 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1024 GtkRecentFilter *filter = gtk_recent_filter_new ();
1026 gtk_recent_filter_add_pattern (filter, "*.sps");
1027 gtk_recent_filter_add_pattern (filter, "*.SPS");
1029 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1031 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1034 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1036 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1040 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1043 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1044 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1046 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1048 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1050 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1052 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1054 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1056 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1058 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1060 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1062 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1064 merge_help_menu (de->ui_manager);
1066 g_signal_connect (de->data_editor, "notify::ui-manager",
1067 G_CALLBACK (on_ui_manager_changed), de);
1068 on_ui_manager_changed (de->data_editor, NULL, de);
1070 gtk_widget_show (GTK_WIDGET (de->data_editor));
1071 gtk_widget_show (box);
1073 ll_push_head (&all_data_windows, &de->ll);
1077 psppire_data_window_dispose (GObject *object)
1079 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1083 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1084 g_object_unref (dw->uim);
1088 if (dw->builder != NULL)
1090 g_object_unref (dw->builder);
1096 g_object_unref (dw->dict);
1102 g_object_unref (dw->data_store);
1103 dw->data_store = NULL;
1106 if (dw->ll.next != NULL)
1108 ll_remove (&dw->ll);
1112 if (G_OBJECT_CLASS (parent_class)->dispose)
1113 G_OBJECT_CLASS (parent_class)->dispose (object);
1117 psppire_data_window_finalize (GObject *object)
1119 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1123 struct dataset *dataset = dw->dataset;
1124 struct session *session = dataset_session (dataset);
1128 dataset_set_callbacks (dataset, NULL, NULL);
1129 session_set_active_dataset (session, NULL);
1130 dataset_destroy (dataset);
1133 if (G_OBJECT_CLASS (parent_class)->finalize)
1134 G_OBJECT_CLASS (parent_class)->finalize (object);
1138 psppire_data_window_set_property (GObject *object,
1140 const GValue *value,
1143 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1148 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1157 psppire_data_window_get_property (GObject *object,
1162 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1167 g_value_set_pointer (value, window->dataset);
1170 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1176 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1182 ui_string = gtk_ui_manager_get_ui (uim);
1183 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1187 g_return_val_if_fail (merge_id != 0, 0);
1189 list = gtk_ui_manager_get_action_groups (uim);
1190 for (; list != NULL; list = list->next)
1192 GtkActionGroup *action_group = list->data;
1193 GList *actions = gtk_action_group_list_actions (action_group);
1196 for (action = actions; action != NULL; action = action->next)
1198 GtkAction *a = action->data;
1200 if (PSPPIRE_IS_DIALOG_ACTION (a))
1201 g_object_set (a, "manager", pdw->ui_manager, NULL);
1204 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1207 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1208 gtk_ui_manager_get_accel_group (uim));
1214 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1215 GtkUIManager *uim, guint merge_id)
1219 g_return_if_fail (merge_id != 0);
1221 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1223 list = gtk_ui_manager_get_action_groups (uim);
1224 for (; list != NULL; list = list->next)
1226 GtkActionGroup *action_group = list->data;
1227 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1230 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1231 gtk_ui_manager_get_accel_group (uim));
1235 psppire_data_window_new (struct dataset *ds)
1239 if (the_session == NULL)
1240 the_session = session_create ();
1244 char *dataset_name = session_generate_dataset_name (the_session);
1245 ds = dataset_create (the_session, dataset_name);
1246 free (dataset_name);
1248 assert (dataset_session (ds) == the_session);
1252 psppire_data_window_get_type (),
1253 "description", _("Data Editor"),
1257 if (dataset_name (ds) != NULL)
1258 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1264 psppire_data_window_is_empty (PsppireDataWindow *dw)
1266 return psppire_dict_get_var_cnt (dw->dict) == 0;
1270 psppire_data_window_iface_init (PsppireWindowIface *iface)
1272 iface->save = save_file;
1273 iface->pick_filename = data_pick_filename;
1274 iface->load = load_file;
1278 psppire_default_data_window (void)
1280 if (ll_is_empty (&all_data_windows))
1281 create_data_window ();
1282 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1286 psppire_data_window_set_default (PsppireDataWindow *pdw)
1288 ll_remove (&pdw->ll);
1289 ll_push_head (&all_data_windows, &pdw->ll);
1293 psppire_data_window_undefault (PsppireDataWindow *pdw)
1295 ll_remove (&pdw->ll);
1296 ll_push_tail (&all_data_windows, &pdw->ll);
1300 psppire_data_window_for_dataset (struct dataset *ds)
1302 PsppireDataWindow *pdw;
1304 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1305 if (pdw->dataset == ds)
1312 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1314 PsppireDataWindow *pdw;
1316 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1317 if (pdw->data_store == data_store)
1324 create_data_window (void)
1326 gtk_widget_show (psppire_data_window_new (NULL));
1330 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1334 if (PSPPIRE_IS_DATA_WINDOW (victim)
1335 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1337 window = GTK_WIDGET (victim);
1338 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1341 window = psppire_data_window_new (NULL);
1343 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1344 gtk_widget_show_all (window);