1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012 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/builder-wrapper.h"
31 #include "ui/gui/chi-square-dialog.h"
32 #include "ui/gui/comments-dialog.h"
33 #include "ui/gui/compute-dialog.h"
34 #include "ui/gui/count-dialog.h"
35 #include "ui/gui/crosstabs-dialog.h"
36 #include "ui/gui/entry-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/helper.h"
45 #include "ui/gui/k-related-dialog.h"
46 #include "ui/gui/npar-two-sample-related.h"
47 #include "ui/gui/oneway-anova-dialog.h"
48 #include "ui/gui/psppire-data-window.h"
49 #include "ui/gui/psppire-syntax-window.h"
50 #include "ui/gui/psppire-window.h"
51 #include "ui/gui/psppire.h"
52 #include "ui/gui/runs-dialog.h"
53 #include "ui/gui/ks-one-sample-dialog.h"
54 #include "ui/gui/recode-dialog.h"
55 #include "ui/gui/regression-dialog.h"
56 #include "ui/gui/select-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/univariate-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");
389 add_most_recent (file_name, mime_type);
394 /* Save DE to file */
396 save_file (PsppireWindow *w)
398 const gchar *file_name = NULL;
399 gchar *utf8_file_name = NULL;
401 struct string filename ;
402 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
405 file_name = psppire_window_get_filename (w);
407 fnx = g_string_new (file_name);
409 if ( ! name_has_suffix (fnx->str))
411 if ( de->save_as_portable)
412 g_string_append (fnx, ".por");
414 g_string_append (fnx, ".sav");
417 ds_init_empty (&filename);
419 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
421 g_string_free (fnx, TRUE);
423 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
424 g_free (utf8_file_name);
426 syntax = g_strdup_printf ("%s OUTFILE=%s.",
427 de->save_as_portable ? "EXPORT" : "SAVE",
428 ds_cstr (&filename));
430 ds_destroy (&filename);
432 g_free (execute_syntax_string (de, syntax));
437 insert_case (PsppireDataWindow *dw)
439 psppire_data_editor_insert_case (dw->data_editor);
443 on_insert_variable (PsppireDataWindow *dw)
445 psppire_data_editor_insert_variable (dw->data_editor);
450 display_dict (PsppireDataWindow *de)
452 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
456 sysfile_info (PsppireDataWindow *de)
458 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
460 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
462 struct string filename;
464 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
466 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
471 ds_init_empty (&filename);
473 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
475 g_free (utf8_file_name);
477 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
478 g_free (execute_syntax_string (de, syntax));
481 gtk_widget_destroy (dialog);
485 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
487 data_pick_filename (PsppireWindow *window)
489 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
490 GtkFileFilter *filter = gtk_file_filter_new ();
491 GtkWidget *button_sys;
493 gtk_file_chooser_dialog_new (_("Save"),
495 GTK_FILE_CHOOSER_ACTION_SAVE,
496 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
497 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
500 g_object_set (dialog, "local-only", FALSE, NULL);
502 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
503 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
504 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
506 filter = gtk_file_filter_new ();
507 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
508 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
509 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
511 filter = gtk_file_filter_new ();
512 gtk_file_filter_set_name (filter, _("All Files"));
513 gtk_file_filter_add_pattern (filter, "*");
514 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
517 GtkWidget *button_por;
518 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
520 gtk_radio_button_new_with_label (NULL, _("System File"));
523 gtk_radio_button_new_with_label
524 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
527 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
528 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
530 gtk_widget_show_all (vbox);
532 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
535 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
538 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
540 case GTK_RESPONSE_ACCEPT:
545 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
548 de->save_as_portable =
549 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
551 if ( ! name_has_suffix (filename->str))
553 if ( de->save_as_portable)
554 g_string_append (filename, ".por");
556 g_string_append (filename, ".sav");
559 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
561 g_string_free (filename, TRUE);
568 gtk_widget_destroy (dialog);
572 confirm_delete_dataset (PsppireDataWindow *de,
573 const char *old_dataset,
574 const char *new_dataset,
575 const char *existing_dataset)
580 dialog = gtk_message_dialog_new (
581 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
582 _("Delete Existing Dataset?"));
584 gtk_message_dialog_format_secondary_text (
585 GTK_MESSAGE_DIALOG (dialog),
586 _("Renaming \"%s\" to \"%s\" will destroy the existing "
587 "dataset named \"%s\". Are you sure that you want to do this?"),
588 old_dataset, new_dataset, existing_dataset);
590 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
591 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
592 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
595 g_object_set (dialog, "icon-name", "pspp", NULL);
597 result = gtk_dialog_run (GTK_DIALOG (dialog));
599 gtk_widget_destroy (dialog);
601 return result == GTK_RESPONSE_OK;
605 on_rename_dataset (PsppireDataWindow *de)
607 struct dataset *ds = de->dataset;
608 struct session *session = dataset_session (ds);
609 const char *old_name = dataset_name (ds);
610 struct dataset *existing_dataset;
614 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
616 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
620 if (new_name == NULL)
623 existing_dataset = session_lookup_dataset (session, new_name);
624 if (existing_dataset == NULL || existing_dataset == ds
625 || confirm_delete_dataset (de, old_name, new_name,
626 dataset_name (existing_dataset)))
627 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
634 on_edit_paste (PsppireDataWindow *de)
636 psppire_data_editor_clip_paste (de->data_editor);
640 on_edit_copy (PsppireDataWindow *de)
642 psppire_data_editor_clip_copy (de->data_editor);
648 on_edit_cut (PsppireDataWindow *de)
650 psppire_data_editor_clip_cut (de->data_editor);
655 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
657 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
659 if ( gtk_toggle_action_get_active (action))
660 gtk_widget_show (statusbar);
662 gtk_widget_hide (statusbar);
667 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
669 const gboolean grid_visible = gtk_toggle_action_get_active (action);
671 psppire_data_editor_show_grid (de->data_editor, grid_visible);
675 data_view_activate (PsppireDataWindow *de)
677 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
682 variable_view_activate (PsppireDataWindow *de)
684 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
689 fonts_activate (PsppireDataWindow *de)
691 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
692 PangoFontDescription *current_font;
695 gtk_font_selection_dialog_new (_("Font Selection"));
698 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
699 font_name = pango_font_description_to_string (current_font);
701 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
705 gtk_window_set_transient_for (GTK_WINDOW (dialog),
706 GTK_WINDOW (toplevel));
708 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
710 const gchar *font = gtk_font_selection_dialog_get_font_name
711 (GTK_FONT_SELECTION_DIALOG (dialog));
713 PangoFontDescription* font_desc =
714 pango_font_description_from_string (font);
716 psppire_data_editor_set_font (de->data_editor, font_desc);
719 gtk_widget_hide (dialog);
724 /* Callback for the value labels action */
726 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
728 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
732 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
734 psppire_data_editor_split_window (de->data_editor,
735 gtk_toggle_action_get_active (ta));
740 file_quit (PsppireDataWindow *de)
742 /* FIXME: Need to be more intelligent here.
743 Give the user the opportunity to save any unsaved data.
750 on_recent_data_select (GtkMenuShell *menushell,
751 PsppireWindow *window)
756 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
758 file = g_filename_from_uri (uri, NULL, NULL);
762 open_data_window (window, file);
768 charset_from_mime_type (const char *mime_type)
774 if (mime_type == NULL)
777 charset = c_strcasestr (mime_type, "charset=");
785 /* Parse a "quoted-string" as defined by RFC 822. */
786 for (p++; *p != '\0' && *p != '"'; p++)
789 ds_put_byte (&s, *p);
790 else if (*++p != '\0')
791 ds_put_byte (&s, *p);
796 /* Parse a "token" as defined by RFC 2045. */
797 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
798 ds_put_byte (&s, *p++);
800 if (!ds_is_empty (&s))
801 return ds_steal_cstr (&s);
808 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
815 /* Get the file name and its encoding. */
816 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
817 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
818 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
819 gtk_recent_info_unref (item);
821 se = psppire_syntax_window_new (encoding);
825 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
826 gtk_widget_show (se);
828 gtk_widget_destroy (se);
836 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
838 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
840 gtk_action_set_visible (de->delete_cases, case_num != -1);
845 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
847 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
849 gtk_action_set_visible (de->delete_variables, var != -1);
852 /* Callback for when the datasheet/varsheet is selected */
854 on_switch_sheet (GtkNotebook *notebook,
855 GtkNotebookPage *page,
859 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
861 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
863 GtkWidget *view_data =
864 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
866 GtkWidget *view_variables =
867 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
871 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
872 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
874 gtk_action_set_sensitive (de->insert_variable, TRUE);
875 gtk_action_set_sensitive (de->insert_case, FALSE);
876 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
878 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
879 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
880 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
881 gtk_action_set_sensitive (de->insert_case, TRUE);
884 g_assert_not_reached ();
889 update_paste_menuitem (de, page_num);
896 set_unsaved (gpointer w)
898 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
902 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
903 Returns a pointer to the action
906 connect_action (PsppireDataWindow *dw, const char *action_name,
909 GtkAction *action = get_action_assert (dw->builder, action_name);
911 g_signal_connect_swapped (action, "activate", handler, dw);
916 /* Initializes as much of a PsppireDataWindow as we can and must before the
917 dataset has been set.
919 In particular, the 'menu' member is required in case the "filename" property
920 is set before the "dataset" property: otherwise PsppireWindow will try to
921 modify the menu as part of the "filename" property_set() function and end up
922 with a Gtk-CRITICAL since 'menu' is NULL. */
924 psppire_data_window_init (PsppireDataWindow *de)
928 de->builder = builder_new ("data-editor.ui");
930 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
932 PSPPIRE_WINDOW (de)->menu =
933 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
937 psppire_data_window_finish_init (PsppireDataWindow *de,
940 static const struct dataset_callbacks cbs =
942 set_unsaved, /* changed */
943 transformation_change_callback, /* transformations_changed */
952 GtkWidget *box = gtk_vbox_new (FALSE, 0);
955 dict = psppire_dict_new_from_dict (dataset_dict (ds));
956 de->var_store = psppire_var_store_new (dict);
957 de->data_store = psppire_data_store_new (dict);
958 psppire_data_store_set_reader (de->data_store, NULL);
960 menubar = get_widget_assert (de->builder, "menubar");
961 hb = get_widget_assert (de->builder, "handlebox1");
962 sb = get_widget_assert (de->builder, "status-bar");
965 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
968 g_signal_connect_swapped (de->data_store, "case-changed",
969 G_CALLBACK (set_unsaved), de);
971 g_signal_connect_swapped (de->data_store, "case-inserted",
972 G_CALLBACK (set_unsaved), de);
974 g_signal_connect_swapped (de->data_store, "cases-deleted",
975 G_CALLBACK (set_unsaved), de);
977 dataset_set_callbacks (de->dataset, &cbs, de);
979 connect_help (de->builder);
981 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
982 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
983 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
984 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
986 gtk_container_add (GTK_CONTAINER (de), box);
988 set_cut_copy_menuitem_sensitivity (de, FALSE);
990 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
991 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
994 set_paste_menuitem_sensitivity (de, FALSE);
996 g_signal_connect_swapped (de->data_editor, "data-available-changed",
997 G_CALLBACK (set_paste_menuitem_sensitivity), de);
999 g_signal_connect (dict, "weight-changed",
1000 G_CALLBACK (on_weight_change),
1003 g_signal_connect (dict, "filter-changed",
1004 G_CALLBACK (on_filter_change),
1007 g_signal_connect (dict, "split-changed",
1008 G_CALLBACK (on_split_change),
1012 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1014 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1016 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1018 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1020 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1022 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1024 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1026 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1028 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1030 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1032 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1034 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1036 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1038 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1040 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1043 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1045 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1047 gtk_action_set_visible (de->delete_cases, FALSE);
1052 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1054 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1056 gtk_action_set_visible (de->delete_variables, FALSE);
1060 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1062 connect_action (de, "data_select-cases", G_CALLBACK (select_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, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1070 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1072 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1074 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1076 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1078 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1080 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1082 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1084 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1086 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1088 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1090 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1092 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1094 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1095 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1097 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1099 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1101 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1102 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1103 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1104 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1105 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1106 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1110 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1112 GtkWidget *recent_data =
1113 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1115 GtkWidget *recent_files =
1116 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1119 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1120 gtk_recent_manager_get_default ());
1122 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1123 gtk_recent_manager_get_default ());
1125 g_object_set (menu_data, "show-tips", TRUE, NULL);
1126 g_object_set (menu_files, "show-tips", TRUE, NULL);
1129 GtkRecentFilter *filter = gtk_recent_filter_new ();
1131 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1132 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1134 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1136 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1139 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1142 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1145 GtkRecentFilter *filter = gtk_recent_filter_new ();
1147 gtk_recent_filter_add_pattern (filter, "*.sps");
1148 gtk_recent_filter_add_pattern (filter, "*.SPS");
1150 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1152 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1155 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1157 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1161 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1164 g_signal_connect (de->data_editor,
1166 G_CALLBACK (enable_delete_cases),
1169 g_signal_connect (de->data_editor,
1170 "variables-selected",
1171 G_CALLBACK (enable_delete_variables),
1175 g_signal_connect (de->data_editor,
1177 G_CALLBACK (on_switch_sheet), de);
1179 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1180 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1182 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1184 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1186 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1188 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1190 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1192 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1194 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1196 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1198 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1201 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1203 merge_help_menu (uim);
1207 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1208 "datasheet-cases-popup");
1210 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1211 "varsheet-variable-popup");
1213 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1214 "datasheet-variable-popup");
1216 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1217 G_CALLBACK (psppire_data_editor_sort_ascending),
1220 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1221 G_CALLBACK (psppire_data_editor_sort_descending),
1224 g_object_set (de->data_editor,
1225 "datasheet-column-menu", data_sheet_variable_popup_menu,
1226 "datasheet-row-menu", data_sheet_cases_popup_menu,
1227 "varsheet-row-menu", var_sheet_variable_popup_menu,
1231 gtk_widget_show (GTK_WIDGET (de->data_editor));
1232 gtk_widget_show (box);
1234 ll_push_head (&all_data_windows, &de->ll);
1238 psppire_data_window_dispose (GObject *object)
1240 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1242 if (dw->builder != NULL)
1244 g_object_unref (dw->builder);
1250 g_object_unref (dw->var_store);
1251 dw->var_store = NULL;
1256 g_object_unref (dw->data_store);
1257 dw->data_store = NULL;
1260 if (dw->ll.next != NULL)
1262 ll_remove (&dw->ll);
1266 if (G_OBJECT_CLASS (parent_class)->dispose)
1267 G_OBJECT_CLASS (parent_class)->dispose (object);
1271 psppire_data_window_set_property (GObject *object,
1273 const GValue *value,
1276 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1281 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1284 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1290 psppire_data_window_get_property (GObject *object,
1295 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1300 g_value_set_pointer (value, window->dataset);
1303 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1309 psppire_data_window_new (struct dataset *ds)
1313 if (the_session == NULL)
1314 the_session = session_create ();
1318 static int n_datasets;
1321 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1322 ds = dataset_create (the_session, dataset_name);
1323 free (dataset_name);
1325 assert (dataset_session (ds) == the_session);
1329 psppire_data_window_get_type (),
1330 "description", _("Data Editor"),
1334 if (dataset_name (ds) != NULL)
1335 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1341 psppire_data_window_is_empty (PsppireDataWindow *dw)
1343 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1347 psppire_data_window_iface_init (PsppireWindowIface *iface)
1349 iface->save = save_file;
1350 iface->pick_filename = data_pick_filename;
1351 iface->load = load_file;
1355 psppire_default_data_window (void)
1357 if (ll_is_empty (&all_data_windows))
1358 create_data_window ();
1359 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1363 psppire_data_window_set_default (PsppireDataWindow *pdw)
1365 ll_remove (&pdw->ll);
1366 ll_push_head (&all_data_windows, &pdw->ll);
1370 psppire_data_window_undefault (PsppireDataWindow *pdw)
1372 ll_remove (&pdw->ll);
1373 ll_push_tail (&all_data_windows, &pdw->ll);
1377 psppire_data_window_for_dataset (struct dataset *ds)
1379 PsppireDataWindow *pdw;
1381 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1382 if (pdw->dataset == ds)
1389 create_data_window (void)
1391 gtk_widget_show (psppire_data_window_new (NULL));
1395 open_data_window (PsppireWindow *victim, const char *file_name)
1399 if (PSPPIRE_IS_DATA_WINDOW (victim)
1400 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1401 window = GTK_WIDGET (victim);
1403 window = psppire_data_window_new (NULL);
1405 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1406 gtk_widget_show (window);