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-data-editor.h"
37 #include "ui/gui/psppire-dialog-action.h"
38 #include "ui/gui/psppire-encoding-selector.h"
39 #include "ui/gui/psppire-syntax-window.h"
40 #include "ui/gui/psppire-window.h"
41 #include "ui/gui/windows-menu.h"
42 #include "ui/gui/goto-case-dialog.h"
43 #include "ui/gui/psppire.h"
44 #include "ui/syntax-gen.h"
46 #include "gl/c-strcase.h"
47 #include "gl/c-strcasestr.h"
48 #include "gl/xvasprintf.h"
50 #include <ssw-sheet.h>
52 #include "find-dialog.h"
53 #include "options-dialog.h"
54 #include "psppire-dialog-action-1sks.h"
55 #include "psppire-dialog-action-aggregate.h"
56 #include "psppire-dialog-action-autorecode.h"
57 #include "psppire-dialog-action-barchart.h"
58 #include "psppire-dialog-action-binomial.h"
59 #include "psppire-dialog-action-chisquare.h"
60 #include "psppire-dialog-action-comments.h"
61 #include "psppire-dialog-action-compute.h"
62 #include "psppire-dialog-action-correlation.h"
63 #include "psppire-dialog-action-count.h"
64 #include "psppire-dialog-action-crosstabs.h"
65 #include "psppire-dialog-action-descriptives.h"
66 #include "psppire-dialog-action-examine.h"
67 #include "psppire-dialog-action-factor.h"
68 #include "psppire-dialog-action-flip.h"
69 #include "psppire-dialog-action-frequencies.h"
70 #include "psppire-dialog-action-histogram.h"
71 #include "psppire-dialog-action-indep-samps.h"
72 #include "psppire-dialog-action-k-independent.h"
73 #include "psppire-dialog-action-k-related.h"
74 #include "psppire-dialog-action-kmeans.h"
75 #include "psppire-dialog-action-logistic.h"
76 #include "psppire-dialog-action-means.h"
77 #include "psppire-dialog-action-oneway.h"
78 #include "psppire-dialog-action-paired.h"
79 #include "psppire-dialog-action-rank.h"
80 #include "psppire-dialog-action-recode-same.h"
81 #include "psppire-dialog-action-recode-different.h"
82 #include "psppire-dialog-action-regression.h"
83 #include "psppire-dialog-action-reliability.h"
84 #include "psppire-dialog-action-roc.h"
85 #include "psppire-dialog-action-runs.h"
86 #include "psppire-dialog-action-scatterplot.h"
87 #include "psppire-dialog-action-select.h"
88 #include "psppire-dialog-action-sort.h"
89 #include "psppire-dialog-action-split.h"
90 #include "psppire-dialog-action-tt1s.h"
91 #include "psppire-dialog-action-two-sample.h"
92 #include "psppire-dialog-action-univariate.h"
93 #include "psppire-dialog-action-var-info.h"
94 #include "psppire-dialog-action-weight.h"
98 #define _(msgid) gettext (msgid)
99 #define N_(msgid) msgid
101 struct session *the_session;
102 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
104 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
106 static void psppire_data_window_dispose (GObject *object);
107 static void psppire_data_window_finalize (GObject *object);
108 static void psppire_data_window_set_property (GObject *object,
112 static void psppire_data_window_get_property (GObject *object,
118 G_DEFINE_TYPE_WITH_CODE (PsppireDataWindow, psppire_data_window, PSPPIRE_TYPE_WINDOW,
119 G_IMPLEMENT_INTERFACE (PSPPIRE_TYPE_WINDOW_MODEL,
120 psppire_data_window_iface_init))
122 static GObjectClass *parent_class ;
129 psppire_data_window_class_init (PsppireDataWindowClass *class)
131 GObjectClass *object_class = G_OBJECT_CLASS (class);
133 parent_class = g_type_class_peek_parent (class);
135 object_class->dispose = psppire_data_window_dispose;
136 object_class->finalize = psppire_data_window_finalize;
137 object_class->set_property = psppire_data_window_set_property;
138 object_class->get_property = psppire_data_window_get_property;
140 g_object_class_install_property (
141 object_class, PROP_DATASET,
142 g_param_spec_pointer ("dataset", "Dataset",
143 "'struct datset *' represented by the window",
144 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
149 /* Run the EXECUTE command. */
151 execute (PsppireDataWindow *dw)
153 execute_const_syntax_string (dw, "EXECUTE.");
157 transformation_change_callback (bool transformations_pending,
160 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
162 GtkWidget *status_label =
163 get_widget_assert (de->builder, "case-counter-area");
166 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de),
167 "transform-pending");
169 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
170 transformations_pending);
173 if (transformations_pending)
174 gtk_label_set_text (GTK_LABEL (status_label),
175 _("Transformations Pending"));
177 gtk_label_set_text (GTK_LABEL (status_label), "");
180 /* Callback for when the dictionary changes its filter variable */
182 on_filter_change (GObject *o, gint filter_index, gpointer data)
184 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
186 GtkWidget *filter_status_area =
187 get_widget_assert (de->builder, "filter-use-status-area");
189 if (filter_index == -1)
191 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
195 PsppireDict *dict = NULL;
196 struct variable *var ;
199 g_object_get (de->data_editor, "dictionary", &dict, NULL);
201 var = psppire_dict_get_variable (dict, filter_index);
203 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
205 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
211 /* Callback for when the dictionary changes its split variables */
213 on_split_change (PsppireDict *dict, gpointer data)
215 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
217 size_t n_split_vars = dict_get_n_splits (dict->dict);
219 GtkWidget *split_status_area =
220 get_widget_assert (de->builder, "split-file-status-area");
222 if (n_split_vars == 0)
224 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
230 const struct variable *const * split_vars =
231 dict_get_split_vars (dict->dict);
233 text = g_string_new (_("Split by "));
235 for (i = 0 ; i < n_split_vars - 1; ++i)
237 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
239 g_string_append (text, var_get_name (split_vars[i]));
241 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
243 g_string_free (text, TRUE);
250 /* Callback for when the dictionary changes its weights */
252 on_weight_change (GObject *o, gint weight_index, gpointer data)
254 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
256 GtkWidget *weight_status_area =
257 get_widget_assert (de->builder, "weight-status-area");
259 if (weight_index == -1)
261 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
265 struct variable *var ;
266 PsppireDict *dict = NULL;
269 g_object_get (de->data_editor, "dictionary", &dict, NULL);
271 var = psppire_dict_get_variable (dict, weight_index);
273 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
275 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
283 dump_rm (GtkRecentManager *rm)
285 GList *items = gtk_recent_manager_get_items (rm);
289 g_print ("Recent Items:\n");
290 for (i = items; i; i = i->next)
292 GtkRecentInfo *ri = i->data;
294 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
295 gtk_recent_info_get_short_name (ri),
296 gtk_recent_info_get_mime_type (ri),
297 gtk_recent_info_get_description (ri),
298 gtk_recent_info_get_uri (ri)
302 gtk_recent_info_unref (ri);
310 has_suffix (const gchar *name, const gchar *suffix)
312 size_t name_len = strlen (name);
313 size_t suffix_len = strlen (suffix);
314 return (name_len > suffix_len
315 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
319 name_has_por_suffix (const gchar *name)
321 return has_suffix (name, ".por");
325 name_has_sav_suffix (const gchar *name)
327 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
330 /* Returns true if NAME has a suffix which might denote a PSPP file */
332 name_has_suffix (const gchar *name)
334 return name_has_por_suffix (name) || name_has_sav_suffix (name);
338 load_file (PsppireWindow *de, const gchar *file_name, const char *encoding,
341 const char *mime_type = NULL;
342 gchar *syntax = NULL;
347 gchar *utf8_file_name;
348 struct string filename;
350 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
352 if (NULL == utf8_file_name)
355 ds_init_empty (&filename);
356 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
358 g_free (utf8_file_name);
360 if (encoding && encoding[0])
361 syntax = g_strdup_printf ("GET FILE=%s ENCODING='%s'.",
362 ds_cstr (&filename), encoding);
364 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
365 ds_destroy (&filename);
372 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
373 lex_reader_for_string (syntax, "UTF-8"));
376 if (ok && syn == NULL)
378 if (name_has_por_suffix (file_name))
379 mime_type = "application/x-spss-por";
380 else if (name_has_sav_suffix (file_name))
381 mime_type = "application/x-spss-sav";
383 add_most_recent (file_name, mime_type, encoding);
390 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
392 if (format == PSPPIRE_DATA_WINDOW_SAV)
394 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
400 /* Save DE to file */
402 save_file (PsppireWindow *w)
404 const gchar *file_name = NULL;
405 gchar *utf8_file_name = NULL;
407 struct string filename ;
408 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
411 file_name = psppire_window_get_filename (w);
413 fnx = g_string_new (file_name);
415 if (! name_has_suffix (fnx->str))
416 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
418 ds_init_empty (&filename);
420 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
422 g_string_free (fnx, TRUE);
424 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
425 g_free (utf8_file_name);
427 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
428 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
429 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
430 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
431 ds_cstr (&filename));
433 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
435 ds_destroy (&filename);
437 g_free (execute_syntax_string (de, syntax));
442 display_dict (PsppireDataWindow *de)
444 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
448 sysfile_info (PsppireDataWindow *de)
450 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
452 if (GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
454 struct string filename;
456 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
457 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
460 const gchar *encoding = psppire_encoding_selector_get_encoding (
461 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
465 ds_init_empty (&filename);
467 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
469 g_free (utf8_file_name);
472 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
473 ds_cstr (&filename), encoding);
475 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
476 g_free (execute_syntax_string (de, syntax));
479 gtk_widget_destroy (dialog);
483 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
485 data_pick_filename (PsppireWindow *window)
487 GtkListStore *list_store;
488 GtkWidget *combo_box;
490 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
491 GtkFileFilter *filter;
493 gtk_file_chooser_dialog_new (_("Save"),
495 GTK_FILE_CHOOSER_ACTION_SAVE,
496 _("Cancel"), GTK_RESPONSE_CANCEL,
497 _("Save"), GTK_RESPONSE_ACCEPT,
500 g_object_set (dialog, "local-only", FALSE, NULL);
502 filter = gtk_file_filter_new ();
503 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
504 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
505 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
507 filter = gtk_file_filter_new ();
508 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
509 gtk_file_filter_add_pattern (filter, "*.zsav");
510 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
512 filter = gtk_file_filter_new ();
513 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
514 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
515 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
517 filter = gtk_file_filter_new ();
518 gtk_file_filter_set_name (filter, _("All Files"));
519 gtk_file_filter_add_pattern (filter, "*");
520 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
521 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
524 GtkCellRenderer *cell;
529 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
530 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
532 gtk_list_store_append (list_store, &iter);
533 gtk_list_store_set (list_store, &iter,
534 0, PSPPIRE_DATA_WINDOW_SAV,
537 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
539 gtk_list_store_append (list_store, &iter);
540 gtk_list_store_set (list_store, &iter,
541 0, PSPPIRE_DATA_WINDOW_ZSAV,
542 1, _("Compressed System File"),
545 gtk_list_store_append (list_store, &iter);
546 gtk_list_store_set (list_store, &iter,
547 0, PSPPIRE_DATA_WINDOW_POR,
548 1, _("Portable File"),
551 label = gtk_label_new (_("Format:"));
553 cell = gtk_cell_renderer_text_new ();
554 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
555 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
558 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
559 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
560 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
561 gtk_widget_show_all (hbox);
563 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
566 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
569 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
571 case GTK_RESPONSE_ACCEPT:
576 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
582 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
583 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
588 if (! name_has_suffix (filename->str))
589 g_string_append (filename,
590 psppire_data_window_format_to_string (format));
592 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
594 g_string_free (filename, TRUE);
601 gtk_widget_destroy (dialog);
605 confirm_delete_dataset (PsppireDataWindow *de,
606 const char *old_dataset,
607 const char *new_dataset,
608 const char *existing_dataset)
613 dialog = gtk_message_dialog_new (
614 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
615 _("Delete Existing Dataset?"));
617 gtk_message_dialog_format_secondary_text (
618 GTK_MESSAGE_DIALOG (dialog),
619 _("Renaming \"%s\" to \"%s\" will destroy the existing "
620 "dataset named \"%s\". Are you sure that you want to do this?"),
621 old_dataset, new_dataset, existing_dataset);
623 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
624 _("Cancel"), GTK_RESPONSE_CANCEL,
625 _("Delete"), GTK_RESPONSE_OK,
628 g_object_set (dialog, "icon-name", "org.gnu.pspp", NULL);
630 result = gtk_dialog_run (GTK_DIALOG (dialog));
632 gtk_widget_destroy (dialog);
634 return result == GTK_RESPONSE_OK;
638 on_rename_dataset (PsppireDataWindow *de)
640 struct dataset *ds = de->dataset;
641 struct session *session = dataset_session (ds);
642 const char *old_name = dataset_name (ds);
643 struct dataset *existing_dataset;
647 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
649 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
653 if (new_name == NULL)
656 existing_dataset = session_lookup_dataset (session, new_name);
657 if (existing_dataset == NULL || existing_dataset == ds
658 || confirm_delete_dataset (de, old_name, new_name,
659 dataset_name (existing_dataset)))
660 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
668 status_bar_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
670 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
672 GVariant *state = g_action_get_state (action);
673 const gboolean visible = g_variant_get_boolean (state);
674 g_action_change_state (action, g_variant_new_boolean (!visible));
676 gtk_widget_set_visible (statusbar, !visible);
681 grid_lines_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
683 GVariant *state = g_action_get_state (action);
684 const gboolean grid_visible = g_variant_get_boolean (state);
685 g_action_change_state (action, g_variant_new_boolean (!grid_visible));
687 psppire_data_editor_show_grid (de->data_editor, !grid_visible);
692 on_switch_page (GtkNotebook *notebook, GtkWidget *page, guint pn, gpointer ud)
694 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (ud);
696 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de), "view_dv");
701 g_action_change_state (action, g_variant_new_string ("DATA"));
702 gtk_widget_show (GTK_WIDGET (de->ti_insert_case));
703 gtk_widget_show (GTK_WIDGET (de->ti_jump_to_case));
704 gtk_widget_show (GTK_WIDGET (de->ti_find));
706 gtk_widget_show (GTK_WIDGET (de->mi_go_to_case));
707 gtk_widget_show (GTK_WIDGET (de->mi_insert_case));
708 gtk_widget_show (GTK_WIDGET (de->mi_find));
709 gtk_widget_show (GTK_WIDGET (de->mi_find_separator));
710 gtk_widget_show (GTK_WIDGET (de->mi_clear_cases));
715 g_action_change_state (action, g_variant_new_string ("VARS"));
716 gtk_widget_hide (GTK_WIDGET (de->ti_insert_case));
717 gtk_widget_hide (GTK_WIDGET (de->ti_jump_to_case));
718 gtk_widget_hide (GTK_WIDGET (de->ti_find));
720 gtk_widget_hide (GTK_WIDGET (de->mi_go_to_case));
721 gtk_widget_hide (GTK_WIDGET (de->mi_insert_case));
722 gtk_widget_hide (GTK_WIDGET (de->mi_find));
723 gtk_widget_hide (GTK_WIDGET (de->mi_find_separator));
724 gtk_widget_hide (GTK_WIDGET (de->mi_clear_cases));
732 activate_change_view (GAction *action, GVariant *param, PsppireDataWindow *de)
734 g_action_change_state (action, param);
735 GVariant *new_state = g_action_get_state (action);
737 const gchar *what = g_variant_get_string (new_state, NULL);
738 if (0 == g_strcmp0 (what, "DATA"))
740 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
742 else if (0 == g_strcmp0 (what, "VARS"))
744 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
751 fonts_activate (PsppireDataWindow *de)
753 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
754 GtkWidget *dialog = gtk_font_chooser_dialog_new (NULL, GTK_WINDOW (toplevel));
755 GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET(de->data_editor));
756 const PangoFontDescription *current_font ;
758 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, "font", ¤t_font, NULL);
760 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (dialog), current_font);
762 gtk_window_set_transient_for (GTK_WINDOW (dialog),
763 GTK_WINDOW (toplevel));
765 if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)))
767 PangoFontDescription* font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog));
769 psppire_data_editor_set_font (de->data_editor, font_desc);
772 gtk_widget_hide (dialog);
777 /* Callback for the value labels action */
780 value_labels_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
782 GVariant *v = g_action_get_state (action);
783 gboolean labels_active = g_variant_get_boolean (v);
784 g_action_change_state (action, g_variant_new_boolean (!labels_active));
786 GVariant *new_state = g_action_get_state (action);
787 labels_active = g_variant_get_boolean (new_state);
788 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
790 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (de->ti_value_labels_button),
795 on_labels_button_toggle (GtkToggleToolButton *ttb, PsppireDataWindow *de)
797 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "value_labels");
799 gboolean labels_active = gtk_toggle_tool_button_get_active (ttb);
801 g_action_change_state (a, g_variant_new_boolean (labels_active));
803 GVariant *new_state = g_action_get_state (a);
804 labels_active = g_variant_get_boolean (new_state);
805 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
809 on_recent_data_select (GtkMenuShell *menushell,
810 PsppireWindow *window)
815 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
817 file = g_filename_from_uri (uri, NULL, NULL);
821 open_data_window (window, file, NULL, NULL);
827 charset_from_mime_type (const char *mime_type)
833 if (mime_type == NULL)
836 charset = c_strcasestr (mime_type, "charset=");
844 /* Parse a "quoted-string" as defined by RFC 822. */
845 for (p++; *p != '\0' && *p != '"'; p++)
848 ds_put_byte (&s, *p);
849 else if (*++p != '\0')
850 ds_put_byte (&s, *p);
855 /* Parse a "token" as defined by RFC 2045. */
856 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
857 ds_put_byte (&s, *p++);
859 if (!ds_is_empty (&s))
860 return ds_steal_cstr (&s);
867 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
874 /* Get the file name and its encoding. */
875 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
876 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
877 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
878 gtk_recent_info_unref (item);
880 se = psppire_syntax_window_new (encoding);
882 if (psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL))
883 gtk_widget_show (se);
885 gtk_widget_destroy (se);
892 set_unsaved (gpointer w)
894 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
898 /* Only a data file with at least one variable can be saved. */
900 enable_save (PsppireDataWindow *dw)
902 gboolean enable = psppire_dict_get_n_vars (dw->dict) > 0;
904 GAction *save_as = g_action_map_lookup_action (G_ACTION_MAP (dw), "save-as");
905 GAction *save = g_action_map_lookup_action (G_ACTION_MAP (dw), "save");
908 g_object_set (save, "enabled", enable, NULL);
911 g_object_set (save_as, "enabled", enable, NULL);
914 /* Initializes as much of a PsppireDataWindow as we can and must before the
915 dataset has been set.
917 In particular, the 'menu' member is required in case the "filename" property
918 is set before the "dataset" property: otherwise PsppireWindow will try to
919 modify the menu as part of the "filename" property_set() function and end up
920 with a Gtk-CRITICAL since 'menu' is NULL. */
922 psppire_data_window_init (PsppireDataWindow *dw)
924 dw->dispose_has_run = FALSE;
926 dw->builder = builder_new ("data-editor.ui");
930 file_import (PsppireDataWindow *dw)
932 GtkWidget *w = psppire_import_assistant_new (GTK_WINDOW (dw));
933 PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
934 gtk_widget_show_all (w);
936 int response = psppire_import_assistant_run (asst);
940 case GTK_RESPONSE_APPLY:
942 gchar *fn = g_path_get_basename (asst->file_name);
943 open_data_window (PSPPIRE_WINDOW (dw), fn, NULL, psppire_import_assistant_generate_syntax (asst));
947 case PSPPIRE_RESPONSE_PASTE:
948 free (paste_syntax_to_window (psppire_import_assistant_generate_syntax (asst)));
954 gtk_widget_destroy (GTK_WIDGET (asst));
960 connect_dialog_action (GType type, PsppireDataWindow *de)
962 GAction *act = g_object_new (type,
966 g_action_map_add_action (G_ACTION_MAP (de), act);
970 g_action_activate_null (GAction *a)
972 g_action_activate (a, NULL);
976 connect_action_to_menuitem (GActionMap *map, const gchar *action_name, GtkWidget *w, const gchar *accel)
978 GAction *a = g_action_map_lookup_action (map, action_name);
981 g_error ("Action \"%s\" not found in map", action_name);
985 GtkApplication *app = GTK_APPLICATION (g_application_get_default());
987 /* First set the label for the accellerator so that it appears
989 GtkWidget *child = gtk_bin_get_child (GTK_BIN (w));
991 GdkModifierType modifier;
992 gtk_accelerator_parse (accel, &key, &modifier);
993 gtk_accel_label_set_accel (GTK_ACCEL_LABEL (child), key, modifier);
995 /* Now tell the application that it must do something when that
996 key combination is pressed */
997 const gchar *accels[2];
1001 gchar *detailed_action_name = NULL;
1002 if (GTK_IS_WINDOW (map))
1003 detailed_action_name = g_strdup_printf ("win.%s", action_name);
1004 else if (GTK_IS_APPLICATION (map))
1005 detailed_action_name = g_strdup_printf ("app.%s", action_name);
1007 gtk_application_set_accels_for_action (app,
1008 detailed_action_name,
1010 free (detailed_action_name);
1013 g_signal_connect_swapped (w, "activate", G_CALLBACK (g_action_activate_null), a);
1018 on_realize (PsppireDataWindow *dw)
1020 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 1);
1025 on_cut (PsppireDataWindow *dw)
1027 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1028 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1030 PsppireDict *dict = NULL;
1031 g_object_get (dw->data_editor, "dictionary", &dict, NULL);
1034 SswSheet *sheet = SSW_SHEET (dw->data_editor->data_sheet);
1035 SswRange sel = *sheet->selection;
1037 if (ssw_sheet_try_cut (sheet))
1040 if (sel.start_x > sel.end_x)
1042 gint tmp = sel.start_x;
1043 sel.start_x = sel.end_x;
1046 if (sel.start_y > sel.end_y)
1048 gint tmp = sel.start_y;
1049 sel.start_y = sel.end_y;
1053 GtkClipboard *clip =
1054 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1055 GDK_SELECTION_CLIPBOARD);
1057 /* Save the selected area to a string */
1058 GString *str = g_string_new ("");
1059 for (y = sel.start_y ; y <= sel.end_y; ++y)
1061 for (x = sel.start_x ; x <= sel.end_x; ++x)
1063 const struct variable * var = psppire_dict_get_variable (dict, x);
1064 gboolean use_value_label = FALSE;
1065 g_object_get (dw->data_editor, "value-labels", &use_value_label, NULL);
1066 gchar *s = psppire_data_store_get_string (dw->data_editor->data_store,
1067 y, var, use_value_label);
1068 g_string_append (str, s);
1070 g_string_append (str, "\t");
1074 g_string_append (str, "\n");
1077 gtk_clipboard_set_text (clip, str->str, str->len);
1078 g_string_free (str, TRUE);
1080 /* Now fill the selected area with SYSMIS or blanks */
1081 for (x = sel.start_x ; x <= sel.end_x; ++x)
1083 const struct variable *var = psppire_dict_get_variable (dict, x);
1084 int width = var_get_width (var);
1086 value_init (&sm, width);
1087 if (var_is_numeric (var))
1090 memset (sm.s, 0, width);
1091 for (y = sel.start_y ; y <= sel.end_y; ++y)
1093 psppire_data_store_set_value (dw->data_editor->data_store,
1097 value_destroy (&sm, width);
1103 on_copy (PsppireDataWindow *dw)
1105 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1106 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1108 GtkClipboard *clip =
1109 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1110 GDK_SELECTION_CLIPBOARD);
1112 ssw_sheet_set_clip (SSW_SHEET (dw->data_editor->data_sheet), clip);
1117 on_paste (PsppireDataWindow *dw)
1119 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1120 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1122 psppire_data_editor_paste (dw->data_editor);
1127 on_clear_cases (PsppireDataWindow *dw)
1129 PsppireDataEditor *de = dw->data_editor;
1130 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1131 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1133 SswRange *range = SSW_SHEET(de->data_sheet)->selection;
1134 g_return_if_fail (range->start_y >= 0);
1135 psppire_data_store_delete_cases (de->data_store, range->start_y,
1136 range->end_y - range->start_y + 1);
1137 gtk_widget_queue_draw (GTK_WIDGET (de->data_sheet));
1142 on_clear_variables (PsppireDataWindow *dw)
1144 PsppireDataEditor *de = dw->data_editor;
1145 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1146 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1148 psppire_data_editor_data_delete_variables (de);
1152 psppire_data_editor_var_delete_variables (de);
1157 insert_variable (PsppireDataWindow *dw)
1159 PsppireDataEditor *de = dw->data_editor;
1160 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1162 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1164 SswRange *range = SSW_SHEET(de->data_sheet)->selection;
1165 psppire_data_editor_insert_new_variable_at_posn (de, range->start_x);
1169 SswRange *range = SSW_SHEET(de->var_sheet)->selection;
1170 PsppireDict *dict = NULL;
1171 g_object_get (de->var_sheet, "data-model", &dict, NULL);
1172 psppire_dict_insert_variable (dict, range->start_y, NULL);
1173 gtk_widget_queue_draw (GTK_WIDGET (de->var_sheet));
1178 insert_case_at_row (PsppireDataWindow *dw)
1180 PsppireDataEditor *de = dw->data_editor;
1181 SswRange *range = SSW_SHEET(de->data_sheet)->selection;
1182 psppire_data_editor_insert_new_case_at_posn (de, range->start_y);
1186 goto_case (PsppireDataWindow *dw)
1188 PsppireDataEditor *de = dw->data_editor;
1189 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1190 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1192 goto_case_dialog (PSPPIRE_DATA_SHEET (de->data_sheet));
1197 create_file_menu (PsppireDataWindow *dw)
1199 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1200 GtkWidget *menu = gtk_menu_new ();
1203 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1204 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1206 GtkWidget *new_menu = gtk_menu_new ();
1208 g_object_set (new, "submenu", new_menu, NULL);
1210 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1211 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1213 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1214 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1216 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1217 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1220 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1221 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Primary>O");
1223 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1224 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1226 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1227 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1229 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1231 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1232 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Primary>S");
1234 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1235 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Primary>S");
1237 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1238 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1241 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1242 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1243 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1245 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1248 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1249 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1251 GtkWidget *dd_menu = gtk_menu_new ();
1253 g_object_set (display_data, "submenu", dd_menu, NULL);
1255 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1256 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1257 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1258 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1260 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1261 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1264 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1267 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1268 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1270 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1271 gtk_recent_manager_get_default ());
1273 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1274 gtk_recent_manager_get_default ());
1276 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1277 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1279 g_object_set (menu_data, "show-tips", TRUE, NULL);
1280 g_object_set (menu_files, "show-tips", TRUE, NULL);
1282 g_object_set (mi_data, "submenu", menu_data, NULL);
1283 g_object_set (mi_files, "submenu", menu_files, NULL);
1286 GtkRecentFilter *filter = gtk_recent_filter_new ();
1288 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1289 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1291 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1293 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1296 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1299 GtkRecentFilter *filter = gtk_recent_filter_new ();
1301 gtk_recent_filter_add_pattern (filter, "*.sps");
1302 gtk_recent_filter_add_pattern (filter, "*.SPS");
1304 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1306 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1309 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1312 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1315 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1316 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1318 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1319 "quit", quit, "<Primary>Q");
1322 g_object_set (menuitem, "submenu", menu, NULL);
1323 gtk_widget_show_all (menuitem);
1330 create_edit_menu (PsppireDataWindow *dw)
1333 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1335 GtkWidget *menu = gtk_menu_new ();
1337 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1338 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1339 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1340 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1342 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1343 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1345 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1346 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1347 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1349 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1351 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1353 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1354 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1357 GtkAccelGroup *ag = gtk_accel_group_new ();
1359 GdkModifierType modifier;
1361 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1362 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1364 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1365 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1366 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1368 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1369 gtk_accelerator_parse ("<Primary>X", &key, &modifier);
1370 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1371 key, modifier, GTK_ACCEL_VISIBLE);
1373 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1374 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1375 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1376 gtk_accelerator_parse ("<Primary>C", &key, &modifier);
1377 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1378 key, modifier, GTK_ACCEL_VISIBLE);
1380 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1381 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1382 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1383 gtk_accelerator_parse ("<Primary>V", &key, &modifier);
1384 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1385 key, modifier, GTK_ACCEL_VISIBLE);
1387 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1388 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1389 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1391 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1392 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1393 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1394 g_object_unref (ag);
1398 dw->mi_find_separator = gtk_separator_menu_item_new ();
1399 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1401 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1402 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1403 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1407 dw->mi_options = gtk_menu_item_new_with_mnemonic (_("_Options..."));
1408 g_signal_connect_swapped (dw->mi_options, "activate",
1409 G_CALLBACK (options_dialog), dw);
1410 gtk_menu_attach (GTK_MENU (menu), dw->mi_options, 0, 1, i, i + 1); ++i;
1413 g_object_set (menuitem, "submenu", menu, NULL);
1415 gtk_widget_show_all (menuitem);
1421 psppire_data_window_finish_init (PsppireDataWindow *de,
1424 static const struct dataset_callbacks cbs =
1426 set_unsaved, /* changed */
1427 transformation_change_callback, /* transformations_changed */
1434 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1437 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1438 de->data_store = psppire_data_store_new (de->dict);
1439 psppire_data_store_set_reader (de->data_store, NULL);
1441 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1442 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1443 gtk_widget_show (menubar);
1445 hb = gtk_toolbar_new ();
1446 sb = get_widget_assert (de->builder, "status-bar");
1449 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1451 g_signal_connect (de, "realize",
1452 G_CALLBACK (on_realize), de);
1454 g_signal_connect_swapped (de->data_store, "case-changed",
1455 G_CALLBACK (set_unsaved), de);
1457 dataset_set_callbacks (de->dataset, &cbs, de);
1459 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1460 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1461 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1462 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1464 gtk_container_add (GTK_CONTAINER (de), box);
1466 g_signal_connect (de->dict, "weight-changed",
1467 G_CALLBACK (on_weight_change),
1470 g_signal_connect (de->dict, "filter-changed",
1471 G_CALLBACK (on_filter_change),
1474 g_signal_connect (de->dict, "split-changed",
1475 G_CALLBACK (on_split_change),
1478 g_signal_connect_swapped (de->dict, "items-changed",
1479 G_CALLBACK (enable_save), de);
1480 g_signal_connect_swapped (de->dict, "variable-inserted",
1481 G_CALLBACK (enable_save), de);
1482 g_signal_connect_swapped (de->dict, "variable-deleted",
1483 G_CALLBACK (enable_save), de);
1486 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1487 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1488 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1489 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1490 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1492 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1493 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1494 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1495 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1496 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1497 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1498 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1501 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1502 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1503 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1504 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1506 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1507 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1509 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1510 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1512 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1513 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1514 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1515 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1516 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1517 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1518 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1519 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1520 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1522 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1523 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1525 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1526 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1527 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1529 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1530 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1531 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1532 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1533 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1534 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1535 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_INDEPENDENT, de);
1538 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1539 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1540 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1544 GSimpleAction *save = g_simple_action_new ("save", NULL);
1545 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1546 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1550 GSimpleAction *open = g_simple_action_new ("open", NULL);
1551 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1552 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1556 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1557 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1558 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1562 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1563 g_signal_connect_swapped (rename_dataset_act, "activate",
1564 G_CALLBACK (on_rename_dataset), de);
1565 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1569 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1570 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1571 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1574 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1575 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1576 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1580 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1581 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1582 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1586 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1587 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1588 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1593 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1594 g_variant_new_string ("DATA"));
1595 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1596 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1600 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1601 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1602 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1606 GSimpleAction *act_value_labels =
1607 g_simple_action_new_stateful ("value_labels", NULL,
1608 g_variant_new_boolean (FALSE));
1609 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1610 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1614 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1615 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1616 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1620 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1621 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1625 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1626 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1627 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1631 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1632 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1633 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1637 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1638 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1639 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1643 GSimpleAction *find = g_simple_action_new ("find", NULL);
1644 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1645 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1651 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1652 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1653 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1654 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "pspp-file-open-data");
1658 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1659 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1660 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1661 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "pspp-file-save-data");
1664 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1667 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1669 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1671 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1672 G_CALLBACK (psppire_dialog_action_activate_null), a);
1674 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1675 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "pspp-edit-go-to-variable");
1676 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1680 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1682 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1684 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1685 G_CALLBACK (g_action_activate_null), a);
1687 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1688 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "pspp-edit-go-to-case");
1689 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1693 de->ti_find = gtk_tool_button_new (NULL, "Find");
1695 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1697 g_signal_connect_swapped (de->ti_find, "clicked",
1698 G_CALLBACK (g_action_activate_null), a);
1701 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1702 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "pspp-edit-find");
1703 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1707 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1708 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1710 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1711 G_CALLBACK (g_action_activate_null), a);
1713 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1714 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "pspp-edit-insert-case");
1715 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1719 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1720 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1722 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1723 G_CALLBACK (g_action_activate_null), a);
1725 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1726 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "pspp-edit-insert-variable");
1727 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1730 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1733 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1734 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1735 "PsppireDialogActionSplit");
1737 g_signal_connect_swapped (ti, "clicked",
1738 G_CALLBACK (psppire_dialog_action_activate_null), a);
1739 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1740 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "pspp-data-split-file");
1741 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1745 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1746 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1747 "PsppireDialogActionWeight");
1749 g_signal_connect_swapped (ti, "clicked",
1750 G_CALLBACK (psppire_dialog_action_activate_null), a);
1751 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1752 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "pspp-data-weight-cases");
1753 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1757 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1758 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1760 g_signal_connect (de->ti_value_labels_button, "toggled",
1761 G_CALLBACK (on_labels_button_toggle), de);
1762 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1763 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "pspp-view-value-labels");
1764 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1769 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1770 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1772 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1773 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1774 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1775 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1777 g_signal_connect (de->data_editor, "switch-page",
1778 G_CALLBACK (on_switch_page), de);
1780 gtk_widget_show (GTK_WIDGET (de->data_editor));
1781 gtk_widget_show_all (box);
1783 ll_push_head (&all_data_windows, &de->ll);
1788 psppire_data_window_dispose (GObject *object)
1790 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1792 if (dw->dispose_has_run)
1794 dw->dispose_has_run = TRUE;
1796 g_object_unref (dw->builder);
1800 g_signal_handlers_disconnect_by_func (dw->dict,
1801 G_CALLBACK (enable_save), dw);
1802 g_signal_handlers_disconnect_by_func (dw->dict,
1803 G_CALLBACK (on_weight_change), dw);
1804 g_signal_handlers_disconnect_by_func (dw->dict,
1805 G_CALLBACK (on_filter_change), dw);
1806 g_signal_handlers_disconnect_by_func (dw->dict,
1807 G_CALLBACK (on_split_change), dw);
1809 g_object_unref (dw->dict);
1812 g_object_unref (dw->data_store);
1814 if (G_OBJECT_CLASS (parent_class)->dispose)
1815 G_OBJECT_CLASS (parent_class)->dispose (object);
1819 psppire_data_window_finalize (GObject *object)
1821 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1825 struct dataset *dataset = dw->dataset;
1826 struct session *session = dataset_session (dataset);
1830 dataset_set_callbacks (dataset, NULL, NULL);
1831 session_set_active_dataset (session, NULL);
1832 dataset_destroy (dataset);
1835 if (dw->ll.next != NULL)
1837 ll_remove (&dw->ll);
1841 if (G_OBJECT_CLASS (parent_class)->finalize)
1842 G_OBJECT_CLASS (parent_class)->finalize (object);
1846 psppire_data_window_set_property (GObject *object,
1848 const GValue *value,
1851 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1856 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1859 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1865 psppire_data_window_get_property (GObject *object,
1870 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1875 g_value_set_pointer (value, window->dataset);
1878 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1886 psppire_data_window_new (struct dataset *ds)
1890 if (the_session == NULL)
1891 the_session = session_create (NULL);
1895 char *dataset_name = session_generate_dataset_name (the_session);
1896 ds = dataset_create (the_session, dataset_name);
1897 free (dataset_name);
1899 assert (dataset_session (ds) == the_session);
1903 psppire_data_window_get_type (),
1904 "description", _("Data Editor"),
1908 if (dataset_name (ds) != NULL)
1909 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1912 GApplication *app = g_application_get_default ();
1913 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1921 psppire_data_window_is_empty (PsppireDataWindow *dw)
1923 return psppire_dict_get_n_vars (dw->dict) == 0;
1928 psppire_data_window_iface_init (PsppireWindowIface *iface)
1930 iface->save = save_file;
1931 iface->pick_filename = data_pick_filename;
1932 iface->load = load_file;
1939 psppire_default_data_window (void)
1941 if (ll_is_empty (&all_data_windows))
1942 create_data_window ();
1943 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1949 psppire_data_window_set_default (PsppireDataWindow *pdw)
1951 ll_remove (&pdw->ll);
1952 ll_push_head (&all_data_windows, &pdw->ll);
1956 psppire_data_window_undefault (PsppireDataWindow *pdw)
1958 ll_remove (&pdw->ll);
1959 ll_push_tail (&all_data_windows, &pdw->ll);
1965 psppire_data_window_for_dataset (struct dataset *ds)
1967 PsppireDataWindow *pdw;
1969 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1970 if (pdw->dataset == ds)
1977 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1979 PsppireDataWindow *pdw;
1981 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1982 if (pdw->data_store == data_store)
1989 create_data_window (void)
1991 GtkWidget *w = psppire_data_window_new (NULL);
1993 gtk_widget_show (w);
1995 return GTK_WINDOW (w);
1999 open_data_window (PsppireWindow *victim, const char *file_name,
2000 const char *encoding, gpointer hint)
2004 if (PSPPIRE_IS_DATA_WINDOW (victim)
2005 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
2007 window = GTK_WIDGET (victim);
2010 window = psppire_data_window_new (NULL);
2012 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
2013 return GTK_WINDOW (window);