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 GtkWidget *dialog = gtk_font_selection_dialog_new (_("Font Selection"));
702 GtkStyle *style = gtk_widget_get_style (GTK_WIDGET(de->data_editor));
703 PangoFontDescription *current_font = style->font_desc;
704 gchar *font_name = pango_font_description_to_string (current_font);
706 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
710 gtk_window_set_transient_for (GTK_WINDOW (dialog),
711 GTK_WINDOW (toplevel));
713 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
715 const gchar *font = gtk_font_selection_dialog_get_font_name
716 (GTK_FONT_SELECTION_DIALOG (dialog));
718 PangoFontDescription* font_desc =
719 pango_font_description_from_string (font);
721 psppire_data_editor_set_font (de->data_editor, font_desc);
724 gtk_widget_hide (dialog);
729 /* Callback for the value labels action */
731 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
733 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
737 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
739 psppire_data_editor_split_window (de->data_editor,
740 gtk_toggle_action_get_active (ta));
745 file_quit (PsppireDataWindow *de)
747 /* FIXME: Need to be more intelligent here.
748 Give the user the opportunity to save any unsaved data.
754 on_recent_data_select (GtkMenuShell *menushell,
755 PsppireWindow *window)
760 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
762 file = g_filename_from_uri (uri, NULL, NULL);
766 open_data_window (window, file, NULL, NULL);
772 charset_from_mime_type (const char *mime_type)
778 if (mime_type == NULL)
781 charset = c_strcasestr (mime_type, "charset=");
789 /* Parse a "quoted-string" as defined by RFC 822. */
790 for (p++; *p != '\0' && *p != '"'; p++)
793 ds_put_byte (&s, *p);
794 else if (*++p != '\0')
795 ds_put_byte (&s, *p);
800 /* Parse a "token" as defined by RFC 2045. */
801 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
802 ds_put_byte (&s, *p++);
804 if (!ds_is_empty (&s))
805 return ds_steal_cstr (&s);
812 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
819 /* Get the file name and its encoding. */
820 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
821 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
822 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
823 gtk_recent_info_unref (item);
825 se = psppire_syntax_window_new (encoding);
829 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
830 gtk_widget_show (se);
832 gtk_widget_destroy (se);
838 set_unsaved (gpointer w)
840 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
844 on_switch_page (PsppireDataEditor *de, gpointer p,
845 gint pagenum, PsppireDataWindow *dw)
847 GtkWidget *page_menu_item;
851 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
853 ? "/ui/menubar/view/view_data"
854 : "/ui/menubar/view/view_variables");
855 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
856 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
860 on_ui_manager_changed (PsppireDataEditor *de,
861 GParamSpec *pspec UNUSED,
862 PsppireDataWindow *dw)
864 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
870 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
871 g_object_unref (dw->uim);
878 g_object_ref (dw->uim);
879 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
883 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
884 Returns a pointer to the action
887 connect_action (PsppireDataWindow *dw, const char *action_name,
890 GtkAction *action = get_action_assert (dw->builder, action_name);
892 g_signal_connect_swapped (action, "activate", handler, dw);
897 /* Only a data file with at least one variable can be saved. */
899 enable_save (PsppireDataWindow *dw)
901 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
903 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
905 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
909 /* Initializes as much of a PsppireDataWindow as we can and must before the
910 dataset has been set.
912 In particular, the 'menu' member is required in case the "filename" property
913 is set before the "dataset" property: otherwise PsppireWindow will try to
914 modify the menu as part of the "filename" property_set() function and end up
915 with a Gtk-CRITICAL since 'menu' is NULL. */
917 psppire_data_window_init (PsppireDataWindow *de)
920 de->builder = builder_new ("data-editor.ui");
922 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
924 w = gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all");
926 PSPPIRE_WINDOW (de)->menu = GTK_MENU_SHELL (gtk_widget_get_parent (w));
933 psppire_data_window_finish_init (PsppireDataWindow *de,
936 static const struct dataset_callbacks cbs =
938 set_unsaved, /* changed */
939 transformation_change_callback, /* transformations_changed */
946 GtkWidget *box = gtk_vbox_new (FALSE, 0);
949 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
950 de->data_store = psppire_data_store_new (de->dict);
951 psppire_data_store_set_reader (de->data_store, NULL);
953 menubar = get_widget_assert (de->builder, "menubar");
954 hb = get_widget_assert (de->builder, "handlebox1");
955 sb = get_widget_assert (de->builder, "status-bar");
961 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
962 g_signal_connect (de->data_editor, "switch-page",
963 G_CALLBACK (on_switch_page), de);
965 g_signal_connect_swapped (de->data_store, "case-changed",
966 G_CALLBACK (set_unsaved), de);
968 g_signal_connect_swapped (de->data_store, "case-inserted",
969 G_CALLBACK (set_unsaved), de);
971 g_signal_connect_swapped (de->data_store, "cases-deleted",
972 G_CALLBACK (set_unsaved), de);
974 dataset_set_callbacks (de->dataset, &cbs, de);
976 connect_help (de->builder);
978 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
979 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
980 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
981 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
983 gtk_container_add (GTK_CONTAINER (de), box);
985 g_signal_connect (de->dict, "weight-changed",
986 G_CALLBACK (on_weight_change),
989 g_signal_connect (de->dict, "filter-changed",
990 G_CALLBACK (on_filter_change),
993 g_signal_connect (de->dict, "split-changed",
994 G_CALLBACK (on_split_change),
997 g_signal_connect_swapped (de->dict, "backend-changed",
998 G_CALLBACK (enable_save), de);
999 g_signal_connect_swapped (de->dict, "variable-inserted",
1000 G_CALLBACK (enable_save), de);
1001 g_signal_connect_swapped (de->dict, "variable-deleted",
1002 G_CALLBACK (enable_save), de);
1005 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1006 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
1007 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1008 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1009 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1010 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1011 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1012 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1014 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1016 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1017 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1018 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1019 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1020 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1021 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1022 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1023 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1026 GtkWidget *recent_data =
1027 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
1029 GtkWidget *recent_files =
1030 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
1033 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1034 gtk_recent_manager_get_default ());
1036 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1037 gtk_recent_manager_get_default ());
1039 g_object_set (menu_data, "show-tips", TRUE, NULL);
1040 g_object_set (menu_files, "show-tips", TRUE, NULL);
1043 GtkRecentFilter *filter = gtk_recent_filter_new ();
1045 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1046 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1048 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1050 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1053 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1056 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1059 GtkRecentFilter *filter = gtk_recent_filter_new ();
1061 gtk_recent_filter_add_pattern (filter, "*.sps");
1062 gtk_recent_filter_add_pattern (filter, "*.SPS");
1064 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1066 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1069 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1071 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1075 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1078 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1079 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1081 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1083 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1085 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1087 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1089 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1091 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1093 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1095 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1097 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1099 merge_help_menu (de->ui_manager);
1101 g_signal_connect (de->data_editor, "notify::ui-manager",
1102 G_CALLBACK (on_ui_manager_changed), de);
1103 on_ui_manager_changed (de->data_editor, NULL, de);
1105 gtk_widget_show (GTK_WIDGET (de->data_editor));
1106 gtk_widget_show (box);
1108 ll_push_head (&all_data_windows, &de->ll);
1112 psppire_data_window_dispose (GObject *object)
1114 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1118 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1119 g_object_unref (dw->uim);
1123 if (dw->builder != NULL)
1125 g_object_unref (dw->builder);
1131 g_signal_handlers_disconnect_by_func (dw->dict,
1132 G_CALLBACK (enable_save), dw);
1133 g_signal_handlers_disconnect_by_func (dw->dict,
1134 G_CALLBACK (on_weight_change), dw);
1135 g_signal_handlers_disconnect_by_func (dw->dict,
1136 G_CALLBACK (on_filter_change), dw);
1137 g_signal_handlers_disconnect_by_func (dw->dict,
1138 G_CALLBACK (on_split_change), dw);
1140 g_object_unref (dw->dict);
1146 g_object_unref (dw->data_store);
1147 dw->data_store = NULL;
1150 if (dw->ll.next != NULL)
1152 ll_remove (&dw->ll);
1156 if (G_OBJECT_CLASS (parent_class)->dispose)
1157 G_OBJECT_CLASS (parent_class)->dispose (object);
1161 psppire_data_window_finalize (GObject *object)
1163 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1167 struct dataset *dataset = dw->dataset;
1168 struct session *session = dataset_session (dataset);
1172 dataset_set_callbacks (dataset, NULL, NULL);
1173 session_set_active_dataset (session, NULL);
1174 dataset_destroy (dataset);
1177 if (G_OBJECT_CLASS (parent_class)->finalize)
1178 G_OBJECT_CLASS (parent_class)->finalize (object);
1182 psppire_data_window_set_property (GObject *object,
1184 const GValue *value,
1187 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1192 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1195 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1201 psppire_data_window_get_property (GObject *object,
1206 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1211 g_value_set_pointer (value, window->dataset);
1214 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1220 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1226 ui_string = gtk_ui_manager_get_ui (uim);
1227 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1231 g_return_val_if_fail (merge_id != 0, 0);
1233 list = gtk_ui_manager_get_action_groups (uim);
1234 for (; list != NULL; list = list->next)
1236 GtkActionGroup *action_group = list->data;
1237 GList *actions = gtk_action_group_list_actions (action_group);
1240 for (action = actions; action != NULL; action = action->next)
1242 GtkAction *a = action->data;
1244 if (PSPPIRE_IS_DIALOG_ACTION (a))
1245 g_object_set (a, "manager", pdw->ui_manager, NULL);
1248 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1251 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1252 gtk_ui_manager_get_accel_group (uim));
1258 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1259 GtkUIManager *uim, guint merge_id)
1263 g_return_if_fail (merge_id != 0);
1265 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1267 list = gtk_ui_manager_get_action_groups (uim);
1268 for (; list != NULL; list = list->next)
1270 GtkActionGroup *action_group = list->data;
1271 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1274 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1275 gtk_ui_manager_get_accel_group (uim));
1279 psppire_data_window_new (struct dataset *ds)
1283 if (the_session == NULL)
1284 the_session = session_create (NULL);
1288 char *dataset_name = session_generate_dataset_name (the_session);
1289 ds = dataset_create (the_session, dataset_name);
1290 free (dataset_name);
1292 assert (dataset_session (ds) == the_session);
1296 psppire_data_window_get_type (),
1297 "description", _("Data Editor"),
1301 if (dataset_name (ds) != NULL)
1302 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1308 psppire_data_window_is_empty (PsppireDataWindow *dw)
1310 return psppire_dict_get_var_cnt (dw->dict) == 0;
1314 psppire_data_window_iface_init (PsppireWindowIface *iface)
1316 iface->save = save_file;
1317 iface->pick_filename = data_pick_filename;
1318 iface->load = load_file;
1322 psppire_default_data_window (void)
1324 if (ll_is_empty (&all_data_windows))
1325 create_data_window ();
1326 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1330 psppire_data_window_set_default (PsppireDataWindow *pdw)
1332 ll_remove (&pdw->ll);
1333 ll_push_head (&all_data_windows, &pdw->ll);
1337 psppire_data_window_undefault (PsppireDataWindow *pdw)
1339 ll_remove (&pdw->ll);
1340 ll_push_tail (&all_data_windows, &pdw->ll);
1344 psppire_data_window_for_dataset (struct dataset *ds)
1346 PsppireDataWindow *pdw;
1348 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1349 if (pdw->dataset == ds)
1356 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1358 PsppireDataWindow *pdw;
1360 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1361 if (pdw->data_store == data_store)
1368 create_data_window (void)
1370 gtk_widget_show (psppire_data_window_new (NULL));
1374 open_data_window (PsppireWindow *victim, const char *file_name,
1375 const char *encoding, gpointer hint)
1379 if (PSPPIRE_IS_DATA_WINDOW (victim)
1380 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1382 window = GTK_WIDGET (victim);
1383 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1386 window = psppire_data_window_new (NULL);
1388 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
1389 gtk_widget_show_all (window);