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/entry-dialog.h"
32 #include "ui/gui/executor.h"
33 #include "ui/gui/help-menu.h"
34 #include "ui/gui/helper.h"
35 #include "ui/gui/helper.h"
36 #include "ui/gui/oneway-anova-dialog.h"
37 #include "ui/gui/psppire-data-window.h"
38 #include "ui/gui/psppire-dialog-action.h"
39 #include "ui/gui/psppire-syntax-window.h"
40 #include "ui/gui/psppire-window.h"
41 #include "ui/gui/psppire.h"
42 #include "ui/gui/recode-dialog.h"
43 #include "ui/gui/select-cases-dialog.h"
44 #include "ui/gui/split-file-dialog.h"
45 #include "ui/gui/text-data-import-dialog.h"
46 #include "ui/gui/weight-cases-dialog.h"
47 #include "ui/syntax-gen.h"
49 #include "gl/c-strcase.h"
50 #include "gl/c-strcasestr.h"
51 #include "gl/xvasprintf.h"
54 #define _(msgid) gettext (msgid)
55 #define N_(msgid) msgid
57 struct session *the_session;
58 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
60 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
61 static void psppire_data_window_init (PsppireDataWindow *data_editor);
64 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
66 static void psppire_data_window_dispose (GObject *object);
67 static void psppire_data_window_finalize (GObject *object);
68 static void psppire_data_window_set_property (GObject *object,
72 static void psppire_data_window_get_property (GObject *object,
77 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
78 static void psppire_data_window_remove_ui (PsppireDataWindow *,
79 GtkUIManager *, guint);
82 psppire_data_window_get_type (void)
84 static GType psppire_data_window_type = 0;
86 if (!psppire_data_window_type)
88 static const GTypeInfo psppire_data_window_info =
90 sizeof (PsppireDataWindowClass),
93 (GClassInitFunc)psppire_data_window_class_init,
94 (GClassFinalizeFunc) NULL,
96 sizeof (PsppireDataWindow),
98 (GInstanceInitFunc) psppire_data_window_init,
101 static const GInterfaceInfo window_interface_info =
103 (GInterfaceInitFunc) psppire_data_window_iface_init,
108 psppire_data_window_type =
109 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
110 &psppire_data_window_info, 0);
113 g_type_add_interface_static (psppire_data_window_type,
114 PSPPIRE_TYPE_WINDOW_MODEL,
115 &window_interface_info);
118 return psppire_data_window_type;
121 static GObjectClass *parent_class ;
128 psppire_data_window_class_init (PsppireDataWindowClass *class)
130 GObjectClass *object_class = G_OBJECT_CLASS (class);
132 parent_class = g_type_class_peek_parent (class);
134 object_class->dispose = psppire_data_window_dispose;
135 object_class->finalize = psppire_data_window_finalize;
136 object_class->set_property = psppire_data_window_set_property;
137 object_class->get_property = psppire_data_window_get_property;
139 g_object_class_install_property (
140 object_class, PROP_DATASET,
141 g_param_spec_pointer ("dataset", "Dataset",
142 "'struct datset *' represented by the window",
143 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
146 /* Run the EXECUTE command. */
148 execute (PsppireDataWindow *dw)
150 execute_const_syntax_string (dw, "EXECUTE.");
154 transformation_change_callback (bool transformations_pending,
157 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
159 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
161 GtkWidget *menuitem =
162 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
164 GtkWidget *status_label =
165 get_widget_assert (de->builder, "case-counter-area");
167 gtk_widget_set_sensitive (menuitem, transformations_pending);
170 if ( transformations_pending)
171 gtk_label_set_text (GTK_LABEL (status_label),
172 _("Transformations Pending"));
174 gtk_label_set_text (GTK_LABEL (status_label), "");
177 /* Callback for when the dictionary changes its filter variable */
179 on_filter_change (GObject *o, gint filter_index, gpointer data)
181 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
183 GtkWidget *filter_status_area =
184 get_widget_assert (de->builder, "filter-use-status-area");
186 if ( filter_index == -1 )
188 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
192 PsppireDict *dict = NULL;
193 struct variable *var ;
196 g_object_get (de->data_editor, "dictionary", &dict, NULL);
198 var = psppire_dict_get_variable (dict, filter_index);
200 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
202 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
208 /* Callback for when the dictionary changes its split variables */
210 on_split_change (PsppireDict *dict, gpointer data)
212 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
214 size_t n_split_vars = dict_get_split_cnt (dict->dict);
216 GtkWidget *split_status_area =
217 get_widget_assert (de->builder, "split-file-status-area");
219 if ( n_split_vars == 0 )
221 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
227 const struct variable *const * split_vars =
228 dict_get_split_vars (dict->dict);
230 text = g_string_new (_("Split by "));
232 for (i = 0 ; i < n_split_vars - 1; ++i )
234 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
236 g_string_append (text, var_get_name (split_vars[i]));
238 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
240 g_string_free (text, TRUE);
247 /* Callback for when the dictionary changes its weights */
249 on_weight_change (GObject *o, gint weight_index, gpointer data)
251 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
253 GtkWidget *weight_status_area =
254 get_widget_assert (de->builder, "weight-status-area");
256 if ( weight_index == -1 )
258 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
262 struct variable *var ;
263 PsppireDict *dict = NULL;
266 g_object_get (de->data_editor, "dictionary", &dict, NULL);
268 var = psppire_dict_get_variable (dict, weight_index);
270 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
272 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
280 dump_rm (GtkRecentManager *rm)
282 GList *items = gtk_recent_manager_get_items (rm);
286 g_print ("Recent Items:\n");
287 for (i = items; i; i = i->next)
289 GtkRecentInfo *ri = i->data;
291 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
292 gtk_recent_info_get_short_name (ri),
293 gtk_recent_info_get_mime_type (ri),
294 gtk_recent_info_get_description (ri),
295 gtk_recent_info_get_uri (ri)
299 gtk_recent_info_unref (ri);
307 name_has_por_suffix (const gchar *name)
309 size_t length = strlen (name);
310 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
314 name_has_sav_suffix (const gchar *name)
316 size_t length = strlen (name);
317 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
320 /* Returns true if NAME has a suffix which might denote a PSPP file */
322 name_has_suffix (const gchar *name)
324 return name_has_por_suffix (name) || name_has_sav_suffix (name);
328 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
330 const char *mime_type = NULL;
331 gchar *syntax = NULL;
336 gchar *utf8_file_name;
337 struct string filename;
338 ds_init_empty (&filename);
340 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
342 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
344 g_free (utf8_file_name);
346 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
347 ds_destroy (&filename);
355 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
356 lex_reader_for_string (syntax));
359 if (ok && syn == NULL)
361 if (name_has_por_suffix (file_name))
362 mime_type = "application/x-spss-por";
363 else if (name_has_sav_suffix (file_name))
364 mime_type = "application/x-spss-sav";
366 add_most_recent (file_name, mime_type);
372 /* Save DE to file */
374 save_file (PsppireWindow *w)
376 const gchar *file_name = NULL;
377 gchar *utf8_file_name = NULL;
379 struct string filename ;
380 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
383 file_name = psppire_window_get_filename (w);
385 fnx = g_string_new (file_name);
387 if ( ! name_has_suffix (fnx->str))
389 if ( de->save_as_portable)
390 g_string_append (fnx, ".por");
392 g_string_append (fnx, ".sav");
395 ds_init_empty (&filename);
397 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
399 g_string_free (fnx, TRUE);
401 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
402 g_free (utf8_file_name);
404 syntax = g_strdup_printf ("%s OUTFILE=%s.",
405 de->save_as_portable ? "EXPORT" : "SAVE",
406 ds_cstr (&filename));
408 ds_destroy (&filename);
410 g_free (execute_syntax_string (de, syntax));
415 display_dict (PsppireDataWindow *de)
417 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
421 sysfile_info (PsppireDataWindow *de)
423 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
425 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
427 struct string filename;
429 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
431 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
436 ds_init_empty (&filename);
438 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
440 g_free (utf8_file_name);
442 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
443 g_free (execute_syntax_string (de, syntax));
446 gtk_widget_destroy (dialog);
450 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
452 data_pick_filename (PsppireWindow *window)
454 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
455 GtkFileFilter *filter = gtk_file_filter_new ();
456 GtkWidget *button_sys;
458 gtk_file_chooser_dialog_new (_("Save"),
460 GTK_FILE_CHOOSER_ACTION_SAVE,
461 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
462 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
465 g_object_set (dialog, "local-only", FALSE, NULL);
467 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
468 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
469 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
471 filter = gtk_file_filter_new ();
472 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
473 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
474 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
476 filter = gtk_file_filter_new ();
477 gtk_file_filter_set_name (filter, _("All Files"));
478 gtk_file_filter_add_pattern (filter, "*");
479 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
482 GtkWidget *button_por;
483 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
485 gtk_radio_button_new_with_label (NULL, _("System File"));
488 gtk_radio_button_new_with_label
489 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
492 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
493 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
495 gtk_widget_show_all (vbox);
497 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
500 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
503 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
505 case GTK_RESPONSE_ACCEPT:
510 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
513 de->save_as_portable =
514 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
516 if ( ! name_has_suffix (filename->str))
518 if ( de->save_as_portable)
519 g_string_append (filename, ".por");
521 g_string_append (filename, ".sav");
524 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
526 g_string_free (filename, TRUE);
533 gtk_widget_destroy (dialog);
537 confirm_delete_dataset (PsppireDataWindow *de,
538 const char *old_dataset,
539 const char *new_dataset,
540 const char *existing_dataset)
545 dialog = gtk_message_dialog_new (
546 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
547 _("Delete Existing Dataset?"));
549 gtk_message_dialog_format_secondary_text (
550 GTK_MESSAGE_DIALOG (dialog),
551 _("Renaming \"%s\" to \"%s\" will destroy the existing "
552 "dataset named \"%s\". Are you sure that you want to do this?"),
553 old_dataset, new_dataset, existing_dataset);
555 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
556 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
557 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
560 g_object_set (dialog, "icon-name", "pspp", NULL);
562 result = gtk_dialog_run (GTK_DIALOG (dialog));
564 gtk_widget_destroy (dialog);
566 return result == GTK_RESPONSE_OK;
570 on_rename_dataset (PsppireDataWindow *de)
572 struct dataset *ds = de->dataset;
573 struct session *session = dataset_session (ds);
574 const char *old_name = dataset_name (ds);
575 struct dataset *existing_dataset;
579 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
581 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
585 if (new_name == NULL)
588 existing_dataset = session_lookup_dataset (session, new_name);
589 if (existing_dataset == NULL || existing_dataset == ds
590 || confirm_delete_dataset (de, old_name, new_name,
591 dataset_name (existing_dataset)))
592 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
599 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
601 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
603 if ( gtk_toggle_action_get_active (action))
604 gtk_widget_show (statusbar);
606 gtk_widget_hide (statusbar);
611 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
613 const gboolean grid_visible = gtk_toggle_action_get_active (action);
615 psppire_data_editor_show_grid (de->data_editor, grid_visible);
619 data_view_activate (PsppireDataWindow *de)
621 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
626 variable_view_activate (PsppireDataWindow *de)
628 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
633 fonts_activate (PsppireDataWindow *de)
635 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
636 PangoFontDescription *current_font;
639 gtk_font_selection_dialog_new (_("Font Selection"));
642 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
643 font_name = pango_font_description_to_string (current_font);
645 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
649 gtk_window_set_transient_for (GTK_WINDOW (dialog),
650 GTK_WINDOW (toplevel));
652 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
654 const gchar *font = gtk_font_selection_dialog_get_font_name
655 (GTK_FONT_SELECTION_DIALOG (dialog));
657 PangoFontDescription* font_desc =
658 pango_font_description_from_string (font);
660 psppire_data_editor_set_font (de->data_editor, font_desc);
663 gtk_widget_hide (dialog);
668 /* Callback for the value labels action */
670 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
672 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
676 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
678 psppire_data_editor_split_window (de->data_editor,
679 gtk_toggle_action_get_active (ta));
684 file_quit (PsppireDataWindow *de)
686 /* FIXME: Need to be more intelligent here.
687 Give the user the opportunity to save any unsaved data.
693 on_recent_data_select (GtkMenuShell *menushell,
694 PsppireWindow *window)
699 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
701 file = g_filename_from_uri (uri, NULL, NULL);
705 open_data_window (window, file, NULL);
711 charset_from_mime_type (const char *mime_type)
717 if (mime_type == NULL)
720 charset = c_strcasestr (mime_type, "charset=");
728 /* Parse a "quoted-string" as defined by RFC 822. */
729 for (p++; *p != '\0' && *p != '"'; p++)
732 ds_put_byte (&s, *p);
733 else if (*++p != '\0')
734 ds_put_byte (&s, *p);
739 /* Parse a "token" as defined by RFC 2045. */
740 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
741 ds_put_byte (&s, *p++);
743 if (!ds_is_empty (&s))
744 return ds_steal_cstr (&s);
751 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
758 /* Get the file name and its encoding. */
759 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
760 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
761 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
762 gtk_recent_info_unref (item);
764 se = psppire_syntax_window_new (encoding);
768 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
769 gtk_widget_show (se);
771 gtk_widget_destroy (se);
777 set_unsaved (gpointer w)
779 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
783 on_switch_page (PsppireDataEditor *de, gpointer p,
784 gint pagenum, PsppireDataWindow *dw)
786 GtkWidget *page_menu_item;
790 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
792 ? "/ui/menubar/view/view_data"
793 : "/ui/menubar/view/view_variables");
794 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
795 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
799 on_ui_manager_changed (PsppireDataEditor *de,
800 GParamSpec *pspec UNUSED,
801 PsppireDataWindow *dw)
803 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
809 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
810 g_object_unref (dw->uim);
817 g_object_ref (dw->uim);
818 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
822 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
823 Returns a pointer to the action
826 connect_action (PsppireDataWindow *dw, const char *action_name,
829 GtkAction *action = get_action_assert (dw->builder, action_name);
831 g_signal_connect_swapped (action, "activate", handler, dw);
836 /* Only a data file with at least one variable can be saved. */
838 enable_save (PsppireDataWindow *dw)
840 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
842 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
844 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
848 /* Initializes as much of a PsppireDataWindow as we can and must before the
849 dataset has been set.
851 In particular, the 'menu' member is required in case the "filename" property
852 is set before the "dataset" property: otherwise PsppireWindow will try to
853 modify the menu as part of the "filename" property_set() function and end up
854 with a Gtk-CRITICAL since 'menu' is NULL. */
856 psppire_data_window_init (PsppireDataWindow *de)
858 de->builder = builder_new ("data-editor.ui");
860 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
862 PSPPIRE_WINDOW (de)->menu =
863 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
870 psppire_data_window_finish_init (PsppireDataWindow *de,
873 static const struct dataset_callbacks cbs =
875 set_unsaved, /* changed */
876 transformation_change_callback, /* transformations_changed */
883 GtkWidget *box = gtk_vbox_new (FALSE, 0);
886 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
887 de->data_store = psppire_data_store_new (de->dict);
888 psppire_data_store_set_reader (de->data_store, NULL);
890 menubar = get_widget_assert (de->builder, "menubar");
891 hb = get_widget_assert (de->builder, "handlebox1");
892 sb = get_widget_assert (de->builder, "status-bar");
898 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
899 g_signal_connect (de->data_editor, "switch-page",
900 G_CALLBACK (on_switch_page), de);
902 g_signal_connect_swapped (de->data_store, "case-changed",
903 G_CALLBACK (set_unsaved), de);
905 g_signal_connect_swapped (de->data_store, "case-inserted",
906 G_CALLBACK (set_unsaved), de);
908 g_signal_connect_swapped (de->data_store, "cases-deleted",
909 G_CALLBACK (set_unsaved), de);
911 dataset_set_callbacks (de->dataset, &cbs, de);
913 connect_help (de->builder);
915 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
916 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
917 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
918 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
920 gtk_container_add (GTK_CONTAINER (de), box);
922 g_signal_connect (de->dict, "weight-changed",
923 G_CALLBACK (on_weight_change),
926 g_signal_connect (de->dict, "filter-changed",
927 G_CALLBACK (on_filter_change),
930 g_signal_connect (de->dict, "split-changed",
931 G_CALLBACK (on_split_change),
934 g_signal_connect_swapped (de->dict, "backend-changed",
935 G_CALLBACK (enable_save), de);
936 g_signal_connect_swapped (de->dict, "variable-inserted",
937 G_CALLBACK (enable_save), de);
938 g_signal_connect_swapped (de->dict, "variable-deleted",
939 G_CALLBACK (enable_save), de);
942 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
943 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
944 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
945 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
946 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
947 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
948 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
949 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
951 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
953 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
954 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
955 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
956 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
957 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
958 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
959 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
960 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
961 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
964 GtkWidget *recent_data =
965 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
967 GtkWidget *recent_files =
968 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
971 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
972 gtk_recent_manager_get_default ());
974 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
975 gtk_recent_manager_get_default ());
977 g_object_set (menu_data, "show-tips", TRUE, NULL);
978 g_object_set (menu_files, "show-tips", TRUE, NULL);
981 GtkRecentFilter *filter = gtk_recent_filter_new ();
983 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
984 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
986 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
988 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
991 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
994 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
997 GtkRecentFilter *filter = gtk_recent_filter_new ();
999 gtk_recent_filter_add_pattern (filter, "*.sps");
1000 gtk_recent_filter_add_pattern (filter, "*.SPS");
1002 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1004 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1007 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1009 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1013 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1016 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1017 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1019 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1021 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1023 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1025 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1027 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1029 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1031 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1033 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1035 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1037 merge_help_menu (de->ui_manager);
1039 g_signal_connect (de->data_editor, "notify::ui-manager",
1040 G_CALLBACK (on_ui_manager_changed), de);
1041 on_ui_manager_changed (de->data_editor, NULL, de);
1043 gtk_widget_show (GTK_WIDGET (de->data_editor));
1044 gtk_widget_show (box);
1046 ll_push_head (&all_data_windows, &de->ll);
1050 psppire_data_window_dispose (GObject *object)
1052 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1056 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1057 g_object_unref (dw->uim);
1061 if (dw->builder != NULL)
1063 g_object_unref (dw->builder);
1069 g_signal_handlers_disconnect_by_func (dw->dict,
1070 G_CALLBACK (enable_save), dw);
1071 g_signal_handlers_disconnect_by_func (dw->dict,
1072 G_CALLBACK (on_weight_change), dw);
1073 g_signal_handlers_disconnect_by_func (dw->dict,
1074 G_CALLBACK (on_filter_change), dw);
1075 g_signal_handlers_disconnect_by_func (dw->dict,
1076 G_CALLBACK (on_split_change), dw);
1078 g_object_unref (dw->dict);
1084 g_object_unref (dw->data_store);
1085 dw->data_store = NULL;
1088 if (dw->ll.next != NULL)
1090 ll_remove (&dw->ll);
1094 if (G_OBJECT_CLASS (parent_class)->dispose)
1095 G_OBJECT_CLASS (parent_class)->dispose (object);
1099 psppire_data_window_finalize (GObject *object)
1101 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1105 struct dataset *dataset = dw->dataset;
1106 struct session *session = dataset_session (dataset);
1110 dataset_set_callbacks (dataset, NULL, NULL);
1111 session_set_active_dataset (session, NULL);
1112 dataset_destroy (dataset);
1115 if (G_OBJECT_CLASS (parent_class)->finalize)
1116 G_OBJECT_CLASS (parent_class)->finalize (object);
1120 psppire_data_window_set_property (GObject *object,
1122 const GValue *value,
1125 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1130 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1133 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1139 psppire_data_window_get_property (GObject *object,
1144 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1149 g_value_set_pointer (value, window->dataset);
1152 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1158 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1164 ui_string = gtk_ui_manager_get_ui (uim);
1165 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1169 g_return_val_if_fail (merge_id != 0, 0);
1171 list = gtk_ui_manager_get_action_groups (uim);
1172 for (; list != NULL; list = list->next)
1174 GtkActionGroup *action_group = list->data;
1175 GList *actions = gtk_action_group_list_actions (action_group);
1178 for (action = actions; action != NULL; action = action->next)
1180 GtkAction *a = action->data;
1182 if (PSPPIRE_IS_DIALOG_ACTION (a))
1183 g_object_set (a, "manager", pdw->ui_manager, NULL);
1186 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1189 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1190 gtk_ui_manager_get_accel_group (uim));
1196 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1197 GtkUIManager *uim, guint merge_id)
1201 g_return_if_fail (merge_id != 0);
1203 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1205 list = gtk_ui_manager_get_action_groups (uim);
1206 for (; list != NULL; list = list->next)
1208 GtkActionGroup *action_group = list->data;
1209 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1212 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1213 gtk_ui_manager_get_accel_group (uim));
1217 psppire_data_window_new (struct dataset *ds)
1221 if (the_session == NULL)
1222 the_session = session_create (NULL);
1226 char *dataset_name = session_generate_dataset_name (the_session);
1227 ds = dataset_create (the_session, dataset_name);
1228 free (dataset_name);
1230 assert (dataset_session (ds) == the_session);
1234 psppire_data_window_get_type (),
1235 "description", _("Data Editor"),
1239 if (dataset_name (ds) != NULL)
1240 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1246 psppire_data_window_is_empty (PsppireDataWindow *dw)
1248 return psppire_dict_get_var_cnt (dw->dict) == 0;
1252 psppire_data_window_iface_init (PsppireWindowIface *iface)
1254 iface->save = save_file;
1255 iface->pick_filename = data_pick_filename;
1256 iface->load = load_file;
1260 psppire_default_data_window (void)
1262 if (ll_is_empty (&all_data_windows))
1263 create_data_window ();
1264 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1268 psppire_data_window_set_default (PsppireDataWindow *pdw)
1270 ll_remove (&pdw->ll);
1271 ll_push_head (&all_data_windows, &pdw->ll);
1275 psppire_data_window_undefault (PsppireDataWindow *pdw)
1277 ll_remove (&pdw->ll);
1278 ll_push_tail (&all_data_windows, &pdw->ll);
1282 psppire_data_window_for_dataset (struct dataset *ds)
1284 PsppireDataWindow *pdw;
1286 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1287 if (pdw->dataset == ds)
1294 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1296 PsppireDataWindow *pdw;
1298 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1299 if (pdw->data_store == data_store)
1306 create_data_window (void)
1308 gtk_widget_show (psppire_data_window_new (NULL));
1312 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1316 if (PSPPIRE_IS_DATA_WINDOW (victim)
1317 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1319 window = GTK_WIDGET (victim);
1320 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1323 window = psppire_data_window_new (NULL);
1325 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1326 gtk_widget_show_all (window);