1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/builder-wrapper.h"
30 #include "ui/gui/chi-square-dialog.h"
31 #include "ui/gui/comments-dialog.h"
32 #include "ui/gui/compute-dialog.h"
33 #include "ui/gui/count-dialog.h"
34 #include "ui/gui/crosstabs-dialog.h"
35 #include "ui/gui/entry-dialog.h"
36 #include "ui/gui/executor.h"
37 #include "ui/gui/find-dialog.h"
38 #include "ui/gui/goto-case-dialog.h"
39 #include "ui/gui/help-menu.h"
40 #include "ui/gui/helper.h"
41 #include "ui/gui/helper.h"
42 #include "ui/gui/k-related-dialog.h"
43 #include "ui/gui/npar-two-sample-related.h"
44 #include "ui/gui/oneway-anova-dialog.h"
45 #include "ui/gui/psppire-data-window.h"
46 #include "ui/gui/psppire-syntax-window.h"
47 #include "ui/gui/psppire-window.h"
48 #include "ui/gui/psppire.h"
49 #include "ui/gui/runs-dialog.h"
50 #include "ui/gui/ks-one-sample-dialog.h"
51 #include "ui/gui/recode-dialog.h"
52 #include "ui/gui/select-cases-dialog.h"
53 #include "ui/gui/split-file-dialog.h"
54 #include "ui/gui/t-test-one-sample.h"
55 #include "ui/gui/t-test-paired-samples.h"
56 #include "ui/gui/text-data-import-dialog.h"
57 #include "ui/gui/transpose-dialog.h"
58 #include "ui/gui/univariate-dialog.h"
59 #include "ui/gui/weight-cases-dialog.h"
60 #include "ui/syntax-gen.h"
62 #include "gl/c-strcase.h"
63 #include "gl/c-strcasestr.h"
64 #include "gl/xvasprintf.h"
67 #define _(msgid) gettext (msgid)
68 #define N_(msgid) msgid
70 struct session *the_session;
71 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
73 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
74 static void psppire_data_window_init (PsppireDataWindow *data_editor);
77 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
79 static void psppire_data_window_dispose (GObject *object);
80 static void psppire_data_window_finalize (GObject *object);
81 static void psppire_data_window_set_property (GObject *object,
85 static void psppire_data_window_get_property (GObject *object,
91 psppire_data_window_get_type (void)
93 static GType psppire_data_window_type = 0;
95 if (!psppire_data_window_type)
97 static const GTypeInfo psppire_data_window_info =
99 sizeof (PsppireDataWindowClass),
102 (GClassInitFunc)psppire_data_window_class_init,
103 (GClassFinalizeFunc) NULL,
105 sizeof (PsppireDataWindow),
107 (GInstanceInitFunc) psppire_data_window_init,
110 static const GInterfaceInfo window_interface_info =
112 (GInterfaceInitFunc) psppire_data_window_iface_init,
117 psppire_data_window_type =
118 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
119 &psppire_data_window_info, 0);
122 g_type_add_interface_static (psppire_data_window_type,
123 PSPPIRE_TYPE_WINDOW_MODEL,
124 &window_interface_info);
127 return psppire_data_window_type;
130 static GObjectClass *parent_class ;
137 psppire_data_window_class_init (PsppireDataWindowClass *class)
139 GObjectClass *object_class = G_OBJECT_CLASS (class);
141 parent_class = g_type_class_peek_parent (class);
143 object_class->dispose = psppire_data_window_dispose;
144 object_class->finalize = psppire_data_window_finalize;
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 /* Only a data file with at least one variable can be saved. */
915 enable_save (PsppireDataWindow *dw)
917 PsppireDict *dict = dw->var_store->dictionary;
918 gboolean enable = psppire_dict_get_var_cnt (dict) > 0;
920 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
922 gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
926 /* Initializes as much of a PsppireDataWindow as we can and must before the
927 dataset has been set.
929 In particular, the 'menu' member is required in case the "filename" property
930 is set before the "dataset" property: otherwise PsppireWindow will try to
931 modify the menu as part of the "filename" property_set() function and end up
932 with a Gtk-CRITICAL since 'menu' is NULL. */
934 psppire_data_window_init (PsppireDataWindow *de)
938 de->builder = builder_new ("data-editor.ui");
940 uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
942 PSPPIRE_WINDOW (de)->menu =
943 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
947 psppire_data_window_finish_init (PsppireDataWindow *de,
950 static const struct dataset_callbacks cbs =
952 set_unsaved, /* changed */
953 transformation_change_callback, /* transformations_changed */
962 GtkWidget *box = gtk_vbox_new (FALSE, 0);
965 dict = psppire_dict_new_from_dict (dataset_dict (ds));
966 de->var_store = psppire_var_store_new (dict);
967 g_object_unref (dict);
968 de->data_store = psppire_data_store_new (dict);
969 psppire_data_store_set_reader (de->data_store, NULL);
971 menubar = get_widget_assert (de->builder, "menubar");
972 hb = get_widget_assert (de->builder, "handlebox1");
973 sb = get_widget_assert (de->builder, "status-bar");
976 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
979 g_signal_connect_swapped (de->data_store, "case-changed",
980 G_CALLBACK (set_unsaved), de);
982 g_signal_connect_swapped (de->data_store, "case-inserted",
983 G_CALLBACK (set_unsaved), de);
985 g_signal_connect_swapped (de->data_store, "cases-deleted",
986 G_CALLBACK (set_unsaved), de);
988 dataset_set_callbacks (de->dataset, &cbs, de);
990 connect_help (de->builder);
992 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
993 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
994 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
995 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
997 gtk_container_add (GTK_CONTAINER (de), box);
999 set_cut_copy_menuitem_sensitivity (de, FALSE);
1001 g_signal_connect_swapped (de->data_editor, "data-selection-changed",
1002 G_CALLBACK (set_cut_copy_menuitem_sensitivity), de);
1005 set_paste_menuitem_sensitivity (de, FALSE);
1007 g_signal_connect_swapped (de->data_editor, "data-available-changed",
1008 G_CALLBACK (set_paste_menuitem_sensitivity), de);
1010 g_signal_connect (dict, "weight-changed",
1011 G_CALLBACK (on_weight_change),
1014 g_signal_connect (dict, "filter-changed",
1015 G_CALLBACK (on_filter_change),
1018 g_signal_connect (dict, "split-changed",
1019 G_CALLBACK (on_split_change),
1022 g_signal_connect_swapped (dict, "backend-changed",
1023 G_CALLBACK (enable_save), de);
1024 g_signal_connect_swapped (dict, "variable-inserted",
1025 G_CALLBACK (enable_save), de);
1026 g_signal_connect_swapped (dict, "variable-deleted",
1027 G_CALLBACK (enable_save), de);
1030 connect_action (de, "edit_copy", G_CALLBACK (on_edit_copy));
1032 connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
1034 connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
1036 connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
1038 connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
1040 connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
1042 connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
1044 connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
1046 connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1048 connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1050 connect_action (de, "edit_paste", G_CALLBACK (on_edit_paste));
1052 de->insert_case = connect_action (de, "edit_insert-case", G_CALLBACK (insert_case));
1054 de->insert_variable = connect_action (de, "action_insert-variable", G_CALLBACK (on_insert_variable));
1056 de->invoke_goto_dialog = connect_action (de, "edit_goto-case", G_CALLBACK (goto_case_dialog));
1058 g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1061 de->delete_cases = get_action_assert (de->builder, "edit_clear-cases");
1063 g_signal_connect_swapped (de->delete_cases, "activate", G_CALLBACK (psppire_data_editor_delete_cases), de->data_editor);
1065 gtk_action_set_visible (de->delete_cases, FALSE);
1070 de->delete_variables = get_action_assert (de->builder, "edit_clear-variables");
1072 g_signal_connect_swapped (de->delete_variables, "activate", G_CALLBACK (psppire_data_editor_delete_variables), de->data_editor);
1074 gtk_action_set_visible (de->delete_variables, FALSE);
1078 connect_action (de, "data_transpose", G_CALLBACK (transpose_dialog));
1079 connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1080 connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1081 connect_action (de, "transform_compute", G_CALLBACK (compute_dialog));
1082 connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1083 connect_action (de, "edit_find", G_CALLBACK (find_dialog));
1084 connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1085 connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1086 connect_action (de, "oneway-anova", G_CALLBACK (oneway_anova_dialog));
1087 connect_action (de, "paired-t-test", G_CALLBACK (t_test_paired_samples_dialog));
1088 connect_action (de, "one-sample-t-test", G_CALLBACK (t_test_one_sample_dialog));
1089 connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1090 connect_action (de, "transform_count", G_CALLBACK (count_dialog));
1091 connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1092 connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1093 connect_action (de, "crosstabs", G_CALLBACK (crosstabs_dialog));
1094 connect_action (de, "univariate", G_CALLBACK (univariate_dialog));
1095 connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
1096 connect_action (de, "runs", G_CALLBACK (runs_dialog));
1097 connect_action (de, "ks-one-sample", G_CALLBACK (ks_one_sample_dialog));
1098 connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
1099 connect_action (de, "two-related-samples", G_CALLBACK (two_related_dialog));
1102 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1104 GtkWidget *recent_data =
1105 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-data");
1107 GtkWidget *recent_files =
1108 gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
1111 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1112 gtk_recent_manager_get_default ());
1114 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1115 gtk_recent_manager_get_default ());
1117 g_object_set (menu_data, "show-tips", TRUE, NULL);
1118 g_object_set (menu_files, "show-tips", TRUE, NULL);
1121 GtkRecentFilter *filter = gtk_recent_filter_new ();
1123 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1124 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1126 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1128 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1131 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1134 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1137 GtkRecentFilter *filter = gtk_recent_filter_new ();
1139 gtk_recent_filter_add_pattern (filter, "*.sps");
1140 gtk_recent_filter_add_pattern (filter, "*.SPS");
1142 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1144 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1147 gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1149 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1153 connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1156 g_signal_connect (de->data_editor,
1158 G_CALLBACK (enable_delete_cases),
1161 g_signal_connect (de->data_editor,
1162 "variables-selected",
1163 G_CALLBACK (enable_delete_variables),
1167 g_signal_connect (de->data_editor,
1169 G_CALLBACK (on_switch_sheet), de);
1171 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1172 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1174 connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1176 connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1178 connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1180 connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1182 connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1184 connect_action (de, "file_quit", G_CALLBACK (file_quit));
1186 connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1188 connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1190 g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1193 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
1195 merge_help_menu (uim);
1199 GtkWidget *data_sheet_cases_popup_menu = get_widget_assert (de->builder,
1200 "datasheet-cases-popup");
1202 GtkWidget *var_sheet_variable_popup_menu = get_widget_assert (de->builder,
1203 "varsheet-variable-popup");
1205 GtkWidget *data_sheet_variable_popup_menu = get_widget_assert (de->builder,
1206 "datasheet-variable-popup");
1208 g_signal_connect_swapped (get_action_assert (de->builder, "sort-up"), "activate",
1209 G_CALLBACK (psppire_data_editor_sort_ascending),
1212 g_signal_connect_swapped (get_action_assert (de->builder, "sort-down"), "activate",
1213 G_CALLBACK (psppire_data_editor_sort_descending),
1216 g_object_set (de->data_editor,
1217 "datasheet-column-menu", data_sheet_variable_popup_menu,
1218 "datasheet-row-menu", data_sheet_cases_popup_menu,
1219 "varsheet-row-menu", var_sheet_variable_popup_menu,
1223 gtk_widget_show (GTK_WIDGET (de->data_editor));
1224 gtk_widget_show (box);
1226 ll_push_head (&all_data_windows, &de->ll);
1230 psppire_data_window_dispose (GObject *object)
1232 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1234 if (dw->builder != NULL)
1236 g_object_unref (dw->builder);
1242 g_object_unref (dw->var_store);
1243 dw->var_store = NULL;
1248 g_object_unref (dw->data_store);
1249 dw->data_store = NULL;
1252 if (dw->ll.next != NULL)
1254 ll_remove (&dw->ll);
1258 if (G_OBJECT_CLASS (parent_class)->dispose)
1259 G_OBJECT_CLASS (parent_class)->dispose (object);
1263 psppire_data_window_finalize (GObject *object)
1265 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1269 struct dataset *dataset = dw->dataset;
1270 struct session *session = dataset_session (dataset);
1274 dataset_set_callbacks (dataset, NULL, NULL);
1275 session_set_active_dataset (session, NULL);
1276 dataset_destroy (dataset);
1279 if (G_OBJECT_CLASS (parent_class)->finalize)
1280 G_OBJECT_CLASS (parent_class)->finalize (object);
1284 psppire_data_window_set_property (GObject *object,
1286 const GValue *value,
1289 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1294 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1297 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1303 psppire_data_window_get_property (GObject *object,
1308 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1313 g_value_set_pointer (value, window->dataset);
1316 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1322 psppire_data_window_new (struct dataset *ds)
1326 if (the_session == NULL)
1327 the_session = session_create ();
1331 char *dataset_name = session_generate_dataset_name (the_session);
1332 ds = dataset_create (the_session, dataset_name);
1333 free (dataset_name);
1335 assert (dataset_session (ds) == the_session);
1339 psppire_data_window_get_type (),
1340 "description", _("Data Editor"),
1344 if (dataset_name (ds) != NULL)
1345 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1351 psppire_data_window_is_empty (PsppireDataWindow *dw)
1353 return psppire_var_store_get_var_cnt (dw->var_store) == 0;
1357 psppire_data_window_iface_init (PsppireWindowIface *iface)
1359 iface->save = save_file;
1360 iface->pick_filename = data_pick_filename;
1361 iface->load = load_file;
1365 psppire_default_data_window (void)
1367 if (ll_is_empty (&all_data_windows))
1368 create_data_window ();
1369 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1373 psppire_data_window_set_default (PsppireDataWindow *pdw)
1375 ll_remove (&pdw->ll);
1376 ll_push_head (&all_data_windows, &pdw->ll);
1380 psppire_data_window_undefault (PsppireDataWindow *pdw)
1382 ll_remove (&pdw->ll);
1383 ll_push_tail (&all_data_windows, &pdw->ll);
1387 psppire_data_window_for_dataset (struct dataset *ds)
1389 PsppireDataWindow *pdw;
1391 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1392 if (pdw->dataset == ds)
1399 create_data_window (void)
1401 gtk_widget_show (psppire_data_window_new (NULL));
1405 open_data_window (PsppireWindow *victim, const char *file_name)
1409 if (PSPPIRE_IS_DATA_WINDOW (victim)
1410 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1411 window = GTK_WIDGET (victim);
1413 window = psppire_data_window_new (NULL);
1415 psppire_window_load (PSPPIRE_WINDOW (window), file_name);
1416 gtk_widget_show (window);