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 de->data_store = psppire_data_store_new (dict);
955 psppire_data_store_set_reader (de->data_store, NULL);
957 menubar = get_widget_assert (de->builder, "menubar");
958 hb = get_widget_assert (de->builder, "handlebox1");
959 sb = get_widget_assert (de->builder, "status-bar");
962 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
965 g_signal_connect_swapped (de->data_store, "case-changed",
966 G_CALLBACK (set_unsaved), de);
968 g_signal_connect_swapped (de->data_store, "case-inserted",
969 G_CALLBACK (set_unsaved), de);
971 g_signal_connect_swapped (de->data_store, "cases-deleted",
972 G_CALLBACK (set_unsaved), de);
974 dataset_set_callbacks (de->dataset, &cbs, de);
976 connect_help (de->builder);
978 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
979 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
980 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
981 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
983 gtk_container_add (GTK_CONTAINER (de), box);
985 set_cut_copy_menuitem_sensitivity (de, FALSE);
987 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
988 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
991 set_paste_menuitem_sensitivity (de, FALSE);
993 g_signal_connect_swapped (de->data_editor, "data-available-changed",
994 G_CALLBACK (set_paste_menuitem_sensitivity), de);
996 g_signal_connect (dict, "weight-changed",
997 G_CALLBACK (on_weight_change),
1000 g_signal_connect (dict, "filter-changed",
1001 G_CALLBACK (on_filter_change),
1004 g_signal_connect (dict, "split-changed",
1005 G_CALLBACK (on_split_change),
1009 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1011 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1013 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1015 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1017 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1019 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1021 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1023 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1025 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1027 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1029 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1031 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1033 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1035 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1037 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1040 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1042 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1044 gtk_action_set_visible (de->delete_cases, FALSE);
1049 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1051 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1053 gtk_action_set_visible (de->delete_variables, FALSE);
1057 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1058 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1059 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1060 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1061 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1062 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1063 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1064 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1065 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1066 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1067 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1068 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1069 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1070 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1071 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1072 connect_action (de, "analyze_frequencies", G_CALLBACK (frequencies_dialog));
1073 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1074 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1075 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1076 connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
1077 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1078 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1079 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1080 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1083 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1085 GtkWidget *recent_data =
1086 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1088 GtkWidget *recent_files =
1089 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1092 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1093 gtk_recent_manager_get_default ());
1095 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1096 gtk_recent_manager_get_default ());
1098 g_object_set (menu_data, "show-tips", TRUE, NULL);
1099 g_object_set (menu_files, "show-tips", TRUE, NULL);
1102 GtkRecentFilter *filter = gtk_recent_filter_new ();
1104 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1105 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1107 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1109 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1112 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1115 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1118 GtkRecentFilter *filter = gtk_recent_filter_new ();
1120 gtk_recent_filter_add_pattern (filter, "*.sps");
1121 gtk_recent_filter_add_pattern (filter, "*.SPS");
1123 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1125 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1128 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1130 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1134 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1137 g_signal_connect (de->data_editor,
1139 G_CALLBACK (enable_delete_cases),
1142 g_signal_connect (de->data_editor,
1143 "variables-selected",
1144 G_CALLBACK (enable_delete_variables),
1148 g_signal_connect (de->data_editor,
1150 G_CALLBACK (on_switch_sheet), de);
1152 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1153 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1155 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1157 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1159 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1161 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1163 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1165 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1167 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1169 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1171 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1174 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1176 merge_help_menu (uim);
1180 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1181 "datasheet-cases-popup");
1183 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1184 "varsheet-variable-popup");
1186 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1187 "datasheet-variable-popup");
1189 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1190 G_CALLBACK (psppire_data_editor_sort_ascending),
1193 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1194 G_CALLBACK (psppire_data_editor_sort_descending),
1197 g_object_set (de->data_editor,
1198 "datasheet-column-menu", data_sheet_variable_popup_menu,
1199 "datasheet-row-menu", data_sheet_cases_popup_menu,
1200 "varsheet-row-menu", var_sheet_variable_popup_menu,
1204 gtk_widget_show (GTK_WIDGET (de->data_editor));
1205 gtk_widget_show (box);
1207 ll_push_head (&all_data_windows, &de->ll);
1211 psppire_data_window_dispose (GObject *object)
1213 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1217 struct dataset *dataset = dw->dataset;
1218 struct session *session = dataset_session (dataset);
1222 dataset_set_callbacks (dataset, NULL, NULL);
1223 session_set_active_dataset (session, NULL);
1224 dataset_destroy (dataset);
1227 if (dw->builder != NULL)
1229 g_object_unref (dw->builder);
1235 g_object_unref (dw->var_store);
1236 dw->var_store = NULL;
1241 g_object_unref (dw->data_store);
1242 dw->data_store = NULL;
1245 if (dw->ll.next != NULL)
1247 ll_remove (&dw->ll);
1251 if (G_OBJECT_CLASS (parent_class)->dispose)
1252 G_OBJECT_CLASS (parent_class)->dispose (object);
1256 psppire_data_window_set_property (GObject *object,
1258 const GValue *value,
1261 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1266 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1275 psppire_data_window_get_property (GObject *object,
1280 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1285 g_value_set_pointer (value, window->dataset);
1288 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1294 psppire_data_window_new (struct dataset *ds)
1298 if (the_session == NULL)
1299 the_session = session_create ();
1303 char *dataset_name = session_generate_dataset_name (the_session);
1304 ds = dataset_create (the_session, dataset_name);
1305 free (dataset_name);
1307 assert (dataset_session (ds) == the_session);
1311 psppire_data_window_get_type (),
1312 "description", _("Data Editor"),
1316 if (dataset_name (ds) != NULL)
1317 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1323 psppire_data_window_is_empty (PsppireDataWindow *dw)
1325 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1329 psppire_data_window_iface_init (PsppireWindowIface *iface)
1331 iface->save = save_file;
1332 iface->pick_filename = data_pick_filename;
1333 iface->load = load_file;
1337 psppire_default_data_window (void)
1339 if (ll_is_empty (&all_data_windows))
1340 create_data_window ();
1341 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1345 psppire_data_window_set_default (PsppireDataWindow *pdw)
1347 ll_remove (&pdw->ll);
1348 ll_push_head (&all_data_windows, &pdw->ll);
1352 psppire_data_window_undefault (PsppireDataWindow *pdw)
1354 ll_remove (&pdw->ll);
1355 ll_push_tail (&all_data_windows, &pdw->ll);
1359 psppire_data_window_for_dataset (struct dataset *ds)
1361 PsppireDataWindow *pdw;
1363 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1364 if (pdw->dataset == ds)
1371 create_data_window (void)
1373 gtk_widget_show (psppire_data_window_new (NULL));
1377 open_data_window (PsppireWindow *victim, const char *file_name)
1381 if (PSPPIRE_IS_DATA_WINDOW (victim)
1382 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1383 window = GTK_WIDGET (victim);
1385 window = psppire_data_window_new (NULL);
1387 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1388 gtk_widget_show (window);