1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/binomial-dialog.h"
30 #include "ui/gui/builder-wrapper.h"
31 #include "ui/gui/chi-square-dialog.h"
32 #include "ui/gui/comments-dialog.h"
33 #include "ui/gui/compute-dialog.h"
34 #include "ui/gui/count-dialog.h"
35 #include "ui/gui/crosstabs-dialog.h"
36 #include "ui/gui/entry-dialog.h"
37 #include "ui/gui/executor.h"
38 #include "ui/gui/find-dialog.h"
39 #include "ui/gui/frequencies-dialog.h"
40 #include "ui/gui/goto-case-dialog.h"
41 #include "ui/gui/help-menu.h"
42 #include "ui/gui/helper.h"
43 #include "ui/gui/helper.h"
44 #include "ui/gui/k-related-dialog.h"
45 #include "ui/gui/npar-two-sample-related.h"
46 #include "ui/gui/oneway-anova-dialog.h"
47 #include "ui/gui/psppire-data-window.h"
48 #include "ui/gui/psppire-syntax-window.h"
49 #include "ui/gui/psppire-window.h"
50 #include "ui/gui/psppire.h"
51 #include "ui/gui/runs-dialog.h"
52 #include "ui/gui/ks-one-sample-dialog.h"
53 #include "ui/gui/recode-dialog.h"
54 #include "ui/gui/select-cases-dialog.h"
55 #include "ui/gui/split-file-dialog.h"
56 #include "ui/gui/t-test-one-sample.h"
57 #include "ui/gui/t-test-paired-samples.h"
58 #include "ui/gui/text-data-import-dialog.h"
59 #include "ui/gui/transpose-dialog.h"
60 #include "ui/gui/univariate-dialog.h"
61 #include "ui/gui/weight-cases-dialog.h"
62 #include "ui/syntax-gen.h"
64 #include "gl/c-strcase.h"
65 #include "gl/c-strcasestr.h"
66 #include "gl/xvasprintf.h"
69 #define _(msgid) gettext (msgid)
70 #define N_(msgid) msgid
72 struct session *the_session;
73 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
75 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
76 static void psppire_data_window_init (PsppireDataWindow *data_editor);
79 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
81 static void psppire_data_window_dispose (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->set_property = psppire_data_window_set_property;
146 object_class->get_property = psppire_data_window_get_property;
148 g_object_class_install_property (
149 object_class, PROP_DATASET,
150 g_param_spec_pointer ("dataset", "Dataset",
151 "'struct datset *' represented by the window",
152 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
156 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
158 GtkAction *edit_paste = get_action_assert (de->builder, "edit_paste");
160 gtk_action_set_sensitive (edit_paste, x);
164 set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
166 GtkAction *edit_copy = get_action_assert (de->builder, "edit_copy");
167 GtkAction *edit_cut = get_action_assert (de->builder, "edit_cut");
169 gtk_action_set_sensitive (edit_copy, x);
170 gtk_action_set_sensitive (edit_cut, x);
173 /* Run the EXECUTE command. */
175 execute (PsppireDataWindow *dw)
177 execute_const_syntax_string (dw, "EXECUTE.");
181 transformation_change_callback (bool transformations_pending,
184 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
186 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
188 GtkWidget *menuitem =
189 gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
191 GtkWidget *status_label =
192 get_widget_assert (de->builder, "case-counter-area");
194 gtk_widget_set_sensitive (menuitem, transformations_pending);
197 if ( transformations_pending)
198 gtk_label_set_text (GTK_LABEL (status_label),
199 _("Transformations Pending"));
201 gtk_label_set_text (GTK_LABEL (status_label), "");
204 /* Callback for when the dictionary changes its filter variable */
206 on_filter_change (GObject *o, gint filter_index, gpointer data)
208 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
210 GtkWidget *filter_status_area =
211 get_widget_assert (de->builder, "filter-use-status-area");
213 if ( filter_index == -1 )
215 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
219 PsppireVarStore *vs = NULL;
220 PsppireDict *dict = NULL;
221 struct variable *var ;
224 g_object_get (de->data_editor, "var-store", &vs, NULL);
225 g_object_get (vs, "dictionary", &dict, NULL);
227 var = psppire_dict_get_variable (dict, filter_index);
229 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
231 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
237 /* Callback for when the dictionary changes its split variables */
239 on_split_change (PsppireDict *dict, gpointer data)
241 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
243 size_t n_split_vars = dict_get_split_cnt (dict->dict);
245 GtkWidget *split_status_area =
246 get_widget_assert (de->builder, "split-file-status-area");
248 if ( n_split_vars == 0 )
250 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
256 const struct variable *const * split_vars =
257 dict_get_split_vars (dict->dict);
259 text = g_string_new (_("Split by "));
261 for (i = 0 ; i < n_split_vars - 1; ++i )
263 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
265 g_string_append (text, var_get_name (split_vars[i]));
267 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
269 g_string_free (text, TRUE);
276 /* Callback for when the dictionary changes its weights */
278 on_weight_change (GObject *o, gint weight_index, gpointer data)
280 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
282 GtkWidget *weight_status_area =
283 get_widget_assert (de->builder, "weight-status-area");
285 if ( weight_index == -1 )
287 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
291 struct variable *var ;
292 PsppireVarStore *vs = NULL;
293 PsppireDict *dict = NULL;
296 g_object_get (de->data_editor, "var-store", &vs, NULL);
297 g_object_get (vs, "dictionary", &dict, NULL);
299 var = psppire_dict_get_variable (dict, weight_index);
301 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
303 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
311 dump_rm (GtkRecentManager *rm)
313 GList *items = gtk_recent_manager_get_items (rm);
317 g_print ("Recent Items:\n");
318 for (i = items; i; i = i->next)
320 GtkRecentInfo *ri = i->data;
322 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
323 gtk_recent_info_get_short_name (ri),
324 gtk_recent_info_get_mime_type (ri),
325 gtk_recent_info_get_description (ri),
326 gtk_recent_info_get_uri (ri)
330 gtk_recent_info_unref (ri);
338 name_has_por_suffix (const gchar *name)
340 size_t length = strlen (name);
341 return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
345 name_has_sav_suffix (const gchar *name)
347 size_t length = strlen (name);
348 return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
351 /* Returns true if NAME has a suffix which might denote a PSPP file */
353 name_has_suffix (const gchar *name)
355 return name_has_por_suffix (name) || name_has_sav_suffix (name);
359 load_file (PsppireWindow *de, const gchar *file_name)
361 struct string filename;
362 gchar *utf8_file_name;
363 const char *mime_type;
367 ds_init_empty (&filename);
369 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
371 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
373 g_free (utf8_file_name);
375 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
376 ds_destroy (&filename);
378 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
379 lex_reader_for_string (syntax));
382 mime_type = (name_has_por_suffix (file_name)
383 ? "application/x-spss-por"
384 : "application/x-spss-sav");
386 add_most_recent (file_name, mime_type);
391 /* Save DE to file */
393 save_file (PsppireWindow *w)
395 const gchar *file_name = NULL;
396 gchar *utf8_file_name = NULL;
398 struct string filename ;
399 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
402 file_name = psppire_window_get_filename (w);
404 fnx = g_string_new (file_name);
406 if ( ! name_has_suffix (fnx->str))
408 if ( de->save_as_portable)
409 g_string_append (fnx, ".por");
411 g_string_append (fnx, ".sav");
414 ds_init_empty (&filename);
416 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
418 g_string_free (fnx, TRUE);
420 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
421 g_free (utf8_file_name);
423 syntax = g_strdup_printf ("%s OUTFILE=%s.",
424 de->save_as_portable ? "EXPORT" : "SAVE",
425 ds_cstr (&filename));
427 ds_destroy (&filename);
429 g_free (execute_syntax_string (de, syntax));
434 insert_case (PsppireDataWindow *dw)
436 psppire_data_editor_insert_case (dw->data_editor);
440 on_insert_variable (PsppireDataWindow *dw)
442 psppire_data_editor_insert_variable (dw->data_editor);
447 display_dict (PsppireDataWindow *de)
449 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
453 sysfile_info (PsppireDataWindow *de)
455 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
457 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
459 struct string filename;
461 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
463 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
468 ds_init_empty (&filename);
470 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
472 g_free (utf8_file_name);
474 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
475 g_free (execute_syntax_string (de, syntax));
478 gtk_widget_destroy (dialog);
482 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
484 data_pick_filename (PsppireWindow *window)
486 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
487 GtkFileFilter *filter = gtk_file_filter_new ();
488 GtkWidget *button_sys;
490 gtk_file_chooser_dialog_new (_("Save"),
492 GTK_FILE_CHOOSER_ACTION_SAVE,
493 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
494 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
497 g_object_set (dialog, "local-only", FALSE, NULL);
499 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
500 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
501 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
503 filter = gtk_file_filter_new ();
504 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
505 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
506 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
508 filter = gtk_file_filter_new ();
509 gtk_file_filter_set_name (filter, _("All Files"));
510 gtk_file_filter_add_pattern (filter, "*");
511 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
514 GtkWidget *button_por;
515 GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
517 gtk_radio_button_new_with_label (NULL, _("System File"));
520 gtk_radio_button_new_with_label
521 (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
524 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
525 psppire_box_pack_start_defaults (GTK_BOX (vbox), button_por);
527 gtk_widget_show_all (vbox);
529 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
532 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
535 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
537 case GTK_RESPONSE_ACCEPT:
542 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
545 de->save_as_portable =
546 ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
548 if ( ! name_has_suffix (filename->str))
550 if ( de->save_as_portable)
551 g_string_append (filename, ".por");
553 g_string_append (filename, ".sav");
556 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
558 g_string_free (filename, TRUE);
565 gtk_widget_destroy (dialog);
569 confirm_delete_dataset (PsppireDataWindow *de,
570 const char *old_dataset,
571 const char *new_dataset,
572 const char *existing_dataset)
577 dialog = gtk_message_dialog_new (
578 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
579 _("Delete Existing Dataset?"));
581 gtk_message_dialog_format_secondary_text (
582 GTK_MESSAGE_DIALOG (dialog),
583 _("Renaming \"%s\" to \"%s\" will destroy the existing "
584 "dataset named \"%s\". Are you sure that you want to do this?"),
585 old_dataset, new_dataset, existing_dataset);
587 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
588 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
589 GTK_STOCK_DELETE, GTK_RESPONSE_OK,
592 g_object_set (dialog, "icon-name", "pspp", NULL);
594 result = gtk_dialog_run (GTK_DIALOG (dialog));
596 gtk_widget_destroy (dialog);
598 return result == GTK_RESPONSE_OK;
602 on_rename_dataset (PsppireDataWindow *de)
604 struct dataset *ds = de->dataset;
605 struct session *session = dataset_session (ds);
606 const char *old_name = dataset_name (ds);
607 struct dataset *existing_dataset;
611 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
613 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
617 if (new_name == NULL)
620 existing_dataset = session_lookup_dataset (session, new_name);
621 if (existing_dataset == NULL || existing_dataset == ds
622 || confirm_delete_dataset (de, old_name, new_name,
623 dataset_name (existing_dataset)))
624 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
631 on_edit_paste (PsppireDataWindow *de)
633 psppire_data_editor_clip_paste (de->data_editor);
637 on_edit_copy (PsppireDataWindow *de)
639 psppire_data_editor_clip_copy (de->data_editor);
645 on_edit_cut (PsppireDataWindow *de)
647 psppire_data_editor_clip_cut (de->data_editor);
652 status_bar_activate (PsppireDataWindow *de, GtkToggleAction *action)
654 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
656 if ( gtk_toggle_action_get_active (action))
657 gtk_widget_show (statusbar);
659 gtk_widget_hide (statusbar);
664 grid_lines_activate (PsppireDataWindow *de, GtkToggleAction *action)
666 const gboolean grid_visible = gtk_toggle_action_get_active (action);
668 psppire_data_editor_show_grid (de->data_editor, grid_visible);
672 data_view_activate (PsppireDataWindow *de)
674 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
679 variable_view_activate (PsppireDataWindow *de)
681 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
686 fonts_activate (PsppireDataWindow *de)
688 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
689 PangoFontDescription *current_font;
692 gtk_font_selection_dialog_new (_("Font Selection"));
695 current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
696 font_name = pango_font_description_to_string (current_font);
698 gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
702 gtk_window_set_transient_for (GTK_WINDOW (dialog),
703 GTK_WINDOW (toplevel));
705 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
707 const gchar *font = gtk_font_selection_dialog_get_font_name
708 (GTK_FONT_SELECTION_DIALOG (dialog));
710 PangoFontDescription* font_desc =
711 pango_font_description_from_string (font);
713 psppire_data_editor_set_font (de->data_editor, font_desc);
716 gtk_widget_hide (dialog);
721 /* Callback for the value labels action */
723 toggle_value_labels (PsppireDataWindow *de, GtkToggleAction *ta)
725 g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
729 toggle_split_window (PsppireDataWindow *de, GtkToggleAction *ta)
731 psppire_data_editor_split_window (de->data_editor,
732 gtk_toggle_action_get_active (ta));
737 file_quit (PsppireDataWindow *de)
739 /* FIXME: Need to be more intelligent here.
740 Give the user the opportunity to save any unsaved data.
747 on_recent_data_select (GtkMenuShell *menushell,
748 PsppireWindow *window)
753 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
755 file = g_filename_from_uri (uri, NULL, NULL);
759 open_data_window (window, file);
765 charset_from_mime_type (const char *mime_type)
771 if (mime_type == NULL)
774 charset = c_strcasestr (mime_type, "charset=");
782 /* Parse a "quoted-string" as defined by RFC 822. */
783 for (p++; *p != '\0' && *p != '"'; p++)
786 ds_put_byte (&s, *p);
787 else if (*++p != '\0')
788 ds_put_byte (&s, *p);
793 /* Parse a "token" as defined by RFC 2045. */
794 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
795 ds_put_byte (&s, *p++);
797 if (!ds_is_empty (&s))
798 return ds_steal_cstr (&s);
805 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
812 /* Get the file name and its encoding. */
813 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
814 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
815 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
816 gtk_recent_info_unref (item);
818 se = psppire_syntax_window_new (encoding);
822 if ( psppire_window_load (PSPPIRE_WINDOW (se), file) )
823 gtk_widget_show (se);
825 gtk_widget_destroy (se);
833 enable_delete_cases (GtkWidget *w, gint case_num, gpointer data)
835 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
837 gtk_action_set_visible (de->delete_cases, case_num != -1);
842 enable_delete_variables (GtkWidget *w, gint var, gpointer data)
844 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
846 gtk_action_set_visible (de->delete_variables, var != -1);
849 /* Callback for when the datasheet/varsheet is selected */
851 on_switch_sheet (GtkNotebook *notebook,
852 GtkNotebookPage *page,
856 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (user_data);
858 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
860 GtkWidget *view_data =
861 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_data");
863 GtkWidget *view_variables =
864 gtk_ui_manager_get_widget (uim,"/ui/menubar/view/view_variables");
868 case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
869 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
871 gtk_action_set_sensitive (de->insert_variable, TRUE);
872 gtk_action_set_sensitive (de->insert_case, FALSE);
873 gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
875 case PSPPIRE_DATA_EDITOR_DATA_VIEW:
876 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
877 gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
878 gtk_action_set_sensitive (de->insert_case, TRUE);
881 g_assert_not_reached ();
886 update_paste_menuitem (de, page_num);
893 set_unsaved (gpointer w)
895 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
899 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
900 Returns a pointer to the action
903 connect_action (PsppireDataWindow *dw, const char *action_name,
906 GtkAction *action = get_action_assert (dw->builder, action_name);
908 g_signal_connect_swapped (action, "activate", handler, dw);
913 /* Initializes as much of a PsppireDataWindow as we can and must before the
914 dataset has been set.
916 In particular, the 'menu' member is required in case the "filename" property
917 is set before the "dataset" property: otherwise PsppireWindow will try to
918 modify the menu as part of the "filename" property_set() function and end up
919 with a Gtk-CRITICAL since 'menu' is NULL. */
921 psppire_data_window_init (PsppireDataWindow *de)
925 de->builder = builder_new ("data-editor.ui");
927 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
929 PSPPIRE_WINDOW (de)->menu =
930 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
934 psppire_data_window_finish_init (PsppireDataWindow *de,
937 static const struct dataset_callbacks cbs =
939 set_unsaved, /* changed */
940 transformation_change_callback, /* transformations_changed */
949 GtkWidget *box = gtk_vbox_new (FALSE, 0);
952 dict = psppire_dict_new_from_dict (dataset_dict (ds));
953 de->var_store = psppire_var_store_new (dict);
954 g_object_unref (dict);
955 de->data_store = psppire_data_store_new (dict);
956 psppire_data_store_set_reader (de->data_store, NULL);
958 menubar = get_widget_assert (de->builder, "menubar");
959 hb = get_widget_assert (de->builder, "handlebox1");
960 sb = get_widget_assert (de->builder, "status-bar");
963 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
966 g_signal_connect_swapped (de->data_store, "case-changed",
967 G_CALLBACK (set_unsaved), de);
969 g_signal_connect_swapped (de->data_store, "case-inserted",
970 G_CALLBACK (set_unsaved), de);
972 g_signal_connect_swapped (de->data_store, "cases-deleted",
973 G_CALLBACK (set_unsaved), de);
975 dataset_set_callbacks (de->dataset, &cbs, de);
977 connect_help (de->builder);
979 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
980 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
981 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
982 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
984 gtk_container_add (GTK_CONTAINER (de), box);
986 set_cut_copy_menuitem_sensitivity (de, FALSE);
988 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
989 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
992 set_paste_menuitem_sensitivity (de, FALSE);
994 g_signal_connect_swapped (de->data_editor, "data-available-changed",
995 G_CALLBACK (set_paste_menuitem_sensitivity), de);
997 g_signal_connect (dict, "weight-changed",
998 G_CALLBACK (on_weight_change),
1001 g_signal_connect (dict, "filter-changed",
1002 G_CALLBACK (on_filter_change),
1005 g_signal_connect (dict, "split-changed",
1006 G_CALLBACK (on_split_change),
1010 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1012 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1014 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1016 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1018 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1020 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1022 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1024 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1026 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1028 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1030 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1032 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1034 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1036 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1038 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1041 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1043 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1045 gtk_action_set_visible (de->delete_cases, FALSE);
1050 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1052 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1054 gtk_action_set_visible (de->delete_variables, FALSE);
1058 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1059 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1060 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1061 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1062 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1063 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1064 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1065 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1066 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1067 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1068 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1069 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1070 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1071 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1072 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1073 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1074 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1075 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1076 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1077 connect_action (de, "binomial", G_CALLBACK (binomial_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);
1218 struct dataset *dataset = dw->dataset;
1219 struct session *session = dataset_session (dataset);
1223 dataset_set_callbacks (dataset, NULL, NULL);
1224 session_set_active_dataset (session, NULL);
1225 dataset_destroy (dataset);
1228 if (dw->builder != NULL)
1230 g_object_unref (dw->builder);
1236 g_object_unref (dw->var_store);
1237 dw->var_store = NULL;
1242 g_object_unref (dw->data_store);
1243 dw->data_store = NULL;
1246 if (dw->ll.next != NULL)
1248 ll_remove (&dw->ll);
1252 if (G_OBJECT_CLASS (parent_class)->dispose)
1253 G_OBJECT_CLASS (parent_class)->dispose (object);
1257 psppire_data_window_set_property (GObject *object,
1259 const GValue *value,
1262 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1267 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1270 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1276 psppire_data_window_get_property (GObject *object,
1281 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1286 g_value_set_pointer (value, window->dataset);
1289 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1295 psppire_data_window_new (struct dataset *ds)
1299 if (the_session == NULL)
1300 the_session = session_create ();
1304 char *dataset_name = session_generate_dataset_name (the_session);
1305 ds = dataset_create (the_session, dataset_name);
1306 free (dataset_name);
1308 assert (dataset_session (ds) == the_session);
1312 psppire_data_window_get_type (),
1313 "description", _("Data Editor"),
1317 if (dataset_name (ds) != NULL)
1318 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1324 psppire_data_window_is_empty (PsppireDataWindow *dw)
1326 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1330 psppire_data_window_iface_init (PsppireWindowIface *iface)
1332 iface->save = save_file;
1333 iface->pick_filename = data_pick_filename;
1334 iface->load = load_file;
1338 psppire_default_data_window (void)
1340 if (ll_is_empty (&all_data_windows))
1341 create_data_window ();
1342 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1346 psppire_data_window_set_default (PsppireDataWindow *pdw)
1348 ll_remove (&pdw->ll);
1349 ll_push_head (&all_data_windows, &pdw->ll);
1353 psppire_data_window_undefault (PsppireDataWindow *pdw)
1355 ll_remove (&pdw->ll);
1356 ll_push_tail (&all_data_windows, &pdw->ll);
1360 psppire_data_window_for_dataset (struct dataset *ds)
1362 PsppireDataWindow *pdw;
1364 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1365 if (pdw->dataset == ds)
1372 create_data_window (void)
1374 gtk_widget_show (psppire_data_window_new (NULL));
1378 open_data_window (PsppireWindow *victim, const char *file_name)
1382 if (PSPPIRE_IS_DATA_WINDOW (victim)
1383 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1384 window = GTK_WIDGET (victim);
1386 window = psppire_data_window_new (NULL);
1388 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1389 gtk_widget_show (window);