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/executor.h"
38 #include "ui/gui/find-dialog.h"
39 #include "ui/gui/frequencies-dialog.h"
40 #include "ui/gui/goto-case-dialog.h"
41 #include "ui/gui/help-menu.h"
42 #include "ui/gui/helper.h"
43 #include "ui/gui/helper.h"
44 #include "ui/gui/k-related-dialog.h"
45 #include "ui/gui/npar-two-sample-related.h"
46 #include "ui/gui/oneway-anova-dialog.h"
47 #include "ui/gui/psppire-data-window.h"
48 #include "ui/gui/psppire-syntax-window.h"
49 #include "ui/gui/psppire-window.h"
50 #include "ui/gui/psppire.h"
51 #include "ui/gui/runs-dialog.h"
52 #include "ui/gui/ks-one-sample-dialog.h"
53 #include "ui/gui/recode-dialog.h"
54 #include "ui/gui/regression-dialog.h"
55 #include "ui/gui/select-cases-dialog.h"
56 #include "ui/gui/split-file-dialog.h"
57 #include "ui/gui/t-test-one-sample.h"
58 #include "ui/gui/t-test-paired-samples.h"
59 #include "ui/gui/text-data-import-dialog.h"
60 #include "ui/gui/transpose-dialog.h"
61 #include "ui/gui/univariate-dialog.h"
62 #include "ui/gui/weight-cases-dialog.h"
63 #include "ui/syntax-gen.h"
65 #include "gl/c-strcase.h"
66 #include "gl/c-strcasestr.h"
67 #include "gl/xvasprintf.h"
70 #define _(msgid) gettext (msgid)
71 #define N_(msgid) msgid
73 struct session *the_session;
74 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
76 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
77 static void psppire_data_window_init (PsppireDataWindow *data_editor);
80 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
82 static void psppire_data_window_dispose (GObject *object);
83 static void psppire_data_window_set_property (GObject *object,
87 static void psppire_data_window_get_property (GObject *object,
93 psppire_data_window_get_type (void)
95 static GType psppire_data_window_type = 0;
97 if (!psppire_data_window_type)
99 static const GTypeInfo psppire_data_window_info =
101 sizeof (PsppireDataWindowClass),
104 (GClassInitFunc)psppire_data_window_class_init,
105 (GClassFinalizeFunc) NULL,
107 sizeof (PsppireDataWindow),
109 (GInstanceInitFunc) psppire_data_window_init,
112 static const GInterfaceInfo window_interface_info =
114 (GInterfaceInitFunc) psppire_data_window_iface_init,
119 psppire_data_window_type =
120 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
121 &psppire_data_window_info, 0);
124 g_type_add_interface_static (psppire_data_window_type,
125 PSPPIRE_TYPE_WINDOW_MODEL,
126 &window_interface_info);
129 return psppire_data_window_type;
132 static GObjectClass *parent_class ;
139 psppire_data_window_class_init (PsppireDataWindowClass *class)
141 GObjectClass *object_class = G_OBJECT_CLASS (class);
143 parent_class = g_type_class_peek_parent (class);
145 object_class->dispose = psppire_data_window_dispose;
146 object_class->set_property = psppire_data_window_set_property;
147 object_class->get_property = psppire_data_window_get_property;
149 g_object_class_install_property (
150 object_class, PROP_DATASET,
151 g_param_spec_pointer ("dataset", "Dataset",
152 "'struct datset *' represented by the window",
153 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
157 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
159 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
161 gtk_action_set_sensitive (edit_paste, x);
165 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
167 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
168 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
170 gtk_action_set_sensitive (edit_copy, x);
171 gtk_action_set_sensitive (edit_cut, x);
174 /* Run the EXECUTE command. */
176 execute (PsppireDataWindow *dw)
178 execute_const_syntax_string (dw, "EXECUTE.");
182 transformation_change_callback (bool transformations_pending,
185 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
187 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
189 GtkWidget *menuitem =
190 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
192 GtkWidget *status_label =
193 get_widget_assert (de->builder, "case-counter-area");
195 gtk_widget_set_sensitive (menuitem, transformations_pending);
198 if ( transformations_pending)
199 gtk_label_set_text (GTK_LABEL (status_label),
200 _("Transformations Pending"));
202 gtk_label_set_text (GTK_LABEL (status_label), "");
205 /* Callback for when the dictionary changes its filter variable */
207 on_filter_change (GObject *o, gint filter_index, gpointer data)
209 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
211 GtkWidget *filter_status_area =
212 get_widget_assert (de->builder, "filter-use-status-area");
214 if ( filter_index == -1 )
216 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
220 PsppireVarStore *vs = NULL;
221 PsppireDict *dict = NULL;
222 struct variable *var ;
225 g_object_get (de->data_editor, "var-store", &vs, NULL);
226 g_object_get (vs, "dictionary", &dict, NULL);
228 var = psppire_dict_get_variable (dict, filter_index);
230 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
232 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
238 /* Callback for when the dictionary changes its split variables */
240 on_split_change (PsppireDict *dict, gpointer data)
242 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
244 size_t n_split_vars = dict_get_split_cnt (dict->dict);
246 GtkWidget *split_status_area =
247 get_widget_assert (de->builder, "split-file-status-area");
249 if ( n_split_vars == 0 )
251 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
257 const struct variable *const * split_vars =
258 dict_get_split_vars (dict->dict);
260 text = g_string_new (_("Split by "));
262 for (i = 0 ; i < n_split_vars - 1; ++i )
264 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
266 g_string_append (text, var_get_name (split_vars[i]));
268 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
270 g_string_free (text, TRUE);
277 /* Callback for when the dictionary changes its weights */
279 on_weight_change (GObject *o, gint weight_index, gpointer data)
281 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
283 GtkWidget *weight_status_area =
284 get_widget_assert (de->builder, "weight-status-area");
286 if ( weight_index == -1 )
288 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
292 struct variable *var ;
293 PsppireVarStore *vs = NULL;
294 PsppireDict *dict = NULL;
297 g_object_get (de->data_editor, "var-store", &vs, NULL);
298 g_object_get (vs, "dictionary", &dict, NULL);
300 var = psppire_dict_get_variable (dict, weight_index);
302 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
304 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
312 dump_rm (GtkRecentManager *rm)
314 GList *items = gtk_recent_manager_get_items (rm);
318 g_print ("Recent Items:\n");
319 for (i = items; i; i = i->next)
321 GtkRecentInfo *ri = i->data;
323 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
324 gtk_recent_info_get_short_name (ri),
325 gtk_recent_info_get_mime_type (ri),
326 gtk_recent_info_get_description (ri),
327 gtk_recent_info_get_uri (ri)
331 gtk_recent_info_unref (ri);
339 name_has_por_suffix (const gchar *name)
341 size_t length = strlen (name);
342 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
346 name_has_sav_suffix (const gchar *name)
348 size_t length = strlen (name);
349 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
352 /* Returns true if NAME has a suffix which might denote a PSPP file */
354 name_has_suffix (const gchar *name)
356 return name_has_por_suffix (name) || name_has_sav_suffix (name);
360 load_file (PsppireWindow *de, const gchar *file_name)
362 struct string filename;
363 gchar *utf8_file_name;
364 const char *mime_type;
368 ds_init_empty (&filename);
370 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
372 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
374 g_free (utf8_file_name);
376 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
377 ds_destroy (&filename);
379 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
380 lex_reader_for_string (syntax));
383 mime_type = (name_has_por_suffix (file_name)
384 ? "application/x-spss-por"
385 : "application/x-spss-sav");
387 add_most_recent (file_name, mime_type);
392 /* Save DE to file */
394 save_file (PsppireWindow *w)
396 const gchar *file_name = NULL;
397 gchar *utf8_file_name = NULL;
399 struct string filename ;
400 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
403 file_name = psppire_window_get_filename (w);
405 fnx = g_string_new (file_name);
407 if ( ! name_has_suffix (fnx->str))
409 if ( de->save_as_portable)
410 g_string_append (fnx, ".por");
412 g_string_append (fnx, ".sav");
415 ds_init_empty (&filename);
417 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
419 g_string_free (fnx, TRUE);
421 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
422 g_free (utf8_file_name);
424 syntax = g_strdup_printf ("%s OUTFILE=%s.",
425 de->save_as_portable ? "EXPORT" : "SAVE",
426 ds_cstr (&filename));
428 ds_destroy (&filename);
430 g_free (execute_syntax_string (de, syntax));
435 insert_case (PsppireDataWindow *dw)
437 psppire_data_editor_insert_case (dw->data_editor);
441 on_insert_variable (PsppireDataWindow *dw)
443 psppire_data_editor_insert_variable (dw->data_editor);
448 display_dict (PsppireDataWindow *de)
450 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
454 sysfile_info (PsppireDataWindow *de)
456 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
458 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
460 struct string filename;
462 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
464 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
469 ds_init_empty (&filename);
471 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
473 g_free (utf8_file_name);
475 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
476 g_free (execute_syntax_string (de, syntax));
479 gtk_widget_destroy (dialog);
483 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
485 data_pick_filename (PsppireWindow *window)
487 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
488 GtkFileFilter *filter = gtk_file_filter_new ();
489 GtkWidget *button_sys;
491 gtk_file_chooser_dialog_new (_("Save"),
493 GTK_FILE_CHOOSER_ACTION_SAVE,
494 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
495 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
498 g_object_set (dialog, "local-only", FALSE, NULL);
500 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
501 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
502 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
504 filter = gtk_file_filter_new ();
505 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
506 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
507 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
509 filter = gtk_file_filter_new ();
510 gtk_file_filter_set_name (filter, _("All Files"));
511 gtk_file_filter_add_pattern (filter, "*");
512 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
515 GtkWidget *button_por;
516 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
518 gtk_radio_button_new_with_label (NULL, _("System File"));
521 gtk_radio_button_new_with_label
522 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
525 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
526 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
528 gtk_widget_show_all (vbox);
530 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
533 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
536 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
538 case GTK_RESPONSE_ACCEPT:
543 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
546 de->save_as_portable =
547 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
549 if ( ! name_has_suffix (filename->str))
551 if ( de->save_as_portable)
552 g_string_append (filename, ".por");
554 g_string_append (filename, ".sav");
557 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
559 g_string_free (filename, TRUE);
566 gtk_widget_destroy (dialog);
570 confirm_delete_dataset (PsppireDataWindow *de,
571 const char *old_dataset,
572 const char *new_dataset,
573 const char *existing_dataset)
578 dialog = gtk_message_dialog_new (
579 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
580 _("Delete Existing Dataset?"));
582 gtk_message_dialog_format_secondary_text (
583 GTK_MESSAGE_DIALOG (dialog),
584 _("Renaming \"%s\" to \"%s\" will destroy the existing "
585 "dataset named \"%s\". Are you sure that you want to do this?"),
586 old_dataset, new_dataset, existing_dataset);
588 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
589 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
590 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
593 g_object_set (dialog, "icon-name", "pspp", NULL);
595 result = gtk_dialog_run (GTK_DIALOG (dialog));
597 gtk_widget_destroy (dialog);
599 return result == GTK_RESPONSE_OK;
603 on_rename_dataset (PsppireDataWindow *de)
605 struct dataset *ds = de->dataset;
606 struct session *session = dataset_session (ds);
607 const char *old_name = dataset_name (ds);
608 struct dataset *existing_dataset;
612 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
614 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
618 if (new_name == NULL)
621 existing_dataset = session_lookup_dataset (session, new_name);
622 if (existing_dataset == NULL || existing_dataset == ds
623 || confirm_delete_dataset (de, old_name, new_name,
624 dataset_name (existing_dataset)))
625 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
632 on_edit_paste (PsppireDataWindow *de)
634 psppire_data_editor_clip_paste (de->data_editor);
638 on_edit_copy (PsppireDataWindow *de)
640 psppire_data_editor_clip_copy (de->data_editor);
646 on_edit_cut (PsppireDataWindow *de)
648 psppire_data_editor_clip_cut (de->data_editor);
653 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
655 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
657 if ( gtk_toggle_action_get_active (action))
658 gtk_widget_show (statusbar);
660 gtk_widget_hide (statusbar);
665 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
667 const gboolean grid_visible = gtk_toggle_action_get_active (action);
669 psppire_data_editor_show_grid (de->data_editor, grid_visible);
673 data_view_activate (PsppireDataWindow *de)
675 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
680 variable_view_activate (PsppireDataWindow *de)
682 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
687 fonts_activate (PsppireDataWindow *de)
689 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
690 PangoFontDescription *current_font;
693 gtk_font_selection_dialog_new (_("Font Selection"));
696 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
697 font_name = pango_font_description_to_string (current_font);
699 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
703 gtk_window_set_transient_for (GTK_WINDOW (dialog),
704 GTK_WINDOW (toplevel));
706 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
708 const gchar *font = gtk_font_selection_dialog_get_font_name
709 (GTK_FONT_SELECTION_DIALOG (dialog));
711 PangoFontDescription* font_desc =
712 pango_font_description_from_string (font);
714 psppire_data_editor_set_font (de->data_editor, font_desc);
717 gtk_widget_hide (dialog);
722 /* Callback for the value labels action */
724 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
726 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
730 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
732 psppire_data_editor_split_window (de->data_editor,
733 gtk_toggle_action_get_active (ta));
738 file_quit (PsppireDataWindow *de)
740 /* FIXME: Need to be more intelligent here.
741 Give the user the opportunity to save any unsaved data.
748 on_recent_data_select (GtkMenuShell *menushell,
749 PsppireWindow *window)
754 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
756 file = g_filename_from_uri (uri, NULL, NULL);
760 open_data_window (window, file);
766 charset_from_mime_type (const char *mime_type)
772 if (mime_type == NULL)
775 charset = c_strcasestr (mime_type, "charset=");
783 /* Parse a "quoted-string" as defined by RFC 822. */
784 for (p++; *p != '\0' && *p != '"'; p++)
787 ds_put_byte (&s, *p);
788 else if (*++p != '\0')
789 ds_put_byte (&s, *p);
794 /* Parse a "token" as defined by RFC 2045. */
795 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
796 ds_put_byte (&s, *p++);
798 if (!ds_is_empty (&s))
799 return ds_steal_cstr (&s);
806 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
813 /* Get the file name and its encoding. */
814 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
815 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
816 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
817 gtk_recent_info_unref (item);
819 se = psppire_syntax_window_new (encoding);
823 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
824 gtk_widget_show (se);
826 gtk_widget_destroy (se);
834 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
836 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
838 gtk_action_set_visible (de->delete_cases, case_num != -1);
843 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
845 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
847 gtk_action_set_visible (de->delete_variables, var != -1);
850 /* Callback for when the datasheet/varsheet is selected */
852 on_switch_sheet (GtkNotebook *notebook,
853 GtkNotebookPage *page,
857 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
859 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
861 GtkWidget *view_data =
862 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
864 GtkWidget *view_variables =
865 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
869 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
870 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
872 gtk_action_set_sensitive (de->insert_variable, TRUE);
873 gtk_action_set_sensitive (de->insert_case, FALSE);
874 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
876 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
877 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
878 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
879 gtk_action_set_sensitive (de->insert_case, TRUE);
882 g_assert_not_reached ();
887 update_paste_menuitem (de, page_num);
894 set_unsaved (gpointer w)
896 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
900 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
901 Returns a pointer to the action
904 connect_action (PsppireDataWindow *dw, const char *action_name,
907 GtkAction *action = get_action_assert (dw->builder, action_name);
909 g_signal_connect_swapped (action, "activate", handler, dw);
914 /* Initializes as much of a PsppireDataWindow as we can and must before the
915 dataset has been set.
917 In particular, the 'menu' member is required in case the "filename" property
918 is set before the "dataset" property: otherwise PsppireWindow will try to
919 modify the menu as part of the "filename" property_set() function and end up
920 with a Gtk-CRITICAL since 'menu' is NULL. */
922 psppire_data_window_init (PsppireDataWindow *de)
926 de->builder = builder_new ("data-editor.ui");
928 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
930 PSPPIRE_WINDOW (de)->menu =
931 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
935 psppire_data_window_finish_init (PsppireDataWindow *de,
938 static const struct dataset_callbacks cbs =
940 set_unsaved, /* changed */
941 transformation_change_callback, /* transformations_changed */
950 GtkWidget *box = gtk_vbox_new (FALSE, 0);
953 dict = psppire_dict_new_from_dict (dataset_dict (ds));
954 de->var_store = psppire_var_store_new (dict);
955 de->data_store = psppire_data_store_new (dict);
956 psppire_data_store_set_reader (de->data_store, NULL);
958 menubar = get_widget_assert (de->builder, "menubar");
959 hb = get_widget_assert (de->builder, "handlebox1");
960 sb = get_widget_assert (de->builder, "status-bar");
963 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
966 g_signal_connect_swapped (de->data_store, "case-changed",
967 G_CALLBACK (set_unsaved), de);
969 g_signal_connect_swapped (de->data_store, "case-inserted",
970 G_CALLBACK (set_unsaved), de);
972 g_signal_connect_swapped (de->data_store, "cases-deleted",
973 G_CALLBACK (set_unsaved), de);
975 dataset_set_callbacks (de->dataset, &cbs, de);
977 connect_help (de->builder);
979 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
980 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
981 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
982 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
984 gtk_container_add (GTK_CONTAINER (de), box);
986 set_cut_copy_menuitem_sensitivity (de, FALSE);
988 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
989 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
992 set_paste_menuitem_sensitivity (de, FALSE);
994 g_signal_connect_swapped (de->data_editor, "data-available-changed",
995 G_CALLBACK (set_paste_menuitem_sensitivity), de);
997 g_signal_connect (dict, "weight-changed",
998 G_CALLBACK (on_weight_change),
1001 g_signal_connect (dict, "filter-changed",
1002 G_CALLBACK (on_filter_change),
1005 g_signal_connect (dict, "split-changed",
1006 G_CALLBACK (on_split_change),
1010 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1012 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1014 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1016 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1018 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1020 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1022 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1024 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1026 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1028 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1030 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1032 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1034 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1036 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1038 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1041 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1043 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1045 gtk_action_set_visible (de->delete_cases, FALSE);
1050 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1052 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1054 gtk_action_set_visible (de->delete_variables, FALSE);
1058 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1059 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1060 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1061 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1062 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1063 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1064 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1065 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1066 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1067 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1068 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1069 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1070 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1071 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1072 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1073 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1074 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1075 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1076 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1077 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1078 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1079 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1080 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1081 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1082 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1085 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1087 GtkWidget *recent_data =
1088 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1090 GtkWidget *recent_files =
1091 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1094 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1095 gtk_recent_manager_get_default ());
1097 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1098 gtk_recent_manager_get_default ());
1100 g_object_set (menu_data, "show-tips", TRUE, NULL);
1101 g_object_set (menu_files, "show-tips", TRUE, NULL);
1104 GtkRecentFilter *filter = gtk_recent_filter_new ();
1106 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1107 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1109 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1111 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1114 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1117 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1120 GtkRecentFilter *filter = gtk_recent_filter_new ();
1122 gtk_recent_filter_add_pattern (filter, "*.sps");
1123 gtk_recent_filter_add_pattern (filter, "*.SPS");
1125 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1127 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1130 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1132 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1136 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1139 g_signal_connect (de->data_editor,
1141 G_CALLBACK (enable_delete_cases),
1144 g_signal_connect (de->data_editor,
1145 "variables-selected",
1146 G_CALLBACK (enable_delete_variables),
1150 g_signal_connect (de->data_editor,
1152 G_CALLBACK (on_switch_sheet), de);
1154 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1155 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1157 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1159 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1161 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1163 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1165 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1167 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1169 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1171 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1173 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1176 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1178 merge_help_menu (uim);
1182 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1183 "datasheet-cases-popup");
1185 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1186 "varsheet-variable-popup");
1188 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1189 "datasheet-variable-popup");
1191 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1192 G_CALLBACK (psppire_data_editor_sort_ascending),
1195 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1196 G_CALLBACK (psppire_data_editor_sort_descending),
1199 g_object_set (de->data_editor,
1200 "datasheet-column-menu", data_sheet_variable_popup_menu,
1201 "datasheet-row-menu", data_sheet_cases_popup_menu,
1202 "varsheet-row-menu", var_sheet_variable_popup_menu,
1206 gtk_widget_show (GTK_WIDGET (de->data_editor));
1207 gtk_widget_show (box);
1209 ll_push_head (&all_data_windows, &de->ll);
1213 psppire_data_window_dispose (GObject *object)
1215 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1217 if (dw->builder != NULL)
1219 g_object_unref (dw->builder);
1225 g_object_unref (dw->var_store);
1226 dw->var_store = NULL;
1231 g_object_unref (dw->data_store);
1232 dw->data_store = NULL;
1235 if (dw->ll.next != NULL)
1237 ll_remove (&dw->ll);
1241 if (G_OBJECT_CLASS (parent_class)->dispose)
1242 G_OBJECT_CLASS (parent_class)->dispose (object);
1246 psppire_data_window_set_property (GObject *object,
1248 const GValue *value,
1251 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1256 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1259 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1265 psppire_data_window_get_property (GObject *object,
1270 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1275 g_value_set_pointer (value, window->dataset);
1278 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1284 psppire_data_window_new (struct dataset *ds)
1288 if (the_session == NULL)
1289 the_session = session_create ();
1293 static int n_datasets;
1296 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1297 ds = dataset_create (the_session, dataset_name);
1298 free (dataset_name);
1300 assert (dataset_session (ds) == the_session);
1304 psppire_data_window_get_type (),
1305 "description", _("Data Editor"),
1309 if (dataset_name (ds) != NULL)
1310 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1316 psppire_data_window_is_empty (PsppireDataWindow *dw)
1318 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1322 psppire_data_window_iface_init (PsppireWindowIface *iface)
1324 iface->save = save_file;
1325 iface->pick_filename = data_pick_filename;
1326 iface->load = load_file;
1330 psppire_default_data_window (void)
1332 if (ll_is_empty (&all_data_windows))
1333 create_data_window ();
1334 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1338 psppire_data_window_set_default (PsppireDataWindow *pdw)
1340 ll_remove (&pdw->ll);
1341 ll_push_head (&all_data_windows, &pdw->ll);
1345 psppire_data_window_undefault (PsppireDataWindow *pdw)
1347 ll_remove (&pdw->ll);
1348 ll_push_tail (&all_data_windows, &pdw->ll);
1352 psppire_data_window_for_dataset (struct dataset *ds)
1354 PsppireDataWindow *pdw;
1356 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1357 if (pdw->dataset == ds)
1364 create_data_window (void)
1366 gtk_widget_show (psppire_data_window_new (NULL));
1370 open_data_window (PsppireWindow *victim, const char *file_name)
1374 if (PSPPIRE_IS_DATA_WINDOW (victim)
1375 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1376 window = GTK_WIDGET (victim);
1378 window = psppire_data_window_new (NULL);
1380 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1381 gtk_widget_show (window);