1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/builder-wrapper.h"
30 #include "ui/gui/comments-dialog.h"
31 #include "ui/gui/entry-dialog.h"
32 #include "ui/gui/executor.h"
33 #include "ui/gui/help-menu.h"
34 #include "ui/gui/helper.h"
35 #include "ui/gui/helper.h"
36 #include "ui/gui/psppire-data-window.h"
37 #include "ui/gui/psppire-dialog-action.h"
38 #include "ui/gui/psppire-syntax-window.h"
39 #include "ui/gui/psppire-window.h"
40 #include "ui/gui/psppire.h"
41 #include "ui/gui/recode-dialog.h"
42 #include "ui/gui/select-cases-dialog.h"
43 #include "ui/gui/split-file-dialog.h"
44 #include "ui/gui/text-data-import-dialog.h"
45 #include "ui/gui/weight-cases-dialog.h"
46 #include "ui/syntax-gen.h"
48 #include "gl/c-strcase.h"
49 #include "gl/c-strcasestr.h"
50 #include "gl/xvasprintf.h"
53 #define _(msgid) gettext (msgid)
54 #define N_(msgid) msgid
56 struct session *the_session;
57 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
59 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
60 static void psppire_data_window_init (PsppireDataWindow *data_editor);
63 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
65 static void psppire_data_window_dispose (GObject *object);
66 static void psppire_data_window_finalize (GObject *object);
67 static void psppire_data_window_set_property (GObject *object,
71 static void psppire_data_window_get_property (GObject *object,
76 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
77 static void psppire_data_window_remove_ui (PsppireDataWindow *,
78 GtkUIManager *, guint);
81 psppire_data_window_get_type (void)
83 static GType psppire_data_window_type = 0;
85 if (!psppire_data_window_type)
87 static const GTypeInfo psppire_data_window_info =
89 sizeof (PsppireDataWindowClass),
92 (GClassInitFunc)psppire_data_window_class_init,
93 (GClassFinalizeFunc) NULL,
95 sizeof (PsppireDataWindow),
97 (GInstanceInitFunc) psppire_data_window_init,
100 static const GInterfaceInfo window_interface_info =
102 (GInterfaceInitFunc) psppire_data_window_iface_init,
107 psppire_data_window_type =
108 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
109 &psppire_data_window_info, 0);
112 g_type_add_interface_static (psppire_data_window_type,
113 PSPPIRE_TYPE_WINDOW_MODEL,
114 &window_interface_info);
117 return psppire_data_window_type;
120 static GObjectClass *parent_class ;
127 psppire_data_window_class_init (PsppireDataWindowClass *class)
129 GObjectClass *object_class = G_OBJECT_CLASS (class);
131 parent_class = g_type_class_peek_parent (class);
133 object_class->dispose = psppire_data_window_dispose;
134 object_class->finalize = psppire_data_window_finalize;
135 object_class->set_property = psppire_data_window_set_property;
136 object_class->get_property = psppire_data_window_get_property;
138 g_object_class_install_property (
139 object_class, PROP_DATASET,
140 g_param_spec_pointer ("dataset", "Dataset",
141 "'struct datset *' represented by the window",
142 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
145 /* Run the EXECUTE command. */
147 execute (PsppireDataWindow *dw)
149 execute_const_syntax_string (dw, "EXECUTE.");
153 transformation_change_callback (bool transformations_pending,
156 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
158 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
160 GtkWidget *menuitem =
161 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
163 GtkWidget *status_label =
164 get_widget_assert (de->builder, "case-counter-area");
166 gtk_widget_set_sensitive (menuitem, transformations_pending);
169 if ( transformations_pending)
170 gtk_label_set_text (GTK_LABEL (status_label),
171 _("Transformations Pending"));
173 gtk_label_set_text (GTK_LABEL (status_label), "");
176 /* Callback for when the dictionary changes its filter variable */
178 on_filter_change (GObject *o, gint filter_index, gpointer data)
180 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
182 GtkWidget *filter_status_area =
183 get_widget_assert (de->builder, "filter-use-status-area");
185 if ( filter_index == -1 )
187 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
191 PsppireDict *dict = NULL;
192 struct variable *var ;
195 g_object_get (de->data_editor, "dictionary", &dict, NULL);
197 var = psppire_dict_get_variable (dict, filter_index);
199 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
201 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
207 /* Callback for when the dictionary changes its split variables */
209 on_split_change (PsppireDict *dict, gpointer data)
211 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
213 size_t n_split_vars = dict_get_split_cnt (dict->dict);
215 GtkWidget *split_status_area =
216 get_widget_assert (de->builder, "split-file-status-area");
218 if ( n_split_vars == 0 )
220 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
226 const struct variable *const * split_vars =
227 dict_get_split_vars (dict->dict);
229 text = g_string_new (_("Split by "));
231 for (i = 0 ; i < n_split_vars - 1; ++i )
233 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
235 g_string_append (text, var_get_name (split_vars[i]));
237 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
239 g_string_free (text, TRUE);
246 /* Callback for when the dictionary changes its weights */
248 on_weight_change (GObject *o, gint weight_index, gpointer data)
250 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
252 GtkWidget *weight_status_area =
253 get_widget_assert (de->builder, "weight-status-area");
255 if ( weight_index == -1 )
257 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
261 struct variable *var ;
262 PsppireDict *dict = NULL;
265 g_object_get (de->data_editor, "dictionary", &dict, NULL);
267 var = psppire_dict_get_variable (dict, weight_index);
269 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
271 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
279 dump_rm (GtkRecentManager *rm)
281 GList *items = gtk_recent_manager_get_items (rm);
285 g_print ("Recent Items:\n");
286 for (i = items; i; i = i->next)
288 GtkRecentInfo *ri = i->data;
290 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
291 gtk_recent_info_get_short_name (ri),
292 gtk_recent_info_get_mime_type (ri),
293 gtk_recent_info_get_description (ri),
294 gtk_recent_info_get_uri (ri)
298 gtk_recent_info_unref (ri);
306 has_suffix (const gchar *name, const gchar *suffix)
308 size_t name_len = strlen (name);
309 size_t suffix_len = strlen (suffix);
310 return (name_len > suffix_len
311 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
315 name_has_por_suffix (const gchar *name)
317 return has_suffix (name, ".por");
321 name_has_sav_suffix (const gchar *name)
323 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
326 /* Returns true if NAME has a suffix which might denote a PSPP file */
328 name_has_suffix (const gchar *name)
330 return name_has_por_suffix (name) || name_has_sav_suffix (name);
334 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
336 const char *mime_type = NULL;
337 gchar *syntax = NULL;
342 gchar *utf8_file_name;
343 struct string filename;
345 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
347 if (NULL == utf8_file_name)
350 ds_init_empty (&filename);
351 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
353 g_free (utf8_file_name);
355 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
356 ds_destroy (&filename);
363 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
364 lex_reader_for_string (syntax));
367 if (ok && syn == NULL)
369 if (name_has_por_suffix (file_name))
370 mime_type = "application/x-spss-por";
371 else if (name_has_sav_suffix (file_name))
372 mime_type = "application/x-spss-sav";
374 add_most_recent (file_name, mime_type);
381 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
383 if (format == PSPPIRE_DATA_WINDOW_SAV)
385 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
391 /* Save DE to file */
393 save_file (PsppireWindow *w)
395 const gchar *file_name = NULL;
396 gchar *utf8_file_name = NULL;
398 struct string filename ;
399 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
402 file_name = psppire_window_get_filename (w);
404 fnx = g_string_new (file_name);
406 if ( ! name_has_suffix (fnx->str))
407 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
409 ds_init_empty (&filename);
411 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
413 g_string_free (fnx, TRUE);
415 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
416 g_free (utf8_file_name);
418 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
419 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
420 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
421 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
422 ds_cstr (&filename));
424 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
426 ds_destroy (&filename);
428 g_free (execute_syntax_string (de, syntax));
433 display_dict (PsppireDataWindow *de)
435 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
439 sysfile_info (PsppireDataWindow *de)
441 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
443 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
445 struct string filename;
447 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
449 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
454 ds_init_empty (&filename);
456 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
458 g_free (utf8_file_name);
460 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
461 g_free (execute_syntax_string (de, syntax));
464 gtk_widget_destroy (dialog);
468 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
470 data_pick_filename (PsppireWindow *window)
472 GtkListStore *list_store;
473 GtkWidget *combo_box;
475 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
476 GtkFileFilter *filter;
478 gtk_file_chooser_dialog_new (_("Save"),
480 GTK_FILE_CHOOSER_ACTION_SAVE,
481 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
482 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
485 g_object_set (dialog, "local-only", FALSE, NULL);
487 filter = gtk_file_filter_new ();
488 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
489 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
490 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
492 filter = gtk_file_filter_new ();
493 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
494 gtk_file_filter_add_pattern (filter, "*.zsav");
495 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
497 filter = gtk_file_filter_new ();
498 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
499 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
500 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
502 filter = gtk_file_filter_new ();
503 gtk_file_filter_set_name (filter, _("All Files"));
504 gtk_file_filter_add_pattern (filter, "*");
505 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
506 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
509 GtkCellRenderer *cell;
514 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
515 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
517 gtk_list_store_append (list_store, &iter);
518 gtk_list_store_set (list_store, &iter,
519 0, PSPPIRE_DATA_WINDOW_SAV,
522 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
524 gtk_list_store_append (list_store, &iter);
525 gtk_list_store_set (list_store, &iter,
526 0, PSPPIRE_DATA_WINDOW_ZSAV,
527 1, _("Compressed System File"),
530 gtk_list_store_append (list_store, &iter);
531 gtk_list_store_set (list_store, &iter,
532 0, PSPPIRE_DATA_WINDOW_POR,
533 1, _("Portable File"),
536 label = gtk_label_new (_("Format:"));
538 cell = gtk_cell_renderer_text_new ();
539 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
540 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
543 hbox = gtk_hbox_new (FALSE, 0);
544 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
545 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
546 gtk_widget_show_all (hbox);
548 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
551 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
554 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
556 case GTK_RESPONSE_ACCEPT:
561 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
567 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
568 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
573 if ( ! name_has_suffix (filename->str))
574 g_string_append (filename,
575 psppire_data_window_format_to_string (format));
577 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
579 g_string_free (filename, TRUE);
586 gtk_widget_destroy (dialog);
590 confirm_delete_dataset (PsppireDataWindow *de,
591 const char *old_dataset,
592 const char *new_dataset,
593 const char *existing_dataset)
598 dialog = gtk_message_dialog_new (
599 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
600 _("Delete Existing Dataset?"));
602 gtk_message_dialog_format_secondary_text (
603 GTK_MESSAGE_DIALOG (dialog),
604 _("Renaming \"%s\" to \"%s\" will destroy the existing "
605 "dataset named \"%s\". Are you sure that you want to do this?"),
606 old_dataset, new_dataset, existing_dataset);
608 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
609 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
610 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
613 g_object_set (dialog, "icon-name", "pspp", NULL);
615 result = gtk_dialog_run (GTK_DIALOG (dialog));
617 gtk_widget_destroy (dialog);
619 return result == GTK_RESPONSE_OK;
623 on_rename_dataset (PsppireDataWindow *de)
625 struct dataset *ds = de->dataset;
626 struct session *session = dataset_session (ds);
627 const char *old_name = dataset_name (ds);
628 struct dataset *existing_dataset;
632 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
634 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
638 if (new_name == NULL)
641 existing_dataset = session_lookup_dataset (session, new_name);
642 if (existing_dataset == NULL || existing_dataset == ds
643 || confirm_delete_dataset (de, old_name, new_name,
644 dataset_name (existing_dataset)))
645 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
652 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
654 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
656 if ( gtk_toggle_action_get_active (action))
657 gtk_widget_show (statusbar);
659 gtk_widget_hide (statusbar);
664 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
666 const gboolean grid_visible = gtk_toggle_action_get_active (action);
668 psppire_data_editor_show_grid (de->data_editor, grid_visible);
672 data_view_activate (PsppireDataWindow *de)
674 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
679 variable_view_activate (PsppireDataWindow *de)
681 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
686 fonts_activate (PsppireDataWindow *de)
688 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
689 PangoFontDescription *current_font;
692 gtk_font_selection_dialog_new (_("Font Selection"));
695 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
696 font_name = pango_font_description_to_string (current_font);
698 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
702 gtk_window_set_transient_for (GTK_WINDOW (dialog),
703 GTK_WINDOW (toplevel));
705 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
707 const gchar *font = gtk_font_selection_dialog_get_font_name
708 (GTK_FONT_SELECTION_DIALOG (dialog));
710 PangoFontDescription* font_desc =
711 pango_font_description_from_string (font);
713 psppire_data_editor_set_font (de->data_editor, font_desc);
716 gtk_widget_hide (dialog);
721 /* Callback for the value labels action */
723 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
725 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
729 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
731 psppire_data_editor_split_window (de->data_editor,
732 gtk_toggle_action_get_active (ta));
737 file_quit (PsppireDataWindow *de)
739 /* FIXME: Need to be more intelligent here.
740 Give the user the opportunity to save any unsaved data.
746 on_recent_data_select (GtkMenuShell *menushell,
747 PsppireWindow *window)
752 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
754 file = g_filename_from_uri (uri, NULL, NULL);
758 open_data_window (window, file, NULL);
764 charset_from_mime_type (const char *mime_type)
770 if (mime_type == NULL)
773 charset = c_strcasestr (mime_type, "charset=");
781 /* Parse a "quoted-string" as defined by RFC 822. */
782 for (p++; *p != '\0' && *p != '"'; p++)
785 ds_put_byte (&s, *p);
786 else if (*++p != '\0')
787 ds_put_byte (&s, *p);
792 /* Parse a "token" as defined by RFC 2045. */
793 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
794 ds_put_byte (&s, *p++);
796 if (!ds_is_empty (&s))
797 return ds_steal_cstr (&s);
804 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
811 /* Get the file name and its encoding. */
812 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
813 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
814 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
815 gtk_recent_info_unref (item);
817 se = psppire_syntax_window_new (encoding);
821 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
822 gtk_widget_show (se);
824 gtk_widget_destroy (se);
830 set_unsaved (gpointer w)
832 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
836 on_switch_page (PsppireDataEditor *de, gpointer p,
837 gint pagenum, PsppireDataWindow *dw)
839 GtkWidget *page_menu_item;
843 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
845 ? "/ui/menubar/view/view_data"
846 : "/ui/menubar/view/view_variables");
847 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
848 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
852 on_ui_manager_changed (PsppireDataEditor *de,
853 GParamSpec *pspec UNUSED,
854 PsppireDataWindow *dw)
856 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
862 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
863 g_object_unref (dw->uim);
870 g_object_ref (dw->uim);
871 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
875 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
876 Returns a pointer to the action
879 connect_action (PsppireDataWindow *dw, const char *action_name,
882 GtkAction *action = get_action_assert (dw->builder, action_name);
884 g_signal_connect_swapped (action, "activate", handler, dw);
889 /* Only a data file with at least one variable can be saved. */
891 enable_save (PsppireDataWindow *dw)
893 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
895 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
897 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
901 /* Initializes as much of a PsppireDataWindow as we can and must before the
902 dataset has been set.
904 In particular, the 'menu' member is required in case the "filename" property
905 is set before the "dataset" property: otherwise PsppireWindow will try to
906 modify the menu as part of the "filename" property_set() function and end up
907 with a Gtk-CRITICAL since 'menu' is NULL. */
909 psppire_data_window_init (PsppireDataWindow *de)
911 de->builder = builder_new ("data-editor.ui");
913 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
915 PSPPIRE_WINDOW (de)->menu =
916 GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
923 psppire_data_window_finish_init (PsppireDataWindow *de,
926 static const struct dataset_callbacks cbs =
928 set_unsaved, /* changed */
929 transformation_change_callback, /* transformations_changed */
936 GtkWidget *box = gtk_vbox_new (FALSE, 0);
939 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
940 de->data_store = psppire_data_store_new (de->dict);
941 psppire_data_store_set_reader (de->data_store, NULL);
943 menubar = get_widget_assert (de->builder, "menubar");
944 hb = get_widget_assert (de->builder, "handlebox1");
945 sb = get_widget_assert (de->builder, "status-bar");
951 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
952 g_signal_connect (de->data_editor, "switch-page",
953 G_CALLBACK (on_switch_page), de);
955 g_signal_connect_swapped (de->data_store, "case-changed",
956 G_CALLBACK (set_unsaved), de);
958 g_signal_connect_swapped (de->data_store, "case-inserted",
959 G_CALLBACK (set_unsaved), de);
961 g_signal_connect_swapped (de->data_store, "cases-deleted",
962 G_CALLBACK (set_unsaved), de);
964 dataset_set_callbacks (de->dataset, &cbs, de);
966 connect_help (de->builder);
968 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
969 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
970 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
971 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
973 gtk_container_add (GTK_CONTAINER (de), box);
975 g_signal_connect (de->dict, "weight-changed",
976 G_CALLBACK (on_weight_change),
979 g_signal_connect (de->dict, "filter-changed",
980 G_CALLBACK (on_filter_change),
983 g_signal_connect (de->dict, "split-changed",
984 G_CALLBACK (on_split_change),
987 g_signal_connect_swapped (de->dict, "backend-changed",
988 G_CALLBACK (enable_save), de);
989 g_signal_connect_swapped (de->dict, "variable-inserted",
990 G_CALLBACK (enable_save), de);
991 g_signal_connect_swapped (de->dict, "variable-deleted",
992 G_CALLBACK (enable_save), de);
995 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
996 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
997 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
998 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
999 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1000 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1001 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1002 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1004 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1006 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1007 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1008 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1009 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1010 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1011 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1012 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1013 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1016 GtkWidget *recent_data =
1017 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
1019 GtkWidget *recent_files =
1020 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
1023 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1024 gtk_recent_manager_get_default ());
1026 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1027 gtk_recent_manager_get_default ());
1029 g_object_set (menu_data, "show-tips", TRUE, NULL);
1030 g_object_set (menu_files, "show-tips", TRUE, NULL);
1033 GtkRecentFilter *filter = gtk_recent_filter_new ();
1035 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1036 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1038 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1040 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1043 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1046 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1049 GtkRecentFilter *filter = gtk_recent_filter_new ();
1051 gtk_recent_filter_add_pattern (filter, "*.sps");
1052 gtk_recent_filter_add_pattern (filter, "*.SPS");
1054 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1056 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1059 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1061 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1065 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1068 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1069 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1071 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1073 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1075 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1077 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1079 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1081 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1083 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1085 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1087 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1089 merge_help_menu (de->ui_manager);
1091 g_signal_connect (de->data_editor, "notify::ui-manager",
1092 G_CALLBACK (on_ui_manager_changed), de);
1093 on_ui_manager_changed (de->data_editor, NULL, de);
1095 gtk_widget_show (GTK_WIDGET (de->data_editor));
1096 gtk_widget_show (box);
1098 ll_push_head (&all_data_windows, &de->ll);
1102 psppire_data_window_dispose (GObject *object)
1104 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1108 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1109 g_object_unref (dw->uim);
1113 if (dw->builder != NULL)
1115 g_object_unref (dw->builder);
1121 g_signal_handlers_disconnect_by_func (dw->dict,
1122 G_CALLBACK (enable_save), dw);
1123 g_signal_handlers_disconnect_by_func (dw->dict,
1124 G_CALLBACK (on_weight_change), dw);
1125 g_signal_handlers_disconnect_by_func (dw->dict,
1126 G_CALLBACK (on_filter_change), dw);
1127 g_signal_handlers_disconnect_by_func (dw->dict,
1128 G_CALLBACK (on_split_change), dw);
1130 g_object_unref (dw->dict);
1136 g_object_unref (dw->data_store);
1137 dw->data_store = NULL;
1140 if (dw->ll.next != NULL)
1142 ll_remove (&dw->ll);
1146 if (G_OBJECT_CLASS (parent_class)->dispose)
1147 G_OBJECT_CLASS (parent_class)->dispose (object);
1151 psppire_data_window_finalize (GObject *object)
1153 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1157 struct dataset *dataset = dw->dataset;
1158 struct session *session = dataset_session (dataset);
1162 dataset_set_callbacks (dataset, NULL, NULL);
1163 session_set_active_dataset (session, NULL);
1164 dataset_destroy (dataset);
1167 if (G_OBJECT_CLASS (parent_class)->finalize)
1168 G_OBJECT_CLASS (parent_class)->finalize (object);
1172 psppire_data_window_set_property (GObject *object,
1174 const GValue *value,
1177 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1182 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1185 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1191 psppire_data_window_get_property (GObject *object,
1196 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1201 g_value_set_pointer (value, window->dataset);
1204 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1210 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1216 ui_string = gtk_ui_manager_get_ui (uim);
1217 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1221 g_return_val_if_fail (merge_id != 0, 0);
1223 list = gtk_ui_manager_get_action_groups (uim);
1224 for (; list != NULL; list = list->next)
1226 GtkActionGroup *action_group = list->data;
1227 GList *actions = gtk_action_group_list_actions (action_group);
1230 for (action = actions; action != NULL; action = action->next)
1232 GtkAction *a = action->data;
1234 if (PSPPIRE_IS_DIALOG_ACTION (a))
1235 g_object_set (a, "manager", pdw->ui_manager, NULL);
1238 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1241 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1242 gtk_ui_manager_get_accel_group (uim));
1248 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1249 GtkUIManager *uim, guint merge_id)
1253 g_return_if_fail (merge_id != 0);
1255 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1257 list = gtk_ui_manager_get_action_groups (uim);
1258 for (; list != NULL; list = list->next)
1260 GtkActionGroup *action_group = list->data;
1261 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1264 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1265 gtk_ui_manager_get_accel_group (uim));
1269 psppire_data_window_new (struct dataset *ds)
1273 if (the_session == NULL)
1274 the_session = session_create (NULL);
1278 char *dataset_name = session_generate_dataset_name (the_session);
1279 ds = dataset_create (the_session, dataset_name);
1280 free (dataset_name);
1282 assert (dataset_session (ds) == the_session);
1286 psppire_data_window_get_type (),
1287 "description", _("Data Editor"),
1291 if (dataset_name (ds) != NULL)
1292 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1298 psppire_data_window_is_empty (PsppireDataWindow *dw)
1300 return psppire_dict_get_var_cnt (dw->dict) == 0;
1304 psppire_data_window_iface_init (PsppireWindowIface *iface)
1306 iface->save = save_file;
1307 iface->pick_filename = data_pick_filename;
1308 iface->load = load_file;
1312 psppire_default_data_window (void)
1314 if (ll_is_empty (&all_data_windows))
1315 create_data_window ();
1316 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1320 psppire_data_window_set_default (PsppireDataWindow *pdw)
1322 ll_remove (&pdw->ll);
1323 ll_push_head (&all_data_windows, &pdw->ll);
1327 psppire_data_window_undefault (PsppireDataWindow *pdw)
1329 ll_remove (&pdw->ll);
1330 ll_push_tail (&all_data_windows, &pdw->ll);
1334 psppire_data_window_for_dataset (struct dataset *ds)
1336 PsppireDataWindow *pdw;
1338 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1339 if (pdw->dataset == ds)
1346 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1348 PsppireDataWindow *pdw;
1350 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1351 if (pdw->data_store == data_store)
1358 create_data_window (void)
1360 gtk_widget_show (psppire_data_window_new (NULL));
1364 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1368 if (PSPPIRE_IS_DATA_WINDOW (victim)
1369 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1371 window = GTK_WIDGET (victim);
1372 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1375 window = psppire_data_window_new (NULL);
1377 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1378 gtk_widget_show_all (window);