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/recode-dialog.h"
47 #include "ui/gui/select-cases-dialog.h"
48 #include "ui/gui/split-file-dialog.h"
49 #include "ui/gui/t-test-paired-samples.h"
50 #include "ui/gui/text-data-import-dialog.h"
51 #include "ui/gui/weight-cases-dialog.h"
52 #include "ui/syntax-gen.h"
54 #include "gl/c-strcase.h"
55 #include "gl/c-strcasestr.h"
56 #include "gl/xvasprintf.h"
59 #define _(msgid) gettext (msgid)
60 #define N_(msgid) msgid
62 struct session *the_session;
63 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
65 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
66 static void psppire_data_window_init (PsppireDataWindow *data_editor);
69 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
71 static void psppire_data_window_dispose (GObject *object);
72 static void psppire_data_window_finalize (GObject *object);
73 static void psppire_data_window_set_property (GObject *object,
77 static void psppire_data_window_get_property (GObject *object,
82 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
83 static void psppire_data_window_remove_ui (PsppireDataWindow *,
84 GtkUIManager *, guint);
87 psppire_data_window_get_type (void)
89 static GType psppire_data_window_type = 0;
91 if (!psppire_data_window_type)
93 static const GTypeInfo psppire_data_window_info =
95 sizeof (PsppireDataWindowClass),
98 (GClassInitFunc)psppire_data_window_class_init,
99 (GClassFinalizeFunc) NULL,
101 sizeof (PsppireDataWindow),
103 (GInstanceInitFunc) psppire_data_window_init,
106 static const GInterfaceInfo window_interface_info =
108 (GInterfaceInitFunc) psppire_data_window_iface_init,
113 psppire_data_window_type =
114 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
115 &psppire_data_window_info, 0);
118 g_type_add_interface_static (psppire_data_window_type,
119 PSPPIRE_TYPE_WINDOW_MODEL,
120 &window_interface_info);
123 return psppire_data_window_type;
126 static GObjectClass *parent_class ;
133 psppire_data_window_class_init (PsppireDataWindowClass *class)
135 GObjectClass *object_class = G_OBJECT_CLASS (class);
137 parent_class = g_type_class_peek_parent (class);
139 object_class->dispose = psppire_data_window_dispose;
140 object_class->finalize = psppire_data_window_finalize;
141 object_class->set_property = psppire_data_window_set_property;
142 object_class->get_property = psppire_data_window_get_property;
144 g_object_class_install_property (
145 object_class, PROP_DATASET,
146 g_param_spec_pointer ("dataset", "Dataset",
147 "'struct datset *' represented by the window",
148 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
151 /* Run the EXECUTE command. */
153 execute (PsppireDataWindow *dw)
155 execute_const_syntax_string (dw, "EXECUTE.");
159 transformation_change_callback (bool transformations_pending,
162 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
164 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
166 GtkWidget *menuitem =
167 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
169 GtkWidget *status_label =
170 get_widget_assert (de->builder, "case-counter-area");
172 gtk_widget_set_sensitive (menuitem, transformations_pending);
175 if ( transformations_pending)
176 gtk_label_set_text (GTK_LABEL (status_label),
177 _("Transformations Pending"));
179 gtk_label_set_text (GTK_LABEL (status_label), "");
182 /* Callback for when the dictionary changes its filter variable */
184 on_filter_change (GObject *o, gint filter_index, gpointer data)
186 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
188 GtkWidget *filter_status_area =
189 get_widget_assert (de->builder, "filter-use-status-area");
191 if ( filter_index == -1 )
193 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
197 PsppireDict *dict = NULL;
198 struct variable *var ;
201 g_object_get (de->data_editor, "dictionary", &dict, NULL);
203 var = psppire_dict_get_variable (dict, filter_index);
205 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
207 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
213 /* Callback for when the dictionary changes its split variables */
215 on_split_change (PsppireDict *dict, gpointer data)
217 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
219 size_t n_split_vars = dict_get_split_cnt (dict->dict);
221 GtkWidget *split_status_area =
222 get_widget_assert (de->builder, "split-file-status-area");
224 if ( n_split_vars == 0 )
226 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
232 const struct variable *const * split_vars =
233 dict_get_split_vars (dict->dict);
235 text = g_string_new (_("Split by "));
237 for (i = 0 ; i < n_split_vars - 1; ++i )
239 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
241 g_string_append (text, var_get_name (split_vars[i]));
243 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
245 g_string_free (text, TRUE);
252 /* Callback for when the dictionary changes its weights */
254 on_weight_change (GObject *o, gint weight_index, gpointer data)
256 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
258 GtkWidget *weight_status_area =
259 get_widget_assert (de->builder, "weight-status-area");
261 if ( weight_index == -1 )
263 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
267 struct variable *var ;
268 PsppireDict *dict = NULL;
271 g_object_get (de->data_editor, "dictionary", &dict, NULL);
273 var = psppire_dict_get_variable (dict, weight_index);
275 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
277 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
285 dump_rm (GtkRecentManager *rm)
287 GList *items = gtk_recent_manager_get_items (rm);
291 g_print ("Recent Items:\n");
292 for (i = items; i; i = i->next)
294 GtkRecentInfo *ri = i->data;
296 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
297 gtk_recent_info_get_short_name (ri),
298 gtk_recent_info_get_mime_type (ri),
299 gtk_recent_info_get_description (ri),
300 gtk_recent_info_get_uri (ri)
304 gtk_recent_info_unref (ri);
312 name_has_por_suffix (const gchar *name)
314 size_t length = strlen (name);
315 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
319 name_has_sav_suffix (const gchar *name)
321 size_t length = strlen (name);
322 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
325 /* Returns true if NAME has a suffix which might denote a PSPP file */
327 name_has_suffix (const gchar *name)
329 return name_has_por_suffix (name) || name_has_sav_suffix (name);
333 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
335 const char *mime_type = NULL;
336 gchar *syntax = NULL;
341 gchar *utf8_file_name;
342 struct string filename;
343 ds_init_empty (&filename);
345 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
347 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
349 g_free (utf8_file_name);
351 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
352 ds_destroy (&filename);
360 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
361 lex_reader_for_string (syntax));
364 if (ok && syn == NULL)
366 if (name_has_por_suffix (file_name))
367 mime_type = "application/x-spss-por";
368 else if (name_has_sav_suffix (file_name))
369 mime_type = "application/x-spss-sav";
371 add_most_recent (file_name, mime_type);
377 /* Save DE to file */
379 save_file (PsppireWindow *w)
381 const gchar *file_name = NULL;
382 gchar *utf8_file_name = NULL;
384 struct string filename ;
385 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
388 file_name = psppire_window_get_filename (w);
390 fnx = g_string_new (file_name);
392 if ( ! name_has_suffix (fnx->str))
394 if ( de->save_as_portable)
395 g_string_append (fnx, ".por");
397 g_string_append (fnx, ".sav");
400 ds_init_empty (&filename);
402 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
404 g_string_free (fnx, TRUE);
406 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
407 g_free (utf8_file_name);
409 syntax = g_strdup_printf ("%s OUTFILE=%s.",
410 de->save_as_portable ? "EXPORT" : "SAVE",
411 ds_cstr (&filename));
413 ds_destroy (&filename);
415 g_free (execute_syntax_string (de, syntax));
420 display_dict (PsppireDataWindow *de)
422 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
426 sysfile_info (PsppireDataWindow *de)
428 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
430 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
432 struct string filename;
434 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
436 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
441 ds_init_empty (&filename);
443 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
445 g_free (utf8_file_name);
447 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
448 g_free (execute_syntax_string (de, syntax));
451 gtk_widget_destroy (dialog);
455 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
457 data_pick_filename (PsppireWindow *window)
459 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
460 GtkFileFilter *filter = gtk_file_filter_new ();
461 GtkWidget *button_sys;
463 gtk_file_chooser_dialog_new (_("Save"),
465 GTK_FILE_CHOOSER_ACTION_SAVE,
466 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
467 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
470 g_object_set (dialog, "local-only", FALSE, NULL);
472 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
473 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
474 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
476 filter = gtk_file_filter_new ();
477 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
478 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
479 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
481 filter = gtk_file_filter_new ();
482 gtk_file_filter_set_name (filter, _("All Files"));
483 gtk_file_filter_add_pattern (filter, "*");
484 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
487 GtkWidget *button_por;
488 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
490 gtk_radio_button_new_with_label (NULL, _("System File"));
493 gtk_radio_button_new_with_label
494 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
497 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
498 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
500 gtk_widget_show_all (vbox);
502 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
505 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
508 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
510 case GTK_RESPONSE_ACCEPT:
515 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
518 de->save_as_portable =
519 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
521 if ( ! name_has_suffix (filename->str))
523 if ( de->save_as_portable)
524 g_string_append (filename, ".por");
526 g_string_append (filename, ".sav");
529 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
531 g_string_free (filename, TRUE);
538 gtk_widget_destroy (dialog);
542 confirm_delete_dataset (PsppireDataWindow *de,
543 const char *old_dataset,
544 const char *new_dataset,
545 const char *existing_dataset)
550 dialog = gtk_message_dialog_new (
551 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
552 _("Delete Existing Dataset?"));
554 gtk_message_dialog_format_secondary_text (
555 GTK_MESSAGE_DIALOG (dialog),
556 _("Renaming \"%s\" to \"%s\" will destroy the existing "
557 "dataset named \"%s\". Are you sure that you want to do this?"),
558 old_dataset, new_dataset, existing_dataset);
560 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
561 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
562 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
565 g_object_set (dialog, "icon-name", "pspp", NULL);
567 result = gtk_dialog_run (GTK_DIALOG (dialog));
569 gtk_widget_destroy (dialog);
571 return result == GTK_RESPONSE_OK;
575 on_rename_dataset (PsppireDataWindow *de)
577 struct dataset *ds = de->dataset;
578 struct session *session = dataset_session (ds);
579 const char *old_name = dataset_name (ds);
580 struct dataset *existing_dataset;
584 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
586 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
590 if (new_name == NULL)
593 existing_dataset = session_lookup_dataset (session, new_name);
594 if (existing_dataset == NULL || existing_dataset == ds
595 || confirm_delete_dataset (de, old_name, new_name,
596 dataset_name (existing_dataset)))
597 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
604 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
606 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
608 if ( gtk_toggle_action_get_active (action))
609 gtk_widget_show (statusbar);
611 gtk_widget_hide (statusbar);
616 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
618 const gboolean grid_visible = gtk_toggle_action_get_active (action);
620 psppire_data_editor_show_grid (de->data_editor, grid_visible);
624 data_view_activate (PsppireDataWindow *de)
626 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
631 variable_view_activate (PsppireDataWindow *de)
633 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
638 fonts_activate (PsppireDataWindow *de)
640 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
641 PangoFontDescription *current_font;
644 gtk_font_selection_dialog_new (_("Font Selection"));
647 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
648 font_name = pango_font_description_to_string (current_font);
650 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
654 gtk_window_set_transient_for (GTK_WINDOW (dialog),
655 GTK_WINDOW (toplevel));
657 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
659 const gchar *font = gtk_font_selection_dialog_get_font_name
660 (GTK_FONT_SELECTION_DIALOG (dialog));
662 PangoFontDescription* font_desc =
663 pango_font_description_from_string (font);
665 psppire_data_editor_set_font (de->data_editor, font_desc);
668 gtk_widget_hide (dialog);
673 /* Callback for the value labels action */
675 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
677 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
681 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
683 psppire_data_editor_split_window (de->data_editor,
684 gtk_toggle_action_get_active (ta));
689 file_quit (PsppireDataWindow *de)
691 /* FIXME: Need to be more intelligent here.
692 Give the user the opportunity to save any unsaved data.
698 on_recent_data_select (GtkMenuShell *menushell,
699 PsppireWindow *window)
704 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
706 file = g_filename_from_uri (uri, NULL, NULL);
710 open_data_window (window, file, NULL);
716 charset_from_mime_type (const char *mime_type)
722 if (mime_type == NULL)
725 charset = c_strcasestr (mime_type, "charset=");
733 /* Parse a "quoted-string" as defined by RFC 822. */
734 for (p++; *p != '\0' && *p != '"'; p++)
737 ds_put_byte (&s, *p);
738 else if (*++p != '\0')
739 ds_put_byte (&s, *p);
744 /* Parse a "token" as defined by RFC 2045. */
745 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
746 ds_put_byte (&s, *p++);
748 if (!ds_is_empty (&s))
749 return ds_steal_cstr (&s);
756 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
763 /* Get the file name and its encoding. */
764 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
765 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
766 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
767 gtk_recent_info_unref (item);
769 se = psppire_syntax_window_new (encoding);
773 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
774 gtk_widget_show (se);
776 gtk_widget_destroy (se);
782 set_unsaved (gpointer w)
784 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
788 on_switch_page (PsppireDataEditor *de, gpointer p,
789 gint pagenum, PsppireDataWindow *dw)
791 GtkWidget *page_menu_item;
795 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
797 ? "/ui/menubar/view/view_data"
798 : "/ui/menubar/view/view_variables");
799 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
800 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
804 on_ui_manager_changed (PsppireDataEditor *de,
805 GParamSpec *pspec UNUSED,
806 PsppireDataWindow *dw)
808 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
814 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
815 g_object_unref (dw->uim);
822 g_object_ref (dw->uim);
823 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
827 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
828 Returns a pointer to the action
831 connect_action (PsppireDataWindow *dw, const char *action_name,
834 GtkAction *action = get_action_assert (dw->builder, action_name);
836 g_signal_connect_swapped (action, "activate", handler, dw);
841 /* Only a data file with at least one variable can be saved. */
843 enable_save (PsppireDataWindow *dw)
845 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
847 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
849 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
853 /* Initializes as much of a PsppireDataWindow as we can and must before the
854 dataset has been set.
856 In particular, the 'menu' member is required in case the "filename" property
857 is set before the "dataset" property: otherwise PsppireWindow will try to
858 modify the menu as part of the "filename" property_set() function and end up
859 with a Gtk-CRITICAL since 'menu' is NULL. */
861 psppire_data_window_init (PsppireDataWindow *de)
863 de->builder = builder_new ("data-editor.ui");
865 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
867 PSPPIRE_WINDOW (de)->menu =
868 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
875 psppire_data_window_finish_init (PsppireDataWindow *de,
878 static const struct dataset_callbacks cbs =
880 set_unsaved, /* changed */
881 transformation_change_callback, /* transformations_changed */
888 GtkWidget *box = gtk_vbox_new (FALSE, 0);
891 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
892 de->data_store = psppire_data_store_new (de->dict);
893 psppire_data_store_set_reader (de->data_store, NULL);
895 menubar = get_widget_assert (de->builder, "menubar");
896 hb = get_widget_assert (de->builder, "handlebox1");
897 sb = get_widget_assert (de->builder, "status-bar");
903 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
904 g_signal_connect (de->data_editor, "switch-page",
905 G_CALLBACK (on_switch_page), de);
907 g_signal_connect_swapped (de->data_store, "case-changed",
908 G_CALLBACK (set_unsaved), de);
910 g_signal_connect_swapped (de->data_store, "case-inserted",
911 G_CALLBACK (set_unsaved), de);
913 g_signal_connect_swapped (de->data_store, "cases-deleted",
914 G_CALLBACK (set_unsaved), de);
916 dataset_set_callbacks (de->dataset, &cbs, de);
918 connect_help (de->builder);
920 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
921 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
922 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
923 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
925 gtk_container_add (GTK_CONTAINER (de), box);
927 g_signal_connect (de->dict, "weight-changed",
928 G_CALLBACK (on_weight_change),
931 g_signal_connect (de->dict, "filter-changed",
932 G_CALLBACK (on_filter_change),
935 g_signal_connect (de->dict, "split-changed",
936 G_CALLBACK (on_split_change),
939 g_signal_connect_swapped (de->dict, "backend-changed",
940 G_CALLBACK (enable_save), de);
941 g_signal_connect_swapped (de->dict, "variable-inserted",
942 G_CALLBACK (enable_save), de);
943 g_signal_connect_swapped (de->dict, "variable-deleted",
944 G_CALLBACK (enable_save), de);
947 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
948 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
949 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
950 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
951 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
952 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
953 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
954 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
956 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
958 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
959 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
960 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
961 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
962 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
963 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
964 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
965 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
966 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
967 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
968 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
969 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
970 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
971 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
974 GtkWidget *recent_data =
975 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
977 GtkWidget *recent_files =
978 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
981 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
982 gtk_recent_manager_get_default ());
984 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
985 gtk_recent_manager_get_default ());
987 g_object_set (menu_data, "show-tips", TRUE, NULL);
988 g_object_set (menu_files, "show-tips", TRUE, NULL);
991 GtkRecentFilter *filter = gtk_recent_filter_new ();
993 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
994 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
996 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
998 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1001 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1004 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1007 GtkRecentFilter *filter = gtk_recent_filter_new ();
1009 gtk_recent_filter_add_pattern (filter, "*.sps");
1010 gtk_recent_filter_add_pattern (filter, "*.SPS");
1012 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1014 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1017 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1019 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1023 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1026 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1027 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1029 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1031 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1033 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1035 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1037 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1039 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1041 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1043 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1045 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1047 merge_help_menu (de->ui_manager);
1049 g_signal_connect (de->data_editor, "notify::ui-manager",
1050 G_CALLBACK (on_ui_manager_changed), de);
1051 on_ui_manager_changed (de->data_editor, NULL, de);
1053 gtk_widget_show (GTK_WIDGET (de->data_editor));
1054 gtk_widget_show (box);
1056 ll_push_head (&all_data_windows, &de->ll);
1060 psppire_data_window_dispose (GObject *object)
1062 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1066 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1067 g_object_unref (dw->uim);
1071 if (dw->builder != NULL)
1073 g_object_unref (dw->builder);
1079 g_signal_handlers_disconnect_by_func (dw->dict,
1080 G_CALLBACK (enable_save), dw);
1081 g_signal_handlers_disconnect_by_func (dw->dict,
1082 G_CALLBACK (on_weight_change), dw);
1083 g_signal_handlers_disconnect_by_func (dw->dict,
1084 G_CALLBACK (on_filter_change), dw);
1085 g_signal_handlers_disconnect_by_func (dw->dict,
1086 G_CALLBACK (on_split_change), dw);
1088 g_object_unref (dw->dict);
1094 g_object_unref (dw->data_store);
1095 dw->data_store = NULL;
1098 if (dw->ll.next != NULL)
1100 ll_remove (&dw->ll);
1104 if (G_OBJECT_CLASS (parent_class)->dispose)
1105 G_OBJECT_CLASS (parent_class)->dispose (object);
1109 psppire_data_window_finalize (GObject *object)
1111 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1115 struct dataset *dataset = dw->dataset;
1116 struct session *session = dataset_session (dataset);
1120 dataset_set_callbacks (dataset, NULL, NULL);
1121 session_set_active_dataset (session, NULL);
1122 dataset_destroy (dataset);
1125 if (G_OBJECT_CLASS (parent_class)->finalize)
1126 G_OBJECT_CLASS (parent_class)->finalize (object);
1130 psppire_data_window_set_property (GObject *object,
1132 const GValue *value,
1135 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1140 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1149 psppire_data_window_get_property (GObject *object,
1154 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1159 g_value_set_pointer (value, window->dataset);
1162 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1168 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1174 ui_string = gtk_ui_manager_get_ui (uim);
1175 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1179 g_return_val_if_fail (merge_id != 0, 0);
1181 list = gtk_ui_manager_get_action_groups (uim);
1182 for (; list != NULL; list = list->next)
1184 GtkActionGroup *action_group = list->data;
1185 GList *actions = gtk_action_group_list_actions (action_group);
1188 for (action = actions; action != NULL; action = action->next)
1190 GtkAction *a = action->data;
1192 if (PSPPIRE_IS_DIALOG_ACTION (a))
1193 g_object_set (a, "manager", pdw->ui_manager, NULL);
1196 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1199 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1200 gtk_ui_manager_get_accel_group (uim));
1206 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1207 GtkUIManager *uim, guint merge_id)
1211 g_return_if_fail (merge_id != 0);
1213 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1215 list = gtk_ui_manager_get_action_groups (uim);
1216 for (; list != NULL; list = list->next)
1218 GtkActionGroup *action_group = list->data;
1219 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1222 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1223 gtk_ui_manager_get_accel_group (uim));
1227 psppire_data_window_new (struct dataset *ds)
1231 if (the_session == NULL)
1232 the_session = session_create (NULL);
1236 char *dataset_name = session_generate_dataset_name (the_session);
1237 ds = dataset_create (the_session, dataset_name);
1238 free (dataset_name);
1240 assert (dataset_session (ds) == the_session);
1244 psppire_data_window_get_type (),
1245 "description", _("Data Editor"),
1249 if (dataset_name (ds) != NULL)
1250 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1256 psppire_data_window_is_empty (PsppireDataWindow *dw)
1258 return psppire_dict_get_var_cnt (dw->dict) == 0;
1262 psppire_data_window_iface_init (PsppireWindowIface *iface)
1264 iface->save = save_file;
1265 iface->pick_filename = data_pick_filename;
1266 iface->load = load_file;
1270 psppire_default_data_window (void)
1272 if (ll_is_empty (&all_data_windows))
1273 create_data_window ();
1274 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1278 psppire_data_window_set_default (PsppireDataWindow *pdw)
1280 ll_remove (&pdw->ll);
1281 ll_push_head (&all_data_windows, &pdw->ll);
1285 psppire_data_window_undefault (PsppireDataWindow *pdw)
1287 ll_remove (&pdw->ll);
1288 ll_push_tail (&all_data_windows, &pdw->ll);
1292 psppire_data_window_for_dataset (struct dataset *ds)
1294 PsppireDataWindow *pdw;
1296 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1297 if (pdw->dataset == ds)
1304 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1306 PsppireDataWindow *pdw;
1308 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1309 if (pdw->data_store == data_store)
1316 create_data_window (void)
1318 gtk_widget_show (psppire_data_window_new (NULL));
1322 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1326 if (PSPPIRE_IS_DATA_WINDOW (victim)
1327 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1329 window = GTK_WIDGET (victim);
1330 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1333 window = psppire_data_window_new (NULL);
1335 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1336 gtk_widget_show_all (window);