1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/builder-wrapper.h"
30 #include "ui/gui/comments-dialog.h"
31 #include "ui/gui/compute-dialog.h"
32 #include "ui/gui/count-dialog.h"
33 #include "ui/gui/entry-dialog.h"
34 #include "ui/gui/executor.h"
35 #include "ui/gui/help-menu.h"
36 #include "ui/gui/helper.h"
37 #include "ui/gui/helper.h"
38 #include "ui/gui/k-related-dialog.h"
39 #include "ui/gui/npar-two-sample-related.h"
40 #include "ui/gui/oneway-anova-dialog.h"
41 #include "ui/gui/psppire-data-window.h"
42 #include "ui/gui/psppire-dialog-action.h"
43 #include "ui/gui/psppire-syntax-window.h"
44 #include "ui/gui/psppire-window.h"
45 #include "ui/gui/psppire.h"
46 #include "ui/gui/ks-one-sample-dialog.h"
47 #include "ui/gui/recode-dialog.h"
48 #include "ui/gui/select-cases-dialog.h"
49 #include "ui/gui/split-file-dialog.h"
50 #include "ui/gui/t-test-one-sample.h"
51 #include "ui/gui/t-test-paired-samples.h"
52 #include "ui/gui/text-data-import-dialog.h"
53 #include "ui/gui/weight-cases-dialog.h"
54 #include "ui/syntax-gen.h"
56 #include "gl/c-strcase.h"
57 #include "gl/c-strcasestr.h"
58 #include "gl/xvasprintf.h"
61 #define _(msgid) gettext (msgid)
62 #define N_(msgid) msgid
64 struct session *the_session;
65 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
67 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
68 static void psppire_data_window_init (PsppireDataWindow *data_editor);
71 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
73 static void psppire_data_window_dispose (GObject *object);
74 static void psppire_data_window_finalize (GObject *object);
75 static void psppire_data_window_set_property (GObject *object,
79 static void psppire_data_window_get_property (GObject *object,
84 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
85 static void psppire_data_window_remove_ui (PsppireDataWindow *,
86 GtkUIManager *, guint);
89 psppire_data_window_get_type (void)
91 static GType psppire_data_window_type = 0;
93 if (!psppire_data_window_type)
95 static const GTypeInfo psppire_data_window_info =
97 sizeof (PsppireDataWindowClass),
100 (GClassInitFunc)psppire_data_window_class_init,
101 (GClassFinalizeFunc) NULL,
103 sizeof (PsppireDataWindow),
105 (GInstanceInitFunc) psppire_data_window_init,
108 static const GInterfaceInfo window_interface_info =
110 (GInterfaceInitFunc) psppire_data_window_iface_init,
115 psppire_data_window_type =
116 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
117 &psppire_data_window_info, 0);
120 g_type_add_interface_static (psppire_data_window_type,
121 PSPPIRE_TYPE_WINDOW_MODEL,
122 &window_interface_info);
125 return psppire_data_window_type;
128 static GObjectClass *parent_class ;
135 psppire_data_window_class_init (PsppireDataWindowClass *class)
137 GObjectClass *object_class = G_OBJECT_CLASS (class);
139 parent_class = g_type_class_peek_parent (class);
141 object_class->dispose = psppire_data_window_dispose;
142 object_class->finalize = psppire_data_window_finalize;
143 object_class->set_property = psppire_data_window_set_property;
144 object_class->get_property = psppire_data_window_get_property;
146 g_object_class_install_property (
147 object_class, PROP_DATASET,
148 g_param_spec_pointer ("dataset", "Dataset",
149 "'struct datset *' represented by the window",
150 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
153 /* Run the EXECUTE command. */
155 execute (PsppireDataWindow *dw)
157 execute_const_syntax_string (dw, "EXECUTE.");
161 transformation_change_callback (bool transformations_pending,
164 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
166 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
168 GtkWidget *menuitem =
169 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
171 GtkWidget *status_label =
172 get_widget_assert (de->builder, "case-counter-area");
174 gtk_widget_set_sensitive (menuitem, transformations_pending);
177 if ( transformations_pending)
178 gtk_label_set_text (GTK_LABEL (status_label),
179 _("Transformations Pending"));
181 gtk_label_set_text (GTK_LABEL (status_label), "");
184 /* Callback for when the dictionary changes its filter variable */
186 on_filter_change (GObject *o, gint filter_index, gpointer data)
188 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
190 GtkWidget *filter_status_area =
191 get_widget_assert (de->builder, "filter-use-status-area");
193 if ( filter_index == -1 )
195 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
199 PsppireDict *dict = NULL;
200 struct variable *var ;
203 g_object_get (de->data_editor, "dictionary", &dict, NULL);
205 var = psppire_dict_get_variable (dict, filter_index);
207 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
209 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
215 /* Callback for when the dictionary changes its split variables */
217 on_split_change (PsppireDict *dict, gpointer data)
219 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
221 size_t n_split_vars = dict_get_split_cnt (dict->dict);
223 GtkWidget *split_status_area =
224 get_widget_assert (de->builder, "split-file-status-area");
226 if ( n_split_vars == 0 )
228 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
234 const struct variable *const * split_vars =
235 dict_get_split_vars (dict->dict);
237 text = g_string_new (_("Split by "));
239 for (i = 0 ; i < n_split_vars - 1; ++i )
241 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
243 g_string_append (text, var_get_name (split_vars[i]));
245 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
247 g_string_free (text, TRUE);
254 /* Callback for when the dictionary changes its weights */
256 on_weight_change (GObject *o, gint weight_index, gpointer data)
258 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
260 GtkWidget *weight_status_area =
261 get_widget_assert (de->builder, "weight-status-area");
263 if ( weight_index == -1 )
265 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
269 struct variable *var ;
270 PsppireDict *dict = NULL;
273 g_object_get (de->data_editor, "dictionary", &dict, NULL);
275 var = psppire_dict_get_variable (dict, weight_index);
277 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
279 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
287 dump_rm (GtkRecentManager *rm)
289 GList *items = gtk_recent_manager_get_items (rm);
293 g_print ("Recent Items:\n");
294 for (i = items; i; i = i->next)
296 GtkRecentInfo *ri = i->data;
298 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
299 gtk_recent_info_get_short_name (ri),
300 gtk_recent_info_get_mime_type (ri),
301 gtk_recent_info_get_description (ri),
302 gtk_recent_info_get_uri (ri)
306 gtk_recent_info_unref (ri);
314 name_has_por_suffix (const gchar *name)
316 size_t length = strlen (name);
317 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
321 name_has_sav_suffix (const gchar *name)
323 size_t length = strlen (name);
324 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
327 /* Returns true if NAME has a suffix which might denote a PSPP file */
329 name_has_suffix (const gchar *name)
331 return name_has_por_suffix (name) || name_has_sav_suffix (name);
335 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
337 const char *mime_type = NULL;
338 gchar *syntax = NULL;
343 gchar *utf8_file_name;
344 struct string filename;
345 ds_init_empty (&filename);
347 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
349 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
351 g_free (utf8_file_name);
353 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
354 ds_destroy (&filename);
362 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
363 lex_reader_for_string (syntax));
366 if (ok && syn == NULL)
368 if (name_has_por_suffix (file_name))
369 mime_type = "application/x-spss-por";
370 else if (name_has_sav_suffix (file_name))
371 mime_type = "application/x-spss-sav";
373 add_most_recent (file_name, mime_type);
379 /* Save DE to file */
381 save_file (PsppireWindow *w)
383 const gchar *file_name = NULL;
384 gchar *utf8_file_name = NULL;
386 struct string filename ;
387 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
390 file_name = psppire_window_get_filename (w);
392 fnx = g_string_new (file_name);
394 if ( ! name_has_suffix (fnx->str))
396 if ( de->save_as_portable)
397 g_string_append (fnx, ".por");
399 g_string_append (fnx, ".sav");
402 ds_init_empty (&filename);
404 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
406 g_string_free (fnx, TRUE);
408 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
409 g_free (utf8_file_name);
411 syntax = g_strdup_printf ("%s OUTFILE=%s.",
412 de->save_as_portable ? "EXPORT" : "SAVE",
413 ds_cstr (&filename));
415 ds_destroy (&filename);
417 g_free (execute_syntax_string (de, syntax));
422 display_dict (PsppireDataWindow *de)
424 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
428 sysfile_info (PsppireDataWindow *de)
430 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
432 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
434 struct string filename;
436 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
438 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
443 ds_init_empty (&filename);
445 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
447 g_free (utf8_file_name);
449 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
450 g_free (execute_syntax_string (de, syntax));
453 gtk_widget_destroy (dialog);
457 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
459 data_pick_filename (PsppireWindow *window)
461 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
462 GtkFileFilter *filter = gtk_file_filter_new ();
463 GtkWidget *button_sys;
465 gtk_file_chooser_dialog_new (_("Save"),
467 GTK_FILE_CHOOSER_ACTION_SAVE,
468 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
469 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
472 g_object_set (dialog, "local-only", FALSE, NULL);
474 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
475 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
476 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
478 filter = gtk_file_filter_new ();
479 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
480 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
481 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
483 filter = gtk_file_filter_new ();
484 gtk_file_filter_set_name (filter, _("All Files"));
485 gtk_file_filter_add_pattern (filter, "*");
486 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
489 GtkWidget *button_por;
490 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
492 gtk_radio_button_new_with_label (NULL, _("System File"));
495 gtk_radio_button_new_with_label
496 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
499 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
500 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
502 gtk_widget_show_all (vbox);
504 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
507 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
510 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
512 case GTK_RESPONSE_ACCEPT:
517 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
520 de->save_as_portable =
521 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
523 if ( ! name_has_suffix (filename->str))
525 if ( de->save_as_portable)
526 g_string_append (filename, ".por");
528 g_string_append (filename, ".sav");
531 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
533 g_string_free (filename, TRUE);
540 gtk_widget_destroy (dialog);
544 confirm_delete_dataset (PsppireDataWindow *de,
545 const char *old_dataset,
546 const char *new_dataset,
547 const char *existing_dataset)
552 dialog = gtk_message_dialog_new (
553 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
554 _("Delete Existing Dataset?"));
556 gtk_message_dialog_format_secondary_text (
557 GTK_MESSAGE_DIALOG (dialog),
558 _("Renaming \"%s\" to \"%s\" will destroy the existing "
559 "dataset named \"%s\". Are you sure that you want to do this?"),
560 old_dataset, new_dataset, existing_dataset);
562 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
563 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
564 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
567 g_object_set (dialog, "icon-name", "pspp", NULL);
569 result = gtk_dialog_run (GTK_DIALOG (dialog));
571 gtk_widget_destroy (dialog);
573 return result == GTK_RESPONSE_OK;
577 on_rename_dataset (PsppireDataWindow *de)
579 struct dataset *ds = de->dataset;
580 struct session *session = dataset_session (ds);
581 const char *old_name = dataset_name (ds);
582 struct dataset *existing_dataset;
586 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
588 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
592 if (new_name == NULL)
595 existing_dataset = session_lookup_dataset (session, new_name);
596 if (existing_dataset == NULL || existing_dataset == ds
597 || confirm_delete_dataset (de, old_name, new_name,
598 dataset_name (existing_dataset)))
599 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
606 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
608 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
610 if ( gtk_toggle_action_get_active (action))
611 gtk_widget_show (statusbar);
613 gtk_widget_hide (statusbar);
618 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
620 const gboolean grid_visible = gtk_toggle_action_get_active (action);
622 psppire_data_editor_show_grid (de->data_editor, grid_visible);
626 data_view_activate (PsppireDataWindow *de)
628 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
633 variable_view_activate (PsppireDataWindow *de)
635 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
640 fonts_activate (PsppireDataWindow *de)
642 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
643 PangoFontDescription *current_font;
646 gtk_font_selection_dialog_new (_("Font Selection"));
649 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
650 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)
865 de->builder = builder_new ("data-editor.ui");
867 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
869 PSPPIRE_WINDOW (de)->menu =
870 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
877 psppire_data_window_finish_init (PsppireDataWindow *de,
880 static const struct dataset_callbacks cbs =
882 set_unsaved, /* changed */
883 transformation_change_callback, /* transformations_changed */
890 GtkWidget *box = gtk_vbox_new (FALSE, 0);
893 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
894 de->data_store = psppire_data_store_new (de->dict);
895 psppire_data_store_set_reader (de->data_store, NULL);
897 menubar = get_widget_assert (de->builder, "menubar");
898 hb = get_widget_assert (de->builder, "handlebox1");
899 sb = get_widget_assert (de->builder, "status-bar");
905 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
906 g_signal_connect (de->data_editor, "switch-page",
907 G_CALLBACK (on_switch_page), de);
909 g_signal_connect_swapped (de->data_store, "case-changed",
910 G_CALLBACK (set_unsaved), de);
912 g_signal_connect_swapped (de->data_store, "case-inserted",
913 G_CALLBACK (set_unsaved), de);
915 g_signal_connect_swapped (de->data_store, "cases-deleted",
916 G_CALLBACK (set_unsaved), de);
918 dataset_set_callbacks (de->dataset, &cbs, de);
920 connect_help (de->builder);
922 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
923 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
924 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
925 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
927 gtk_container_add (GTK_CONTAINER (de), box);
929 g_signal_connect (de->dict, "weight-changed",
930 G_CALLBACK (on_weight_change),
933 g_signal_connect (de->dict, "filter-changed",
934 G_CALLBACK (on_filter_change),
937 g_signal_connect (de->dict, "split-changed",
938 G_CALLBACK (on_split_change),
941 g_signal_connect_swapped (de->dict, "backend-changed",
942 G_CALLBACK (enable_save), de);
943 g_signal_connect_swapped (de->dict, "variable-inserted",
944 G_CALLBACK (enable_save), de);
945 g_signal_connect_swapped (de->dict, "variable-deleted",
946 G_CALLBACK (enable_save), de);
949 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
950 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
951 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
952 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
953 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
954 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
955 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
956 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
958 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
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, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
974 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
975 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
978 GtkWidget *recent_data =
979 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
981 GtkWidget *recent_files =
982 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
985 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
986 gtk_recent_manager_get_default ());
988 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
989 gtk_recent_manager_get_default ());
991 g_object_set (menu_data, "show-tips", TRUE, NULL);
992 g_object_set (menu_files, "show-tips", TRUE, NULL);
995 GtkRecentFilter *filter = gtk_recent_filter_new ();
997 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
998 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1000 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1002 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1005 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1008 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1011 GtkRecentFilter *filter = gtk_recent_filter_new ();
1013 gtk_recent_filter_add_pattern (filter, "*.sps");
1014 gtk_recent_filter_add_pattern (filter, "*.SPS");
1016 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1018 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1021 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1023 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1027 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1030 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1031 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1033 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1035 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1037 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1039 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1041 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1043 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1045 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1047 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1049 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1051 merge_help_menu (de->ui_manager);
1053 g_signal_connect (de->data_editor, "notify::ui-manager",
1054 G_CALLBACK (on_ui_manager_changed), de);
1055 on_ui_manager_changed (de->data_editor, NULL, de);
1057 gtk_widget_show (GTK_WIDGET (de->data_editor));
1058 gtk_widget_show (box);
1060 ll_push_head (&all_data_windows, &de->ll);
1064 psppire_data_window_dispose (GObject *object)
1066 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1070 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1071 g_object_unref (dw->uim);
1075 if (dw->builder != NULL)
1077 g_object_unref (dw->builder);
1083 g_signal_handlers_disconnect_by_func (dw->dict,
1084 G_CALLBACK (enable_save), dw);
1085 g_signal_handlers_disconnect_by_func (dw->dict,
1086 G_CALLBACK (on_weight_change), dw);
1087 g_signal_handlers_disconnect_by_func (dw->dict,
1088 G_CALLBACK (on_filter_change), dw);
1089 g_signal_handlers_disconnect_by_func (dw->dict,
1090 G_CALLBACK (on_split_change), dw);
1092 g_object_unref (dw->dict);
1098 g_object_unref (dw->data_store);
1099 dw->data_store = NULL;
1102 if (dw->ll.next != NULL)
1104 ll_remove (&dw->ll);
1108 if (G_OBJECT_CLASS (parent_class)->dispose)
1109 G_OBJECT_CLASS (parent_class)->dispose (object);
1113 psppire_data_window_finalize (GObject *object)
1115 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1119 struct dataset *dataset = dw->dataset;
1120 struct session *session = dataset_session (dataset);
1124 dataset_set_callbacks (dataset, NULL, NULL);
1125 session_set_active_dataset (session, NULL);
1126 dataset_destroy (dataset);
1129 if (G_OBJECT_CLASS (parent_class)->finalize)
1130 G_OBJECT_CLASS (parent_class)->finalize (object);
1134 psppire_data_window_set_property (GObject *object,
1136 const GValue *value,
1139 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1144 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1147 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1153 psppire_data_window_get_property (GObject *object,
1158 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1163 g_value_set_pointer (value, window->dataset);
1166 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1172 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1178 ui_string = gtk_ui_manager_get_ui (uim);
1179 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1183 g_return_val_if_fail (merge_id != 0, 0);
1185 list = gtk_ui_manager_get_action_groups (uim);
1186 for (; list != NULL; list = list->next)
1188 GtkActionGroup *action_group = list->data;
1189 GList *actions = gtk_action_group_list_actions (action_group);
1192 for (action = actions; action != NULL; action = action->next)
1194 GtkAction *a = action->data;
1196 if (PSPPIRE_IS_DIALOG_ACTION (a))
1197 g_object_set (a, "manager", pdw->ui_manager, NULL);
1200 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1203 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1204 gtk_ui_manager_get_accel_group (uim));
1210 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1211 GtkUIManager *uim, guint merge_id)
1215 g_return_if_fail (merge_id != 0);
1217 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1219 list = gtk_ui_manager_get_action_groups (uim);
1220 for (; list != NULL; list = list->next)
1222 GtkActionGroup *action_group = list->data;
1223 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1226 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1227 gtk_ui_manager_get_accel_group (uim));
1231 psppire_data_window_new (struct dataset *ds)
1235 if (the_session == NULL)
1236 the_session = session_create (NULL);
1240 char *dataset_name = session_generate_dataset_name (the_session);
1241 ds = dataset_create (the_session, dataset_name);
1242 free (dataset_name);
1244 assert (dataset_session (ds) == the_session);
1248 psppire_data_window_get_type (),
1249 "description", _("Data Editor"),
1253 if (dataset_name (ds) != NULL)
1254 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1260 psppire_data_window_is_empty (PsppireDataWindow *dw)
1262 return psppire_dict_get_var_cnt (dw->dict) == 0;
1266 psppire_data_window_iface_init (PsppireWindowIface *iface)
1268 iface->save = save_file;
1269 iface->pick_filename = data_pick_filename;
1270 iface->load = load_file;
1274 psppire_default_data_window (void)
1276 if (ll_is_empty (&all_data_windows))
1277 create_data_window ();
1278 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1282 psppire_data_window_set_default (PsppireDataWindow *pdw)
1284 ll_remove (&pdw->ll);
1285 ll_push_head (&all_data_windows, &pdw->ll);
1289 psppire_data_window_undefault (PsppireDataWindow *pdw)
1291 ll_remove (&pdw->ll);
1292 ll_push_tail (&all_data_windows, &pdw->ll);
1296 psppire_data_window_for_dataset (struct dataset *ds)
1298 PsppireDataWindow *pdw;
1300 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1301 if (pdw->dataset == ds)
1308 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1310 PsppireDataWindow *pdw;
1312 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1313 if (pdw->data_store == data_store)
1320 create_data_window (void)
1322 gtk_widget_show (psppire_data_window_new (NULL));
1326 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1330 if (PSPPIRE_IS_DATA_WINDOW (victim)
1331 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1333 window = GTK_WIDGET (victim);
1334 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1337 window = psppire_data_window_new (NULL);
1339 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1340 gtk_widget_show_all (window);