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/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-encoding-selector.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 has_suffix (const gchar *name, const gchar *suffix)
309 size_t name_len = strlen (name);
310 size_t suffix_len = strlen (suffix);
311 return (name_len > suffix_len
312 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
316 name_has_por_suffix (const gchar *name)
318 return has_suffix (name, ".por");
322 name_has_sav_suffix (const gchar *name)
324 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
327 /* Returns true if NAME has a suffix which might denote a PSPP file */
329 name_has_suffix (const gchar *name)
331 return name_has_por_suffix (name) || name_has_sav_suffix (name);
335 load_file (PsppireWindow *de, const gchar *file_name, const char *encoding,
338 const char *mime_type = NULL;
339 gchar *syntax = NULL;
344 gchar *utf8_file_name;
345 struct string filename;
347 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
349 if (NULL == utf8_file_name)
352 ds_init_empty (&filename);
353 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
355 g_free (utf8_file_name);
357 if (encoding && encoding[0])
358 syntax = g_strdup_printf ("GET FILE=%s ENCODING='%s'.",
359 ds_cstr (&filename), encoding);
361 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
362 ds_destroy (&filename);
369 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
370 lex_reader_for_string (syntax));
373 if (ok && syn == NULL)
375 if (name_has_por_suffix (file_name))
376 mime_type = "application/x-spss-por";
377 else if (name_has_sav_suffix (file_name))
378 mime_type = "application/x-spss-sav";
380 add_most_recent (file_name, mime_type, encoding);
387 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
389 if (format == PSPPIRE_DATA_WINDOW_SAV)
391 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
397 /* Save DE to file */
399 save_file (PsppireWindow *w)
401 const gchar *file_name = NULL;
402 gchar *utf8_file_name = NULL;
404 struct string filename ;
405 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
408 file_name = psppire_window_get_filename (w);
410 fnx = g_string_new (file_name);
412 if ( ! name_has_suffix (fnx->str))
413 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
415 ds_init_empty (&filename);
417 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
419 g_string_free (fnx, TRUE);
421 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
422 g_free (utf8_file_name);
424 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
425 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
426 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
427 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
428 ds_cstr (&filename));
430 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
432 ds_destroy (&filename);
434 g_free (execute_syntax_string (de, syntax));
439 display_dict (PsppireDataWindow *de)
441 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
445 sysfile_info (PsppireDataWindow *de)
447 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
449 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
451 struct string filename;
453 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
454 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
457 const gchar *encoding = psppire_encoding_selector_get_encoding (
458 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
462 ds_init_empty (&filename);
464 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
466 g_free (utf8_file_name);
469 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
470 ds_cstr (&filename), encoding);
472 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
473 g_free (execute_syntax_string (de, syntax));
476 gtk_widget_destroy (dialog);
480 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
482 data_pick_filename (PsppireWindow *window)
484 GtkListStore *list_store;
485 GtkWidget *combo_box;
487 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
488 GtkFileFilter *filter;
490 gtk_file_chooser_dialog_new (_("Save"),
492 GTK_FILE_CHOOSER_ACTION_SAVE,
493 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
494 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
497 g_object_set (dialog, "local-only", FALSE, NULL);
499 filter = gtk_file_filter_new ();
500 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
501 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
502 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
504 filter = gtk_file_filter_new ();
505 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
506 gtk_file_filter_add_pattern (filter, "*.zsav");
507 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
509 filter = gtk_file_filter_new ();
510 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
511 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
512 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
514 filter = gtk_file_filter_new ();
515 gtk_file_filter_set_name (filter, _("All Files"));
516 gtk_file_filter_add_pattern (filter, "*");
517 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
518 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
521 GtkCellRenderer *cell;
526 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
527 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
529 gtk_list_store_append (list_store, &iter);
530 gtk_list_store_set (list_store, &iter,
531 0, PSPPIRE_DATA_WINDOW_SAV,
534 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
536 gtk_list_store_append (list_store, &iter);
537 gtk_list_store_set (list_store, &iter,
538 0, PSPPIRE_DATA_WINDOW_ZSAV,
539 1, _("Compressed System File"),
542 gtk_list_store_append (list_store, &iter);
543 gtk_list_store_set (list_store, &iter,
544 0, PSPPIRE_DATA_WINDOW_POR,
545 1, _("Portable File"),
548 label = gtk_label_new (_("Format:"));
550 cell = gtk_cell_renderer_text_new ();
551 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
552 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
555 hbox = gtk_hbox_new (FALSE, 0);
556 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
557 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
558 gtk_widget_show_all (hbox);
560 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
563 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
566 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
568 case GTK_RESPONSE_ACCEPT:
573 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
579 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
580 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
585 if ( ! name_has_suffix (filename->str))
586 g_string_append (filename,
587 psppire_data_window_format_to_string (format));
589 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
591 g_string_free (filename, TRUE);
598 gtk_widget_destroy (dialog);
602 confirm_delete_dataset (PsppireDataWindow *de,
603 const char *old_dataset,
604 const char *new_dataset,
605 const char *existing_dataset)
610 dialog = gtk_message_dialog_new (
611 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
612 _("Delete Existing Dataset?"));
614 gtk_message_dialog_format_secondary_text (
615 GTK_MESSAGE_DIALOG (dialog),
616 _("Renaming \"%s\" to \"%s\" will destroy the existing "
617 "dataset named \"%s\". Are you sure that you want to do this?"),
618 old_dataset, new_dataset, existing_dataset);
620 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
621 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
622 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
625 g_object_set (dialog, "icon-name", "pspp", NULL);
627 result = gtk_dialog_run (GTK_DIALOG (dialog));
629 gtk_widget_destroy (dialog);
631 return result == GTK_RESPONSE_OK;
635 on_rename_dataset (PsppireDataWindow *de)
637 struct dataset *ds = de->dataset;
638 struct session *session = dataset_session (ds);
639 const char *old_name = dataset_name (ds);
640 struct dataset *existing_dataset;
644 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
646 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
650 if (new_name == NULL)
653 existing_dataset = session_lookup_dataset (session, new_name);
654 if (existing_dataset == NULL || existing_dataset == ds
655 || confirm_delete_dataset (de, old_name, new_name,
656 dataset_name (existing_dataset)))
657 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
664 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
666 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
668 if ( gtk_toggle_action_get_active (action))
669 gtk_widget_show (statusbar);
671 gtk_widget_hide (statusbar);
676 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
678 const gboolean grid_visible = gtk_toggle_action_get_active (action);
680 psppire_data_editor_show_grid (de->data_editor, grid_visible);
684 data_view_activate (PsppireDataWindow *de)
686 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
691 variable_view_activate (PsppireDataWindow *de)
693 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
698 fonts_activate (PsppireDataWindow *de)
700 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
701 PangoFontDescription *current_font;
704 gtk_font_selection_dialog_new (_("Font Selection"));
707 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
708 font_name = pango_font_description_to_string (current_font);
710 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
714 gtk_window_set_transient_for (GTK_WINDOW (dialog),
715 GTK_WINDOW (toplevel));
717 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
719 const gchar *font = gtk_font_selection_dialog_get_font_name
720 (GTK_FONT_SELECTION_DIALOG (dialog));
722 PangoFontDescription* font_desc =
723 pango_font_description_from_string (font);
725 psppire_data_editor_set_font (de->data_editor, font_desc);
728 gtk_widget_hide (dialog);
733 /* Callback for the value labels action */
735 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
737 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
741 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
743 psppire_data_editor_split_window (de->data_editor,
744 gtk_toggle_action_get_active (ta));
749 file_quit (PsppireDataWindow *de)
751 /* FIXME: Need to be more intelligent here.
752 Give the user the opportunity to save any unsaved data.
758 on_recent_data_select (GtkMenuShell *menushell,
759 PsppireWindow *window)
764 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
766 file = g_filename_from_uri (uri, NULL, NULL);
770 open_data_window (window, file, NULL, NULL);
776 charset_from_mime_type (const char *mime_type)
782 if (mime_type == NULL)
785 charset = c_strcasestr (mime_type, "charset=");
793 /* Parse a "quoted-string" as defined by RFC 822. */
794 for (p++; *p != '\0' && *p != '"'; p++)
797 ds_put_byte (&s, *p);
798 else if (*++p != '\0')
799 ds_put_byte (&s, *p);
804 /* Parse a "token" as defined by RFC 2045. */
805 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
806 ds_put_byte (&s, *p++);
808 if (!ds_is_empty (&s))
809 return ds_steal_cstr (&s);
816 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
823 /* Get the file name and its encoding. */
824 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
825 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
826 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
827 gtk_recent_info_unref (item);
829 se = psppire_syntax_window_new (encoding);
833 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
834 gtk_widget_show (se);
836 gtk_widget_destroy (se);
842 set_unsaved (gpointer w)
844 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
848 on_switch_page (PsppireDataEditor *de, gpointer p,
849 gint pagenum, PsppireDataWindow *dw)
851 GtkWidget *page_menu_item;
855 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
857 ? "/ui/menubar/view/view_data"
858 : "/ui/menubar/view/view_variables");
859 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
860 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
864 on_ui_manager_changed (PsppireDataEditor *de,
865 GParamSpec *pspec UNUSED,
866 PsppireDataWindow *dw)
868 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
874 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
875 g_object_unref (dw->uim);
882 g_object_ref (dw->uim);
883 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
887 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
888 Returns a pointer to the action
891 connect_action (PsppireDataWindow *dw, const char *action_name,
894 GtkAction *action = get_action_assert (dw->builder, action_name);
896 g_signal_connect_swapped (action, "activate", handler, dw);
901 /* Only a data file with at least one variable can be saved. */
903 enable_save (PsppireDataWindow *dw)
905 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
907 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
909 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
913 /* Initializes as much of a PsppireDataWindow as we can and must before the
914 dataset has been set.
916 In particular, the 'menu' member is required in case the "filename" property
917 is set before the "dataset" property: otherwise PsppireWindow will try to
918 modify the menu as part of the "filename" property_set() function and end up
919 with a Gtk-CRITICAL since 'menu' is NULL. */
921 psppire_data_window_init (PsppireDataWindow *de)
923 de->builder = builder_new ("data-editor.ui");
925 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
927 PSPPIRE_WINDOW (de)->menu =
928 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
935 psppire_data_window_finish_init (PsppireDataWindow *de,
938 static const struct dataset_callbacks cbs =
940 set_unsaved, /* changed */
941 transformation_change_callback, /* transformations_changed */
948 GtkWidget *box = gtk_vbox_new (FALSE, 0);
951 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
952 de->data_store = psppire_data_store_new (de->dict);
953 psppire_data_store_set_reader (de->data_store, NULL);
955 menubar = get_widget_assert (de->builder, "menubar");
956 hb = get_widget_assert (de->builder, "handlebox1");
957 sb = get_widget_assert (de->builder, "status-bar");
963 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
964 g_signal_connect (de->data_editor, "switch-page",
965 G_CALLBACK (on_switch_page), de);
967 g_signal_connect_swapped (de->data_store, "case-changed",
968 G_CALLBACK (set_unsaved), de);
970 g_signal_connect_swapped (de->data_store, "case-inserted",
971 G_CALLBACK (set_unsaved), de);
973 g_signal_connect_swapped (de->data_store, "cases-deleted",
974 G_CALLBACK (set_unsaved), de);
976 dataset_set_callbacks (de->dataset, &cbs, de);
978 connect_help (de->builder);
980 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
981 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
982 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
983 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
985 gtk_container_add (GTK_CONTAINER (de), box);
987 g_signal_connect (de->dict, "weight-changed",
988 G_CALLBACK (on_weight_change),
991 g_signal_connect (de->dict, "filter-changed",
992 G_CALLBACK (on_filter_change),
995 g_signal_connect (de->dict, "split-changed",
996 G_CALLBACK (on_split_change),
999 g_signal_connect_swapped (de->dict, "backend-changed",
1000 G_CALLBACK (enable_save), de);
1001 g_signal_connect_swapped (de->dict, "variable-inserted",
1002 G_CALLBACK (enable_save), de);
1003 g_signal_connect_swapped (de->dict, "variable-deleted",
1004 G_CALLBACK (enable_save), de);
1007 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1008 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
1009 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1010 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1011 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1012 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1013 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1014 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1016 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1018 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1019 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1020 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1021 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1022 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1023 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1024 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1025 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1028 GtkWidget *recent_data =
1029 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
1031 GtkWidget *recent_files =
1032 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
1035 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1036 gtk_recent_manager_get_default ());
1038 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1039 gtk_recent_manager_get_default ());
1041 g_object_set (menu_data, "show-tips", TRUE, NULL);
1042 g_object_set (menu_files, "show-tips", TRUE, NULL);
1045 GtkRecentFilter *filter = gtk_recent_filter_new ();
1047 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1048 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1050 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1052 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1055 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1058 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1061 GtkRecentFilter *filter = gtk_recent_filter_new ();
1063 gtk_recent_filter_add_pattern (filter, "*.sps");
1064 gtk_recent_filter_add_pattern (filter, "*.SPS");
1066 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1068 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1071 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1073 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1077 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1080 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1081 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1083 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1085 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1087 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1089 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1091 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1093 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1095 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1097 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1099 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1101 merge_help_menu (de->ui_manager);
1103 g_signal_connect (de->data_editor, "notify::ui-manager",
1104 G_CALLBACK (on_ui_manager_changed), de);
1105 on_ui_manager_changed (de->data_editor, NULL, de);
1107 gtk_widget_show (GTK_WIDGET (de->data_editor));
1108 gtk_widget_show (box);
1110 ll_push_head (&all_data_windows, &de->ll);
1114 psppire_data_window_dispose (GObject *object)
1116 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1120 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1121 g_object_unref (dw->uim);
1125 if (dw->builder != NULL)
1127 g_object_unref (dw->builder);
1133 g_signal_handlers_disconnect_by_func (dw->dict,
1134 G_CALLBACK (enable_save), dw);
1135 g_signal_handlers_disconnect_by_func (dw->dict,
1136 G_CALLBACK (on_weight_change), dw);
1137 g_signal_handlers_disconnect_by_func (dw->dict,
1138 G_CALLBACK (on_filter_change), dw);
1139 g_signal_handlers_disconnect_by_func (dw->dict,
1140 G_CALLBACK (on_split_change), dw);
1142 g_object_unref (dw->dict);
1148 g_object_unref (dw->data_store);
1149 dw->data_store = NULL;
1152 if (dw->ll.next != NULL)
1154 ll_remove (&dw->ll);
1158 if (G_OBJECT_CLASS (parent_class)->dispose)
1159 G_OBJECT_CLASS (parent_class)->dispose (object);
1163 psppire_data_window_finalize (GObject *object)
1165 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1169 struct dataset *dataset = dw->dataset;
1170 struct session *session = dataset_session (dataset);
1174 dataset_set_callbacks (dataset, NULL, NULL);
1175 session_set_active_dataset (session, NULL);
1176 dataset_destroy (dataset);
1179 if (G_OBJECT_CLASS (parent_class)->finalize)
1180 G_OBJECT_CLASS (parent_class)->finalize (object);
1184 psppire_data_window_set_property (GObject *object,
1186 const GValue *value,
1189 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1194 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1197 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1203 psppire_data_window_get_property (GObject *object,
1208 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1213 g_value_set_pointer (value, window->dataset);
1216 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1222 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1228 ui_string = gtk_ui_manager_get_ui (uim);
1229 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1233 g_return_val_if_fail (merge_id != 0, 0);
1235 list = gtk_ui_manager_get_action_groups (uim);
1236 for (; list != NULL; list = list->next)
1238 GtkActionGroup *action_group = list->data;
1239 GList *actions = gtk_action_group_list_actions (action_group);
1242 for (action = actions; action != NULL; action = action->next)
1244 GtkAction *a = action->data;
1246 if (PSPPIRE_IS_DIALOG_ACTION (a))
1247 g_object_set (a, "manager", pdw->ui_manager, NULL);
1250 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1253 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1254 gtk_ui_manager_get_accel_group (uim));
1260 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1261 GtkUIManager *uim, guint merge_id)
1265 g_return_if_fail (merge_id != 0);
1267 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1269 list = gtk_ui_manager_get_action_groups (uim);
1270 for (; list != NULL; list = list->next)
1272 GtkActionGroup *action_group = list->data;
1273 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1276 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1277 gtk_ui_manager_get_accel_group (uim));
1281 psppire_data_window_new (struct dataset *ds)
1285 if (the_session == NULL)
1286 the_session = session_create (NULL);
1290 char *dataset_name = session_generate_dataset_name (the_session);
1291 ds = dataset_create (the_session, dataset_name);
1292 free (dataset_name);
1294 assert (dataset_session (ds) == the_session);
1298 psppire_data_window_get_type (),
1299 "description", _("Data Editor"),
1303 if (dataset_name (ds) != NULL)
1304 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1310 psppire_data_window_is_empty (PsppireDataWindow *dw)
1312 return psppire_dict_get_var_cnt (dw->dict) == 0;
1316 psppire_data_window_iface_init (PsppireWindowIface *iface)
1318 iface->save = save_file;
1319 iface->pick_filename = data_pick_filename;
1320 iface->load = load_file;
1324 psppire_default_data_window (void)
1326 if (ll_is_empty (&all_data_windows))
1327 create_data_window ();
1328 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1332 psppire_data_window_set_default (PsppireDataWindow *pdw)
1334 ll_remove (&pdw->ll);
1335 ll_push_head (&all_data_windows, &pdw->ll);
1339 psppire_data_window_undefault (PsppireDataWindow *pdw)
1341 ll_remove (&pdw->ll);
1342 ll_push_tail (&all_data_windows, &pdw->ll);
1346 psppire_data_window_for_dataset (struct dataset *ds)
1348 PsppireDataWindow *pdw;
1350 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1351 if (pdw->dataset == ds)
1358 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1360 PsppireDataWindow *pdw;
1362 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1363 if (pdw->data_store == data_store)
1370 create_data_window (void)
1372 gtk_widget_show (psppire_data_window_new (NULL));
1376 open_data_window (PsppireWindow *victim, const char *file_name,
1377 const char *encoding, gpointer hint)
1381 if (PSPPIRE_IS_DATA_WINDOW (victim)
1382 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1384 window = GTK_WIDGET (victim);
1385 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1388 window = psppire_data_window_new (NULL);
1390 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
1391 gtk_widget_show_all (window);