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 = gtk_style_context_get_font (style, GTK_STATE_FLAG_NORMAL);
793 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (dialog), current_font);
795 gtk_window_set_transient_for (GTK_WINDOW (dialog),
796 GTK_WINDOW (toplevel));
798 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
800 PangoFontDescription* font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog));
802 psppire_data_editor_set_font (de->data_editor, font_desc);
805 gtk_widget_hide (dialog);
810 /* Callback for the value labels action */
813 value_labels_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
815 GVariant *v = g_action_get_state (action);
816 gboolean labels_active = g_variant_get_boolean (v);
817 g_action_change_state (action, g_variant_new_boolean (!labels_active));
819 GVariant *new_state = g_action_get_state (action);
820 labels_active = g_variant_get_boolean (new_state);
821 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
823 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (de->ti_value_labels_button),
828 on_labels_button_toggle (GtkToggleToolButton *ttb, PsppireDataWindow *de)
830 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "value_labels");
832 gboolean labels_active = gtk_toggle_tool_button_get_active (ttb);
834 g_action_change_state (a, g_variant_new_boolean (labels_active));
836 GVariant *new_state = g_action_get_state (a);
837 labels_active = g_variant_get_boolean (new_state);
838 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
842 on_recent_data_select (GtkMenuShell *menushell,
843 PsppireWindow *window)
848 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
850 file = g_filename_from_uri (uri, NULL, NULL);
854 open_data_window (window, file, NULL, NULL);
860 charset_from_mime_type (const char *mime_type)
866 if (mime_type == NULL)
869 charset = c_strcasestr (mime_type, "charset=");
877 /* Parse a "quoted-string" as defined by RFC 822. */
878 for (p++; *p != '\0' && *p != '"'; p++)
881 ds_put_byte (&s, *p);
882 else if (*++p != '\0')
883 ds_put_byte (&s, *p);
888 /* Parse a "token" as defined by RFC 2045. */
889 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
890 ds_put_byte (&s, *p++);
892 if (!ds_is_empty (&s))
893 return ds_steal_cstr (&s);
900 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
907 /* Get the file name and its encoding. */
908 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
909 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
910 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
911 gtk_recent_info_unref (item);
913 se = psppire_syntax_window_new (encoding);
917 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
918 gtk_widget_show (se);
920 gtk_widget_destroy (se);
926 set_unsaved (gpointer w)
928 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
932 /* Only a data file with at least one variable can be saved. */
934 enable_save (PsppireDataWindow *dw)
936 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
938 GAction *save_as = g_action_map_lookup_action (G_ACTION_MAP (dw), "save-as");
939 GAction *save = g_action_map_lookup_action (G_ACTION_MAP (dw), "save");
942 g_object_set (save, "enabled", enable, NULL);
945 g_object_set (save_as, "enabled", enable, NULL);
948 /* Initializes as much of a PsppireDataWindow as we can and must before the
949 dataset has been set.
951 In particular, the 'menu' member is required in case the "filename" property
952 is set before the "dataset" property: otherwise PsppireWindow will try to
953 modify the menu as part of the "filename" property_set() function and end up
954 with a Gtk-CRITICAL since 'menu' is NULL. */
956 psppire_data_window_init (PsppireDataWindow *de)
958 de->builder = builder_new ("data-editor.ui");
962 file_import (PsppireDataWindow *dw)
964 GtkWidget *w = psppire_import_assistant_new (GTK_WINDOW (dw));
965 PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
966 gtk_widget_show_all (w);
968 asst->main_loop = g_main_loop_new (NULL, TRUE);
969 g_main_loop_run (asst->main_loop);
970 g_main_loop_unref (asst->main_loop);
972 if (!asst->file_name)
975 switch (asst->response)
977 case GTK_RESPONSE_APPLY:
979 gchar *fn = g_path_get_basename (asst->file_name);
980 open_data_window (PSPPIRE_WINDOW (dw), fn, NULL, psppire_import_assistant_generate_syntax (asst));
984 case PSPPIRE_RESPONSE_PASTE:
985 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 set_data_page (PsppireDataWindow *dw)
1058 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 1);
1059 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 0);
1064 on_cut (PsppireDataWindow *dw)
1066 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1069 PsppireDict *dict = NULL;
1070 g_object_get (dw->data_editor, "dictionary", &dict, NULL);
1073 JmdSheet *sheet = JMD_SHEET (dw->data_editor->data_sheet);
1074 JmdRange sel = *sheet->selection;
1076 GtkClipboard *clip =
1077 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1078 GDK_SELECTION_CLIPBOARD);
1080 /* Save the selected area to a string */
1081 GString *str = g_string_new ("");
1082 for (y = sel.start_y ; y <= sel.end_y; ++y)
1084 for (x = sel.start_x ; x <= sel.end_x; ++x)
1086 const struct variable * var = psppire_dict_get_variable (dict, x);
1087 gchar *s = psppire_data_store_get_string (dw->data_editor->data_store,
1089 g_string_append (str, s);
1090 g_string_append (str, "\t");
1093 g_string_append (str, "\n");
1096 gtk_clipboard_set_text (clip, str->str, str->len);
1097 g_string_free (str, TRUE);
1099 /* Now fill the selected area with SYSMIS */
1102 for (x = sel.start_x ; x <= sel.end_x; ++x)
1104 const struct variable * var = psppire_dict_get_variable (dict, x);
1105 for (y = sel.start_y ; y <= sel.end_y; ++y)
1107 psppire_data_store_set_value (dw->data_editor->data_store,
1119 on_copy (PsppireDataWindow *dw)
1121 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1124 GtkClipboard *clip =
1125 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1126 GDK_SELECTION_CLIPBOARD);
1128 jmd_sheet_set_clip (JMD_SHEET (dw->data_editor->data_sheet), clip);
1134 trf (GtkClipboard *clip,
1140 for (i = 0; i < n_atoms; ++i)
1142 g_print ("%s\n", gdk_atom_name (atoms[i]));
1147 on_paste (PsppireDataWindow *dw)
1149 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1152 GtkClipboard *clip =
1153 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1154 GDK_SELECTION_CLIPBOARD);
1156 gtk_clipboard_request_targets (clip, trf, dw);
1162 on_clear_cases (PsppireDataWindow *dw)
1165 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1168 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1169 psppire_data_sheet_edit_clear_cases (ds);
1175 on_clear_variables (PsppireDataWindow *dw)
1178 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1181 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1182 psppire_data_sheet_edit_clear_variables (ds);
1186 psppire_var_sheet_clear_variables (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1194 insert_variable (PsppireDataWindow *dw)
1197 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1200 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1201 psppire_data_sheet_insert_variable (ds);
1205 psppire_var_sheet_insert_variable (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1213 insert_case_at_row (PsppireDataWindow *dw)
1216 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1218 psppire_data_sheet_insert_case (ds);
1225 goto_case (PsppireDataWindow *dw)
1228 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1230 goto_case_dialog (ds);
1236 create_file_menu (PsppireDataWindow *dw)
1238 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1239 GtkWidget *menu = gtk_menu_new ();
1242 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1243 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1245 GtkWidget *new_menu = gtk_menu_new ();
1247 g_object_set (new, "submenu", new_menu, NULL);
1249 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1250 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1252 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1253 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1255 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1256 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1259 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1260 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Ctrl>O");
1262 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1263 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1265 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1266 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1268 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1270 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1271 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Ctrl>S");
1273 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1274 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Ctrl>S");
1276 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1277 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1280 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1281 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1282 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1284 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1287 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1288 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1290 GtkWidget *dd_menu = gtk_menu_new ();
1292 g_object_set (display_data, "submenu", dd_menu, NULL);
1294 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1295 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1296 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1297 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1299 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1300 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1303 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1306 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1307 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1309 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1310 gtk_recent_manager_get_default ());
1312 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1313 gtk_recent_manager_get_default ());
1315 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1316 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1318 g_object_set (menu_data, "show-tips", TRUE, NULL);
1319 g_object_set (menu_files, "show-tips", TRUE, NULL);
1321 g_object_set (mi_data, "submenu", menu_data, NULL);
1322 g_object_set (mi_files, "submenu", menu_files, NULL);
1325 GtkRecentFilter *filter = gtk_recent_filter_new ();
1327 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1328 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1330 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1332 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1335 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1338 GtkRecentFilter *filter = gtk_recent_filter_new ();
1340 gtk_recent_filter_add_pattern (filter, "*.sps");
1341 gtk_recent_filter_add_pattern (filter, "*.SPS");
1343 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1345 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1348 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1351 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1354 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1355 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1357 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1358 "quit", quit, "<Ctrl>Q");
1361 g_object_set (menuitem, "submenu", menu, NULL);
1362 gtk_widget_show_all (menuitem);
1369 create_edit_menu (PsppireDataWindow *dw)
1372 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1374 GtkWidget *menu = gtk_menu_new ();
1376 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1377 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1378 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1379 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1381 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1382 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1384 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1385 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1386 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1388 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1390 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1392 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1393 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1396 GtkAccelGroup *ag = gtk_accel_group_new ();
1398 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1399 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1401 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1402 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1403 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1405 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1406 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1407 'X', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1409 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1410 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1411 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1412 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1413 'C', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1415 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1416 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1417 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1418 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1419 'V', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1421 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1422 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1423 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1425 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1426 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1427 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1431 dw->mi_find_separator = gtk_separator_menu_item_new ();
1432 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1434 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1435 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1436 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1439 g_object_set (menuitem, "submenu", menu, NULL);
1441 gtk_widget_show_all (menuitem);
1447 psppire_data_window_finish_init (PsppireDataWindow *de,
1450 static const struct dataset_callbacks cbs =
1452 set_unsaved, /* changed */
1453 transformation_change_callback, /* transformations_changed */
1460 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1463 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1464 de->data_store = psppire_data_store_new (de->dict);
1465 psppire_data_store_set_reader (de->data_store, NULL);
1467 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1468 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1469 gtk_widget_show (menubar);
1471 hb = gtk_toolbar_new ();
1472 sb = get_widget_assert (de->builder, "status-bar");
1475 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1477 g_signal_connect (de, "realize",
1478 G_CALLBACK (set_data_page), de);
1480 g_signal_connect_swapped (de->data_store, "case-changed",
1481 G_CALLBACK (set_unsaved), de);
1483 g_signal_connect_swapped (de->data_store, "case-inserted",
1484 G_CALLBACK (set_unsaved), de);
1486 g_signal_connect_swapped (de->data_store, "cases-deleted",
1487 G_CALLBACK (set_unsaved), de);
1489 dataset_set_callbacks (de->dataset, &cbs, de);
1491 connect_help (de->builder);
1493 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1494 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1495 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1496 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1498 gtk_container_add (GTK_CONTAINER (de), box);
1500 g_signal_connect (de->dict, "weight-changed",
1501 G_CALLBACK (on_weight_change),
1504 g_signal_connect (de->dict, "filter-changed",
1505 G_CALLBACK (on_filter_change),
1508 g_signal_connect (de->dict, "split-changed",
1509 G_CALLBACK (on_split_change),
1512 g_signal_connect_swapped (de->dict, "changed",
1513 G_CALLBACK (enable_save), de);
1514 g_signal_connect_swapped (de->dict, "variable-inserted",
1515 G_CALLBACK (enable_save), de);
1516 g_signal_connect_swapped (de->dict, "variable-deleted",
1517 G_CALLBACK (enable_save), de);
1520 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1521 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1522 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1523 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1524 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1526 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1527 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1528 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1529 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1530 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1531 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1532 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1535 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1536 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1537 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1538 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1540 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1541 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1543 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1544 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1546 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1547 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1548 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1549 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1550 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1551 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1552 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1553 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1554 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1556 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1557 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1559 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1560 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1561 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1563 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1564 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1565 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1566 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1567 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1568 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1571 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1572 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1573 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1577 GSimpleAction *save = g_simple_action_new ("save", NULL);
1578 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1579 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1583 GSimpleAction *open = g_simple_action_new ("open", NULL);
1584 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1585 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1589 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1590 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1591 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1595 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1596 g_signal_connect_swapped (rename_dataset_act, "activate",
1597 G_CALLBACK (on_rename_dataset), de);
1598 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1602 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1603 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1604 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1607 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1608 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1609 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1613 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1614 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1615 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1619 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1620 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1621 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1626 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1627 g_variant_new_string ("DATA"));
1628 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1629 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1633 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1634 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1635 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1639 GSimpleAction *act_value_labels =
1640 g_simple_action_new_stateful ("value_labels", NULL,
1641 g_variant_new_boolean (FALSE));
1642 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1643 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1647 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1648 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1649 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1653 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1654 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1658 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1659 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1660 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1664 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1665 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1666 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1670 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1671 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1672 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1676 GSimpleAction *find = g_simple_action_new ("find", NULL);
1677 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1678 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1684 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1685 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1686 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1687 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1691 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1692 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1693 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1694 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1697 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1700 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1702 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1704 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1705 G_CALLBACK (psppire_dialog_action_activate_null), a);
1707 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1708 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1709 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1713 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1715 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1717 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1718 G_CALLBACK (g_action_activate_null), a);
1720 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1721 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1722 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1726 de->ti_find = gtk_tool_button_new (NULL, "Find");
1728 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1730 g_signal_connect_swapped (de->ti_find, "clicked",
1731 G_CALLBACK (g_action_activate_null), a);
1734 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1735 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1736 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1740 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1741 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1743 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1744 G_CALLBACK (g_action_activate_null), a);
1746 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1747 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1748 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1752 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1753 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1755 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1756 G_CALLBACK (g_action_activate_null), a);
1758 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1759 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1760 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1763 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1766 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1767 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1768 "PsppireDialogActionSplit");
1770 g_signal_connect_swapped (ti, "clicked",
1771 G_CALLBACK (psppire_dialog_action_activate_null), a);
1772 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1773 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1774 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1778 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1779 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1780 "PsppireDialogActionWeight");
1782 g_signal_connect_swapped (ti, "clicked",
1783 G_CALLBACK (psppire_dialog_action_activate_null), a);
1784 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1785 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1786 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1790 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1791 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1793 g_signal_connect (de->ti_value_labels_button, "toggled",
1794 G_CALLBACK (on_labels_button_toggle), de);
1795 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1796 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1797 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1802 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1803 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1805 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1806 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1807 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1808 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1810 g_signal_connect (de->data_editor, "switch-page",
1811 G_CALLBACK (on_switch_page), de);
1813 gtk_widget_show (GTK_WIDGET (de->data_editor));
1814 gtk_widget_show_all (box);
1816 ll_push_head (&all_data_windows, &de->ll);
1821 psppire_data_window_dispose (GObject *object)
1823 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1825 if (dw->builder != NULL)
1827 g_object_unref (dw->builder);
1833 g_signal_handlers_disconnect_by_func (dw->dict,
1834 G_CALLBACK (enable_save), dw);
1835 g_signal_handlers_disconnect_by_func (dw->dict,
1836 G_CALLBACK (on_weight_change), dw);
1837 g_signal_handlers_disconnect_by_func (dw->dict,
1838 G_CALLBACK (on_filter_change), dw);
1839 g_signal_handlers_disconnect_by_func (dw->dict,
1840 G_CALLBACK (on_split_change), dw);
1842 g_object_unref (dw->dict);
1848 g_object_unref (dw->data_store);
1849 dw->data_store = NULL;
1852 if (dw->ll.next != NULL)
1854 ll_remove (&dw->ll);
1858 if (G_OBJECT_CLASS (parent_class)->dispose)
1859 G_OBJECT_CLASS (parent_class)->dispose (object);
1863 psppire_data_window_finalize (GObject *object)
1865 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1869 struct dataset *dataset = dw->dataset;
1870 struct session *session = dataset_session (dataset);
1874 dataset_set_callbacks (dataset, NULL, NULL);
1875 session_set_active_dataset (session, NULL);
1876 dataset_destroy (dataset);
1879 if (G_OBJECT_CLASS (parent_class)->finalize)
1880 G_OBJECT_CLASS (parent_class)->finalize (object);
1884 psppire_data_window_set_property (GObject *object,
1886 const GValue *value,
1889 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1894 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1897 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1903 psppire_data_window_get_property (GObject *object,
1908 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1913 g_value_set_pointer (value, window->dataset);
1916 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1924 psppire_data_window_new (struct dataset *ds)
1928 if (the_session == NULL)
1929 the_session = session_create (NULL);
1933 char *dataset_name = session_generate_dataset_name (the_session);
1934 ds = dataset_create (the_session, dataset_name);
1935 free (dataset_name);
1937 assert (dataset_session (ds) == the_session);
1941 psppire_data_window_get_type (),
1942 "description", _("Data Editor"),
1946 if (dataset_name (ds) != NULL)
1947 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1950 GApplication *app = g_application_get_default ();
1951 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1959 psppire_data_window_is_empty (PsppireDataWindow *dw)
1961 return psppire_dict_get_var_cnt (dw->dict) == 0;
1966 psppire_data_window_iface_init (PsppireWindowIface *iface)
1968 iface->save = save_file;
1969 iface->pick_filename = data_pick_filename;
1970 iface->load = load_file;
1977 psppire_default_data_window (void)
1979 if (ll_is_empty (&all_data_windows))
1980 create_data_window ();
1981 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1987 psppire_data_window_set_default (PsppireDataWindow *pdw)
1989 ll_remove (&pdw->ll);
1990 ll_push_head (&all_data_windows, &pdw->ll);
1994 psppire_data_window_undefault (PsppireDataWindow *pdw)
1996 ll_remove (&pdw->ll);
1997 ll_push_tail (&all_data_windows, &pdw->ll);
2003 psppire_data_window_for_dataset (struct dataset *ds)
2005 PsppireDataWindow *pdw;
2007 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2008 if (pdw->dataset == ds)
2017 psppire_data_window_for_data_store (PsppireDataStore *data_store)
2019 PsppireDataWindow *pdw;
2021 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2022 if (pdw->data_store == data_store)
2031 create_data_window (void)
2033 GtkWidget *w = psppire_data_window_new (NULL);
2035 gtk_widget_show (w);
2037 return GTK_WINDOW (w);
2043 open_data_window (PsppireWindow *victim, const char *file_name,
2044 const char *encoding, gpointer hint)
2048 if (PSPPIRE_IS_DATA_WINDOW (victim)
2049 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
2051 window = GTK_WIDGET (victim);
2052 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
2055 window = psppire_data_window_new (NULL);
2057 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
2058 gtk_widget_show_all (window);