1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/binomial-dialog.h"
30 #include "ui/gui/builder-wrapper.h"
31 #include "ui/gui/chi-square-dialog.h"
32 #include "ui/gui/comments-dialog.h"
33 #include "ui/gui/compute-dialog.h"
34 #include "ui/gui/correlation-dialog.h"
35 #include "ui/gui/count-dialog.h"
36 #include "ui/gui/crosstabs-dialog.h"
37 #include "ui/gui/descriptives-dialog.h"
38 #include "ui/gui/entry-dialog.h"
39 #include "ui/gui/examine-dialog.h"
40 #include "ui/gui/executor.h"
41 #include "ui/gui/factor-dialog.h"
42 #include "ui/gui/find-dialog.h"
43 #include "ui/gui/frequencies-dialog.h"
44 #include "ui/gui/goto-case-dialog.h"
45 #include "ui/gui/help-menu.h"
46 #include "ui/gui/helper.h"
47 #include "ui/gui/helper.h"
48 #include "ui/gui/k-means-dialog.h"
49 #include "ui/gui/k-related-dialog.h"
50 #include "ui/gui/npar-two-sample-related.h"
51 #include "ui/gui/oneway-anova-dialog.h"
52 #include "ui/gui/psppire-data-window.h"
53 #include "ui/gui/psppire-syntax-window.h"
54 #include "ui/gui/psppire-window.h"
55 #include "ui/gui/psppire.h"
56 #include "ui/gui/rank-dialog.h"
57 #include "ui/gui/runs-dialog.h"
58 #include "ui/gui/ks-one-sample-dialog.h"
59 #include "ui/gui/recode-dialog.h"
60 #include "ui/gui/regression-dialog.h"
61 #include "ui/gui/reliability-dialog.h"
62 #include "ui/gui/roc-dialog.h"
63 #include "ui/gui/select-cases-dialog.h"
64 #include "ui/gui/sort-cases-dialog.h"
65 #include "ui/gui/split-file-dialog.h"
66 #include "ui/gui/t-test-independent-samples-dialog.h"
67 #include "ui/gui/t-test-one-sample.h"
68 #include "ui/gui/t-test-paired-samples.h"
69 #include "ui/gui/text-data-import-dialog.h"
70 #include "ui/gui/transpose-dialog.h"
71 #include "ui/gui/univariate-dialog.h"
72 #include "ui/gui/variable-info-dialog.h"
73 #include "ui/gui/weight-cases-dialog.h"
74 #include "ui/syntax-gen.h"
76 #include "gl/c-strcase.h"
77 #include "gl/c-strcasestr.h"
78 #include "gl/xvasprintf.h"
81 #define _(msgid) gettext (msgid)
82 #define N_(msgid) msgid
84 struct session *the_session;
85 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
87 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
88 static void psppire_data_window_init (PsppireDataWindow *data_editor);
91 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
93 static void psppire_data_window_dispose (GObject *object);
94 static void psppire_data_window_set_property (GObject *object,
98 static void psppire_data_window_get_property (GObject *object,
104 psppire_data_window_get_type (void)
106 static GType psppire_data_window_type = 0;
108 if (!psppire_data_window_type)
110 static const GTypeInfo psppire_data_window_info =
112 sizeof (PsppireDataWindowClass),
115 (GClassInitFunc)psppire_data_window_class_init,
116 (GClassFinalizeFunc) NULL,
118 sizeof (PsppireDataWindow),
120 (GInstanceInitFunc) psppire_data_window_init,
123 static const GInterfaceInfo window_interface_info =
125 (GInterfaceInitFunc) psppire_data_window_iface_init,
130 psppire_data_window_type =
131 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
132 &psppire_data_window_info, 0);
135 g_type_add_interface_static (psppire_data_window_type,
136 PSPPIRE_TYPE_WINDOW_MODEL,
137 &window_interface_info);
140 return psppire_data_window_type;
143 static GObjectClass *parent_class ;
150 psppire_data_window_class_init (PsppireDataWindowClass *class)
152 GObjectClass *object_class = G_OBJECT_CLASS (class);
154 parent_class = g_type_class_peek_parent (class);
156 object_class->dispose = psppire_data_window_dispose;
157 object_class->set_property = psppire_data_window_set_property;
158 object_class->get_property = psppire_data_window_get_property;
160 g_object_class_install_property (
161 object_class, PROP_DATASET,
162 g_param_spec_pointer ("dataset", "Dataset",
163 "'struct datset *' represented by the window",
164 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
168 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
170 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
172 gtk_action_set_sensitive (edit_paste, x);
176 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
178 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
179 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
181 gtk_action_set_sensitive (edit_copy, x);
182 gtk_action_set_sensitive (edit_cut, x);
185 /* Run the EXECUTE command. */
187 execute (PsppireDataWindow *dw)
189 execute_const_syntax_string (dw, "EXECUTE.");
193 transformation_change_callback (bool transformations_pending,
196 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
198 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
200 GtkWidget *menuitem =
201 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
203 GtkWidget *status_label =
204 get_widget_assert (de->builder, "case-counter-area");
206 gtk_widget_set_sensitive (menuitem, transformations_pending);
209 if ( transformations_pending)
210 gtk_label_set_text (GTK_LABEL (status_label),
211 _("Transformations Pending"));
213 gtk_label_set_text (GTK_LABEL (status_label), "");
216 /* Callback for when the dictionary changes its filter variable */
218 on_filter_change (GObject *o, gint filter_index, gpointer data)
220 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
222 GtkWidget *filter_status_area =
223 get_widget_assert (de->builder, "filter-use-status-area");
225 if ( filter_index == -1 )
227 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
231 PsppireVarStore *vs = NULL;
232 PsppireDict *dict = NULL;
233 struct variable *var ;
236 g_object_get (de->data_editor, "var-store", &vs, NULL);
237 g_object_get (vs, "dictionary", &dict, NULL);
239 var = psppire_dict_get_variable (dict, filter_index);
241 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
243 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
249 /* Callback for when the dictionary changes its split variables */
251 on_split_change (PsppireDict *dict, gpointer data)
253 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
255 size_t n_split_vars = dict_get_split_cnt (dict->dict);
257 GtkWidget *split_status_area =
258 get_widget_assert (de->builder, "split-file-status-area");
260 if ( n_split_vars == 0 )
262 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
268 const struct variable *const * split_vars =
269 dict_get_split_vars (dict->dict);
271 text = g_string_new (_("Split by "));
273 for (i = 0 ; i < n_split_vars - 1; ++i )
275 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
277 g_string_append (text, var_get_name (split_vars[i]));
279 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
281 g_string_free (text, TRUE);
288 /* Callback for when the dictionary changes its weights */
290 on_weight_change (GObject *o, gint weight_index, gpointer data)
292 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
294 GtkWidget *weight_status_area =
295 get_widget_assert (de->builder, "weight-status-area");
297 if ( weight_index == -1 )
299 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
303 struct variable *var ;
304 PsppireVarStore *vs = NULL;
305 PsppireDict *dict = NULL;
308 g_object_get (de->data_editor, "var-store", &vs, NULL);
309 g_object_get (vs, "dictionary", &dict, NULL);
311 var = psppire_dict_get_variable (dict, weight_index);
313 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
315 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
323 dump_rm (GtkRecentManager *rm)
325 GList *items = gtk_recent_manager_get_items (rm);
329 g_print ("Recent Items:\n");
330 for (i = items; i; i = i->next)
332 GtkRecentInfo *ri = i->data;
334 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
335 gtk_recent_info_get_short_name (ri),
336 gtk_recent_info_get_mime_type (ri),
337 gtk_recent_info_get_description (ri),
338 gtk_recent_info_get_uri (ri)
342 gtk_recent_info_unref (ri);
350 name_has_por_suffix (const gchar *name)
352 size_t length = strlen (name);
353 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
357 name_has_sav_suffix (const gchar *name)
359 size_t length = strlen (name);
360 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
363 /* Returns true if NAME has a suffix which might denote a PSPP file */
365 name_has_suffix (const gchar *name)
367 return name_has_por_suffix (name) || name_has_sav_suffix (name);
371 load_file (PsppireWindow *de, const gchar *file_name)
373 struct string filename;
374 gchar *utf8_file_name;
375 const char *mime_type;
379 ds_init_empty (&filename);
381 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
383 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
385 g_free (utf8_file_name);
387 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
388 ds_destroy (&filename);
390 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
391 lex_reader_for_string (syntax));
394 mime_type = (name_has_por_suffix (file_name)
395 ? "application/x-spss-por"
396 : "application/x-spss-sav");
398 add_most_recent (file_name, mime_type);
403 /* Save DE to file */
405 save_file (PsppireWindow *w)
407 const gchar *file_name = NULL;
408 gchar *utf8_file_name = NULL;
410 struct string filename ;
411 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
414 file_name = psppire_window_get_filename (w);
416 fnx = g_string_new (file_name);
418 if ( ! name_has_suffix (fnx->str))
420 if ( de->save_as_portable)
421 g_string_append (fnx, ".por");
423 g_string_append (fnx, ".sav");
426 ds_init_empty (&filename);
428 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
430 g_string_free (fnx, TRUE);
432 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
433 g_free (utf8_file_name);
435 syntax = g_strdup_printf ("%s OUTFILE=%s.",
436 de->save_as_portable ? "EXPORT" : "SAVE",
437 ds_cstr (&filename));
439 ds_destroy (&filename);
441 g_free (execute_syntax_string (de, syntax));
446 insert_case (PsppireDataWindow *dw)
448 psppire_data_editor_insert_case (dw->data_editor);
452 on_insert_variable (PsppireDataWindow *dw)
454 psppire_data_editor_insert_variable (dw->data_editor);
459 display_dict (PsppireDataWindow *de)
461 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
465 sysfile_info (PsppireDataWindow *de)
467 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
469 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
471 struct string filename;
473 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
475 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
480 ds_init_empty (&filename);
482 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
484 g_free (utf8_file_name);
486 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
487 g_free (execute_syntax_string (de, syntax));
490 gtk_widget_destroy (dialog);
494 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
496 data_pick_filename (PsppireWindow *window)
498 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
499 GtkFileFilter *filter = gtk_file_filter_new ();
500 GtkWidget *button_sys;
502 gtk_file_chooser_dialog_new (_("Save"),
504 GTK_FILE_CHOOSER_ACTION_SAVE,
505 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
506 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
509 g_object_set (dialog, "local-only", FALSE, NULL);
511 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
512 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
513 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
515 filter = gtk_file_filter_new ();
516 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
517 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
518 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
520 filter = gtk_file_filter_new ();
521 gtk_file_filter_set_name (filter, _("All Files"));
522 gtk_file_filter_add_pattern (filter, "*");
523 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
526 GtkWidget *button_por;
527 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
529 gtk_radio_button_new_with_label (NULL, _("System File"));
532 gtk_radio_button_new_with_label
533 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
536 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
537 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
539 gtk_widget_show_all (vbox);
541 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
544 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
547 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
549 case GTK_RESPONSE_ACCEPT:
554 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
557 de->save_as_portable =
558 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
560 if ( ! name_has_suffix (filename->str))
562 if ( de->save_as_portable)
563 g_string_append (filename, ".por");
565 g_string_append (filename, ".sav");
568 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
570 g_string_free (filename, TRUE);
577 gtk_widget_destroy (dialog);
581 confirm_delete_dataset (PsppireDataWindow *de,
582 const char *old_dataset,
583 const char *new_dataset,
584 const char *existing_dataset)
589 dialog = gtk_message_dialog_new (
590 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
591 _("Delete Existing Dataset?"));
593 gtk_message_dialog_format_secondary_text (
594 GTK_MESSAGE_DIALOG (dialog),
595 _("Renaming \"%s\" to \"%s\" will delete destroy the existing "
596 "dataset named \"%s\". Are you sure that you want to do this?"),
597 old_dataset, new_dataset, existing_dataset);
599 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
600 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
601 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
604 g_object_set (dialog, "icon-name", "pspp", NULL);
606 result = gtk_dialog_run (GTK_DIALOG (dialog));
608 gtk_widget_destroy (dialog);
610 return result == GTK_RESPONSE_OK;
614 on_rename_dataset (PsppireDataWindow *de)
616 struct dataset *ds = de->dataset;
617 struct session *session = dataset_session (ds);
618 const char *old_name = dataset_name (ds);
619 struct dataset *existing_dataset;
623 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
625 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
629 if (new_name == NULL)
632 existing_dataset = session_lookup_dataset (session, new_name);
633 if (existing_dataset == NULL || existing_dataset == ds
634 || confirm_delete_dataset (de, old_name, new_name,
635 dataset_name (existing_dataset)))
636 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
643 on_edit_paste (PsppireDataWindow *de)
645 psppire_data_editor_clip_paste (de->data_editor);
649 on_edit_copy (PsppireDataWindow *de)
651 psppire_data_editor_clip_copy (de->data_editor);
657 on_edit_cut (PsppireDataWindow *de)
659 psppire_data_editor_clip_cut (de->data_editor);
664 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
666 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
668 if ( gtk_toggle_action_get_active (action))
669 gtk_widget_show (statusbar);
671 gtk_widget_hide (statusbar);
676 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
678 const gboolean grid_visible = gtk_toggle_action_get_active (action);
680 psppire_data_editor_show_grid (de->data_editor, grid_visible);
684 data_view_activate (PsppireDataWindow *de)
686 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
691 variable_view_activate (PsppireDataWindow *de)
693 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
698 fonts_activate (PsppireDataWindow *de)
700 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
701 PangoFontDescription *current_font;
704 gtk_font_selection_dialog_new (_("Font Selection"));
707 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
708 font_name = pango_font_description_to_string (current_font);
710 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
714 gtk_window_set_transient_for (GTK_WINDOW (dialog),
715 GTK_WINDOW (toplevel));
717 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
719 const gchar *font = gtk_font_selection_dialog_get_font_name
720 (GTK_FONT_SELECTION_DIALOG (dialog));
722 PangoFontDescription* font_desc =
723 pango_font_description_from_string (font);
725 psppire_data_editor_set_font (de->data_editor, font_desc);
728 gtk_widget_hide (dialog);
733 /* Callback for the value labels action */
735 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
737 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
741 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
743 psppire_data_editor_split_window (de->data_editor,
744 gtk_toggle_action_get_active (ta));
749 file_quit (PsppireDataWindow *de)
751 /* FIXME: Need to be more intelligent here.
752 Give the user the opportunity to save any unsaved data.
759 on_recent_data_select (GtkMenuShell *menushell,
760 PsppireWindow *window)
765 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
767 file = g_filename_from_uri (uri, NULL, NULL);
771 open_data_window (window, file);
777 charset_from_mime_type (const char *mime_type)
783 if (mime_type == NULL)
786 charset = c_strcasestr (mime_type, "charset=");
794 /* Parse a "quoted-string" as defined by RFC 822. */
795 for (p++; *p != '\0' && *p != '"'; p++)
798 ds_put_byte (&s, *p);
799 else if (*++p != '\0')
800 ds_put_byte (&s, *p);
805 /* Parse a "token" as defined by RFC 2045. */
806 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
807 ds_put_byte (&s, *p++);
809 if (!ds_is_empty (&s))
810 return ds_steal_cstr (&s);
817 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
824 /* Get the file name and its encoding. */
825 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
826 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
827 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
828 gtk_recent_info_unref (item);
830 se = psppire_syntax_window_new (encoding);
834 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
835 gtk_widget_show (se);
837 gtk_widget_destroy (se);
845 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
847 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
849 gtk_action_set_visible (de->delete_cases, case_num != -1);
854 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
856 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
858 gtk_action_set_visible (de->delete_variables, var != -1);
861 /* Callback for when the datasheet/varsheet is selected */
863 on_switch_sheet (GtkNotebook *notebook,
864 GtkNotebookPage *page,
868 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
870 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
872 GtkWidget *view_data =
873 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
875 GtkWidget *view_variables =
876 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
880 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
881 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
883 gtk_action_set_sensitive (de->insert_variable, TRUE);
884 gtk_action_set_sensitive (de->insert_case, FALSE);
885 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
887 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
888 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
889 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
890 gtk_action_set_sensitive (de->insert_case, TRUE);
893 g_assert_not_reached ();
898 update_paste_menuitem (de, page_num);
905 set_unsaved (gpointer w)
907 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
911 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
912 Returns a pointer to the action
915 connect_action (PsppireDataWindow *dw, const char *action_name,
918 GtkAction *action = get_action_assert (dw->builder, action_name);
920 g_signal_connect_swapped (action, "activate", handler, dw);
925 /* Initializes as much of a PsppireDataWindow as we can and must before the
926 dataset has been set.
928 In particular, the 'menu' member is required in case the "filename" property
929 is set before the "dataset" property: otherwise PsppireWindow will try to
930 modify the menu as part of the "filename" property_set() function and end up
931 with a Gtk-CRITICAL since 'menu' is NULL. */
933 psppire_data_window_init (PsppireDataWindow *de)
937 de->builder = builder_new ("data-editor.ui");
939 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
941 PSPPIRE_WINDOW (de)->menu =
942 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
946 psppire_data_window_finish_init (PsppireDataWindow *de,
949 static const struct dataset_callbacks cbs =
951 set_unsaved, /* changed */
952 transformation_change_callback, /* transformations_changed */
961 GtkWidget *box = gtk_vbox_new (FALSE, 0);
964 dict = psppire_dict_new_from_dict (dataset_dict (ds));
965 de->var_store = psppire_var_store_new (dict);
966 de->data_store = psppire_data_store_new (dict);
967 psppire_data_store_set_reader (de->data_store, NULL);
969 menubar = get_widget_assert (de->builder, "menubar");
970 hb = get_widget_assert (de->builder, "handlebox1");
971 sb = get_widget_assert (de->builder, "status-bar");
974 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
977 g_signal_connect_swapped (de->data_store, "case-changed",
978 G_CALLBACK (set_unsaved), de);
980 g_signal_connect_swapped (de->data_store, "case-inserted",
981 G_CALLBACK (set_unsaved), de);
983 g_signal_connect_swapped (de->data_store, "cases-deleted",
984 G_CALLBACK (set_unsaved), de);
986 dataset_set_callbacks (de->dataset, &cbs, de);
988 connect_help (de->builder);
990 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
991 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
992 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
993 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
995 gtk_container_add (GTK_CONTAINER (de), box);
997 set_cut_copy_menuitem_sensitivity (de, FALSE);
999 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
1000 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
1003 set_paste_menuitem_sensitivity (de, FALSE);
1005 g_signal_connect_swapped (de->data_editor, "data-available-changed",
1006 G_CALLBACK (set_paste_menuitem_sensitivity), de);
1008 g_signal_connect (dict, "weight-changed",
1009 G_CALLBACK (on_weight_change),
1012 g_signal_connect (dict, "filter-changed",
1013 G_CALLBACK (on_filter_change),
1016 g_signal_connect (dict, "split-changed",
1017 G_CALLBACK (on_split_change),
1021 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1023 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1025 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1027 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1029 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1031 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1033 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1035 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1037 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1039 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1041 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1043 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1045 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1047 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1049 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1052 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1054 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1056 gtk_action_set_visible (de->delete_cases, FALSE);
1061 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1063 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1065 gtk_action_set_visible (de->delete_variables, FALSE);
1069 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1071 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1073 connect_action (de, "data_sort-cases", G_CALLBACK (sort_cases_dialog));
1075 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1077 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1079 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1081 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1083 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1085 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1088 connect_action (de, "utilities_variables", G_CALLBACK (variable_info_dialog));
1090 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1092 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1094 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1096 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1098 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1100 connect_action (de, "transform_rank", G_CALLBACK (rank_dialog));
1102 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1104 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1106 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1108 connect_action (de, "analyze_descriptives", G_CALLBACK (descriptives_dialog));
1110 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1112 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1114 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1116 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1118 connect_action (de, "reliability", G_CALLBACK (reliability_dialog));
1120 connect_action (de, "roc-curve", G_CALLBACK (roc_dialog));
1122 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1124 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1126 connect_action (de, "correlation", G_CALLBACK (correlation_dialog));
1128 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1130 connect_action (de, "k-means", G_CALLBACK (k_means_dialog));
1132 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1133 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1134 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1135 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1136 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1137 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1141 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1143 GtkWidget *recent_data =
1144 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1146 GtkWidget *recent_files =
1147 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1150 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1151 gtk_recent_manager_get_default ());
1153 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1154 gtk_recent_manager_get_default ());
1156 g_object_set (menu_data, "show-tips", TRUE, NULL);
1157 g_object_set (menu_files, "show-tips", TRUE, NULL);
1160 GtkRecentFilter *filter = gtk_recent_filter_new ();
1162 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1163 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1165 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1167 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1170 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1173 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1176 GtkRecentFilter *filter = gtk_recent_filter_new ();
1178 gtk_recent_filter_add_pattern (filter, "*.sps");
1179 gtk_recent_filter_add_pattern (filter, "*.SPS");
1181 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1183 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1186 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1188 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1192 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1195 g_signal_connect (de->data_editor,
1197 G_CALLBACK (enable_delete_cases),
1200 g_signal_connect (de->data_editor,
1201 "variables-selected",
1202 G_CALLBACK (enable_delete_variables),
1206 g_signal_connect (de->data_editor,
1208 G_CALLBACK (on_switch_sheet), de);
1210 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1211 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1213 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1215 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1217 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1219 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1221 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1223 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1225 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1227 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1229 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1232 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1234 merge_help_menu (uim);
1238 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1239 "datasheet-cases-popup");
1241 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1242 "varsheet-variable-popup");
1244 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1245 "datasheet-variable-popup");
1247 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1248 G_CALLBACK (psppire_data_editor_sort_ascending),
1251 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1252 G_CALLBACK (psppire_data_editor_sort_descending),
1255 g_object_set (de->data_editor,
1256 "datasheet-column-menu", data_sheet_variable_popup_menu,
1257 "datasheet-row-menu", data_sheet_cases_popup_menu,
1258 "varsheet-row-menu", var_sheet_variable_popup_menu,
1262 gtk_widget_show (GTK_WIDGET (de->data_editor));
1263 gtk_widget_show (box);
1265 ll_push_head (&all_data_windows, &de->ll);
1269 psppire_data_window_dispose (GObject *object)
1271 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1273 if (dw->builder != NULL)
1275 g_object_unref (dw->builder);
1281 g_object_unref (dw->var_store);
1282 dw->var_store = NULL;
1287 g_object_unref (dw->data_store);
1288 dw->data_store = NULL;
1291 if (dw->ll.next != NULL)
1293 ll_remove (&dw->ll);
1297 if (G_OBJECT_CLASS (parent_class)->dispose)
1298 G_OBJECT_CLASS (parent_class)->dispose (object);
1302 psppire_data_window_set_property (GObject *object,
1304 const GValue *value,
1307 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1312 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1315 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1321 psppire_data_window_get_property (GObject *object,
1326 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1331 g_value_set_pointer (value, window->dataset);
1334 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1340 psppire_data_window_new (struct dataset *ds)
1344 if (the_session == NULL)
1345 the_session = session_create ();
1349 static int n_datasets;
1352 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1353 ds = dataset_create (the_session, dataset_name);
1354 free (dataset_name);
1356 assert (dataset_session (ds) == the_session);
1360 psppire_data_window_get_type (),
1361 /* TRANSLATORS: This will form a filename. Please avoid whitespace. */
1362 "description", _("Data Editor"),
1366 if (dataset_name (ds) != NULL)
1367 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1373 psppire_data_window_is_empty (PsppireDataWindow *dw)
1375 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1379 psppire_data_window_iface_init (PsppireWindowIface *iface)
1381 iface->save = save_file;
1382 iface->pick_filename = data_pick_filename;
1383 iface->load = load_file;
1387 psppire_default_data_window (void)
1389 if (ll_is_empty (&all_data_windows))
1390 create_data_window ();
1391 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1395 psppire_data_window_set_default (PsppireDataWindow *pdw)
1397 ll_remove (&pdw->ll);
1398 ll_push_head (&all_data_windows, &pdw->ll);
1402 psppire_data_window_undefault (PsppireDataWindow *pdw)
1404 ll_remove (&pdw->ll);
1405 ll_push_tail (&all_data_windows, &pdw->ll);
1409 psppire_data_window_for_dataset (struct dataset *ds)
1411 PsppireDataWindow *pdw;
1413 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1414 if (pdw->dataset == ds)
1421 create_data_window (void)
1423 gtk_widget_show (psppire_data_window_new (NULL));
1427 open_data_window (PsppireWindow *victim, const char *file_name)
1431 if (PSPPIRE_IS_DATA_WINDOW (victim)
1432 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1433 window = GTK_WIDGET (victim);
1435 window = psppire_data_window_new (NULL);
1437 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1438 gtk_widget_show (window);