1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014,
3 2016, 2017 Free Software Foundation
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include "data/dataset.h"
24 #include "data/session.h"
25 #include "language/lexer/lexer.h"
26 #include "libpspp/message.h"
27 #include "libpspp/str.h"
28 #include "ui/gui/builder-wrapper.h"
29 #include "ui/gui/entry-dialog.h"
30 #include "ui/gui/executor.h"
31 #include "ui/gui/help-menu.h"
32 #include "ui/gui/helper.h"
33 #include "ui/gui/helper.h"
34 #include "ui/gui/psppire-import-assistant.h"
35 #include "ui/gui/psppire-data-window.h"
36 #include "ui/gui/psppire-dialog-action.h"
37 #include "ui/gui/psppire-encoding-selector.h"
38 #include "ui/gui/psppire-syntax-window.h"
39 #include "ui/gui/psppire-window.h"
40 #include "ui/gui/windows-menu.h"
41 #include "ui/gui/goto-case-dialog.h"
42 #include "ui/gui/psppire.h"
43 #include "ui/syntax-gen.h"
45 #include "gl/c-strcase.h"
46 #include "gl/c-strcasestr.h"
47 #include "gl/xvasprintf.h"
49 #include "ui/gui/efficient-sheet/jmd-sheet.h"
51 #include "find-dialog.h"
52 #include "options-dialog.h"
53 #include "psppire-dialog-action-1sks.h"
54 #include "psppire-dialog-action-aggregate.h"
55 #include "psppire-dialog-action-autorecode.h"
56 #include "psppire-dialog-action-barchart.h"
57 #include "psppire-dialog-action-binomial.h"
58 #include "psppire-dialog-action-chisquare.h"
59 #include "psppire-dialog-action-comments.h"
60 #include "psppire-dialog-action-compute.h"
61 #include "psppire-dialog-action-correlation.h"
62 #include "psppire-dialog-action-count.h"
63 #include "psppire-dialog-action-crosstabs.h"
64 #include "psppire-dialog-action-descriptives.h"
65 #include "psppire-dialog-action-examine.h"
66 #include "psppire-dialog-action-factor.h"
67 #include "psppire-dialog-action-flip.h"
68 #include "psppire-dialog-action-frequencies.h"
69 #include "psppire-dialog-action-histogram.h"
70 #include "psppire-dialog-action-indep-samps.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 PsppireDict *dict = NULL;
1074 g_object_get (dw->data_editor, "dictionary", &dict, NULL);
1077 JmdSheet *sheet = JMD_SHEET (dw->data_editor->data_sheet);
1078 JmdRange sel = *sheet->selection;
1080 GtkClipboard *clip =
1081 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1082 GDK_SELECTION_CLIPBOARD);
1084 /* Save the selected area to a string */
1085 GString *str = g_string_new ("");
1086 for (y = sel.start_y ; y <= sel.end_y; ++y)
1088 for (x = sel.start_x ; x <= sel.end_x; ++x)
1090 const struct variable * var = psppire_dict_get_variable (dict, x);
1091 gchar *s = psppire_data_store_get_string (dw->data_editor->data_store,
1093 g_string_append (str, s);
1094 g_string_append (str, "\t");
1097 g_string_append (str, "\n");
1100 gtk_clipboard_set_text (clip, str->str, str->len);
1101 g_string_free (str, TRUE);
1103 /* Now fill the selected area with SYSMIS */
1106 for (x = sel.start_x ; x <= sel.end_x; ++x)
1108 const struct variable * var = psppire_dict_get_variable (dict, x);
1109 for (y = sel.start_y ; y <= sel.end_y; ++y)
1111 psppire_data_store_set_value (dw->data_editor->data_store,
1123 on_copy (PsppireDataWindow *dw)
1125 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1128 GtkClipboard *clip =
1129 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1130 GDK_SELECTION_CLIPBOARD);
1132 jmd_sheet_set_clip (JMD_SHEET (dw->data_editor->data_sheet), clip);
1138 trf (GtkClipboard *clip,
1144 for (i = 0; i < n_atoms; ++i)
1146 g_print ("%s\n", gdk_atom_name (atoms[i]));
1151 on_paste (PsppireDataWindow *dw)
1153 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1156 GtkClipboard *clip =
1157 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1158 GDK_SELECTION_CLIPBOARD);
1160 gtk_clipboard_request_targets (clip, trf, dw);
1166 on_clear_cases (PsppireDataWindow *dw)
1169 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1172 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1173 psppire_data_sheet_edit_clear_cases (ds);
1179 on_clear_variables (PsppireDataWindow *dw)
1182 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1185 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1186 psppire_data_sheet_edit_clear_variables (ds);
1190 psppire_var_sheet_clear_variables (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1198 insert_variable (PsppireDataWindow *dw)
1201 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1204 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1205 psppire_data_sheet_insert_variable (ds);
1209 psppire_var_sheet_insert_variable (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1217 insert_case_at_row (PsppireDataWindow *dw)
1220 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1222 psppire_data_sheet_insert_case (ds);
1229 goto_case (PsppireDataWindow *dw)
1231 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1234 goto_case_dialog (JMD_SHEET (dw->data_editor->data_sheet));
1240 create_file_menu (PsppireDataWindow *dw)
1242 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1243 GtkWidget *menu = gtk_menu_new ();
1246 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1247 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1249 GtkWidget *new_menu = gtk_menu_new ();
1251 g_object_set (new, "submenu", new_menu, NULL);
1253 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1254 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1256 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1257 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1259 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1260 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1263 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1264 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Ctrl>O");
1266 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1267 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1269 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1270 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1272 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1274 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1275 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Ctrl>S");
1277 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1278 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Ctrl>S");
1280 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1281 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1284 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1285 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1286 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1288 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1291 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1292 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1294 GtkWidget *dd_menu = gtk_menu_new ();
1296 g_object_set (display_data, "submenu", dd_menu, NULL);
1298 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1299 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1300 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1301 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1303 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1304 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1307 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1310 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1311 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1313 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1314 gtk_recent_manager_get_default ());
1316 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1317 gtk_recent_manager_get_default ());
1319 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1320 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1322 g_object_set (menu_data, "show-tips", TRUE, NULL);
1323 g_object_set (menu_files, "show-tips", TRUE, NULL);
1325 g_object_set (mi_data, "submenu", menu_data, NULL);
1326 g_object_set (mi_files, "submenu", menu_files, NULL);
1329 GtkRecentFilter *filter = gtk_recent_filter_new ();
1331 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1332 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1334 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1336 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1339 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1342 GtkRecentFilter *filter = gtk_recent_filter_new ();
1344 gtk_recent_filter_add_pattern (filter, "*.sps");
1345 gtk_recent_filter_add_pattern (filter, "*.SPS");
1347 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1349 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1352 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1355 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1358 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1359 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1361 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1362 "quit", quit, "<Ctrl>Q");
1365 g_object_set (menuitem, "submenu", menu, NULL);
1366 gtk_widget_show_all (menuitem);
1373 create_edit_menu (PsppireDataWindow *dw)
1376 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1378 GtkWidget *menu = gtk_menu_new ();
1380 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1381 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1382 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1383 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1385 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1386 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1388 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1389 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1390 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1392 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1394 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1396 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1397 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1400 GtkAccelGroup *ag = gtk_accel_group_new ();
1402 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1403 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1405 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1406 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1407 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1409 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1410 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1411 'X', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1413 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1414 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1415 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1416 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1417 'C', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1419 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1420 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1421 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1422 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1423 'V', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1425 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1426 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1427 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1429 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1430 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1431 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1435 dw->mi_find_separator = gtk_separator_menu_item_new ();
1436 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1438 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1439 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1440 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1444 dw->mi_options = gtk_menu_item_new_with_mnemonic (_("_Options..."));
1445 g_signal_connect_swapped (dw->mi_options, "activate",
1446 G_CALLBACK (options_dialog), dw);
1447 gtk_menu_attach (GTK_MENU (menu), dw->mi_options, 0, 1, i, i + 1); ++i;
1450 g_object_set (menuitem, "submenu", menu, NULL);
1452 gtk_widget_show_all (menuitem);
1458 psppire_data_window_finish_init (PsppireDataWindow *de,
1461 static const struct dataset_callbacks cbs =
1463 set_unsaved, /* changed */
1464 transformation_change_callback, /* transformations_changed */
1471 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1474 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1475 de->data_store = psppire_data_store_new (de->dict);
1476 psppire_data_store_set_reader (de->data_store, NULL);
1478 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1479 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1480 gtk_widget_show (menubar);
1482 hb = gtk_toolbar_new ();
1483 sb = get_widget_assert (de->builder, "status-bar");
1486 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1488 g_signal_connect (de, "realize",
1489 G_CALLBACK (set_data_page), de);
1491 g_signal_connect_swapped (de->data_store, "case-changed",
1492 G_CALLBACK (set_unsaved), de);
1494 dataset_set_callbacks (de->dataset, &cbs, de);
1496 connect_help (de->builder);
1498 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1499 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1500 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1501 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1503 gtk_container_add (GTK_CONTAINER (de), box);
1505 g_signal_connect (de->dict, "weight-changed",
1506 G_CALLBACK (on_weight_change),
1509 g_signal_connect (de->dict, "filter-changed",
1510 G_CALLBACK (on_filter_change),
1513 g_signal_connect (de->dict, "split-changed",
1514 G_CALLBACK (on_split_change),
1517 g_signal_connect_swapped (de->dict, "items-changed",
1518 G_CALLBACK (enable_save), de);
1519 g_signal_connect_swapped (de->dict, "variable-inserted",
1520 G_CALLBACK (enable_save), de);
1521 g_signal_connect_swapped (de->dict, "variable-deleted",
1522 G_CALLBACK (enable_save), de);
1525 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1526 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1527 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1528 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1529 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1531 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1532 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1533 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1534 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1535 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1536 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1537 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1540 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1541 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1542 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1543 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1545 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1546 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1548 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1549 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1551 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1552 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1553 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1554 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1555 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1556 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1557 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1558 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1559 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1561 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1562 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1564 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1565 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1566 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1568 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1569 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1570 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1571 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1572 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1573 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1576 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1577 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1578 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1582 GSimpleAction *save = g_simple_action_new ("save", NULL);
1583 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1584 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1588 GSimpleAction *open = g_simple_action_new ("open", NULL);
1589 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1590 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1594 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1595 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1596 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1600 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1601 g_signal_connect_swapped (rename_dataset_act, "activate",
1602 G_CALLBACK (on_rename_dataset), de);
1603 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1607 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1608 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1609 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1612 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1613 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1614 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1618 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1619 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1620 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1624 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1625 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1626 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1631 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1632 g_variant_new_string ("DATA"));
1633 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1634 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1638 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1639 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1640 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1644 GSimpleAction *act_value_labels =
1645 g_simple_action_new_stateful ("value_labels", NULL,
1646 g_variant_new_boolean (FALSE));
1647 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1648 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1652 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1653 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1654 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1658 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1659 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1663 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1664 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1665 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1669 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1670 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1671 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1675 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1676 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1677 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1681 GSimpleAction *find = g_simple_action_new ("find", NULL);
1682 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1683 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1689 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1690 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1691 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1692 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1696 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1697 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1698 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1699 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1702 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1705 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1707 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1709 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1710 G_CALLBACK (psppire_dialog_action_activate_null), a);
1712 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1713 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1714 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1718 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1720 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1722 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1723 G_CALLBACK (g_action_activate_null), a);
1725 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1726 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1727 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1731 de->ti_find = gtk_tool_button_new (NULL, "Find");
1733 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1735 g_signal_connect_swapped (de->ti_find, "clicked",
1736 G_CALLBACK (g_action_activate_null), a);
1739 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1740 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1741 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1745 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1746 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1748 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1749 G_CALLBACK (g_action_activate_null), a);
1751 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1752 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1753 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1757 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1758 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1760 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1761 G_CALLBACK (g_action_activate_null), a);
1763 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1764 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1765 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1768 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1771 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1772 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1773 "PsppireDialogActionSplit");
1775 g_signal_connect_swapped (ti, "clicked",
1776 G_CALLBACK (psppire_dialog_action_activate_null), a);
1777 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1778 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1779 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1783 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1784 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1785 "PsppireDialogActionWeight");
1787 g_signal_connect_swapped (ti, "clicked",
1788 G_CALLBACK (psppire_dialog_action_activate_null), a);
1789 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1790 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1791 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1795 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1796 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1798 g_signal_connect (de->ti_value_labels_button, "toggled",
1799 G_CALLBACK (on_labels_button_toggle), de);
1800 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1801 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1802 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1807 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1808 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1810 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1811 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1812 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1813 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1815 g_signal_connect (de->data_editor, "switch-page",
1816 G_CALLBACK (on_switch_page), de);
1818 gtk_widget_show (GTK_WIDGET (de->data_editor));
1819 gtk_widget_show_all (box);
1821 ll_push_head (&all_data_windows, &de->ll);
1826 psppire_data_window_dispose (GObject *object)
1828 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1830 if (dw->builder != NULL)
1832 g_object_unref (dw->builder);
1838 g_signal_handlers_disconnect_by_func (dw->dict,
1839 G_CALLBACK (enable_save), dw);
1840 g_signal_handlers_disconnect_by_func (dw->dict,
1841 G_CALLBACK (on_weight_change), dw);
1842 g_signal_handlers_disconnect_by_func (dw->dict,
1843 G_CALLBACK (on_filter_change), dw);
1844 g_signal_handlers_disconnect_by_func (dw->dict,
1845 G_CALLBACK (on_split_change), dw);
1847 g_object_unref (dw->dict);
1853 g_object_unref (dw->data_store);
1854 dw->data_store = NULL;
1857 if (dw->ll.next != NULL)
1859 ll_remove (&dw->ll);
1863 if (G_OBJECT_CLASS (parent_class)->dispose)
1864 G_OBJECT_CLASS (parent_class)->dispose (object);
1868 psppire_data_window_finalize (GObject *object)
1870 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1874 struct dataset *dataset = dw->dataset;
1875 struct session *session = dataset_session (dataset);
1879 dataset_set_callbacks (dataset, NULL, NULL);
1880 session_set_active_dataset (session, NULL);
1881 dataset_destroy (dataset);
1884 if (G_OBJECT_CLASS (parent_class)->finalize)
1885 G_OBJECT_CLASS (parent_class)->finalize (object);
1889 psppire_data_window_set_property (GObject *object,
1891 const GValue *value,
1894 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1899 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1902 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1908 psppire_data_window_get_property (GObject *object,
1913 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1918 g_value_set_pointer (value, window->dataset);
1921 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1929 psppire_data_window_new (struct dataset *ds)
1933 if (the_session == NULL)
1934 the_session = session_create (NULL);
1938 char *dataset_name = session_generate_dataset_name (the_session);
1939 ds = dataset_create (the_session, dataset_name);
1940 free (dataset_name);
1942 assert (dataset_session (ds) == the_session);
1946 psppire_data_window_get_type (),
1947 "description", _("Data Editor"),
1951 if (dataset_name (ds) != NULL)
1952 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1955 GApplication *app = g_application_get_default ();
1956 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1964 psppire_data_window_is_empty (PsppireDataWindow *dw)
1966 return psppire_dict_get_var_cnt (dw->dict) == 0;
1971 psppire_data_window_iface_init (PsppireWindowIface *iface)
1973 iface->save = save_file;
1974 iface->pick_filename = data_pick_filename;
1975 iface->load = load_file;
1982 psppire_default_data_window (void)
1984 if (ll_is_empty (&all_data_windows))
1985 create_data_window ();
1986 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1992 psppire_data_window_set_default (PsppireDataWindow *pdw)
1994 ll_remove (&pdw->ll);
1995 ll_push_head (&all_data_windows, &pdw->ll);
1999 psppire_data_window_undefault (PsppireDataWindow *pdw)
2001 ll_remove (&pdw->ll);
2002 ll_push_tail (&all_data_windows, &pdw->ll);
2008 psppire_data_window_for_dataset (struct dataset *ds)
2010 PsppireDataWindow *pdw;
2012 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2013 if (pdw->dataset == ds)
2020 psppire_data_window_for_data_store (PsppireDataStore *data_store)
2022 PsppireDataWindow *pdw;
2024 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2025 if (pdw->data_store == data_store)
2032 create_data_window (void)
2034 GtkWidget *w = psppire_data_window_new (NULL);
2036 gtk_widget_show (w);
2038 return GTK_WINDOW (w);
2042 open_data_window (PsppireWindow *victim, const char *file_name,
2043 const char *encoding, gpointer hint)
2047 if (PSPPIRE_IS_DATA_WINDOW (victim)
2048 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
2050 window = GTK_WIDGET (victim);
2051 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
2054 window = psppire_data_window_new (NULL);
2056 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
2057 gtk_widget_show_all (window);
2058 return GTK_WINDOW (window);