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/count-dialog.h"
34 #include "ui/gui/crosstabs-dialog.h"
35 #include "ui/gui/descriptives-dialog.h"
36 #include "ui/gui/entry-dialog.h"
37 #include "ui/gui/examine-dialog.h"
38 #include "ui/gui/executor.h"
39 #include "ui/gui/factor-dialog.h"
40 #include "ui/gui/find-dialog.h"
41 #include "ui/gui/frequencies-dialog.h"
42 #include "ui/gui/goto-case-dialog.h"
43 #include "ui/gui/help-menu.h"
44 #include "ui/gui/helper.h"
45 #include "ui/gui/k-related-dialog.h"
46 #include "ui/gui/oneway-anova-dialog.h"
47 #include "ui/gui/psppire-data-window.h"
48 #include "ui/gui/psppire-syntax-window.h"
49 #include "ui/gui/psppire-window.h"
50 #include "ui/gui/psppire.h"
51 #include "ui/gui/rank-dialog.h"
52 #include "ui/gui/recode-dialog.h"
53 #include "ui/gui/regression-dialog.h"
54 #include "ui/gui/reliability-dialog.h"
55 #include "ui/gui/roc-dialog.h"
56 #include "ui/gui/select-cases-dialog.h"
57 #include "ui/gui/sort-cases-dialog.h"
58 #include "ui/gui/split-file-dialog.h"
59 #include "ui/gui/t-test-independent-samples-dialog.h"
60 #include "ui/gui/t-test-one-sample.h"
61 #include "ui/gui/t-test-paired-samples.h"
62 #include "ui/gui/text-data-import-dialog.h"
63 #include "ui/gui/transpose-dialog.h"
64 #include "ui/gui/variable-info-dialog.h"
65 #include "ui/gui/weight-cases-dialog.h"
66 #include "ui/syntax-gen.h"
68 #include "gl/c-strcase.h"
69 #include "gl/c-strcasestr.h"
70 #include "gl/xvasprintf.h"
73 #define _(msgid) gettext (msgid)
74 #define N_(msgid) msgid
76 struct session *the_session;
77 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
79 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
80 static void psppire_data_window_init (PsppireDataWindow *data_editor);
83 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
85 static void psppire_data_window_dispose (GObject *object);
86 static void psppire_data_window_set_property (GObject *object,
90 static void psppire_data_window_get_property (GObject *object,
96 psppire_data_window_get_type (void)
98 static GType psppire_data_window_type = 0;
100 if (!psppire_data_window_type)
102 static const GTypeInfo psppire_data_window_info =
104 sizeof (PsppireDataWindowClass),
107 (GClassInitFunc)psppire_data_window_class_init,
108 (GClassFinalizeFunc) NULL,
110 sizeof (PsppireDataWindow),
112 (GInstanceInitFunc) psppire_data_window_init,
115 static const GInterfaceInfo window_interface_info =
117 (GInterfaceInitFunc) psppire_data_window_iface_init,
122 psppire_data_window_type =
123 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
124 &psppire_data_window_info, 0);
127 g_type_add_interface_static (psppire_data_window_type,
128 PSPPIRE_TYPE_WINDOW_MODEL,
129 &window_interface_info);
132 return psppire_data_window_type;
135 static GObjectClass *parent_class ;
142 psppire_data_window_class_init (PsppireDataWindowClass *class)
144 GObjectClass *object_class = G_OBJECT_CLASS (class);
146 parent_class = g_type_class_peek_parent (class);
148 object_class->dispose = psppire_data_window_dispose;
149 object_class->set_property = psppire_data_window_set_property;
150 object_class->get_property = psppire_data_window_get_property;
152 g_object_class_install_property (
153 object_class, PROP_DATASET,
154 g_param_spec_pointer ("dataset", "Dataset",
155 "'struct datset *' represented by the window",
156 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
160 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
162 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
164 gtk_action_set_sensitive (edit_paste, x);
168 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
170 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
171 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
173 gtk_action_set_sensitive (edit_copy, x);
174 gtk_action_set_sensitive (edit_cut, x);
177 /* Run the EXECUTE command. */
179 execute (PsppireDataWindow *dw)
181 execute_const_syntax_string (dw, "EXECUTE.");
185 transformation_change_callback (bool transformations_pending,
188 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
190 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
192 GtkWidget *menuitem =
193 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
195 GtkWidget *status_label =
196 get_widget_assert (de->builder, "case-counter-area");
198 gtk_widget_set_sensitive (menuitem, transformations_pending);
201 if ( transformations_pending)
202 gtk_label_set_text (GTK_LABEL (status_label),
203 _("Transformations Pending"));
205 gtk_label_set_text (GTK_LABEL (status_label), "");
208 /* Callback for when the dictionary changes its filter variable */
210 on_filter_change (GObject *o, gint filter_index, gpointer data)
212 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
214 GtkWidget *filter_status_area =
215 get_widget_assert (de->builder, "filter-use-status-area");
217 if ( filter_index == -1 )
219 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
223 PsppireVarStore *vs = NULL;
224 PsppireDict *dict = NULL;
225 struct variable *var ;
228 g_object_get (de->data_editor, "var-store", &vs, NULL);
229 g_object_get (vs, "dictionary", &dict, NULL);
231 var = psppire_dict_get_variable (dict, filter_index);
233 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
235 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
241 /* Callback for when the dictionary changes its split variables */
243 on_split_change (PsppireDict *dict, gpointer data)
245 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
247 size_t n_split_vars = dict_get_split_cnt (dict->dict);
249 GtkWidget *split_status_area =
250 get_widget_assert (de->builder, "split-file-status-area");
252 if ( n_split_vars == 0 )
254 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
260 const struct variable *const * split_vars =
261 dict_get_split_vars (dict->dict);
263 text = g_string_new (_("Split by "));
265 for (i = 0 ; i < n_split_vars - 1; ++i )
267 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
269 g_string_append (text, var_get_name (split_vars[i]));
271 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
273 g_string_free (text, TRUE);
280 /* Callback for when the dictionary changes its weights */
282 on_weight_change (GObject *o, gint weight_index, gpointer data)
284 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
286 GtkWidget *weight_status_area =
287 get_widget_assert (de->builder, "weight-status-area");
289 if ( weight_index == -1 )
291 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
295 struct variable *var ;
296 PsppireVarStore *vs = NULL;
297 PsppireDict *dict = NULL;
300 g_object_get (de->data_editor, "var-store", &vs, NULL);
301 g_object_get (vs, "dictionary", &dict, NULL);
303 var = psppire_dict_get_variable (dict, weight_index);
305 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
307 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
315 dump_rm (GtkRecentManager *rm)
317 GList *items = gtk_recent_manager_get_items (rm);
321 g_print ("Recent Items:\n");
322 for (i = items; i; i = i->next)
324 GtkRecentInfo *ri = i->data;
326 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
327 gtk_recent_info_get_short_name (ri),
328 gtk_recent_info_get_mime_type (ri),
329 gtk_recent_info_get_description (ri),
330 gtk_recent_info_get_uri (ri)
334 gtk_recent_info_unref (ri);
342 name_has_por_suffix (const gchar *name)
344 size_t length = strlen (name);
345 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
349 name_has_sav_suffix (const gchar *name)
351 size_t length = strlen (name);
352 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
355 /* Returns true if NAME has a suffix which might denote a PSPP file */
357 name_has_suffix (const gchar *name)
359 return name_has_por_suffix (name) || name_has_sav_suffix (name);
363 load_file (PsppireWindow *de, const gchar *file_name)
365 struct string filename;
366 gchar *utf8_file_name;
367 const char *mime_type;
371 ds_init_empty (&filename);
373 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
375 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
377 g_free (utf8_file_name);
379 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
380 ds_destroy (&filename);
382 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
383 lex_reader_for_string (syntax));
386 mime_type = (name_has_por_suffix (file_name)
387 ? "application/x-spss-por"
388 : "application/x-spss-sav");
389 add_most_recent (ds_cstr (&filename), 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 GtkWidget *button_sys;
492 gtk_file_chooser_dialog_new (_("Save"),
494 GTK_FILE_CHOOSER_ACTION_SAVE,
495 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
496 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
499 GtkFileFilter *filter = gtk_file_filter_new ();
500 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
501 gtk_file_filter_add_pattern (filter, "*.sav");
502 gtk_file_filter_add_pattern (filter, "*.SAV");
503 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
505 filter = gtk_file_filter_new ();
506 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
507 gtk_file_filter_add_pattern (filter, "*.por");
508 gtk_file_filter_add_pattern (filter, "*.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 delete 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", "psppicon", 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);
835 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
837 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
839 gtk_action_set_visible (de->delete_cases, case_num != -1);
844 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
846 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
848 gtk_action_set_visible (de->delete_variables, var != -1);
851 /* Callback for when the datasheet/varsheet is selected */
853 on_switch_sheet (GtkNotebook *notebook,
854 GtkNotebookPage *page,
858 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
860 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
862 GtkWidget *view_data =
863 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
865 GtkWidget *view_variables =
866 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
870 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
871 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
873 gtk_action_set_sensitive (de->insert_variable, TRUE);
874 gtk_action_set_sensitive (de->insert_case, FALSE);
875 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
877 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
878 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
879 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
880 gtk_action_set_sensitive (de->insert_case, TRUE);
883 g_assert_not_reached ();
888 update_paste_menuitem (de, page_num);
895 set_unsaved (gpointer w)
897 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
901 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
902 Returns a pointer to the action
905 connect_action (PsppireDataWindow *dw, const char *action_name,
908 GtkAction *action = get_action_assert (dw->builder, action_name);
910 g_signal_connect_swapped (action, "activate", handler, dw);
915 /* Initializes as much of a PsppireDataWindow as we can and must before the
916 dataset has been set.
918 In particular, the 'menu' member is required in case the "filename" property
919 is set before the "dataset" property: otherwise PsppireWindow will try to
920 modify the menu as part of the "filename" property_set() function and end up
921 with a Gtk-CRITICAL since 'menu' is NULL. */
923 psppire_data_window_init (PsppireDataWindow *de)
927 de->builder = builder_new ("data-editor.ui");
929 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
931 PSPPIRE_WINDOW (de)->menu =
932 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
936 psppire_data_window_finish_init (PsppireDataWindow *de,
939 static const struct dataset_callbacks cbs =
941 set_unsaved, /* changed */
942 transformation_change_callback, /* transformations_changed */
951 GtkWidget *box = gtk_vbox_new (FALSE, 0);
954 dict = psppire_dict_new_from_dict (dataset_dict (ds));
955 de->var_store = psppire_var_store_new (dict);
956 de->data_store = psppire_data_store_new (dict);
957 psppire_data_store_set_reader (de->data_store, NULL);
959 menubar = get_widget_assert (de->builder, "menubar");
960 hb = get_widget_assert (de->builder, "handlebox1");
961 sb = get_widget_assert (de->builder, "status-bar");
964 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
967 g_signal_connect_swapped (de->data_store, "case-changed",
968 G_CALLBACK (set_unsaved), de);
970 g_signal_connect_swapped (de->data_store, "case-inserted",
971 G_CALLBACK (set_unsaved), de);
973 g_signal_connect_swapped (de->data_store, "cases-deleted",
974 G_CALLBACK (set_unsaved), de);
976 dataset_set_callbacks (de->dataset, &cbs, de);
978 connect_help (de->builder);
980 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
981 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
982 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
983 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
985 gtk_container_add (GTK_CONTAINER (de), box);
987 set_cut_copy_menuitem_sensitivity (de, FALSE);
989 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
990 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
993 set_paste_menuitem_sensitivity (de, FALSE);
995 g_signal_connect_swapped (de->data_editor, "data-available-changed",
996 G_CALLBACK (set_paste_menuitem_sensitivity), de);
998 g_signal_connect (dict, "weight-changed",
999 G_CALLBACK (on_weight_change),
1002 g_signal_connect (dict, "filter-changed",
1003 G_CALLBACK (on_filter_change),
1006 g_signal_connect (dict, "split-changed",
1007 G_CALLBACK (on_split_change),
1011 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1013 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1015 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1017 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1019 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1021 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1023 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1025 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1027 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1029 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1031 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1033 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1035 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1037 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1039 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1042 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1044 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1046 gtk_action_set_visible (de->delete_cases, FALSE);
1051 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1053 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1055 gtk_action_set_visible (de->delete_variables, FALSE);
1059 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1061 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1063 connect_action (de, "data_sort-cases", G_CALLBACK (sort_cases_dialog));
1065 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1067 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1069 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1071 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1073 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1076 connect_action (de, "utilities_variables", G_CALLBACK (variable_info_dialog));
1078 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1080 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1082 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1084 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1086 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1088 connect_action (de, "transform_rank", G_CALLBACK (rank_dialog));
1090 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1092 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1094 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1096 connect_action (de, "analyze_descriptives", G_CALLBACK (descriptives_dialog));
1098 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1100 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1102 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1104 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1106 connect_action (de, "reliability", G_CALLBACK (reliability_dialog));
1108 connect_action (de, "roc-curve", G_CALLBACK (roc_dialog));
1110 connect_action (de, "correlation", G_CALLBACK (correlation_dialog));
1112 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1114 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1116 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1118 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1122 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1124 GtkWidget *recent_data =
1125 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1127 GtkWidget *recent_files =
1128 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1131 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1132 gtk_recent_manager_get_default ());
1134 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1135 gtk_recent_manager_get_default ());
1137 g_object_set (menu_data, "show-tips", TRUE, NULL);
1138 g_object_set (menu_files, "show-tips", TRUE, NULL);
1141 GtkRecentFilter *filter = gtk_recent_filter_new ();
1143 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1144 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1146 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1148 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1151 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1154 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1157 GtkRecentFilter *filter = gtk_recent_filter_new ();
1159 gtk_recent_filter_add_pattern (filter, "*.sps");
1160 gtk_recent_filter_add_pattern (filter, "*.SPS");
1162 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1164 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1167 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1169 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1173 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1176 g_signal_connect (de->data_editor,
1178 G_CALLBACK (enable_delete_cases),
1181 g_signal_connect (de->data_editor,
1182 "variables-selected",
1183 G_CALLBACK (enable_delete_variables),
1187 g_signal_connect (de->data_editor,
1189 G_CALLBACK (on_switch_sheet), de);
1191 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1192 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1194 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1196 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1198 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1200 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1202 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1204 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1206 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1208 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1210 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1213 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1215 merge_help_menu (uim);
1219 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1220 "datasheet-cases-popup");
1222 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1223 "varsheet-variable-popup");
1225 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1226 "datasheet-variable-popup");
1228 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1229 G_CALLBACK (psppire_data_editor_sort_ascending),
1232 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1233 G_CALLBACK (psppire_data_editor_sort_descending),
1236 g_object_set (de->data_editor,
1237 "datasheet-column-menu", data_sheet_variable_popup_menu,
1238 "datasheet-row-menu", data_sheet_cases_popup_menu,
1239 "varsheet-row-menu", var_sheet_variable_popup_menu,
1243 gtk_widget_show (GTK_WIDGET (de->data_editor));
1244 gtk_widget_show (box);
1246 ll_push_head (&all_data_windows, &de->ll);
1250 psppire_data_window_dispose (GObject *object)
1252 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1254 if (dw->builder != NULL)
1256 g_object_unref (dw->builder);
1262 g_object_unref (dw->var_store);
1263 dw->var_store = NULL;
1268 g_object_unref (dw->data_store);
1269 dw->data_store = NULL;
1272 if (dw->ll.next != NULL)
1274 ll_remove (&dw->ll);
1278 if (G_OBJECT_CLASS (parent_class)->dispose)
1279 G_OBJECT_CLASS (parent_class)->dispose (object);
1283 psppire_data_window_set_property (GObject *object,
1285 const GValue *value,
1288 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1293 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1296 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1302 psppire_data_window_get_property (GObject *object,
1307 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1312 g_value_set_pointer (value, window->dataset);
1315 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1321 psppire_data_window_new (struct dataset *ds)
1325 if (the_session == NULL)
1326 the_session = session_create ();
1330 static int n_datasets;
1333 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1334 ds = dataset_create (the_session, dataset_name);
1335 free (dataset_name);
1337 assert (dataset_session (ds) == the_session);
1341 psppire_data_window_get_type (),
1342 /* TRANSLATORS: This will form a filename. Please avoid whitespace. */
1343 "description", _("Data Editor"),
1347 if (dataset_name (ds) != NULL)
1348 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1354 psppire_data_window_is_empty (PsppireDataWindow *dw)
1356 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1360 psppire_data_window_iface_init (PsppireWindowIface *iface)
1362 iface->save = save_file;
1363 iface->pick_filename = data_pick_filename;
1364 iface->load = load_file;
1368 psppire_default_data_window (void)
1370 if (ll_is_empty (&all_data_windows))
1371 create_data_window ();
1372 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1376 psppire_data_window_set_default (PsppireDataWindow *pdw)
1378 ll_remove (&pdw->ll);
1379 ll_push_head (&all_data_windows, &pdw->ll);
1383 psppire_data_window_undefault (PsppireDataWindow *pdw)
1385 ll_remove (&pdw->ll);
1386 ll_push_tail (&all_data_windows, &pdw->ll);
1390 psppire_data_window_for_dataset (struct dataset *ds)
1392 PsppireDataWindow *pdw;
1394 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1395 if (pdw->dataset == ds)
1402 create_data_window (void)
1404 gtk_widget_show (psppire_data_window_new (NULL));
1408 open_data_window (PsppireWindow *victim, const char *file_name)
1412 if (PSPPIRE_IS_DATA_WINDOW (victim)
1413 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1414 window = GTK_WIDGET (victim);
1416 window = psppire_data_window_new (NULL);
1418 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1419 gtk_widget_show (window);