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/builder-wrapper.h"
30 #include "ui/gui/chi-square-dialog.h"
31 #include "ui/gui/comments-dialog.h"
32 #include "ui/gui/compute-dialog.h"
33 #include "ui/gui/count-dialog.h"
34 #include "ui/gui/crosstabs-dialog.h"
35 #include "ui/gui/entry-dialog.h"
36 #include "ui/gui/executor.h"
37 #include "ui/gui/find-dialog.h"
38 #include "ui/gui/frequencies-dialog.h"
39 #include "ui/gui/goto-case-dialog.h"
40 #include "ui/gui/help-menu.h"
41 #include "ui/gui/helper.h"
42 #include "ui/gui/helper.h"
43 #include "ui/gui/k-related-dialog.h"
44 #include "ui/gui/npar-two-sample-related.h"
45 #include "ui/gui/oneway-anova-dialog.h"
46 #include "ui/gui/psppire-data-window.h"
47 #include "ui/gui/psppire-syntax-window.h"
48 #include "ui/gui/psppire-window.h"
49 #include "ui/gui/psppire.h"
50 #include "ui/gui/runs-dialog.h"
51 #include "ui/gui/ks-one-sample-dialog.h"
52 #include "ui/gui/recode-dialog.h"
53 #include "ui/gui/select-cases-dialog.h"
54 #include "ui/gui/split-file-dialog.h"
55 #include "ui/gui/t-test-one-sample.h"
56 #include "ui/gui/t-test-paired-samples.h"
57 #include "ui/gui/text-data-import-dialog.h"
58 #include "ui/gui/transpose-dialog.h"
59 #include "ui/gui/univariate-dialog.h"
60 #include "ui/gui/weight-cases-dialog.h"
61 #include "ui/syntax-gen.h"
63 #include "gl/c-strcase.h"
64 #include "gl/c-strcasestr.h"
65 #include "gl/xvasprintf.h"
68 #define _(msgid) gettext (msgid)
69 #define N_(msgid) msgid
71 struct session *the_session;
72 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
74 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
75 static void psppire_data_window_init (PsppireDataWindow *data_editor);
78 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
80 static void psppire_data_window_dispose (GObject *object);
81 static void psppire_data_window_finalize (GObject *object);
82 static void psppire_data_window_set_property (GObject *object,
86 static void psppire_data_window_get_property (GObject *object,
92 psppire_data_window_get_type (void)
94 static GType psppire_data_window_type = 0;
96 if (!psppire_data_window_type)
98 static const GTypeInfo psppire_data_window_info =
100 sizeof (PsppireDataWindowClass),
103 (GClassInitFunc)psppire_data_window_class_init,
104 (GClassFinalizeFunc) NULL,
106 sizeof (PsppireDataWindow),
108 (GInstanceInitFunc) psppire_data_window_init,
111 static const GInterfaceInfo window_interface_info =
113 (GInterfaceInitFunc) psppire_data_window_iface_init,
118 psppire_data_window_type =
119 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
120 &psppire_data_window_info, 0);
123 g_type_add_interface_static (psppire_data_window_type,
124 PSPPIRE_TYPE_WINDOW_MODEL,
125 &window_interface_info);
128 return psppire_data_window_type;
131 static GObjectClass *parent_class ;
138 psppire_data_window_class_init (PsppireDataWindowClass *class)
140 GObjectClass *object_class = G_OBJECT_CLASS (class);
142 parent_class = g_type_class_peek_parent (class);
144 object_class->dispose = psppire_data_window_dispose;
145 object_class->finalize = psppire_data_window_finalize;
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 g_object_unref (dict);
956 de->data_store = psppire_data_store_new (dict);
957 psppire_data_store_set_reader (de->data_store, NULL);
959 menubar = get_widget_assert (de->builder, "menubar");
960 hb = get_widget_assert (de->builder, "handlebox1");
961 sb = get_widget_assert (de->builder, "status-bar");
964 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
967 g_signal_connect_swapped (de->data_store, "case-changed",
968 G_CALLBACK (set_unsaved), de);
970 g_signal_connect_swapped (de->data_store, "case-inserted",
971 G_CALLBACK (set_unsaved), de);
973 g_signal_connect_swapped (de->data_store, "cases-deleted",
974 G_CALLBACK (set_unsaved), de);
976 dataset_set_callbacks (de->dataset, &cbs, de);
978 connect_help (de->builder);
980 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
981 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
982 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
983 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
985 gtk_container_add (GTK_CONTAINER (de), box);
987 set_cut_copy_menuitem_sensitivity (de, FALSE);
989 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
990 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
993 set_paste_menuitem_sensitivity (de, FALSE);
995 g_signal_connect_swapped (de->data_editor, "data-available-changed",
996 G_CALLBACK (set_paste_menuitem_sensitivity), de);
998 g_signal_connect (dict, "weight-changed",
999 G_CALLBACK (on_weight_change),
1002 g_signal_connect (dict, "filter-changed",
1003 G_CALLBACK (on_filter_change),
1006 g_signal_connect (dict, "split-changed",
1007 G_CALLBACK (on_split_change),
1011 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1013 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1015 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1017 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1019 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1021 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1023 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1025 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1027 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1029 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1031 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1033 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1035 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1037 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1039 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1042 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1044 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1046 gtk_action_set_visible (de->delete_cases, FALSE);
1051 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1053 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1055 gtk_action_set_visible (de->delete_variables, FALSE);
1059 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1060 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1061 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1062 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1063 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1064 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1065 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1066 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1067 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1068 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1069 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1070 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1071 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1072 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1073 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1074 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1075 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1076 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1077 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1078 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1079 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1080 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1081 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1084 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1086 GtkWidget *recent_data =
1087 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1089 GtkWidget *recent_files =
1090 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1093 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1094 gtk_recent_manager_get_default ());
1096 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1097 gtk_recent_manager_get_default ());
1099 g_object_set (menu_data, "show-tips", TRUE, NULL);
1100 g_object_set (menu_files, "show-tips", TRUE, NULL);
1103 GtkRecentFilter *filter = gtk_recent_filter_new ();
1105 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1106 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1108 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1110 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1113 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1116 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1119 GtkRecentFilter *filter = gtk_recent_filter_new ();
1121 gtk_recent_filter_add_pattern (filter, "*.sps");
1122 gtk_recent_filter_add_pattern (filter, "*.SPS");
1124 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1126 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1129 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1131 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1135 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1138 g_signal_connect (de->data_editor,
1140 G_CALLBACK (enable_delete_cases),
1143 g_signal_connect (de->data_editor,
1144 "variables-selected",
1145 G_CALLBACK (enable_delete_variables),
1149 g_signal_connect (de->data_editor,
1151 G_CALLBACK (on_switch_sheet), de);
1153 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1154 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1156 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1158 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1160 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1162 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1164 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1166 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1168 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1170 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1172 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1175 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1177 merge_help_menu (uim);
1181 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1182 "datasheet-cases-popup");
1184 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1185 "varsheet-variable-popup");
1187 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1188 "datasheet-variable-popup");
1190 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1191 G_CALLBACK (psppire_data_editor_sort_ascending),
1194 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1195 G_CALLBACK (psppire_data_editor_sort_descending),
1198 g_object_set (de->data_editor,
1199 "datasheet-column-menu", data_sheet_variable_popup_menu,
1200 "datasheet-row-menu", data_sheet_cases_popup_menu,
1201 "varsheet-row-menu", var_sheet_variable_popup_menu,
1205 gtk_widget_show (GTK_WIDGET (de->data_editor));
1206 gtk_widget_show (box);
1208 ll_push_head (&all_data_windows, &de->ll);
1212 psppire_data_window_dispose (GObject *object)
1214 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1216 if (dw->builder != NULL)
1218 g_object_unref (dw->builder);
1224 g_object_unref (dw->var_store);
1225 dw->var_store = NULL;
1230 g_object_unref (dw->data_store);
1231 dw->data_store = NULL;
1234 if (dw->ll.next != NULL)
1236 ll_remove (&dw->ll);
1240 if (G_OBJECT_CLASS (parent_class)->dispose)
1241 G_OBJECT_CLASS (parent_class)->dispose (object);
1245 psppire_data_window_finalize (GObject *object)
1247 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1251 struct dataset *dataset = dw->dataset;
1252 struct session *session = dataset_session (dataset);
1256 dataset_set_callbacks (dataset, NULL, NULL);
1257 session_set_active_dataset (session, NULL);
1258 dataset_destroy (dataset);
1261 if (G_OBJECT_CLASS (parent_class)->finalize)
1262 G_OBJECT_CLASS (parent_class)->finalize (object);
1266 psppire_data_window_set_property (GObject *object,
1268 const GValue *value,
1271 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1276 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1279 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1285 psppire_data_window_get_property (GObject *object,
1290 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1295 g_value_set_pointer (value, window->dataset);
1298 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1304 psppire_data_window_new (struct dataset *ds)
1308 if (the_session == NULL)
1309 the_session = session_create ();
1313 char *dataset_name = session_generate_dataset_name (the_session);
1314 ds = dataset_create (the_session, dataset_name);
1315 free (dataset_name);
1317 assert (dataset_session (ds) == the_session);
1321 psppire_data_window_get_type (),
1322 "description", _("Data Editor"),
1326 if (dataset_name (ds) != NULL)
1327 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1333 psppire_data_window_is_empty (PsppireDataWindow *dw)
1335 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1339 psppire_data_window_iface_init (PsppireWindowIface *iface)
1341 iface->save = save_file;
1342 iface->pick_filename = data_pick_filename;
1343 iface->load = load_file;
1347 psppire_default_data_window (void)
1349 if (ll_is_empty (&all_data_windows))
1350 create_data_window ();
1351 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1355 psppire_data_window_set_default (PsppireDataWindow *pdw)
1357 ll_remove (&pdw->ll);
1358 ll_push_head (&all_data_windows, &pdw->ll);
1362 psppire_data_window_undefault (PsppireDataWindow *pdw)
1364 ll_remove (&pdw->ll);
1365 ll_push_tail (&all_data_windows, &pdw->ll);
1369 psppire_data_window_for_dataset (struct dataset *ds)
1371 PsppireDataWindow *pdw;
1373 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1374 if (pdw->dataset == ds)
1381 create_data_window (void)
1383 gtk_widget_show (psppire_data_window_new (NULL));
1387 open_data_window (PsppireWindow *victim, const char *file_name)
1391 if (PSPPIRE_IS_DATA_WINDOW (victim)
1392 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1393 window = GTK_WIDGET (victim);
1395 window = psppire_data_window_new (NULL);
1397 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1398 gtk_widget_show (window);