1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/binomial-dialog.h"
30 #include "ui/gui/builder-wrapper.h"
31 #include "ui/gui/chi-square-dialog.h"
32 #include "ui/gui/comments-dialog.h"
33 #include "ui/gui/compute-dialog.h"
34 #include "ui/gui/count-dialog.h"
35 #include "ui/gui/crosstabs-dialog.h"
36 #include "ui/gui/entry-dialog.h"
37 #include "ui/gui/examine-dialog.h"
38 #include "ui/gui/executor.h"
39 #include "ui/gui/factor-dialog.h"
40 #include "ui/gui/find-dialog.h"
41 #include "ui/gui/frequencies-dialog.h"
42 #include "ui/gui/goto-case-dialog.h"
43 #include "ui/gui/help-menu.h"
44 #include "ui/gui/helper.h"
45 #include "ui/gui/helper.h"
46 #include "ui/gui/k-related-dialog.h"
47 #include "ui/gui/npar-two-sample-related.h"
48 #include "ui/gui/oneway-anova-dialog.h"
49 #include "ui/gui/psppire-data-window.h"
50 #include "ui/gui/psppire-syntax-window.h"
51 #include "ui/gui/psppire-window.h"
52 #include "ui/gui/psppire.h"
53 #include "ui/gui/rank-dialog.h"
54 #include "ui/gui/runs-dialog.h"
55 #include "ui/gui/ks-one-sample-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/univariate-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_mime_type (filter, "application/x-spss-sav");
509 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
511 filter = gtk_file_filter_new ();
512 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
513 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
514 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
516 filter = gtk_file_filter_new ();
517 gtk_file_filter_set_name (filter, _("All Files"));
518 gtk_file_filter_add_pattern (filter, "*");
519 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
522 GtkWidget *button_por;
523 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
525 gtk_radio_button_new_with_label (NULL, _("System File"));
528 gtk_radio_button_new_with_label
529 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
532 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
533 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
535 gtk_widget_show_all (vbox);
537 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
540 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
543 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
545 case GTK_RESPONSE_ACCEPT:
550 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
553 de->save_as_portable =
554 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
556 if ( ! name_has_suffix (filename->str))
558 if ( de->save_as_portable)
559 g_string_append (filename, ".por");
561 g_string_append (filename, ".sav");
564 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
566 g_string_free (filename, TRUE);
573 gtk_widget_destroy (dialog);
577 confirm_delete_dataset (PsppireDataWindow *de,
578 const char *old_dataset,
579 const char *new_dataset,
580 const char *existing_dataset)
585 dialog = gtk_message_dialog_new (
586 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
587 _("Delete Existing Dataset?"));
589 gtk_message_dialog_format_secondary_text (
590 GTK_MESSAGE_DIALOG (dialog),
591 _("Renaming \"%s\" to \"%s\" will delete destroy the existing "
592 "dataset named \"%s\". Are you sure that you want to do this?"),
593 old_dataset, new_dataset, existing_dataset);
595 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
596 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
597 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
600 g_object_set (dialog, "icon-name", "pspp", NULL);
602 result = gtk_dialog_run (GTK_DIALOG (dialog));
604 gtk_widget_destroy (dialog);
606 return result == GTK_RESPONSE_OK;
610 on_rename_dataset (PsppireDataWindow *de)
612 struct dataset *ds = de->dataset;
613 struct session *session = dataset_session (ds);
614 const char *old_name = dataset_name (ds);
615 struct dataset *existing_dataset;
619 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
621 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
625 if (new_name == NULL)
628 existing_dataset = session_lookup_dataset (session, new_name);
629 if (existing_dataset == NULL || existing_dataset == ds
630 || confirm_delete_dataset (de, old_name, new_name,
631 dataset_name (existing_dataset)))
632 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
639 on_edit_paste (PsppireDataWindow *de)
641 psppire_data_editor_clip_paste (de->data_editor);
645 on_edit_copy (PsppireDataWindow *de)
647 psppire_data_editor_clip_copy (de->data_editor);
653 on_edit_cut (PsppireDataWindow *de)
655 psppire_data_editor_clip_cut (de->data_editor);
660 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
662 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
664 if ( gtk_toggle_action_get_active (action))
665 gtk_widget_show (statusbar);
667 gtk_widget_hide (statusbar);
672 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
674 const gboolean grid_visible = gtk_toggle_action_get_active (action);
676 psppire_data_editor_show_grid (de->data_editor, grid_visible);
680 data_view_activate (PsppireDataWindow *de)
682 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
687 variable_view_activate (PsppireDataWindow *de)
689 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
694 fonts_activate (PsppireDataWindow *de)
696 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
697 PangoFontDescription *current_font;
700 gtk_font_selection_dialog_new (_("Font Selection"));
703 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
704 font_name = pango_font_description_to_string (current_font);
706 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
710 gtk_window_set_transient_for (GTK_WINDOW (dialog),
711 GTK_WINDOW (toplevel));
713 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
715 const gchar *font = gtk_font_selection_dialog_get_font_name
716 (GTK_FONT_SELECTION_DIALOG (dialog));
718 PangoFontDescription* font_desc =
719 pango_font_description_from_string (font);
721 psppire_data_editor_set_font (de->data_editor, font_desc);
724 gtk_widget_hide (dialog);
729 /* Callback for the value labels action */
731 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
733 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
737 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
739 psppire_data_editor_split_window (de->data_editor,
740 gtk_toggle_action_get_active (ta));
745 file_quit (PsppireDataWindow *de)
747 /* FIXME: Need to be more intelligent here.
748 Give the user the opportunity to save any unsaved data.
755 on_recent_data_select (GtkMenuShell *menushell,
756 PsppireWindow *window)
761 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
763 file = g_filename_from_uri (uri, NULL, NULL);
767 open_data_window (window, file);
773 charset_from_mime_type (const char *mime_type)
779 if (mime_type == NULL)
782 charset = c_strcasestr (mime_type, "charset=");
790 /* Parse a "quoted-string" as defined by RFC 822. */
791 for (p++; *p != '\0' && *p != '"'; p++)
794 ds_put_byte (&s, *p);
795 else if (*++p != '\0')
796 ds_put_byte (&s, *p);
801 /* Parse a "token" as defined by RFC 2045. */
802 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
803 ds_put_byte (&s, *p++);
805 if (!ds_is_empty (&s))
806 return ds_steal_cstr (&s);
813 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
820 /* Get the file name and its encoding. */
821 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
822 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
823 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
824 gtk_recent_info_unref (item);
826 se = psppire_syntax_window_new (encoding);
830 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
831 gtk_widget_show (se);
833 gtk_widget_destroy (se);
841 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
843 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
845 gtk_action_set_visible (de->delete_cases, case_num != -1);
850 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
852 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
854 gtk_action_set_visible (de->delete_variables, var != -1);
857 /* Callback for when the datasheet/varsheet is selected */
859 on_switch_sheet (GtkNotebook *notebook,
860 GtkNotebookPage *page,
864 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
866 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
868 GtkWidget *view_data =
869 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
871 GtkWidget *view_variables =
872 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
876 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
877 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
879 gtk_action_set_sensitive (de->insert_variable, TRUE);
880 gtk_action_set_sensitive (de->insert_case, FALSE);
881 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
883 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
884 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
885 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
886 gtk_action_set_sensitive (de->insert_case, TRUE);
889 g_assert_not_reached ();
894 update_paste_menuitem (de, page_num);
901 set_unsaved (gpointer w)
903 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
907 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
908 Returns a pointer to the action
911 connect_action (PsppireDataWindow *dw, const char *action_name,
914 GtkAction *action = get_action_assert (dw->builder, action_name);
916 g_signal_connect_swapped (action, "activate", handler, dw);
921 /* Initializes as much of a PsppireDataWindow as we can and must before the
922 dataset has been set.
924 In particular, the 'menu' member is required in case the "filename" property
925 is set before the "dataset" property: otherwise PsppireWindow will try to
926 modify the menu as part of the "filename" property_set() function and end up
927 with a Gtk-CRITICAL since 'menu' is NULL. */
929 psppire_data_window_init (PsppireDataWindow *de)
933 de->builder = builder_new ("data-editor.ui");
935 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
937 PSPPIRE_WINDOW (de)->menu =
938 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
942 psppire_data_window_finish_init (PsppireDataWindow *de,
945 static const struct dataset_callbacks cbs =
947 set_unsaved, /* changed */
948 transformation_change_callback, /* transformations_changed */
957 GtkWidget *box = gtk_vbox_new (FALSE, 0);
960 dict = psppire_dict_new_from_dict (dataset_dict (ds));
961 de->var_store = psppire_var_store_new (dict);
962 de->data_store = psppire_data_store_new (dict);
963 psppire_data_store_set_reader (de->data_store, NULL);
965 menubar = get_widget_assert (de->builder, "menubar");
966 hb = get_widget_assert (de->builder, "handlebox1");
967 sb = get_widget_assert (de->builder, "status-bar");
970 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
973 g_signal_connect_swapped (de->data_store, "case-changed",
974 G_CALLBACK (set_unsaved), de);
976 g_signal_connect_swapped (de->data_store, "case-inserted",
977 G_CALLBACK (set_unsaved), de);
979 g_signal_connect_swapped (de->data_store, "cases-deleted",
980 G_CALLBACK (set_unsaved), de);
982 dataset_set_callbacks (de->dataset, &cbs, de);
984 connect_help (de->builder);
986 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
987 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
988 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
989 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
991 gtk_container_add (GTK_CONTAINER (de), box);
993 set_cut_copy_menuitem_sensitivity (de, FALSE);
995 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
996 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
999 set_paste_menuitem_sensitivity (de, FALSE);
1001 g_signal_connect_swapped (de->data_editor, "data-available-changed",
1002 G_CALLBACK (set_paste_menuitem_sensitivity), de);
1004 g_signal_connect (dict, "weight-changed",
1005 G_CALLBACK (on_weight_change),
1008 g_signal_connect (dict, "filter-changed",
1009 G_CALLBACK (on_filter_change),
1012 g_signal_connect (dict, "split-changed",
1013 G_CALLBACK (on_split_change),
1017 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1019 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1021 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1023 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1025 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1027 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1029 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1031 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1033 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1035 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1037 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1039 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1041 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1043 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1045 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1048 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1050 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1052 gtk_action_set_visible (de->delete_cases, FALSE);
1057 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1059 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1061 gtk_action_set_visible (de->delete_variables, FALSE);
1065 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1067 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1069 connect_action (de, "data_sort-cases", G_CALLBACK (sort_cases_dialog));
1071 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1073 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1075 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1077 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1079 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1081 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1083 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1085 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1087 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1089 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1091 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1093 connect_action (de, "transform_rank", G_CALLBACK (rank_dialog));
1095 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1097 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1099 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1101 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1103 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1105 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1107 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1109 connect_action (de, "reliability", G_CALLBACK (reliability_dialog));
1111 connect_action (de, "roc-curve", G_CALLBACK (roc_dialog));
1113 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1115 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1117 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1119 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1120 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1121 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1122 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1123 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1124 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1128 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1130 GtkWidget *recent_data =
1131 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1133 GtkWidget *recent_files =
1134 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1137 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1138 gtk_recent_manager_get_default ());
1140 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1141 gtk_recent_manager_get_default ());
1143 g_object_set (menu_data, "show-tips", TRUE, NULL);
1144 g_object_set (menu_files, "show-tips", TRUE, NULL);
1147 GtkRecentFilter *filter = gtk_recent_filter_new ();
1149 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1150 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1152 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1154 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1157 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1160 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1163 GtkRecentFilter *filter = gtk_recent_filter_new ();
1165 gtk_recent_filter_add_pattern (filter, "*.sps");
1166 gtk_recent_filter_add_pattern (filter, "*.SPS");
1168 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1170 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1173 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1175 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1179 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1182 g_signal_connect (de->data_editor,
1184 G_CALLBACK (enable_delete_cases),
1187 g_signal_connect (de->data_editor,
1188 "variables-selected",
1189 G_CALLBACK (enable_delete_variables),
1193 g_signal_connect (de->data_editor,
1195 G_CALLBACK (on_switch_sheet), de);
1197 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1198 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1200 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1202 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1204 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1206 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1208 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1210 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1212 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1214 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1216 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1219 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1221 merge_help_menu (uim);
1225 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1226 "datasheet-cases-popup");
1228 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1229 "varsheet-variable-popup");
1231 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1232 "datasheet-variable-popup");
1234 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1235 G_CALLBACK (psppire_data_editor_sort_ascending),
1238 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1239 G_CALLBACK (psppire_data_editor_sort_descending),
1242 g_object_set (de->data_editor,
1243 "datasheet-column-menu", data_sheet_variable_popup_menu,
1244 "datasheet-row-menu", data_sheet_cases_popup_menu,
1245 "varsheet-row-menu", var_sheet_variable_popup_menu,
1249 gtk_widget_show (GTK_WIDGET (de->data_editor));
1250 gtk_widget_show (box);
1252 ll_push_head (&all_data_windows, &de->ll);
1256 psppire_data_window_dispose (GObject *object)
1258 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1260 if (dw->builder != NULL)
1262 g_object_unref (dw->builder);
1268 g_object_unref (dw->var_store);
1269 dw->var_store = NULL;
1274 g_object_unref (dw->data_store);
1275 dw->data_store = NULL;
1278 if (dw->ll.next != NULL)
1280 ll_remove (&dw->ll);
1284 if (G_OBJECT_CLASS (parent_class)->dispose)
1285 G_OBJECT_CLASS (parent_class)->dispose (object);
1289 psppire_data_window_set_property (GObject *object,
1291 const GValue *value,
1294 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1299 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1302 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1308 psppire_data_window_get_property (GObject *object,
1313 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1318 g_value_set_pointer (value, window->dataset);
1321 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1327 psppire_data_window_new (struct dataset *ds)
1331 if (the_session == NULL)
1332 the_session = session_create ();
1336 static int n_datasets;
1339 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1340 ds = dataset_create (the_session, dataset_name);
1341 free (dataset_name);
1343 assert (dataset_session (ds) == the_session);
1347 psppire_data_window_get_type (),
1348 /* TRANSLATORS: This will form a filename. Please avoid whitespace. */
1349 "description", _("Data Editor"),
1353 if (dataset_name (ds) != NULL)
1354 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1360 psppire_data_window_is_empty (PsppireDataWindow *dw)
1362 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1366 psppire_data_window_iface_init (PsppireWindowIface *iface)
1368 iface->save = save_file;
1369 iface->pick_filename = data_pick_filename;
1370 iface->load = load_file;
1374 psppire_default_data_window (void)
1376 if (ll_is_empty (&all_data_windows))
1377 create_data_window ();
1378 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1382 psppire_data_window_set_default (PsppireDataWindow *pdw)
1384 ll_remove (&pdw->ll);
1385 ll_push_head (&all_data_windows, &pdw->ll);
1389 psppire_data_window_undefault (PsppireDataWindow *pdw)
1391 ll_remove (&pdw->ll);
1392 ll_push_tail (&all_data_windows, &pdw->ll);
1396 psppire_data_window_for_dataset (struct dataset *ds)
1398 PsppireDataWindow *pdw;
1400 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1401 if (pdw->dataset == ds)
1408 create_data_window (void)
1410 gtk_widget_show (psppire_data_window_new (NULL));
1414 open_data_window (PsppireWindow *victim, const char *file_name)
1418 if (PSPPIRE_IS_DATA_WINDOW (victim)
1419 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1420 window = GTK_WIDGET (victim);
1422 window = psppire_data_window_new (NULL);
1424 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1425 gtk_widget_show (window);