1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011 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/binomial-dialog.h"
30 #include "ui/gui/chi-square-dialog.h"
31 #include "ui/gui/comments-dialog.h"
32 #include "ui/gui/compute-dialog.h"
33 #include "ui/gui/correlation-dialog.h"
34 #include "ui/gui/count-dialog.h"
35 #include "ui/gui/crosstabs-dialog.h"
36 #include "ui/gui/descriptives-dialog.h"
37 #include "ui/gui/entry-dialog.h"
38 #include "ui/gui/examine-dialog.h"
39 #include "ui/gui/executor.h"
40 #include "ui/gui/factor-dialog.h"
41 #include "ui/gui/find-dialog.h"
42 #include "ui/gui/frequencies-dialog.h"
43 #include "ui/gui/goto-case-dialog.h"
44 #include "ui/gui/help-menu.h"
45 #include "ui/gui/helper.h"
46 #include "ui/gui/k-related-dialog.h"
47 #include "ui/gui/npar-two-sample-related.h"
48 #include "ui/gui/oneway-anova-dialog.h"
49 #include "ui/gui/psppire-data-window.h"
50 #include "ui/gui/psppire-syntax-window.h"
51 #include "ui/gui/psppire-window.h"
52 #include "ui/gui/psppire.h"
53 #include "ui/gui/rank-dialog.h"
54 #include "ui/gui/recode-dialog.h"
55 #include "ui/gui/regression-dialog.h"
56 #include "ui/gui/reliability-dialog.h"
57 #include "ui/gui/roc-dialog.h"
58 #include "ui/gui/select-cases-dialog.h"
59 #include "ui/gui/sort-cases-dialog.h"
60 #include "ui/gui/split-file-dialog.h"
61 #include "ui/gui/t-test-independent-samples-dialog.h"
62 #include "ui/gui/t-test-one-sample.h"
63 #include "ui/gui/t-test-paired-samples.h"
64 #include "ui/gui/text-data-import-dialog.h"
65 #include "ui/gui/transpose-dialog.h"
66 #include "ui/gui/variable-info-dialog.h"
67 #include "ui/gui/weight-cases-dialog.h"
68 #include "ui/syntax-gen.h"
70 #include "gl/c-strcase.h"
71 #include "gl/c-strcasestr.h"
72 #include "gl/xvasprintf.h"
75 #define _(msgid) gettext (msgid)
76 #define N_(msgid) msgid
78 struct session *the_session;
79 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
81 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
82 static void psppire_data_window_init (PsppireDataWindow *data_editor);
85 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
87 static void psppire_data_window_dispose (GObject *object);
88 static void psppire_data_window_set_property (GObject *object,
92 static void psppire_data_window_get_property (GObject *object,
98 psppire_data_window_get_type (void)
100 static GType psppire_data_window_type = 0;
102 if (!psppire_data_window_type)
104 static const GTypeInfo psppire_data_window_info =
106 sizeof (PsppireDataWindowClass),
109 (GClassInitFunc)psppire_data_window_class_init,
110 (GClassFinalizeFunc) NULL,
112 sizeof (PsppireDataWindow),
114 (GInstanceInitFunc) psppire_data_window_init,
117 static const GInterfaceInfo window_interface_info =
119 (GInterfaceInitFunc) psppire_data_window_iface_init,
124 psppire_data_window_type =
125 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
126 &psppire_data_window_info, 0);
129 g_type_add_interface_static (psppire_data_window_type,
130 PSPPIRE_TYPE_WINDOW_MODEL,
131 &window_interface_info);
134 return psppire_data_window_type;
137 static GObjectClass *parent_class ;
144 psppire_data_window_class_init (PsppireDataWindowClass *class)
146 GObjectClass *object_class = G_OBJECT_CLASS (class);
148 parent_class = g_type_class_peek_parent (class);
150 object_class->dispose = psppire_data_window_dispose;
151 object_class->set_property = psppire_data_window_set_property;
152 object_class->get_property = psppire_data_window_get_property;
154 g_object_class_install_property (
155 object_class, PROP_DATASET,
156 g_param_spec_pointer ("dataset", "Dataset",
157 "'struct datset *' represented by the window",
158 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
162 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
164 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
166 gtk_action_set_sensitive (edit_paste, x);
170 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
172 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
173 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
175 gtk_action_set_sensitive (edit_copy, x);
176 gtk_action_set_sensitive (edit_cut, x);
179 /* Run the EXECUTE command. */
181 execute (PsppireDataWindow *dw)
183 execute_const_syntax_string (dw, "EXECUTE.");
187 transformation_change_callback (bool transformations_pending,
190 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
192 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
194 GtkWidget *menuitem =
195 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
197 GtkWidget *status_label =
198 get_widget_assert (de->builder, "case-counter-area");
200 gtk_widget_set_sensitive (menuitem, transformations_pending);
203 if ( transformations_pending)
204 gtk_label_set_text (GTK_LABEL (status_label),
205 _("Transformations Pending"));
207 gtk_label_set_text (GTK_LABEL (status_label), "");
210 /* Callback for when the dictionary changes its filter variable */
212 on_filter_change (GObject *o, gint filter_index, gpointer data)
214 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
216 GtkWidget *filter_status_area =
217 get_widget_assert (de->builder, "filter-use-status-area");
219 if ( filter_index == -1 )
221 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
225 PsppireVarStore *vs = NULL;
226 PsppireDict *dict = NULL;
227 struct variable *var ;
230 g_object_get (de->data_editor, "var-store", &vs, NULL);
231 g_object_get (vs, "dictionary", &dict, NULL);
233 var = psppire_dict_get_variable (dict, filter_index);
235 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
237 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
243 /* Callback for when the dictionary changes its split variables */
245 on_split_change (PsppireDict *dict, gpointer data)
247 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
249 size_t n_split_vars = dict_get_split_cnt (dict->dict);
251 GtkWidget *split_status_area =
252 get_widget_assert (de->builder, "split-file-status-area");
254 if ( n_split_vars == 0 )
256 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
262 const struct variable *const * split_vars =
263 dict_get_split_vars (dict->dict);
265 text = g_string_new (_("Split by "));
267 for (i = 0 ; i < n_split_vars - 1; ++i )
269 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
271 g_string_append (text, var_get_name (split_vars[i]));
273 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
275 g_string_free (text, TRUE);
282 /* Callback for when the dictionary changes its weights */
284 on_weight_change (GObject *o, gint weight_index, gpointer data)
286 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
288 GtkWidget *weight_status_area =
289 get_widget_assert (de->builder, "weight-status-area");
291 if ( weight_index == -1 )
293 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
297 struct variable *var ;
298 PsppireVarStore *vs = NULL;
299 PsppireDict *dict = NULL;
302 g_object_get (de->data_editor, "var-store", &vs, NULL);
303 g_object_get (vs, "dictionary", &dict, NULL);
305 var = psppire_dict_get_variable (dict, weight_index);
307 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
309 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
317 dump_rm (GtkRecentManager *rm)
319 GList *items = gtk_recent_manager_get_items (rm);
323 g_print ("Recent Items:\n");
324 for (i = items; i; i = i->next)
326 GtkRecentInfo *ri = i->data;
328 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
329 gtk_recent_info_get_short_name (ri),
330 gtk_recent_info_get_mime_type (ri),
331 gtk_recent_info_get_description (ri),
332 gtk_recent_info_get_uri (ri)
336 gtk_recent_info_unref (ri);
344 name_has_por_suffix (const gchar *name)
346 size_t length = strlen (name);
347 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
351 name_has_sav_suffix (const gchar *name)
353 size_t length = strlen (name);
354 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
357 /* Returns true if NAME has a suffix which might denote a PSPP file */
359 name_has_suffix (const gchar *name)
361 return name_has_por_suffix (name) || name_has_sav_suffix (name);
365 load_file (PsppireWindow *de, const gchar *file_name)
367 struct string filename;
368 gchar *utf8_file_name;
369 const char *mime_type;
373 ds_init_empty (&filename);
375 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
377 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
379 g_free (utf8_file_name);
381 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
382 ds_destroy (&filename);
384 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
385 lex_reader_for_string (syntax));
388 mime_type = (name_has_por_suffix (file_name)
389 ? "application/x-spss-por"
390 : "application/x-spss-sav");
392 add_most_recent (file_name, mime_type);
397 /* Save DE to file */
399 save_file (PsppireWindow *w)
401 const gchar *file_name = NULL;
402 gchar *utf8_file_name = NULL;
404 struct string filename ;
405 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
408 file_name = psppire_window_get_filename (w);
410 fnx = g_string_new (file_name);
412 if ( ! name_has_suffix (fnx->str))
414 if ( de->save_as_portable)
415 g_string_append (fnx, ".por");
417 g_string_append (fnx, ".sav");
420 ds_init_empty (&filename);
422 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
424 g_string_free (fnx, TRUE);
426 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
427 g_free (utf8_file_name);
429 syntax = g_strdup_printf ("%s OUTFILE=%s.",
430 de->save_as_portable ? "EXPORT" : "SAVE",
431 ds_cstr (&filename));
433 ds_destroy (&filename);
435 g_free (execute_syntax_string (de, syntax));
440 insert_case (PsppireDataWindow *dw)
442 psppire_data_editor_insert_case (dw->data_editor);
446 on_insert_variable (PsppireDataWindow *dw)
448 psppire_data_editor_insert_variable (dw->data_editor);
453 display_dict (PsppireDataWindow *de)
455 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
459 sysfile_info (PsppireDataWindow *de)
461 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
463 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
465 struct string filename;
467 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
469 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
474 ds_init_empty (&filename);
476 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
478 g_free (utf8_file_name);
480 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
481 g_free (execute_syntax_string (de, syntax));
484 gtk_widget_destroy (dialog);
488 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
490 data_pick_filename (PsppireWindow *window)
492 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
493 GtkWidget *button_sys;
495 gtk_file_chooser_dialog_new (_("Save"),
497 GTK_FILE_CHOOSER_ACTION_SAVE,
498 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
499 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
502 GtkFileFilter *filter = gtk_file_filter_new ();
503 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
504 gtk_file_filter_add_pattern (filter, "*.sav");
505 gtk_file_filter_add_pattern (filter, "*.SAV");
506 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
508 filter = gtk_file_filter_new ();
509 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
510 gtk_file_filter_add_pattern (filter, "*.por");
511 gtk_file_filter_add_pattern (filter, "*.POR");
512 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
514 filter = gtk_file_filter_new ();
515 gtk_file_filter_set_name (filter, _("All Files"));
516 gtk_file_filter_add_pattern (filter, "*");
517 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
520 GtkWidget *button_por;
521 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
523 gtk_radio_button_new_with_label (NULL, _("System File"));
526 gtk_radio_button_new_with_label
527 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
530 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
531 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
533 gtk_widget_show_all (vbox);
535 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
538 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
541 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
543 case GTK_RESPONSE_ACCEPT:
548 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
551 de->save_as_portable =
552 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
554 if ( ! name_has_suffix (filename->str))
556 if ( de->save_as_portable)
557 g_string_append (filename, ".por");
559 g_string_append (filename, ".sav");
562 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
564 g_string_free (filename, TRUE);
571 gtk_widget_destroy (dialog);
575 confirm_delete_dataset (PsppireDataWindow *de,
576 const char *old_dataset,
577 const char *new_dataset,
578 const char *existing_dataset)
583 dialog = gtk_message_dialog_new (
584 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
585 _("Delete Existing Dataset?"));
587 gtk_message_dialog_format_secondary_text (
588 GTK_MESSAGE_DIALOG (dialog),
589 _("Renaming \"%s\" to \"%s\" will delete destroy the existing "
590 "dataset named \"%s\". Are you sure that you want to do this?"),
591 old_dataset, new_dataset, existing_dataset);
593 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
594 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
595 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
598 g_object_set (dialog, "icon-name", "psppicon", NULL);
600 result = gtk_dialog_run (GTK_DIALOG (dialog));
602 gtk_widget_destroy (dialog);
604 return result == GTK_RESPONSE_OK;
608 on_rename_dataset (PsppireDataWindow *de)
610 struct dataset *ds = de->dataset;
611 struct session *session = dataset_session (ds);
612 const char *old_name = dataset_name (ds);
613 struct dataset *existing_dataset;
617 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
619 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
623 if (new_name == NULL)
626 existing_dataset = session_lookup_dataset (session, new_name);
627 if (existing_dataset == NULL || existing_dataset == ds
628 || confirm_delete_dataset (de, old_name, new_name,
629 dataset_name (existing_dataset)))
630 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
637 on_edit_paste (PsppireDataWindow *de)
639 psppire_data_editor_clip_paste (de->data_editor);
643 on_edit_copy (PsppireDataWindow *de)
645 psppire_data_editor_clip_copy (de->data_editor);
651 on_edit_cut (PsppireDataWindow *de)
653 psppire_data_editor_clip_cut (de->data_editor);
658 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
660 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
662 if ( gtk_toggle_action_get_active (action))
663 gtk_widget_show (statusbar);
665 gtk_widget_hide (statusbar);
670 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
672 const gboolean grid_visible = gtk_toggle_action_get_active (action);
674 psppire_data_editor_show_grid (de->data_editor, grid_visible);
678 data_view_activate (PsppireDataWindow *de)
680 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
685 variable_view_activate (PsppireDataWindow *de)
687 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
692 fonts_activate (PsppireDataWindow *de)
694 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
695 PangoFontDescription *current_font;
698 gtk_font_selection_dialog_new (_("Font Selection"));
701 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
702 font_name = pango_font_description_to_string (current_font);
704 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
708 gtk_window_set_transient_for (GTK_WINDOW (dialog),
709 GTK_WINDOW (toplevel));
711 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
713 const gchar *font = gtk_font_selection_dialog_get_font_name
714 (GTK_FONT_SELECTION_DIALOG (dialog));
716 PangoFontDescription* font_desc =
717 pango_font_description_from_string (font);
719 psppire_data_editor_set_font (de->data_editor, font_desc);
722 gtk_widget_hide (dialog);
727 /* Callback for the value labels action */
729 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
731 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
735 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
737 psppire_data_editor_split_window (de->data_editor,
738 gtk_toggle_action_get_active (ta));
743 file_quit (PsppireDataWindow *de)
745 /* FIXME: Need to be more intelligent here.
746 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);
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) )
829 gtk_widget_show (se);
831 gtk_widget_destroy (se);
838 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
840 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
842 gtk_action_set_visible (de->delete_cases, case_num != -1);
847 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
849 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
851 gtk_action_set_visible (de->delete_variables, var != -1);
854 /* Callback for when the datasheet/varsheet is selected */
856 on_switch_sheet (GtkNotebook *notebook,
857 GtkNotebookPage *page,
861 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
863 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
865 GtkWidget *view_data =
866 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
868 GtkWidget *view_variables =
869 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
873 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
874 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
876 gtk_action_set_sensitive (de->insert_variable, TRUE);
877 gtk_action_set_sensitive (de->insert_case, FALSE);
878 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
880 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
881 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
882 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
883 gtk_action_set_sensitive (de->insert_case, TRUE);
886 g_assert_not_reached ();
891 update_paste_menuitem (de, page_num);
898 set_unsaved (gpointer w)
900 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
904 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
905 Returns a pointer to the action
908 connect_action (PsppireDataWindow *dw, const char *action_name,
911 GtkAction *action = get_action_assert (dw->builder, action_name);
913 g_signal_connect_swapped (action, "activate", handler, dw);
918 /* Initializes as much of a PsppireDataWindow as we can and must before the
919 dataset has been set.
921 In particular, the 'menu' member is required in case the "filename" property
922 is set before the "dataset" property: otherwise PsppireWindow will try to
923 modify the menu as part of the "filename" property_set() function and end up
924 with a Gtk-CRITICAL since 'menu' is NULL. */
926 psppire_data_window_init (PsppireDataWindow *de)
930 de->builder = builder_new ("data-editor.ui");
932 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
934 PSPPIRE_WINDOW (de)->menu =
935 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
939 psppire_data_window_finish_init (PsppireDataWindow *de,
942 static const struct dataset_callbacks cbs =
944 set_unsaved, /* changed */
945 transformation_change_callback, /* transformations_changed */
954 GtkWidget *box = gtk_vbox_new (FALSE, 0);
957 dict = psppire_dict_new_from_dict (dataset_dict (ds));
958 de->var_store = psppire_var_store_new (dict);
959 de->data_store = psppire_data_store_new (dict);
960 psppire_data_store_set_reader (de->data_store, NULL);
962 menubar = get_widget_assert (de->builder, "menubar");
963 hb = get_widget_assert (de->builder, "handlebox1");
964 sb = get_widget_assert (de->builder, "status-bar");
967 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
970 g_signal_connect_swapped (de->data_store, "case-changed",
971 G_CALLBACK (set_unsaved), de);
973 g_signal_connect_swapped (de->data_store, "case-inserted",
974 G_CALLBACK (set_unsaved), de);
976 g_signal_connect_swapped (de->data_store, "cases-deleted",
977 G_CALLBACK (set_unsaved), de);
979 dataset_set_callbacks (de->dataset, &cbs, de);
981 connect_help (de->builder);
983 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
984 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
985 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
986 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
988 gtk_container_add (GTK_CONTAINER (de), box);
990 set_cut_copy_menuitem_sensitivity (de, FALSE);
992 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
993 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
996 set_paste_menuitem_sensitivity (de, FALSE);
998 g_signal_connect_swapped (de->data_editor, "data-available-changed",
999 G_CALLBACK (set_paste_menuitem_sensitivity), de);
1001 g_signal_connect (dict, "weight-changed",
1002 G_CALLBACK (on_weight_change),
1005 g_signal_connect (dict, "filter-changed",
1006 G_CALLBACK (on_filter_change),
1009 g_signal_connect (dict, "split-changed",
1010 G_CALLBACK (on_split_change),
1014 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1016 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1018 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1020 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1022 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1024 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1026 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1028 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1030 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1032 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1034 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1036 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1038 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1040 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1042 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1045 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1047 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1049 gtk_action_set_visible (de->delete_cases, FALSE);
1054 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1056 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1058 gtk_action_set_visible (de->delete_variables, FALSE);
1062 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1064 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1066 connect_action (de, "data_sort-cases", G_CALLBACK (sort_cases_dialog));
1068 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1070 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1072 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1074 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1076 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1078 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1081 connect_action (de, "utilities_variables", G_CALLBACK (variable_info_dialog));
1083 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1085 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1087 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1089 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1091 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1093 connect_action (de, "transform_rank", G_CALLBACK (rank_dialog));
1095 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1097 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1099 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1101 connect_action (de, "analyze_descriptives", G_CALLBACK (descriptives_dialog));
1103 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1105 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1107 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1109 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1111 connect_action (de, "reliability", G_CALLBACK (reliability_dialog));
1113 connect_action (de, "roc-curve", G_CALLBACK (roc_dialog));
1115 connect_action (de, "correlation", G_CALLBACK (correlation_dialog));
1117 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1119 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1121 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1123 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1124 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1128 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1130 GtkWidget *recent_data =
1131 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1133 GtkWidget *recent_files =
1134 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1137 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1138 gtk_recent_manager_get_default ());
1140 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1141 gtk_recent_manager_get_default ());
1143 g_object_set (menu_data, "show-tips", TRUE, NULL);
1144 g_object_set (menu_files, "show-tips", TRUE, NULL);
1147 GtkRecentFilter *filter = gtk_recent_filter_new ();
1149 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1150 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1152 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1154 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1157 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1160 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1163 GtkRecentFilter *filter = gtk_recent_filter_new ();
1165 gtk_recent_filter_add_pattern (filter, "*.sps");
1166 gtk_recent_filter_add_pattern (filter, "*.SPS");
1168 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1170 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1173 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1175 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1179 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1182 g_signal_connect (de->data_editor,
1184 G_CALLBACK (enable_delete_cases),
1187 g_signal_connect (de->data_editor,
1188 "variables-selected",
1189 G_CALLBACK (enable_delete_variables),
1193 g_signal_connect (de->data_editor,
1195 G_CALLBACK (on_switch_sheet), de);
1197 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1198 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1200 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1202 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1204 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1206 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1208 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1210 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1212 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1214 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1216 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1219 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1221 merge_help_menu (uim);
1225 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1226 "datasheet-cases-popup");
1228 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1229 "varsheet-variable-popup");
1231 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1232 "datasheet-variable-popup");
1234 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1235 G_CALLBACK (psppire_data_editor_sort_ascending),
1238 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1239 G_CALLBACK (psppire_data_editor_sort_descending),
1242 g_object_set (de->data_editor,
1243 "datasheet-column-menu", data_sheet_variable_popup_menu,
1244 "datasheet-row-menu", data_sheet_cases_popup_menu,
1245 "varsheet-row-menu", var_sheet_variable_popup_menu,
1249 gtk_widget_show (GTK_WIDGET (de->data_editor));
1250 gtk_widget_show (box);
1252 ll_push_head (&all_data_windows, &de->ll);
1256 psppire_data_window_dispose (GObject *object)
1258 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1260 if (dw->builder != NULL)
1262 g_object_unref (dw->builder);
1268 g_object_unref (dw->var_store);
1269 dw->var_store = NULL;
1274 g_object_unref (dw->data_store);
1275 dw->data_store = NULL;
1278 if (dw->ll.next != NULL)
1280 ll_remove (&dw->ll);
1284 if (G_OBJECT_CLASS (parent_class)->dispose)
1285 G_OBJECT_CLASS (parent_class)->dispose (object);
1289 psppire_data_window_set_property (GObject *object,
1291 const GValue *value,
1294 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1299 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1302 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1308 psppire_data_window_get_property (GObject *object,
1313 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1318 g_value_set_pointer (value, window->dataset);
1321 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1327 psppire_data_window_new (struct dataset *ds)
1331 if (the_session == NULL)
1332 the_session = session_create ();
1336 static int n_datasets;
1339 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1340 ds = dataset_create (the_session, dataset_name);
1341 free (dataset_name);
1343 assert (dataset_session (ds) == the_session);
1347 psppire_data_window_get_type (),
1348 /* TRANSLATORS: This will form a filename. Please avoid whitespace. */
1349 "description", _("Data Editor"),
1353 if (dataset_name (ds) != NULL)
1354 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1360 psppire_data_window_is_empty (PsppireDataWindow *dw)
1362 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1366 psppire_data_window_iface_init (PsppireWindowIface *iface)
1368 iface->save = save_file;
1369 iface->pick_filename = data_pick_filename;
1370 iface->load = load_file;
1374 psppire_default_data_window (void)
1376 if (ll_is_empty (&all_data_windows))
1377 create_data_window ();
1378 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1382 psppire_data_window_set_default (PsppireDataWindow *pdw)
1384 ll_remove (&pdw->ll);
1385 ll_push_head (&all_data_windows, &pdw->ll);
1389 psppire_data_window_undefault (PsppireDataWindow *pdw)
1391 ll_remove (&pdw->ll);
1392 ll_push_tail (&all_data_windows, &pdw->ll);
1396 psppire_data_window_for_dataset (struct dataset *ds)
1398 PsppireDataWindow *pdw;
1400 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1401 if (pdw->dataset == ds)
1408 create_data_window (void)
1410 gtk_widget_show (psppire_data_window_new (NULL));
1414 open_data_window (PsppireWindow *victim, const char *file_name)
1418 if (PSPPIRE_IS_DATA_WINDOW (victim)
1419 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1420 window = GTK_WIDGET (victim);
1422 window = psppire_data_window_new (NULL);
1424 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1425 gtk_widget_show (window);