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/count-dialog.h"
32 #include "ui/gui/entry-dialog.h"
33 #include "ui/gui/executor.h"
34 #include "ui/gui/help-menu.h"
35 #include "ui/gui/helper.h"
36 #include "ui/gui/helper.h"
37 #include "ui/gui/npar-two-sample-related.h"
38 #include "ui/gui/oneway-anova-dialog.h"
39 #include "ui/gui/psppire-data-window.h"
40 #include "ui/gui/psppire-dialog-action.h"
41 #include "ui/gui/psppire-syntax-window.h"
42 #include "ui/gui/psppire-window.h"
43 #include "ui/gui/psppire.h"
44 #include "ui/gui/recode-dialog.h"
45 #include "ui/gui/select-cases-dialog.h"
46 #include "ui/gui/split-file-dialog.h"
47 #include "ui/gui/t-test-paired-samples.h"
48 #include "ui/gui/text-data-import-dialog.h"
49 #include "ui/gui/weight-cases-dialog.h"
50 #include "ui/syntax-gen.h"
52 #include "gl/c-strcase.h"
53 #include "gl/c-strcasestr.h"
54 #include "gl/xvasprintf.h"
57 #define _(msgid) gettext (msgid)
58 #define N_(msgid) msgid
60 struct session *the_session;
61 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
63 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
64 static void psppire_data_window_init (PsppireDataWindow *data_editor);
67 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
69 static void psppire_data_window_dispose (GObject *object);
70 static void psppire_data_window_finalize (GObject *object);
71 static void psppire_data_window_set_property (GObject *object,
75 static void psppire_data_window_get_property (GObject *object,
80 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
81 static void psppire_data_window_remove_ui (PsppireDataWindow *,
82 GtkUIManager *, guint);
85 psppire_data_window_get_type (void)
87 static GType psppire_data_window_type = 0;
89 if (!psppire_data_window_type)
91 static const GTypeInfo psppire_data_window_info =
93 sizeof (PsppireDataWindowClass),
96 (GClassInitFunc)psppire_data_window_class_init,
97 (GClassFinalizeFunc) NULL,
99 sizeof (PsppireDataWindow),
101 (GInstanceInitFunc) psppire_data_window_init,
104 static const GInterfaceInfo window_interface_info =
106 (GInterfaceInitFunc) psppire_data_window_iface_init,
111 psppire_data_window_type =
112 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
113 &psppire_data_window_info, 0);
116 g_type_add_interface_static (psppire_data_window_type,
117 PSPPIRE_TYPE_WINDOW_MODEL,
118 &window_interface_info);
121 return psppire_data_window_type;
124 static GObjectClass *parent_class ;
131 psppire_data_window_class_init (PsppireDataWindowClass *class)
133 GObjectClass *object_class = G_OBJECT_CLASS (class);
135 parent_class = g_type_class_peek_parent (class);
137 object_class->dispose = psppire_data_window_dispose;
138 object_class->finalize = psppire_data_window_finalize;
139 object_class->set_property = psppire_data_window_set_property;
140 object_class->get_property = psppire_data_window_get_property;
142 g_object_class_install_property (
143 object_class, PROP_DATASET,
144 g_param_spec_pointer ("dataset", "Dataset",
145 "'struct datset *' represented by the window",
146 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
149 /* Run the EXECUTE command. */
151 execute (PsppireDataWindow *dw)
153 execute_const_syntax_string (dw, "EXECUTE.");
157 transformation_change_callback (bool transformations_pending,
160 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
162 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
164 GtkWidget *menuitem =
165 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
167 GtkWidget *status_label =
168 get_widget_assert (de->builder, "case-counter-area");
170 gtk_widget_set_sensitive (menuitem, transformations_pending);
173 if ( transformations_pending)
174 gtk_label_set_text (GTK_LABEL (status_label),
175 _("Transformations Pending"));
177 gtk_label_set_text (GTK_LABEL (status_label), "");
180 /* Callback for when the dictionary changes its filter variable */
182 on_filter_change (GObject *o, gint filter_index, gpointer data)
184 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
186 GtkWidget *filter_status_area =
187 get_widget_assert (de->builder, "filter-use-status-area");
189 if ( filter_index == -1 )
191 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
195 PsppireDict *dict = NULL;
196 struct variable *var ;
199 g_object_get (de->data_editor, "dictionary", &dict, NULL);
201 var = psppire_dict_get_variable (dict, filter_index);
203 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
205 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
211 /* Callback for when the dictionary changes its split variables */
213 on_split_change (PsppireDict *dict, gpointer data)
215 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
217 size_t n_split_vars = dict_get_split_cnt (dict->dict);
219 GtkWidget *split_status_area =
220 get_widget_assert (de->builder, "split-file-status-area");
222 if ( n_split_vars == 0 )
224 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
230 const struct variable *const * split_vars =
231 dict_get_split_vars (dict->dict);
233 text = g_string_new (_("Split by "));
235 for (i = 0 ; i < n_split_vars - 1; ++i )
237 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
239 g_string_append (text, var_get_name (split_vars[i]));
241 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
243 g_string_free (text, TRUE);
250 /* Callback for when the dictionary changes its weights */
252 on_weight_change (GObject *o, gint weight_index, gpointer data)
254 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
256 GtkWidget *weight_status_area =
257 get_widget_assert (de->builder, "weight-status-area");
259 if ( weight_index == -1 )
261 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
265 struct variable *var ;
266 PsppireDict *dict = NULL;
269 g_object_get (de->data_editor, "dictionary", &dict, NULL);
271 var = psppire_dict_get_variable (dict, weight_index);
273 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
275 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
283 dump_rm (GtkRecentManager *rm)
285 GList *items = gtk_recent_manager_get_items (rm);
289 g_print ("Recent Items:\n");
290 for (i = items; i; i = i->next)
292 GtkRecentInfo *ri = i->data;
294 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
295 gtk_recent_info_get_short_name (ri),
296 gtk_recent_info_get_mime_type (ri),
297 gtk_recent_info_get_description (ri),
298 gtk_recent_info_get_uri (ri)
302 gtk_recent_info_unref (ri);
310 name_has_por_suffix (const gchar *name)
312 size_t length = strlen (name);
313 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
317 name_has_sav_suffix (const gchar *name)
319 size_t length = strlen (name);
320 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
323 /* Returns true if NAME has a suffix which might denote a PSPP file */
325 name_has_suffix (const gchar *name)
327 return name_has_por_suffix (name) || name_has_sav_suffix (name);
331 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
333 const char *mime_type = NULL;
334 gchar *syntax = NULL;
339 gchar *utf8_file_name;
340 struct string filename;
341 ds_init_empty (&filename);
343 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
345 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
347 g_free (utf8_file_name);
349 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
350 ds_destroy (&filename);
358 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
359 lex_reader_for_string (syntax));
362 if (ok && syn == NULL)
364 if (name_has_por_suffix (file_name))
365 mime_type = "application/x-spss-por";
366 else if (name_has_sav_suffix (file_name))
367 mime_type = "application/x-spss-sav";
369 add_most_recent (file_name, mime_type);
375 /* Save DE to file */
377 save_file (PsppireWindow *w)
379 const gchar *file_name = NULL;
380 gchar *utf8_file_name = NULL;
382 struct string filename ;
383 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
386 file_name = psppire_window_get_filename (w);
388 fnx = g_string_new (file_name);
390 if ( ! name_has_suffix (fnx->str))
392 if ( de->save_as_portable)
393 g_string_append (fnx, ".por");
395 g_string_append (fnx, ".sav");
398 ds_init_empty (&filename);
400 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
402 g_string_free (fnx, TRUE);
404 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
405 g_free (utf8_file_name);
407 syntax = g_strdup_printf ("%s OUTFILE=%s.",
408 de->save_as_portable ? "EXPORT" : "SAVE",
409 ds_cstr (&filename));
411 ds_destroy (&filename);
413 g_free (execute_syntax_string (de, syntax));
418 display_dict (PsppireDataWindow *de)
420 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
424 sysfile_info (PsppireDataWindow *de)
426 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
428 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
430 struct string filename;
432 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
434 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
439 ds_init_empty (&filename);
441 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
443 g_free (utf8_file_name);
445 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
446 g_free (execute_syntax_string (de, syntax));
449 gtk_widget_destroy (dialog);
453 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
455 data_pick_filename (PsppireWindow *window)
457 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
458 GtkFileFilter *filter = gtk_file_filter_new ();
459 GtkWidget *button_sys;
461 gtk_file_chooser_dialog_new (_("Save"),
463 GTK_FILE_CHOOSER_ACTION_SAVE,
464 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
465 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
468 g_object_set (dialog, "local-only", FALSE, NULL);
470 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
471 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
472 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
474 filter = gtk_file_filter_new ();
475 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
476 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
477 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
479 filter = gtk_file_filter_new ();
480 gtk_file_filter_set_name (filter, _("All Files"));
481 gtk_file_filter_add_pattern (filter, "*");
482 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
485 GtkWidget *button_por;
486 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
488 gtk_radio_button_new_with_label (NULL, _("System File"));
491 gtk_radio_button_new_with_label
492 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
495 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
496 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
498 gtk_widget_show_all (vbox);
500 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
503 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
506 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
508 case GTK_RESPONSE_ACCEPT:
513 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
516 de->save_as_portable =
517 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
519 if ( ! name_has_suffix (filename->str))
521 if ( de->save_as_portable)
522 g_string_append (filename, ".por");
524 g_string_append (filename, ".sav");
527 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
529 g_string_free (filename, TRUE);
536 gtk_widget_destroy (dialog);
540 confirm_delete_dataset (PsppireDataWindow *de,
541 const char *old_dataset,
542 const char *new_dataset,
543 const char *existing_dataset)
548 dialog = gtk_message_dialog_new (
549 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
550 _("Delete Existing Dataset?"));
552 gtk_message_dialog_format_secondary_text (
553 GTK_MESSAGE_DIALOG (dialog),
554 _("Renaming \"%s\" to \"%s\" will destroy the existing "
555 "dataset named \"%s\". Are you sure that you want to do this?"),
556 old_dataset, new_dataset, existing_dataset);
558 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
559 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
560 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
563 g_object_set (dialog, "icon-name", "pspp", NULL);
565 result = gtk_dialog_run (GTK_DIALOG (dialog));
567 gtk_widget_destroy (dialog);
569 return result == GTK_RESPONSE_OK;
573 on_rename_dataset (PsppireDataWindow *de)
575 struct dataset *ds = de->dataset;
576 struct session *session = dataset_session (ds);
577 const char *old_name = dataset_name (ds);
578 struct dataset *existing_dataset;
582 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
584 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
588 if (new_name == NULL)
591 existing_dataset = session_lookup_dataset (session, new_name);
592 if (existing_dataset == NULL || existing_dataset == ds
593 || confirm_delete_dataset (de, old_name, new_name,
594 dataset_name (existing_dataset)))
595 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
602 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
604 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
606 if ( gtk_toggle_action_get_active (action))
607 gtk_widget_show (statusbar);
609 gtk_widget_hide (statusbar);
614 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
616 const gboolean grid_visible = gtk_toggle_action_get_active (action);
618 psppire_data_editor_show_grid (de->data_editor, grid_visible);
622 data_view_activate (PsppireDataWindow *de)
624 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
629 variable_view_activate (PsppireDataWindow *de)
631 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
636 fonts_activate (PsppireDataWindow *de)
638 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
639 PangoFontDescription *current_font;
642 gtk_font_selection_dialog_new (_("Font Selection"));
645 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
646 font_name = pango_font_description_to_string (current_font);
648 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
652 gtk_window_set_transient_for (GTK_WINDOW (dialog),
653 GTK_WINDOW (toplevel));
655 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
657 const gchar *font = gtk_font_selection_dialog_get_font_name
658 (GTK_FONT_SELECTION_DIALOG (dialog));
660 PangoFontDescription* font_desc =
661 pango_font_description_from_string (font);
663 psppire_data_editor_set_font (de->data_editor, font_desc);
666 gtk_widget_hide (dialog);
671 /* Callback for the value labels action */
673 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
675 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
679 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
681 psppire_data_editor_split_window (de->data_editor,
682 gtk_toggle_action_get_active (ta));
687 file_quit (PsppireDataWindow *de)
689 /* FIXME: Need to be more intelligent here.
690 Give the user the opportunity to save any unsaved data.
696 on_recent_data_select (GtkMenuShell *menushell,
697 PsppireWindow *window)
702 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
704 file = g_filename_from_uri (uri, NULL, NULL);
708 open_data_window (window, file, NULL);
714 charset_from_mime_type (const char *mime_type)
720 if (mime_type == NULL)
723 charset = c_strcasestr (mime_type, "charset=");
731 /* Parse a "quoted-string" as defined by RFC 822. */
732 for (p++; *p != '\0' && *p != '"'; p++)
735 ds_put_byte (&s, *p);
736 else if (*++p != '\0')
737 ds_put_byte (&s, *p);
742 /* Parse a "token" as defined by RFC 2045. */
743 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
744 ds_put_byte (&s, *p++);
746 if (!ds_is_empty (&s))
747 return ds_steal_cstr (&s);
754 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
761 /* Get the file name and its encoding. */
762 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
763 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
764 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
765 gtk_recent_info_unref (item);
767 se = psppire_syntax_window_new (encoding);
771 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
772 gtk_widget_show (se);
774 gtk_widget_destroy (se);
780 set_unsaved (gpointer w)
782 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
786 on_switch_page (PsppireDataEditor *de, gpointer p,
787 gint pagenum, PsppireDataWindow *dw)
789 GtkWidget *page_menu_item;
793 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
795 ? "/ui/menubar/view/view_data"
796 : "/ui/menubar/view/view_variables");
797 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
798 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
802 on_ui_manager_changed (PsppireDataEditor *de,
803 GParamSpec *pspec UNUSED,
804 PsppireDataWindow *dw)
806 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
812 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
813 g_object_unref (dw->uim);
820 g_object_ref (dw->uim);
821 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
825 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
826 Returns a pointer to the action
829 connect_action (PsppireDataWindow *dw, const char *action_name,
832 GtkAction *action = get_action_assert (dw->builder, action_name);
834 g_signal_connect_swapped (action, "activate", handler, dw);
839 /* Only a data file with at least one variable can be saved. */
841 enable_save (PsppireDataWindow *dw)
843 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
845 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
847 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
851 /* Initializes as much of a PsppireDataWindow as we can and must before the
852 dataset has been set.
854 In particular, the 'menu' member is required in case the "filename" property
855 is set before the "dataset" property: otherwise PsppireWindow will try to
856 modify the menu as part of the "filename" property_set() function and end up
857 with a Gtk-CRITICAL since 'menu' is NULL. */
859 psppire_data_window_init (PsppireDataWindow *de)
861 de->builder = builder_new ("data-editor.ui");
863 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
865 PSPPIRE_WINDOW (de)->menu =
866 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
873 psppire_data_window_finish_init (PsppireDataWindow *de,
876 static const struct dataset_callbacks cbs =
878 set_unsaved, /* changed */
879 transformation_change_callback, /* transformations_changed */
886 GtkWidget *box = gtk_vbox_new (FALSE, 0);
889 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
890 de->data_store = psppire_data_store_new (de->dict);
891 psppire_data_store_set_reader (de->data_store, NULL);
893 menubar = get_widget_assert (de->builder, "menubar");
894 hb = get_widget_assert (de->builder, "handlebox1");
895 sb = get_widget_assert (de->builder, "status-bar");
901 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
902 g_signal_connect (de->data_editor, "switch-page",
903 G_CALLBACK (on_switch_page), de);
905 g_signal_connect_swapped (de->data_store, "case-changed",
906 G_CALLBACK (set_unsaved), de);
908 g_signal_connect_swapped (de->data_store, "case-inserted",
909 G_CALLBACK (set_unsaved), de);
911 g_signal_connect_swapped (de->data_store, "cases-deleted",
912 G_CALLBACK (set_unsaved), de);
914 dataset_set_callbacks (de->dataset, &cbs, de);
916 connect_help (de->builder);
918 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
919 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
920 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
921 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
923 gtk_container_add (GTK_CONTAINER (de), box);
925 g_signal_connect (de->dict, "weight-changed",
926 G_CALLBACK (on_weight_change),
929 g_signal_connect (de->dict, "filter-changed",
930 G_CALLBACK (on_filter_change),
933 g_signal_connect (de->dict, "split-changed",
934 G_CALLBACK (on_split_change),
937 g_signal_connect_swapped (de->dict, "backend-changed",
938 G_CALLBACK (enable_save), de);
939 g_signal_connect_swapped (de->dict, "variable-inserted",
940 G_CALLBACK (enable_save), de);
941 g_signal_connect_swapped (de->dict, "variable-deleted",
942 G_CALLBACK (enable_save), de);
945 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
946 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
947 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
948 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
949 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
950 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
951 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
952 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
954 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
956 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
957 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
958 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
959 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
960 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
961 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
962 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
963 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
964 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
965 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
966 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
967 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
970 GtkWidget *recent_data =
971 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
973 GtkWidget *recent_files =
974 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
977 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
978 gtk_recent_manager_get_default ());
980 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
981 gtk_recent_manager_get_default ());
983 g_object_set (menu_data, "show-tips", TRUE, NULL);
984 g_object_set (menu_files, "show-tips", TRUE, NULL);
987 GtkRecentFilter *filter = gtk_recent_filter_new ();
989 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
990 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
992 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
994 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
997 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1000 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1003 GtkRecentFilter *filter = gtk_recent_filter_new ();
1005 gtk_recent_filter_add_pattern (filter, "*.sps");
1006 gtk_recent_filter_add_pattern (filter, "*.SPS");
1008 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1010 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1013 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1015 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1019 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1022 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1023 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1025 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1027 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1029 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1031 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1033 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1035 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1037 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1039 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1041 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1043 merge_help_menu (de->ui_manager);
1045 g_signal_connect (de->data_editor, "notify::ui-manager",
1046 G_CALLBACK (on_ui_manager_changed), de);
1047 on_ui_manager_changed (de->data_editor, NULL, de);
1049 gtk_widget_show (GTK_WIDGET (de->data_editor));
1050 gtk_widget_show (box);
1052 ll_push_head (&all_data_windows, &de->ll);
1056 psppire_data_window_dispose (GObject *object)
1058 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1062 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1063 g_object_unref (dw->uim);
1067 if (dw->builder != NULL)
1069 g_object_unref (dw->builder);
1075 g_signal_handlers_disconnect_by_func (dw->dict,
1076 G_CALLBACK (enable_save), dw);
1077 g_signal_handlers_disconnect_by_func (dw->dict,
1078 G_CALLBACK (on_weight_change), dw);
1079 g_signal_handlers_disconnect_by_func (dw->dict,
1080 G_CALLBACK (on_filter_change), dw);
1081 g_signal_handlers_disconnect_by_func (dw->dict,
1082 G_CALLBACK (on_split_change), dw);
1084 g_object_unref (dw->dict);
1090 g_object_unref (dw->data_store);
1091 dw->data_store = NULL;
1094 if (dw->ll.next != NULL)
1096 ll_remove (&dw->ll);
1100 if (G_OBJECT_CLASS (parent_class)->dispose)
1101 G_OBJECT_CLASS (parent_class)->dispose (object);
1105 psppire_data_window_finalize (GObject *object)
1107 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1111 struct dataset *dataset = dw->dataset;
1112 struct session *session = dataset_session (dataset);
1116 dataset_set_callbacks (dataset, NULL, NULL);
1117 session_set_active_dataset (session, NULL);
1118 dataset_destroy (dataset);
1121 if (G_OBJECT_CLASS (parent_class)->finalize)
1122 G_OBJECT_CLASS (parent_class)->finalize (object);
1126 psppire_data_window_set_property (GObject *object,
1128 const GValue *value,
1131 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1136 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1139 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1145 psppire_data_window_get_property (GObject *object,
1150 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1155 g_value_set_pointer (value, window->dataset);
1158 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1164 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1170 ui_string = gtk_ui_manager_get_ui (uim);
1171 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1175 g_return_val_if_fail (merge_id != 0, 0);
1177 list = gtk_ui_manager_get_action_groups (uim);
1178 for (; list != NULL; list = list->next)
1180 GtkActionGroup *action_group = list->data;
1181 GList *actions = gtk_action_group_list_actions (action_group);
1184 for (action = actions; action != NULL; action = action->next)
1186 GtkAction *a = action->data;
1188 if (PSPPIRE_IS_DIALOG_ACTION (a))
1189 g_object_set (a, "manager", pdw->ui_manager, NULL);
1192 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1195 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1196 gtk_ui_manager_get_accel_group (uim));
1202 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1203 GtkUIManager *uim, guint merge_id)
1207 g_return_if_fail (merge_id != 0);
1209 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1211 list = gtk_ui_manager_get_action_groups (uim);
1212 for (; list != NULL; list = list->next)
1214 GtkActionGroup *action_group = list->data;
1215 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1218 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1219 gtk_ui_manager_get_accel_group (uim));
1223 psppire_data_window_new (struct dataset *ds)
1227 if (the_session == NULL)
1228 the_session = session_create (NULL);
1232 char *dataset_name = session_generate_dataset_name (the_session);
1233 ds = dataset_create (the_session, dataset_name);
1234 free (dataset_name);
1236 assert (dataset_session (ds) == the_session);
1240 psppire_data_window_get_type (),
1241 "description", _("Data Editor"),
1245 if (dataset_name (ds) != NULL)
1246 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1252 psppire_data_window_is_empty (PsppireDataWindow *dw)
1254 return psppire_dict_get_var_cnt (dw->dict) == 0;
1258 psppire_data_window_iface_init (PsppireWindowIface *iface)
1260 iface->save = save_file;
1261 iface->pick_filename = data_pick_filename;
1262 iface->load = load_file;
1266 psppire_default_data_window (void)
1268 if (ll_is_empty (&all_data_windows))
1269 create_data_window ();
1270 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1274 psppire_data_window_set_default (PsppireDataWindow *pdw)
1276 ll_remove (&pdw->ll);
1277 ll_push_head (&all_data_windows, &pdw->ll);
1281 psppire_data_window_undefault (PsppireDataWindow *pdw)
1283 ll_remove (&pdw->ll);
1284 ll_push_tail (&all_data_windows, &pdw->ll);
1288 psppire_data_window_for_dataset (struct dataset *ds)
1290 PsppireDataWindow *pdw;
1292 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1293 if (pdw->dataset == ds)
1300 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1302 PsppireDataWindow *pdw;
1304 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1305 if (pdw->data_store == data_store)
1312 create_data_window (void)
1314 gtk_widget_show (psppire_data_window_new (NULL));
1318 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1322 if (PSPPIRE_IS_DATA_WINDOW (victim)
1323 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1325 window = GTK_WIDGET (victim);
1326 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1329 window = psppire_data_window_new (NULL);
1331 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1332 gtk_widget_show_all (window);