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/psppire-data-window.h"
37 #include "ui/gui/psppire-dialog-action.h"
38 #include "ui/gui/psppire-syntax-window.h"
39 #include "ui/gui/psppire-window.h"
40 #include "ui/gui/psppire.h"
41 #include "ui/gui/recode-dialog.h"
42 #include "ui/gui/select-cases-dialog.h"
43 #include "ui/gui/split-file-dialog.h"
44 #include "ui/gui/text-data-import-dialog.h"
45 #include "ui/gui/weight-cases-dialog.h"
46 #include "ui/syntax-gen.h"
48 #include "gl/c-strcase.h"
49 #include "gl/c-strcasestr.h"
50 #include "gl/xvasprintf.h"
53 #define _(msgid) gettext (msgid)
54 #define N_(msgid) msgid
56 struct session *the_session;
57 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
59 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
60 static void psppire_data_window_init (PsppireDataWindow *data_editor);
63 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
65 static void psppire_data_window_dispose (GObject *object);
66 static void psppire_data_window_finalize (GObject *object);
67 static void psppire_data_window_set_property (GObject *object,
71 static void psppire_data_window_get_property (GObject *object,
76 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
77 static void psppire_data_window_remove_ui (PsppireDataWindow *,
78 GtkUIManager *, guint);
81 psppire_data_window_get_type (void)
83 static GType psppire_data_window_type = 0;
85 if (!psppire_data_window_type)
87 static const GTypeInfo psppire_data_window_info =
89 sizeof (PsppireDataWindowClass),
92 (GClassInitFunc)psppire_data_window_class_init,
93 (GClassFinalizeFunc) NULL,
95 sizeof (PsppireDataWindow),
97 (GInstanceInitFunc) psppire_data_window_init,
100 static const GInterfaceInfo window_interface_info =
102 (GInterfaceInitFunc) psppire_data_window_iface_init,
107 psppire_data_window_type =
108 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
109 &psppire_data_window_info, 0);
112 g_type_add_interface_static (psppire_data_window_type,
113 PSPPIRE_TYPE_WINDOW_MODEL,
114 &window_interface_info);
117 return psppire_data_window_type;
120 static GObjectClass *parent_class ;
127 psppire_data_window_class_init (PsppireDataWindowClass *class)
129 GObjectClass *object_class = G_OBJECT_CLASS (class);
131 parent_class = g_type_class_peek_parent (class);
133 object_class->dispose = psppire_data_window_dispose;
134 object_class->finalize = psppire_data_window_finalize;
135 object_class->set_property = psppire_data_window_set_property;
136 object_class->get_property = psppire_data_window_get_property;
138 g_object_class_install_property (
139 object_class, PROP_DATASET,
140 g_param_spec_pointer ("dataset", "Dataset",
141 "'struct datset *' represented by the window",
142 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
145 /* Run the EXECUTE command. */
147 execute (PsppireDataWindow *dw)
149 execute_const_syntax_string (dw, "EXECUTE.");
153 transformation_change_callback (bool transformations_pending,
156 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
158 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
160 GtkWidget *menuitem =
161 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
163 GtkWidget *status_label =
164 get_widget_assert (de->builder, "case-counter-area");
166 gtk_widget_set_sensitive (menuitem, transformations_pending);
169 if ( transformations_pending)
170 gtk_label_set_text (GTK_LABEL (status_label),
171 _("Transformations Pending"));
173 gtk_label_set_text (GTK_LABEL (status_label), "");
176 /* Callback for when the dictionary changes its filter variable */
178 on_filter_change (GObject *o, gint filter_index, gpointer data)
180 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
182 GtkWidget *filter_status_area =
183 get_widget_assert (de->builder, "filter-use-status-area");
185 if ( filter_index == -1 )
187 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
191 PsppireDict *dict = NULL;
192 struct variable *var ;
195 g_object_get (de->data_editor, "dictionary", &dict, NULL);
197 var = psppire_dict_get_variable (dict, filter_index);
199 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
201 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
207 /* Callback for when the dictionary changes its split variables */
209 on_split_change (PsppireDict *dict, gpointer data)
211 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
213 size_t n_split_vars = dict_get_split_cnt (dict->dict);
215 GtkWidget *split_status_area =
216 get_widget_assert (de->builder, "split-file-status-area");
218 if ( n_split_vars == 0 )
220 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
226 const struct variable *const * split_vars =
227 dict_get_split_vars (dict->dict);
229 text = g_string_new (_("Split by "));
231 for (i = 0 ; i < n_split_vars - 1; ++i )
233 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
235 g_string_append (text, var_get_name (split_vars[i]));
237 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
239 g_string_free (text, TRUE);
246 /* Callback for when the dictionary changes its weights */
248 on_weight_change (GObject *o, gint weight_index, gpointer data)
250 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
252 GtkWidget *weight_status_area =
253 get_widget_assert (de->builder, "weight-status-area");
255 if ( weight_index == -1 )
257 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
261 struct variable *var ;
262 PsppireDict *dict = NULL;
265 g_object_get (de->data_editor, "dictionary", &dict, NULL);
267 var = psppire_dict_get_variable (dict, weight_index);
269 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
271 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
279 dump_rm (GtkRecentManager *rm)
281 GList *items = gtk_recent_manager_get_items (rm);
285 g_print ("Recent Items:\n");
286 for (i = items; i; i = i->next)
288 GtkRecentInfo *ri = i->data;
290 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
291 gtk_recent_info_get_short_name (ri),
292 gtk_recent_info_get_mime_type (ri),
293 gtk_recent_info_get_description (ri),
294 gtk_recent_info_get_uri (ri)
298 gtk_recent_info_unref (ri);
306 name_has_por_suffix (const gchar *name)
308 size_t length = strlen (name);
309 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
313 name_has_sav_suffix (const gchar *name)
315 size_t length = strlen (name);
316 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
319 /* Returns true if NAME has a suffix which might denote a PSPP file */
321 name_has_suffix (const gchar *name)
323 return name_has_por_suffix (name) || name_has_sav_suffix (name);
327 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
329 const char *mime_type = NULL;
330 gchar *syntax = NULL;
335 gchar *utf8_file_name;
336 struct string filename;
337 ds_init_empty (&filename);
339 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
341 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
343 g_free (utf8_file_name);
345 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
346 ds_destroy (&filename);
354 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
355 lex_reader_for_string (syntax));
358 if (ok && syn == NULL)
360 if (name_has_por_suffix (file_name))
361 mime_type = "application/x-spss-por";
362 else if (name_has_sav_suffix (file_name))
363 mime_type = "application/x-spss-sav";
365 add_most_recent (file_name, mime_type);
371 /* Save DE to file */
373 save_file (PsppireWindow *w)
375 const gchar *file_name = NULL;
376 gchar *utf8_file_name = NULL;
378 struct string filename ;
379 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
382 file_name = psppire_window_get_filename (w);
384 fnx = g_string_new (file_name);
386 if ( ! name_has_suffix (fnx->str))
388 if ( de->save_as_portable)
389 g_string_append (fnx, ".por");
391 g_string_append (fnx, ".sav");
394 ds_init_empty (&filename);
396 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
398 g_string_free (fnx, TRUE);
400 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
401 g_free (utf8_file_name);
403 syntax = g_strdup_printf ("%s OUTFILE=%s.",
404 de->save_as_portable ? "EXPORT" : "SAVE",
405 ds_cstr (&filename));
407 ds_destroy (&filename);
409 g_free (execute_syntax_string (de, syntax));
414 display_dict (PsppireDataWindow *de)
416 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
420 sysfile_info (PsppireDataWindow *de)
422 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
424 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
426 struct string filename;
428 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
430 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
435 ds_init_empty (&filename);
437 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
439 g_free (utf8_file_name);
441 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
442 g_free (execute_syntax_string (de, syntax));
445 gtk_widget_destroy (dialog);
449 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
451 data_pick_filename (PsppireWindow *window)
453 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
454 GtkFileFilter *filter = gtk_file_filter_new ();
455 GtkWidget *button_sys;
457 gtk_file_chooser_dialog_new (_("Save"),
459 GTK_FILE_CHOOSER_ACTION_SAVE,
460 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
461 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
464 g_object_set (dialog, "local-only", FALSE, NULL);
466 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
467 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
468 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
470 filter = gtk_file_filter_new ();
471 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
472 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
473 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
475 filter = gtk_file_filter_new ();
476 gtk_file_filter_set_name (filter, _("All Files"));
477 gtk_file_filter_add_pattern (filter, "*");
478 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
481 GtkWidget *button_por;
482 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
484 gtk_radio_button_new_with_label (NULL, _("System File"));
487 gtk_radio_button_new_with_label
488 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
491 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
492 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
494 gtk_widget_show_all (vbox);
496 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
499 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
502 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
504 case GTK_RESPONSE_ACCEPT:
509 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
512 de->save_as_portable =
513 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
515 if ( ! name_has_suffix (filename->str))
517 if ( de->save_as_portable)
518 g_string_append (filename, ".por");
520 g_string_append (filename, ".sav");
523 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
525 g_string_free (filename, TRUE);
532 gtk_widget_destroy (dialog);
536 confirm_delete_dataset (PsppireDataWindow *de,
537 const char *old_dataset,
538 const char *new_dataset,
539 const char *existing_dataset)
544 dialog = gtk_message_dialog_new (
545 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
546 _("Delete Existing Dataset?"));
548 gtk_message_dialog_format_secondary_text (
549 GTK_MESSAGE_DIALOG (dialog),
550 _("Renaming \"%s\" to \"%s\" will destroy the existing "
551 "dataset named \"%s\". Are you sure that you want to do this?"),
552 old_dataset, new_dataset, existing_dataset);
554 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
555 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
556 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
559 g_object_set (dialog, "icon-name", "pspp", NULL);
561 result = gtk_dialog_run (GTK_DIALOG (dialog));
563 gtk_widget_destroy (dialog);
565 return result == GTK_RESPONSE_OK;
569 on_rename_dataset (PsppireDataWindow *de)
571 struct dataset *ds = de->dataset;
572 struct session *session = dataset_session (ds);
573 const char *old_name = dataset_name (ds);
574 struct dataset *existing_dataset;
578 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
580 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
584 if (new_name == NULL)
587 existing_dataset = session_lookup_dataset (session, new_name);
588 if (existing_dataset == NULL || existing_dataset == ds
589 || confirm_delete_dataset (de, old_name, new_name,
590 dataset_name (existing_dataset)))
591 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
598 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
600 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
602 if ( gtk_toggle_action_get_active (action))
603 gtk_widget_show (statusbar);
605 gtk_widget_hide (statusbar);
610 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
612 const gboolean grid_visible = gtk_toggle_action_get_active (action);
614 psppire_data_editor_show_grid (de->data_editor, grid_visible);
618 data_view_activate (PsppireDataWindow *de)
620 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
625 variable_view_activate (PsppireDataWindow *de)
627 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
632 fonts_activate (PsppireDataWindow *de)
634 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
635 PangoFontDescription *current_font;
638 gtk_font_selection_dialog_new (_("Font Selection"));
641 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
642 font_name = pango_font_description_to_string (current_font);
644 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
648 gtk_window_set_transient_for (GTK_WINDOW (dialog),
649 GTK_WINDOW (toplevel));
651 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
653 const gchar *font = gtk_font_selection_dialog_get_font_name
654 (GTK_FONT_SELECTION_DIALOG (dialog));
656 PangoFontDescription* font_desc =
657 pango_font_description_from_string (font);
659 psppire_data_editor_set_font (de->data_editor, font_desc);
662 gtk_widget_hide (dialog);
667 /* Callback for the value labels action */
669 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
671 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
675 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
677 psppire_data_editor_split_window (de->data_editor,
678 gtk_toggle_action_get_active (ta));
683 file_quit (PsppireDataWindow *de)
685 /* FIXME: Need to be more intelligent here.
686 Give the user the opportunity to save any unsaved data.
692 on_recent_data_select (GtkMenuShell *menushell,
693 PsppireWindow *window)
698 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
700 file = g_filename_from_uri (uri, NULL, NULL);
704 open_data_window (window, file, NULL);
710 charset_from_mime_type (const char *mime_type)
716 if (mime_type == NULL)
719 charset = c_strcasestr (mime_type, "charset=");
727 /* Parse a "quoted-string" as defined by RFC 822. */
728 for (p++; *p != '\0' && *p != '"'; p++)
731 ds_put_byte (&s, *p);
732 else if (*++p != '\0')
733 ds_put_byte (&s, *p);
738 /* Parse a "token" as defined by RFC 2045. */
739 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
740 ds_put_byte (&s, *p++);
742 if (!ds_is_empty (&s))
743 return ds_steal_cstr (&s);
750 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
757 /* Get the file name and its encoding. */
758 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
759 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
760 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
761 gtk_recent_info_unref (item);
763 se = psppire_syntax_window_new (encoding);
767 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
768 gtk_widget_show (se);
770 gtk_widget_destroy (se);
776 set_unsaved (gpointer w)
778 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
782 on_switch_page (PsppireDataEditor *de, gpointer p,
783 gint pagenum, PsppireDataWindow *dw)
785 GtkWidget *page_menu_item;
789 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
791 ? "/ui/menubar/view/view_data"
792 : "/ui/menubar/view/view_variables");
793 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
794 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
798 on_ui_manager_changed (PsppireDataEditor *de,
799 GParamSpec *pspec UNUSED,
800 PsppireDataWindow *dw)
802 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
808 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
809 g_object_unref (dw->uim);
816 g_object_ref (dw->uim);
817 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
821 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
822 Returns a pointer to the action
825 connect_action (PsppireDataWindow *dw, const char *action_name,
828 GtkAction *action = get_action_assert (dw->builder, action_name);
830 g_signal_connect_swapped (action, "activate", handler, dw);
835 /* Only a data file with at least one variable can be saved. */
837 enable_save (PsppireDataWindow *dw)
839 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
841 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
843 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
847 /* Initializes as much of a PsppireDataWindow as we can and must before the
848 dataset has been set.
850 In particular, the 'menu' member is required in case the "filename" property
851 is set before the "dataset" property: otherwise PsppireWindow will try to
852 modify the menu as part of the "filename" property_set() function and end up
853 with a Gtk-CRITICAL since 'menu' is NULL. */
855 psppire_data_window_init (PsppireDataWindow *de)
857 de->builder = builder_new ("data-editor.ui");
859 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
861 PSPPIRE_WINDOW (de)->menu =
862 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
869 psppire_data_window_finish_init (PsppireDataWindow *de,
872 static const struct dataset_callbacks cbs =
874 set_unsaved, /* changed */
875 transformation_change_callback, /* transformations_changed */
882 GtkWidget *box = gtk_vbox_new (FALSE, 0);
885 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
886 de->data_store = psppire_data_store_new (de->dict);
887 psppire_data_store_set_reader (de->data_store, NULL);
889 menubar = get_widget_assert (de->builder, "menubar");
890 hb = get_widget_assert (de->builder, "handlebox1");
891 sb = get_widget_assert (de->builder, "status-bar");
897 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
898 g_signal_connect (de->data_editor, "switch-page",
899 G_CALLBACK (on_switch_page), de);
901 g_signal_connect_swapped (de->data_store, "case-changed",
902 G_CALLBACK (set_unsaved), de);
904 g_signal_connect_swapped (de->data_store, "case-inserted",
905 G_CALLBACK (set_unsaved), de);
907 g_signal_connect_swapped (de->data_store, "cases-deleted",
908 G_CALLBACK (set_unsaved), de);
910 dataset_set_callbacks (de->dataset, &cbs, de);
912 connect_help (de->builder);
914 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
915 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
916 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
917 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
919 gtk_container_add (GTK_CONTAINER (de), box);
921 g_signal_connect (de->dict, "weight-changed",
922 G_CALLBACK (on_weight_change),
925 g_signal_connect (de->dict, "filter-changed",
926 G_CALLBACK (on_filter_change),
929 g_signal_connect (de->dict, "split-changed",
930 G_CALLBACK (on_split_change),
933 g_signal_connect_swapped (de->dict, "backend-changed",
934 G_CALLBACK (enable_save), de);
935 g_signal_connect_swapped (de->dict, "variable-inserted",
936 G_CALLBACK (enable_save), de);
937 g_signal_connect_swapped (de->dict, "variable-deleted",
938 G_CALLBACK (enable_save), de);
941 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
942 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
943 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
944 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
945 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
946 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
947 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
948 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
950 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
952 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
953 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
954 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
955 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
956 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
957 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
958 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
959 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
962 GtkWidget *recent_data =
963 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
965 GtkWidget *recent_files =
966 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
969 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
970 gtk_recent_manager_get_default ());
972 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
973 gtk_recent_manager_get_default ());
975 g_object_set (menu_data, "show-tips", TRUE, NULL);
976 g_object_set (menu_files, "show-tips", TRUE, NULL);
979 GtkRecentFilter *filter = gtk_recent_filter_new ();
981 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
982 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
984 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
986 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
989 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
992 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
995 GtkRecentFilter *filter = gtk_recent_filter_new ();
997 gtk_recent_filter_add_pattern (filter, "*.sps");
998 gtk_recent_filter_add_pattern (filter, "*.SPS");
1000 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1002 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1005 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1007 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1011 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1014 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1015 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1017 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1019 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1021 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1023 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1025 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1027 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1029 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1031 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1033 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1035 merge_help_menu (de->ui_manager);
1037 g_signal_connect (de->data_editor, "notify::ui-manager",
1038 G_CALLBACK (on_ui_manager_changed), de);
1039 on_ui_manager_changed (de->data_editor, NULL, de);
1041 gtk_widget_show (GTK_WIDGET (de->data_editor));
1042 gtk_widget_show (box);
1044 ll_push_head (&all_data_windows, &de->ll);
1048 psppire_data_window_dispose (GObject *object)
1050 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1054 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1055 g_object_unref (dw->uim);
1059 if (dw->builder != NULL)
1061 g_object_unref (dw->builder);
1067 g_signal_handlers_disconnect_by_func (dw->dict,
1068 G_CALLBACK (enable_save), dw);
1069 g_signal_handlers_disconnect_by_func (dw->dict,
1070 G_CALLBACK (on_weight_change), dw);
1071 g_signal_handlers_disconnect_by_func (dw->dict,
1072 G_CALLBACK (on_filter_change), dw);
1073 g_signal_handlers_disconnect_by_func (dw->dict,
1074 G_CALLBACK (on_split_change), dw);
1076 g_object_unref (dw->dict);
1082 g_object_unref (dw->data_store);
1083 dw->data_store = NULL;
1086 if (dw->ll.next != NULL)
1088 ll_remove (&dw->ll);
1092 if (G_OBJECT_CLASS (parent_class)->dispose)
1093 G_OBJECT_CLASS (parent_class)->dispose (object);
1097 psppire_data_window_finalize (GObject *object)
1099 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1103 struct dataset *dataset = dw->dataset;
1104 struct session *session = dataset_session (dataset);
1108 dataset_set_callbacks (dataset, NULL, NULL);
1109 session_set_active_dataset (session, NULL);
1110 dataset_destroy (dataset);
1113 if (G_OBJECT_CLASS (parent_class)->finalize)
1114 G_OBJECT_CLASS (parent_class)->finalize (object);
1118 psppire_data_window_set_property (GObject *object,
1120 const GValue *value,
1123 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1128 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1131 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1137 psppire_data_window_get_property (GObject *object,
1142 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1147 g_value_set_pointer (value, window->dataset);
1150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1156 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1162 ui_string = gtk_ui_manager_get_ui (uim);
1163 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1167 g_return_val_if_fail (merge_id != 0, 0);
1169 list = gtk_ui_manager_get_action_groups (uim);
1170 for (; list != NULL; list = list->next)
1172 GtkActionGroup *action_group = list->data;
1173 GList *actions = gtk_action_group_list_actions (action_group);
1176 for (action = actions; action != NULL; action = action->next)
1178 GtkAction *a = action->data;
1180 if (PSPPIRE_IS_DIALOG_ACTION (a))
1181 g_object_set (a, "manager", pdw->ui_manager, NULL);
1184 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1187 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1188 gtk_ui_manager_get_accel_group (uim));
1194 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1195 GtkUIManager *uim, guint merge_id)
1199 g_return_if_fail (merge_id != 0);
1201 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1203 list = gtk_ui_manager_get_action_groups (uim);
1204 for (; list != NULL; list = list->next)
1206 GtkActionGroup *action_group = list->data;
1207 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1210 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1211 gtk_ui_manager_get_accel_group (uim));
1215 psppire_data_window_new (struct dataset *ds)
1219 if (the_session == NULL)
1220 the_session = session_create (NULL);
1224 char *dataset_name = session_generate_dataset_name (the_session);
1225 ds = dataset_create (the_session, dataset_name);
1226 free (dataset_name);
1228 assert (dataset_session (ds) == the_session);
1232 psppire_data_window_get_type (),
1233 "description", _("Data Editor"),
1237 if (dataset_name (ds) != NULL)
1238 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1244 psppire_data_window_is_empty (PsppireDataWindow *dw)
1246 return psppire_dict_get_var_cnt (dw->dict) == 0;
1250 psppire_data_window_iface_init (PsppireWindowIface *iface)
1252 iface->save = save_file;
1253 iface->pick_filename = data_pick_filename;
1254 iface->load = load_file;
1258 psppire_default_data_window (void)
1260 if (ll_is_empty (&all_data_windows))
1261 create_data_window ();
1262 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1266 psppire_data_window_set_default (PsppireDataWindow *pdw)
1268 ll_remove (&pdw->ll);
1269 ll_push_head (&all_data_windows, &pdw->ll);
1273 psppire_data_window_undefault (PsppireDataWindow *pdw)
1275 ll_remove (&pdw->ll);
1276 ll_push_tail (&all_data_windows, &pdw->ll);
1280 psppire_data_window_for_dataset (struct dataset *ds)
1282 PsppireDataWindow *pdw;
1284 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1285 if (pdw->dataset == ds)
1292 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1294 PsppireDataWindow *pdw;
1296 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1297 if (pdw->data_store == data_store)
1304 create_data_window (void)
1306 gtk_widget_show (psppire_data_window_new (NULL));
1310 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1314 if (PSPPIRE_IS_DATA_WINDOW (victim)
1315 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1317 window = GTK_WIDGET (victim);
1318 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1321 window = psppire_data_window_new (NULL);
1323 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1324 gtk_widget_show_all (window);