1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/dataset.h"
23 #include "data/session.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/message.h"
26 #include "libpspp/str.h"
27 #include "ui/gui/builder-wrapper.h"
28 #include "ui/gui/entry-dialog.h"
29 #include "ui/gui/executor.h"
30 #include "ui/gui/help-menu.h"
31 #include "ui/gui/helper.h"
32 #include "ui/gui/helper.h"
33 #include "ui/gui/psppire-import-assistant.h"
34 #include "ui/gui/psppire-data-window.h"
35 #include "ui/gui/psppire-dialog-action.h"
36 #include "ui/gui/psppire-encoding-selector.h"
37 #include "ui/gui/psppire-syntax-window.h"
38 #include "ui/gui/psppire-window.h"
39 #include "ui/gui/windows-menu.h"
40 #include "ui/gui/goto-case-dialog.h"
41 #include "ui/gui/psppire.h"
42 #include "ui/syntax-gen.h"
44 #include "gl/c-strcase.h"
45 #include "gl/c-strcasestr.h"
46 #include "gl/xvasprintf.h"
48 #include "ui/gui/efficient-sheet/jmd-sheet.h"
50 #include "find-dialog.h"
51 #include "psppire-dialog-action-1sks.h"
52 #include "psppire-dialog-action-aggregate.h"
53 #include "psppire-dialog-action-autorecode.h"
54 #include "psppire-dialog-action-barchart.h"
55 #include "psppire-dialog-action-binomial.h"
56 #include "psppire-dialog-action-chisquare.h"
57 #include "psppire-dialog-action-comments.h"
58 #include "psppire-dialog-action-compute.h"
59 #include "psppire-dialog-action-correlation.h"
60 #include "psppire-dialog-action-count.h"
61 #include "psppire-dialog-action-crosstabs.h"
62 #include "psppire-dialog-action-descriptives.h"
63 #include "psppire-dialog-action-examine.h"
64 #include "psppire-dialog-action-factor.h"
65 #include "psppire-dialog-action-flip.h"
66 #include "psppire-dialog-action-frequencies.h"
67 #include "psppire-dialog-action-histogram.h"
68 #include "psppire-dialog-action-indep-samps.h"
69 #include "psppire-dialog-action-k-related.h"
70 #include "psppire-dialog-action-kmeans.h"
71 #include "psppire-dialog-action-logistic.h"
72 #include "psppire-dialog-action-means.h"
73 #include "psppire-dialog-action-oneway.h"
74 #include "psppire-dialog-action-paired.h"
75 #include "psppire-dialog-action-rank.h"
76 #include "psppire-dialog-action-recode-same.h"
77 #include "psppire-dialog-action-recode-different.h"
78 #include "psppire-dialog-action-regression.h"
79 #include "psppire-dialog-action-reliability.h"
80 #include "psppire-dialog-action-roc.h"
81 #include "psppire-dialog-action-runs.h"
82 #include "psppire-dialog-action-scatterplot.h"
83 #include "psppire-dialog-action-select.h"
84 #include "psppire-dialog-action-sort.h"
85 #include "psppire-dialog-action-split.h"
86 #include "psppire-dialog-action-tt1s.h"
87 #include "psppire-dialog-action-two-sample.h"
88 #include "psppire-dialog-action-univariate.h"
89 #include "psppire-dialog-action-var-info.h"
90 #include "psppire-dialog-action-weight.h"
94 #define _(msgid) gettext (msgid)
95 #define N_(msgid) msgid
97 struct session *the_session;
98 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
100 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
101 static void psppire_data_window_init (PsppireDataWindow *data_editor);
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 psppire_data_window_get_type (void)
120 static GType psppire_data_window_type = 0;
122 if (!psppire_data_window_type)
124 static const GTypeInfo psppire_data_window_info =
126 sizeof (PsppireDataWindowClass),
129 (GClassInitFunc)psppire_data_window_class_init,
130 (GClassFinalizeFunc) NULL,
132 sizeof (PsppireDataWindow),
134 (GInstanceInitFunc) psppire_data_window_init,
137 static const GInterfaceInfo window_interface_info =
139 (GInterfaceInitFunc) psppire_data_window_iface_init,
144 psppire_data_window_type =
145 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
146 &psppire_data_window_info, 0);
149 g_type_add_interface_static (psppire_data_window_type,
150 PSPPIRE_TYPE_WINDOW_MODEL,
151 &window_interface_info);
154 return psppire_data_window_type;
157 static GObjectClass *parent_class ;
164 psppire_data_window_class_init (PsppireDataWindowClass *class)
166 GObjectClass *object_class = G_OBJECT_CLASS (class);
168 parent_class = g_type_class_peek_parent (class);
170 object_class->dispose = psppire_data_window_dispose;
171 object_class->finalize = psppire_data_window_finalize;
172 object_class->set_property = psppire_data_window_set_property;
173 object_class->get_property = psppire_data_window_get_property;
175 g_object_class_install_property (
176 object_class, PROP_DATASET,
177 g_param_spec_pointer ("dataset", "Dataset",
178 "'struct datset *' represented by the window",
179 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
184 /* Run the EXECUTE command. */
186 execute (PsppireDataWindow *dw)
188 execute_const_syntax_string (dw, "EXECUTE.");
192 transformation_change_callback (bool transformations_pending,
195 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
197 GtkWidget *status_label =
198 get_widget_assert (de->builder, "case-counter-area");
201 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de),
202 "transform-pending");
204 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
205 transformations_pending);
208 if ( transformations_pending)
209 gtk_label_set_text (GTK_LABEL (status_label),
210 _("Transformations Pending"));
212 gtk_label_set_text (GTK_LABEL (status_label), "");
215 /* Callback for when the dictionary changes its filter variable */
217 on_filter_change (GObject *o, gint filter_index, gpointer data)
219 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
221 GtkWidget *filter_status_area =
222 get_widget_assert (de->builder, "filter-use-status-area");
224 if ( filter_index == -1 )
226 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
230 PsppireDict *dict = NULL;
231 struct variable *var ;
234 g_object_get (de->data_editor, "dictionary", &dict, NULL);
236 var = psppire_dict_get_variable (dict, filter_index);
238 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
240 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
246 /* Callback for when the dictionary changes its split variables */
248 on_split_change (PsppireDict *dict, gpointer data)
250 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
252 size_t n_split_vars = dict_get_split_cnt (dict->dict);
254 GtkWidget *split_status_area =
255 get_widget_assert (de->builder, "split-file-status-area");
257 if ( n_split_vars == 0 )
259 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
265 const struct variable *const * split_vars =
266 dict_get_split_vars (dict->dict);
268 text = g_string_new (_("Split by "));
270 for (i = 0 ; i < n_split_vars - 1; ++i )
272 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
274 g_string_append (text, var_get_name (split_vars[i]));
276 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
278 g_string_free (text, TRUE);
285 /* Callback for when the dictionary changes its weights */
287 on_weight_change (GObject *o, gint weight_index, gpointer data)
289 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
291 GtkWidget *weight_status_area =
292 get_widget_assert (de->builder, "weight-status-area");
294 if ( weight_index == -1 )
296 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
300 struct variable *var ;
301 PsppireDict *dict = NULL;
304 g_object_get (de->data_editor, "dictionary", &dict, NULL);
306 var = psppire_dict_get_variable (dict, weight_index);
308 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
310 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
318 dump_rm (GtkRecentManager *rm)
320 GList *items = gtk_recent_manager_get_items (rm);
324 g_print ("Recent Items:\n");
325 for (i = items; i; i = i->next)
327 GtkRecentInfo *ri = i->data;
329 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
330 gtk_recent_info_get_short_name (ri),
331 gtk_recent_info_get_mime_type (ri),
332 gtk_recent_info_get_description (ri),
333 gtk_recent_info_get_uri (ri)
337 gtk_recent_info_unref (ri);
345 has_suffix (const gchar *name, const gchar *suffix)
347 size_t name_len = strlen (name);
348 size_t suffix_len = strlen (suffix);
349 return (name_len > suffix_len
350 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
354 name_has_por_suffix (const gchar *name)
356 return has_suffix (name, ".por");
360 name_has_sav_suffix (const gchar *name)
362 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
365 /* Returns true if NAME has a suffix which might denote a PSPP file */
367 name_has_suffix (const gchar *name)
369 return name_has_por_suffix (name) || name_has_sav_suffix (name);
373 load_file (PsppireWindow *de, const gchar *file_name, const char *encoding,
376 const char *mime_type = NULL;
377 gchar *syntax = NULL;
382 gchar *utf8_file_name;
383 struct string filename;
385 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
387 if (NULL == utf8_file_name)
390 ds_init_empty (&filename);
391 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
393 g_free (utf8_file_name);
395 if (encoding && encoding[0])
396 syntax = g_strdup_printf ("GET FILE=%s ENCODING='%s'.",
397 ds_cstr (&filename), encoding);
399 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
400 ds_destroy (&filename);
407 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
408 lex_reader_for_string (syntax, "UTF-8"));
411 if (ok && syn == NULL)
413 if (name_has_por_suffix (file_name))
414 mime_type = "application/x-spss-por";
415 else if (name_has_sav_suffix (file_name))
416 mime_type = "application/x-spss-sav";
418 add_most_recent (file_name, mime_type, encoding);
425 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
427 if (format == PSPPIRE_DATA_WINDOW_SAV)
429 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
435 /* Save DE to file */
437 save_file (PsppireWindow *w)
439 const gchar *file_name = NULL;
440 gchar *utf8_file_name = NULL;
442 struct string filename ;
443 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
446 file_name = psppire_window_get_filename (w);
448 fnx = g_string_new (file_name);
450 if ( ! name_has_suffix (fnx->str))
451 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
453 ds_init_empty (&filename);
455 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
457 g_string_free (fnx, TRUE);
459 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
460 g_free (utf8_file_name);
462 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
463 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
464 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
465 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
466 ds_cstr (&filename));
468 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
470 ds_destroy (&filename);
472 g_free (execute_syntax_string (de, syntax));
477 display_dict (PsppireDataWindow *de)
479 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
483 sysfile_info (PsppireDataWindow *de)
485 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
487 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
489 struct string filename;
491 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
492 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
495 const gchar *encoding = psppire_encoding_selector_get_encoding (
496 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
500 ds_init_empty (&filename);
502 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
504 g_free (utf8_file_name);
507 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
508 ds_cstr (&filename), encoding);
510 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
511 g_free (execute_syntax_string (de, syntax));
514 gtk_widget_destroy (dialog);
518 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
520 data_pick_filename (PsppireWindow *window)
522 GtkListStore *list_store;
523 GtkWidget *combo_box;
525 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
526 GtkFileFilter *filter;
528 gtk_file_chooser_dialog_new (_("Save"),
530 GTK_FILE_CHOOSER_ACTION_SAVE,
531 _("Cancel"), GTK_RESPONSE_CANCEL,
532 _("Save"), GTK_RESPONSE_ACCEPT,
535 g_object_set (dialog, "local-only", FALSE, NULL);
537 filter = gtk_file_filter_new ();
538 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
539 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
540 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
542 filter = gtk_file_filter_new ();
543 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
544 gtk_file_filter_add_pattern (filter, "*.zsav");
545 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
547 filter = gtk_file_filter_new ();
548 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
549 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
550 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
552 filter = gtk_file_filter_new ();
553 gtk_file_filter_set_name (filter, _("All Files"));
554 gtk_file_filter_add_pattern (filter, "*");
555 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
556 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
559 GtkCellRenderer *cell;
564 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
565 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
567 gtk_list_store_append (list_store, &iter);
568 gtk_list_store_set (list_store, &iter,
569 0, PSPPIRE_DATA_WINDOW_SAV,
572 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
574 gtk_list_store_append (list_store, &iter);
575 gtk_list_store_set (list_store, &iter,
576 0, PSPPIRE_DATA_WINDOW_ZSAV,
577 1, _("Compressed System File"),
580 gtk_list_store_append (list_store, &iter);
581 gtk_list_store_set (list_store, &iter,
582 0, PSPPIRE_DATA_WINDOW_POR,
583 1, _("Portable File"),
586 label = gtk_label_new (_("Format:"));
588 cell = gtk_cell_renderer_text_new ();
589 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
590 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
593 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
594 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
595 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
596 gtk_widget_show_all (hbox);
598 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
601 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
604 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
606 case GTK_RESPONSE_ACCEPT:
611 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
617 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
618 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
623 if ( ! name_has_suffix (filename->str))
624 g_string_append (filename,
625 psppire_data_window_format_to_string (format));
627 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
629 g_string_free (filename, TRUE);
636 gtk_widget_destroy (dialog);
640 confirm_delete_dataset (PsppireDataWindow *de,
641 const char *old_dataset,
642 const char *new_dataset,
643 const char *existing_dataset)
648 dialog = gtk_message_dialog_new (
649 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
650 _("Delete Existing Dataset?"));
652 gtk_message_dialog_format_secondary_text (
653 GTK_MESSAGE_DIALOG (dialog),
654 _("Renaming \"%s\" to \"%s\" will destroy the existing "
655 "dataset named \"%s\". Are you sure that you want to do this?"),
656 old_dataset, new_dataset, existing_dataset);
658 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
659 _("Cancel"), GTK_RESPONSE_CANCEL,
660 _("Delete"), GTK_RESPONSE_OK,
663 g_object_set (dialog, "icon-name", "pspp", NULL);
665 result = gtk_dialog_run (GTK_DIALOG (dialog));
667 gtk_widget_destroy (dialog);
669 return result == GTK_RESPONSE_OK;
673 on_rename_dataset (PsppireDataWindow *de)
675 struct dataset *ds = de->dataset;
676 struct session *session = dataset_session (ds);
677 const char *old_name = dataset_name (ds);
678 struct dataset *existing_dataset;
682 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
684 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
688 if (new_name == NULL)
691 existing_dataset = session_lookup_dataset (session, new_name);
692 if (existing_dataset == NULL || existing_dataset == ds
693 || confirm_delete_dataset (de, old_name, new_name,
694 dataset_name (existing_dataset)))
695 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
703 status_bar_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
705 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
707 GVariant *state = g_action_get_state (action);
708 const gboolean visible = g_variant_get_boolean (state);
709 g_action_change_state (action, g_variant_new_boolean (!visible));
711 gtk_widget_set_visible (statusbar, !visible);
716 grid_lines_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
718 GVariant *state = g_action_get_state (action);
719 const gboolean grid_visible = g_variant_get_boolean (state);
720 g_action_change_state (action, g_variant_new_boolean (!grid_visible));
722 psppire_data_editor_show_grid (de->data_editor, !grid_visible);
727 on_switch_page (GtkNotebook *notebook, GtkWidget *page, guint pn, gpointer ud)
729 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (ud);
731 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de), "view_dv");
736 g_action_change_state (action, g_variant_new_string ("DATA"));
737 gtk_widget_show (GTK_WIDGET (de->ti_insert_case));
738 gtk_widget_show (GTK_WIDGET (de->ti_jump_to_case));
739 gtk_widget_show (GTK_WIDGET (de->ti_find));
741 gtk_widget_show (GTK_WIDGET (de->mi_go_to_case));
742 gtk_widget_show (GTK_WIDGET (de->mi_insert_case));
743 gtk_widget_show (GTK_WIDGET (de->mi_find));
744 gtk_widget_show (GTK_WIDGET (de->mi_find_separator));
745 gtk_widget_show (GTK_WIDGET (de->mi_clear_cases));
750 g_action_change_state (action, g_variant_new_string ("VARS"));
751 gtk_widget_hide (GTK_WIDGET (de->ti_insert_case));
752 gtk_widget_hide (GTK_WIDGET (de->ti_jump_to_case));
753 gtk_widget_hide (GTK_WIDGET (de->ti_find));
755 gtk_widget_hide (GTK_WIDGET (de->mi_go_to_case));
756 gtk_widget_hide (GTK_WIDGET (de->mi_insert_case));
757 gtk_widget_hide (GTK_WIDGET (de->mi_find));
758 gtk_widget_hide (GTK_WIDGET (de->mi_find_separator));
759 gtk_widget_hide (GTK_WIDGET (de->mi_clear_cases));
767 activate_change_view (GAction *action, GVariant *param, PsppireDataWindow *de)
769 g_action_change_state (action, param);
770 GVariant *new_state = g_action_get_state (action);
772 const gchar *what = g_variant_get_string (new_state, NULL);
773 if (0 == g_strcmp0 (what, "DATA"))
775 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
777 else if (0 == g_strcmp0 (what, "VARS"))
779 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
786 fonts_activate (PsppireDataWindow *de)
788 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
789 GtkWidget *dialog = gtk_font_chooser_dialog_new (NULL, GTK_WINDOW (toplevel));
790 GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET(de->data_editor));
791 const PangoFontDescription *current_font ;
793 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, "font", ¤t_font, NULL);
795 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (dialog), current_font);
797 gtk_window_set_transient_for (GTK_WINDOW (dialog),
798 GTK_WINDOW (toplevel));
800 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
802 PangoFontDescription* font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog));
804 psppire_data_editor_set_font (de->data_editor, font_desc);
807 gtk_widget_hide (dialog);
812 /* Callback for the value labels action */
815 value_labels_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
817 GVariant *v = g_action_get_state (action);
818 gboolean labels_active = g_variant_get_boolean (v);
819 g_action_change_state (action, g_variant_new_boolean (!labels_active));
821 GVariant *new_state = g_action_get_state (action);
822 labels_active = g_variant_get_boolean (new_state);
823 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
825 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (de->ti_value_labels_button),
830 on_labels_button_toggle (GtkToggleToolButton *ttb, PsppireDataWindow *de)
832 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "value_labels");
834 gboolean labels_active = gtk_toggle_tool_button_get_active (ttb);
836 g_action_change_state (a, g_variant_new_boolean (labels_active));
838 GVariant *new_state = g_action_get_state (a);
839 labels_active = g_variant_get_boolean (new_state);
840 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
844 on_recent_data_select (GtkMenuShell *menushell,
845 PsppireWindow *window)
850 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
852 file = g_filename_from_uri (uri, NULL, NULL);
856 open_data_window (window, file, NULL, NULL);
862 charset_from_mime_type (const char *mime_type)
868 if (mime_type == NULL)
871 charset = c_strcasestr (mime_type, "charset=");
879 /* Parse a "quoted-string" as defined by RFC 822. */
880 for (p++; *p != '\0' && *p != '"'; p++)
883 ds_put_byte (&s, *p);
884 else if (*++p != '\0')
885 ds_put_byte (&s, *p);
890 /* Parse a "token" as defined by RFC 2045. */
891 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
892 ds_put_byte (&s, *p++);
894 if (!ds_is_empty (&s))
895 return ds_steal_cstr (&s);
902 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
909 /* Get the file name and its encoding. */
910 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
911 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
912 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
913 gtk_recent_info_unref (item);
915 se = psppire_syntax_window_new (encoding);
919 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
920 gtk_widget_show (se);
922 gtk_widget_destroy (se);
928 set_unsaved (gpointer w)
930 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
934 /* Only a data file with at least one variable can be saved. */
936 enable_save (PsppireDataWindow *dw)
938 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
940 GAction *save_as = g_action_map_lookup_action (G_ACTION_MAP (dw), "save-as");
941 GAction *save = g_action_map_lookup_action (G_ACTION_MAP (dw), "save");
944 g_object_set (save, "enabled", enable, NULL);
947 g_object_set (save_as, "enabled", enable, NULL);
950 /* Initializes as much of a PsppireDataWindow as we can and must before the
951 dataset has been set.
953 In particular, the 'menu' member is required in case the "filename" property
954 is set before the "dataset" property: otherwise PsppireWindow will try to
955 modify the menu as part of the "filename" property_set() function and end up
956 with a Gtk-CRITICAL since 'menu' is NULL. */
958 psppire_data_window_init (PsppireDataWindow *de)
960 de->builder = builder_new ("data-editor.ui");
964 file_import (PsppireDataWindow *dw)
966 GtkWidget *w = psppire_import_assistant_new (GTK_WINDOW (dw));
967 PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
968 gtk_widget_show_all (w);
970 asst->main_loop = g_main_loop_new (NULL, TRUE);
971 g_main_loop_run (asst->main_loop);
972 g_main_loop_unref (asst->main_loop);
974 if (!asst->file_name)
977 switch (asst->response)
979 case GTK_RESPONSE_APPLY:
981 gchar *fn = g_path_get_basename (asst->file_name);
982 open_data_window (PSPPIRE_WINDOW (dw), fn, NULL, psppire_import_assistant_generate_syntax (asst));
986 case PSPPIRE_RESPONSE_PASTE:
987 free (paste_syntax_to_window (psppire_import_assistant_generate_syntax (asst)));
994 gtk_widget_destroy (GTK_WIDGET (asst));
1000 connect_dialog_action (GType type, PsppireDataWindow *de)
1002 GAction *act = g_object_new (type,
1006 g_action_map_add_action (G_ACTION_MAP (de), act);
1010 g_action_activate_null (GAction *a)
1012 g_action_activate (a, NULL);
1016 connect_action_to_menuitem (GActionMap *map, const gchar *action_name, GtkWidget *w, const gchar *accel)
1018 GAction *a = g_action_map_lookup_action (map, action_name);
1021 g_error ("Action \"%s\" not found in map", action_name);
1025 GtkApplication *app = GTK_APPLICATION (g_application_get_default());
1027 /* First set the label for the accellerator so that it appears
1029 GtkWidget *child = gtk_bin_get_child (GTK_BIN (w));
1031 GdkModifierType modifier;
1032 gtk_accelerator_parse (accel, &key, &modifier);
1033 gtk_accel_label_set_accel (GTK_ACCEL_LABEL (child), key, modifier);
1035 /* Now tell the application that it must do something when that
1036 key combination is pressed */
1037 const gchar *accels[2];
1041 gchar *detailed_action_name = NULL;
1042 if (GTK_IS_WINDOW (map))
1043 detailed_action_name = g_strdup_printf ("win.%s", action_name);
1044 else if (GTK_IS_APPLICATION (map))
1045 detailed_action_name = g_strdup_printf ("app.%s", action_name);
1047 gtk_application_set_accels_for_action (app,
1048 detailed_action_name,
1050 free (detailed_action_name);
1053 g_signal_connect_swapped (w, "activate", G_CALLBACK (g_action_activate_null), a);
1058 set_data_page (PsppireDataWindow *dw)
1060 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 1);
1061 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 0);
1066 on_cut (PsppireDataWindow *dw)
1068 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1071 PsppireDict *dict = NULL;
1072 g_object_get (dw->data_editor, "dictionary", &dict, NULL);
1075 JmdSheet *sheet = JMD_SHEET (dw->data_editor->data_sheet);
1076 JmdRange sel = *sheet->selection;
1078 GtkClipboard *clip =
1079 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1080 GDK_SELECTION_CLIPBOARD);
1082 /* Save the selected area to a string */
1083 GString *str = g_string_new ("");
1084 for (y = sel.start_y ; y <= sel.end_y; ++y)
1086 for (x = sel.start_x ; x <= sel.end_x; ++x)
1088 const struct variable * var = psppire_dict_get_variable (dict, x);
1089 gchar *s = psppire_data_store_get_string (dw->data_editor->data_store,
1091 g_string_append (str, s);
1092 g_string_append (str, "\t");
1095 g_string_append (str, "\n");
1098 gtk_clipboard_set_text (clip, str->str, str->len);
1099 g_string_free (str, TRUE);
1101 /* Now fill the selected area with SYSMIS */
1104 for (x = sel.start_x ; x <= sel.end_x; ++x)
1106 const struct variable * var = psppire_dict_get_variable (dict, x);
1107 for (y = sel.start_y ; y <= sel.end_y; ++y)
1109 psppire_data_store_set_value (dw->data_editor->data_store,
1121 on_copy (PsppireDataWindow *dw)
1123 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1126 GtkClipboard *clip =
1127 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1128 GDK_SELECTION_CLIPBOARD);
1130 jmd_sheet_set_clip (JMD_SHEET (dw->data_editor->data_sheet), clip);
1136 trf (GtkClipboard *clip,
1142 for (i = 0; i < n_atoms; ++i)
1144 g_print ("%s\n", gdk_atom_name (atoms[i]));
1149 on_paste (PsppireDataWindow *dw)
1151 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1154 GtkClipboard *clip =
1155 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1156 GDK_SELECTION_CLIPBOARD);
1158 gtk_clipboard_request_targets (clip, trf, dw);
1164 on_clear_cases (PsppireDataWindow *dw)
1167 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1170 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1171 psppire_data_sheet_edit_clear_cases (ds);
1177 on_clear_variables (PsppireDataWindow *dw)
1180 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1183 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1184 psppire_data_sheet_edit_clear_variables (ds);
1188 psppire_var_sheet_clear_variables (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1196 insert_variable (PsppireDataWindow *dw)
1199 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1202 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1203 psppire_data_sheet_insert_variable (ds);
1207 psppire_var_sheet_insert_variable (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1215 insert_case_at_row (PsppireDataWindow *dw)
1218 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1220 psppire_data_sheet_insert_case (ds);
1227 goto_case (PsppireDataWindow *dw)
1230 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1232 goto_case_dialog (ds);
1238 create_file_menu (PsppireDataWindow *dw)
1240 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1241 GtkWidget *menu = gtk_menu_new ();
1244 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1245 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1247 GtkWidget *new_menu = gtk_menu_new ();
1249 g_object_set (new, "submenu", new_menu, NULL);
1251 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1252 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1254 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1255 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1257 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1258 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1261 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1262 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Ctrl>O");
1264 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1265 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1267 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1268 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1270 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1272 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1273 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Ctrl>S");
1275 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1276 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Ctrl>S");
1278 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1279 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1282 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1283 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1284 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1286 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1289 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1290 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1292 GtkWidget *dd_menu = gtk_menu_new ();
1294 g_object_set (display_data, "submenu", dd_menu, NULL);
1296 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1297 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1298 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1299 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1301 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1302 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1305 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1308 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1309 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1311 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1312 gtk_recent_manager_get_default ());
1314 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1315 gtk_recent_manager_get_default ());
1317 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1318 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1320 g_object_set (menu_data, "show-tips", TRUE, NULL);
1321 g_object_set (menu_files, "show-tips", TRUE, NULL);
1323 g_object_set (mi_data, "submenu", menu_data, NULL);
1324 g_object_set (mi_files, "submenu", menu_files, NULL);
1327 GtkRecentFilter *filter = gtk_recent_filter_new ();
1329 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1330 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1332 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1334 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1337 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1340 GtkRecentFilter *filter = gtk_recent_filter_new ();
1342 gtk_recent_filter_add_pattern (filter, "*.sps");
1343 gtk_recent_filter_add_pattern (filter, "*.SPS");
1345 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1347 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1350 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1353 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1356 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1357 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1359 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1360 "quit", quit, "<Ctrl>Q");
1363 g_object_set (menuitem, "submenu", menu, NULL);
1364 gtk_widget_show_all (menuitem);
1371 create_edit_menu (PsppireDataWindow *dw)
1374 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1376 GtkWidget *menu = gtk_menu_new ();
1378 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1379 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1380 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1381 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1383 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1384 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1386 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1387 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1388 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1390 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1392 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1394 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1395 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1398 GtkAccelGroup *ag = gtk_accel_group_new ();
1400 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1401 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1403 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1404 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1405 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1407 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1408 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1409 'X', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1411 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1412 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1413 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1414 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1415 'C', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1417 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1418 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1419 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1420 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1421 'V', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1423 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1424 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1425 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1427 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1428 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1429 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1433 dw->mi_find_separator = gtk_separator_menu_item_new ();
1434 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1436 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1437 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1438 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1441 g_object_set (menuitem, "submenu", menu, NULL);
1443 gtk_widget_show_all (menuitem);
1449 psppire_data_window_finish_init (PsppireDataWindow *de,
1452 static const struct dataset_callbacks cbs =
1454 set_unsaved, /* changed */
1455 transformation_change_callback, /* transformations_changed */
1462 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1465 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1466 de->data_store = psppire_data_store_new (de->dict);
1467 psppire_data_store_set_reader (de->data_store, NULL);
1469 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1470 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1471 gtk_widget_show (menubar);
1473 hb = gtk_toolbar_new ();
1474 sb = get_widget_assert (de->builder, "status-bar");
1477 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1479 g_signal_connect (de, "realize",
1480 G_CALLBACK (set_data_page), de);
1482 g_signal_connect_swapped (de->data_store, "case-changed",
1483 G_CALLBACK (set_unsaved), de);
1485 g_signal_connect_swapped (de->data_store, "case-inserted",
1486 G_CALLBACK (set_unsaved), de);
1488 g_signal_connect_swapped (de->data_store, "cases-deleted",
1489 G_CALLBACK (set_unsaved), de);
1491 dataset_set_callbacks (de->dataset, &cbs, de);
1493 connect_help (de->builder);
1495 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1496 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1497 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1498 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1500 gtk_container_add (GTK_CONTAINER (de), box);
1502 g_signal_connect (de->dict, "weight-changed",
1503 G_CALLBACK (on_weight_change),
1506 g_signal_connect (de->dict, "filter-changed",
1507 G_CALLBACK (on_filter_change),
1510 g_signal_connect (de->dict, "split-changed",
1511 G_CALLBACK (on_split_change),
1514 g_signal_connect_swapped (de->dict, "changed",
1515 G_CALLBACK (enable_save), de);
1516 g_signal_connect_swapped (de->dict, "variable-inserted",
1517 G_CALLBACK (enable_save), de);
1518 g_signal_connect_swapped (de->dict, "variable-deleted",
1519 G_CALLBACK (enable_save), de);
1522 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1523 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1524 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1525 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1526 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1528 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1529 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1530 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1531 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1532 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1533 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1534 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1537 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1538 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1539 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1540 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1542 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1543 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1545 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1546 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1548 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1549 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1550 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1551 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1552 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1553 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1554 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1555 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1556 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1558 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1559 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1561 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1562 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1563 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1565 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1566 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1567 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1568 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1569 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1570 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1573 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1574 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1575 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1579 GSimpleAction *save = g_simple_action_new ("save", NULL);
1580 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1581 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1585 GSimpleAction *open = g_simple_action_new ("open", NULL);
1586 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1587 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1591 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1592 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1593 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1597 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1598 g_signal_connect_swapped (rename_dataset_act, "activate",
1599 G_CALLBACK (on_rename_dataset), de);
1600 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1604 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1605 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1606 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1609 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1610 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1611 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1615 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1616 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1617 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1621 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1622 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1623 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1628 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1629 g_variant_new_string ("DATA"));
1630 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1631 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1635 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1636 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1637 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1641 GSimpleAction *act_value_labels =
1642 g_simple_action_new_stateful ("value_labels", NULL,
1643 g_variant_new_boolean (FALSE));
1644 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1645 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1649 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1650 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1651 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1655 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1656 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1660 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1661 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1662 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1666 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1667 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1668 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1672 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1673 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1674 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1678 GSimpleAction *find = g_simple_action_new ("find", NULL);
1679 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1680 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1686 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1687 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1688 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1689 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1693 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1694 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1695 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1696 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1699 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1702 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1704 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1706 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1707 G_CALLBACK (psppire_dialog_action_activate_null), a);
1709 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1710 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1711 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1715 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1717 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1719 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1720 G_CALLBACK (g_action_activate_null), a);
1722 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1723 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1724 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1728 de->ti_find = gtk_tool_button_new (NULL, "Find");
1730 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1732 g_signal_connect_swapped (de->ti_find, "clicked",
1733 G_CALLBACK (g_action_activate_null), a);
1736 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1737 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1738 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1742 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1743 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1745 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1746 G_CALLBACK (g_action_activate_null), a);
1748 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1749 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1750 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1754 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1755 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1757 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1758 G_CALLBACK (g_action_activate_null), a);
1760 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1761 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1762 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1765 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1768 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1769 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1770 "PsppireDialogActionSplit");
1772 g_signal_connect_swapped (ti, "clicked",
1773 G_CALLBACK (psppire_dialog_action_activate_null), a);
1774 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1775 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1776 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1780 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1781 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1782 "PsppireDialogActionWeight");
1784 g_signal_connect_swapped (ti, "clicked",
1785 G_CALLBACK (psppire_dialog_action_activate_null), a);
1786 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1787 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1788 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1792 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1793 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1795 g_signal_connect (de->ti_value_labels_button, "toggled",
1796 G_CALLBACK (on_labels_button_toggle), de);
1797 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1798 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1799 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1804 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1805 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1807 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1808 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1809 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1810 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1812 g_signal_connect (de->data_editor, "switch-page",
1813 G_CALLBACK (on_switch_page), de);
1815 gtk_widget_show (GTK_WIDGET (de->data_editor));
1816 gtk_widget_show_all (box);
1818 ll_push_head (&all_data_windows, &de->ll);
1823 psppire_data_window_dispose (GObject *object)
1825 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1827 if (dw->builder != NULL)
1829 g_object_unref (dw->builder);
1835 g_signal_handlers_disconnect_by_func (dw->dict,
1836 G_CALLBACK (enable_save), dw);
1837 g_signal_handlers_disconnect_by_func (dw->dict,
1838 G_CALLBACK (on_weight_change), dw);
1839 g_signal_handlers_disconnect_by_func (dw->dict,
1840 G_CALLBACK (on_filter_change), dw);
1841 g_signal_handlers_disconnect_by_func (dw->dict,
1842 G_CALLBACK (on_split_change), dw);
1844 g_object_unref (dw->dict);
1850 g_object_unref (dw->data_store);
1851 dw->data_store = NULL;
1854 if (dw->ll.next != NULL)
1856 ll_remove (&dw->ll);
1860 if (G_OBJECT_CLASS (parent_class)->dispose)
1861 G_OBJECT_CLASS (parent_class)->dispose (object);
1865 psppire_data_window_finalize (GObject *object)
1867 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1871 struct dataset *dataset = dw->dataset;
1872 struct session *session = dataset_session (dataset);
1876 dataset_set_callbacks (dataset, NULL, NULL);
1877 session_set_active_dataset (session, NULL);
1878 dataset_destroy (dataset);
1881 if (G_OBJECT_CLASS (parent_class)->finalize)
1882 G_OBJECT_CLASS (parent_class)->finalize (object);
1886 psppire_data_window_set_property (GObject *object,
1888 const GValue *value,
1891 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1896 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1899 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1905 psppire_data_window_get_property (GObject *object,
1910 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1915 g_value_set_pointer (value, window->dataset);
1918 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1926 psppire_data_window_new (struct dataset *ds)
1930 if (the_session == NULL)
1931 the_session = session_create (NULL);
1935 char *dataset_name = session_generate_dataset_name (the_session);
1936 ds = dataset_create (the_session, dataset_name);
1937 free (dataset_name);
1939 assert (dataset_session (ds) == the_session);
1943 psppire_data_window_get_type (),
1944 "description", _("Data Editor"),
1948 if (dataset_name (ds) != NULL)
1949 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1952 GApplication *app = g_application_get_default ();
1953 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1961 psppire_data_window_is_empty (PsppireDataWindow *dw)
1963 return psppire_dict_get_var_cnt (dw->dict) == 0;
1968 psppire_data_window_iface_init (PsppireWindowIface *iface)
1970 iface->save = save_file;
1971 iface->pick_filename = data_pick_filename;
1972 iface->load = load_file;
1979 psppire_default_data_window (void)
1981 if (ll_is_empty (&all_data_windows))
1982 create_data_window ();
1983 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1989 psppire_data_window_set_default (PsppireDataWindow *pdw)
1991 ll_remove (&pdw->ll);
1992 ll_push_head (&all_data_windows, &pdw->ll);
1996 psppire_data_window_undefault (PsppireDataWindow *pdw)
1998 ll_remove (&pdw->ll);
1999 ll_push_tail (&all_data_windows, &pdw->ll);
2005 psppire_data_window_for_dataset (struct dataset *ds)
2007 PsppireDataWindow *pdw;
2009 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2010 if (pdw->dataset == ds)
2019 psppire_data_window_for_data_store (PsppireDataStore *data_store)
2021 PsppireDataWindow *pdw;
2023 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2024 if (pdw->data_store == data_store)
2033 create_data_window (void)
2035 GtkWidget *w = psppire_data_window_new (NULL);
2037 gtk_widget_show (w);
2039 return GTK_WINDOW (w);
2045 open_data_window (PsppireWindow *victim, const char *file_name,
2046 const char *encoding, gpointer hint)
2050 if (PSPPIRE_IS_DATA_WINDOW (victim)
2051 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
2053 window = GTK_WIDGET (victim);
2054 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
2057 window = psppire_data_window_new (NULL);
2059 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
2060 gtk_widget_show_all (window);