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_class_init (PsppireDataWindowClass *class);
105 static void psppire_data_window_init (PsppireDataWindow *data_editor);
108 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
110 static void psppire_data_window_dispose (GObject *object);
111 static void psppire_data_window_finalize (GObject *object);
112 static void psppire_data_window_set_property (GObject *object,
116 static void psppire_data_window_get_property (GObject *object,
122 psppire_data_window_get_type (void)
124 static GType psppire_data_window_type = 0;
126 if (!psppire_data_window_type)
128 static const GTypeInfo psppire_data_window_info =
130 sizeof (PsppireDataWindowClass),
133 (GClassInitFunc)psppire_data_window_class_init,
134 (GClassFinalizeFunc) NULL,
136 sizeof (PsppireDataWindow),
138 (GInstanceInitFunc) psppire_data_window_init,
141 static const GInterfaceInfo window_interface_info =
143 (GInterfaceInitFunc) psppire_data_window_iface_init,
148 psppire_data_window_type =
149 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
150 &psppire_data_window_info, 0);
153 g_type_add_interface_static (psppire_data_window_type,
154 PSPPIRE_TYPE_WINDOW_MODEL,
155 &window_interface_info);
158 return psppire_data_window_type;
161 static GObjectClass *parent_class ;
168 psppire_data_window_class_init (PsppireDataWindowClass *class)
170 GObjectClass *object_class = G_OBJECT_CLASS (class);
172 parent_class = g_type_class_peek_parent (class);
174 object_class->dispose = psppire_data_window_dispose;
175 object_class->finalize = psppire_data_window_finalize;
176 object_class->set_property = psppire_data_window_set_property;
177 object_class->get_property = psppire_data_window_get_property;
179 g_object_class_install_property (
180 object_class, PROP_DATASET,
181 g_param_spec_pointer ("dataset", "Dataset",
182 "'struct datset *' represented by the window",
183 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
188 /* Run the EXECUTE command. */
190 execute (PsppireDataWindow *dw)
192 execute_const_syntax_string (dw, "EXECUTE.");
196 transformation_change_callback (bool transformations_pending,
199 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
201 GtkWidget *status_label =
202 get_widget_assert (de->builder, "case-counter-area");
205 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de),
206 "transform-pending");
208 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
209 transformations_pending);
212 if ( transformations_pending)
213 gtk_label_set_text (GTK_LABEL (status_label),
214 _("Transformations Pending"));
216 gtk_label_set_text (GTK_LABEL (status_label), "");
219 /* Callback for when the dictionary changes its filter variable */
221 on_filter_change (GObject *o, gint filter_index, gpointer data)
223 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
225 GtkWidget *filter_status_area =
226 get_widget_assert (de->builder, "filter-use-status-area");
228 if ( filter_index == -1 )
230 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
234 PsppireDict *dict = NULL;
235 struct variable *var ;
238 g_object_get (de->data_editor, "dictionary", &dict, NULL);
240 var = psppire_dict_get_variable (dict, filter_index);
242 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
244 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
250 /* Callback for when the dictionary changes its split variables */
252 on_split_change (PsppireDict *dict, gpointer data)
254 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
256 size_t n_split_vars = dict_get_split_cnt (dict->dict);
258 GtkWidget *split_status_area =
259 get_widget_assert (de->builder, "split-file-status-area");
261 if ( n_split_vars == 0 )
263 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
269 const struct variable *const * split_vars =
270 dict_get_split_vars (dict->dict);
272 text = g_string_new (_("Split by "));
274 for (i = 0 ; i < n_split_vars - 1; ++i )
276 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
278 g_string_append (text, var_get_name (split_vars[i]));
280 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
282 g_string_free (text, TRUE);
289 /* Callback for when the dictionary changes its weights */
291 on_weight_change (GObject *o, gint weight_index, gpointer data)
293 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
295 GtkWidget *weight_status_area =
296 get_widget_assert (de->builder, "weight-status-area");
298 if ( weight_index == -1 )
300 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
304 struct variable *var ;
305 PsppireDict *dict = NULL;
308 g_object_get (de->data_editor, "dictionary", &dict, NULL);
310 var = psppire_dict_get_variable (dict, weight_index);
312 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
314 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
322 dump_rm (GtkRecentManager *rm)
324 GList *items = gtk_recent_manager_get_items (rm);
328 g_print ("Recent Items:\n");
329 for (i = items; i; i = i->next)
331 GtkRecentInfo *ri = i->data;
333 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
334 gtk_recent_info_get_short_name (ri),
335 gtk_recent_info_get_mime_type (ri),
336 gtk_recent_info_get_description (ri),
337 gtk_recent_info_get_uri (ri)
341 gtk_recent_info_unref (ri);
349 has_suffix (const gchar *name, const gchar *suffix)
351 size_t name_len = strlen (name);
352 size_t suffix_len = strlen (suffix);
353 return (name_len > suffix_len
354 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
358 name_has_por_suffix (const gchar *name)
360 return has_suffix (name, ".por");
364 name_has_sav_suffix (const gchar *name)
366 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
369 /* Returns true if NAME has a suffix which might denote a PSPP file */
371 name_has_suffix (const gchar *name)
373 return name_has_por_suffix (name) || name_has_sav_suffix (name);
377 load_file (PsppireWindow *de, const gchar *file_name, const char *encoding,
380 const char *mime_type = NULL;
381 gchar *syntax = NULL;
386 gchar *utf8_file_name;
387 struct string filename;
389 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
391 if (NULL == utf8_file_name)
394 ds_init_empty (&filename);
395 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
397 g_free (utf8_file_name);
399 if (encoding && encoding[0])
400 syntax = g_strdup_printf ("GET FILE=%s ENCODING='%s'.",
401 ds_cstr (&filename), encoding);
403 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
404 ds_destroy (&filename);
411 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
412 lex_reader_for_string (syntax, "UTF-8"));
415 if (ok && syn == NULL)
417 if (name_has_por_suffix (file_name))
418 mime_type = "application/x-spss-por";
419 else if (name_has_sav_suffix (file_name))
420 mime_type = "application/x-spss-sav";
422 add_most_recent (file_name, mime_type, encoding);
429 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
431 if (format == PSPPIRE_DATA_WINDOW_SAV)
433 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
439 /* Save DE to file */
441 save_file (PsppireWindow *w)
443 const gchar *file_name = NULL;
444 gchar *utf8_file_name = NULL;
446 struct string filename ;
447 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
450 file_name = psppire_window_get_filename (w);
452 fnx = g_string_new (file_name);
454 if ( ! name_has_suffix (fnx->str))
455 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
457 ds_init_empty (&filename);
459 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
461 g_string_free (fnx, TRUE);
463 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
464 g_free (utf8_file_name);
466 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
467 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
468 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
469 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
470 ds_cstr (&filename));
472 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
474 ds_destroy (&filename);
476 g_free (execute_syntax_string (de, syntax));
481 display_dict (PsppireDataWindow *de)
483 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
487 sysfile_info (PsppireDataWindow *de)
489 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
491 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
493 struct string filename;
495 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
496 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
499 const gchar *encoding = psppire_encoding_selector_get_encoding (
500 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
504 ds_init_empty (&filename);
506 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
508 g_free (utf8_file_name);
511 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
512 ds_cstr (&filename), encoding);
514 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
515 g_free (execute_syntax_string (de, syntax));
518 gtk_widget_destroy (dialog);
522 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
524 data_pick_filename (PsppireWindow *window)
526 GtkListStore *list_store;
527 GtkWidget *combo_box;
529 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
530 GtkFileFilter *filter;
532 gtk_file_chooser_dialog_new (_("Save"),
534 GTK_FILE_CHOOSER_ACTION_SAVE,
535 _("Cancel"), GTK_RESPONSE_CANCEL,
536 _("Save"), GTK_RESPONSE_ACCEPT,
539 g_object_set (dialog, "local-only", FALSE, NULL);
541 filter = gtk_file_filter_new ();
542 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
543 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
544 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
546 filter = gtk_file_filter_new ();
547 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
548 gtk_file_filter_add_pattern (filter, "*.zsav");
549 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
551 filter = gtk_file_filter_new ();
552 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
553 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
554 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
556 filter = gtk_file_filter_new ();
557 gtk_file_filter_set_name (filter, _("All Files"));
558 gtk_file_filter_add_pattern (filter, "*");
559 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
560 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
563 GtkCellRenderer *cell;
568 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
569 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
571 gtk_list_store_append (list_store, &iter);
572 gtk_list_store_set (list_store, &iter,
573 0, PSPPIRE_DATA_WINDOW_SAV,
576 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
578 gtk_list_store_append (list_store, &iter);
579 gtk_list_store_set (list_store, &iter,
580 0, PSPPIRE_DATA_WINDOW_ZSAV,
581 1, _("Compressed System File"),
584 gtk_list_store_append (list_store, &iter);
585 gtk_list_store_set (list_store, &iter,
586 0, PSPPIRE_DATA_WINDOW_POR,
587 1, _("Portable File"),
590 label = gtk_label_new (_("Format:"));
592 cell = gtk_cell_renderer_text_new ();
593 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
594 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
597 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
598 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
599 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
600 gtk_widget_show_all (hbox);
602 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
605 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
608 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
610 case GTK_RESPONSE_ACCEPT:
615 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
621 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
622 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
627 if ( ! name_has_suffix (filename->str))
628 g_string_append (filename,
629 psppire_data_window_format_to_string (format));
631 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
633 g_string_free (filename, TRUE);
640 gtk_widget_destroy (dialog);
644 confirm_delete_dataset (PsppireDataWindow *de,
645 const char *old_dataset,
646 const char *new_dataset,
647 const char *existing_dataset)
652 dialog = gtk_message_dialog_new (
653 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
654 _("Delete Existing Dataset?"));
656 gtk_message_dialog_format_secondary_text (
657 GTK_MESSAGE_DIALOG (dialog),
658 _("Renaming \"%s\" to \"%s\" will destroy the existing "
659 "dataset named \"%s\". Are you sure that you want to do this?"),
660 old_dataset, new_dataset, existing_dataset);
662 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
663 _("Cancel"), GTK_RESPONSE_CANCEL,
664 _("Delete"), GTK_RESPONSE_OK,
667 g_object_set (dialog, "icon-name", "pspp", NULL);
669 result = gtk_dialog_run (GTK_DIALOG (dialog));
671 gtk_widget_destroy (dialog);
673 return result == GTK_RESPONSE_OK;
677 on_rename_dataset (PsppireDataWindow *de)
679 struct dataset *ds = de->dataset;
680 struct session *session = dataset_session (ds);
681 const char *old_name = dataset_name (ds);
682 struct dataset *existing_dataset;
686 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
688 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
692 if (new_name == NULL)
695 existing_dataset = session_lookup_dataset (session, new_name);
696 if (existing_dataset == NULL || existing_dataset == ds
697 || confirm_delete_dataset (de, old_name, new_name,
698 dataset_name (existing_dataset)))
699 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
707 status_bar_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
709 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
711 GVariant *state = g_action_get_state (action);
712 const gboolean visible = g_variant_get_boolean (state);
713 g_action_change_state (action, g_variant_new_boolean (!visible));
715 gtk_widget_set_visible (statusbar, !visible);
720 grid_lines_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
722 GVariant *state = g_action_get_state (action);
723 const gboolean grid_visible = g_variant_get_boolean (state);
724 g_action_change_state (action, g_variant_new_boolean (!grid_visible));
726 psppire_data_editor_show_grid (de->data_editor, !grid_visible);
731 on_switch_page (GtkNotebook *notebook, GtkWidget *page, guint pn, gpointer ud)
733 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (ud);
735 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de), "view_dv");
740 g_action_change_state (action, g_variant_new_string ("DATA"));
741 gtk_widget_show (GTK_WIDGET (de->ti_insert_case));
742 gtk_widget_show (GTK_WIDGET (de->ti_jump_to_case));
743 gtk_widget_show (GTK_WIDGET (de->ti_find));
745 gtk_widget_show (GTK_WIDGET (de->mi_go_to_case));
746 gtk_widget_show (GTK_WIDGET (de->mi_insert_case));
747 gtk_widget_show (GTK_WIDGET (de->mi_find));
748 gtk_widget_show (GTK_WIDGET (de->mi_find_separator));
749 gtk_widget_show (GTK_WIDGET (de->mi_clear_cases));
754 g_action_change_state (action, g_variant_new_string ("VARS"));
755 gtk_widget_hide (GTK_WIDGET (de->ti_insert_case));
756 gtk_widget_hide (GTK_WIDGET (de->ti_jump_to_case));
757 gtk_widget_hide (GTK_WIDGET (de->ti_find));
759 gtk_widget_hide (GTK_WIDGET (de->mi_go_to_case));
760 gtk_widget_hide (GTK_WIDGET (de->mi_insert_case));
761 gtk_widget_hide (GTK_WIDGET (de->mi_find));
762 gtk_widget_hide (GTK_WIDGET (de->mi_find_separator));
763 gtk_widget_hide (GTK_WIDGET (de->mi_clear_cases));
771 activate_change_view (GAction *action, GVariant *param, PsppireDataWindow *de)
773 g_action_change_state (action, param);
774 GVariant *new_state = g_action_get_state (action);
776 const gchar *what = g_variant_get_string (new_state, NULL);
777 if (0 == g_strcmp0 (what, "DATA"))
779 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
781 else if (0 == g_strcmp0 (what, "VARS"))
783 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
790 fonts_activate (PsppireDataWindow *de)
792 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
793 GtkWidget *dialog = gtk_font_chooser_dialog_new (NULL, GTK_WINDOW (toplevel));
794 GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET(de->data_editor));
795 const PangoFontDescription *current_font ;
797 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, "font", ¤t_font, NULL);
799 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (dialog), current_font);
801 gtk_window_set_transient_for (GTK_WINDOW (dialog),
802 GTK_WINDOW (toplevel));
804 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
806 PangoFontDescription* font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog));
808 psppire_data_editor_set_font (de->data_editor, font_desc);
811 gtk_widget_hide (dialog);
816 /* Callback for the value labels action */
819 value_labels_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
821 GVariant *v = g_action_get_state (action);
822 gboolean labels_active = g_variant_get_boolean (v);
823 g_action_change_state (action, g_variant_new_boolean (!labels_active));
825 GVariant *new_state = g_action_get_state (action);
826 labels_active = g_variant_get_boolean (new_state);
827 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
829 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (de->ti_value_labels_button),
834 on_labels_button_toggle (GtkToggleToolButton *ttb, PsppireDataWindow *de)
836 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "value_labels");
838 gboolean labels_active = gtk_toggle_tool_button_get_active (ttb);
840 g_action_change_state (a, g_variant_new_boolean (labels_active));
842 GVariant *new_state = g_action_get_state (a);
843 labels_active = g_variant_get_boolean (new_state);
844 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
848 on_recent_data_select (GtkMenuShell *menushell,
849 PsppireWindow *window)
854 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
856 file = g_filename_from_uri (uri, NULL, NULL);
860 open_data_window (window, file, NULL, NULL);
866 charset_from_mime_type (const char *mime_type)
872 if (mime_type == NULL)
875 charset = c_strcasestr (mime_type, "charset=");
883 /* Parse a "quoted-string" as defined by RFC 822. */
884 for (p++; *p != '\0' && *p != '"'; p++)
887 ds_put_byte (&s, *p);
888 else if (*++p != '\0')
889 ds_put_byte (&s, *p);
894 /* Parse a "token" as defined by RFC 2045. */
895 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
896 ds_put_byte (&s, *p++);
898 if (!ds_is_empty (&s))
899 return ds_steal_cstr (&s);
906 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
913 /* Get the file name and its encoding. */
914 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
915 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
916 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
917 gtk_recent_info_unref (item);
919 se = psppire_syntax_window_new (encoding);
923 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
924 gtk_widget_show (se);
926 gtk_widget_destroy (se);
932 set_unsaved (gpointer w)
934 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
938 /* Only a data file with at least one variable can be saved. */
940 enable_save (PsppireDataWindow *dw)
942 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
944 GAction *save_as = g_action_map_lookup_action (G_ACTION_MAP (dw), "save-as");
945 GAction *save = g_action_map_lookup_action (G_ACTION_MAP (dw), "save");
948 g_object_set (save, "enabled", enable, NULL);
951 g_object_set (save_as, "enabled", enable, NULL);
954 /* Initializes as much of a PsppireDataWindow as we can and must before the
955 dataset has been set.
957 In particular, the 'menu' member is required in case the "filename" property
958 is set before the "dataset" property: otherwise PsppireWindow will try to
959 modify the menu as part of the "filename" property_set() function and end up
960 with a Gtk-CRITICAL since 'menu' is NULL. */
962 psppire_data_window_init (PsppireDataWindow *de)
964 de->builder = builder_new ("data-editor.ui");
968 file_import (PsppireDataWindow *dw)
970 GtkWidget *w = psppire_import_assistant_new (GTK_WINDOW (dw));
971 PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
972 gtk_widget_show_all (w);
974 int response = psppire_import_assistant_run (asst);
978 case GTK_RESPONSE_APPLY:
980 gchar *fn = g_path_get_basename (asst->file_name);
981 open_data_window (PSPPIRE_WINDOW (dw), fn, NULL, psppire_import_assistant_generate_syntax (asst));
985 case PSPPIRE_RESPONSE_PASTE:
986 free (paste_syntax_to_window (psppire_import_assistant_generate_syntax (asst)));
992 gtk_widget_destroy (GTK_WIDGET (asst));
998 connect_dialog_action (GType type, PsppireDataWindow *de)
1000 GAction *act = g_object_new (type,
1004 g_action_map_add_action (G_ACTION_MAP (de), act);
1008 g_action_activate_null (GAction *a)
1010 g_action_activate (a, NULL);
1014 connect_action_to_menuitem (GActionMap *map, const gchar *action_name, GtkWidget *w, const gchar *accel)
1016 GAction *a = g_action_map_lookup_action (map, action_name);
1019 g_error ("Action \"%s\" not found in map", action_name);
1023 GtkApplication *app = GTK_APPLICATION (g_application_get_default());
1025 /* First set the label for the accellerator so that it appears
1027 GtkWidget *child = gtk_bin_get_child (GTK_BIN (w));
1029 GdkModifierType modifier;
1030 gtk_accelerator_parse (accel, &key, &modifier);
1031 gtk_accel_label_set_accel (GTK_ACCEL_LABEL (child), key, modifier);
1033 /* Now tell the application that it must do something when that
1034 key combination is pressed */
1035 const gchar *accels[2];
1039 gchar *detailed_action_name = NULL;
1040 if (GTK_IS_WINDOW (map))
1041 detailed_action_name = g_strdup_printf ("win.%s", action_name);
1042 else if (GTK_IS_APPLICATION (map))
1043 detailed_action_name = g_strdup_printf ("app.%s", action_name);
1045 gtk_application_set_accels_for_action (app,
1046 detailed_action_name,
1048 free (detailed_action_name);
1051 g_signal_connect_swapped (w, "activate", G_CALLBACK (g_action_activate_null), a);
1056 on_realize (PsppireDataWindow *dw)
1058 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 1);
1063 on_cut (PsppireDataWindow *dw)
1065 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1066 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1068 PsppireDict *dict = NULL;
1069 g_object_get (dw->data_editor, "dictionary", &dict, NULL);
1072 SswSheet *sheet = SSW_SHEET (dw->data_editor->data_sheet);
1073 SswRange sel = *sheet->selection;
1075 GtkClipboard *clip =
1076 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1077 GDK_SELECTION_CLIPBOARD);
1079 /* Save the selected area to a string */
1080 GString *str = g_string_new ("");
1081 for (y = sel.start_y ; y <= sel.end_y; ++y)
1083 for (x = sel.start_x ; x <= sel.end_x; ++x)
1085 const struct variable * var = psppire_dict_get_variable (dict, x);
1086 gchar *s = psppire_data_store_get_string (dw->data_editor->data_store,
1088 g_string_append (str, s);
1089 g_string_append (str, "\t");
1092 g_string_append (str, "\n");
1095 gtk_clipboard_set_text (clip, str->str, str->len);
1096 g_string_free (str, TRUE);
1098 /* Now fill the selected area with SYSMIS */
1101 for (x = sel.start_x ; x <= sel.end_x; ++x)
1103 const struct variable * var = psppire_dict_get_variable (dict, x);
1104 for (y = sel.start_y ; y <= sel.end_y; ++y)
1106 psppire_data_store_set_value (dw->data_editor->data_store,
1116 on_copy (PsppireDataWindow *dw)
1118 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1119 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1121 GtkClipboard *clip =
1122 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1123 GDK_SELECTION_CLIPBOARD);
1125 ssw_sheet_set_clip (SSW_SHEET (dw->data_editor->data_sheet), clip);
1130 on_paste (PsppireDataWindow *dw)
1132 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1133 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1135 psppire_data_editor_paste (dw->data_editor);
1140 on_clear_cases (PsppireDataWindow *dw)
1142 PsppireDataEditor *de = dw->data_editor;
1143 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1144 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1146 SswRange *range = SSW_SHEET(de->data_sheet)->selection;
1147 psppire_data_store_delete_cases (de->data_store, range->start_y,
1148 range->end_y - range->start_y + 1);
1149 gtk_widget_queue_draw (GTK_WIDGET (de->data_sheet));
1154 on_clear_variables (PsppireDataWindow *dw)
1156 PsppireDataEditor *de = dw->data_editor;
1157 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1158 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1160 psppire_data_editor_data_delete_variables (de);
1164 psppire_data_editor_var_delete_variables (de);
1169 insert_variable (PsppireDataWindow *dw)
1171 PsppireDataEditor *de = dw->data_editor;
1172 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1174 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1176 SswRange *range = SSW_SHEET(de->data_sheet)->selection;
1177 psppire_data_editor_insert_new_variable_at_posn (de, range->start_x);
1181 SswRange *range = SSW_SHEET(de->var_sheet)->selection;
1182 psppire_data_editor_insert_new_variable_at_posn (de, range->start_y);
1187 insert_case_at_row (PsppireDataWindow *dw)
1189 PsppireDataEditor *de = dw->data_editor;
1190 SswRange *range = SSW_SHEET(de->data_sheet)->selection;
1191 psppire_data_editor_insert_new_case_at_posn (de, range->start_y);
1195 goto_case (PsppireDataWindow *dw)
1197 PsppireDataEditor *de = dw->data_editor;
1198 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1199 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1201 goto_case_dialog (PSPPIRE_DATA_SHEET (de->data_sheet));
1206 create_file_menu (PsppireDataWindow *dw)
1208 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1209 GtkWidget *menu = gtk_menu_new ();
1212 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1213 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1215 GtkWidget *new_menu = gtk_menu_new ();
1217 g_object_set (new, "submenu", new_menu, NULL);
1219 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1220 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1222 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1223 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1225 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1226 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1229 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1230 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Ctrl>O");
1232 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1233 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1235 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1236 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1238 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1240 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1241 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Ctrl>S");
1243 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1244 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Ctrl>S");
1246 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1247 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1250 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1251 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1252 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1254 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1257 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1258 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1260 GtkWidget *dd_menu = gtk_menu_new ();
1262 g_object_set (display_data, "submenu", dd_menu, NULL);
1264 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1265 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1266 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1267 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1269 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1270 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1273 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1276 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1277 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1279 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1280 gtk_recent_manager_get_default ());
1282 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1283 gtk_recent_manager_get_default ());
1285 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1286 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1288 g_object_set (menu_data, "show-tips", TRUE, NULL);
1289 g_object_set (menu_files, "show-tips", TRUE, NULL);
1291 g_object_set (mi_data, "submenu", menu_data, NULL);
1292 g_object_set (mi_files, "submenu", menu_files, NULL);
1295 GtkRecentFilter *filter = gtk_recent_filter_new ();
1297 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1298 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1300 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1302 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1305 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1308 GtkRecentFilter *filter = gtk_recent_filter_new ();
1310 gtk_recent_filter_add_pattern (filter, "*.sps");
1311 gtk_recent_filter_add_pattern (filter, "*.SPS");
1313 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1315 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1318 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1321 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1324 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1325 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1327 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1328 "quit", quit, "<Ctrl>Q");
1331 g_object_set (menuitem, "submenu", menu, NULL);
1332 gtk_widget_show_all (menuitem);
1339 create_edit_menu (PsppireDataWindow *dw)
1342 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1344 GtkWidget *menu = gtk_menu_new ();
1346 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1347 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1348 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1349 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1351 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1352 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1354 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1355 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1356 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1358 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1360 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1362 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1363 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1366 GtkAccelGroup *ag = gtk_accel_group_new ();
1368 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1369 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1371 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1372 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1373 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1375 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1376 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1377 'X', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1379 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1380 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1381 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1382 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1383 'C', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1385 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1386 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1387 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1388 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1389 'V', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1391 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1392 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1393 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1395 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1396 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1397 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1401 dw->mi_find_separator = gtk_separator_menu_item_new ();
1402 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1404 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1405 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1406 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1410 dw->mi_options = gtk_menu_item_new_with_mnemonic (_("_Options..."));
1411 g_signal_connect_swapped (dw->mi_options, "activate",
1412 G_CALLBACK (options_dialog), dw);
1413 gtk_menu_attach (GTK_MENU (menu), dw->mi_options, 0, 1, i, i + 1); ++i;
1416 g_object_set (menuitem, "submenu", menu, NULL);
1418 gtk_widget_show_all (menuitem);
1424 psppire_data_window_finish_init (PsppireDataWindow *de,
1427 static const struct dataset_callbacks cbs =
1429 set_unsaved, /* changed */
1430 transformation_change_callback, /* transformations_changed */
1437 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1440 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1441 de->data_store = psppire_data_store_new (de->dict);
1442 psppire_data_store_set_reader (de->data_store, NULL);
1444 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1445 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1446 gtk_widget_show (menubar);
1448 hb = gtk_toolbar_new ();
1449 sb = get_widget_assert (de->builder, "status-bar");
1452 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1454 g_signal_connect (de, "realize",
1455 G_CALLBACK (on_realize), de);
1457 g_signal_connect_swapped (de->data_store, "case-changed",
1458 G_CALLBACK (set_unsaved), de);
1460 dataset_set_callbacks (de->dataset, &cbs, de);
1462 connect_help (de->builder);
1464 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1465 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1466 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1467 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1469 gtk_container_add (GTK_CONTAINER (de), box);
1471 g_signal_connect (de->dict, "weight-changed",
1472 G_CALLBACK (on_weight_change),
1475 g_signal_connect (de->dict, "filter-changed",
1476 G_CALLBACK (on_filter_change),
1479 g_signal_connect (de->dict, "split-changed",
1480 G_CALLBACK (on_split_change),
1483 g_signal_connect_swapped (de->dict, "items-changed",
1484 G_CALLBACK (enable_save), de);
1485 g_signal_connect_swapped (de->dict, "variable-inserted",
1486 G_CALLBACK (enable_save), de);
1487 g_signal_connect_swapped (de->dict, "variable-deleted",
1488 G_CALLBACK (enable_save), de);
1491 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1492 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1493 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1494 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1495 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1497 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1498 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1499 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1500 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1501 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1502 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1503 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1506 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1507 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1508 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1509 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1511 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1512 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1514 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1515 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1517 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1518 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1519 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1520 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1521 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1522 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1523 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1524 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1525 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1527 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1528 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1530 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1531 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1532 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1534 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1535 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1536 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1537 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1538 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1539 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1540 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_INDEPENDENT, de);
1543 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1544 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1545 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1549 GSimpleAction *save = g_simple_action_new ("save", NULL);
1550 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1551 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1555 GSimpleAction *open = g_simple_action_new ("open", NULL);
1556 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1557 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1561 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1562 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1563 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1567 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1568 g_signal_connect_swapped (rename_dataset_act, "activate",
1569 G_CALLBACK (on_rename_dataset), de);
1570 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1574 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1575 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1576 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1579 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1580 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1581 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1585 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1586 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1587 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1591 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1592 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1593 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1598 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1599 g_variant_new_string ("DATA"));
1600 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1601 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1605 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1606 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1607 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1611 GSimpleAction *act_value_labels =
1612 g_simple_action_new_stateful ("value_labels", NULL,
1613 g_variant_new_boolean (FALSE));
1614 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1615 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1619 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1620 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1621 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1625 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1626 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1630 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1631 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1632 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1636 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1637 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1638 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1642 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1643 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1644 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1648 GSimpleAction *find = g_simple_action_new ("find", NULL);
1649 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1650 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1656 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1657 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1658 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1659 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1663 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1664 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1665 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1666 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1669 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1672 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1674 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1676 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1677 G_CALLBACK (psppire_dialog_action_activate_null), a);
1679 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1680 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1681 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1685 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1687 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1689 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1690 G_CALLBACK (g_action_activate_null), a);
1692 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1693 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1694 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1698 de->ti_find = gtk_tool_button_new (NULL, "Find");
1700 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1702 g_signal_connect_swapped (de->ti_find, "clicked",
1703 G_CALLBACK (g_action_activate_null), a);
1706 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1707 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1708 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1712 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1713 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1715 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1716 G_CALLBACK (g_action_activate_null), a);
1718 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1719 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1720 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1724 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1725 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1727 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1728 G_CALLBACK (g_action_activate_null), a);
1730 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1731 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1732 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1735 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1738 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1739 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1740 "PsppireDialogActionSplit");
1742 g_signal_connect_swapped (ti, "clicked",
1743 G_CALLBACK (psppire_dialog_action_activate_null), a);
1744 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1745 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1746 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1750 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1751 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1752 "PsppireDialogActionWeight");
1754 g_signal_connect_swapped (ti, "clicked",
1755 G_CALLBACK (psppire_dialog_action_activate_null), a);
1756 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1757 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1758 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1762 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1763 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1765 g_signal_connect (de->ti_value_labels_button, "toggled",
1766 G_CALLBACK (on_labels_button_toggle), de);
1767 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1768 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1769 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1774 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1775 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1777 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1778 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1779 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1780 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1782 g_signal_connect (de->data_editor, "switch-page",
1783 G_CALLBACK (on_switch_page), de);
1785 gtk_widget_show (GTK_WIDGET (de->data_editor));
1786 gtk_widget_show_all (box);
1788 ll_push_head (&all_data_windows, &de->ll);
1793 psppire_data_window_dispose (GObject *object)
1795 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1797 if (dw->builder != NULL)
1799 g_object_unref (dw->builder);
1805 g_signal_handlers_disconnect_by_func (dw->dict,
1806 G_CALLBACK (enable_save), dw);
1807 g_signal_handlers_disconnect_by_func (dw->dict,
1808 G_CALLBACK (on_weight_change), dw);
1809 g_signal_handlers_disconnect_by_func (dw->dict,
1810 G_CALLBACK (on_filter_change), dw);
1811 g_signal_handlers_disconnect_by_func (dw->dict,
1812 G_CALLBACK (on_split_change), dw);
1814 g_object_unref (dw->dict);
1820 g_object_unref (dw->data_store);
1821 dw->data_store = NULL;
1824 if (dw->ll.next != NULL)
1826 ll_remove (&dw->ll);
1830 if (G_OBJECT_CLASS (parent_class)->dispose)
1831 G_OBJECT_CLASS (parent_class)->dispose (object);
1835 psppire_data_window_finalize (GObject *object)
1837 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1841 struct dataset *dataset = dw->dataset;
1842 struct session *session = dataset_session (dataset);
1846 dataset_set_callbacks (dataset, NULL, NULL);
1847 session_set_active_dataset (session, NULL);
1848 dataset_destroy (dataset);
1851 if (G_OBJECT_CLASS (parent_class)->finalize)
1852 G_OBJECT_CLASS (parent_class)->finalize (object);
1856 psppire_data_window_set_property (GObject *object,
1858 const GValue *value,
1861 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1866 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1869 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1875 psppire_data_window_get_property (GObject *object,
1880 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1885 g_value_set_pointer (value, window->dataset);
1888 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1896 psppire_data_window_new (struct dataset *ds)
1900 if (the_session == NULL)
1901 the_session = session_create (NULL);
1905 char *dataset_name = session_generate_dataset_name (the_session);
1906 ds = dataset_create (the_session, dataset_name);
1907 free (dataset_name);
1909 assert (dataset_session (ds) == the_session);
1913 psppire_data_window_get_type (),
1914 "description", _("Data Editor"),
1918 if (dataset_name (ds) != NULL)
1919 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1922 GApplication *app = g_application_get_default ();
1923 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1931 psppire_data_window_is_empty (PsppireDataWindow *dw)
1933 return psppire_dict_get_var_cnt (dw->dict) == 0;
1938 psppire_data_window_iface_init (PsppireWindowIface *iface)
1940 iface->save = save_file;
1941 iface->pick_filename = data_pick_filename;
1942 iface->load = load_file;
1949 psppire_default_data_window (void)
1951 if (ll_is_empty (&all_data_windows))
1952 create_data_window ();
1953 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1959 psppire_data_window_set_default (PsppireDataWindow *pdw)
1961 ll_remove (&pdw->ll);
1962 ll_push_head (&all_data_windows, &pdw->ll);
1966 psppire_data_window_undefault (PsppireDataWindow *pdw)
1968 ll_remove (&pdw->ll);
1969 ll_push_tail (&all_data_windows, &pdw->ll);
1975 psppire_data_window_for_dataset (struct dataset *ds)
1977 PsppireDataWindow *pdw;
1979 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1980 if (pdw->dataset == ds)
1987 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1989 PsppireDataWindow *pdw;
1991 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1992 if (pdw->data_store == data_store)
1999 create_data_window (void)
2001 GtkWidget *w = psppire_data_window_new (NULL);
2003 gtk_widget_show (w);
2005 return GTK_WINDOW (w);
2009 open_data_window (PsppireWindow *victim, const char *file_name,
2010 const char *encoding, gpointer hint)
2014 if (PSPPIRE_IS_DATA_WINDOW (victim)
2015 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
2017 window = GTK_WIDGET (victim);
2018 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
2021 window = psppire_data_window_new (NULL);
2023 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
2024 gtk_widget_show_all (window);
2025 return GTK_WINDOW (window);