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/ks-one-sample-dialog.h"
57 #include "ui/gui/recode-dialog.h"
58 #include "ui/gui/regression-dialog.h"
59 #include "ui/gui/reliability-dialog.h"
60 #include "ui/gui/roc-dialog.h"
61 #include "ui/gui/select-cases-dialog.h"
62 #include "ui/gui/sort-cases-dialog.h"
63 #include "ui/gui/split-file-dialog.h"
64 #include "ui/gui/t-test-independent-samples-dialog.h"
65 #include "ui/gui/t-test-one-sample.h"
66 #include "ui/gui/t-test-paired-samples.h"
67 #include "ui/gui/text-data-import-dialog.h"
68 #include "ui/gui/transpose-dialog.h"
69 #include "ui/gui/univariate-dialog.h"
70 #include "ui/gui/variable-info-dialog.h"
71 #include "ui/gui/weight-cases-dialog.h"
72 #include "ui/syntax-gen.h"
74 #include "gl/c-strcase.h"
75 #include "gl/c-strcasestr.h"
76 #include "gl/xvasprintf.h"
79 #define _(msgid) gettext (msgid)
80 #define N_(msgid) msgid
82 struct session *the_session;
83 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
85 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
86 static void psppire_data_window_init (PsppireDataWindow *data_editor);
89 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
91 static void psppire_data_window_dispose (GObject *object);
92 static void psppire_data_window_set_property (GObject *object,
96 static void psppire_data_window_get_property (GObject *object,
102 psppire_data_window_get_type (void)
104 static GType psppire_data_window_type = 0;
106 if (!psppire_data_window_type)
108 static const GTypeInfo psppire_data_window_info =
110 sizeof (PsppireDataWindowClass),
113 (GClassInitFunc)psppire_data_window_class_init,
114 (GClassFinalizeFunc) NULL,
116 sizeof (PsppireDataWindow),
118 (GInstanceInitFunc) psppire_data_window_init,
121 static const GInterfaceInfo window_interface_info =
123 (GInterfaceInitFunc) psppire_data_window_iface_init,
128 psppire_data_window_type =
129 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
130 &psppire_data_window_info, 0);
133 g_type_add_interface_static (psppire_data_window_type,
134 PSPPIRE_TYPE_WINDOW_MODEL,
135 &window_interface_info);
138 return psppire_data_window_type;
141 static GObjectClass *parent_class ;
148 psppire_data_window_class_init (PsppireDataWindowClass *class)
150 GObjectClass *object_class = G_OBJECT_CLASS (class);
152 parent_class = g_type_class_peek_parent (class);
154 object_class->dispose = psppire_data_window_dispose;
155 object_class->set_property = psppire_data_window_set_property;
156 object_class->get_property = psppire_data_window_get_property;
158 g_object_class_install_property (
159 object_class, PROP_DATASET,
160 g_param_spec_pointer ("dataset", "Dataset",
161 "'struct datset *' represented by the window",
162 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
166 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
168 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
170 gtk_action_set_sensitive (edit_paste, x);
174 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
176 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
177 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
179 gtk_action_set_sensitive (edit_copy, x);
180 gtk_action_set_sensitive (edit_cut, x);
183 /* Run the EXECUTE command. */
185 execute (PsppireDataWindow *dw)
187 execute_const_syntax_string (dw, "EXECUTE.");
191 transformation_change_callback (bool transformations_pending,
194 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
196 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
198 GtkWidget *menuitem =
199 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
201 GtkWidget *status_label =
202 get_widget_assert (de->builder, "case-counter-area");
204 gtk_widget_set_sensitive (menuitem, transformations_pending);
207 if ( transformations_pending)
208 gtk_label_set_text (GTK_LABEL (status_label),
209 _("Transformations Pending"));
211 gtk_label_set_text (GTK_LABEL (status_label), "");
214 /* Callback for when the dictionary changes its filter variable */
216 on_filter_change (GObject *o, gint filter_index, gpointer data)
218 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
220 GtkWidget *filter_status_area =
221 get_widget_assert (de->builder, "filter-use-status-area");
223 if ( filter_index == -1 )
225 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
229 PsppireVarStore *vs = NULL;
230 PsppireDict *dict = NULL;
231 struct variable *var ;
234 g_object_get (de->data_editor, "var-store", &vs, NULL);
235 g_object_get (vs, "dictionary", &dict, NULL);
237 var = psppire_dict_get_variable (dict, filter_index);
239 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
241 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
247 /* Callback for when the dictionary changes its split variables */
249 on_split_change (PsppireDict *dict, gpointer data)
251 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
253 size_t n_split_vars = dict_get_split_cnt (dict->dict);
255 GtkWidget *split_status_area =
256 get_widget_assert (de->builder, "split-file-status-area");
258 if ( n_split_vars == 0 )
260 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
266 const struct variable *const * split_vars =
267 dict_get_split_vars (dict->dict);
269 text = g_string_new (_("Split by "));
271 for (i = 0 ; i < n_split_vars - 1; ++i )
273 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
275 g_string_append (text, var_get_name (split_vars[i]));
277 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
279 g_string_free (text, TRUE);
286 /* Callback for when the dictionary changes its weights */
288 on_weight_change (GObject *o, gint weight_index, gpointer data)
290 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
292 GtkWidget *weight_status_area =
293 get_widget_assert (de->builder, "weight-status-area");
295 if ( weight_index == -1 )
297 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
301 struct variable *var ;
302 PsppireVarStore *vs = NULL;
303 PsppireDict *dict = NULL;
306 g_object_get (de->data_editor, "var-store", &vs, NULL);
307 g_object_get (vs, "dictionary", &dict, NULL);
309 var = psppire_dict_get_variable (dict, weight_index);
311 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
313 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
321 dump_rm (GtkRecentManager *rm)
323 GList *items = gtk_recent_manager_get_items (rm);
327 g_print ("Recent Items:\n");
328 for (i = items; i; i = i->next)
330 GtkRecentInfo *ri = i->data;
332 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
333 gtk_recent_info_get_short_name (ri),
334 gtk_recent_info_get_mime_type (ri),
335 gtk_recent_info_get_description (ri),
336 gtk_recent_info_get_uri (ri)
340 gtk_recent_info_unref (ri);
348 name_has_por_suffix (const gchar *name)
350 size_t length = strlen (name);
351 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
355 name_has_sav_suffix (const gchar *name)
357 size_t length = strlen (name);
358 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
361 /* Returns true if NAME has a suffix which might denote a PSPP file */
363 name_has_suffix (const gchar *name)
365 return name_has_por_suffix (name) || name_has_sav_suffix (name);
369 load_file (PsppireWindow *de, const gchar *file_name)
371 struct string filename;
372 gchar *utf8_file_name;
373 const char *mime_type;
377 ds_init_empty (&filename);
379 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
381 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
383 g_free (utf8_file_name);
385 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
386 ds_destroy (&filename);
388 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
389 lex_reader_for_string (syntax));
392 mime_type = (name_has_por_suffix (file_name)
393 ? "application/x-spss-por"
394 : "application/x-spss-sav");
396 add_most_recent (file_name, mime_type);
401 /* Save DE to file */
403 save_file (PsppireWindow *w)
405 const gchar *file_name = NULL;
406 gchar *utf8_file_name = NULL;
408 struct string filename ;
409 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
412 file_name = psppire_window_get_filename (w);
414 fnx = g_string_new (file_name);
416 if ( ! name_has_suffix (fnx->str))
418 if ( de->save_as_portable)
419 g_string_append (fnx, ".por");
421 g_string_append (fnx, ".sav");
424 ds_init_empty (&filename);
426 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
428 g_string_free (fnx, TRUE);
430 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
431 g_free (utf8_file_name);
433 syntax = g_strdup_printf ("%s OUTFILE=%s.",
434 de->save_as_portable ? "EXPORT" : "SAVE",
435 ds_cstr (&filename));
437 ds_destroy (&filename);
439 g_free (execute_syntax_string (de, syntax));
444 insert_case (PsppireDataWindow *dw)
446 psppire_data_editor_insert_case (dw->data_editor);
450 on_insert_variable (PsppireDataWindow *dw)
452 psppire_data_editor_insert_variable (dw->data_editor);
457 display_dict (PsppireDataWindow *de)
459 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
463 sysfile_info (PsppireDataWindow *de)
465 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
467 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
469 struct string filename;
471 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
473 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
478 ds_init_empty (&filename);
480 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
482 g_free (utf8_file_name);
484 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
485 g_free (execute_syntax_string (de, syntax));
488 gtk_widget_destroy (dialog);
492 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
494 data_pick_filename (PsppireWindow *window)
496 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
497 GtkFileFilter *filter = gtk_file_filter_new ();
498 GtkWidget *button_sys;
500 gtk_file_chooser_dialog_new (_("Save"),
502 GTK_FILE_CHOOSER_ACTION_SAVE,
503 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
504 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
507 g_object_set (dialog, "local-only", FALSE, NULL);
509 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
510 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
511 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
513 filter = gtk_file_filter_new ();
514 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
515 gtk_file_filter_add_mime_type (filter, "application/x-spss-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", "pspp", 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);
843 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
845 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
847 gtk_action_set_visible (de->delete_cases, case_num != -1);
852 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
854 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
856 gtk_action_set_visible (de->delete_variables, var != -1);
859 /* Callback for when the datasheet/varsheet is selected */
861 on_switch_sheet (GtkNotebook *notebook,
862 GtkNotebookPage *page,
866 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
868 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
870 GtkWidget *view_data =
871 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
873 GtkWidget *view_variables =
874 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
878 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
879 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
881 gtk_action_set_sensitive (de->insert_variable, TRUE);
882 gtk_action_set_sensitive (de->insert_case, FALSE);
883 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
885 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
886 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
887 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
888 gtk_action_set_sensitive (de->insert_case, TRUE);
891 g_assert_not_reached ();
896 update_paste_menuitem (de, page_num);
903 set_unsaved (gpointer w)
905 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
909 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
910 Returns a pointer to the action
913 connect_action (PsppireDataWindow *dw, const char *action_name,
916 GtkAction *action = get_action_assert (dw->builder, action_name);
918 g_signal_connect_swapped (action, "activate", handler, dw);
923 /* Initializes as much of a PsppireDataWindow as we can and must before the
924 dataset has been set.
926 In particular, the 'menu' member is required in case the "filename" property
927 is set before the "dataset" property: otherwise PsppireWindow will try to
928 modify the menu as part of the "filename" property_set() function and end up
929 with a Gtk-CRITICAL since 'menu' is NULL. */
931 psppire_data_window_init (PsppireDataWindow *de)
935 de->builder = builder_new ("data-editor.ui");
937 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
939 PSPPIRE_WINDOW (de)->menu =
940 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
944 psppire_data_window_finish_init (PsppireDataWindow *de,
947 static const struct dataset_callbacks cbs =
949 set_unsaved, /* changed */
950 transformation_change_callback, /* transformations_changed */
959 GtkWidget *box = gtk_vbox_new (FALSE, 0);
962 dict = psppire_dict_new_from_dict (dataset_dict (ds));
963 de->var_store = psppire_var_store_new (dict);
964 de->data_store = psppire_data_store_new (dict);
965 psppire_data_store_set_reader (de->data_store, NULL);
967 menubar = get_widget_assert (de->builder, "menubar");
968 hb = get_widget_assert (de->builder, "handlebox1");
969 sb = get_widget_assert (de->builder, "status-bar");
972 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
975 g_signal_connect_swapped (de->data_store, "case-changed",
976 G_CALLBACK (set_unsaved), de);
978 g_signal_connect_swapped (de->data_store, "case-inserted",
979 G_CALLBACK (set_unsaved), de);
981 g_signal_connect_swapped (de->data_store, "cases-deleted",
982 G_CALLBACK (set_unsaved), de);
984 dataset_set_callbacks (de->dataset, &cbs, de);
986 connect_help (de->builder);
988 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
989 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
990 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
991 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
993 gtk_container_add (GTK_CONTAINER (de), box);
995 set_cut_copy_menuitem_sensitivity (de, FALSE);
997 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
998 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
1001 set_paste_menuitem_sensitivity (de, FALSE);
1003 g_signal_connect_swapped (de->data_editor, "data-available-changed",
1004 G_CALLBACK (set_paste_menuitem_sensitivity), de);
1006 g_signal_connect (dict, "weight-changed",
1007 G_CALLBACK (on_weight_change),
1010 g_signal_connect (dict, "filter-changed",
1011 G_CALLBACK (on_filter_change),
1014 g_signal_connect (dict, "split-changed",
1015 G_CALLBACK (on_split_change),
1019 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1021 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1023 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1025 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1027 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1029 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1031 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1033 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1035 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1037 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1039 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1041 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1043 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1045 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1047 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1050 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1052 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1054 gtk_action_set_visible (de->delete_cases, FALSE);
1059 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1061 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1063 gtk_action_set_visible (de->delete_variables, FALSE);
1067 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1069 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1071 connect_action (de, "data_sort-cases", G_CALLBACK (sort_cases_dialog));
1073 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1075 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1077 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1079 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1081 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1083 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1086 connect_action (de, "utilities_variables", G_CALLBACK (variable_info_dialog));
1088 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1090 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1092 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1094 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1096 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1098 connect_action (de, "transform_rank", G_CALLBACK (rank_dialog));
1100 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1102 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1104 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1106 connect_action (de, "analyze_descriptives", G_CALLBACK (descriptives_dialog));
1108 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1110 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1112 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1114 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1116 connect_action (de, "reliability", G_CALLBACK (reliability_dialog));
1118 connect_action (de, "roc-curve", G_CALLBACK (roc_dialog));
1120 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1122 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1124 connect_action (de, "correlation", G_CALLBACK (correlation_dialog));
1126 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1128 connect_action (de, "k-means", G_CALLBACK (k_means_dialog));
1130 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1131 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1132 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1133 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1134 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1135 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1139 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1141 GtkWidget *recent_data =
1142 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1144 GtkWidget *recent_files =
1145 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1148 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1149 gtk_recent_manager_get_default ());
1151 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1152 gtk_recent_manager_get_default ());
1154 g_object_set (menu_data, "show-tips", TRUE, NULL);
1155 g_object_set (menu_files, "show-tips", TRUE, NULL);
1158 GtkRecentFilter *filter = gtk_recent_filter_new ();
1160 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1161 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1163 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1165 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1168 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1171 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1174 GtkRecentFilter *filter = gtk_recent_filter_new ();
1176 gtk_recent_filter_add_pattern (filter, "*.sps");
1177 gtk_recent_filter_add_pattern (filter, "*.SPS");
1179 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1181 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1184 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1186 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1190 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1193 g_signal_connect (de->data_editor,
1195 G_CALLBACK (enable_delete_cases),
1198 g_signal_connect (de->data_editor,
1199 "variables-selected",
1200 G_CALLBACK (enable_delete_variables),
1204 g_signal_connect (de->data_editor,
1206 G_CALLBACK (on_switch_sheet), de);
1208 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1209 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1211 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1213 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1215 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1217 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1219 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1221 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1223 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1225 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1227 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1230 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1232 merge_help_menu (uim);
1236 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1237 "datasheet-cases-popup");
1239 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1240 "varsheet-variable-popup");
1242 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1243 "datasheet-variable-popup");
1245 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1246 G_CALLBACK (psppire_data_editor_sort_ascending),
1249 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1250 G_CALLBACK (psppire_data_editor_sort_descending),
1253 g_object_set (de->data_editor,
1254 "datasheet-column-menu", data_sheet_variable_popup_menu,
1255 "datasheet-row-menu", data_sheet_cases_popup_menu,
1256 "varsheet-row-menu", var_sheet_variable_popup_menu,
1260 gtk_widget_show (GTK_WIDGET (de->data_editor));
1261 gtk_widget_show (box);
1263 ll_push_head (&all_data_windows, &de->ll);
1267 psppire_data_window_dispose (GObject *object)
1269 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1271 if (dw->builder != NULL)
1273 g_object_unref (dw->builder);
1279 g_object_unref (dw->var_store);
1280 dw->var_store = NULL;
1285 g_object_unref (dw->data_store);
1286 dw->data_store = NULL;
1289 if (dw->ll.next != NULL)
1291 ll_remove (&dw->ll);
1295 if (G_OBJECT_CLASS (parent_class)->dispose)
1296 G_OBJECT_CLASS (parent_class)->dispose (object);
1300 psppire_data_window_set_property (GObject *object,
1302 const GValue *value,
1305 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1310 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1313 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1319 psppire_data_window_get_property (GObject *object,
1324 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1329 g_value_set_pointer (value, window->dataset);
1332 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1338 psppire_data_window_new (struct dataset *ds)
1342 if (the_session == NULL)
1343 the_session = session_create ();
1347 static int n_datasets;
1350 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1351 ds = dataset_create (the_session, dataset_name);
1352 free (dataset_name);
1354 assert (dataset_session (ds) == the_session);
1358 psppire_data_window_get_type (),
1359 /* TRANSLATORS: This will form a filename. Please avoid whitespace. */
1360 "description", _("Data Editor"),
1364 if (dataset_name (ds) != NULL)
1365 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1371 psppire_data_window_is_empty (PsppireDataWindow *dw)
1373 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1377 psppire_data_window_iface_init (PsppireWindowIface *iface)
1379 iface->save = save_file;
1380 iface->pick_filename = data_pick_filename;
1381 iface->load = load_file;
1385 psppire_default_data_window (void)
1387 if (ll_is_empty (&all_data_windows))
1388 create_data_window ();
1389 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1393 psppire_data_window_set_default (PsppireDataWindow *pdw)
1395 ll_remove (&pdw->ll);
1396 ll_push_head (&all_data_windows, &pdw->ll);
1400 psppire_data_window_undefault (PsppireDataWindow *pdw)
1402 ll_remove (&pdw->ll);
1403 ll_push_tail (&all_data_windows, &pdw->ll);
1407 psppire_data_window_for_dataset (struct dataset *ds)
1409 PsppireDataWindow *pdw;
1411 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1412 if (pdw->dataset == ds)
1419 create_data_window (void)
1421 gtk_widget_show (psppire_data_window_new (NULL));
1425 open_data_window (PsppireWindow *victim, const char *file_name)
1429 if (PSPPIRE_IS_DATA_WINDOW (victim)
1430 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1431 window = GTK_WIDGET (victim);
1433 window = psppire_data_window_new (NULL);
1435 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1436 gtk_widget_show (window);