1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 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/builder-wrapper.h"
28 #include "ui/gui/entry-dialog.h"
29 #include "ui/gui/executor.h"
30 #include "ui/gui/help-menu.h"
31 #include "ui/gui/helper.h"
32 #include "ui/gui/helper.h"
33 #include "ui/gui/psppire-import-assistant.h"
34 #include "ui/gui/psppire-data-window.h"
35 #include "ui/gui/psppire-dialog-action.h"
36 #include "ui/gui/psppire-encoding-selector.h"
37 #include "ui/gui/psppire-syntax-window.h"
38 #include "ui/gui/psppire-window.h"
39 #include "ui/gui/psppire.h"
40 #include "ui/syntax-gen.h"
42 #include "gl/c-strcase.h"
43 #include "gl/c-strcasestr.h"
44 #include "gl/xvasprintf.h"
47 #define _(msgid) gettext (msgid)
48 #define N_(msgid) msgid
50 struct session *the_session;
51 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
53 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
54 static void psppire_data_window_init (PsppireDataWindow *data_editor);
57 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
59 static void psppire_data_window_dispose (GObject *object);
60 static void psppire_data_window_finalize (GObject *object);
61 static void psppire_data_window_set_property (GObject *object,
65 static void psppire_data_window_get_property (GObject *object,
70 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
71 static void psppire_data_window_remove_ui (PsppireDataWindow *,
72 GtkUIManager *, guint);
75 psppire_data_window_get_type (void)
77 static GType psppire_data_window_type = 0;
79 if (!psppire_data_window_type)
81 static const GTypeInfo psppire_data_window_info =
83 sizeof (PsppireDataWindowClass),
86 (GClassInitFunc)psppire_data_window_class_init,
87 (GClassFinalizeFunc) NULL,
89 sizeof (PsppireDataWindow),
91 (GInstanceInitFunc) psppire_data_window_init,
94 static const GInterfaceInfo window_interface_info =
96 (GInterfaceInitFunc) psppire_data_window_iface_init,
101 psppire_data_window_type =
102 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
103 &psppire_data_window_info, 0);
106 g_type_add_interface_static (psppire_data_window_type,
107 PSPPIRE_TYPE_WINDOW_MODEL,
108 &window_interface_info);
111 return psppire_data_window_type;
114 static GObjectClass *parent_class ;
121 psppire_data_window_class_init (PsppireDataWindowClass *class)
123 GObjectClass *object_class = G_OBJECT_CLASS (class);
125 parent_class = g_type_class_peek_parent (class);
127 object_class->dispose = psppire_data_window_dispose;
128 object_class->finalize = psppire_data_window_finalize;
129 object_class->set_property = psppire_data_window_set_property;
130 object_class->get_property = psppire_data_window_get_property;
132 g_object_class_install_property (
133 object_class, PROP_DATASET,
134 g_param_spec_pointer ("dataset", "Dataset",
135 "'struct datset *' represented by the window",
136 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
139 /* Run the EXECUTE command. */
141 execute (PsppireDataWindow *dw)
143 execute_const_syntax_string (dw, "EXECUTE.");
147 transformation_change_callback (bool transformations_pending,
150 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
152 GtkWidget *status_label =
153 get_widget_assert (de->builder, "case-counter-area");
155 { /* Set the sensitivity of the "Transformations Pending" menuitem */
157 GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
159 GtkWidget *menuitem =
160 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
162 gtk_widget_set_sensitive (menuitem, transformations_pending);
166 if ( transformations_pending)
167 gtk_label_set_text (GTK_LABEL (status_label),
168 _("Transformations Pending"));
170 gtk_label_set_text (GTK_LABEL (status_label), "");
173 /* Callback for when the dictionary changes its filter variable */
175 on_filter_change (GObject *o, gint filter_index, gpointer data)
177 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
179 GtkWidget *filter_status_area =
180 get_widget_assert (de->builder, "filter-use-status-area");
182 if ( filter_index == -1 )
184 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
188 PsppireDict *dict = NULL;
189 struct variable *var ;
192 g_object_get (de->data_editor, "dictionary", &dict, NULL);
194 var = psppire_dict_get_variable (dict, filter_index);
196 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
198 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
204 /* Callback for when the dictionary changes its split variables */
206 on_split_change (PsppireDict *dict, gpointer data)
208 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
210 size_t n_split_vars = dict_get_split_cnt (dict->dict);
212 GtkWidget *split_status_area =
213 get_widget_assert (de->builder, "split-file-status-area");
215 if ( n_split_vars == 0 )
217 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
223 const struct variable *const * split_vars =
224 dict_get_split_vars (dict->dict);
226 text = g_string_new (_("Split by "));
228 for (i = 0 ; i < n_split_vars - 1; ++i )
230 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
232 g_string_append (text, var_get_name (split_vars[i]));
234 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
236 g_string_free (text, TRUE);
243 /* Callback for when the dictionary changes its weights */
245 on_weight_change (GObject *o, gint weight_index, gpointer data)
247 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
249 GtkWidget *weight_status_area =
250 get_widget_assert (de->builder, "weight-status-area");
252 if ( weight_index == -1 )
254 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
258 struct variable *var ;
259 PsppireDict *dict = NULL;
262 g_object_get (de->data_editor, "dictionary", &dict, NULL);
264 var = psppire_dict_get_variable (dict, weight_index);
266 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
268 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
276 dump_rm (GtkRecentManager *rm)
278 GList *items = gtk_recent_manager_get_items (rm);
282 g_print ("Recent Items:\n");
283 for (i = items; i; i = i->next)
285 GtkRecentInfo *ri = i->data;
287 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
288 gtk_recent_info_get_short_name (ri),
289 gtk_recent_info_get_mime_type (ri),
290 gtk_recent_info_get_description (ri),
291 gtk_recent_info_get_uri (ri)
295 gtk_recent_info_unref (ri);
303 has_suffix (const gchar *name, const gchar *suffix)
305 size_t name_len = strlen (name);
306 size_t suffix_len = strlen (suffix);
307 return (name_len > suffix_len
308 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
312 name_has_por_suffix (const gchar *name)
314 return has_suffix (name, ".por");
318 name_has_sav_suffix (const gchar *name)
320 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
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, const char *encoding,
334 const char *mime_type = NULL;
335 gchar *syntax = NULL;
340 gchar *utf8_file_name;
341 struct string filename;
343 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
345 if (NULL == utf8_file_name)
348 ds_init_empty (&filename);
349 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
351 g_free (utf8_file_name);
353 if (encoding && encoding[0])
354 syntax = g_strdup_printf ("GET FILE=%s ENCODING='%s'.",
355 ds_cstr (&filename), encoding);
357 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
358 ds_destroy (&filename);
365 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
366 lex_reader_for_string (syntax, "UTF-8"));
369 if (ok && syn == NULL)
371 if (name_has_por_suffix (file_name))
372 mime_type = "application/x-spss-por";
373 else if (name_has_sav_suffix (file_name))
374 mime_type = "application/x-spss-sav";
376 add_most_recent (file_name, mime_type, encoding);
383 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
385 if (format == PSPPIRE_DATA_WINDOW_SAV)
387 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
393 /* Save DE to file */
395 save_file (PsppireWindow *w)
397 const gchar *file_name = NULL;
398 gchar *utf8_file_name = NULL;
400 struct string filename ;
401 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
404 file_name = psppire_window_get_filename (w);
406 fnx = g_string_new (file_name);
408 if ( ! name_has_suffix (fnx->str))
409 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
411 ds_init_empty (&filename);
413 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
415 g_string_free (fnx, TRUE);
417 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
418 g_free (utf8_file_name);
420 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
421 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
422 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
423 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
424 ds_cstr (&filename));
426 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
428 ds_destroy (&filename);
430 g_free (execute_syntax_string (de, syntax));
435 display_dict (PsppireDataWindow *de)
437 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
441 sysfile_info (PsppireDataWindow *de)
443 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
445 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
447 struct string filename;
449 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
450 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
453 const gchar *encoding = psppire_encoding_selector_get_encoding (
454 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
458 ds_init_empty (&filename);
460 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
462 g_free (utf8_file_name);
465 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
466 ds_cstr (&filename), encoding);
468 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
469 g_free (execute_syntax_string (de, syntax));
472 gtk_widget_destroy (dialog);
476 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
478 data_pick_filename (PsppireWindow *window)
480 GtkListStore *list_store;
481 GtkWidget *combo_box;
483 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
484 GtkFileFilter *filter;
486 gtk_file_chooser_dialog_new (_("Save"),
488 GTK_FILE_CHOOSER_ACTION_SAVE,
489 _("Cancel"), GTK_RESPONSE_CANCEL,
490 _("Save"), GTK_RESPONSE_ACCEPT,
493 g_object_set (dialog, "local-only", FALSE, NULL);
495 filter = gtk_file_filter_new ();
496 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
497 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
498 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
500 filter = gtk_file_filter_new ();
501 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
502 gtk_file_filter_add_pattern (filter, "*.zsav");
503 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
505 filter = gtk_file_filter_new ();
506 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
507 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
508 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
510 filter = gtk_file_filter_new ();
511 gtk_file_filter_set_name (filter, _("All Files"));
512 gtk_file_filter_add_pattern (filter, "*");
513 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
514 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
517 GtkCellRenderer *cell;
522 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
523 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
525 gtk_list_store_append (list_store, &iter);
526 gtk_list_store_set (list_store, &iter,
527 0, PSPPIRE_DATA_WINDOW_SAV,
530 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
532 gtk_list_store_append (list_store, &iter);
533 gtk_list_store_set (list_store, &iter,
534 0, PSPPIRE_DATA_WINDOW_ZSAV,
535 1, _("Compressed System File"),
538 gtk_list_store_append (list_store, &iter);
539 gtk_list_store_set (list_store, &iter,
540 0, PSPPIRE_DATA_WINDOW_POR,
541 1, _("Portable File"),
544 label = gtk_label_new (_("Format:"));
546 cell = gtk_cell_renderer_text_new ();
547 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
548 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
551 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
552 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
553 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
554 gtk_widget_show_all (hbox);
556 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
559 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
562 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
564 case GTK_RESPONSE_ACCEPT:
569 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
575 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
576 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
581 if ( ! name_has_suffix (filename->str))
582 g_string_append (filename,
583 psppire_data_window_format_to_string (format));
585 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
587 g_string_free (filename, TRUE);
594 gtk_widget_destroy (dialog);
598 confirm_delete_dataset (PsppireDataWindow *de,
599 const char *old_dataset,
600 const char *new_dataset,
601 const char *existing_dataset)
606 dialog = gtk_message_dialog_new (
607 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
608 _("Delete Existing Dataset?"));
610 gtk_message_dialog_format_secondary_text (
611 GTK_MESSAGE_DIALOG (dialog),
612 _("Renaming \"%s\" to \"%s\" will destroy the existing "
613 "dataset named \"%s\". Are you sure that you want to do this?"),
614 old_dataset, new_dataset, existing_dataset);
616 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
617 _("Cancel"), GTK_RESPONSE_CANCEL,
618 _("Delete"), GTK_RESPONSE_OK,
621 g_object_set (dialog, "icon-name", "pspp", NULL);
623 result = gtk_dialog_run (GTK_DIALOG (dialog));
625 gtk_widget_destroy (dialog);
627 return result == GTK_RESPONSE_OK;
631 on_rename_dataset (PsppireDataWindow *de)
633 struct dataset *ds = de->dataset;
634 struct session *session = dataset_session (ds);
635 const char *old_name = dataset_name (ds);
636 struct dataset *existing_dataset;
640 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
642 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
646 if (new_name == NULL)
649 existing_dataset = session_lookup_dataset (session, new_name);
650 if (existing_dataset == NULL || existing_dataset == ds
651 || confirm_delete_dataset (de, old_name, new_name,
652 dataset_name (existing_dataset)))
653 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
660 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
662 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
664 if ( gtk_toggle_action_get_active (action))
665 gtk_widget_show (statusbar);
667 gtk_widget_hide (statusbar);
672 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
674 const gboolean grid_visible = gtk_toggle_action_get_active (action);
676 psppire_data_editor_show_grid (de->data_editor, grid_visible);
680 data_view_activate (PsppireDataWindow *de)
682 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
687 variable_view_activate (PsppireDataWindow *de)
689 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
694 fonts_activate (PsppireDataWindow *de)
696 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
697 GtkWidget *dialog = gtk_font_chooser_dialog_new (NULL, GTK_WINDOW (toplevel));
698 GtkStyle *style = gtk_widget_get_style (GTK_WIDGET(de->data_editor));
699 PangoFontDescription *current_font = style->font_desc;
701 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (dialog), current_font);
703 gtk_window_set_transient_for (GTK_WINDOW (dialog),
704 GTK_WINDOW (toplevel));
706 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
708 PangoFontDescription* font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog));
710 psppire_data_editor_set_font (de->data_editor, font_desc);
713 gtk_widget_hide (dialog);
718 /* Callback for the value labels action */
720 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
722 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
726 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
728 psppire_data_editor_split_window (de->data_editor,
729 gtk_toggle_action_get_active (ta));
734 file_quit (PsppireDataWindow *de)
736 /* FIXME: Need to be more intelligent here.
737 Give the user the opportunity to save any unsaved data.
743 on_recent_data_select (GtkMenuShell *menushell,
744 PsppireWindow *window)
749 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
751 file = g_filename_from_uri (uri, NULL, NULL);
755 open_data_window (window, file, NULL, NULL);
761 charset_from_mime_type (const char *mime_type)
767 if (mime_type == NULL)
770 charset = c_strcasestr (mime_type, "charset=");
778 /* Parse a "quoted-string" as defined by RFC 822. */
779 for (p++; *p != '\0' && *p != '"'; p++)
782 ds_put_byte (&s, *p);
783 else if (*++p != '\0')
784 ds_put_byte (&s, *p);
789 /* Parse a "token" as defined by RFC 2045. */
790 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
791 ds_put_byte (&s, *p++);
793 if (!ds_is_empty (&s))
794 return ds_steal_cstr (&s);
801 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
808 /* Get the file name and its encoding. */
809 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
810 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
811 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
812 gtk_recent_info_unref (item);
814 se = psppire_syntax_window_new (encoding);
818 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
819 gtk_widget_show (se);
821 gtk_widget_destroy (se);
827 set_unsaved (gpointer w)
829 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
833 on_switch_page (PsppireDataEditor *de, gpointer p,
834 gint pagenum, PsppireDataWindow *dw)
836 /* Set the appropriate ui_manager according to the selected page.
837 This is necessary, because the menus for the variable view and
838 the data view are different (slightly). */
840 gboolean is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
841 const char *path = (is_ds
842 ? "/ui/menubar/view/view_data"
843 : "/ui/menubar/view/view_variables");
845 GtkWidget *page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
846 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
850 on_ui_manager_changed (PsppireDataEditor *de,
851 GParamSpec *pspec UNUSED,
852 PsppireDataWindow *dw)
854 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
860 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
861 g_object_unref (dw->uim);
868 g_object_ref (dw->uim);
869 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
873 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
874 Returns a pointer to the action
877 connect_action (PsppireDataWindow *dw, const char *action_name,
880 GtkAction *action = get_action_assert (dw->builder, action_name);
882 g_signal_connect_swapped (action, "activate", handler, dw);
887 /* Only a data file with at least one variable can be saved. */
889 enable_save (PsppireDataWindow *dw)
891 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
893 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
895 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
899 /* Initializes as much of a PsppireDataWindow as we can and must before the
900 dataset has been set.
902 In particular, the 'menu' member is required in case the "filename" property
903 is set before the "dataset" property: otherwise PsppireWindow will try to
904 modify the menu as part of the "filename" property_set() function and end up
905 with a Gtk-CRITICAL since 'menu' is NULL. */
907 psppire_data_window_init (PsppireDataWindow *de)
910 de->builder = builder_new ("data-editor.ui");
912 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
914 w = gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all");
916 PSPPIRE_WINDOW (de)->menu = GTK_MENU_SHELL (gtk_widget_get_parent (w));
923 file_import (PsppireDataWindow *dw)
925 GtkWidget *w = psppire_import_assistant_new (GTK_WINDOW (dw));
926 PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
927 gtk_widget_show_all (w);
929 asst->main_loop = g_main_loop_new (NULL, TRUE);
930 g_main_loop_run (asst->main_loop);
931 g_main_loop_unref (asst->main_loop);
933 if (!asst->file_name)
936 switch (asst->response)
938 case GTK_RESPONSE_APPLY:
941 gchar *fn = g_path_get_basename (asst->file_name);
942 open_data_window (PSPPIRE_WINDOW (dw), fn, NULL, psppire_import_assistant_generate_syntax (asst));
946 case PSPPIRE_RESPONSE_PASTE:
948 free (paste_syntax_to_window (psppire_import_assistant_generate_syntax (asst)));
955 gtk_widget_destroy (GTK_WIDGET (asst));
959 psppire_data_window_finish_init (PsppireDataWindow *de,
962 static const struct dataset_callbacks cbs =
964 set_unsaved, /* changed */
965 transformation_change_callback, /* transformations_changed */
972 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
975 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
976 de->data_store = psppire_data_store_new (de->dict);
977 psppire_data_store_set_reader (de->data_store, NULL);
979 menubar = get_widget_assert (de->builder, "menubar");
980 hb = get_widget_assert (de->builder, "toolbar");
981 sb = get_widget_assert (de->builder, "status-bar");
987 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
988 g_signal_connect (de->data_editor, "switch-page",
989 G_CALLBACK (on_switch_page), de);
991 g_signal_connect_swapped (de->data_store, "case-changed",
992 G_CALLBACK (set_unsaved), de);
994 g_signal_connect_swapped (de->data_store, "case-inserted",
995 G_CALLBACK (set_unsaved), de);
997 g_signal_connect_swapped (de->data_store, "cases-deleted",
998 G_CALLBACK (set_unsaved), de);
1000 dataset_set_callbacks (de->dataset, &cbs, de);
1002 connect_help (de->builder);
1004 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1005 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1006 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1007 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1009 gtk_container_add (GTK_CONTAINER (de), box);
1011 g_signal_connect (de->dict, "weight-changed",
1012 G_CALLBACK (on_weight_change),
1015 g_signal_connect (de->dict, "filter-changed",
1016 G_CALLBACK (on_filter_change),
1019 g_signal_connect (de->dict, "split-changed",
1020 G_CALLBACK (on_split_change),
1023 g_signal_connect_swapped (de->dict, "backend-changed",
1024 G_CALLBACK (enable_save), de);
1025 g_signal_connect_swapped (de->dict, "variable-inserted",
1026 G_CALLBACK (enable_save), de);
1027 g_signal_connect_swapped (de->dict, "variable-deleted",
1028 G_CALLBACK (enable_save), de);
1031 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1032 connect_action (de, "file_import", G_CALLBACK (file_import));
1034 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1035 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1036 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1037 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1038 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1039 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1041 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1044 GtkWidget *recent_data =
1045 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
1047 GtkWidget *recent_files =
1048 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
1051 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1052 gtk_recent_manager_get_default ());
1054 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1055 gtk_recent_manager_get_default ());
1057 g_object_set (menu_data, "show-tips", TRUE, NULL);
1058 g_object_set (menu_files, "show-tips", TRUE, NULL);
1061 GtkRecentFilter *filter = gtk_recent_filter_new ();
1063 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1064 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1066 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1068 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1071 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1074 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1077 GtkRecentFilter *filter = gtk_recent_filter_new ();
1079 gtk_recent_filter_add_pattern (filter, "*.sps");
1080 gtk_recent_filter_add_pattern (filter, "*.SPS");
1082 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1084 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1087 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1089 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1093 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1096 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1097 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1099 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1101 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1103 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1105 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1107 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1109 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1111 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1113 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1115 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1117 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1119 g_signal_connect (de->data_editor, "notify::ui-manager",
1120 G_CALLBACK (on_ui_manager_changed), de);
1121 on_ui_manager_changed (de->data_editor, NULL, de);
1123 gtk_widget_show (GTK_WIDGET (de->data_editor));
1124 gtk_widget_show (box);
1126 ll_push_head (&all_data_windows, &de->ll);
1130 psppire_data_window_dispose (GObject *object)
1132 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1136 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1137 g_object_unref (dw->uim);
1141 if (dw->builder != NULL)
1143 g_object_unref (dw->builder);
1149 g_signal_handlers_disconnect_by_func (dw->dict,
1150 G_CALLBACK (enable_save), dw);
1151 g_signal_handlers_disconnect_by_func (dw->dict,
1152 G_CALLBACK (on_weight_change), dw);
1153 g_signal_handlers_disconnect_by_func (dw->dict,
1154 G_CALLBACK (on_filter_change), dw);
1155 g_signal_handlers_disconnect_by_func (dw->dict,
1156 G_CALLBACK (on_split_change), dw);
1158 g_object_unref (dw->dict);
1164 g_object_unref (dw->data_store);
1165 dw->data_store = NULL;
1168 if (dw->ll.next != NULL)
1170 ll_remove (&dw->ll);
1174 if (G_OBJECT_CLASS (parent_class)->dispose)
1175 G_OBJECT_CLASS (parent_class)->dispose (object);
1179 psppire_data_window_finalize (GObject *object)
1181 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1185 struct dataset *dataset = dw->dataset;
1186 struct session *session = dataset_session (dataset);
1190 dataset_set_callbacks (dataset, NULL, NULL);
1191 session_set_active_dataset (session, NULL);
1192 dataset_destroy (dataset);
1195 if (G_OBJECT_CLASS (parent_class)->finalize)
1196 G_OBJECT_CLASS (parent_class)->finalize (object);
1200 psppire_data_window_set_property (GObject *object,
1202 const GValue *value,
1205 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1210 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1213 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1219 psppire_data_window_get_property (GObject *object,
1224 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1229 g_value_set_pointer (value, window->dataset);
1232 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1238 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1244 ui_string = gtk_ui_manager_get_ui (uim);
1245 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1249 g_return_val_if_fail (merge_id != 0, 0);
1251 list = gtk_ui_manager_get_action_groups (uim);
1252 for (; list != NULL; list = list->next)
1254 GtkActionGroup *action_group = list->data;
1255 GList *actions = gtk_action_group_list_actions (action_group);
1258 for (action = actions; action != NULL; action = action->next)
1260 GtkAction *a = action->data;
1262 if (PSPPIRE_IS_DIALOG_ACTION (a))
1263 g_object_set (a, "manager", pdw->ui_manager, NULL);
1266 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1269 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1270 gtk_ui_manager_get_accel_group (uim));
1276 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1277 GtkUIManager *uim, guint merge_id)
1281 g_return_if_fail (merge_id != 0);
1283 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1285 list = gtk_ui_manager_get_action_groups (uim);
1286 for (; list != NULL; list = list->next)
1288 GtkActionGroup *action_group = list->data;
1289 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1292 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1293 gtk_ui_manager_get_accel_group (uim));
1297 psppire_data_window_new (struct dataset *ds)
1301 if (the_session == NULL)
1302 the_session = session_create (NULL);
1306 char *dataset_name = session_generate_dataset_name (the_session);
1307 ds = dataset_create (the_session, dataset_name);
1308 free (dataset_name);
1310 assert (dataset_session (ds) == the_session);
1314 psppire_data_window_get_type (),
1315 "description", _("Data Editor"),
1319 if (dataset_name (ds) != NULL)
1320 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1326 psppire_data_window_is_empty (PsppireDataWindow *dw)
1328 return psppire_dict_get_var_cnt (dw->dict) == 0;
1332 psppire_data_window_iface_init (PsppireWindowIface *iface)
1334 iface->save = save_file;
1335 iface->pick_filename = data_pick_filename;
1336 iface->load = load_file;
1340 psppire_default_data_window (void)
1342 if (ll_is_empty (&all_data_windows))
1343 create_data_window ();
1344 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1348 psppire_data_window_set_default (PsppireDataWindow *pdw)
1350 ll_remove (&pdw->ll);
1351 ll_push_head (&all_data_windows, &pdw->ll);
1355 psppire_data_window_undefault (PsppireDataWindow *pdw)
1357 ll_remove (&pdw->ll);
1358 ll_push_tail (&all_data_windows, &pdw->ll);
1362 psppire_data_window_for_dataset (struct dataset *ds)
1364 PsppireDataWindow *pdw;
1366 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1367 if (pdw->dataset == ds)
1374 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1376 PsppireDataWindow *pdw;
1378 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1379 if (pdw->data_store == data_store)
1386 create_data_window (void)
1388 gtk_widget_show (psppire_data_window_new (NULL));
1392 open_data_window (PsppireWindow *victim, const char *file_name,
1393 const char *encoding, gpointer hint)
1397 if (PSPPIRE_IS_DATA_WINDOW (victim)
1398 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1400 window = GTK_WIDGET (victim);
1401 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1404 window = psppire_data_window_new (NULL);
1406 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
1407 gtk_widget_show_all (window);