1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/binomial-dialog.h"
30 #include "ui/gui/chi-square-dialog.h"
31 #include "ui/gui/comments-dialog.h"
32 #include "ui/gui/compute-dialog.h"
33 #include "ui/gui/correlation-dialog.h"
34 #include "ui/gui/count-dialog.h"
35 #include "ui/gui/crosstabs-dialog.h"
36 #include "ui/gui/descriptives-dialog.h"
37 #include "ui/gui/entry-dialog.h"
38 #include "ui/gui/examine-dialog.h"
39 #include "ui/gui/executor.h"
40 #include "ui/gui/factor-dialog.h"
41 #include "ui/gui/find-dialog.h"
42 #include "ui/gui/frequencies-dialog.h"
43 #include "ui/gui/goto-case-dialog.h"
44 #include "ui/gui/help-menu.h"
45 #include "ui/gui/helper.h"
46 #include "ui/gui/k-means-dialog.h"
47 #include "ui/gui/k-related-dialog.h"
48 #include "ui/gui/npar-two-sample-related.h"
49 #include "ui/gui/oneway-anova-dialog.h"
50 #include "ui/gui/psppire-data-window.h"
51 #include "ui/gui/psppire-syntax-window.h"
52 #include "ui/gui/psppire-window.h"
53 #include "ui/gui/psppire.h"
54 #include "ui/gui/rank-dialog.h"
55 #include "ui/gui/recode-dialog.h"
56 #include "ui/gui/regression-dialog.h"
57 #include "ui/gui/reliability-dialog.h"
58 #include "ui/gui/roc-dialog.h"
59 #include "ui/gui/select-cases-dialog.h"
60 #include "ui/gui/sort-cases-dialog.h"
61 #include "ui/gui/split-file-dialog.h"
62 #include "ui/gui/t-test-independent-samples-dialog.h"
63 #include "ui/gui/t-test-one-sample.h"
64 #include "ui/gui/t-test-paired-samples.h"
65 #include "ui/gui/text-data-import-dialog.h"
66 #include "ui/gui/transpose-dialog.h"
67 #include "ui/gui/variable-info-dialog.h"
68 #include "ui/gui/weight-cases-dialog.h"
69 #include "ui/syntax-gen.h"
71 #include "gl/c-strcase.h"
72 #include "gl/c-strcasestr.h"
73 #include "gl/xvasprintf.h"
76 #define _(msgid) gettext (msgid)
77 #define N_(msgid) msgid
79 struct session *the_session;
80 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
82 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
83 static void psppire_data_window_init (PsppireDataWindow *data_editor);
86 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
88 static void psppire_data_window_dispose (GObject *object);
89 static void psppire_data_window_set_property (GObject *object,
93 static void psppire_data_window_get_property (GObject *object,
99 psppire_data_window_get_type (void)
101 static GType psppire_data_window_type = 0;
103 if (!psppire_data_window_type)
105 static const GTypeInfo psppire_data_window_info =
107 sizeof (PsppireDataWindowClass),
110 (GClassInitFunc)psppire_data_window_class_init,
111 (GClassFinalizeFunc) NULL,
113 sizeof (PsppireDataWindow),
115 (GInstanceInitFunc) psppire_data_window_init,
118 static const GInterfaceInfo window_interface_info =
120 (GInterfaceInitFunc) psppire_data_window_iface_init,
125 psppire_data_window_type =
126 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
127 &psppire_data_window_info, 0);
130 g_type_add_interface_static (psppire_data_window_type,
131 PSPPIRE_TYPE_WINDOW_MODEL,
132 &window_interface_info);
135 return psppire_data_window_type;
138 static GObjectClass *parent_class ;
145 psppire_data_window_class_init (PsppireDataWindowClass *class)
147 GObjectClass *object_class = G_OBJECT_CLASS (class);
149 parent_class = g_type_class_peek_parent (class);
151 object_class->dispose = psppire_data_window_dispose;
152 object_class->set_property = psppire_data_window_set_property;
153 object_class->get_property = psppire_data_window_get_property;
155 g_object_class_install_property (
156 object_class, PROP_DATASET,
157 g_param_spec_pointer ("dataset", "Dataset",
158 "'struct datset *' represented by the window",
159 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
163 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
165 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
167 gtk_action_set_sensitive (edit_paste, x);
171 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
173 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
174 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
176 gtk_action_set_sensitive (edit_copy, x);
177 gtk_action_set_sensitive (edit_cut, x);
180 /* Run the EXECUTE command. */
182 execute (PsppireDataWindow *dw)
184 execute_const_syntax_string (dw, "EXECUTE.");
188 transformation_change_callback (bool transformations_pending,
191 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
193 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
195 GtkWidget *menuitem =
196 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
198 GtkWidget *status_label =
199 get_widget_assert (de->builder, "case-counter-area");
201 gtk_widget_set_sensitive (menuitem, transformations_pending);
204 if ( transformations_pending)
205 gtk_label_set_text (GTK_LABEL (status_label),
206 _("Transformations Pending"));
208 gtk_label_set_text (GTK_LABEL (status_label), "");
211 /* Callback for when the dictionary changes its filter variable */
213 on_filter_change (GObject *o, gint filter_index, gpointer data)
215 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
217 GtkWidget *filter_status_area =
218 get_widget_assert (de->builder, "filter-use-status-area");
220 if ( filter_index == -1 )
222 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
226 PsppireVarStore *vs = NULL;
227 PsppireDict *dict = NULL;
228 struct variable *var ;
231 g_object_get (de->data_editor, "var-store", &vs, NULL);
232 g_object_get (vs, "dictionary", &dict, NULL);
234 var = psppire_dict_get_variable (dict, filter_index);
236 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
238 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
244 /* Callback for when the dictionary changes its split variables */
246 on_split_change (PsppireDict *dict, gpointer data)
248 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
250 size_t n_split_vars = dict_get_split_cnt (dict->dict);
252 GtkWidget *split_status_area =
253 get_widget_assert (de->builder, "split-file-status-area");
255 if ( n_split_vars == 0 )
257 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
263 const struct variable *const * split_vars =
264 dict_get_split_vars (dict->dict);
266 text = g_string_new (_("Split by "));
268 for (i = 0 ; i < n_split_vars - 1; ++i )
270 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
272 g_string_append (text, var_get_name (split_vars[i]));
274 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
276 g_string_free (text, TRUE);
283 /* Callback for when the dictionary changes its weights */
285 on_weight_change (GObject *o, gint weight_index, gpointer data)
287 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
289 GtkWidget *weight_status_area =
290 get_widget_assert (de->builder, "weight-status-area");
292 if ( weight_index == -1 )
294 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
298 struct variable *var ;
299 PsppireVarStore *vs = NULL;
300 PsppireDict *dict = NULL;
303 g_object_get (de->data_editor, "var-store", &vs, NULL);
304 g_object_get (vs, "dictionary", &dict, NULL);
306 var = psppire_dict_get_variable (dict, weight_index);
308 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
310 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
318 dump_rm (GtkRecentManager *rm)
320 GList *items = gtk_recent_manager_get_items (rm);
324 g_print ("Recent Items:\n");
325 for (i = items; i; i = i->next)
327 GtkRecentInfo *ri = i->data;
329 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
330 gtk_recent_info_get_short_name (ri),
331 gtk_recent_info_get_mime_type (ri),
332 gtk_recent_info_get_description (ri),
333 gtk_recent_info_get_uri (ri)
337 gtk_recent_info_unref (ri);
345 name_has_por_suffix (const gchar *name)
347 size_t length = strlen (name);
348 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
352 name_has_sav_suffix (const gchar *name)
354 size_t length = strlen (name);
355 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
358 /* Returns true if NAME has a suffix which might denote a PSPP file */
360 name_has_suffix (const gchar *name)
362 return name_has_por_suffix (name) || name_has_sav_suffix (name);
366 load_file (PsppireWindow *de, const gchar *file_name)
368 struct string filename;
369 gchar *utf8_file_name;
370 const char *mime_type;
374 ds_init_empty (&filename);
376 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
378 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
380 g_free (utf8_file_name);
382 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
383 ds_destroy (&filename);
385 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
386 lex_reader_for_string (syntax));
389 mime_type = (name_has_por_suffix (file_name)
390 ? "application/x-spss-por"
391 : "application/x-spss-sav");
393 add_most_recent (file_name, mime_type);
398 /* Save DE to file */
400 save_file (PsppireWindow *w)
402 const gchar *file_name = NULL;
403 gchar *utf8_file_name = NULL;
405 struct string filename ;
406 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
409 file_name = psppire_window_get_filename (w);
411 fnx = g_string_new (file_name);
413 if ( ! name_has_suffix (fnx->str))
415 if ( de->save_as_portable)
416 g_string_append (fnx, ".por");
418 g_string_append (fnx, ".sav");
421 ds_init_empty (&filename);
423 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
425 g_string_free (fnx, TRUE);
427 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
428 g_free (utf8_file_name);
430 syntax = g_strdup_printf ("%s OUTFILE=%s.",
431 de->save_as_portable ? "EXPORT" : "SAVE",
432 ds_cstr (&filename));
434 ds_destroy (&filename);
436 g_free (execute_syntax_string (de, syntax));
441 insert_case (PsppireDataWindow *dw)
443 psppire_data_editor_insert_case (dw->data_editor);
447 on_insert_variable (PsppireDataWindow *dw)
449 psppire_data_editor_insert_variable (dw->data_editor);
454 display_dict (PsppireDataWindow *de)
456 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
460 sysfile_info (PsppireDataWindow *de)
462 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
464 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
466 struct string filename;
468 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
470 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
475 ds_init_empty (&filename);
477 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
479 g_free (utf8_file_name);
481 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
482 g_free (execute_syntax_string (de, syntax));
485 gtk_widget_destroy (dialog);
489 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
491 data_pick_filename (PsppireWindow *window)
493 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
494 GtkWidget *button_sys;
496 gtk_file_chooser_dialog_new (_("Save"),
498 GTK_FILE_CHOOSER_ACTION_SAVE,
499 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
500 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
503 GtkFileFilter *filter = gtk_file_filter_new ();
504 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
505 gtk_file_filter_add_pattern (filter, "*.sav");
506 gtk_file_filter_add_pattern (filter, "*.SAV");
507 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
509 filter = gtk_file_filter_new ();
510 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
511 gtk_file_filter_add_pattern (filter, "*.por");
512 gtk_file_filter_add_pattern (filter, "*.POR");
513 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
515 filter = gtk_file_filter_new ();
516 gtk_file_filter_set_name (filter, _("All Files"));
517 gtk_file_filter_add_pattern (filter, "*");
518 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
521 GtkWidget *button_por;
522 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
524 gtk_radio_button_new_with_label (NULL, _("System File"));
527 gtk_radio_button_new_with_label
528 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
531 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
532 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
534 gtk_widget_show_all (vbox);
536 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
539 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
542 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
544 case GTK_RESPONSE_ACCEPT:
549 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
552 de->save_as_portable =
553 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
555 if ( ! name_has_suffix (filename->str))
557 if ( de->save_as_portable)
558 g_string_append (filename, ".por");
560 g_string_append (filename, ".sav");
563 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
565 g_string_free (filename, TRUE);
572 gtk_widget_destroy (dialog);
576 confirm_delete_dataset (PsppireDataWindow *de,
577 const char *old_dataset,
578 const char *new_dataset,
579 const char *existing_dataset)
584 dialog = gtk_message_dialog_new (
585 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
586 _("Delete Existing Dataset?"));
588 gtk_message_dialog_format_secondary_text (
589 GTK_MESSAGE_DIALOG (dialog),
590 _("Renaming \"%s\" to \"%s\" will delete destroy the existing "
591 "dataset named \"%s\". Are you sure that you want to do this?"),
592 old_dataset, new_dataset, existing_dataset);
594 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
595 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
596 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
599 g_object_set (dialog, "icon-name", "psppicon", NULL);
601 result = gtk_dialog_run (GTK_DIALOG (dialog));
603 gtk_widget_destroy (dialog);
605 return result == GTK_RESPONSE_OK;
609 on_rename_dataset (PsppireDataWindow *de)
611 struct dataset *ds = de->dataset;
612 struct session *session = dataset_session (ds);
613 const char *old_name = dataset_name (ds);
614 struct dataset *existing_dataset;
618 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
620 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
624 if (new_name == NULL)
627 existing_dataset = session_lookup_dataset (session, new_name);
628 if (existing_dataset == NULL || existing_dataset == ds
629 || confirm_delete_dataset (de, old_name, new_name,
630 dataset_name (existing_dataset)))
631 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
638 on_edit_paste (PsppireDataWindow *de)
640 psppire_data_editor_clip_paste (de->data_editor);
644 on_edit_copy (PsppireDataWindow *de)
646 psppire_data_editor_clip_copy (de->data_editor);
652 on_edit_cut (PsppireDataWindow *de)
654 psppire_data_editor_clip_cut (de->data_editor);
659 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
661 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
663 if ( gtk_toggle_action_get_active (action))
664 gtk_widget_show (statusbar);
666 gtk_widget_hide (statusbar);
671 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
673 const gboolean grid_visible = gtk_toggle_action_get_active (action);
675 psppire_data_editor_show_grid (de->data_editor, grid_visible);
679 data_view_activate (PsppireDataWindow *de)
681 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
686 variable_view_activate (PsppireDataWindow *de)
688 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
693 fonts_activate (PsppireDataWindow *de)
695 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
696 PangoFontDescription *current_font;
699 gtk_font_selection_dialog_new (_("Font Selection"));
702 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
703 font_name = pango_font_description_to_string (current_font);
705 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
709 gtk_window_set_transient_for (GTK_WINDOW (dialog),
710 GTK_WINDOW (toplevel));
712 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
714 const gchar *font = gtk_font_selection_dialog_get_font_name
715 (GTK_FONT_SELECTION_DIALOG (dialog));
717 PangoFontDescription* font_desc =
718 pango_font_description_from_string (font);
720 psppire_data_editor_set_font (de->data_editor, font_desc);
723 gtk_widget_hide (dialog);
728 /* Callback for the value labels action */
730 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
732 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
736 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
738 psppire_data_editor_split_window (de->data_editor,
739 gtk_toggle_action_get_active (ta));
744 file_quit (PsppireDataWindow *de)
746 /* FIXME: Need to be more intelligent here.
747 Give the user the opportunity to save any unsaved data.
754 on_recent_data_select (GtkMenuShell *menushell,
755 PsppireWindow *window)
760 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
762 file = g_filename_from_uri (uri, NULL, NULL);
766 open_data_window (window, file);
772 charset_from_mime_type (const char *mime_type)
778 if (mime_type == NULL)
781 charset = c_strcasestr (mime_type, "charset=");
789 /* Parse a "quoted-string" as defined by RFC 822. */
790 for (p++; *p != '\0' && *p != '"'; p++)
793 ds_put_byte (&s, *p);
794 else if (*++p != '\0')
795 ds_put_byte (&s, *p);
800 /* Parse a "token" as defined by RFC 2045. */
801 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
802 ds_put_byte (&s, *p++);
804 if (!ds_is_empty (&s))
805 return ds_steal_cstr (&s);
812 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
819 /* Get the file name and its encoding. */
820 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
821 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
822 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
823 gtk_recent_info_unref (item);
825 se = psppire_syntax_window_new (encoding);
829 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
830 gtk_widget_show (se);
832 gtk_widget_destroy (se);
839 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
841 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
843 gtk_action_set_visible (de->delete_cases, case_num != -1);
848 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
850 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
852 gtk_action_set_visible (de->delete_variables, var != -1);
855 /* Callback for when the datasheet/varsheet is selected */
857 on_switch_sheet (GtkNotebook *notebook,
858 GtkNotebookPage *page,
862 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
864 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
866 GtkWidget *view_data =
867 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
869 GtkWidget *view_variables =
870 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
874 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
875 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
877 gtk_action_set_sensitive (de->insert_variable, TRUE);
878 gtk_action_set_sensitive (de->insert_case, FALSE);
879 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
881 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
882 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
883 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
884 gtk_action_set_sensitive (de->insert_case, TRUE);
887 g_assert_not_reached ();
892 update_paste_menuitem (de, page_num);
899 set_unsaved (gpointer w)
901 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
905 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
906 Returns a pointer to the action
909 connect_action (PsppireDataWindow *dw, const char *action_name,
912 GtkAction *action = get_action_assert (dw->builder, action_name);
914 g_signal_connect_swapped (action, "activate", handler, dw);
919 /* Initializes as much of a PsppireDataWindow as we can and must before the
920 dataset has been set.
922 In particular, the 'menu' member is required in case the "filename" property
923 is set before the "dataset" property: otherwise PsppireWindow will try to
924 modify the menu as part of the "filename" property_set() function and end up
925 with a Gtk-CRITICAL since 'menu' is NULL. */
927 psppire_data_window_init (PsppireDataWindow *de)
931 de->builder = builder_new ("data-editor.ui");
933 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
935 PSPPIRE_WINDOW (de)->menu =
936 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
940 psppire_data_window_finish_init (PsppireDataWindow *de,
943 static const struct dataset_callbacks cbs =
945 set_unsaved, /* changed */
946 transformation_change_callback, /* transformations_changed */
955 GtkWidget *box = gtk_vbox_new (FALSE, 0);
958 dict = psppire_dict_new_from_dict (dataset_dict (ds));
959 de->var_store = psppire_var_store_new (dict);
960 de->data_store = psppire_data_store_new (dict);
961 psppire_data_store_set_reader (de->data_store, NULL);
963 menubar = get_widget_assert (de->builder, "menubar");
964 hb = get_widget_assert (de->builder, "handlebox1");
965 sb = get_widget_assert (de->builder, "status-bar");
968 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
971 g_signal_connect_swapped (de->data_store, "case-changed",
972 G_CALLBACK (set_unsaved), de);
974 g_signal_connect_swapped (de->data_store, "case-inserted",
975 G_CALLBACK (set_unsaved), de);
977 g_signal_connect_swapped (de->data_store, "cases-deleted",
978 G_CALLBACK (set_unsaved), de);
980 dataset_set_callbacks (de->dataset, &cbs, de);
982 connect_help (de->builder);
984 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
985 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
986 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
987 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
989 gtk_container_add (GTK_CONTAINER (de), box);
991 set_cut_copy_menuitem_sensitivity (de, FALSE);
993 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
994 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
997 set_paste_menuitem_sensitivity (de, FALSE);
999 g_signal_connect_swapped (de->data_editor, "data-available-changed",
1000 G_CALLBACK (set_paste_menuitem_sensitivity), de);
1002 g_signal_connect (dict, "weight-changed",
1003 G_CALLBACK (on_weight_change),
1006 g_signal_connect (dict, "filter-changed",
1007 G_CALLBACK (on_filter_change),
1010 g_signal_connect (dict, "split-changed",
1011 G_CALLBACK (on_split_change),
1015 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1017 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1019 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1021 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1023 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1025 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1027 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1029 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1031 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1033 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1035 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1037 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1039 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1041 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1043 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1046 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1048 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1050 gtk_action_set_visible (de->delete_cases, FALSE);
1055 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1057 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1059 gtk_action_set_visible (de->delete_variables, FALSE);
1063 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1065 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1067 connect_action (de, "data_sort-cases", G_CALLBACK (sort_cases_dialog));
1069 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1071 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1073 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1075 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1077 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1079 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1082 connect_action (de, "utilities_variables", G_CALLBACK (variable_info_dialog));
1084 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1086 connect_action (de, "indep-t-test", G_CALLBACK (t_test_independent_samples_dialog));
1088 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1090 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1092 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1094 connect_action (de, "transform_rank", G_CALLBACK (rank_dialog));
1096 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1098 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1100 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1102 connect_action (de, "analyze_descriptives", G_CALLBACK (descriptives_dialog));
1104 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1106 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1108 connect_action (de, "analyze_explore", G_CALLBACK (examine_dialog));
1110 connect_action (de, "linear-regression", G_CALLBACK (regression_dialog));
1112 connect_action (de, "reliability", G_CALLBACK (reliability_dialog));
1114 connect_action (de, "roc-curve", G_CALLBACK (roc_dialog));
1116 connect_action (de, "correlation", G_CALLBACK (correlation_dialog));
1118 connect_action (de, "factor-analysis", G_CALLBACK (factor_dialog));
1120 connect_action (de, "k-means", G_CALLBACK (k_means_dialog));
1122 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1124 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1126 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1127 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1131 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1133 GtkWidget *recent_data =
1134 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1136 GtkWidget *recent_files =
1137 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1140 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1141 gtk_recent_manager_get_default ());
1143 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1144 gtk_recent_manager_get_default ());
1146 g_object_set (menu_data, "show-tips", TRUE, NULL);
1147 g_object_set (menu_files, "show-tips", TRUE, NULL);
1150 GtkRecentFilter *filter = gtk_recent_filter_new ();
1152 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1153 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1155 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1157 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1160 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1163 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1166 GtkRecentFilter *filter = gtk_recent_filter_new ();
1168 gtk_recent_filter_add_pattern (filter, "*.sps");
1169 gtk_recent_filter_add_pattern (filter, "*.SPS");
1171 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1173 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1176 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1178 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1182 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1185 g_signal_connect (de->data_editor,
1187 G_CALLBACK (enable_delete_cases),
1190 g_signal_connect (de->data_editor,
1191 "variables-selected",
1192 G_CALLBACK (enable_delete_variables),
1196 g_signal_connect (de->data_editor,
1198 G_CALLBACK (on_switch_sheet), de);
1200 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1201 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1203 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1205 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1207 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1209 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1211 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1213 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1215 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1217 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1219 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1222 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1224 merge_help_menu (uim);
1228 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1229 "datasheet-cases-popup");
1231 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1232 "varsheet-variable-popup");
1234 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1235 "datasheet-variable-popup");
1237 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1238 G_CALLBACK (psppire_data_editor_sort_ascending),
1241 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1242 G_CALLBACK (psppire_data_editor_sort_descending),
1245 g_object_set (de->data_editor,
1246 "datasheet-column-menu", data_sheet_variable_popup_menu,
1247 "datasheet-row-menu", data_sheet_cases_popup_menu,
1248 "varsheet-row-menu", var_sheet_variable_popup_menu,
1252 gtk_widget_show (GTK_WIDGET (de->data_editor));
1253 gtk_widget_show (box);
1255 ll_push_head (&all_data_windows, &de->ll);
1259 psppire_data_window_dispose (GObject *object)
1261 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1263 if (dw->builder != NULL)
1265 g_object_unref (dw->builder);
1271 g_object_unref (dw->var_store);
1272 dw->var_store = NULL;
1277 g_object_unref (dw->data_store);
1278 dw->data_store = NULL;
1281 if (dw->ll.next != NULL)
1283 ll_remove (&dw->ll);
1287 if (G_OBJECT_CLASS (parent_class)->dispose)
1288 G_OBJECT_CLASS (parent_class)->dispose (object);
1292 psppire_data_window_set_property (GObject *object,
1294 const GValue *value,
1297 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1302 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1305 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1311 psppire_data_window_get_property (GObject *object,
1316 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1321 g_value_set_pointer (value, window->dataset);
1324 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1330 psppire_data_window_new (struct dataset *ds)
1334 if (the_session == NULL)
1335 the_session = session_create ();
1339 static int n_datasets;
1342 dataset_name = xasprintf ("DataSet%d", ++n_datasets);
1343 ds = dataset_create (the_session, dataset_name);
1344 free (dataset_name);
1346 assert (dataset_session (ds) == the_session);
1350 psppire_data_window_get_type (),
1351 /* TRANSLATORS: This will form a filename. Please avoid whitespace. */
1352 "description", _("Data Editor"),
1356 if (dataset_name (ds) != NULL)
1357 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1363 psppire_data_window_is_empty (PsppireDataWindow *dw)
1365 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1369 psppire_data_window_iface_init (PsppireWindowIface *iface)
1371 iface->save = save_file;
1372 iface->pick_filename = data_pick_filename;
1373 iface->load = load_file;
1377 psppire_default_data_window (void)
1379 if (ll_is_empty (&all_data_windows))
1380 create_data_window ();
1381 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1385 psppire_data_window_set_default (PsppireDataWindow *pdw)
1387 ll_remove (&pdw->ll);
1388 ll_push_head (&all_data_windows, &pdw->ll);
1392 psppire_data_window_undefault (PsppireDataWindow *pdw)
1394 ll_remove (&pdw->ll);
1395 ll_push_tail (&all_data_windows, &pdw->ll);
1399 psppire_data_window_for_dataset (struct dataset *ds)
1401 PsppireDataWindow *pdw;
1403 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1404 if (pdw->dataset == ds)
1411 create_data_window (void)
1413 gtk_widget_show (psppire_data_window_new (NULL));
1417 open_data_window (PsppireWindow *victim, const char *file_name)
1421 if (PSPPIRE_IS_DATA_WINDOW (victim)
1422 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1423 window = GTK_WIDGET (victim);
1425 window = psppire_data_window_new (NULL);
1427 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1428 gtk_widget_show (window);