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/entry-dialog.h"
35 #include "ui/gui/executor.h"
36 #include "ui/gui/find-dialog.h"
37 #include "ui/gui/goto-case-dialog.h"
38 #include "ui/gui/help-menu.h"
39 #include "ui/gui/helper.h"
40 #include "ui/gui/helper.h"
41 #include "ui/gui/k-related-dialog.h"
42 #include "ui/gui/npar-two-sample-related.h"
43 #include "ui/gui/oneway-anova-dialog.h"
44 #include "ui/gui/psppire-data-window.h"
45 #include "ui/gui/psppire-syntax-window.h"
46 #include "ui/gui/psppire-window.h"
47 #include "ui/gui/psppire.h"
48 #include "ui/gui/runs-dialog.h"
49 #include "ui/gui/ks-one-sample-dialog.h"
50 #include "ui/gui/recode-dialog.h"
51 #include "ui/gui/select-cases-dialog.h"
52 #include "ui/gui/split-file-dialog.h"
53 #include "ui/gui/t-test-one-sample.h"
54 #include "ui/gui/t-test-paired-samples.h"
55 #include "ui/gui/text-data-import-dialog.h"
56 #include "ui/gui/transpose-dialog.h"
57 #include "ui/gui/univariate-dialog.h"
58 #include "ui/gui/weight-cases-dialog.h"
59 #include "ui/syntax-gen.h"
61 #include "gl/c-strcase.h"
62 #include "gl/c-strcasestr.h"
63 #include "gl/xvasprintf.h"
66 #define _(msgid) gettext (msgid)
67 #define N_(msgid) msgid
69 struct session *the_session;
70 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
72 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
73 static void psppire_data_window_init (PsppireDataWindow *data_editor);
76 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
78 static void psppire_data_window_dispose (GObject *object);
79 static void psppire_data_window_finalize (GObject *object);
80 static void psppire_data_window_set_property (GObject *object,
84 static void psppire_data_window_get_property (GObject *object,
90 psppire_data_window_get_type (void)
92 static GType psppire_data_window_type = 0;
94 if (!psppire_data_window_type)
96 static const GTypeInfo psppire_data_window_info =
98 sizeof (PsppireDataWindowClass),
101 (GClassInitFunc)psppire_data_window_class_init,
102 (GClassFinalizeFunc) NULL,
104 sizeof (PsppireDataWindow),
106 (GInstanceInitFunc) psppire_data_window_init,
109 static const GInterfaceInfo window_interface_info =
111 (GInterfaceInitFunc) psppire_data_window_iface_init,
116 psppire_data_window_type =
117 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
118 &psppire_data_window_info, 0);
121 g_type_add_interface_static (psppire_data_window_type,
122 PSPPIRE_TYPE_WINDOW_MODEL,
123 &window_interface_info);
126 return psppire_data_window_type;
129 static GObjectClass *parent_class ;
136 psppire_data_window_class_init (PsppireDataWindowClass *class)
138 GObjectClass *object_class = G_OBJECT_CLASS (class);
140 parent_class = g_type_class_peek_parent (class);
142 object_class->dispose = psppire_data_window_dispose;
143 object_class->finalize = psppire_data_window_finalize;
144 object_class->set_property = psppire_data_window_set_property;
145 object_class->get_property = psppire_data_window_get_property;
147 g_object_class_install_property (
148 object_class, PROP_DATASET,
149 g_param_spec_pointer ("dataset", "Dataset",
150 "'struct datset *' represented by the window",
151 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
155 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
157 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
159 gtk_action_set_sensitive (edit_paste, x);
163 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
165 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
166 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
168 gtk_action_set_sensitive (edit_copy, x);
169 gtk_action_set_sensitive (edit_cut, x);
172 /* Run the EXECUTE command. */
174 execute (PsppireDataWindow *dw)
176 execute_const_syntax_string (dw, "EXECUTE.");
180 transformation_change_callback (bool transformations_pending,
183 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
185 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
187 GtkWidget *menuitem =
188 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
190 GtkWidget *status_label =
191 get_widget_assert (de->builder, "case-counter-area");
193 gtk_widget_set_sensitive (menuitem, transformations_pending);
196 if ( transformations_pending)
197 gtk_label_set_text (GTK_LABEL (status_label),
198 _("Transformations Pending"));
200 gtk_label_set_text (GTK_LABEL (status_label), "");
203 /* Callback for when the dictionary changes its filter variable */
205 on_filter_change (GObject *o, gint filter_index, gpointer data)
207 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
209 GtkWidget *filter_status_area =
210 get_widget_assert (de->builder, "filter-use-status-area");
212 if ( filter_index == -1 )
214 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
218 PsppireVarStore *vs = NULL;
219 PsppireDict *dict = NULL;
220 struct variable *var ;
223 g_object_get (de->data_editor, "var-store", &vs, NULL);
224 g_object_get (vs, "dictionary", &dict, NULL);
226 var = psppire_dict_get_variable (dict, filter_index);
228 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
230 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
236 /* Callback for when the dictionary changes its split variables */
238 on_split_change (PsppireDict *dict, gpointer data)
240 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
242 size_t n_split_vars = dict_get_split_cnt (dict->dict);
244 GtkWidget *split_status_area =
245 get_widget_assert (de->builder, "split-file-status-area");
247 if ( n_split_vars == 0 )
249 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
255 const struct variable *const * split_vars =
256 dict_get_split_vars (dict->dict);
258 text = g_string_new (_("Split by "));
260 for (i = 0 ; i < n_split_vars - 1; ++i )
262 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
264 g_string_append (text, var_get_name (split_vars[i]));
266 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
268 g_string_free (text, TRUE);
275 /* Callback for when the dictionary changes its weights */
277 on_weight_change (GObject *o, gint weight_index, gpointer data)
279 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
281 GtkWidget *weight_status_area =
282 get_widget_assert (de->builder, "weight-status-area");
284 if ( weight_index == -1 )
286 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
290 struct variable *var ;
291 PsppireVarStore *vs = NULL;
292 PsppireDict *dict = NULL;
295 g_object_get (de->data_editor, "var-store", &vs, NULL);
296 g_object_get (vs, "dictionary", &dict, NULL);
298 var = psppire_dict_get_variable (dict, weight_index);
300 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
302 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
310 dump_rm (GtkRecentManager *rm)
312 GList *items = gtk_recent_manager_get_items (rm);
316 g_print ("Recent Items:\n");
317 for (i = items; i; i = i->next)
319 GtkRecentInfo *ri = i->data;
321 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
322 gtk_recent_info_get_short_name (ri),
323 gtk_recent_info_get_mime_type (ri),
324 gtk_recent_info_get_description (ri),
325 gtk_recent_info_get_uri (ri)
329 gtk_recent_info_unref (ri);
337 name_has_por_suffix (const gchar *name)
339 size_t length = strlen (name);
340 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
344 name_has_sav_suffix (const gchar *name)
346 size_t length = strlen (name);
347 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
350 /* Returns true if NAME has a suffix which might denote a PSPP file */
352 name_has_suffix (const gchar *name)
354 return name_has_por_suffix (name) || name_has_sav_suffix (name);
358 load_file (PsppireWindow *de, const gchar *file_name)
360 struct string filename;
361 gchar *utf8_file_name;
362 const char *mime_type;
366 ds_init_empty (&filename);
368 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
370 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
372 g_free (utf8_file_name);
374 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
375 ds_destroy (&filename);
377 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
378 lex_reader_for_string (syntax));
381 mime_type = (name_has_por_suffix (file_name)
382 ? "application/x-spss-por"
383 : "application/x-spss-sav");
385 add_most_recent (file_name, mime_type);
390 /* Save DE to file */
392 save_file (PsppireWindow *w)
394 const gchar *file_name = NULL;
395 gchar *utf8_file_name = NULL;
397 struct string filename ;
398 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
401 file_name = psppire_window_get_filename (w);
403 fnx = g_string_new (file_name);
405 if ( ! name_has_suffix (fnx->str))
407 if ( de->save_as_portable)
408 g_string_append (fnx, ".por");
410 g_string_append (fnx, ".sav");
413 ds_init_empty (&filename);
415 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
417 g_string_free (fnx, TRUE);
419 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
420 g_free (utf8_file_name);
422 syntax = g_strdup_printf ("%s OUTFILE=%s.",
423 de->save_as_portable ? "EXPORT" : "SAVE",
424 ds_cstr (&filename));
426 ds_destroy (&filename);
428 g_free (execute_syntax_string (de, syntax));
433 insert_case (PsppireDataWindow *dw)
435 psppire_data_editor_insert_case (dw->data_editor);
439 on_insert_variable (PsppireDataWindow *dw)
441 psppire_data_editor_insert_variable (dw->data_editor);
446 display_dict (PsppireDataWindow *de)
448 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
452 sysfile_info (PsppireDataWindow *de)
454 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
456 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
458 struct string filename;
460 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
462 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
467 ds_init_empty (&filename);
469 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
471 g_free (utf8_file_name);
473 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
474 g_free (execute_syntax_string (de, syntax));
477 gtk_widget_destroy (dialog);
481 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
483 data_pick_filename (PsppireWindow *window)
485 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
486 GtkFileFilter *filter = gtk_file_filter_new ();
487 GtkWidget *button_sys;
489 gtk_file_chooser_dialog_new (_("Save"),
491 GTK_FILE_CHOOSER_ACTION_SAVE,
492 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
493 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
496 g_object_set (dialog, "local-only", FALSE, NULL);
498 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
499 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
500 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
502 filter = gtk_file_filter_new ();
503 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
504 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
505 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
507 filter = gtk_file_filter_new ();
508 gtk_file_filter_set_name (filter, _("All Files"));
509 gtk_file_filter_add_pattern (filter, "*");
510 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
513 GtkWidget *button_por;
514 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
516 gtk_radio_button_new_with_label (NULL, _("System File"));
519 gtk_radio_button_new_with_label
520 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
523 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
524 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
526 gtk_widget_show_all (vbox);
528 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
531 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
534 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
536 case GTK_RESPONSE_ACCEPT:
541 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
544 de->save_as_portable =
545 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
547 if ( ! name_has_suffix (filename->str))
549 if ( de->save_as_portable)
550 g_string_append (filename, ".por");
552 g_string_append (filename, ".sav");
555 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
557 g_string_free (filename, TRUE);
564 gtk_widget_destroy (dialog);
568 confirm_delete_dataset (PsppireDataWindow *de,
569 const char *old_dataset,
570 const char *new_dataset,
571 const char *existing_dataset)
576 dialog = gtk_message_dialog_new (
577 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
578 _("Delete Existing Dataset?"));
580 gtk_message_dialog_format_secondary_text (
581 GTK_MESSAGE_DIALOG (dialog),
582 _("Renaming \"%s\" to \"%s\" will destroy the existing "
583 "dataset named \"%s\". Are you sure that you want to do this?"),
584 old_dataset, new_dataset, existing_dataset);
586 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
587 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
588 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
591 g_object_set (dialog, "icon-name", "pspp", NULL);
593 result = gtk_dialog_run (GTK_DIALOG (dialog));
595 gtk_widget_destroy (dialog);
597 return result == GTK_RESPONSE_OK;
601 on_rename_dataset (PsppireDataWindow *de)
603 struct dataset *ds = de->dataset;
604 struct session *session = dataset_session (ds);
605 const char *old_name = dataset_name (ds);
606 struct dataset *existing_dataset;
610 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
612 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
616 if (new_name == NULL)
619 existing_dataset = session_lookup_dataset (session, new_name);
620 if (existing_dataset == NULL || existing_dataset == ds
621 || confirm_delete_dataset (de, old_name, new_name,
622 dataset_name (existing_dataset)))
623 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
630 on_edit_paste (PsppireDataWindow *de)
632 psppire_data_editor_clip_paste (de->data_editor);
636 on_edit_copy (PsppireDataWindow *de)
638 psppire_data_editor_clip_copy (de->data_editor);
644 on_edit_cut (PsppireDataWindow *de)
646 psppire_data_editor_clip_cut (de->data_editor);
651 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
653 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
655 if ( gtk_toggle_action_get_active (action))
656 gtk_widget_show (statusbar);
658 gtk_widget_hide (statusbar);
663 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
665 const gboolean grid_visible = gtk_toggle_action_get_active (action);
667 psppire_data_editor_show_grid (de->data_editor, grid_visible);
671 data_view_activate (PsppireDataWindow *de)
673 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
678 variable_view_activate (PsppireDataWindow *de)
680 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
685 fonts_activate (PsppireDataWindow *de)
687 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
688 PangoFontDescription *current_font;
691 gtk_font_selection_dialog_new (_("Font Selection"));
694 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
695 font_name = pango_font_description_to_string (current_font);
697 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
701 gtk_window_set_transient_for (GTK_WINDOW (dialog),
702 GTK_WINDOW (toplevel));
704 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
706 const gchar *font = gtk_font_selection_dialog_get_font_name
707 (GTK_FONT_SELECTION_DIALOG (dialog));
709 PangoFontDescription* font_desc =
710 pango_font_description_from_string (font);
712 psppire_data_editor_set_font (de->data_editor, font_desc);
715 gtk_widget_hide (dialog);
720 /* Callback for the value labels action */
722 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
724 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
728 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
730 psppire_data_editor_split_window (de->data_editor,
731 gtk_toggle_action_get_active (ta));
736 file_quit (PsppireDataWindow *de)
738 /* FIXME: Need to be more intelligent here.
739 Give the user the opportunity to save any unsaved data.
746 on_recent_data_select (GtkMenuShell *menushell,
747 PsppireWindow *window)
752 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
754 file = g_filename_from_uri (uri, NULL, NULL);
758 open_data_window (window, file);
764 charset_from_mime_type (const char *mime_type)
770 if (mime_type == NULL)
773 charset = c_strcasestr (mime_type, "charset=");
781 /* Parse a "quoted-string" as defined by RFC 822. */
782 for (p++; *p != '\0' && *p != '"'; p++)
785 ds_put_byte (&s, *p);
786 else if (*++p != '\0')
787 ds_put_byte (&s, *p);
792 /* Parse a "token" as defined by RFC 2045. */
793 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
794 ds_put_byte (&s, *p++);
796 if (!ds_is_empty (&s))
797 return ds_steal_cstr (&s);
804 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
811 /* Get the file name and its encoding. */
812 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
813 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
814 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
815 gtk_recent_info_unref (item);
817 se = psppire_syntax_window_new (encoding);
821 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
822 gtk_widget_show (se);
824 gtk_widget_destroy (se);
832 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
834 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
836 gtk_action_set_visible (de->delete_cases, case_num != -1);
841 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
843 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
845 gtk_action_set_visible (de->delete_variables, var != -1);
848 /* Callback for when the datasheet/varsheet is selected */
850 on_switch_sheet (GtkNotebook *notebook,
851 GtkNotebookPage *page,
855 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
857 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
859 GtkWidget *view_data =
860 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
862 GtkWidget *view_variables =
863 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
867 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
868 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
870 gtk_action_set_sensitive (de->insert_variable, TRUE);
871 gtk_action_set_sensitive (de->insert_case, FALSE);
872 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
874 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
875 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
876 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
877 gtk_action_set_sensitive (de->insert_case, TRUE);
880 g_assert_not_reached ();
885 update_paste_menuitem (de, page_num);
892 set_unsaved (gpointer w)
894 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
898 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
899 Returns a pointer to the action
902 connect_action (PsppireDataWindow *dw, const char *action_name,
905 GtkAction *action = get_action_assert (dw->builder, action_name);
907 g_signal_connect_swapped (action, "activate", handler, dw);
912 /* Only a data file with at least one variable can be saved. */
914 enable_save (PsppireDataWindow *dw)
916 PsppireDict *dict = dw->var_store->dictionary;
917 gboolean enable = psppire_dict_get_var_cnt (dict) > 0;
919 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
921 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
925 /* Initializes as much of a PsppireDataWindow as we can and must before the
926 dataset has been set.
928 In particular, the 'menu' member is required in case the "filename" property
929 is set before the "dataset" property: otherwise PsppireWindow will try to
930 modify the menu as part of the "filename" property_set() function and end up
931 with a Gtk-CRITICAL since 'menu' is NULL. */
933 psppire_data_window_init (PsppireDataWindow *de)
937 de->builder = builder_new ("data-editor.ui");
939 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
941 PSPPIRE_WINDOW (de)->menu =
942 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
946 psppire_data_window_finish_init (PsppireDataWindow *de,
949 static const struct dataset_callbacks cbs =
951 set_unsaved, /* changed */
952 transformation_change_callback, /* transformations_changed */
961 GtkWidget *box = gtk_vbox_new (FALSE, 0);
964 dict = psppire_dict_new_from_dict (dataset_dict (ds));
965 de->var_store = psppire_var_store_new (dict);
966 g_object_unref (dict);
967 de->data_store = psppire_data_store_new (dict);
968 psppire_data_store_set_reader (de->data_store, NULL);
970 menubar = get_widget_assert (de->builder, "menubar");
971 hb = get_widget_assert (de->builder, "handlebox1");
972 sb = get_widget_assert (de->builder, "status-bar");
975 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
978 g_signal_connect_swapped (de->data_store, "case-changed",
979 G_CALLBACK (set_unsaved), de);
981 g_signal_connect_swapped (de->data_store, "case-inserted",
982 G_CALLBACK (set_unsaved), de);
984 g_signal_connect_swapped (de->data_store, "cases-deleted",
985 G_CALLBACK (set_unsaved), de);
987 dataset_set_callbacks (de->dataset, &cbs, de);
989 connect_help (de->builder);
991 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
992 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
993 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
994 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
996 gtk_container_add (GTK_CONTAINER (de), box);
998 set_cut_copy_menuitem_sensitivity (de, FALSE);
1000 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
1001 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
1004 set_paste_menuitem_sensitivity (de, FALSE);
1006 g_signal_connect_swapped (de->data_editor, "data-available-changed",
1007 G_CALLBACK (set_paste_menuitem_sensitivity), de);
1009 g_signal_connect (dict, "weight-changed",
1010 G_CALLBACK (on_weight_change),
1013 g_signal_connect (dict, "filter-changed",
1014 G_CALLBACK (on_filter_change),
1017 g_signal_connect (dict, "split-changed",
1018 G_CALLBACK (on_split_change),
1021 g_signal_connect_swapped (dict, "backend-changed",
1022 G_CALLBACK (enable_save), de);
1023 g_signal_connect_swapped (dict, "variable-inserted",
1024 G_CALLBACK (enable_save), de);
1025 g_signal_connect_swapped (dict, "variable-deleted",
1026 G_CALLBACK (enable_save), de);
1029 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1031 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1033 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1035 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1037 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1039 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1041 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1043 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1045 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1047 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1049 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1051 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1053 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1055 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1057 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1060 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1062 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1064 gtk_action_set_visible (de->delete_cases, FALSE);
1069 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1071 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1073 gtk_action_set_visible (de->delete_variables, FALSE);
1077 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1078 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1079 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1080 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1081 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1082 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1083 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1084 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1085 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1086 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1087 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1088 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1089 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1090 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1091 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1092 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1093 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1094 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1095 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1096 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1097 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1100 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1102 GtkWidget *recent_data =
1103 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1105 GtkWidget *recent_files =
1106 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1109 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1110 gtk_recent_manager_get_default ());
1112 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1113 gtk_recent_manager_get_default ());
1115 g_object_set (menu_data, "show-tips", TRUE, NULL);
1116 g_object_set (menu_files, "show-tips", TRUE, NULL);
1119 GtkRecentFilter *filter = gtk_recent_filter_new ();
1121 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1122 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1124 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1126 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1129 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1132 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1135 GtkRecentFilter *filter = gtk_recent_filter_new ();
1137 gtk_recent_filter_add_pattern (filter, "*.sps");
1138 gtk_recent_filter_add_pattern (filter, "*.SPS");
1140 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1142 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1145 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1147 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1151 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1154 g_signal_connect (de->data_editor,
1156 G_CALLBACK (enable_delete_cases),
1159 g_signal_connect (de->data_editor,
1160 "variables-selected",
1161 G_CALLBACK (enable_delete_variables),
1165 g_signal_connect (de->data_editor,
1167 G_CALLBACK (on_switch_sheet), de);
1169 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1170 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1172 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1174 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1176 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1178 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1180 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1182 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1184 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1186 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1188 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1191 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1193 merge_help_menu (uim);
1197 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1198 "datasheet-cases-popup");
1200 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1201 "varsheet-variable-popup");
1203 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1204 "datasheet-variable-popup");
1206 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1207 G_CALLBACK (psppire_data_editor_sort_ascending),
1210 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1211 G_CALLBACK (psppire_data_editor_sort_descending),
1214 g_object_set (de->data_editor,
1215 "datasheet-column-menu", data_sheet_variable_popup_menu,
1216 "datasheet-row-menu", data_sheet_cases_popup_menu,
1217 "varsheet-row-menu", var_sheet_variable_popup_menu,
1221 gtk_widget_show (GTK_WIDGET (de->data_editor));
1222 gtk_widget_show (box);
1224 ll_push_head (&all_data_windows, &de->ll);
1228 psppire_data_window_dispose (GObject *object)
1230 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1232 if (dw->builder != NULL)
1234 g_object_unref (dw->builder);
1240 g_object_unref (dw->var_store);
1241 dw->var_store = NULL;
1246 g_object_unref (dw->data_store);
1247 dw->data_store = NULL;
1250 if (dw->ll.next != NULL)
1252 ll_remove (&dw->ll);
1256 if (G_OBJECT_CLASS (parent_class)->dispose)
1257 G_OBJECT_CLASS (parent_class)->dispose (object);
1261 psppire_data_window_finalize (GObject *object)
1263 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1267 struct dataset *dataset = dw->dataset;
1268 struct session *session = dataset_session (dataset);
1272 dataset_set_callbacks (dataset, NULL, NULL);
1273 session_set_active_dataset (session, NULL);
1274 dataset_destroy (dataset);
1277 if (G_OBJECT_CLASS (parent_class)->finalize)
1278 G_OBJECT_CLASS (parent_class)->finalize (object);
1282 psppire_data_window_set_property (GObject *object,
1284 const GValue *value,
1287 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1292 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1295 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1301 psppire_data_window_get_property (GObject *object,
1306 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1311 g_value_set_pointer (value, window->dataset);
1314 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1320 psppire_data_window_new (struct dataset *ds)
1324 if (the_session == NULL)
1325 the_session = session_create ();
1329 char *dataset_name = session_generate_dataset_name (the_session);
1330 ds = dataset_create (the_session, dataset_name);
1331 free (dataset_name);
1333 assert (dataset_session (ds) == the_session);
1337 psppire_data_window_get_type (),
1338 "description", _("Data Editor"),
1342 if (dataset_name (ds) != NULL)
1343 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1349 psppire_data_window_is_empty (PsppireDataWindow *dw)
1351 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1355 psppire_data_window_iface_init (PsppireWindowIface *iface)
1357 iface->save = save_file;
1358 iface->pick_filename = data_pick_filename;
1359 iface->load = load_file;
1363 psppire_default_data_window (void)
1365 if (ll_is_empty (&all_data_windows))
1366 create_data_window ();
1367 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1371 psppire_data_window_set_default (PsppireDataWindow *pdw)
1373 ll_remove (&pdw->ll);
1374 ll_push_head (&all_data_windows, &pdw->ll);
1378 psppire_data_window_undefault (PsppireDataWindow *pdw)
1380 ll_remove (&pdw->ll);
1381 ll_push_tail (&all_data_windows, &pdw->ll);
1385 psppire_data_window_for_dataset (struct dataset *ds)
1387 PsppireDataWindow *pdw;
1389 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1390 if (pdw->dataset == ds)
1397 create_data_window (void)
1399 gtk_widget_show (psppire_data_window_new (NULL));
1403 open_data_window (PsppireWindow *victim, const char *file_name)
1407 if (PSPPIRE_IS_DATA_WINDOW (victim)
1408 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1409 window = GTK_WIDGET (victim);
1411 window = psppire_data_window_new (NULL);
1413 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1414 gtk_widget_show (window);