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/binomial-dialog.h"
29 #include "ui/gui/chi-square-dialog.h"
30 #include "ui/gui/comments-dialog.h"
31 #include "ui/gui/compute-dialog.h"
32 #include "ui/gui/correlation-dialog.h"
33 #include "ui/gui/crosstabs-dialog.h"
34 #include "ui/gui/descriptives-dialog.h"
35 #include "ui/gui/entry-dialog.h"
36 #include "ui/gui/examine-dialog.h"
37 #include "ui/gui/executor.h"
38 #include "ui/gui/factor-dialog.h"
39 #include "ui/gui/find-dialog.h"
40 #include "ui/gui/frequencies-dialog.h"
41 #include "ui/gui/goto-case-dialog.h"
42 #include "ui/gui/help-menu.h"
43 #include "ui/gui/helper.h"
44 #include "ui/gui/k-related-dialog.h"
45 #include "ui/gui/oneway-anova-dialog.h"
46 #include "ui/gui/psppire-data-window.h"
47 #include "ui/gui/psppire-syntax-window.h"
48 #include "ui/gui/psppire-window.h"
49 #include "ui/gui/psppire.h"
50 #include "ui/gui/rank-dialog.h"
51 #include "ui/gui/recode-dialog.h"
52 #include "ui/gui/regression-dialog.h"
53 #include "ui/gui/reliability-dialog.h"
54 #include "ui/gui/roc-dialog.h"
55 #include "ui/gui/select-cases-dialog.h"
56 #include "ui/gui/sort-cases-dialog.h"
57 #include "ui/gui/split-file-dialog.h"
58 #include "ui/gui/t-test-independent-samples-dialog.h"
59 #include "ui/gui/t-test-one-sample.h"
60 #include "ui/gui/t-test-paired-samples.h"
61 #include "ui/gui/text-data-import-dialog.h"
62 #include "ui/gui/transpose-dialog.h"
63 #include "ui/gui/variable-info-dialog.h"
64 #include "ui/gui/weight-cases-dialog.h"
65 #include "ui/syntax-gen.h"
67 #include "gl/c-strcase.h"
68 #include "gl/c-strcasestr.h"
69 #include "gl/xvasprintf.h"
72 #define _(msgid) gettext (msgid)
73 #define N_(msgid) msgid
75 struct session *the_session;
76 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
78 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
79 static void psppire_data_window_init (PsppireDataWindow *data_editor);
82 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
84 static void psppire_data_window_dispose (GObject *object);
85 static void psppire_data_window_set_property (GObject *object,
89 static void psppire_data_window_get_property (GObject *object,
95 psppire_data_window_get_type (void)
97 static GType psppire_data_window_type = 0;
99 if (!psppire_data_window_type)
101 static const GTypeInfo psppire_data_window_info =
103 sizeof (PsppireDataWindowClass),
106 (GClassInitFunc)psppire_data_window_class_init,
107 (GClassFinalizeFunc) NULL,
109 sizeof (PsppireDataWindow),
111 (GInstanceInitFunc) psppire_data_window_init,
114 static const GInterfaceInfo window_interface_info =
116 (GInterfaceInitFunc) psppire_data_window_iface_init,
121 psppire_data_window_type =
122 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
123 &psppire_data_window_info, 0);
126 g_type_add_interface_static (psppire_data_window_type,
127 PSPPIRE_TYPE_WINDOW_MODEL,
128 &window_interface_info);
131 return psppire_data_window_type;
134 static GObjectClass *parent_class ;
141 psppire_data_window_class_init (PsppireDataWindowClass *class)
143 GObjectClass *object_class = G_OBJECT_CLASS (class);
145 parent_class = g_type_class_peek_parent (class);
147 object_class->dispose = psppire_data_window_dispose;
148 object_class->set_property = psppire_data_window_set_property;
149 object_class->get_property = psppire_data_window_get_property;
151 g_object_class_install_property (
152 object_class, PROP_DATASET,
153 g_param_spec_pointer ("dataset", "Dataset",
154 "'struct datset *' represented by the window",
155 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
159 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
161 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
163 gtk_action_set_sensitive (edit_paste, x);
167 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
169 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
170 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
172 gtk_action_set_sensitive (edit_copy, x);
173 gtk_action_set_sensitive (edit_cut, x);
176 /* Run the EXECUTE command. */
178 execute (PsppireDataWindow *dw)
180 execute_const_syntax_string (dw, "EXECUTE.");
184 transformation_change_callback (bool transformations_pending,
187 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
189 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
191 GtkWidget *menuitem =
192 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
194 GtkWidget *status_label =
195 get_widget_assert (de->builder, "case-counter-area");
197 gtk_widget_set_sensitive (menuitem, transformations_pending);
200 if ( transformations_pending)
201 gtk_label_set_text (GTK_LABEL (status_label),
202 _("Transformations Pending"));
204 gtk_label_set_text (GTK_LABEL (status_label), "");
207 /* Callback for when the dictionary changes its filter variable */
209 on_filter_change (GObject *o, gint filter_index, gpointer data)
211 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
213 GtkWidget *filter_status_area =
214 get_widget_assert (de->builder, "filter-use-status-area");
216 if ( filter_index == -1 )
218 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
222 PsppireVarStore *vs = NULL;
223 PsppireDict *dict = NULL;
224 struct variable *var ;
227 g_object_get (de->data_editor, "var-store", &vs, NULL);
228 g_object_get (vs, "dictionary", &dict, NULL);
230 var = psppire_dict_get_variable (dict, filter_index);
232 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
234 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
240 /* Callback for when the dictionary changes its split variables */
242 on_split_change (PsppireDict *dict, gpointer data)
244 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
246 size_t n_split_vars = dict_get_split_cnt (dict->dict);
248 GtkWidget *split_status_area =
249 get_widget_assert (de->builder, "split-file-status-area");
251 if ( n_split_vars == 0 )
253 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
259 const struct variable *const * split_vars =
260 dict_get_split_vars (dict->dict);
262 text = g_string_new (_("Split by "));
264 for (i = 0 ; i < n_split_vars - 1; ++i )
266 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
268 g_string_append (text, var_get_name (split_vars[i]));
270 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
272 g_string_free (text, TRUE);
279 /* Callback for when the dictionary changes its weights */
281 on_weight_change (GObject *o, gint weight_index, gpointer data)
283 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
285 GtkWidget *weight_status_area =
286 get_widget_assert (de->builder, "weight-status-area");
288 if ( weight_index == -1 )
290 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
294 struct variable *var ;
295 PsppireVarStore *vs = NULL;
296 PsppireDict *dict = NULL;
299 g_object_get (de->data_editor, "var-store", &vs, NULL);
300 g_object_get (vs, "dictionary", &dict, NULL);
302 var = psppire_dict_get_variable (dict, weight_index);
304 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
306 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
314 dump_rm (GtkRecentManager *rm)
316 GList *items = gtk_recent_manager_get_items (rm);
320 g_print ("Recent Items:\n");
321 for (i = items; i; i = i->next)
323 GtkRecentInfo *ri = i->data;
325 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
326 gtk_recent_info_get_short_name (ri),
327 gtk_recent_info_get_mime_type (ri),
328 gtk_recent_info_get_description (ri),
329 gtk_recent_info_get_uri (ri)
333 gtk_recent_info_unref (ri);
341 name_has_por_suffix (const gchar *name)
343 size_t length = strlen (name);
344 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
348 name_has_sav_suffix (const gchar *name)
350 size_t length = strlen (name);
351 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
354 /* Returns true if NAME has a suffix which might denote a PSPP file */
356 name_has_suffix (const gchar *name)
358 return name_has_por_suffix (name) || name_has_sav_suffix (name);
362 load_file (PsppireWindow *de, const gchar *file_name)
364 struct string filename;
365 gchar *utf8_file_name;
366 const char *mime_type;
370 ds_init_empty (&filename);
372 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
374 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
376 g_free (utf8_file_name);
378 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
379 ds_destroy (&filename);
381 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
382 lex_reader_for_string (syntax));
385 mime_type = (name_has_por_suffix (file_name)
386 ? "application/x-spss-por"
387 : "application/x-spss-sav");
388 add_most_recent (ds_cstr (&filename), mime_type);
393 /* Save DE to file */
395 save_file (PsppireWindow *w)
397 const gchar *file_name = NULL;
398 gchar *utf8_file_name = NULL;
400 struct string filename ;
401 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
404 file_name = psppire_window_get_filename (w);
406 fnx = g_string_new (file_name);
408 if ( ! name_has_suffix (fnx->str))
410 if ( de->save_as_portable)
411 g_string_append (fnx, ".por");
413 g_string_append (fnx, ".sav");
416 ds_init_empty (&filename);
418 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
420 g_string_free (fnx, TRUE);
422 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
423 g_free (utf8_file_name);
425 syntax = g_strdup_printf ("%s OUTFILE=%s.",
426 de->save_as_portable ? "EXPORT" : "SAVE",
427 ds_cstr (&filename));
429 ds_destroy (&filename);
431 g_free (execute_syntax_string (de, syntax));
436 insert_case (PsppireDataWindow *dw)
438 psppire_data_editor_insert_case (dw->data_editor);
442 on_insert_variable (PsppireDataWindow *dw)
444 psppire_data_editor_insert_variable (dw->data_editor);
449 display_dict (PsppireDataWindow *de)
451 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
455 sysfile_info (PsppireDataWindow *de)
457 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
459 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
461 struct string filename;
463 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
465 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
470 ds_init_empty (&filename);
472 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
474 g_free (utf8_file_name);
476 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
477 g_free (execute_syntax_string (de, syntax));
480 gtk_widget_destroy (dialog);
484 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
486 data_pick_filename (PsppireWindow *window)
488 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
489 GtkWidget *button_sys;
491 gtk_file_chooser_dialog_new (_("Save"),
493 GTK_FILE_CHOOSER_ACTION_SAVE,
494 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
495 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
498 GtkFileFilter *filter = gtk_file_filter_new ();
499 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
500 gtk_file_filter_add_pattern (filter, "*.sav");
501 gtk_file_filter_add_pattern (filter, "*.SAV");
502 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
504 filter = gtk_file_filter_new ();
505 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
506 gtk_file_filter_add_pattern (filter, "*.por");
507 gtk_file_filter_add_pattern (filter, "*.POR");
508 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
510 filter = gtk_file_filter_new ();
511 gtk_file_filter_set_name (filter, _("All Files"));
512 gtk_file_filter_add_pattern (filter, "*");
513 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
516 GtkWidget *button_por;
517 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
519 gtk_radio_button_new_with_label (NULL, _("System File"));
522 gtk_radio_button_new_with_label
523 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
526 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
527 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
529 gtk_widget_show_all (vbox);
531 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
534 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
537 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
539 case GTK_RESPONSE_ACCEPT:
544 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
547 de->save_as_portable =
548 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
550 if ( ! name_has_suffix (filename->str))
552 if ( de->save_as_portable)
553 g_string_append (filename, ".por");
555 g_string_append (filename, ".sav");
558 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
560 g_string_free (filename, TRUE);
567 gtk_widget_destroy (dialog);
571 confirm_delete_dataset (PsppireDataWindow *de,
572 const char *old_dataset,
573 const char *new_dataset,
574 const char *existing_dataset)
579 dialog = gtk_message_dialog_new (
580 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
581 _("Delete Existing Dataset?"));
583 gtk_message_dialog_format_secondary_text (
584 GTK_MESSAGE_DIALOG (dialog),
585 _("Renaming \"%s\" to \"%s\" will delete destroy the existing "
586 "dataset named \"%s\". Are you sure that you want to do this?"),
587 old_dataset, new_dataset, existing_dataset);
589 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
590 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
591 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
594 g_object_set (dialog, "icon-name", "psppicon", NULL);
596 result = gtk_dialog_run (GTK_DIALOG (dialog));
598 gtk_widget_destroy (dialog);
600 return result == GTK_RESPONSE_OK;
604 on_rename_dataset (PsppireDataWindow *de)
606 struct dataset *ds = de->dataset;
607 struct session *session = dataset_session (ds);
608 const char *old_name = dataset_name (ds);
609 struct dataset *existing_dataset;
613 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
615 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
619 if (new_name == NULL)
622 existing_dataset = session_lookup_dataset (session, new_name);
623 if (existing_dataset == NULL || existing_dataset == ds
624 || confirm_delete_dataset (de, old_name, new_name,
625 dataset_name (existing_dataset)))
626 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
633 on_edit_paste (PsppireDataWindow *de)
635 psppire_data_editor_clip_paste (de->data_editor);
639 on_edit_copy (PsppireDataWindow *de)
641 psppire_data_editor_clip_copy (de->data_editor);
647 on_edit_cut (PsppireDataWindow *de)
649 psppire_data_editor_clip_cut (de->data_editor);
654 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
656 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
658 if ( gtk_toggle_action_get_active (action))
659 gtk_widget_show (statusbar);
661 gtk_widget_hide (statusbar);
666 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
668 const gboolean grid_visible = gtk_toggle_action_get_active (action);
670 psppire_data_editor_show_grid (de->data_editor, grid_visible);
674 data_view_activate (PsppireDataWindow *de)
676 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
681 variable_view_activate (PsppireDataWindow *de)
683 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
688 fonts_activate (PsppireDataWindow *de)
690 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
691 PangoFontDescription *current_font;
694 gtk_font_selection_dialog_new (_("Font Selection"));
697 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
698 font_name = pango_font_description_to_string (current_font);
700 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
704 gtk_window_set_transient_for (GTK_WINDOW (dialog),
705 GTK_WINDOW (toplevel));
707 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
709 const gchar *font = gtk_font_selection_dialog_get_font_name
710 (GTK_FONT_SELECTION_DIALOG (dialog));
712 PangoFontDescription* font_desc =
713 pango_font_description_from_string (font);
715 psppire_data_editor_set_font (de->data_editor, font_desc);
718 gtk_widget_hide (dialog);
723 /* Callback for the value labels action */
725 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
727 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
731 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
733 psppire_data_editor_split_window (de->data_editor,
734 gtk_toggle_action_get_active (ta));
739 file_quit (PsppireDataWindow *de)
741 /* FIXME: Need to be more intelligent here.
742 Give the user the opportunity to save any unsaved data.
749 on_recent_data_select (GtkMenuShell *menushell,
750 PsppireWindow *window)
755 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
757 file = g_filename_from_uri (uri, NULL, NULL);
761 open_data_window (window, file);
767 charset_from_mime_type (const char *mime_type)
773 if (mime_type == NULL)
776 charset = c_strcasestr (mime_type, "charset=");
784 /* Parse a "quoted-string" as defined by RFC 822. */
785 for (p++; *p != '\0' && *p != '"'; p++)
788 ds_put_byte (&s, *p);
789 else if (*++p != '\0')
790 ds_put_byte (&s, *p);
795 /* Parse a "token" as defined by RFC 2045. */
796 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
797 ds_put_byte (&s, *p++);
799 if (!ds_is_empty (&s))
800 return ds_steal_cstr (&s);
807 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
814 /* Get the file name and its encoding. */
815 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
816 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
817 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
818 gtk_recent_info_unref (item);
820 se = psppire_syntax_window_new (encoding);
824 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
825 gtk_widget_show (se);
827 gtk_widget_destroy (se);
834 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
836 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
838 gtk_action_set_visible (de->delete_cases, case_num != -1);
843 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
845 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
847 gtk_action_set_visible (de->delete_variables, var != -1);
850 /* Callback for when the datasheet/varsheet is selected */
852 on_switch_sheet (GtkNotebook *notebook,
853 GtkNotebookPage *page,
857 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
859 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
861 GtkWidget *view_data =
862 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
864 GtkWidget *view_variables =
865 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
869 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
870 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
872 gtk_action_set_sensitive (de->insert_variable, TRUE);
873 gtk_action_set_sensitive (de->insert_case, FALSE);
874 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
876 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
877 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
878 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
879 gtk_action_set_sensitive (de->insert_case, TRUE);
882 g_assert_not_reached ();
887 update_paste_menuitem (de, page_num);
894 set_unsaved (gpointer w)
896 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
900 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
901 Returns a pointer to the action
904 connect_action (PsppireDataWindow *dw, const char *action_name,
907 GtkAction *action = get_action_assert (dw->builder, action_name);
909 g_signal_connect_swapped (action, "activate", handler, dw);
914 /* Initializes as much of a PsppireDataWindow as we can and must before the
915 dataset has been set.
917 In particular, the 'menu' member is required in case the "filename" property
918 is set before the "dataset" property: otherwise PsppireWindow will try to
919 modify the menu as part of the "filename" property_set() function and end up
920 with a Gtk-CRITICAL since 'menu' is NULL. */
922 psppire_data_window_init (PsppireDataWindow *de)
926 de->builder = builder_new ("data-editor.ui");
928 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
930 PSPPIRE_WINDOW (de)->menu =
931 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
935 psppire_data_window_finish_init (PsppireDataWindow *de,
938 static const struct dataset_callbacks cbs =
940 set_unsaved, /* changed */
941 transformation_change_callback, /* transformations_changed */
950 GtkWidget *box = gtk_vbox_new (FALSE, 0);
953 dict = psppire_dict_new_from_dict (dataset_dict (ds));
954 de->var_store = psppire_var_store_new (dict);
955 de->data_store = psppire_data_store_new (dict);
956 psppire_data_store_set_reader (de->data_store, NULL);
958 menubar = get_widget_assert (de->builder, "menubar");
959 hb = get_widget_assert (de->builder, "handlebox1");
960 sb = get_widget_assert (de->builder, "status-bar");
963 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
966 g_signal_connect_swapped (de->data_store, "case-changed",
967 G_CALLBACK (set_unsaved), de);
969 g_signal_connect_swapped (de->data_store, "case-inserted",
970 G_CALLBACK (set_unsaved), de);
972 g_signal_connect_swapped (de->data_store, "cases-deleted",
973 G_CALLBACK (set_unsaved), de);
975 dataset_set_callbacks (de->dataset, &cbs, de);
977 connect_help (de->builder);
979 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
980 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
981 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
982 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
984 gtk_container_add (GTK_CONTAINER (de), box);
986 set_cut_copy_menuitem_sensitivity (de, FALSE);
988 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
989 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
992 set_paste_menuitem_sensitivity (de, FALSE);
994 g_signal_connect_swapped (de->data_editor, "data-available-changed",
995 G_CALLBACK (set_paste_menuitem_sensitivity), de);
997 g_signal_connect (dict, "weight-changed",
998 G_CALLBACK (on_weight_change),
1001 g_signal_connect (dict, "filter-changed",
1002 G_CALLBACK (on_filter_change),
1005 g_signal_connect (dict, "split-changed",
1006 G_CALLBACK (on_split_change),
1010 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1012 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1014 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1016 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1018 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1020 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1022 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1024 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1026 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1028 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1030 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1032 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1034 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1036 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1038 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1041 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1043 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1045 gtk_action_set_visible (de->delete_cases, FALSE);
1050 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1052 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1054 gtk_action_set_visible (de->delete_variables, FALSE);
1058 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1060 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1062 connect_action (de, "data_sort-cases", G_CALLBACK (sort_cases_dialog));
1064 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1066 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1068 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1070 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1072 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1075 connect_action (de, "utilities_variables", G_CALLBACK (variable_info_dialog));
1077 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1079 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1081 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1083 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1085 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1087 connect_action (de, "transform_rank", G_CALLBACK (rank_dialog));
1089 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1091 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1093 connect_action (de, "analyze_descriptives", G_CALLBACK (descriptives_dialog));
1095 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1097 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1099 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1101 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1103 connect_action (de, "reliability", G_CALLBACK (reliability_dialog));
1105 connect_action (de, "roc-curve", G_CALLBACK (roc_dialog));
1107 connect_action (de, "correlation", G_CALLBACK (correlation_dialog));
1109 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1111 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1113 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1115 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1119 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1121 GtkWidget *recent_data =
1122 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1124 GtkWidget *recent_files =
1125 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1128 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1129 gtk_recent_manager_get_default ());
1131 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1132 gtk_recent_manager_get_default ());
1135 GtkRecentFilter *filter = gtk_recent_filter_new ();
1137 gtk_recent_filter_add_pattern (filter, "*.sav");
1138 gtk_recent_filter_add_pattern (filter, "*.SAV");
1139 gtk_recent_filter_add_pattern (filter, "*.por");
1140 gtk_recent_filter_add_pattern (filter, "*.POR");
1142 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1144 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1147 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1150 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1153 GtkRecentFilter *filter = gtk_recent_filter_new ();
1155 gtk_recent_filter_add_pattern (filter, "*.sps");
1156 gtk_recent_filter_add_pattern (filter, "*.SPS");
1158 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1160 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1163 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1165 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1169 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1172 g_signal_connect (de->data_editor,
1174 G_CALLBACK (enable_delete_cases),
1177 g_signal_connect (de->data_editor,
1178 "variables-selected",
1179 G_CALLBACK (enable_delete_variables),
1183 g_signal_connect (de->data_editor,
1185 G_CALLBACK (on_switch_sheet), de);
1187 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1188 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1190 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1192 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1194 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1196 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1198 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1200 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1202 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1204 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1206 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1209 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1211 merge_help_menu (uim);
1215 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1216 "datasheet-cases-popup");
1218 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1219 "varsheet-variable-popup");
1221 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1222 "datasheet-variable-popup");
1224 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1225 G_CALLBACK (psppire_data_editor_sort_ascending),
1228 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1229 G_CALLBACK (psppire_data_editor_sort_descending),
1232 g_object_set (de->data_editor,
1233 "datasheet-column-menu", data_sheet_variable_popup_menu,
1234 "datasheet-row-menu", data_sheet_cases_popup_menu,
1235 "varsheet-row-menu", var_sheet_variable_popup_menu,
1239 gtk_widget_show (GTK_WIDGET (de->data_editor));
1240 gtk_widget_show (box);
1242 ll_push_head (&all_data_windows, &de->ll);
1246 psppire_data_window_dispose (GObject *object)
1248 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1250 if (dw->builder != NULL)
1252 g_object_unref (dw->builder);
1258 g_object_unref (dw->var_store);
1259 dw->var_store = NULL;
1264 g_object_unref (dw->data_store);
1265 dw->data_store = NULL;
1268 if (dw->ll.next != NULL)
1270 ll_remove (&dw->ll);
1274 if (G_OBJECT_CLASS (parent_class)->dispose)
1275 G_OBJECT_CLASS (parent_class)->dispose (object);
1279 psppire_data_window_set_property (GObject *object,
1281 const GValue *value,
1284 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1289 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1292 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1298 psppire_data_window_get_property (GObject *object,
1303 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1308 g_value_set_pointer (value, window->dataset);
1311 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1317 psppire_data_window_new (struct dataset *ds)
1321 if (the_session == NULL)
1322 the_session = session_create ();
1326 static int n_datasets;
1329 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1330 ds = dataset_create (the_session, dataset_name);
1331 free (dataset_name);
1333 assert (dataset_session (ds) == the_session);
1337 psppire_data_window_get_type (),
1338 /* TRANSLATORS: This will form a filename. Please avoid whitespace. */
1339 "description", _("Data Editor"),
1343 if (dataset_name (ds) != NULL)
1344 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1350 psppire_data_window_is_empty (PsppireDataWindow *dw)
1352 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1356 psppire_data_window_iface_init (PsppireWindowIface *iface)
1358 iface->save = save_file;
1359 iface->pick_filename = data_pick_filename;
1360 iface->load = load_file;
1364 psppire_default_data_window (void)
1366 if (ll_is_empty (&all_data_windows))
1367 create_data_window ();
1368 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1372 psppire_data_window_set_default (PsppireDataWindow *pdw)
1374 ll_remove (&pdw->ll);
1375 ll_push_head (&all_data_windows, &pdw->ll);
1379 psppire_data_window_undefault (PsppireDataWindow *pdw)
1381 ll_remove (&pdw->ll);
1382 ll_push_tail (&all_data_windows, &pdw->ll);
1386 psppire_data_window_for_dataset (struct dataset *ds)
1388 PsppireDataWindow *pdw;
1390 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1391 if (pdw->dataset == ds)
1398 create_data_window (void)
1400 gtk_widget_show (psppire_data_window_new (NULL));
1404 open_data_window (PsppireWindow *victim, const char *file_name)
1408 if (PSPPIRE_IS_DATA_WINDOW (victim)
1409 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1410 window = GTK_WIDGET (victim);
1412 window = psppire_data_window_new (NULL);
1414 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1415 gtk_widget_show (window);