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, gpointer syn)
337 const char *mime_type = NULL;
338 gchar *syntax = NULL;
343 gchar *utf8_file_name;
344 struct string filename;
346 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
348 if (NULL == utf8_file_name)
351 ds_init_empty (&filename);
352 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
354 g_free (utf8_file_name);
356 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
357 ds_destroy (&filename);
364 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
365 lex_reader_for_string (syntax));
368 if (ok && syn == NULL)
370 if (name_has_por_suffix (file_name))
371 mime_type = "application/x-spss-por";
372 else if (name_has_sav_suffix (file_name))
373 mime_type = "application/x-spss-sav";
375 add_most_recent (file_name, mime_type);
382 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
384 if (format == PSPPIRE_DATA_WINDOW_SAV)
386 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
392 /* Save DE to file */
394 save_file (PsppireWindow *w)
396 const gchar *file_name = NULL;
397 gchar *utf8_file_name = NULL;
399 struct string filename ;
400 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
403 file_name = psppire_window_get_filename (w);
405 fnx = g_string_new (file_name);
407 if ( ! name_has_suffix (fnx->str))
408 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
410 ds_init_empty (&filename);
412 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
414 g_string_free (fnx, TRUE);
416 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
417 g_free (utf8_file_name);
419 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
420 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
421 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
422 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
423 ds_cstr (&filename));
425 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
427 ds_destroy (&filename);
429 g_free (execute_syntax_string (de, syntax));
434 display_dict (PsppireDataWindow *de)
436 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
440 sysfile_info (PsppireDataWindow *de)
442 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
444 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
446 struct string filename;
448 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
449 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
452 const gchar *encoding = psppire_encoding_selector_get_encoding (
453 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
457 ds_init_empty (&filename);
459 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
461 g_free (utf8_file_name);
464 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
465 ds_cstr (&filename), encoding);
467 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
468 g_free (execute_syntax_string (de, syntax));
471 gtk_widget_destroy (dialog);
475 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
477 data_pick_filename (PsppireWindow *window)
479 GtkListStore *list_store;
480 GtkWidget *combo_box;
482 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
483 GtkFileFilter *filter;
485 gtk_file_chooser_dialog_new (_("Save"),
487 GTK_FILE_CHOOSER_ACTION_SAVE,
488 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
489 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
492 g_object_set (dialog, "local-only", FALSE, NULL);
494 filter = gtk_file_filter_new ();
495 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
496 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
497 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
499 filter = gtk_file_filter_new ();
500 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
501 gtk_file_filter_add_pattern (filter, "*.zsav");
502 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
504 filter = gtk_file_filter_new ();
505 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
506 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
507 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
509 filter = gtk_file_filter_new ();
510 gtk_file_filter_set_name (filter, _("All Files"));
511 gtk_file_filter_add_pattern (filter, "*");
512 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
513 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
516 GtkCellRenderer *cell;
521 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
522 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
524 gtk_list_store_append (list_store, &iter);
525 gtk_list_store_set (list_store, &iter,
526 0, PSPPIRE_DATA_WINDOW_SAV,
529 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
531 gtk_list_store_append (list_store, &iter);
532 gtk_list_store_set (list_store, &iter,
533 0, PSPPIRE_DATA_WINDOW_ZSAV,
534 1, _("Compressed System File"),
537 gtk_list_store_append (list_store, &iter);
538 gtk_list_store_set (list_store, &iter,
539 0, PSPPIRE_DATA_WINDOW_POR,
540 1, _("Portable File"),
543 label = gtk_label_new (_("Format:"));
545 cell = gtk_cell_renderer_text_new ();
546 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
547 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
550 hbox = gtk_hbox_new (FALSE, 0);
551 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
552 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
553 gtk_widget_show_all (hbox);
555 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
558 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
561 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
563 case GTK_RESPONSE_ACCEPT:
568 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
574 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
575 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
580 if ( ! name_has_suffix (filename->str))
581 g_string_append (filename,
582 psppire_data_window_format_to_string (format));
584 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
586 g_string_free (filename, TRUE);
593 gtk_widget_destroy (dialog);
597 confirm_delete_dataset (PsppireDataWindow *de,
598 const char *old_dataset,
599 const char *new_dataset,
600 const char *existing_dataset)
605 dialog = gtk_message_dialog_new (
606 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
607 _("Delete Existing Dataset?"));
609 gtk_message_dialog_format_secondary_text (
610 GTK_MESSAGE_DIALOG (dialog),
611 _("Renaming \"%s\" to \"%s\" will destroy the existing "
612 "dataset named \"%s\". Are you sure that you want to do this?"),
613 old_dataset, new_dataset, existing_dataset);
615 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
616 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
617 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
620 g_object_set (dialog, "icon-name", "pspp", NULL);
622 result = gtk_dialog_run (GTK_DIALOG (dialog));
624 gtk_widget_destroy (dialog);
626 return result == GTK_RESPONSE_OK;
630 on_rename_dataset (PsppireDataWindow *de)
632 struct dataset *ds = de->dataset;
633 struct session *session = dataset_session (ds);
634 const char *old_name = dataset_name (ds);
635 struct dataset *existing_dataset;
639 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
641 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
645 if (new_name == NULL)
648 existing_dataset = session_lookup_dataset (session, new_name);
649 if (existing_dataset == NULL || existing_dataset == ds
650 || confirm_delete_dataset (de, old_name, new_name,
651 dataset_name (existing_dataset)))
652 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
659 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
661 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
663 if ( gtk_toggle_action_get_active (action))
664 gtk_widget_show (statusbar);
666 gtk_widget_hide (statusbar);
671 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
673 const gboolean grid_visible = gtk_toggle_action_get_active (action);
675 psppire_data_editor_show_grid (de->data_editor, grid_visible);
679 data_view_activate (PsppireDataWindow *de)
681 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
686 variable_view_activate (PsppireDataWindow *de)
688 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
693 fonts_activate (PsppireDataWindow *de)
695 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
696 PangoFontDescription *current_font;
699 gtk_font_selection_dialog_new (_("Font Selection"));
702 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
703 font_name = pango_font_description_to_string (current_font);
705 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
709 gtk_window_set_transient_for (GTK_WINDOW (dialog),
710 GTK_WINDOW (toplevel));
712 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
714 const gchar *font = gtk_font_selection_dialog_get_font_name
715 (GTK_FONT_SELECTION_DIALOG (dialog));
717 PangoFontDescription* font_desc =
718 pango_font_description_from_string (font);
720 psppire_data_editor_set_font (de->data_editor, font_desc);
723 gtk_widget_hide (dialog);
728 /* Callback for the value labels action */
730 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
732 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
736 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
738 psppire_data_editor_split_window (de->data_editor,
739 gtk_toggle_action_get_active (ta));
744 file_quit (PsppireDataWindow *de)
746 /* FIXME: Need to be more intelligent here.
747 Give the user the opportunity to save any unsaved data.
753 on_recent_data_select (GtkMenuShell *menushell,
754 PsppireWindow *window)
759 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
761 file = g_filename_from_uri (uri, NULL, NULL);
765 open_data_window (window, file, NULL);
771 charset_from_mime_type (const char *mime_type)
777 if (mime_type == NULL)
780 charset = c_strcasestr (mime_type, "charset=");
788 /* Parse a "quoted-string" as defined by RFC 822. */
789 for (p++; *p != '\0' && *p != '"'; p++)
792 ds_put_byte (&s, *p);
793 else if (*++p != '\0')
794 ds_put_byte (&s, *p);
799 /* Parse a "token" as defined by RFC 2045. */
800 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
801 ds_put_byte (&s, *p++);
803 if (!ds_is_empty (&s))
804 return ds_steal_cstr (&s);
811 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
818 /* Get the file name and its encoding. */
819 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
820 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
821 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
822 gtk_recent_info_unref (item);
824 se = psppire_syntax_window_new (encoding);
828 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
829 gtk_widget_show (se);
831 gtk_widget_destroy (se);
837 set_unsaved (gpointer w)
839 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
843 on_switch_page (PsppireDataEditor *de, gpointer p,
844 gint pagenum, PsppireDataWindow *dw)
846 GtkWidget *page_menu_item;
850 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
852 ? "/ui/menubar/view/view_data"
853 : "/ui/menubar/view/view_variables");
854 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
855 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
859 on_ui_manager_changed (PsppireDataEditor *de,
860 GParamSpec *pspec UNUSED,
861 PsppireDataWindow *dw)
863 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
869 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
870 g_object_unref (dw->uim);
877 g_object_ref (dw->uim);
878 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
882 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
883 Returns a pointer to the action
886 connect_action (PsppireDataWindow *dw, const char *action_name,
889 GtkAction *action = get_action_assert (dw->builder, action_name);
891 g_signal_connect_swapped (action, "activate", handler, dw);
896 /* Only a data file with at least one variable can be saved. */
898 enable_save (PsppireDataWindow *dw)
900 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
902 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
904 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
908 /* Initializes as much of a PsppireDataWindow as we can and must before the
909 dataset has been set.
911 In particular, the 'menu' member is required in case the "filename" property
912 is set before the "dataset" property: otherwise PsppireWindow will try to
913 modify the menu as part of the "filename" property_set() function and end up
914 with a Gtk-CRITICAL since 'menu' is NULL. */
916 psppire_data_window_init (PsppireDataWindow *de)
918 de->builder = builder_new ("data-editor.ui");
920 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
922 PSPPIRE_WINDOW (de)->menu =
923 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
930 psppire_data_window_finish_init (PsppireDataWindow *de,
933 static const struct dataset_callbacks cbs =
935 set_unsaved, /* changed */
936 transformation_change_callback, /* transformations_changed */
943 GtkWidget *box = gtk_vbox_new (FALSE, 0);
946 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
947 de->data_store = psppire_data_store_new (de->dict);
948 psppire_data_store_set_reader (de->data_store, NULL);
950 menubar = get_widget_assert (de->builder, "menubar");
951 hb = get_widget_assert (de->builder, "handlebox1");
952 sb = get_widget_assert (de->builder, "status-bar");
958 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
959 g_signal_connect (de->data_editor, "switch-page",
960 G_CALLBACK (on_switch_page), de);
962 g_signal_connect_swapped (de->data_store, "case-changed",
963 G_CALLBACK (set_unsaved), de);
965 g_signal_connect_swapped (de->data_store, "case-inserted",
966 G_CALLBACK (set_unsaved), de);
968 g_signal_connect_swapped (de->data_store, "cases-deleted",
969 G_CALLBACK (set_unsaved), de);
971 dataset_set_callbacks (de->dataset, &cbs, de);
973 connect_help (de->builder);
975 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
976 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
977 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
978 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
980 gtk_container_add (GTK_CONTAINER (de), box);
982 g_signal_connect (de->dict, "weight-changed",
983 G_CALLBACK (on_weight_change),
986 g_signal_connect (de->dict, "filter-changed",
987 G_CALLBACK (on_filter_change),
990 g_signal_connect (de->dict, "split-changed",
991 G_CALLBACK (on_split_change),
994 g_signal_connect_swapped (de->dict, "backend-changed",
995 G_CALLBACK (enable_save), de);
996 g_signal_connect_swapped (de->dict, "variable-inserted",
997 G_CALLBACK (enable_save), de);
998 g_signal_connect_swapped (de->dict, "variable-deleted",
999 G_CALLBACK (enable_save), de);
1002 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1003 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
1004 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1005 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1006 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1007 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1008 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1009 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1011 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1013 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1014 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1015 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1016 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1017 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1018 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1019 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1020 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1023 GtkWidget *recent_data =
1024 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
1026 GtkWidget *recent_files =
1027 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
1030 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1031 gtk_recent_manager_get_default ());
1033 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1034 gtk_recent_manager_get_default ());
1036 g_object_set (menu_data, "show-tips", TRUE, NULL);
1037 g_object_set (menu_files, "show-tips", TRUE, NULL);
1040 GtkRecentFilter *filter = gtk_recent_filter_new ();
1042 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1043 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1045 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1047 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1050 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1053 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1056 GtkRecentFilter *filter = gtk_recent_filter_new ();
1058 gtk_recent_filter_add_pattern (filter, "*.sps");
1059 gtk_recent_filter_add_pattern (filter, "*.SPS");
1061 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1063 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1066 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1068 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1072 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1075 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1076 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1078 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1080 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1082 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1084 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1086 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1088 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1090 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1092 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1094 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1096 merge_help_menu (de->ui_manager);
1098 g_signal_connect (de->data_editor, "notify::ui-manager",
1099 G_CALLBACK (on_ui_manager_changed), de);
1100 on_ui_manager_changed (de->data_editor, NULL, de);
1102 gtk_widget_show (GTK_WIDGET (de->data_editor));
1103 gtk_widget_show (box);
1105 ll_push_head (&all_data_windows, &de->ll);
1109 psppire_data_window_dispose (GObject *object)
1111 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1115 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1116 g_object_unref (dw->uim);
1120 if (dw->builder != NULL)
1122 g_object_unref (dw->builder);
1128 g_signal_handlers_disconnect_by_func (dw->dict,
1129 G_CALLBACK (enable_save), dw);
1130 g_signal_handlers_disconnect_by_func (dw->dict,
1131 G_CALLBACK (on_weight_change), dw);
1132 g_signal_handlers_disconnect_by_func (dw->dict,
1133 G_CALLBACK (on_filter_change), dw);
1134 g_signal_handlers_disconnect_by_func (dw->dict,
1135 G_CALLBACK (on_split_change), dw);
1137 g_object_unref (dw->dict);
1143 g_object_unref (dw->data_store);
1144 dw->data_store = NULL;
1147 if (dw->ll.next != NULL)
1149 ll_remove (&dw->ll);
1153 if (G_OBJECT_CLASS (parent_class)->dispose)
1154 G_OBJECT_CLASS (parent_class)->dispose (object);
1158 psppire_data_window_finalize (GObject *object)
1160 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1164 struct dataset *dataset = dw->dataset;
1165 struct session *session = dataset_session (dataset);
1169 dataset_set_callbacks (dataset, NULL, NULL);
1170 session_set_active_dataset (session, NULL);
1171 dataset_destroy (dataset);
1174 if (G_OBJECT_CLASS (parent_class)->finalize)
1175 G_OBJECT_CLASS (parent_class)->finalize (object);
1179 psppire_data_window_set_property (GObject *object,
1181 const GValue *value,
1184 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1189 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1192 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1198 psppire_data_window_get_property (GObject *object,
1203 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1208 g_value_set_pointer (value, window->dataset);
1211 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1217 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1223 ui_string = gtk_ui_manager_get_ui (uim);
1224 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1228 g_return_val_if_fail (merge_id != 0, 0);
1230 list = gtk_ui_manager_get_action_groups (uim);
1231 for (; list != NULL; list = list->next)
1233 GtkActionGroup *action_group = list->data;
1234 GList *actions = gtk_action_group_list_actions (action_group);
1237 for (action = actions; action != NULL; action = action->next)
1239 GtkAction *a = action->data;
1241 if (PSPPIRE_IS_DIALOG_ACTION (a))
1242 g_object_set (a, "manager", pdw->ui_manager, NULL);
1245 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1248 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1249 gtk_ui_manager_get_accel_group (uim));
1255 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1256 GtkUIManager *uim, guint merge_id)
1260 g_return_if_fail (merge_id != 0);
1262 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1264 list = gtk_ui_manager_get_action_groups (uim);
1265 for (; list != NULL; list = list->next)
1267 GtkActionGroup *action_group = list->data;
1268 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1271 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1272 gtk_ui_manager_get_accel_group (uim));
1276 psppire_data_window_new (struct dataset *ds)
1280 if (the_session == NULL)
1281 the_session = session_create (NULL);
1285 char *dataset_name = session_generate_dataset_name (the_session);
1286 ds = dataset_create (the_session, dataset_name);
1287 free (dataset_name);
1289 assert (dataset_session (ds) == the_session);
1293 psppire_data_window_get_type (),
1294 "description", _("Data Editor"),
1298 if (dataset_name (ds) != NULL)
1299 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1305 psppire_data_window_is_empty (PsppireDataWindow *dw)
1307 return psppire_dict_get_var_cnt (dw->dict) == 0;
1311 psppire_data_window_iface_init (PsppireWindowIface *iface)
1313 iface->save = save_file;
1314 iface->pick_filename = data_pick_filename;
1315 iface->load = load_file;
1319 psppire_default_data_window (void)
1321 if (ll_is_empty (&all_data_windows))
1322 create_data_window ();
1323 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1327 psppire_data_window_set_default (PsppireDataWindow *pdw)
1329 ll_remove (&pdw->ll);
1330 ll_push_head (&all_data_windows, &pdw->ll);
1334 psppire_data_window_undefault (PsppireDataWindow *pdw)
1336 ll_remove (&pdw->ll);
1337 ll_push_tail (&all_data_windows, &pdw->ll);
1341 psppire_data_window_for_dataset (struct dataset *ds)
1343 PsppireDataWindow *pdw;
1345 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1346 if (pdw->dataset == ds)
1353 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1355 PsppireDataWindow *pdw;
1357 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1358 if (pdw->data_store == data_store)
1365 create_data_window (void)
1367 gtk_widget_show (psppire_data_window_new (NULL));
1371 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1375 if (PSPPIRE_IS_DATA_WINDOW (victim)
1376 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1378 window = GTK_WIDGET (victim);
1379 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1382 window = psppire_data_window_new (NULL);
1384 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1385 gtk_widget_show_all (window);