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;
344 ds_init_empty (&filename);
346 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
348 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
350 g_free (utf8_file_name);
352 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
353 ds_destroy (&filename);
361 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
362 lex_reader_for_string (syntax));
365 if (ok && syn == NULL)
367 if (name_has_por_suffix (file_name))
368 mime_type = "application/x-spss-por";
369 else if (name_has_sav_suffix (file_name))
370 mime_type = "application/x-spss-sav";
372 add_most_recent (file_name, mime_type);
379 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
381 if (format == PSPPIRE_DATA_WINDOW_SAV)
383 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
389 /* Save DE to file */
391 save_file (PsppireWindow *w)
393 const gchar *file_name = NULL;
394 gchar *utf8_file_name = NULL;
396 struct string filename ;
397 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
400 file_name = psppire_window_get_filename (w);
402 fnx = g_string_new (file_name);
404 if ( ! name_has_suffix (fnx->str))
405 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
407 ds_init_empty (&filename);
409 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
411 g_string_free (fnx, TRUE);
413 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
414 g_free (utf8_file_name);
416 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
417 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
418 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
419 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
420 ds_cstr (&filename));
422 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
424 ds_destroy (&filename);
426 g_free (execute_syntax_string (de, syntax));
431 display_dict (PsppireDataWindow *de)
433 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
437 sysfile_info (PsppireDataWindow *de)
439 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
441 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
443 struct string filename;
445 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
447 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
452 ds_init_empty (&filename);
454 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
456 g_free (utf8_file_name);
458 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
459 g_free (execute_syntax_string (de, syntax));
462 gtk_widget_destroy (dialog);
466 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
468 data_pick_filename (PsppireWindow *window)
470 GtkListStore *list_store;
471 GtkWidget *combo_box;
473 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
474 GtkFileFilter *filter;
476 gtk_file_chooser_dialog_new (_("Save"),
478 GTK_FILE_CHOOSER_ACTION_SAVE,
479 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
480 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
483 g_object_set (dialog, "local-only", FALSE, NULL);
485 filter = gtk_file_filter_new ();
486 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
487 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
488 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
490 filter = gtk_file_filter_new ();
491 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
492 gtk_file_filter_add_pattern (filter, "*.zsav");
493 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
495 filter = gtk_file_filter_new ();
496 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
497 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
498 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
500 filter = gtk_file_filter_new ();
501 gtk_file_filter_set_name (filter, _("All Files"));
502 gtk_file_filter_add_pattern (filter, "*");
503 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
504 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
507 GtkCellRenderer *cell;
512 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
513 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
515 gtk_list_store_append (list_store, &iter);
516 gtk_list_store_set (list_store, &iter,
517 0, PSPPIRE_DATA_WINDOW_SAV,
520 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
522 gtk_list_store_append (list_store, &iter);
523 gtk_list_store_set (list_store, &iter,
524 0, PSPPIRE_DATA_WINDOW_ZSAV,
525 1, _("Compressed System File"),
528 gtk_list_store_append (list_store, &iter);
529 gtk_list_store_set (list_store, &iter,
530 0, PSPPIRE_DATA_WINDOW_POR,
531 1, _("Portable File"),
534 label = gtk_label_new (_("Format:"));
536 cell = gtk_cell_renderer_text_new ();
537 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
538 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
541 hbox = gtk_hbox_new (FALSE, 0);
542 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
543 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
544 gtk_widget_show_all (hbox);
546 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
549 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
552 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
554 case GTK_RESPONSE_ACCEPT:
559 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
565 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
566 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
571 if ( ! name_has_suffix (filename->str))
572 g_string_append (filename,
573 psppire_data_window_format_to_string (format));
575 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
577 g_string_free (filename, TRUE);
584 gtk_widget_destroy (dialog);
588 confirm_delete_dataset (PsppireDataWindow *de,
589 const char *old_dataset,
590 const char *new_dataset,
591 const char *existing_dataset)
596 dialog = gtk_message_dialog_new (
597 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
598 _("Delete Existing Dataset?"));
600 gtk_message_dialog_format_secondary_text (
601 GTK_MESSAGE_DIALOG (dialog),
602 _("Renaming \"%s\" to \"%s\" will destroy the existing "
603 "dataset named \"%s\". Are you sure that you want to do this?"),
604 old_dataset, new_dataset, existing_dataset);
606 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
607 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
608 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
611 g_object_set (dialog, "icon-name", "pspp", NULL);
613 result = gtk_dialog_run (GTK_DIALOG (dialog));
615 gtk_widget_destroy (dialog);
617 return result == GTK_RESPONSE_OK;
621 on_rename_dataset (PsppireDataWindow *de)
623 struct dataset *ds = de->dataset;
624 struct session *session = dataset_session (ds);
625 const char *old_name = dataset_name (ds);
626 struct dataset *existing_dataset;
630 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
632 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
636 if (new_name == NULL)
639 existing_dataset = session_lookup_dataset (session, new_name);
640 if (existing_dataset == NULL || existing_dataset == ds
641 || confirm_delete_dataset (de, old_name, new_name,
642 dataset_name (existing_dataset)))
643 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
650 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
652 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
654 if ( gtk_toggle_action_get_active (action))
655 gtk_widget_show (statusbar);
657 gtk_widget_hide (statusbar);
662 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
664 const gboolean grid_visible = gtk_toggle_action_get_active (action);
666 psppire_data_editor_show_grid (de->data_editor, grid_visible);
670 data_view_activate (PsppireDataWindow *de)
672 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
677 variable_view_activate (PsppireDataWindow *de)
679 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
684 fonts_activate (PsppireDataWindow *de)
686 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
687 GtkWidget *dialog = gtk_font_selection_dialog_new (_("Font Selection"));
688 GtkStyle *style = gtk_widget_get_style (GTK_WIDGET(de->data_editor));
689 PangoFontDescription *current_font = style->font_desc;
690 gchar *font_name = pango_font_description_to_string (current_font);
692 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
696 gtk_window_set_transient_for (GTK_WINDOW (dialog),
697 GTK_WINDOW (toplevel));
699 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
701 const gchar *font = gtk_font_selection_dialog_get_font_name
702 (GTK_FONT_SELECTION_DIALOG (dialog));
704 PangoFontDescription* font_desc =
705 pango_font_description_from_string (font);
707 psppire_data_editor_set_font (de->data_editor, font_desc);
710 gtk_widget_hide (dialog);
715 /* Callback for the value labels action */
717 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
719 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
723 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
725 psppire_data_editor_split_window (de->data_editor,
726 gtk_toggle_action_get_active (ta));
731 file_quit (PsppireDataWindow *de)
733 /* FIXME: Need to be more intelligent here.
734 Give the user the opportunity to save any unsaved data.
740 on_recent_data_select (GtkMenuShell *menushell,
741 PsppireWindow *window)
746 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
748 file = g_filename_from_uri (uri, NULL, NULL);
752 open_data_window (window, file, NULL);
758 charset_from_mime_type (const char *mime_type)
764 if (mime_type == NULL)
767 charset = c_strcasestr (mime_type, "charset=");
775 /* Parse a "quoted-string" as defined by RFC 822. */
776 for (p++; *p != '\0' && *p != '"'; p++)
779 ds_put_byte (&s, *p);
780 else if (*++p != '\0')
781 ds_put_byte (&s, *p);
786 /* Parse a "token" as defined by RFC 2045. */
787 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
788 ds_put_byte (&s, *p++);
790 if (!ds_is_empty (&s))
791 return ds_steal_cstr (&s);
798 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
805 /* Get the file name and its encoding. */
806 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
807 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
808 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
809 gtk_recent_info_unref (item);
811 se = psppire_syntax_window_new (encoding);
815 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) )
816 gtk_widget_show (se);
818 gtk_widget_destroy (se);
824 set_unsaved (gpointer w)
826 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
830 on_switch_page (PsppireDataEditor *de, gpointer p,
831 gint pagenum, PsppireDataWindow *dw)
833 GtkWidget *page_menu_item;
837 is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
839 ? "/ui/menubar/view/view_data"
840 : "/ui/menubar/view/view_variables");
841 page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
842 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
846 on_ui_manager_changed (PsppireDataEditor *de,
847 GParamSpec *pspec UNUSED,
848 PsppireDataWindow *dw)
850 GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
856 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
857 g_object_unref (dw->uim);
864 g_object_ref (dw->uim);
865 dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
869 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
870 Returns a pointer to the action
873 connect_action (PsppireDataWindow *dw, const char *action_name,
876 GtkAction *action = get_action_assert (dw->builder, action_name);
878 g_signal_connect_swapped (action, "activate", handler, dw);
883 /* Only a data file with at least one variable can be saved. */
885 enable_save (PsppireDataWindow *dw)
887 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
889 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
891 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
895 /* Initializes as much of a PsppireDataWindow as we can and must before the
896 dataset has been set.
898 In particular, the 'menu' member is required in case the "filename" property
899 is set before the "dataset" property: otherwise PsppireWindow will try to
900 modify the menu as part of the "filename" property_set() function and end up
901 with a Gtk-CRITICAL since 'menu' is NULL. */
903 psppire_data_window_init (PsppireDataWindow *de)
906 de->builder = builder_new ("data-editor.ui");
908 de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
910 w = gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all");
912 PSPPIRE_WINDOW (de)->menu = GTK_MENU_SHELL (gtk_widget_get_parent (w));
919 psppire_data_window_finish_init (PsppireDataWindow *de,
922 static const struct dataset_callbacks cbs =
924 set_unsaved, /* changed */
925 transformation_change_callback, /* transformations_changed */
932 GtkWidget *box = gtk_vbox_new (FALSE, 0);
935 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
936 de->data_store = psppire_data_store_new (de->dict);
937 psppire_data_store_set_reader (de->data_store, NULL);
939 menubar = get_widget_assert (de->builder, "menubar");
940 hb = get_widget_assert (de->builder, "handlebox1");
941 sb = get_widget_assert (de->builder, "status-bar");
947 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
948 g_signal_connect (de->data_editor, "switch-page",
949 G_CALLBACK (on_switch_page), de);
951 g_signal_connect_swapped (de->data_store, "case-changed",
952 G_CALLBACK (set_unsaved), de);
954 g_signal_connect_swapped (de->data_store, "case-inserted",
955 G_CALLBACK (set_unsaved), de);
957 g_signal_connect_swapped (de->data_store, "cases-deleted",
958 G_CALLBACK (set_unsaved), de);
960 dataset_set_callbacks (de->dataset, &cbs, de);
962 connect_help (de->builder);
964 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
965 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
966 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
967 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
969 gtk_container_add (GTK_CONTAINER (de), box);
971 g_signal_connect (de->dict, "weight-changed",
972 G_CALLBACK (on_weight_change),
975 g_signal_connect (de->dict, "filter-changed",
976 G_CALLBACK (on_filter_change),
979 g_signal_connect (de->dict, "split-changed",
980 G_CALLBACK (on_split_change),
983 g_signal_connect_swapped (de->dict, "backend-changed",
984 G_CALLBACK (enable_save), de);
985 g_signal_connect_swapped (de->dict, "variable-inserted",
986 G_CALLBACK (enable_save), de);
987 g_signal_connect_swapped (de->dict, "variable-deleted",
988 G_CALLBACK (enable_save), de);
991 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
992 connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
993 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
994 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
995 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
996 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
997 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
998 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1000 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1002 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1003 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1004 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1005 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1006 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1007 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1008 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1009 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1012 GtkWidget *recent_data =
1013 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
1015 GtkWidget *recent_files =
1016 gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
1019 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1020 gtk_recent_manager_get_default ());
1022 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1023 gtk_recent_manager_get_default ());
1025 g_object_set (menu_data, "show-tips", TRUE, NULL);
1026 g_object_set (menu_files, "show-tips", TRUE, NULL);
1029 GtkRecentFilter *filter = gtk_recent_filter_new ();
1031 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1032 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1034 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1036 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1039 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1042 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1045 GtkRecentFilter *filter = gtk_recent_filter_new ();
1047 gtk_recent_filter_add_pattern (filter, "*.sps");
1048 gtk_recent_filter_add_pattern (filter, "*.SPS");
1050 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1052 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1055 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1057 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1061 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1064 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1065 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1067 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1069 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1071 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1073 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1075 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1077 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1079 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1081 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1083 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1085 merge_help_menu (de->ui_manager);
1087 g_signal_connect (de->data_editor, "notify::ui-manager",
1088 G_CALLBACK (on_ui_manager_changed), de);
1089 on_ui_manager_changed (de->data_editor, NULL, de);
1091 gtk_widget_show (GTK_WIDGET (de->data_editor));
1092 gtk_widget_show (box);
1094 ll_push_head (&all_data_windows, &de->ll);
1098 psppire_data_window_dispose (GObject *object)
1100 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1104 psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1105 g_object_unref (dw->uim);
1109 if (dw->builder != NULL)
1111 g_object_unref (dw->builder);
1117 g_signal_handlers_disconnect_by_func (dw->dict,
1118 G_CALLBACK (enable_save), dw);
1119 g_signal_handlers_disconnect_by_func (dw->dict,
1120 G_CALLBACK (on_weight_change), dw);
1121 g_signal_handlers_disconnect_by_func (dw->dict,
1122 G_CALLBACK (on_filter_change), dw);
1123 g_signal_handlers_disconnect_by_func (dw->dict,
1124 G_CALLBACK (on_split_change), dw);
1126 g_object_unref (dw->dict);
1132 g_object_unref (dw->data_store);
1133 dw->data_store = NULL;
1136 if (dw->ll.next != NULL)
1138 ll_remove (&dw->ll);
1142 if (G_OBJECT_CLASS (parent_class)->dispose)
1143 G_OBJECT_CLASS (parent_class)->dispose (object);
1147 psppire_data_window_finalize (GObject *object)
1149 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1153 struct dataset *dataset = dw->dataset;
1154 struct session *session = dataset_session (dataset);
1158 dataset_set_callbacks (dataset, NULL, NULL);
1159 session_set_active_dataset (session, NULL);
1160 dataset_destroy (dataset);
1163 if (G_OBJECT_CLASS (parent_class)->finalize)
1164 G_OBJECT_CLASS (parent_class)->finalize (object);
1168 psppire_data_window_set_property (GObject *object,
1170 const GValue *value,
1173 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1178 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1187 psppire_data_window_get_property (GObject *object,
1192 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1197 g_value_set_pointer (value, window->dataset);
1200 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1206 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1212 ui_string = gtk_ui_manager_get_ui (uim);
1213 merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1217 g_return_val_if_fail (merge_id != 0, 0);
1219 list = gtk_ui_manager_get_action_groups (uim);
1220 for (; list != NULL; list = list->next)
1222 GtkActionGroup *action_group = list->data;
1223 GList *actions = gtk_action_group_list_actions (action_group);
1226 for (action = actions; action != NULL; action = action->next)
1228 GtkAction *a = action->data;
1230 if (PSPPIRE_IS_DIALOG_ACTION (a))
1231 g_object_set (a, "manager", pdw->ui_manager, NULL);
1234 gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1237 gtk_window_add_accel_group (GTK_WINDOW (pdw),
1238 gtk_ui_manager_get_accel_group (uim));
1244 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1245 GtkUIManager *uim, guint merge_id)
1249 g_return_if_fail (merge_id != 0);
1251 gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1253 list = gtk_ui_manager_get_action_groups (uim);
1254 for (; list != NULL; list = list->next)
1256 GtkActionGroup *action_group = list->data;
1257 gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1260 gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1261 gtk_ui_manager_get_accel_group (uim));
1265 psppire_data_window_new (struct dataset *ds)
1269 if (the_session == NULL)
1270 the_session = session_create (NULL);
1274 char *dataset_name = session_generate_dataset_name (the_session);
1275 ds = dataset_create (the_session, dataset_name);
1276 free (dataset_name);
1278 assert (dataset_session (ds) == the_session);
1282 psppire_data_window_get_type (),
1283 "description", _("Data Editor"),
1287 if (dataset_name (ds) != NULL)
1288 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1294 psppire_data_window_is_empty (PsppireDataWindow *dw)
1296 return psppire_dict_get_var_cnt (dw->dict) == 0;
1300 psppire_data_window_iface_init (PsppireWindowIface *iface)
1302 iface->save = save_file;
1303 iface->pick_filename = data_pick_filename;
1304 iface->load = load_file;
1308 psppire_default_data_window (void)
1310 if (ll_is_empty (&all_data_windows))
1311 create_data_window ();
1312 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1316 psppire_data_window_set_default (PsppireDataWindow *pdw)
1318 ll_remove (&pdw->ll);
1319 ll_push_head (&all_data_windows, &pdw->ll);
1323 psppire_data_window_undefault (PsppireDataWindow *pdw)
1325 ll_remove (&pdw->ll);
1326 ll_push_tail (&all_data_windows, &pdw->ll);
1330 psppire_data_window_for_dataset (struct dataset *ds)
1332 PsppireDataWindow *pdw;
1334 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1335 if (pdw->dataset == ds)
1342 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1344 PsppireDataWindow *pdw;
1346 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1347 if (pdw->data_store == data_store)
1354 create_data_window (void)
1356 gtk_widget_show (psppire_data_window_new (NULL));
1360 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1364 if (PSPPIRE_IS_DATA_WINDOW (victim)
1365 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1367 window = GTK_WIDGET (victim);
1368 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1371 window = psppire_data_window_new (NULL);
1373 psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1374 gtk_widget_show_all (window);