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 g_signal_connect_swapped (de->data_store, "cases-deleted",
1495 G_CALLBACK (set_unsaved), de);
1497 dataset_set_callbacks (de->dataset, &cbs, de);
1499 connect_help (de->builder);
1501 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1502 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1503 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1504 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1506 gtk_container_add (GTK_CONTAINER (de), box);
1508 g_signal_connect (de->dict, "weight-changed",
1509 G_CALLBACK (on_weight_change),
1512 g_signal_connect (de->dict, "filter-changed",
1513 G_CALLBACK (on_filter_change),
1516 g_signal_connect (de->dict, "split-changed",
1517 G_CALLBACK (on_split_change),
1520 g_signal_connect_swapped (de->dict, "changed",
1521 G_CALLBACK (enable_save), de);
1522 g_signal_connect_swapped (de->dict, "variable-inserted",
1523 G_CALLBACK (enable_save), de);
1524 g_signal_connect_swapped (de->dict, "variable-deleted",
1525 G_CALLBACK (enable_save), de);
1528 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1529 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1530 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1531 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1532 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1534 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1535 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1536 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1537 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1538 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1539 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1540 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1543 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1544 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1545 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1546 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1548 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1549 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1551 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1552 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1554 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1555 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1556 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1557 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1558 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1559 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1560 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1561 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1562 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1564 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1565 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1567 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1568 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1569 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1571 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1572 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1573 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1574 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1575 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1576 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1579 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1580 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1581 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1585 GSimpleAction *save = g_simple_action_new ("save", NULL);
1586 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1587 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1591 GSimpleAction *open = g_simple_action_new ("open", NULL);
1592 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1593 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1597 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1598 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1599 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1603 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1604 g_signal_connect_swapped (rename_dataset_act, "activate",
1605 G_CALLBACK (on_rename_dataset), de);
1606 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1610 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1611 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1612 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1615 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1616 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1617 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1621 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1622 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1623 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1627 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1628 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1629 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1634 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1635 g_variant_new_string ("DATA"));
1636 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1637 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1641 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1642 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1643 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1647 GSimpleAction *act_value_labels =
1648 g_simple_action_new_stateful ("value_labels", NULL,
1649 g_variant_new_boolean (FALSE));
1650 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1651 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1655 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1656 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1657 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1661 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1662 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1666 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1667 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1668 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1672 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1673 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1674 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1678 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1679 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1680 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1684 GSimpleAction *find = g_simple_action_new ("find", NULL);
1685 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1686 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1692 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1693 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1694 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1695 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1699 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1700 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1701 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1702 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1705 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1708 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1710 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1712 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1713 G_CALLBACK (psppire_dialog_action_activate_null), a);
1715 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1716 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1717 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1721 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1723 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1725 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1726 G_CALLBACK (g_action_activate_null), a);
1728 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1729 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1730 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1734 de->ti_find = gtk_tool_button_new (NULL, "Find");
1736 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1738 g_signal_connect_swapped (de->ti_find, "clicked",
1739 G_CALLBACK (g_action_activate_null), a);
1742 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1743 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1744 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1748 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1749 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1751 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1752 G_CALLBACK (g_action_activate_null), a);
1754 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1755 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1756 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1760 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1761 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1763 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1764 G_CALLBACK (g_action_activate_null), a);
1766 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1767 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1768 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1771 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1774 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1775 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1776 "PsppireDialogActionSplit");
1778 g_signal_connect_swapped (ti, "clicked",
1779 G_CALLBACK (psppire_dialog_action_activate_null), a);
1780 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1781 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1782 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1786 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1787 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1788 "PsppireDialogActionWeight");
1790 g_signal_connect_swapped (ti, "clicked",
1791 G_CALLBACK (psppire_dialog_action_activate_null), a);
1792 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1793 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1794 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1798 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1799 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1801 g_signal_connect (de->ti_value_labels_button, "toggled",
1802 G_CALLBACK (on_labels_button_toggle), de);
1803 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1804 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1805 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1810 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1811 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1813 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1814 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1815 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1816 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1818 g_signal_connect (de->data_editor, "switch-page",
1819 G_CALLBACK (on_switch_page), de);
1821 gtk_widget_show (GTK_WIDGET (de->data_editor));
1822 gtk_widget_show_all (box);
1824 ll_push_head (&all_data_windows, &de->ll);
1829 psppire_data_window_dispose (GObject *object)
1831 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1833 if (dw->builder != NULL)
1835 g_object_unref (dw->builder);
1841 g_signal_handlers_disconnect_by_func (dw->dict,
1842 G_CALLBACK (enable_save), dw);
1843 g_signal_handlers_disconnect_by_func (dw->dict,
1844 G_CALLBACK (on_weight_change), dw);
1845 g_signal_handlers_disconnect_by_func (dw->dict,
1846 G_CALLBACK (on_filter_change), dw);
1847 g_signal_handlers_disconnect_by_func (dw->dict,
1848 G_CALLBACK (on_split_change), dw);
1850 g_object_unref (dw->dict);
1856 g_object_unref (dw->data_store);
1857 dw->data_store = NULL;
1860 if (dw->ll.next != NULL)
1862 ll_remove (&dw->ll);
1866 if (G_OBJECT_CLASS (parent_class)->dispose)
1867 G_OBJECT_CLASS (parent_class)->dispose (object);
1871 psppire_data_window_finalize (GObject *object)
1873 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1877 struct dataset *dataset = dw->dataset;
1878 struct session *session = dataset_session (dataset);
1882 dataset_set_callbacks (dataset, NULL, NULL);
1883 session_set_active_dataset (session, NULL);
1884 dataset_destroy (dataset);
1887 if (G_OBJECT_CLASS (parent_class)->finalize)
1888 G_OBJECT_CLASS (parent_class)->finalize (object);
1892 psppire_data_window_set_property (GObject *object,
1894 const GValue *value,
1897 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1902 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1905 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1911 psppire_data_window_get_property (GObject *object,
1916 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1921 g_value_set_pointer (value, window->dataset);
1924 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1932 psppire_data_window_new (struct dataset *ds)
1936 if (the_session == NULL)
1937 the_session = session_create (NULL);
1941 char *dataset_name = session_generate_dataset_name (the_session);
1942 ds = dataset_create (the_session, dataset_name);
1943 free (dataset_name);
1945 assert (dataset_session (ds) == the_session);
1949 psppire_data_window_get_type (),
1950 "description", _("Data Editor"),
1954 if (dataset_name (ds) != NULL)
1955 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1958 GApplication *app = g_application_get_default ();
1959 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1967 psppire_data_window_is_empty (PsppireDataWindow *dw)
1969 return psppire_dict_get_var_cnt (dw->dict) == 0;
1974 psppire_data_window_iface_init (PsppireWindowIface *iface)
1976 iface->save = save_file;
1977 iface->pick_filename = data_pick_filename;
1978 iface->load = load_file;
1985 psppire_default_data_window (void)
1987 if (ll_is_empty (&all_data_windows))
1988 create_data_window ();
1989 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1995 psppire_data_window_set_default (PsppireDataWindow *pdw)
1997 ll_remove (&pdw->ll);
1998 ll_push_head (&all_data_windows, &pdw->ll);
2002 psppire_data_window_undefault (PsppireDataWindow *pdw)
2004 ll_remove (&pdw->ll);
2005 ll_push_tail (&all_data_windows, &pdw->ll);
2011 psppire_data_window_for_dataset (struct dataset *ds)
2013 PsppireDataWindow *pdw;
2015 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2016 if (pdw->dataset == ds)
2023 create_data_window (void)
2025 GtkWidget *w = psppire_data_window_new (NULL);
2027 gtk_widget_show (w);
2029 return GTK_WINDOW (w);
2033 open_data_window (PsppireWindow *victim, const char *file_name,
2034 const char *encoding, gpointer hint)
2038 if (PSPPIRE_IS_DATA_WINDOW (victim)
2039 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
2041 window = GTK_WIDGET (victim);
2042 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
2045 window = psppire_data_window_new (NULL);
2047 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
2048 gtk_widget_show_all (window);
2049 return GTK_WINDOW (window);