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/psppire-data-sheet.h"
40 #include "ui/gui/psppire-var-sheet.h"
41 #include "ui/gui/windows-menu.h"
42 #include "ui/gui/goto-case-dialog.h"
43 #include "ui/gui/psppire.h"
44 #include "ui/syntax-gen.h"
46 #include "gl/c-strcase.h"
47 #include "gl/c-strcasestr.h"
48 #include "gl/xvasprintf.h"
50 #include "find-dialog.h"
51 #include "options-dialog.h"
52 #include "psppire-dialog-action-1sks.h"
53 #include "psppire-dialog-action-aggregate.h"
54 #include "psppire-dialog-action-autorecode.h"
55 #include "psppire-dialog-action-barchart.h"
56 #include "psppire-dialog-action-binomial.h"
57 #include "psppire-dialog-action-chisquare.h"
58 #include "psppire-dialog-action-comments.h"
59 #include "psppire-dialog-action-compute.h"
60 #include "psppire-dialog-action-correlation.h"
61 #include "psppire-dialog-action-count.h"
62 #include "psppire-dialog-action-crosstabs.h"
63 #include "psppire-dialog-action-descriptives.h"
64 #include "psppire-dialog-action-examine.h"
65 #include "psppire-dialog-action-factor.h"
66 #include "psppire-dialog-action-flip.h"
67 #include "psppire-dialog-action-frequencies.h"
68 #include "psppire-dialog-action-histogram.h"
69 #include "psppire-dialog-action-indep-samps.h"
70 #include "psppire-dialog-action-k-independent.h"
71 #include "psppire-dialog-action-k-related.h"
72 #include "psppire-dialog-action-kmeans.h"
73 #include "psppire-dialog-action-logistic.h"
74 #include "psppire-dialog-action-means.h"
75 #include "psppire-dialog-action-oneway.h"
76 #include "psppire-dialog-action-paired.h"
77 #include "psppire-dialog-action-rank.h"
78 #include "psppire-dialog-action-recode-same.h"
79 #include "psppire-dialog-action-recode-different.h"
80 #include "psppire-dialog-action-regression.h"
81 #include "psppire-dialog-action-reliability.h"
82 #include "psppire-dialog-action-roc.h"
83 #include "psppire-dialog-action-runs.h"
84 #include "psppire-dialog-action-scatterplot.h"
85 #include "psppire-dialog-action-select.h"
86 #include "psppire-dialog-action-sort.h"
87 #include "psppire-dialog-action-split.h"
88 #include "psppire-dialog-action-tt1s.h"
89 #include "psppire-dialog-action-two-sample.h"
90 #include "psppire-dialog-action-univariate.h"
91 #include "psppire-dialog-action-var-info.h"
92 #include "psppire-dialog-action-weight.h"
96 #define _(msgid) gettext (msgid)
97 #define N_(msgid) msgid
99 struct session *the_session;
100 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
102 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
103 static void psppire_data_window_init (PsppireDataWindow *data_editor);
106 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
108 static void psppire_data_window_dispose (GObject *object);
109 static void psppire_data_window_finalize (GObject *object);
110 static void psppire_data_window_set_property (GObject *object,
114 static void psppire_data_window_get_property (GObject *object,
120 psppire_data_window_get_type (void)
122 static GType psppire_data_window_type = 0;
124 if (!psppire_data_window_type)
126 static const GTypeInfo psppire_data_window_info =
128 sizeof (PsppireDataWindowClass),
131 (GClassInitFunc)psppire_data_window_class_init,
132 (GClassFinalizeFunc) NULL,
134 sizeof (PsppireDataWindow),
136 (GInstanceInitFunc) psppire_data_window_init,
139 static const GInterfaceInfo window_interface_info =
141 (GInterfaceInitFunc) psppire_data_window_iface_init,
146 psppire_data_window_type =
147 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
148 &psppire_data_window_info, 0);
151 g_type_add_interface_static (psppire_data_window_type,
152 PSPPIRE_TYPE_WINDOW_MODEL,
153 &window_interface_info);
156 return psppire_data_window_type;
159 static GObjectClass *parent_class ;
166 psppire_data_window_class_init (PsppireDataWindowClass *class)
168 GObjectClass *object_class = G_OBJECT_CLASS (class);
170 parent_class = g_type_class_peek_parent (class);
172 object_class->dispose = psppire_data_window_dispose;
173 object_class->finalize = psppire_data_window_finalize;
174 object_class->set_property = psppire_data_window_set_property;
175 object_class->get_property = psppire_data_window_get_property;
177 g_object_class_install_property (
178 object_class, PROP_DATASET,
179 g_param_spec_pointer ("dataset", "Dataset",
180 "'struct datset *' represented by the window",
181 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
186 /* Run the EXECUTE command. */
188 execute (PsppireDataWindow *dw)
190 execute_const_syntax_string (dw, "EXECUTE.");
194 transformation_change_callback (bool transformations_pending,
197 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
199 GtkWidget *status_label =
200 get_widget_assert (de->builder, "case-counter-area");
203 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de),
204 "transform-pending");
206 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
207 transformations_pending);
210 if ( transformations_pending)
211 gtk_label_set_text (GTK_LABEL (status_label),
212 _("Transformations Pending"));
214 gtk_label_set_text (GTK_LABEL (status_label), "");
217 /* Callback for when the dictionary changes its filter variable */
219 on_filter_change (GObject *o, gint filter_index, gpointer data)
221 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
223 GtkWidget *filter_status_area =
224 get_widget_assert (de->builder, "filter-use-status-area");
226 if ( filter_index == -1 )
228 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
232 PsppireDict *dict = NULL;
233 struct variable *var ;
236 g_object_get (de->data_editor, "dictionary", &dict, NULL);
238 var = psppire_dict_get_variable (dict, filter_index);
240 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
242 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
248 /* Callback for when the dictionary changes its split variables */
250 on_split_change (PsppireDict *dict, gpointer data)
252 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
254 size_t n_split_vars = dict_get_split_cnt (dict->dict);
256 GtkWidget *split_status_area =
257 get_widget_assert (de->builder, "split-file-status-area");
259 if ( n_split_vars == 0 )
261 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
267 const struct variable *const * split_vars =
268 dict_get_split_vars (dict->dict);
270 text = g_string_new (_("Split by "));
272 for (i = 0 ; i < n_split_vars - 1; ++i )
274 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
276 g_string_append (text, var_get_name (split_vars[i]));
278 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
280 g_string_free (text, TRUE);
287 /* Callback for when the dictionary changes its weights */
289 on_weight_change (GObject *o, gint weight_index, gpointer data)
291 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
293 GtkWidget *weight_status_area =
294 get_widget_assert (de->builder, "weight-status-area");
296 if ( weight_index == -1 )
298 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
302 struct variable *var ;
303 PsppireDict *dict = NULL;
306 g_object_get (de->data_editor, "dictionary", &dict, NULL);
308 var = psppire_dict_get_variable (dict, weight_index);
310 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
312 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
320 dump_rm (GtkRecentManager *rm)
322 GList *items = gtk_recent_manager_get_items (rm);
326 g_print ("Recent Items:\n");
327 for (i = items; i; i = i->next)
329 GtkRecentInfo *ri = i->data;
331 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
332 gtk_recent_info_get_short_name (ri),
333 gtk_recent_info_get_mime_type (ri),
334 gtk_recent_info_get_description (ri),
335 gtk_recent_info_get_uri (ri)
339 gtk_recent_info_unref (ri);
347 has_suffix (const gchar *name, const gchar *suffix)
349 size_t name_len = strlen (name);
350 size_t suffix_len = strlen (suffix);
351 return (name_len > suffix_len
352 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
356 name_has_por_suffix (const gchar *name)
358 return has_suffix (name, ".por");
362 name_has_sav_suffix (const gchar *name)
364 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
367 /* Returns true if NAME has a suffix which might denote a PSPP file */
369 name_has_suffix (const gchar *name)
371 return name_has_por_suffix (name) || name_has_sav_suffix (name);
375 load_file (PsppireWindow *de, const gchar *file_name, const char *encoding,
378 const char *mime_type = NULL;
379 gchar *syntax = NULL;
384 gchar *utf8_file_name;
385 struct string filename;
387 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
389 if (NULL == utf8_file_name)
392 ds_init_empty (&filename);
393 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
395 g_free (utf8_file_name);
397 if (encoding && encoding[0])
398 syntax = g_strdup_printf ("GET FILE=%s ENCODING='%s'.",
399 ds_cstr (&filename), encoding);
401 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
402 ds_destroy (&filename);
409 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
410 lex_reader_for_string (syntax, "UTF-8"));
413 if (ok && syn == NULL)
415 if (name_has_por_suffix (file_name))
416 mime_type = "application/x-spss-por";
417 else if (name_has_sav_suffix (file_name))
418 mime_type = "application/x-spss-sav";
420 add_most_recent (file_name, mime_type, encoding);
427 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
429 if (format == PSPPIRE_DATA_WINDOW_SAV)
431 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
437 /* Save DE to file */
439 save_file (PsppireWindow *w)
441 const gchar *file_name = NULL;
442 gchar *utf8_file_name = NULL;
444 struct string filename ;
445 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
448 file_name = psppire_window_get_filename (w);
450 fnx = g_string_new (file_name);
452 if ( ! name_has_suffix (fnx->str))
453 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
455 ds_init_empty (&filename);
457 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
459 g_string_free (fnx, TRUE);
461 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
462 g_free (utf8_file_name);
464 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
465 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
466 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
467 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
468 ds_cstr (&filename));
470 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
472 ds_destroy (&filename);
474 g_free (execute_syntax_string (de, syntax));
479 display_dict (PsppireDataWindow *de)
481 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
485 sysfile_info (PsppireDataWindow *de)
487 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
489 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
491 struct string filename;
493 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
494 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
497 const gchar *encoding = psppire_encoding_selector_get_encoding (
498 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
502 ds_init_empty (&filename);
504 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
506 g_free (utf8_file_name);
509 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
510 ds_cstr (&filename), encoding);
512 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
513 g_free (execute_syntax_string (de, syntax));
516 gtk_widget_destroy (dialog);
520 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
522 data_pick_filename (PsppireWindow *window)
524 GtkListStore *list_store;
525 GtkWidget *combo_box;
527 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
528 GtkFileFilter *filter;
530 gtk_file_chooser_dialog_new (_("Save"),
532 GTK_FILE_CHOOSER_ACTION_SAVE,
533 _("Cancel"), GTK_RESPONSE_CANCEL,
534 _("Save"), GTK_RESPONSE_ACCEPT,
537 g_object_set (dialog, "local-only", FALSE, NULL);
539 filter = gtk_file_filter_new ();
540 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
541 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
542 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
544 filter = gtk_file_filter_new ();
545 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
546 gtk_file_filter_add_pattern (filter, "*.zsav");
547 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
549 filter = gtk_file_filter_new ();
550 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
551 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
552 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
554 filter = gtk_file_filter_new ();
555 gtk_file_filter_set_name (filter, _("All Files"));
556 gtk_file_filter_add_pattern (filter, "*");
557 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
558 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
561 GtkCellRenderer *cell;
566 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
567 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
569 gtk_list_store_append (list_store, &iter);
570 gtk_list_store_set (list_store, &iter,
571 0, PSPPIRE_DATA_WINDOW_SAV,
574 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
576 gtk_list_store_append (list_store, &iter);
577 gtk_list_store_set (list_store, &iter,
578 0, PSPPIRE_DATA_WINDOW_ZSAV,
579 1, _("Compressed System File"),
582 gtk_list_store_append (list_store, &iter);
583 gtk_list_store_set (list_store, &iter,
584 0, PSPPIRE_DATA_WINDOW_POR,
585 1, _("Portable File"),
588 label = gtk_label_new (_("Format:"));
590 cell = gtk_cell_renderer_text_new ();
591 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
592 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
595 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
596 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
597 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
598 gtk_widget_show_all (hbox);
600 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
603 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
606 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
608 case GTK_RESPONSE_ACCEPT:
613 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
619 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
620 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
625 if ( ! name_has_suffix (filename->str))
626 g_string_append (filename,
627 psppire_data_window_format_to_string (format));
629 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
631 g_string_free (filename, TRUE);
638 gtk_widget_destroy (dialog);
642 confirm_delete_dataset (PsppireDataWindow *de,
643 const char *old_dataset,
644 const char *new_dataset,
645 const char *existing_dataset)
650 dialog = gtk_message_dialog_new (
651 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
652 _("Delete Existing Dataset?"));
654 gtk_message_dialog_format_secondary_text (
655 GTK_MESSAGE_DIALOG (dialog),
656 _("Renaming \"%s\" to \"%s\" will destroy the existing "
657 "dataset named \"%s\". Are you sure that you want to do this?"),
658 old_dataset, new_dataset, existing_dataset);
660 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
661 _("Cancel"), GTK_RESPONSE_CANCEL,
662 _("Delete"), GTK_RESPONSE_OK,
665 g_object_set (dialog, "icon-name", "pspp", NULL);
667 result = gtk_dialog_run (GTK_DIALOG (dialog));
669 gtk_widget_destroy (dialog);
671 return result == GTK_RESPONSE_OK;
675 on_rename_dataset (PsppireDataWindow *de)
677 struct dataset *ds = de->dataset;
678 struct session *session = dataset_session (ds);
679 const char *old_name = dataset_name (ds);
680 struct dataset *existing_dataset;
684 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
686 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
690 if (new_name == NULL)
693 existing_dataset = session_lookup_dataset (session, new_name);
694 if (existing_dataset == NULL || existing_dataset == ds
695 || confirm_delete_dataset (de, old_name, new_name,
696 dataset_name (existing_dataset)))
697 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
705 status_bar_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
707 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
709 GVariant *state = g_action_get_state (action);
710 const gboolean visible = g_variant_get_boolean (state);
711 g_action_change_state (action, g_variant_new_boolean (!visible));
713 gtk_widget_set_visible (statusbar, !visible);
718 grid_lines_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
720 GVariant *state = g_action_get_state (action);
721 const gboolean grid_visible = g_variant_get_boolean (state);
722 g_action_change_state (action, g_variant_new_boolean (!grid_visible));
724 psppire_data_editor_show_grid (de->data_editor, !grid_visible);
729 on_switch_page (GtkNotebook *notebook, GtkWidget *page, guint pn, gpointer ud)
731 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (ud);
733 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de), "view_dv");
738 g_action_change_state (action, g_variant_new_string ("DATA"));
739 gtk_widget_show (GTK_WIDGET (de->ti_insert_case));
740 gtk_widget_show (GTK_WIDGET (de->ti_jump_to_case));
741 gtk_widget_show (GTK_WIDGET (de->ti_find));
743 gtk_widget_show (GTK_WIDGET (de->mi_go_to_case));
744 gtk_widget_show (GTK_WIDGET (de->mi_insert_case));
745 gtk_widget_show (GTK_WIDGET (de->mi_find));
746 gtk_widget_show (GTK_WIDGET (de->mi_find_separator));
747 gtk_widget_show (GTK_WIDGET (de->mi_clear_cases));
752 g_action_change_state (action, g_variant_new_string ("VARS"));
753 gtk_widget_hide (GTK_WIDGET (de->ti_insert_case));
754 gtk_widget_hide (GTK_WIDGET (de->ti_jump_to_case));
755 gtk_widget_hide (GTK_WIDGET (de->ti_find));
757 gtk_widget_hide (GTK_WIDGET (de->mi_go_to_case));
758 gtk_widget_hide (GTK_WIDGET (de->mi_insert_case));
759 gtk_widget_hide (GTK_WIDGET (de->mi_find));
760 gtk_widget_hide (GTK_WIDGET (de->mi_find_separator));
761 gtk_widget_hide (GTK_WIDGET (de->mi_clear_cases));
769 activate_change_view (GAction *action, GVariant *param, PsppireDataWindow *de)
771 g_action_change_state (action, param);
772 GVariant *new_state = g_action_get_state (action);
774 const gchar *what = g_variant_get_string (new_state, NULL);
775 if (0 == g_strcmp0 (what, "DATA"))
777 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
779 else if (0 == g_strcmp0 (what, "VARS"))
781 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
788 fonts_activate (PsppireDataWindow *de)
790 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
791 GtkWidget *dialog = gtk_font_chooser_dialog_new (NULL, GTK_WINDOW (toplevel));
792 GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET(de->data_editor));
793 const PangoFontDescription *current_font ;
795 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, "font", ¤t_font, NULL);
797 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (dialog), current_font);
799 gtk_window_set_transient_for (GTK_WINDOW (dialog),
800 GTK_WINDOW (toplevel));
802 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
804 PangoFontDescription* font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog));
806 psppire_data_editor_set_font (de->data_editor, font_desc);
809 gtk_widget_hide (dialog);
814 /* Callback for the value labels action */
817 value_labels_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
819 GVariant *v = g_action_get_state (action);
820 gboolean labels_active = g_variant_get_boolean (v);
821 g_action_change_state (action, g_variant_new_boolean (!labels_active));
823 GVariant *new_state = g_action_get_state (action);
824 labels_active = g_variant_get_boolean (new_state);
825 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
827 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (de->ti_value_labels_button),
832 on_labels_button_toggle (GtkToggleToolButton *ttb, PsppireDataWindow *de)
834 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "value_labels");
836 gboolean labels_active = gtk_toggle_tool_button_get_active (ttb);
838 g_action_change_state (a, g_variant_new_boolean (labels_active));
840 GVariant *new_state = g_action_get_state (a);
841 labels_active = g_variant_get_boolean (new_state);
842 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
846 on_recent_data_select (GtkMenuShell *menushell,
847 PsppireWindow *window)
852 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
854 file = g_filename_from_uri (uri, NULL, NULL);
858 open_data_window (window, file, NULL, NULL);
864 charset_from_mime_type (const char *mime_type)
870 if (mime_type == NULL)
873 charset = c_strcasestr (mime_type, "charset=");
881 /* Parse a "quoted-string" as defined by RFC 822. */
882 for (p++; *p != '\0' && *p != '"'; p++)
885 ds_put_byte (&s, *p);
886 else if (*++p != '\0')
887 ds_put_byte (&s, *p);
892 /* Parse a "token" as defined by RFC 2045. */
893 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
894 ds_put_byte (&s, *p++);
896 if (!ds_is_empty (&s))
897 return ds_steal_cstr (&s);
904 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
911 /* Get the file name and its encoding. */
912 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
913 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
914 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
915 gtk_recent_info_unref (item);
917 se = psppire_syntax_window_new (encoding);
921 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
922 gtk_widget_show (se);
924 gtk_widget_destroy (se);
930 set_unsaved (gpointer w)
932 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
936 /* Only a data file with at least one variable can be saved. */
938 enable_save (PsppireDataWindow *dw)
940 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
942 GAction *save_as = g_action_map_lookup_action (G_ACTION_MAP (dw), "save-as");
943 GAction *save = g_action_map_lookup_action (G_ACTION_MAP (dw), "save");
946 g_object_set (save, "enabled", enable, NULL);
949 g_object_set (save_as, "enabled", enable, NULL);
952 /* Initializes as much of a PsppireDataWindow as we can and must before the
953 dataset has been set.
955 In particular, the 'menu' member is required in case the "filename" property
956 is set before the "dataset" property: otherwise PsppireWindow will try to
957 modify the menu as part of the "filename" property_set() function and end up
958 with a Gtk-CRITICAL since 'menu' is NULL. */
960 psppire_data_window_init (PsppireDataWindow *de)
962 de->builder = builder_new ("data-editor.ui");
966 file_import (PsppireDataWindow *dw)
968 GtkWidget *w = psppire_import_assistant_new (GTK_WINDOW (dw));
969 PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
970 gtk_widget_show_all (w);
972 asst->main_loop = g_main_loop_new (NULL, TRUE);
973 g_main_loop_run (asst->main_loop);
974 g_main_loop_unref (asst->main_loop);
976 if (!asst->file_name)
979 switch (asst->response)
981 case GTK_RESPONSE_APPLY:
983 gchar *fn = g_path_get_basename (asst->file_name);
984 open_data_window (PSPPIRE_WINDOW (dw), fn, NULL, psppire_import_assistant_generate_syntax (asst));
988 case PSPPIRE_RESPONSE_PASTE:
989 free (paste_syntax_to_window (psppire_import_assistant_generate_syntax (asst)));
996 gtk_widget_destroy (GTK_WIDGET (asst));
1002 connect_dialog_action (GType type, PsppireDataWindow *de)
1004 GAction *act = g_object_new (type,
1008 g_action_map_add_action (G_ACTION_MAP (de), act);
1012 g_action_activate_null (GAction *a)
1014 g_action_activate (a, NULL);
1018 connect_action_to_menuitem (GActionMap *map, const gchar *action_name, GtkWidget *w, const gchar *accel)
1020 GAction *a = g_action_map_lookup_action (map, action_name);
1023 g_error ("Action \"%s\" not found in map", action_name);
1027 GtkApplication *app = GTK_APPLICATION (g_application_get_default());
1029 /* First set the label for the accellerator so that it appears
1031 GtkWidget *child = gtk_bin_get_child (GTK_BIN (w));
1033 GdkModifierType modifier;
1034 gtk_accelerator_parse (accel, &key, &modifier);
1035 gtk_accel_label_set_accel (GTK_ACCEL_LABEL (child), key, modifier);
1037 /* Now tell the application that it must do something when that
1038 key combination is pressed */
1039 const gchar *accels[2];
1043 gchar *detailed_action_name = NULL;
1044 if (GTK_IS_WINDOW (map))
1045 detailed_action_name = g_strdup_printf ("win.%s", action_name);
1046 else if (GTK_IS_APPLICATION (map))
1047 detailed_action_name = g_strdup_printf ("app.%s", action_name);
1049 gtk_application_set_accels_for_action (app,
1050 detailed_action_name,
1052 free (detailed_action_name);
1055 g_signal_connect_swapped (w, "activate", G_CALLBACK (g_action_activate_null), a);
1060 set_data_page (PsppireDataWindow *dw)
1062 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 1);
1063 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 0);
1068 on_cut (PsppireDataWindow *dw)
1070 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1073 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1074 psppire_data_sheet_edit_cut (ds);
1079 on_copy (PsppireDataWindow *dw)
1081 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1084 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1085 psppire_data_sheet_edit_copy (ds);
1090 on_paste (PsppireDataWindow *dw)
1092 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1095 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1096 psppire_data_sheet_edit_paste (ds);
1102 on_clear_cases (PsppireDataWindow *dw)
1104 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1107 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1108 psppire_data_sheet_edit_clear_cases (ds);
1113 on_clear_variables (PsppireDataWindow *dw)
1115 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1118 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1119 psppire_data_sheet_edit_clear_variables (ds);
1123 psppire_var_sheet_clear_variables (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1129 insert_variable (PsppireDataWindow *dw)
1131 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1134 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1135 psppire_data_sheet_insert_variable (ds);
1139 psppire_var_sheet_insert_variable (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1145 insert_case_at_row (PsppireDataWindow *dw)
1147 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1149 psppire_data_sheet_insert_case (ds);
1153 goto_case (PsppireDataWindow *dw)
1155 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1157 goto_case_dialog (ds);
1163 create_file_menu (PsppireDataWindow *dw)
1165 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1166 GtkWidget *menu = gtk_menu_new ();
1169 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1170 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1172 GtkWidget *new_menu = gtk_menu_new ();
1174 g_object_set (new, "submenu", new_menu, NULL);
1176 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1177 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1179 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1180 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1182 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1183 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1186 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1187 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Ctrl>O");
1189 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1190 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1192 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1193 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1195 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1197 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1198 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Ctrl>S");
1200 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1201 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Ctrl>S");
1203 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1204 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1207 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1208 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1209 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1211 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1214 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1215 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1217 GtkWidget *dd_menu = gtk_menu_new ();
1219 g_object_set (display_data, "submenu", dd_menu, NULL);
1221 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1222 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1223 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1224 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1226 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1227 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1230 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1233 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1234 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1236 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1237 gtk_recent_manager_get_default ());
1239 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1240 gtk_recent_manager_get_default ());
1242 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1243 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1245 g_object_set (menu_data, "show-tips", TRUE, NULL);
1246 g_object_set (menu_files, "show-tips", TRUE, NULL);
1248 g_object_set (mi_data, "submenu", menu_data, NULL);
1249 g_object_set (mi_files, "submenu", menu_files, NULL);
1252 GtkRecentFilter *filter = gtk_recent_filter_new ();
1254 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1255 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1257 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1259 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1262 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1265 GtkRecentFilter *filter = gtk_recent_filter_new ();
1267 gtk_recent_filter_add_pattern (filter, "*.sps");
1268 gtk_recent_filter_add_pattern (filter, "*.SPS");
1270 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1272 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1275 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1278 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1281 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1282 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1284 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1285 "quit", quit, "<Ctrl>Q");
1288 g_object_set (menuitem, "submenu", menu, NULL);
1289 gtk_widget_show_all (menuitem);
1295 create_edit_menu (PsppireDataWindow *dw)
1298 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1300 GtkWidget *menu = gtk_menu_new ();
1302 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1303 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1304 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1305 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1307 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1308 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1310 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1311 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1312 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1314 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1316 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1318 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1319 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1322 GtkAccelGroup *ag = gtk_accel_group_new ();
1324 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1325 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1327 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1328 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1329 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1331 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1332 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1333 'X', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1335 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1336 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1337 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1338 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1339 'C', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1341 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1342 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1343 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1344 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1345 'V', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1347 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1348 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1349 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1351 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1352 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1353 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1357 dw->mi_find_separator = gtk_separator_menu_item_new ();
1358 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1360 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1361 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1362 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1366 dw->mi_options = gtk_menu_item_new_with_mnemonic (_("_Options..."));
1367 g_signal_connect_swapped (dw->mi_options, "activate",
1368 G_CALLBACK (options_dialog), dw);
1369 gtk_menu_attach (GTK_MENU (menu), dw->mi_options, 0, 1, i, i + 1); ++i;
1372 g_object_set (menuitem, "submenu", menu, NULL);
1374 gtk_widget_show_all (menuitem);
1381 psppire_data_window_finish_init (PsppireDataWindow *de,
1384 static const struct dataset_callbacks cbs =
1386 set_unsaved, /* changed */
1387 transformation_change_callback, /* transformations_changed */
1394 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1397 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1398 de->data_store = psppire_data_store_new (de->dict);
1399 psppire_data_store_set_reader (de->data_store, NULL);
1401 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1402 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1403 gtk_widget_show (menubar);
1405 hb = gtk_toolbar_new ();
1406 sb = get_widget_assert (de->builder, "status-bar");
1409 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1411 g_signal_connect (de, "realize",
1412 G_CALLBACK (set_data_page), de);
1414 g_signal_connect_swapped (de->data_store, "case-changed",
1415 G_CALLBACK (set_unsaved), de);
1417 g_signal_connect_swapped (de->data_store, "case-inserted",
1418 G_CALLBACK (set_unsaved), de);
1420 g_signal_connect_swapped (de->data_store, "cases-deleted",
1421 G_CALLBACK (set_unsaved), de);
1423 dataset_set_callbacks (de->dataset, &cbs, de);
1425 connect_help (de->builder);
1427 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1428 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1429 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1430 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1432 gtk_container_add (GTK_CONTAINER (de), box);
1434 g_signal_connect (de->dict, "weight-changed",
1435 G_CALLBACK (on_weight_change),
1438 g_signal_connect (de->dict, "filter-changed",
1439 G_CALLBACK (on_filter_change),
1442 g_signal_connect (de->dict, "split-changed",
1443 G_CALLBACK (on_split_change),
1446 g_signal_connect_swapped (de->dict, "backend-changed",
1447 G_CALLBACK (enable_save), de);
1448 g_signal_connect_swapped (de->dict, "variable-inserted",
1449 G_CALLBACK (enable_save), de);
1450 g_signal_connect_swapped (de->dict, "variable-deleted",
1451 G_CALLBACK (enable_save), de);
1454 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1455 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1456 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1457 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1458 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1460 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1461 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1462 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1463 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1464 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1465 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1466 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1469 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1470 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1471 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1472 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1474 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1475 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1477 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1478 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1480 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1481 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1482 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1483 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1484 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1485 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1486 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1487 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1488 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1490 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1491 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1493 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1494 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1495 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1497 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1498 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1499 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1500 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1501 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1502 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1503 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_INDEPENDENT, de);
1506 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1507 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1508 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1512 GSimpleAction *save = g_simple_action_new ("save", NULL);
1513 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1514 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1518 GSimpleAction *open = g_simple_action_new ("open", NULL);
1519 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1520 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1524 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1525 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1526 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1530 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1531 g_signal_connect_swapped (rename_dataset_act, "activate",
1532 G_CALLBACK (on_rename_dataset), de);
1533 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1537 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1538 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1539 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1542 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1543 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1544 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1548 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1549 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1550 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1554 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1555 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1556 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1561 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1562 g_variant_new_string ("DATA"));
1563 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1564 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1568 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1569 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1570 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1574 GSimpleAction *act_value_labels =
1575 g_simple_action_new_stateful ("value_labels", NULL,
1576 g_variant_new_boolean (FALSE));
1577 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1578 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1582 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1583 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1584 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1588 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1589 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1593 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1594 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1595 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1599 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1600 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1601 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1605 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1606 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1607 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1611 GSimpleAction *find = g_simple_action_new ("find", NULL);
1612 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1613 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1619 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1620 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1621 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1622 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1626 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1627 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1628 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1629 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1632 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1635 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1637 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1639 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1640 G_CALLBACK (psppire_dialog_action_activate_null), a);
1642 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1643 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1644 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1648 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1650 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1652 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1653 G_CALLBACK (g_action_activate_null), a);
1655 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1656 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1657 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1661 de->ti_find = gtk_tool_button_new (NULL, "Find");
1663 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1665 g_signal_connect_swapped (de->ti_find, "clicked",
1666 G_CALLBACK (g_action_activate_null), a);
1669 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1670 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1671 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1675 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1676 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1678 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1679 G_CALLBACK (g_action_activate_null), a);
1681 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1682 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1683 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1687 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1688 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1690 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1691 G_CALLBACK (g_action_activate_null), a);
1693 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1694 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1695 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1698 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1701 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1702 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1703 "PsppireDialogActionSplit");
1705 g_signal_connect_swapped (ti, "clicked",
1706 G_CALLBACK (psppire_dialog_action_activate_null), a);
1707 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1708 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1709 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1713 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1714 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1715 "PsppireDialogActionWeight");
1717 g_signal_connect_swapped (ti, "clicked",
1718 G_CALLBACK (psppire_dialog_action_activate_null), a);
1719 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1720 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1721 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1725 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1726 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1728 g_signal_connect (de->ti_value_labels_button, "toggled",
1729 G_CALLBACK (on_labels_button_toggle), de);
1730 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1731 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1732 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1737 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1738 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1740 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1741 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1742 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1743 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1745 g_signal_connect (de->data_editor, "switch-page",
1746 G_CALLBACK (on_switch_page), de);
1748 gtk_widget_show (GTK_WIDGET (de->data_editor));
1749 gtk_widget_show_all (box);
1751 ll_push_head (&all_data_windows, &de->ll);
1755 psppire_data_window_dispose (GObject *object)
1757 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1759 if (dw->builder != NULL)
1761 g_object_unref (dw->builder);
1767 g_signal_handlers_disconnect_by_func (dw->dict,
1768 G_CALLBACK (enable_save), dw);
1769 g_signal_handlers_disconnect_by_func (dw->dict,
1770 G_CALLBACK (on_weight_change), dw);
1771 g_signal_handlers_disconnect_by_func (dw->dict,
1772 G_CALLBACK (on_filter_change), dw);
1773 g_signal_handlers_disconnect_by_func (dw->dict,
1774 G_CALLBACK (on_split_change), dw);
1776 g_object_unref (dw->dict);
1782 g_object_unref (dw->data_store);
1783 dw->data_store = NULL;
1786 if (dw->ll.next != NULL)
1788 ll_remove (&dw->ll);
1792 if (G_OBJECT_CLASS (parent_class)->dispose)
1793 G_OBJECT_CLASS (parent_class)->dispose (object);
1797 psppire_data_window_finalize (GObject *object)
1799 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1803 struct dataset *dataset = dw->dataset;
1804 struct session *session = dataset_session (dataset);
1808 dataset_set_callbacks (dataset, NULL, NULL);
1809 session_set_active_dataset (session, NULL);
1810 dataset_destroy (dataset);
1813 if (G_OBJECT_CLASS (parent_class)->finalize)
1814 G_OBJECT_CLASS (parent_class)->finalize (object);
1818 psppire_data_window_set_property (GObject *object,
1820 const GValue *value,
1823 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1828 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1831 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1837 psppire_data_window_get_property (GObject *object,
1842 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1847 g_value_set_pointer (value, window->dataset);
1850 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1857 psppire_data_window_new (struct dataset *ds)
1861 if (the_session == NULL)
1862 the_session = session_create (NULL);
1866 char *dataset_name = session_generate_dataset_name (the_session);
1867 ds = dataset_create (the_session, dataset_name);
1868 free (dataset_name);
1870 assert (dataset_session (ds) == the_session);
1874 psppire_data_window_get_type (),
1875 "description", _("Data Editor"),
1879 if (dataset_name (ds) != NULL)
1880 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1883 GApplication *app = g_application_get_default ();
1884 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1890 psppire_data_window_is_empty (PsppireDataWindow *dw)
1892 return psppire_dict_get_var_cnt (dw->dict) == 0;
1896 psppire_data_window_iface_init (PsppireWindowIface *iface)
1898 iface->save = save_file;
1899 iface->pick_filename = data_pick_filename;
1900 iface->load = load_file;
1906 psppire_default_data_window (void)
1908 if (ll_is_empty (&all_data_windows))
1909 create_data_window ();
1910 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1914 psppire_data_window_set_default (PsppireDataWindow *pdw)
1916 ll_remove (&pdw->ll);
1917 ll_push_head (&all_data_windows, &pdw->ll);
1921 psppire_data_window_undefault (PsppireDataWindow *pdw)
1923 ll_remove (&pdw->ll);
1924 ll_push_tail (&all_data_windows, &pdw->ll);
1928 psppire_data_window_for_dataset (struct dataset *ds)
1930 PsppireDataWindow *pdw;
1932 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1933 if (pdw->dataset == ds)
1940 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1942 PsppireDataWindow *pdw;
1944 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1945 if (pdw->data_store == data_store)
1952 create_data_window (void)
1954 GtkWidget *w = psppire_data_window_new (NULL);
1956 gtk_widget_show (w);
1958 return GTK_WINDOW (w);
1962 open_data_window (PsppireWindow *victim, const char *file_name,
1963 const char *encoding, gpointer hint)
1967 if (PSPPIRE_IS_DATA_WINDOW (victim)
1968 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1970 window = GTK_WIDGET (victim);
1971 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1974 window = psppire_data_window_new (NULL);
1976 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
1977 gtk_widget_show_all (window);
1978 return GTK_WINDOW (window);