1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/binomial-dialog.h"
30 #include "ui/gui/chi-square-dialog.h"
31 #include "ui/gui/comments-dialog.h"
32 #include "ui/gui/compute-dialog.h"
33 #include "ui/gui/correlation-dialog.h"
34 #include "ui/gui/count-dialog.h"
35 #include "ui/gui/crosstabs-dialog.h"
36 #include "ui/gui/descriptives-dialog.h"
37 #include "ui/gui/entry-dialog.h"
38 #include "ui/gui/examine-dialog.h"
39 #include "ui/gui/executor.h"
40 #include "ui/gui/factor-dialog.h"
41 #include "ui/gui/find-dialog.h"
42 #include "ui/gui/frequencies-dialog.h"
43 #include "ui/gui/goto-case-dialog.h"
44 #include "ui/gui/help-menu.h"
45 #include "ui/gui/helper.h"
46 #include "ui/gui/k-means-dialog.h"
47 #include "ui/gui/k-related-dialog.h"
48 #include "ui/gui/npar-two-sample-related.h"
49 #include "ui/gui/oneway-anova-dialog.h"
50 #include "ui/gui/psppire-data-window.h"
51 #include "ui/gui/psppire-syntax-window.h"
52 #include "ui/gui/psppire-window.h"
53 #include "ui/gui/psppire.h"
54 #include "ui/gui/rank-dialog.h"
55 #include "ui/gui/runs-dialog.h"
56 #include "ui/gui/recode-dialog.h"
57 #include "ui/gui/regression-dialog.h"
58 #include "ui/gui/reliability-dialog.h"
59 #include "ui/gui/roc-dialog.h"
60 #include "ui/gui/select-cases-dialog.h"
61 #include "ui/gui/sort-cases-dialog.h"
62 #include "ui/gui/split-file-dialog.h"
63 #include "ui/gui/t-test-independent-samples-dialog.h"
64 #include "ui/gui/t-test-one-sample.h"
65 #include "ui/gui/t-test-paired-samples.h"
66 #include "ui/gui/text-data-import-dialog.h"
67 #include "ui/gui/transpose-dialog.h"
68 #include "ui/gui/variable-info-dialog.h"
69 #include "ui/gui/weight-cases-dialog.h"
70 #include "ui/syntax-gen.h"
72 #include "gl/c-strcase.h"
73 #include "gl/c-strcasestr.h"
74 #include "gl/xvasprintf.h"
77 #define _(msgid) gettext (msgid)
78 #define N_(msgid) msgid
80 struct session *the_session;
81 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
83 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
84 static void psppire_data_window_init (PsppireDataWindow *data_editor);
87 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
89 static void psppire_data_window_dispose (GObject *object);
90 static void psppire_data_window_set_property (GObject *object,
94 static void psppire_data_window_get_property (GObject *object,
100 psppire_data_window_get_type (void)
102 static GType psppire_data_window_type = 0;
104 if (!psppire_data_window_type)
106 static const GTypeInfo psppire_data_window_info =
108 sizeof (PsppireDataWindowClass),
111 (GClassInitFunc)psppire_data_window_class_init,
112 (GClassFinalizeFunc) NULL,
114 sizeof (PsppireDataWindow),
116 (GInstanceInitFunc) psppire_data_window_init,
119 static const GInterfaceInfo window_interface_info =
121 (GInterfaceInitFunc) psppire_data_window_iface_init,
126 psppire_data_window_type =
127 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
128 &psppire_data_window_info, 0);
131 g_type_add_interface_static (psppire_data_window_type,
132 PSPPIRE_TYPE_WINDOW_MODEL,
133 &window_interface_info);
136 return psppire_data_window_type;
139 static GObjectClass *parent_class ;
146 psppire_data_window_class_init (PsppireDataWindowClass *class)
148 GObjectClass *object_class = G_OBJECT_CLASS (class);
150 parent_class = g_type_class_peek_parent (class);
152 object_class->dispose = psppire_data_window_dispose;
153 object_class->set_property = psppire_data_window_set_property;
154 object_class->get_property = psppire_data_window_get_property;
156 g_object_class_install_property (
157 object_class, PROP_DATASET,
158 g_param_spec_pointer ("dataset", "Dataset",
159 "'struct datset *' represented by the window",
160 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
164 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
166 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
168 gtk_action_set_sensitive (edit_paste, x);
172 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
174 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
175 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
177 gtk_action_set_sensitive (edit_copy, x);
178 gtk_action_set_sensitive (edit_cut, x);
181 /* Run the EXECUTE command. */
183 execute (PsppireDataWindow *dw)
185 execute_const_syntax_string (dw, "EXECUTE.");
189 transformation_change_callback (bool transformations_pending,
192 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
194 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
196 GtkWidget *menuitem =
197 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
199 GtkWidget *status_label =
200 get_widget_assert (de->builder, "case-counter-area");
202 gtk_widget_set_sensitive (menuitem, transformations_pending);
205 if ( transformations_pending)
206 gtk_label_set_text (GTK_LABEL (status_label),
207 _("Transformations Pending"));
209 gtk_label_set_text (GTK_LABEL (status_label), "");
212 /* Callback for when the dictionary changes its filter variable */
214 on_filter_change (GObject *o, gint filter_index, gpointer data)
216 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
218 GtkWidget *filter_status_area =
219 get_widget_assert (de->builder, "filter-use-status-area");
221 if ( filter_index == -1 )
223 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
227 PsppireVarStore *vs = NULL;
228 PsppireDict *dict = NULL;
229 struct variable *var ;
232 g_object_get (de->data_editor, "var-store", &vs, NULL);
233 g_object_get (vs, "dictionary", &dict, NULL);
235 var = psppire_dict_get_variable (dict, filter_index);
237 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
239 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
245 /* Callback for when the dictionary changes its split variables */
247 on_split_change (PsppireDict *dict, gpointer data)
249 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
251 size_t n_split_vars = dict_get_split_cnt (dict->dict);
253 GtkWidget *split_status_area =
254 get_widget_assert (de->builder, "split-file-status-area");
256 if ( n_split_vars == 0 )
258 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
264 const struct variable *const * split_vars =
265 dict_get_split_vars (dict->dict);
267 text = g_string_new (_("Split by "));
269 for (i = 0 ; i < n_split_vars - 1; ++i )
271 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
273 g_string_append (text, var_get_name (split_vars[i]));
275 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
277 g_string_free (text, TRUE);
284 /* Callback for when the dictionary changes its weights */
286 on_weight_change (GObject *o, gint weight_index, gpointer data)
288 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
290 GtkWidget *weight_status_area =
291 get_widget_assert (de->builder, "weight-status-area");
293 if ( weight_index == -1 )
295 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
299 struct variable *var ;
300 PsppireVarStore *vs = NULL;
301 PsppireDict *dict = NULL;
304 g_object_get (de->data_editor, "var-store", &vs, NULL);
305 g_object_get (vs, "dictionary", &dict, NULL);
307 var = psppire_dict_get_variable (dict, weight_index);
309 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
311 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
319 dump_rm (GtkRecentManager *rm)
321 GList *items = gtk_recent_manager_get_items (rm);
325 g_print ("Recent Items:\n");
326 for (i = items; i; i = i->next)
328 GtkRecentInfo *ri = i->data;
330 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
331 gtk_recent_info_get_short_name (ri),
332 gtk_recent_info_get_mime_type (ri),
333 gtk_recent_info_get_description (ri),
334 gtk_recent_info_get_uri (ri)
338 gtk_recent_info_unref (ri);
346 name_has_por_suffix (const gchar *name)
348 size_t length = strlen (name);
349 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
353 name_has_sav_suffix (const gchar *name)
355 size_t length = strlen (name);
356 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
359 /* Returns true if NAME has a suffix which might denote a PSPP file */
361 name_has_suffix (const gchar *name)
363 return name_has_por_suffix (name) || name_has_sav_suffix (name);
367 load_file (PsppireWindow *de, const gchar *file_name)
369 struct string filename;
370 gchar *utf8_file_name;
371 const char *mime_type;
375 ds_init_empty (&filename);
377 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
379 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
381 g_free (utf8_file_name);
383 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
384 ds_destroy (&filename);
386 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
387 lex_reader_for_string (syntax));
390 mime_type = (name_has_por_suffix (file_name)
391 ? "application/x-spss-por"
392 : "application/x-spss-sav");
394 add_most_recent (file_name, mime_type);
399 /* Save DE to file */
401 save_file (PsppireWindow *w)
403 const gchar *file_name = NULL;
404 gchar *utf8_file_name = NULL;
406 struct string filename ;
407 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
410 file_name = psppire_window_get_filename (w);
412 fnx = g_string_new (file_name);
414 if ( ! name_has_suffix (fnx->str))
416 if ( de->save_as_portable)
417 g_string_append (fnx, ".por");
419 g_string_append (fnx, ".sav");
422 ds_init_empty (&filename);
424 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
426 g_string_free (fnx, TRUE);
428 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
429 g_free (utf8_file_name);
431 syntax = g_strdup_printf ("%s OUTFILE=%s.",
432 de->save_as_portable ? "EXPORT" : "SAVE",
433 ds_cstr (&filename));
435 ds_destroy (&filename);
437 g_free (execute_syntax_string (de, syntax));
442 insert_case (PsppireDataWindow *dw)
444 psppire_data_editor_insert_case (dw->data_editor);
448 on_insert_variable (PsppireDataWindow *dw)
450 psppire_data_editor_insert_variable (dw->data_editor);
455 display_dict (PsppireDataWindow *de)
457 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
461 sysfile_info (PsppireDataWindow *de)
463 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
465 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
467 struct string filename;
469 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
471 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
476 ds_init_empty (&filename);
478 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
480 g_free (utf8_file_name);
482 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
483 g_free (execute_syntax_string (de, syntax));
486 gtk_widget_destroy (dialog);
490 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
492 data_pick_filename (PsppireWindow *window)
494 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
495 GtkFileFilter *filter = gtk_file_filter_new ();
496 GtkWidget *button_sys;
498 gtk_file_chooser_dialog_new (_("Save"),
500 GTK_FILE_CHOOSER_ACTION_SAVE,
501 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
502 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
505 g_object_set (dialog, "local-only", FALSE, NULL);
507 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
508 gtk_file_filter_add_pattern (filter, "*.sav");
509 gtk_file_filter_add_pattern (filter, "*.SAV");
510 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
512 filter = gtk_file_filter_new ();
513 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
514 gtk_file_filter_add_pattern (filter, "*.por");
515 gtk_file_filter_add_pattern (filter, "*.POR");
516 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
518 filter = gtk_file_filter_new ();
519 gtk_file_filter_set_name (filter, _("All Files"));
520 gtk_file_filter_add_pattern (filter, "*");
521 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
524 GtkWidget *button_por;
525 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
527 gtk_radio_button_new_with_label (NULL, _("System File"));
530 gtk_radio_button_new_with_label
531 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
534 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
535 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
537 gtk_widget_show_all (vbox);
539 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
542 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
545 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
547 case GTK_RESPONSE_ACCEPT:
552 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
555 de->save_as_portable =
556 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
558 if ( ! name_has_suffix (filename->str))
560 if ( de->save_as_portable)
561 g_string_append (filename, ".por");
563 g_string_append (filename, ".sav");
566 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
568 g_string_free (filename, TRUE);
575 gtk_widget_destroy (dialog);
579 confirm_delete_dataset (PsppireDataWindow *de,
580 const char *old_dataset,
581 const char *new_dataset,
582 const char *existing_dataset)
587 dialog = gtk_message_dialog_new (
588 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
589 _("Delete Existing Dataset?"));
591 gtk_message_dialog_format_secondary_text (
592 GTK_MESSAGE_DIALOG (dialog),
593 _("Renaming \"%s\" to \"%s\" will delete destroy the existing "
594 "dataset named \"%s\". Are you sure that you want to do this?"),
595 old_dataset, new_dataset, existing_dataset);
597 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
598 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
599 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
602 g_object_set (dialog, "icon-name", "psppicon", NULL);
604 result = gtk_dialog_run (GTK_DIALOG (dialog));
606 gtk_widget_destroy (dialog);
608 return result == GTK_RESPONSE_OK;
612 on_rename_dataset (PsppireDataWindow *de)
614 struct dataset *ds = de->dataset;
615 struct session *session = dataset_session (ds);
616 const char *old_name = dataset_name (ds);
617 struct dataset *existing_dataset;
621 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
623 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
627 if (new_name == NULL)
630 existing_dataset = session_lookup_dataset (session, new_name);
631 if (existing_dataset == NULL || existing_dataset == ds
632 || confirm_delete_dataset (de, old_name, new_name,
633 dataset_name (existing_dataset)))
634 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
641 on_edit_paste (PsppireDataWindow *de)
643 psppire_data_editor_clip_paste (de->data_editor);
647 on_edit_copy (PsppireDataWindow *de)
649 psppire_data_editor_clip_copy (de->data_editor);
655 on_edit_cut (PsppireDataWindow *de)
657 psppire_data_editor_clip_cut (de->data_editor);
662 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
664 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
666 if ( gtk_toggle_action_get_active (action))
667 gtk_widget_show (statusbar);
669 gtk_widget_hide (statusbar);
674 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
676 const gboolean grid_visible = gtk_toggle_action_get_active (action);
678 psppire_data_editor_show_grid (de->data_editor, grid_visible);
682 data_view_activate (PsppireDataWindow *de)
684 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
689 variable_view_activate (PsppireDataWindow *de)
691 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
696 fonts_activate (PsppireDataWindow *de)
698 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
699 PangoFontDescription *current_font;
702 gtk_font_selection_dialog_new (_("Font Selection"));
705 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
706 font_name = pango_font_description_to_string (current_font);
708 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
712 gtk_window_set_transient_for (GTK_WINDOW (dialog),
713 GTK_WINDOW (toplevel));
715 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
717 const gchar *font = gtk_font_selection_dialog_get_font_name
718 (GTK_FONT_SELECTION_DIALOG (dialog));
720 PangoFontDescription* font_desc =
721 pango_font_description_from_string (font);
723 psppire_data_editor_set_font (de->data_editor, font_desc);
726 gtk_widget_hide (dialog);
731 /* Callback for the value labels action */
733 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
735 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
739 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
741 psppire_data_editor_split_window (de->data_editor,
742 gtk_toggle_action_get_active (ta));
747 file_quit (PsppireDataWindow *de)
749 /* FIXME: Need to be more intelligent here.
750 Give the user the opportunity to save any unsaved data.
757 on_recent_data_select (GtkMenuShell *menushell,
758 PsppireWindow *window)
763 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
765 file = g_filename_from_uri (uri, NULL, NULL);
769 open_data_window (window, file);
775 charset_from_mime_type (const char *mime_type)
781 if (mime_type == NULL)
784 charset = c_strcasestr (mime_type, "charset=");
792 /* Parse a "quoted-string" as defined by RFC 822. */
793 for (p++; *p != '\0' && *p != '"'; p++)
796 ds_put_byte (&s, *p);
797 else if (*++p != '\0')
798 ds_put_byte (&s, *p);
803 /* Parse a "token" as defined by RFC 2045. */
804 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
805 ds_put_byte (&s, *p++);
807 if (!ds_is_empty (&s))
808 return ds_steal_cstr (&s);
815 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
822 /* Get the file name and its encoding. */
823 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
824 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
825 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
826 gtk_recent_info_unref (item);
828 se = psppire_syntax_window_new (encoding);
832 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
833 gtk_widget_show (se);
835 gtk_widget_destroy (se);
842 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
844 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
846 gtk_action_set_visible (de->delete_cases, case_num != -1);
851 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
853 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
855 gtk_action_set_visible (de->delete_variables, var != -1);
858 /* Callback for when the datasheet/varsheet is selected */
860 on_switch_sheet (GtkNotebook *notebook,
861 GtkNotebookPage *page,
865 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
867 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
869 GtkWidget *view_data =
870 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
872 GtkWidget *view_variables =
873 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
877 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
878 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
880 gtk_action_set_sensitive (de->insert_variable, TRUE);
881 gtk_action_set_sensitive (de->insert_case, FALSE);
882 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
884 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
885 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
886 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
887 gtk_action_set_sensitive (de->insert_case, TRUE);
890 g_assert_not_reached ();
895 update_paste_menuitem (de, page_num);
902 set_unsaved (gpointer w)
904 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
908 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
909 Returns a pointer to the action
912 connect_action (PsppireDataWindow *dw, const char *action_name,
915 GtkAction *action = get_action_assert (dw->builder, action_name);
917 g_signal_connect_swapped (action, "activate", handler, dw);
922 /* Initializes as much of a PsppireDataWindow as we can and must before the
923 dataset has been set.
925 In particular, the 'menu' member is required in case the "filename" property
926 is set before the "dataset" property: otherwise PsppireWindow will try to
927 modify the menu as part of the "filename" property_set() function and end up
928 with a Gtk-CRITICAL since 'menu' is NULL. */
930 psppire_data_window_init (PsppireDataWindow *de)
934 de->builder = builder_new ("data-editor.ui");
936 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
938 PSPPIRE_WINDOW (de)->menu =
939 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
943 psppire_data_window_finish_init (PsppireDataWindow *de,
946 static const struct dataset_callbacks cbs =
948 set_unsaved, /* changed */
949 transformation_change_callback, /* transformations_changed */
958 GtkWidget *box = gtk_vbox_new (FALSE, 0);
961 dict = psppire_dict_new_from_dict (dataset_dict (ds));
962 de->var_store = psppire_var_store_new (dict);
963 de->data_store = psppire_data_store_new (dict);
964 psppire_data_store_set_reader (de->data_store, NULL);
966 menubar = get_widget_assert (de->builder, "menubar");
967 hb = get_widget_assert (de->builder, "handlebox1");
968 sb = get_widget_assert (de->builder, "status-bar");
971 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
974 g_signal_connect_swapped (de->data_store, "case-changed",
975 G_CALLBACK (set_unsaved), de);
977 g_signal_connect_swapped (de->data_store, "case-inserted",
978 G_CALLBACK (set_unsaved), de);
980 g_signal_connect_swapped (de->data_store, "cases-deleted",
981 G_CALLBACK (set_unsaved), de);
983 dataset_set_callbacks (de->dataset, &cbs, de);
985 connect_help (de->builder);
987 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
988 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
989 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
990 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
992 gtk_container_add (GTK_CONTAINER (de), box);
994 set_cut_copy_menuitem_sensitivity (de, FALSE);
996 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
997 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
1000 set_paste_menuitem_sensitivity (de, FALSE);
1002 g_signal_connect_swapped (de->data_editor, "data-available-changed",
1003 G_CALLBACK (set_paste_menuitem_sensitivity), de);
1005 g_signal_connect (dict, "weight-changed",
1006 G_CALLBACK (on_weight_change),
1009 g_signal_connect (dict, "filter-changed",
1010 G_CALLBACK (on_filter_change),
1013 g_signal_connect (dict, "split-changed",
1014 G_CALLBACK (on_split_change),
1018 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1020 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1022 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1024 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1026 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1028 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1030 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1032 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1034 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1036 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1038 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1040 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1042 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1044 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1046 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1049 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1051 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1053 gtk_action_set_visible (de->delete_cases, FALSE);
1058 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1060 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1062 gtk_action_set_visible (de->delete_variables, FALSE);
1066 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1068 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1070 connect_action (de, "data_sort-cases", G_CALLBACK (sort_cases_dialog));
1072 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1074 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1076 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1078 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1080 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1082 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1085 connect_action (de, "utilities_variables", G_CALLBACK (variable_info_dialog));
1087 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1089 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1091 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1093 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1095 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1097 connect_action (de, "transform_rank", G_CALLBACK (rank_dialog));
1099 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1101 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1103 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1105 connect_action (de, "analyze_descriptives", G_CALLBACK (descriptives_dialog));
1107 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1109 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1111 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1113 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1115 connect_action (de, "reliability", G_CALLBACK (reliability_dialog));
1117 connect_action (de, "roc-curve", G_CALLBACK (roc_dialog));
1119 connect_action (de, "correlation", G_CALLBACK (correlation_dialog));
1121 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1123 connect_action (de, "k-means", G_CALLBACK (k_means_dialog));
1125 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1126 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1127 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1128 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1129 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1133 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1135 GtkWidget *recent_data =
1136 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1138 GtkWidget *recent_files =
1139 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1142 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1143 gtk_recent_manager_get_default ());
1145 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1146 gtk_recent_manager_get_default ());
1148 g_object_set (menu_data, "show-tips", TRUE, NULL);
1149 g_object_set (menu_files, "show-tips", TRUE, NULL);
1152 GtkRecentFilter *filter = gtk_recent_filter_new ();
1154 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1155 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1157 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1159 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1162 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1165 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1168 GtkRecentFilter *filter = gtk_recent_filter_new ();
1170 gtk_recent_filter_add_pattern (filter, "*.sps");
1171 gtk_recent_filter_add_pattern (filter, "*.SPS");
1173 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1175 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1178 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1180 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1184 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1187 g_signal_connect (de->data_editor,
1189 G_CALLBACK (enable_delete_cases),
1192 g_signal_connect (de->data_editor,
1193 "variables-selected",
1194 G_CALLBACK (enable_delete_variables),
1198 g_signal_connect (de->data_editor,
1200 G_CALLBACK (on_switch_sheet), de);
1202 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1203 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1205 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1207 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1209 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1211 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1213 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1215 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1217 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1219 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1221 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1224 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1226 merge_help_menu (uim);
1230 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1231 "datasheet-cases-popup");
1233 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1234 "varsheet-variable-popup");
1236 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1237 "datasheet-variable-popup");
1239 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1240 G_CALLBACK (psppire_data_editor_sort_ascending),
1243 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1244 G_CALLBACK (psppire_data_editor_sort_descending),
1247 g_object_set (de->data_editor,
1248 "datasheet-column-menu", data_sheet_variable_popup_menu,
1249 "datasheet-row-menu", data_sheet_cases_popup_menu,
1250 "varsheet-row-menu", var_sheet_variable_popup_menu,
1254 gtk_widget_show (GTK_WIDGET (de->data_editor));
1255 gtk_widget_show (box);
1257 ll_push_head (&all_data_windows, &de->ll);
1261 psppire_data_window_dispose (GObject *object)
1263 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1265 if (dw->builder != NULL)
1267 g_object_unref (dw->builder);
1273 g_object_unref (dw->var_store);
1274 dw->var_store = NULL;
1279 g_object_unref (dw->data_store);
1280 dw->data_store = NULL;
1283 if (dw->ll.next != NULL)
1285 ll_remove (&dw->ll);
1289 if (G_OBJECT_CLASS (parent_class)->dispose)
1290 G_OBJECT_CLASS (parent_class)->dispose (object);
1294 psppire_data_window_set_property (GObject *object,
1296 const GValue *value,
1299 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1304 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1313 psppire_data_window_get_property (GObject *object,
1318 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1323 g_value_set_pointer (value, window->dataset);
1326 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1332 psppire_data_window_new (struct dataset *ds)
1336 if (the_session == NULL)
1337 the_session = session_create ();
1341 static int n_datasets;
1344 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1345 ds = dataset_create (the_session, dataset_name);
1346 free (dataset_name);
1348 assert (dataset_session (ds) == the_session);
1352 psppire_data_window_get_type (),
1353 /* TRANSLATORS: This will form a filename. Please avoid whitespace. */
1354 "description", _("Data Editor"),
1358 if (dataset_name (ds) != NULL)
1359 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1365 psppire_data_window_is_empty (PsppireDataWindow *dw)
1367 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1371 psppire_data_window_iface_init (PsppireWindowIface *iface)
1373 iface->save = save_file;
1374 iface->pick_filename = data_pick_filename;
1375 iface->load = load_file;
1379 psppire_default_data_window (void)
1381 if (ll_is_empty (&all_data_windows))
1382 create_data_window ();
1383 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1387 psppire_data_window_set_default (PsppireDataWindow *pdw)
1389 ll_remove (&pdw->ll);
1390 ll_push_head (&all_data_windows, &pdw->ll);
1394 psppire_data_window_undefault (PsppireDataWindow *pdw)
1396 ll_remove (&pdw->ll);
1397 ll_push_tail (&all_data_windows, &pdw->ll);
1401 psppire_data_window_for_dataset (struct dataset *ds)
1403 PsppireDataWindow *pdw;
1405 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1406 if (pdw->dataset == ds)
1413 create_data_window (void)
1415 gtk_widget_show (psppire_data_window_new (NULL));
1419 open_data_window (PsppireWindow *victim, const char *file_name)
1423 if (PSPPIRE_IS_DATA_WINDOW (victim)
1424 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1425 window = GTK_WIDGET (victim);
1427 window = psppire_data_window_new (NULL);
1429 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1430 gtk_widget_show (window);