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/psppire-data-sheet.h"
40 #include "ui/gui/psppire-var-sheet.h"
41 #include "ui/gui/windows-menu.h"
42 #include "ui/gui/goto-case-dialog.h"
43 #include "ui/gui/psppire.h"
44 #include "ui/syntax-gen.h"
46 #include "gl/c-strcase.h"
47 #include "gl/c-strcasestr.h"
48 #include "gl/xvasprintf.h"
50 #include "find-dialog.h"
51 #include "options-dialog.h"
52 #include "psppire-dialog-action-1sks.h"
53 #include "psppire-dialog-action-aggregate.h"
54 #include "psppire-dialog-action-autorecode.h"
55 #include "psppire-dialog-action-barchart.h"
56 #include "psppire-dialog-action-binomial.h"
57 #include "psppire-dialog-action-chisquare.h"
58 #include "psppire-dialog-action-comments.h"
59 #include "psppire-dialog-action-compute.h"
60 #include "psppire-dialog-action-correlation.h"
61 #include "psppire-dialog-action-count.h"
62 #include "psppire-dialog-action-crosstabs.h"
63 #include "psppire-dialog-action-descriptives.h"
64 #include "psppire-dialog-action-examine.h"
65 #include "psppire-dialog-action-factor.h"
66 #include "psppire-dialog-action-flip.h"
67 #include "psppire-dialog-action-frequencies.h"
68 #include "psppire-dialog-action-histogram.h"
69 #include "psppire-dialog-action-indep-samps.h"
70 #include "psppire-dialog-action-k-related.h"
71 #include "psppire-dialog-action-kmeans.h"
72 #include "psppire-dialog-action-logistic.h"
73 #include "psppire-dialog-action-means.h"
74 #include "psppire-dialog-action-oneway.h"
75 #include "psppire-dialog-action-paired.h"
76 #include "psppire-dialog-action-rank.h"
77 #include "psppire-dialog-action-recode-same.h"
78 #include "psppire-dialog-action-recode-different.h"
79 #include "psppire-dialog-action-regression.h"
80 #include "psppire-dialog-action-reliability.h"
81 #include "psppire-dialog-action-roc.h"
82 #include "psppire-dialog-action-runs.h"
83 #include "psppire-dialog-action-scatterplot.h"
84 #include "psppire-dialog-action-select.h"
85 #include "psppire-dialog-action-sort.h"
86 #include "psppire-dialog-action-split.h"
87 #include "psppire-dialog-action-tt1s.h"
88 #include "psppire-dialog-action-two-sample.h"
89 #include "psppire-dialog-action-univariate.h"
90 #include "psppire-dialog-action-var-info.h"
91 #include "psppire-dialog-action-weight.h"
95 #define _(msgid) gettext (msgid)
96 #define N_(msgid) msgid
98 struct session *the_session;
99 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
101 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
102 static void psppire_data_window_init (PsppireDataWindow *data_editor);
105 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
107 static void psppire_data_window_dispose (GObject *object);
108 static void psppire_data_window_finalize (GObject *object);
109 static void psppire_data_window_set_property (GObject *object,
113 static void psppire_data_window_get_property (GObject *object,
119 psppire_data_window_get_type (void)
121 static GType psppire_data_window_type = 0;
123 if (!psppire_data_window_type)
125 static const GTypeInfo psppire_data_window_info =
127 sizeof (PsppireDataWindowClass),
130 (GClassInitFunc)psppire_data_window_class_init,
131 (GClassFinalizeFunc) NULL,
133 sizeof (PsppireDataWindow),
135 (GInstanceInitFunc) psppire_data_window_init,
138 static const GInterfaceInfo window_interface_info =
140 (GInterfaceInitFunc) psppire_data_window_iface_init,
145 psppire_data_window_type =
146 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
147 &psppire_data_window_info, 0);
150 g_type_add_interface_static (psppire_data_window_type,
151 PSPPIRE_TYPE_WINDOW_MODEL,
152 &window_interface_info);
155 return psppire_data_window_type;
158 static GObjectClass *parent_class ;
165 psppire_data_window_class_init (PsppireDataWindowClass *class)
167 GObjectClass *object_class = G_OBJECT_CLASS (class);
169 parent_class = g_type_class_peek_parent (class);
171 object_class->dispose = psppire_data_window_dispose;
172 object_class->finalize = psppire_data_window_finalize;
173 object_class->set_property = psppire_data_window_set_property;
174 object_class->get_property = psppire_data_window_get_property;
176 g_object_class_install_property (
177 object_class, PROP_DATASET,
178 g_param_spec_pointer ("dataset", "Dataset",
179 "'struct datset *' represented by the window",
180 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
185 /* Run the EXECUTE command. */
187 execute (PsppireDataWindow *dw)
189 execute_const_syntax_string (dw, "EXECUTE.");
193 transformation_change_callback (bool transformations_pending,
196 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
198 GtkWidget *status_label =
199 get_widget_assert (de->builder, "case-counter-area");
202 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de),
203 "transform-pending");
205 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
206 transformations_pending);
209 if ( transformations_pending)
210 gtk_label_set_text (GTK_LABEL (status_label),
211 _("Transformations Pending"));
213 gtk_label_set_text (GTK_LABEL (status_label), "");
216 /* Callback for when the dictionary changes its filter variable */
218 on_filter_change (GObject *o, gint filter_index, gpointer data)
220 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
222 GtkWidget *filter_status_area =
223 get_widget_assert (de->builder, "filter-use-status-area");
225 if ( filter_index == -1 )
227 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
231 PsppireDict *dict = NULL;
232 struct variable *var ;
235 g_object_get (de->data_editor, "dictionary", &dict, NULL);
237 var = psppire_dict_get_variable (dict, filter_index);
239 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
241 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
247 /* Callback for when the dictionary changes its split variables */
249 on_split_change (PsppireDict *dict, gpointer data)
251 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
253 size_t n_split_vars = dict_get_split_cnt (dict->dict);
255 GtkWidget *split_status_area =
256 get_widget_assert (de->builder, "split-file-status-area");
258 if ( n_split_vars == 0 )
260 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
266 const struct variable *const * split_vars =
267 dict_get_split_vars (dict->dict);
269 text = g_string_new (_("Split by "));
271 for (i = 0 ; i < n_split_vars - 1; ++i )
273 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
275 g_string_append (text, var_get_name (split_vars[i]));
277 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
279 g_string_free (text, TRUE);
286 /* Callback for when the dictionary changes its weights */
288 on_weight_change (GObject *o, gint weight_index, gpointer data)
290 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
292 GtkWidget *weight_status_area =
293 get_widget_assert (de->builder, "weight-status-area");
295 if ( weight_index == -1 )
297 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
301 struct variable *var ;
302 PsppireDict *dict = NULL;
305 g_object_get (de->data_editor, "dictionary", &dict, NULL);
307 var = psppire_dict_get_variable (dict, weight_index);
309 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
311 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
319 dump_rm (GtkRecentManager *rm)
321 GList *items = gtk_recent_manager_get_items (rm);
325 g_print ("Recent Items:\n");
326 for (i = items; i; i = i->next)
328 GtkRecentInfo *ri = i->data;
330 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
331 gtk_recent_info_get_short_name (ri),
332 gtk_recent_info_get_mime_type (ri),
333 gtk_recent_info_get_description (ri),
334 gtk_recent_info_get_uri (ri)
338 gtk_recent_info_unref (ri);
346 has_suffix (const gchar *name, const gchar *suffix)
348 size_t name_len = strlen (name);
349 size_t suffix_len = strlen (suffix);
350 return (name_len > suffix_len
351 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
355 name_has_por_suffix (const gchar *name)
357 return has_suffix (name, ".por");
361 name_has_sav_suffix (const gchar *name)
363 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
366 /* Returns true if NAME has a suffix which might denote a PSPP file */
368 name_has_suffix (const gchar *name)
370 return name_has_por_suffix (name) || name_has_sav_suffix (name);
374 load_file (PsppireWindow *de, const gchar *file_name, const char *encoding,
377 const char *mime_type = NULL;
378 gchar *syntax = NULL;
383 gchar *utf8_file_name;
384 struct string filename;
386 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
388 if (NULL == utf8_file_name)
391 ds_init_empty (&filename);
392 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
394 g_free (utf8_file_name);
396 if (encoding && encoding[0])
397 syntax = g_strdup_printf ("GET FILE=%s ENCODING='%s'.",
398 ds_cstr (&filename), encoding);
400 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
401 ds_destroy (&filename);
408 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
409 lex_reader_for_string (syntax, "UTF-8"));
412 if (ok && syn == NULL)
414 if (name_has_por_suffix (file_name))
415 mime_type = "application/x-spss-por";
416 else if (name_has_sav_suffix (file_name))
417 mime_type = "application/x-spss-sav";
419 add_most_recent (file_name, mime_type, encoding);
426 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
428 if (format == PSPPIRE_DATA_WINDOW_SAV)
430 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
436 /* Save DE to file */
438 save_file (PsppireWindow *w)
440 const gchar *file_name = NULL;
441 gchar *utf8_file_name = NULL;
443 struct string filename ;
444 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
447 file_name = psppire_window_get_filename (w);
449 fnx = g_string_new (file_name);
451 if ( ! name_has_suffix (fnx->str))
452 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
454 ds_init_empty (&filename);
456 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
458 g_string_free (fnx, TRUE);
460 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
461 g_free (utf8_file_name);
463 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
464 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
465 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
466 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
467 ds_cstr (&filename));
469 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
471 ds_destroy (&filename);
473 g_free (execute_syntax_string (de, syntax));
478 display_dict (PsppireDataWindow *de)
480 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
484 sysfile_info (PsppireDataWindow *de)
486 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
488 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
490 struct string filename;
492 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
493 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
496 const gchar *encoding = psppire_encoding_selector_get_encoding (
497 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
501 ds_init_empty (&filename);
503 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
505 g_free (utf8_file_name);
508 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
509 ds_cstr (&filename), encoding);
511 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
512 g_free (execute_syntax_string (de, syntax));
515 gtk_widget_destroy (dialog);
519 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
521 data_pick_filename (PsppireWindow *window)
523 GtkListStore *list_store;
524 GtkWidget *combo_box;
526 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
527 GtkFileFilter *filter;
529 gtk_file_chooser_dialog_new (_("Save"),
531 GTK_FILE_CHOOSER_ACTION_SAVE,
532 _("Cancel"), GTK_RESPONSE_CANCEL,
533 _("Save"), GTK_RESPONSE_ACCEPT,
536 g_object_set (dialog, "local-only", FALSE, NULL);
538 filter = gtk_file_filter_new ();
539 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
540 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
541 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
543 filter = gtk_file_filter_new ();
544 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
545 gtk_file_filter_add_pattern (filter, "*.zsav");
546 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
548 filter = gtk_file_filter_new ();
549 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
550 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
551 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
553 filter = gtk_file_filter_new ();
554 gtk_file_filter_set_name (filter, _("All Files"));
555 gtk_file_filter_add_pattern (filter, "*");
556 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
557 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
560 GtkCellRenderer *cell;
565 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
566 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
568 gtk_list_store_append (list_store, &iter);
569 gtk_list_store_set (list_store, &iter,
570 0, PSPPIRE_DATA_WINDOW_SAV,
573 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
575 gtk_list_store_append (list_store, &iter);
576 gtk_list_store_set (list_store, &iter,
577 0, PSPPIRE_DATA_WINDOW_ZSAV,
578 1, _("Compressed System File"),
581 gtk_list_store_append (list_store, &iter);
582 gtk_list_store_set (list_store, &iter,
583 0, PSPPIRE_DATA_WINDOW_POR,
584 1, _("Portable File"),
587 label = gtk_label_new (_("Format:"));
589 cell = gtk_cell_renderer_text_new ();
590 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
591 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
594 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
595 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
596 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
597 gtk_widget_show_all (hbox);
599 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
602 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
605 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
607 case GTK_RESPONSE_ACCEPT:
612 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
618 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
619 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
624 if ( ! name_has_suffix (filename->str))
625 g_string_append (filename,
626 psppire_data_window_format_to_string (format));
628 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
630 g_string_free (filename, TRUE);
637 gtk_widget_destroy (dialog);
641 confirm_delete_dataset (PsppireDataWindow *de,
642 const char *old_dataset,
643 const char *new_dataset,
644 const char *existing_dataset)
649 dialog = gtk_message_dialog_new (
650 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
651 _("Delete Existing Dataset?"));
653 gtk_message_dialog_format_secondary_text (
654 GTK_MESSAGE_DIALOG (dialog),
655 _("Renaming \"%s\" to \"%s\" will destroy the existing "
656 "dataset named \"%s\". Are you sure that you want to do this?"),
657 old_dataset, new_dataset, existing_dataset);
659 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
660 _("Cancel"), GTK_RESPONSE_CANCEL,
661 _("Delete"), GTK_RESPONSE_OK,
664 g_object_set (dialog, "icon-name", "pspp", NULL);
666 result = gtk_dialog_run (GTK_DIALOG (dialog));
668 gtk_widget_destroy (dialog);
670 return result == GTK_RESPONSE_OK;
674 on_rename_dataset (PsppireDataWindow *de)
676 struct dataset *ds = de->dataset;
677 struct session *session = dataset_session (ds);
678 const char *old_name = dataset_name (ds);
679 struct dataset *existing_dataset;
683 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
685 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
689 if (new_name == NULL)
692 existing_dataset = session_lookup_dataset (session, new_name);
693 if (existing_dataset == NULL || existing_dataset == ds
694 || confirm_delete_dataset (de, old_name, new_name,
695 dataset_name (existing_dataset)))
696 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
704 status_bar_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
706 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
708 GVariant *state = g_action_get_state (action);
709 const gboolean visible = g_variant_get_boolean (state);
710 g_action_change_state (action, g_variant_new_boolean (!visible));
712 gtk_widget_set_visible (statusbar, !visible);
717 grid_lines_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
719 GVariant *state = g_action_get_state (action);
720 const gboolean grid_visible = g_variant_get_boolean (state);
721 g_action_change_state (action, g_variant_new_boolean (!grid_visible));
723 psppire_data_editor_show_grid (de->data_editor, !grid_visible);
728 on_switch_page (GtkNotebook *notebook, GtkWidget *page, guint pn, gpointer ud)
730 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (ud);
732 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de), "view_dv");
737 g_action_change_state (action, g_variant_new_string ("DATA"));
738 gtk_widget_show (GTK_WIDGET (de->ti_insert_case));
739 gtk_widget_show (GTK_WIDGET (de->ti_jump_to_case));
740 gtk_widget_show (GTK_WIDGET (de->ti_find));
742 gtk_widget_show (GTK_WIDGET (de->mi_go_to_case));
743 gtk_widget_show (GTK_WIDGET (de->mi_insert_case));
744 gtk_widget_show (GTK_WIDGET (de->mi_find));
745 gtk_widget_show (GTK_WIDGET (de->mi_find_separator));
746 gtk_widget_show (GTK_WIDGET (de->mi_clear_cases));
751 g_action_change_state (action, g_variant_new_string ("VARS"));
752 gtk_widget_hide (GTK_WIDGET (de->ti_insert_case));
753 gtk_widget_hide (GTK_WIDGET (de->ti_jump_to_case));
754 gtk_widget_hide (GTK_WIDGET (de->ti_find));
756 gtk_widget_hide (GTK_WIDGET (de->mi_go_to_case));
757 gtk_widget_hide (GTK_WIDGET (de->mi_insert_case));
758 gtk_widget_hide (GTK_WIDGET (de->mi_find));
759 gtk_widget_hide (GTK_WIDGET (de->mi_find_separator));
760 gtk_widget_hide (GTK_WIDGET (de->mi_clear_cases));
768 activate_change_view (GAction *action, GVariant *param, PsppireDataWindow *de)
770 g_action_change_state (action, param);
771 GVariant *new_state = g_action_get_state (action);
773 const gchar *what = g_variant_get_string (new_state, NULL);
774 if (0 == g_strcmp0 (what, "DATA"))
776 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
778 else if (0 == g_strcmp0 (what, "VARS"))
780 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
787 fonts_activate (PsppireDataWindow *de)
789 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
790 GtkWidget *dialog = gtk_font_chooser_dialog_new (NULL, GTK_WINDOW (toplevel));
791 GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET(de->data_editor));
792 const PangoFontDescription *current_font ;
794 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, "font", ¤t_font, NULL);
796 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (dialog), current_font);
798 gtk_window_set_transient_for (GTK_WINDOW (dialog),
799 GTK_WINDOW (toplevel));
801 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
803 PangoFontDescription* font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog));
805 psppire_data_editor_set_font (de->data_editor, font_desc);
808 gtk_widget_hide (dialog);
813 /* Callback for the value labels action */
816 value_labels_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
818 GVariant *v = g_action_get_state (action);
819 gboolean labels_active = g_variant_get_boolean (v);
820 g_action_change_state (action, g_variant_new_boolean (!labels_active));
822 GVariant *new_state = g_action_get_state (action);
823 labels_active = g_variant_get_boolean (new_state);
824 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
826 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (de->ti_value_labels_button),
831 on_labels_button_toggle (GtkToggleToolButton *ttb, PsppireDataWindow *de)
833 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "value_labels");
835 gboolean labels_active = gtk_toggle_tool_button_get_active (ttb);
837 g_action_change_state (a, g_variant_new_boolean (labels_active));
839 GVariant *new_state = g_action_get_state (a);
840 labels_active = g_variant_get_boolean (new_state);
841 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
845 on_recent_data_select (GtkMenuShell *menushell,
846 PsppireWindow *window)
851 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
853 file = g_filename_from_uri (uri, NULL, NULL);
857 open_data_window (window, file, NULL, NULL);
863 charset_from_mime_type (const char *mime_type)
869 if (mime_type == NULL)
872 charset = c_strcasestr (mime_type, "charset=");
880 /* Parse a "quoted-string" as defined by RFC 822. */
881 for (p++; *p != '\0' && *p != '"'; p++)
884 ds_put_byte (&s, *p);
885 else if (*++p != '\0')
886 ds_put_byte (&s, *p);
891 /* Parse a "token" as defined by RFC 2045. */
892 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
893 ds_put_byte (&s, *p++);
895 if (!ds_is_empty (&s))
896 return ds_steal_cstr (&s);
903 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
910 /* Get the file name and its encoding. */
911 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
912 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
913 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
914 gtk_recent_info_unref (item);
916 se = psppire_syntax_window_new (encoding);
920 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
921 gtk_widget_show (se);
923 gtk_widget_destroy (se);
929 set_unsaved (gpointer w)
931 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
935 /* Only a data file with at least one variable can be saved. */
937 enable_save (PsppireDataWindow *dw)
939 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
941 GAction *save_as = g_action_map_lookup_action (G_ACTION_MAP (dw), "save-as");
942 GAction *save = g_action_map_lookup_action (G_ACTION_MAP (dw), "save");
945 g_object_set (save, "enabled", enable, NULL);
948 g_object_set (save_as, "enabled", enable, NULL);
951 /* Initializes as much of a PsppireDataWindow as we can and must before the
952 dataset has been set.
954 In particular, the 'menu' member is required in case the "filename" property
955 is set before the "dataset" property: otherwise PsppireWindow will try to
956 modify the menu as part of the "filename" property_set() function and end up
957 with a Gtk-CRITICAL since 'menu' is NULL. */
959 psppire_data_window_init (PsppireDataWindow *de)
961 de->builder = builder_new ("data-editor.ui");
965 file_import (PsppireDataWindow *dw)
967 GtkWidget *w = psppire_import_assistant_new (GTK_WINDOW (dw));
968 PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
969 gtk_widget_show_all (w);
971 asst->main_loop = g_main_loop_new (NULL, TRUE);
972 g_main_loop_run (asst->main_loop);
973 g_main_loop_unref (asst->main_loop);
975 if (!asst->file_name)
978 switch (asst->response)
980 case GTK_RESPONSE_APPLY:
982 gchar *fn = g_path_get_basename (asst->file_name);
983 open_data_window (PSPPIRE_WINDOW (dw), fn, NULL, psppire_import_assistant_generate_syntax (asst));
987 case PSPPIRE_RESPONSE_PASTE:
988 free (paste_syntax_to_window (psppire_import_assistant_generate_syntax (asst)));
995 gtk_widget_destroy (GTK_WIDGET (asst));
1001 connect_dialog_action (GType type, PsppireDataWindow *de)
1003 GAction *act = g_object_new (type,
1007 g_action_map_add_action (G_ACTION_MAP (de), act);
1011 g_action_activate_null (GAction *a)
1013 g_action_activate (a, NULL);
1017 connect_action_to_menuitem (GActionMap *map, const gchar *action_name, GtkWidget *w, const gchar *accel)
1019 GAction *a = g_action_map_lookup_action (map, action_name);
1022 g_error ("Action \"%s\" not found in map", action_name);
1026 GtkApplication *app = GTK_APPLICATION (g_application_get_default());
1028 /* First set the label for the accellerator so that it appears
1030 GtkWidget *child = gtk_bin_get_child (GTK_BIN (w));
1032 GdkModifierType modifier;
1033 gtk_accelerator_parse (accel, &key, &modifier);
1034 gtk_accel_label_set_accel (GTK_ACCEL_LABEL (child), key, modifier);
1036 /* Now tell the application that it must do something when that
1037 key combination is pressed */
1038 const gchar *accels[2];
1042 gchar *detailed_action_name = NULL;
1043 if (GTK_IS_WINDOW (map))
1044 detailed_action_name = g_strdup_printf ("win.%s", action_name);
1045 else if (GTK_IS_APPLICATION (map))
1046 detailed_action_name = g_strdup_printf ("app.%s", action_name);
1048 gtk_application_set_accels_for_action (app,
1049 detailed_action_name,
1051 free (detailed_action_name);
1054 g_signal_connect_swapped (w, "activate", G_CALLBACK (g_action_activate_null), a);
1059 set_data_page (PsppireDataWindow *dw)
1061 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 1);
1062 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 0);
1067 on_cut (PsppireDataWindow *dw)
1069 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1072 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1073 psppire_data_sheet_edit_cut (ds);
1078 on_copy (PsppireDataWindow *dw)
1080 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1083 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1084 psppire_data_sheet_edit_copy (ds);
1089 on_paste (PsppireDataWindow *dw)
1091 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1094 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1095 psppire_data_sheet_edit_paste (ds);
1101 on_clear_cases (PsppireDataWindow *dw)
1103 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1106 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1107 psppire_data_sheet_edit_clear_cases (ds);
1112 on_clear_variables (PsppireDataWindow *dw)
1114 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1117 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1118 psppire_data_sheet_edit_clear_variables (ds);
1122 psppire_var_sheet_clear_variables (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1128 insert_variable (PsppireDataWindow *dw)
1130 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1133 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1134 psppire_data_sheet_insert_variable (ds);
1138 psppire_var_sheet_insert_variable (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1144 insert_case_at_row (PsppireDataWindow *dw)
1146 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1148 psppire_data_sheet_insert_case (ds);
1152 goto_case (PsppireDataWindow *dw)
1154 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1156 goto_case_dialog (ds);
1162 create_file_menu (PsppireDataWindow *dw)
1164 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1165 GtkWidget *menu = gtk_menu_new ();
1168 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1169 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1171 GtkWidget *new_menu = gtk_menu_new ();
1173 g_object_set (new, "submenu", new_menu, NULL);
1175 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1176 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1178 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1179 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1181 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1182 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1185 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1186 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Ctrl>O");
1188 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1189 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1191 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1192 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1194 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1196 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1197 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Ctrl>S");
1199 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1200 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Ctrl>S");
1202 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1203 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1206 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1207 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1208 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1210 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1213 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1214 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1216 GtkWidget *dd_menu = gtk_menu_new ();
1218 g_object_set (display_data, "submenu", dd_menu, NULL);
1220 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1221 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1222 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1223 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1225 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1226 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1229 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1232 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1233 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1235 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1236 gtk_recent_manager_get_default ());
1238 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1239 gtk_recent_manager_get_default ());
1241 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1242 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1244 g_object_set (menu_data, "show-tips", TRUE, NULL);
1245 g_object_set (menu_files, "show-tips", TRUE, NULL);
1247 g_object_set (mi_data, "submenu", menu_data, NULL);
1248 g_object_set (mi_files, "submenu", menu_files, NULL);
1251 GtkRecentFilter *filter = gtk_recent_filter_new ();
1253 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1254 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1256 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1258 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1261 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1264 GtkRecentFilter *filter = gtk_recent_filter_new ();
1266 gtk_recent_filter_add_pattern (filter, "*.sps");
1267 gtk_recent_filter_add_pattern (filter, "*.SPS");
1269 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1271 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1274 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1277 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1280 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1281 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1283 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1284 "quit", quit, "<Ctrl>Q");
1287 g_object_set (menuitem, "submenu", menu, NULL);
1288 gtk_widget_show_all (menuitem);
1294 create_edit_menu (PsppireDataWindow *dw)
1297 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1299 GtkWidget *menu = gtk_menu_new ();
1301 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1302 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1303 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1304 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1306 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1307 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1309 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1310 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1311 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1313 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1315 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1317 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1318 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1321 GtkAccelGroup *ag = gtk_accel_group_new ();
1323 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1324 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1326 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1327 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1328 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1330 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1331 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1332 'X', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1334 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1335 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1336 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1337 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1338 'C', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1340 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1341 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1342 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1343 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1344 'V', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1346 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1347 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1348 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1350 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1351 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1352 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1356 dw->mi_find_separator = gtk_separator_menu_item_new ();
1357 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1359 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1360 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1361 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1365 dw->mi_options = gtk_menu_item_new_with_mnemonic (_("_Options..."));
1366 g_signal_connect_swapped (dw->mi_options, "activate",
1367 G_CALLBACK (options_dialog), dw);
1368 gtk_menu_attach (GTK_MENU (menu), dw->mi_options, 0, 1, i, i + 1); ++i;
1371 g_object_set (menuitem, "submenu", menu, NULL);
1373 gtk_widget_show_all (menuitem);
1380 psppire_data_window_finish_init (PsppireDataWindow *de,
1383 static const struct dataset_callbacks cbs =
1385 set_unsaved, /* changed */
1386 transformation_change_callback, /* transformations_changed */
1393 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1396 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1397 de->data_store = psppire_data_store_new (de->dict);
1398 psppire_data_store_set_reader (de->data_store, NULL);
1400 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1401 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1402 gtk_widget_show (menubar);
1404 hb = gtk_toolbar_new ();
1405 sb = get_widget_assert (de->builder, "status-bar");
1408 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1410 g_signal_connect (de, "realize",
1411 G_CALLBACK (set_data_page), de);
1413 g_signal_connect_swapped (de->data_store, "case-changed",
1414 G_CALLBACK (set_unsaved), de);
1416 g_signal_connect_swapped (de->data_store, "case-inserted",
1417 G_CALLBACK (set_unsaved), de);
1419 g_signal_connect_swapped (de->data_store, "cases-deleted",
1420 G_CALLBACK (set_unsaved), de);
1422 dataset_set_callbacks (de->dataset, &cbs, de);
1424 connect_help (de->builder);
1426 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1427 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1428 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1429 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1431 gtk_container_add (GTK_CONTAINER (de), box);
1433 g_signal_connect (de->dict, "weight-changed",
1434 G_CALLBACK (on_weight_change),
1437 g_signal_connect (de->dict, "filter-changed",
1438 G_CALLBACK (on_filter_change),
1441 g_signal_connect (de->dict, "split-changed",
1442 G_CALLBACK (on_split_change),
1445 g_signal_connect_swapped (de->dict, "backend-changed",
1446 G_CALLBACK (enable_save), de);
1447 g_signal_connect_swapped (de->dict, "variable-inserted",
1448 G_CALLBACK (enable_save), de);
1449 g_signal_connect_swapped (de->dict, "variable-deleted",
1450 G_CALLBACK (enable_save), de);
1453 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1454 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1455 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1456 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1457 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1459 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1460 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1461 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1462 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1463 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1464 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1465 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1468 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1469 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1470 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1471 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1473 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1474 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1476 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1477 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1479 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1480 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1481 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1482 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1483 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1484 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1485 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1486 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1487 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1489 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1490 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1492 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1493 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1494 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1496 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1497 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1498 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1499 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1500 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1501 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1504 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1505 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1506 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1510 GSimpleAction *save = g_simple_action_new ("save", NULL);
1511 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1512 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1516 GSimpleAction *open = g_simple_action_new ("open", NULL);
1517 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1518 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1522 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1523 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1524 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1528 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1529 g_signal_connect_swapped (rename_dataset_act, "activate",
1530 G_CALLBACK (on_rename_dataset), de);
1531 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1535 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1536 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1537 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1540 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1541 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1542 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1546 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1547 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1548 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1552 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1553 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1554 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1559 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1560 g_variant_new_string ("DATA"));
1561 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1562 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1566 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1567 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1568 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1572 GSimpleAction *act_value_labels =
1573 g_simple_action_new_stateful ("value_labels", NULL,
1574 g_variant_new_boolean (FALSE));
1575 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1576 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1580 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1581 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1582 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1586 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1587 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1591 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1592 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1593 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1597 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1598 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1599 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1603 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1604 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1605 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1609 GSimpleAction *find = g_simple_action_new ("find", NULL);
1610 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1611 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1617 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1618 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1619 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1620 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1624 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1625 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1626 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1627 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1630 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1633 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1635 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1637 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1638 G_CALLBACK (psppire_dialog_action_activate_null), a);
1640 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1641 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1642 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1646 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1648 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1650 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1651 G_CALLBACK (g_action_activate_null), a);
1653 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1654 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1655 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1659 de->ti_find = gtk_tool_button_new (NULL, "Find");
1661 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1663 g_signal_connect_swapped (de->ti_find, "clicked",
1664 G_CALLBACK (g_action_activate_null), a);
1667 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1668 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1669 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1673 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1674 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1676 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1677 G_CALLBACK (g_action_activate_null), a);
1679 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1680 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1681 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1685 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1686 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1688 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1689 G_CALLBACK (g_action_activate_null), a);
1691 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1692 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1693 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1696 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1699 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1700 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1701 "PsppireDialogActionSplit");
1703 g_signal_connect_swapped (ti, "clicked",
1704 G_CALLBACK (psppire_dialog_action_activate_null), a);
1705 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1706 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1707 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1711 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1712 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1713 "PsppireDialogActionWeight");
1715 g_signal_connect_swapped (ti, "clicked",
1716 G_CALLBACK (psppire_dialog_action_activate_null), a);
1717 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1718 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1719 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1723 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1724 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1726 g_signal_connect (de->ti_value_labels_button, "toggled",
1727 G_CALLBACK (on_labels_button_toggle), de);
1728 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1729 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1730 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1735 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1736 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1738 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1739 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1740 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1741 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1743 g_signal_connect (de->data_editor, "switch-page",
1744 G_CALLBACK (on_switch_page), de);
1746 gtk_widget_show (GTK_WIDGET (de->data_editor));
1747 gtk_widget_show_all (box);
1749 ll_push_head (&all_data_windows, &de->ll);
1753 psppire_data_window_dispose (GObject *object)
1755 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1757 if (dw->builder != NULL)
1759 g_object_unref (dw->builder);
1765 g_signal_handlers_disconnect_by_func (dw->dict,
1766 G_CALLBACK (enable_save), dw);
1767 g_signal_handlers_disconnect_by_func (dw->dict,
1768 G_CALLBACK (on_weight_change), dw);
1769 g_signal_handlers_disconnect_by_func (dw->dict,
1770 G_CALLBACK (on_filter_change), dw);
1771 g_signal_handlers_disconnect_by_func (dw->dict,
1772 G_CALLBACK (on_split_change), dw);
1774 g_object_unref (dw->dict);
1780 g_object_unref (dw->data_store);
1781 dw->data_store = NULL;
1784 if (dw->ll.next != NULL)
1786 ll_remove (&dw->ll);
1790 if (G_OBJECT_CLASS (parent_class)->dispose)
1791 G_OBJECT_CLASS (parent_class)->dispose (object);
1795 psppire_data_window_finalize (GObject *object)
1797 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1801 struct dataset *dataset = dw->dataset;
1802 struct session *session = dataset_session (dataset);
1806 dataset_set_callbacks (dataset, NULL, NULL);
1807 session_set_active_dataset (session, NULL);
1808 dataset_destroy (dataset);
1811 if (G_OBJECT_CLASS (parent_class)->finalize)
1812 G_OBJECT_CLASS (parent_class)->finalize (object);
1816 psppire_data_window_set_property (GObject *object,
1818 const GValue *value,
1821 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1826 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1829 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1835 psppire_data_window_get_property (GObject *object,
1840 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1845 g_value_set_pointer (value, window->dataset);
1848 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1855 psppire_data_window_new (struct dataset *ds)
1859 if (the_session == NULL)
1860 the_session = session_create (NULL);
1864 char *dataset_name = session_generate_dataset_name (the_session);
1865 ds = dataset_create (the_session, dataset_name);
1866 free (dataset_name);
1868 assert (dataset_session (ds) == the_session);
1872 psppire_data_window_get_type (),
1873 "description", _("Data Editor"),
1877 if (dataset_name (ds) != NULL)
1878 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1881 GApplication *app = g_application_get_default ();
1882 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1888 psppire_data_window_is_empty (PsppireDataWindow *dw)
1890 return psppire_dict_get_var_cnt (dw->dict) == 0;
1894 psppire_data_window_iface_init (PsppireWindowIface *iface)
1896 iface->save = save_file;
1897 iface->pick_filename = data_pick_filename;
1898 iface->load = load_file;
1904 psppire_default_data_window (void)
1906 if (ll_is_empty (&all_data_windows))
1907 create_data_window ();
1908 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1912 psppire_data_window_set_default (PsppireDataWindow *pdw)
1914 ll_remove (&pdw->ll);
1915 ll_push_head (&all_data_windows, &pdw->ll);
1919 psppire_data_window_undefault (PsppireDataWindow *pdw)
1921 ll_remove (&pdw->ll);
1922 ll_push_tail (&all_data_windows, &pdw->ll);
1926 psppire_data_window_for_dataset (struct dataset *ds)
1928 PsppireDataWindow *pdw;
1930 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1931 if (pdw->dataset == ds)
1938 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1940 PsppireDataWindow *pdw;
1942 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1943 if (pdw->data_store == data_store)
1950 create_data_window (void)
1952 GtkWidget *w = psppire_data_window_new (NULL);
1954 gtk_widget_show (w);
1956 return GTK_WINDOW (w);
1960 open_data_window (PsppireWindow *victim, const char *file_name,
1961 const char *encoding, gpointer hint)
1965 if (PSPPIRE_IS_DATA_WINDOW (victim)
1966 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1968 window = GTK_WIDGET (victim);
1969 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1972 window = psppire_data_window_new (NULL);
1974 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
1975 gtk_widget_show_all (window);
1976 return GTK_WINDOW (window);