1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 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/builder-wrapper.h"
28 #include "ui/gui/entry-dialog.h"
29 #include "ui/gui/executor.h"
30 #include "ui/gui/help-menu.h"
31 #include "ui/gui/helper.h"
32 #include "ui/gui/helper.h"
33 #include "ui/gui/psppire-import-assistant.h"
34 #include "ui/gui/psppire-data-window.h"
35 #include "ui/gui/psppire-dialog-action.h"
36 #include "ui/gui/psppire-encoding-selector.h"
37 #include "ui/gui/psppire-syntax-window.h"
38 #include "ui/gui/psppire-window.h"
39 #include "ui/gui/windows-menu.h"
40 #include "ui/gui/goto-case-dialog.h"
41 #include "ui/gui/psppire.h"
42 #include "ui/syntax-gen.h"
44 #include "gl/c-strcase.h"
45 #include "gl/c-strcasestr.h"
46 #include "gl/xvasprintf.h"
48 #include "find-dialog.h"
49 #include "psppire-dialog-action-1sks.h"
50 #include "psppire-dialog-action-aggregate.h"
51 #include "psppire-dialog-action-autorecode.h"
52 #include "psppire-dialog-action-barchart.h"
53 #include "psppire-dialog-action-binomial.h"
54 #include "psppire-dialog-action-chisquare.h"
55 #include "psppire-dialog-action-comments.h"
56 #include "psppire-dialog-action-compute.h"
57 #include "psppire-dialog-action-correlation.h"
58 #include "psppire-dialog-action-count.h"
59 #include "psppire-dialog-action-crosstabs.h"
60 #include "psppire-dialog-action-descriptives.h"
61 #include "psppire-dialog-action-examine.h"
62 #include "psppire-dialog-action-factor.h"
63 #include "psppire-dialog-action-flip.h"
64 #include "psppire-dialog-action-frequencies.h"
65 #include "psppire-dialog-action-histogram.h"
66 #include "psppire-dialog-action-indep-samps.h"
67 #include "psppire-dialog-action-k-related.h"
68 #include "psppire-dialog-action-kmeans.h"
69 #include "psppire-dialog-action-logistic.h"
70 #include "psppire-dialog-action-means.h"
71 #include "psppire-dialog-action-oneway.h"
72 #include "psppire-dialog-action-paired.h"
73 #include "psppire-dialog-action-rank.h"
74 #include "psppire-dialog-action-recode-same.h"
75 #include "psppire-dialog-action-recode-different.h"
76 #include "psppire-dialog-action-regression.h"
77 #include "psppire-dialog-action-reliability.h"
78 #include "psppire-dialog-action-roc.h"
79 #include "psppire-dialog-action-runs.h"
80 #include "psppire-dialog-action-scatterplot.h"
81 #include "psppire-dialog-action-select.h"
82 #include "psppire-dialog-action-sort.h"
83 #include "psppire-dialog-action-split.h"
84 #include "psppire-dialog-action-tt1s.h"
85 #include "psppire-dialog-action-two-sample.h"
86 #include "psppire-dialog-action-univariate.h"
87 #include "psppire-dialog-action-var-info.h"
88 #include "psppire-dialog-action-weight.h"
92 #define _(msgid) gettext (msgid)
93 #define N_(msgid) msgid
95 struct session *the_session;
96 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
98 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
99 static void psppire_data_window_init (PsppireDataWindow *data_editor);
102 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
104 static void psppire_data_window_dispose (GObject *object);
105 static void psppire_data_window_finalize (GObject *object);
106 static void psppire_data_window_set_property (GObject *object,
110 static void psppire_data_window_get_property (GObject *object,
116 psppire_data_window_get_type (void)
118 static GType psppire_data_window_type = 0;
120 if (!psppire_data_window_type)
122 static const GTypeInfo psppire_data_window_info =
124 sizeof (PsppireDataWindowClass),
127 (GClassInitFunc)psppire_data_window_class_init,
128 (GClassFinalizeFunc) NULL,
130 sizeof (PsppireDataWindow),
132 (GInstanceInitFunc) psppire_data_window_init,
135 static const GInterfaceInfo window_interface_info =
137 (GInterfaceInitFunc) psppire_data_window_iface_init,
142 psppire_data_window_type =
143 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
144 &psppire_data_window_info, 0);
147 g_type_add_interface_static (psppire_data_window_type,
148 PSPPIRE_TYPE_WINDOW_MODEL,
149 &window_interface_info);
152 return psppire_data_window_type;
155 static GObjectClass *parent_class ;
162 psppire_data_window_class_init (PsppireDataWindowClass *class)
164 GObjectClass *object_class = G_OBJECT_CLASS (class);
166 parent_class = g_type_class_peek_parent (class);
168 object_class->dispose = psppire_data_window_dispose;
169 object_class->finalize = psppire_data_window_finalize;
170 object_class->set_property = psppire_data_window_set_property;
171 object_class->get_property = psppire_data_window_get_property;
173 g_object_class_install_property (
174 object_class, PROP_DATASET,
175 g_param_spec_pointer ("dataset", "Dataset",
176 "'struct datset *' represented by the window",
177 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
182 /* Run the EXECUTE command. */
184 execute (PsppireDataWindow *dw)
186 execute_const_syntax_string (dw, "EXECUTE.");
190 transformation_change_callback (bool transformations_pending,
193 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
195 GtkWidget *status_label =
196 get_widget_assert (de->builder, "case-counter-area");
199 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de),
200 "transform-pending");
202 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
203 transformations_pending);
206 if ( transformations_pending)
207 gtk_label_set_text (GTK_LABEL (status_label),
208 _("Transformations Pending"));
210 gtk_label_set_text (GTK_LABEL (status_label), "");
213 /* Callback for when the dictionary changes its filter variable */
215 on_filter_change (GObject *o, gint filter_index, gpointer data)
217 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
219 GtkWidget *filter_status_area =
220 get_widget_assert (de->builder, "filter-use-status-area");
222 if ( filter_index == -1 )
224 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
228 PsppireDict *dict = NULL;
229 struct variable *var ;
232 g_object_get (de->data_editor, "dictionary", &dict, NULL);
234 var = psppire_dict_get_variable (dict, filter_index);
236 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
238 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
244 /* Callback for when the dictionary changes its split variables */
246 on_split_change (PsppireDict *dict, gpointer data)
248 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
250 size_t n_split_vars = dict_get_split_cnt (dict->dict);
252 GtkWidget *split_status_area =
253 get_widget_assert (de->builder, "split-file-status-area");
255 if ( n_split_vars == 0 )
257 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
263 const struct variable *const * split_vars =
264 dict_get_split_vars (dict->dict);
266 text = g_string_new (_("Split by "));
268 for (i = 0 ; i < n_split_vars - 1; ++i )
270 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
272 g_string_append (text, var_get_name (split_vars[i]));
274 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
276 g_string_free (text, TRUE);
283 /* Callback for when the dictionary changes its weights */
285 on_weight_change (GObject *o, gint weight_index, gpointer data)
287 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
289 GtkWidget *weight_status_area =
290 get_widget_assert (de->builder, "weight-status-area");
292 if ( weight_index == -1 )
294 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
298 struct variable *var ;
299 PsppireDict *dict = NULL;
302 g_object_get (de->data_editor, "dictionary", &dict, NULL);
304 var = psppire_dict_get_variable (dict, weight_index);
306 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
308 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
316 dump_rm (GtkRecentManager *rm)
318 GList *items = gtk_recent_manager_get_items (rm);
322 g_print ("Recent Items:\n");
323 for (i = items; i; i = i->next)
325 GtkRecentInfo *ri = i->data;
327 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
328 gtk_recent_info_get_short_name (ri),
329 gtk_recent_info_get_mime_type (ri),
330 gtk_recent_info_get_description (ri),
331 gtk_recent_info_get_uri (ri)
335 gtk_recent_info_unref (ri);
343 has_suffix (const gchar *name, const gchar *suffix)
345 size_t name_len = strlen (name);
346 size_t suffix_len = strlen (suffix);
347 return (name_len > suffix_len
348 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
352 name_has_por_suffix (const gchar *name)
354 return has_suffix (name, ".por");
358 name_has_sav_suffix (const gchar *name)
360 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
363 /* Returns true if NAME has a suffix which might denote a PSPP file */
365 name_has_suffix (const gchar *name)
367 return name_has_por_suffix (name) || name_has_sav_suffix (name);
371 load_file (PsppireWindow *de, const gchar *file_name, const char *encoding,
374 const char *mime_type = NULL;
375 gchar *syntax = NULL;
380 gchar *utf8_file_name;
381 struct string filename;
383 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
385 if (NULL == utf8_file_name)
388 ds_init_empty (&filename);
389 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
391 g_free (utf8_file_name);
393 if (encoding && encoding[0])
394 syntax = g_strdup_printf ("GET FILE=%s ENCODING='%s'.",
395 ds_cstr (&filename), encoding);
397 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
398 ds_destroy (&filename);
405 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
406 lex_reader_for_string (syntax, "UTF-8"));
409 if (ok && syn == NULL)
411 if (name_has_por_suffix (file_name))
412 mime_type = "application/x-spss-por";
413 else if (name_has_sav_suffix (file_name))
414 mime_type = "application/x-spss-sav";
416 add_most_recent (file_name, mime_type, encoding);
423 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
425 if (format == PSPPIRE_DATA_WINDOW_SAV)
427 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
433 /* Save DE to file */
435 save_file (PsppireWindow *w)
437 const gchar *file_name = NULL;
438 gchar *utf8_file_name = NULL;
440 struct string filename ;
441 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
444 file_name = psppire_window_get_filename (w);
446 fnx = g_string_new (file_name);
448 if ( ! name_has_suffix (fnx->str))
449 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
451 ds_init_empty (&filename);
453 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
455 g_string_free (fnx, TRUE);
457 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
458 g_free (utf8_file_name);
460 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
461 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
462 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
463 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
464 ds_cstr (&filename));
466 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
468 ds_destroy (&filename);
470 g_free (execute_syntax_string (de, syntax));
475 display_dict (PsppireDataWindow *de)
477 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
481 sysfile_info (PsppireDataWindow *de)
483 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
485 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
487 struct string filename;
489 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
490 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
493 const gchar *encoding = psppire_encoding_selector_get_encoding (
494 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
498 ds_init_empty (&filename);
500 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
502 g_free (utf8_file_name);
505 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
506 ds_cstr (&filename), encoding);
508 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
509 g_free (execute_syntax_string (de, syntax));
512 gtk_widget_destroy (dialog);
516 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
518 data_pick_filename (PsppireWindow *window)
520 GtkListStore *list_store;
521 GtkWidget *combo_box;
523 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
524 GtkFileFilter *filter;
526 gtk_file_chooser_dialog_new (_("Save"),
528 GTK_FILE_CHOOSER_ACTION_SAVE,
529 _("Cancel"), GTK_RESPONSE_CANCEL,
530 _("Save"), GTK_RESPONSE_ACCEPT,
533 g_object_set (dialog, "local-only", FALSE, NULL);
535 filter = gtk_file_filter_new ();
536 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
537 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
538 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
540 filter = gtk_file_filter_new ();
541 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
542 gtk_file_filter_add_pattern (filter, "*.zsav");
543 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
545 filter = gtk_file_filter_new ();
546 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
547 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
548 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
550 filter = gtk_file_filter_new ();
551 gtk_file_filter_set_name (filter, _("All Files"));
552 gtk_file_filter_add_pattern (filter, "*");
553 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
554 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
557 GtkCellRenderer *cell;
562 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
563 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
565 gtk_list_store_append (list_store, &iter);
566 gtk_list_store_set (list_store, &iter,
567 0, PSPPIRE_DATA_WINDOW_SAV,
570 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
572 gtk_list_store_append (list_store, &iter);
573 gtk_list_store_set (list_store, &iter,
574 0, PSPPIRE_DATA_WINDOW_ZSAV,
575 1, _("Compressed System File"),
578 gtk_list_store_append (list_store, &iter);
579 gtk_list_store_set (list_store, &iter,
580 0, PSPPIRE_DATA_WINDOW_POR,
581 1, _("Portable File"),
584 label = gtk_label_new (_("Format:"));
586 cell = gtk_cell_renderer_text_new ();
587 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
588 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
591 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
592 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
593 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
594 gtk_widget_show_all (hbox);
596 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
599 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
602 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
604 case GTK_RESPONSE_ACCEPT:
609 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
615 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
616 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
621 if ( ! name_has_suffix (filename->str))
622 g_string_append (filename,
623 psppire_data_window_format_to_string (format));
625 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
627 g_string_free (filename, TRUE);
634 gtk_widget_destroy (dialog);
638 confirm_delete_dataset (PsppireDataWindow *de,
639 const char *old_dataset,
640 const char *new_dataset,
641 const char *existing_dataset)
646 dialog = gtk_message_dialog_new (
647 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
648 _("Delete Existing Dataset?"));
650 gtk_message_dialog_format_secondary_text (
651 GTK_MESSAGE_DIALOG (dialog),
652 _("Renaming \"%s\" to \"%s\" will destroy the existing "
653 "dataset named \"%s\". Are you sure that you want to do this?"),
654 old_dataset, new_dataset, existing_dataset);
656 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
657 _("Cancel"), GTK_RESPONSE_CANCEL,
658 _("Delete"), GTK_RESPONSE_OK,
661 g_object_set (dialog, "icon-name", "pspp", NULL);
663 result = gtk_dialog_run (GTK_DIALOG (dialog));
665 gtk_widget_destroy (dialog);
667 return result == GTK_RESPONSE_OK;
671 on_rename_dataset (PsppireDataWindow *de)
673 struct dataset *ds = de->dataset;
674 struct session *session = dataset_session (ds);
675 const char *old_name = dataset_name (ds);
676 struct dataset *existing_dataset;
680 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
682 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
686 if (new_name == NULL)
689 existing_dataset = session_lookup_dataset (session, new_name);
690 if (existing_dataset == NULL || existing_dataset == ds
691 || confirm_delete_dataset (de, old_name, new_name,
692 dataset_name (existing_dataset)))
693 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
701 status_bar_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
703 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
705 GVariant *state = g_action_get_state (action);
706 const gboolean visible = g_variant_get_boolean (state);
707 g_action_change_state (action, g_variant_new_boolean (!visible));
709 gtk_widget_set_visible (statusbar, !visible);
714 grid_lines_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
716 GVariant *state = g_action_get_state (action);
717 const gboolean grid_visible = g_variant_get_boolean (state);
718 g_action_change_state (action, g_variant_new_boolean (!grid_visible));
720 psppire_data_editor_show_grid (de->data_editor, !grid_visible);
725 on_switch_page (GtkNotebook *notebook, GtkWidget *page, guint pn, gpointer ud)
727 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (ud);
729 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de), "view_dv");
734 g_action_change_state (action, g_variant_new_string ("DATA"));
735 gtk_widget_show (GTK_WIDGET (de->ti_insert_case));
736 gtk_widget_show (GTK_WIDGET (de->ti_jump_to_case));
737 gtk_widget_show (GTK_WIDGET (de->ti_find));
739 gtk_widget_show (GTK_WIDGET (de->mi_go_to_case));
740 gtk_widget_show (GTK_WIDGET (de->mi_insert_case));
741 gtk_widget_show (GTK_WIDGET (de->mi_find));
742 gtk_widget_show (GTK_WIDGET (de->mi_find_separator));
743 gtk_widget_show (GTK_WIDGET (de->mi_clear_cases));
748 g_action_change_state (action, g_variant_new_string ("VARS"));
749 gtk_widget_hide (GTK_WIDGET (de->ti_insert_case));
750 gtk_widget_hide (GTK_WIDGET (de->ti_jump_to_case));
751 gtk_widget_hide (GTK_WIDGET (de->ti_find));
753 gtk_widget_hide (GTK_WIDGET (de->mi_go_to_case));
754 gtk_widget_hide (GTK_WIDGET (de->mi_insert_case));
755 gtk_widget_hide (GTK_WIDGET (de->mi_find));
756 gtk_widget_hide (GTK_WIDGET (de->mi_find_separator));
757 gtk_widget_hide (GTK_WIDGET (de->mi_clear_cases));
765 activate_change_view (GAction *action, GVariant *param, PsppireDataWindow *de)
767 g_action_change_state (action, param);
768 GVariant *new_state = g_action_get_state (action);
770 const gchar *what = g_variant_get_string (new_state, NULL);
771 if (0 == g_strcmp0 (what, "DATA"))
773 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
775 else if (0 == g_strcmp0 (what, "VARS"))
777 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
784 fonts_activate (PsppireDataWindow *de)
786 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
787 GtkWidget *dialog = gtk_font_chooser_dialog_new (NULL, GTK_WINDOW (toplevel));
788 GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET(de->data_editor));
789 const PangoFontDescription *current_font = gtk_style_context_get_font (style, GTK_STATE_FLAG_NORMAL);
791 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (dialog), current_font);
793 gtk_window_set_transient_for (GTK_WINDOW (dialog),
794 GTK_WINDOW (toplevel));
796 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
798 PangoFontDescription* font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog));
800 psppire_data_editor_set_font (de->data_editor, font_desc);
803 gtk_widget_hide (dialog);
808 /* Callback for the value labels action */
811 value_labels_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
813 GVariant *v = g_action_get_state (action);
814 gboolean labels_active = g_variant_get_boolean (v);
815 g_action_change_state (action, g_variant_new_boolean (!labels_active));
817 GVariant *new_state = g_action_get_state (action);
818 labels_active = g_variant_get_boolean (new_state);
819 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
821 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (de->ti_value_labels_button),
826 on_labels_button_toggle (GtkToggleToolButton *ttb, PsppireDataWindow *de)
828 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "value_labels");
830 gboolean labels_active = gtk_toggle_tool_button_get_active (ttb);
832 g_action_change_state (a, g_variant_new_boolean (labels_active));
834 GVariant *new_state = g_action_get_state (a);
835 labels_active = g_variant_get_boolean (new_state);
836 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
840 on_recent_data_select (GtkMenuShell *menushell,
841 PsppireWindow *window)
846 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
848 file = g_filename_from_uri (uri, NULL, NULL);
852 open_data_window (window, file, NULL, NULL);
858 charset_from_mime_type (const char *mime_type)
864 if (mime_type == NULL)
867 charset = c_strcasestr (mime_type, "charset=");
875 /* Parse a "quoted-string" as defined by RFC 822. */
876 for (p++; *p != '\0' && *p != '"'; p++)
879 ds_put_byte (&s, *p);
880 else if (*++p != '\0')
881 ds_put_byte (&s, *p);
886 /* Parse a "token" as defined by RFC 2045. */
887 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
888 ds_put_byte (&s, *p++);
890 if (!ds_is_empty (&s))
891 return ds_steal_cstr (&s);
898 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
905 /* Get the file name and its encoding. */
906 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
907 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
908 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
909 gtk_recent_info_unref (item);
911 se = psppire_syntax_window_new (encoding);
915 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
916 gtk_widget_show (se);
918 gtk_widget_destroy (se);
924 set_unsaved (gpointer w)
926 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
930 /* Only a data file with at least one variable can be saved. */
932 enable_save (PsppireDataWindow *dw)
934 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
936 GAction *save_as = g_action_map_lookup_action (G_ACTION_MAP (dw), "save-as");
937 GAction *save = g_action_map_lookup_action (G_ACTION_MAP (dw), "save");
940 g_object_set (save, "enabled", enable, NULL);
943 g_object_set (save_as, "enabled", enable, NULL);
946 /* Initializes as much of a PsppireDataWindow as we can and must before the
947 dataset has been set.
949 In particular, the 'menu' member is required in case the "filename" property
950 is set before the "dataset" property: otherwise PsppireWindow will try to
951 modify the menu as part of the "filename" property_set() function and end up
952 with a Gtk-CRITICAL since 'menu' is NULL. */
954 psppire_data_window_init (PsppireDataWindow *de)
956 de->builder = builder_new ("data-editor.ui");
960 file_import (PsppireDataWindow *dw)
962 GtkWidget *w = psppire_import_assistant_new (GTK_WINDOW (dw));
963 PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
964 gtk_widget_show_all (w);
966 asst->main_loop = g_main_loop_new (NULL, TRUE);
967 g_main_loop_run (asst->main_loop);
968 g_main_loop_unref (asst->main_loop);
970 if (!asst->file_name)
973 switch (asst->response)
975 case GTK_RESPONSE_APPLY:
977 gchar *fn = g_path_get_basename (asst->file_name);
978 open_data_window (PSPPIRE_WINDOW (dw), fn, NULL, psppire_import_assistant_generate_syntax (asst));
982 case PSPPIRE_RESPONSE_PASTE:
983 free (paste_syntax_to_window (psppire_import_assistant_generate_syntax (asst)));
990 gtk_widget_destroy (GTK_WIDGET (asst));
996 connect_dialog_action (GType type, PsppireDataWindow *de)
998 GAction *act = g_object_new (type,
1002 g_action_map_add_action (G_ACTION_MAP (de), act);
1006 g_action_activate_null (GAction *a)
1008 g_action_activate (a, NULL);
1012 connect_action_to_menuitem (GActionMap *map, const gchar *action_name, GtkWidget *w, const gchar *accel)
1014 GAction *a = g_action_map_lookup_action (map, action_name);
1017 g_error ("Action \"%s\" not found in map", action_name);
1021 GtkApplication *app = GTK_APPLICATION (g_application_get_default());
1023 /* First set the label for the accellerator so that it appears
1025 GtkWidget *child = gtk_bin_get_child (GTK_BIN (w));
1027 GdkModifierType modifier;
1028 gtk_accelerator_parse (accel, &key, &modifier);
1029 gtk_accel_label_set_accel (GTK_ACCEL_LABEL (child), key, modifier);
1031 /* Now tell the application that it must do something when that
1032 key combination is pressed */
1033 const gchar *accels[2];
1037 gchar *detailed_action_name = NULL;
1038 if (GTK_IS_WINDOW (map))
1039 detailed_action_name = g_strdup_printf ("win.%s", action_name);
1040 else if (GTK_IS_APPLICATION (map))
1041 detailed_action_name = g_strdup_printf ("app.%s", action_name);
1043 gtk_application_set_accels_for_action (app,
1044 detailed_action_name,
1046 free (detailed_action_name);
1049 g_signal_connect_swapped (w, "activate", G_CALLBACK (g_action_activate_null), a);
1054 set_data_page (PsppireDataWindow *dw)
1056 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 1);
1057 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 0);
1062 on_cut (PsppireDataWindow *dw)
1065 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1068 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1069 psppire_data_sheet_edit_cut (ds);
1077 on_copy (PsppireDataWindow *dw)
1080 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1083 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1084 psppire_data_sheet_edit_copy (ds);
1090 on_paste (PsppireDataWindow *dw)
1093 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1096 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1097 psppire_data_sheet_edit_paste (ds);
1104 on_clear_cases (PsppireDataWindow *dw)
1107 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1110 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1111 psppire_data_sheet_edit_clear_cases (ds);
1117 on_clear_variables (PsppireDataWindow *dw)
1120 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1123 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1124 psppire_data_sheet_edit_clear_variables (ds);
1128 psppire_var_sheet_clear_variables (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1136 insert_variable (PsppireDataWindow *dw)
1139 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1142 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1143 psppire_data_sheet_insert_variable (ds);
1147 psppire_var_sheet_insert_variable (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1155 insert_case_at_row (PsppireDataWindow *dw)
1158 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1160 psppire_data_sheet_insert_case (ds);
1167 goto_case (PsppireDataWindow *dw)
1170 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1172 goto_case_dialog (ds);
1178 create_file_menu (PsppireDataWindow *dw)
1180 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1181 GtkWidget *menu = gtk_menu_new ();
1184 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1185 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1187 GtkWidget *new_menu = gtk_menu_new ();
1189 g_object_set (new, "submenu", new_menu, NULL);
1191 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1192 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1194 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1195 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1197 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1198 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1201 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1202 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Ctrl>O");
1204 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1205 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1207 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1208 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1210 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1212 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1213 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Ctrl>S");
1215 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1216 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Ctrl>S");
1218 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1219 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1222 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1223 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1224 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1226 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1229 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1230 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1232 GtkWidget *dd_menu = gtk_menu_new ();
1234 g_object_set (display_data, "submenu", dd_menu, NULL);
1236 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1237 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1238 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1239 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1241 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1242 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1245 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1248 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1249 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1251 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1252 gtk_recent_manager_get_default ());
1254 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1255 gtk_recent_manager_get_default ());
1257 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1258 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1260 g_object_set (menu_data, "show-tips", TRUE, NULL);
1261 g_object_set (menu_files, "show-tips", TRUE, NULL);
1263 g_object_set (mi_data, "submenu", menu_data, NULL);
1264 g_object_set (mi_files, "submenu", menu_files, NULL);
1267 GtkRecentFilter *filter = gtk_recent_filter_new ();
1269 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1270 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1272 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1274 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1277 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1280 GtkRecentFilter *filter = gtk_recent_filter_new ();
1282 gtk_recent_filter_add_pattern (filter, "*.sps");
1283 gtk_recent_filter_add_pattern (filter, "*.SPS");
1285 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1287 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1290 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1293 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1296 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1297 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1299 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1300 "quit", quit, "<Ctrl>Q");
1303 g_object_set (menuitem, "submenu", menu, NULL);
1304 gtk_widget_show_all (menuitem);
1311 create_edit_menu (PsppireDataWindow *dw)
1314 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1316 GtkWidget *menu = gtk_menu_new ();
1318 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1319 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1320 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1321 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1323 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1324 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1326 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1327 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1328 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1330 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1332 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1334 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1335 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1338 GtkAccelGroup *ag = gtk_accel_group_new ();
1340 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1341 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1343 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1344 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1345 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1347 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1348 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1349 'X', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1351 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1352 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1353 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1354 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1355 'C', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1357 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1358 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1359 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1360 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1361 'V', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1363 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1364 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1365 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1367 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1368 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1369 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1373 dw->mi_find_separator = gtk_separator_menu_item_new ();
1374 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1376 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1377 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1378 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1381 g_object_set (menuitem, "submenu", menu, NULL);
1383 gtk_widget_show_all (menuitem);
1389 psppire_data_window_finish_init (PsppireDataWindow *de,
1392 static const struct dataset_callbacks cbs =
1394 set_unsaved, /* changed */
1395 transformation_change_callback, /* transformations_changed */
1402 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1405 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1406 de->data_store = psppire_data_store_new (de->dict);
1407 psppire_data_store_set_reader (de->data_store, NULL);
1409 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1410 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1411 gtk_widget_show (menubar);
1413 hb = gtk_toolbar_new ();
1414 sb = get_widget_assert (de->builder, "status-bar");
1417 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1419 g_signal_connect (de, "realize",
1420 G_CALLBACK (set_data_page), de);
1422 g_signal_connect_swapped (de->data_store, "case-changed",
1423 G_CALLBACK (set_unsaved), de);
1425 g_signal_connect_swapped (de->data_store, "case-inserted",
1426 G_CALLBACK (set_unsaved), de);
1428 g_signal_connect_swapped (de->data_store, "cases-deleted",
1429 G_CALLBACK (set_unsaved), de);
1431 dataset_set_callbacks (de->dataset, &cbs, de);
1433 connect_help (de->builder);
1435 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1436 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1437 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1438 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1440 gtk_container_add (GTK_CONTAINER (de), box);
1442 g_signal_connect (de->dict, "weight-changed",
1443 G_CALLBACK (on_weight_change),
1446 g_signal_connect (de->dict, "filter-changed",
1447 G_CALLBACK (on_filter_change),
1450 g_signal_connect (de->dict, "split-changed",
1451 G_CALLBACK (on_split_change),
1454 g_signal_connect_swapped (de->dict, "changed",
1455 G_CALLBACK (enable_save), de);
1456 g_signal_connect_swapped (de->dict, "variable-inserted",
1457 G_CALLBACK (enable_save), de);
1458 g_signal_connect_swapped (de->dict, "variable-deleted",
1459 G_CALLBACK (enable_save), de);
1462 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1463 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1464 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1465 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1466 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1468 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1469 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1470 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1471 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1472 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1473 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1474 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1477 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1478 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1479 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1480 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1482 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1483 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1485 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1486 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1488 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1489 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1490 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1491 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1492 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1493 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1494 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1495 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1496 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1498 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1499 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1501 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1502 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1503 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1505 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1506 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1507 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1508 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1509 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1510 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1513 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1514 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1515 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1519 GSimpleAction *save = g_simple_action_new ("save", NULL);
1520 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1521 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1525 GSimpleAction *open = g_simple_action_new ("open", NULL);
1526 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1527 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1531 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1532 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1533 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1537 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1538 g_signal_connect_swapped (rename_dataset_act, "activate",
1539 G_CALLBACK (on_rename_dataset), de);
1540 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1544 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1545 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1546 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1549 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1550 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1551 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1555 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1556 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1557 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1561 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1562 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1563 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1568 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1569 g_variant_new_string ("DATA"));
1570 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1571 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1575 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1576 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1577 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1581 GSimpleAction *act_value_labels =
1582 g_simple_action_new_stateful ("value_labels", NULL,
1583 g_variant_new_boolean (FALSE));
1584 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1585 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1589 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1590 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1591 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1595 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1596 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1600 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1601 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1602 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1606 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1607 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1608 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1612 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1613 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1614 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1618 GSimpleAction *find = g_simple_action_new ("find", NULL);
1619 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1620 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1626 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1627 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1628 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1629 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1633 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1634 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1635 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1636 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1639 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1642 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1644 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1646 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1647 G_CALLBACK (psppire_dialog_action_activate_null), a);
1649 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1650 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1651 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1655 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1657 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1659 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1660 G_CALLBACK (g_action_activate_null), a);
1662 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1663 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1664 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1668 de->ti_find = gtk_tool_button_new (NULL, "Find");
1670 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1672 g_signal_connect_swapped (de->ti_find, "clicked",
1673 G_CALLBACK (g_action_activate_null), a);
1676 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1677 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1678 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1682 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1683 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1685 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1686 G_CALLBACK (g_action_activate_null), a);
1688 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1689 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1690 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1694 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1695 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1697 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1698 G_CALLBACK (g_action_activate_null), a);
1700 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1701 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1702 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1705 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1708 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1709 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1710 "PsppireDialogActionSplit");
1712 g_signal_connect_swapped (ti, "clicked",
1713 G_CALLBACK (psppire_dialog_action_activate_null), a);
1714 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1715 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1716 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1720 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1721 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1722 "PsppireDialogActionWeight");
1724 g_signal_connect_swapped (ti, "clicked",
1725 G_CALLBACK (psppire_dialog_action_activate_null), a);
1726 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1727 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1728 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1732 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1733 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1735 g_signal_connect (de->ti_value_labels_button, "toggled",
1736 G_CALLBACK (on_labels_button_toggle), de);
1737 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1738 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1739 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1744 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1745 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1747 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1748 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1749 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1750 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1752 g_signal_connect (de->data_editor, "switch-page",
1753 G_CALLBACK (on_switch_page), de);
1755 gtk_widget_show (GTK_WIDGET (de->data_editor));
1756 gtk_widget_show_all (box);
1758 ll_push_head (&all_data_windows, &de->ll);
1763 psppire_data_window_dispose (GObject *object)
1765 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1767 if (dw->builder != NULL)
1769 g_object_unref (dw->builder);
1775 g_signal_handlers_disconnect_by_func (dw->dict,
1776 G_CALLBACK (enable_save), dw);
1777 g_signal_handlers_disconnect_by_func (dw->dict,
1778 G_CALLBACK (on_weight_change), dw);
1779 g_signal_handlers_disconnect_by_func (dw->dict,
1780 G_CALLBACK (on_filter_change), dw);
1781 g_signal_handlers_disconnect_by_func (dw->dict,
1782 G_CALLBACK (on_split_change), dw);
1784 g_object_unref (dw->dict);
1790 g_object_unref (dw->data_store);
1791 dw->data_store = NULL;
1794 if (dw->ll.next != NULL)
1796 ll_remove (&dw->ll);
1800 if (G_OBJECT_CLASS (parent_class)->dispose)
1801 G_OBJECT_CLASS (parent_class)->dispose (object);
1805 psppire_data_window_finalize (GObject *object)
1807 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1811 struct dataset *dataset = dw->dataset;
1812 struct session *session = dataset_session (dataset);
1816 dataset_set_callbacks (dataset, NULL, NULL);
1817 session_set_active_dataset (session, NULL);
1818 dataset_destroy (dataset);
1821 if (G_OBJECT_CLASS (parent_class)->finalize)
1822 G_OBJECT_CLASS (parent_class)->finalize (object);
1826 psppire_data_window_set_property (GObject *object,
1828 const GValue *value,
1831 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1836 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1839 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1845 psppire_data_window_get_property (GObject *object,
1850 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1855 g_value_set_pointer (value, window->dataset);
1858 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1866 psppire_data_window_new (struct dataset *ds)
1870 if (the_session == NULL)
1871 the_session = session_create (NULL);
1875 char *dataset_name = session_generate_dataset_name (the_session);
1876 ds = dataset_create (the_session, dataset_name);
1877 free (dataset_name);
1879 assert (dataset_session (ds) == the_session);
1883 psppire_data_window_get_type (),
1884 "description", _("Data Editor"),
1888 if (dataset_name (ds) != NULL)
1889 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1892 GApplication *app = g_application_get_default ();
1893 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1901 psppire_data_window_is_empty (PsppireDataWindow *dw)
1903 return psppire_dict_get_var_cnt (dw->dict) == 0;
1908 psppire_data_window_iface_init (PsppireWindowIface *iface)
1910 iface->save = save_file;
1911 iface->pick_filename = data_pick_filename;
1912 iface->load = load_file;
1919 psppire_default_data_window (void)
1921 if (ll_is_empty (&all_data_windows))
1922 create_data_window ();
1923 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1929 psppire_data_window_set_default (PsppireDataWindow *pdw)
1931 ll_remove (&pdw->ll);
1932 ll_push_head (&all_data_windows, &pdw->ll);
1936 psppire_data_window_undefault (PsppireDataWindow *pdw)
1938 ll_remove (&pdw->ll);
1939 ll_push_tail (&all_data_windows, &pdw->ll);
1945 psppire_data_window_for_dataset (struct dataset *ds)
1947 PsppireDataWindow *pdw;
1949 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1950 if (pdw->dataset == ds)
1959 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1961 PsppireDataWindow *pdw;
1963 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1964 if (pdw->data_store == data_store)
1973 create_data_window (void)
1975 GtkWidget *w = psppire_data_window_new (NULL);
1977 gtk_widget_show (w);
1979 return GTK_WINDOW (w);
1985 open_data_window (PsppireWindow *victim, const char *file_name,
1986 const char *encoding, gpointer hint)
1990 if (PSPPIRE_IS_DATA_WINDOW (victim)
1991 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1993 window = GTK_WIDGET (victim);
1994 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1997 window = psppire_data_window_new (NULL);
1999 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
2000 gtk_widget_show_all (window);