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 "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 PsppireDict *dict = NULL;
1073 g_object_get (dw->data_editor, "dictionary", &dict, NULL);
1076 JmdSheet *sheet = JMD_SHEET (dw->data_editor->data_sheet);
1077 JmdRange sel = *sheet->selection;
1079 GtkClipboard *clip =
1080 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1081 GDK_SELECTION_CLIPBOARD);
1083 /* Save the selected area to a string */
1084 GString *str = g_string_new ("");
1085 for (y = sel.start_y ; y <= sel.end_y; ++y)
1087 for (x = sel.start_x ; x <= sel.end_x; ++x)
1089 const struct variable * var = psppire_dict_get_variable (dict, x);
1090 gchar *s = psppire_data_store_get_string (dw->data_editor->data_store,
1092 g_string_append (str, s);
1093 g_string_append (str, "\t");
1096 g_string_append (str, "\n");
1099 gtk_clipboard_set_text (clip, str->str, str->len);
1100 g_string_free (str, TRUE);
1102 /* Now fill the selected area with SYSMIS */
1105 for (x = sel.start_x ; x <= sel.end_x; ++x)
1107 const struct variable * var = psppire_dict_get_variable (dict, x);
1108 for (y = sel.start_y ; y <= sel.end_y; ++y)
1110 psppire_data_store_set_value (dw->data_editor->data_store,
1122 on_copy (PsppireDataWindow *dw)
1124 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1127 GtkClipboard *clip =
1128 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1129 GDK_SELECTION_CLIPBOARD);
1131 jmd_sheet_set_clip (JMD_SHEET (dw->data_editor->data_sheet), clip);
1137 trf (GtkClipboard *clip,
1143 for (i = 0; i < n_atoms; ++i)
1145 g_print ("%s\n", gdk_atom_name (atoms[i]));
1150 on_paste (PsppireDataWindow *dw)
1152 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1155 GtkClipboard *clip =
1156 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1157 GDK_SELECTION_CLIPBOARD);
1159 gtk_clipboard_request_targets (clip, trf, dw);
1165 on_clear_cases (PsppireDataWindow *dw)
1168 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1171 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1172 psppire_data_sheet_edit_clear_cases (ds);
1178 on_clear_variables (PsppireDataWindow *dw)
1181 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1184 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1185 psppire_data_sheet_edit_clear_variables (ds);
1189 psppire_var_sheet_clear_variables (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1197 insert_variable (PsppireDataWindow *dw)
1200 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1203 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1204 psppire_data_sheet_insert_variable (ds);
1208 psppire_var_sheet_insert_variable (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
1216 insert_case_at_row (PsppireDataWindow *dw)
1219 PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
1221 psppire_data_sheet_insert_case (ds);
1228 goto_case (PsppireDataWindow *dw)
1230 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1233 goto_case_dialog (JMD_SHEET (dw->data_editor->data_sheet));
1239 create_file_menu (PsppireDataWindow *dw)
1241 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1242 GtkWidget *menu = gtk_menu_new ();
1245 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1246 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1248 GtkWidget *new_menu = gtk_menu_new ();
1250 g_object_set (new, "submenu", new_menu, NULL);
1252 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1253 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1255 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1256 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1258 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1259 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1262 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1263 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Ctrl>O");
1265 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1266 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1268 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1269 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1271 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1273 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1274 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Ctrl>S");
1276 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1277 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Ctrl>S");
1279 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1280 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1283 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1284 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1285 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1287 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1290 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1291 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1293 GtkWidget *dd_menu = gtk_menu_new ();
1295 g_object_set (display_data, "submenu", dd_menu, NULL);
1297 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1298 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1299 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1300 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1302 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1303 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1306 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1309 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1310 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1312 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1313 gtk_recent_manager_get_default ());
1315 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1316 gtk_recent_manager_get_default ());
1318 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1319 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1321 g_object_set (menu_data, "show-tips", TRUE, NULL);
1322 g_object_set (menu_files, "show-tips", TRUE, NULL);
1324 g_object_set (mi_data, "submenu", menu_data, NULL);
1325 g_object_set (mi_files, "submenu", menu_files, NULL);
1328 GtkRecentFilter *filter = gtk_recent_filter_new ();
1330 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1331 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1333 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1335 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1338 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1341 GtkRecentFilter *filter = gtk_recent_filter_new ();
1343 gtk_recent_filter_add_pattern (filter, "*.sps");
1344 gtk_recent_filter_add_pattern (filter, "*.SPS");
1346 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1348 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1351 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1354 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1357 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1358 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1360 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1361 "quit", quit, "<Ctrl>Q");
1364 g_object_set (menuitem, "submenu", menu, NULL);
1365 gtk_widget_show_all (menuitem);
1372 create_edit_menu (PsppireDataWindow *dw)
1375 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1377 GtkWidget *menu = gtk_menu_new ();
1379 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1380 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1381 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1382 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1384 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1385 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1387 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1388 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1389 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1391 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1393 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1395 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1396 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1399 GtkAccelGroup *ag = gtk_accel_group_new ();
1401 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1402 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1404 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1405 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1406 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1408 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1409 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1410 'X', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1412 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1413 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1414 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1415 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1416 'C', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1418 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1419 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1420 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1421 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1422 'V', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1424 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1425 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1426 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1428 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1429 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1430 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1434 dw->mi_find_separator = gtk_separator_menu_item_new ();
1435 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1437 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1438 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1439 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1443 dw->mi_options = gtk_menu_item_new_with_mnemonic (_("_Options..."));
1444 g_signal_connect_swapped (dw->mi_options, "activate",
1445 G_CALLBACK (options_dialog), dw);
1446 gtk_menu_attach (GTK_MENU (menu), dw->mi_options, 0, 1, i, i + 1); ++i;
1449 g_object_set (menuitem, "submenu", menu, NULL);
1451 gtk_widget_show_all (menuitem);
1457 psppire_data_window_finish_init (PsppireDataWindow *de,
1460 static const struct dataset_callbacks cbs =
1462 set_unsaved, /* changed */
1463 transformation_change_callback, /* transformations_changed */
1470 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1473 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1474 de->data_store = psppire_data_store_new (de->dict);
1475 psppire_data_store_set_reader (de->data_store, NULL);
1477 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1478 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1479 gtk_widget_show (menubar);
1481 hb = gtk_toolbar_new ();
1482 sb = get_widget_assert (de->builder, "status-bar");
1485 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1487 g_signal_connect (de, "realize",
1488 G_CALLBACK (set_data_page), de);
1490 g_signal_connect_swapped (de->data_store, "case-changed",
1491 G_CALLBACK (set_unsaved), de);
1493 g_signal_connect_swapped (de->data_store, "case-inserted",
1494 G_CALLBACK (set_unsaved), de);
1496 g_signal_connect_swapped (de->data_store, "cases-deleted",
1497 G_CALLBACK (set_unsaved), de);
1499 dataset_set_callbacks (de->dataset, &cbs, de);
1501 connect_help (de->builder);
1503 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1504 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1505 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1506 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1508 gtk_container_add (GTK_CONTAINER (de), box);
1510 g_signal_connect (de->dict, "weight-changed",
1511 G_CALLBACK (on_weight_change),
1514 g_signal_connect (de->dict, "filter-changed",
1515 G_CALLBACK (on_filter_change),
1518 g_signal_connect (de->dict, "split-changed",
1519 G_CALLBACK (on_split_change),
1522 g_signal_connect_swapped (de->dict, "changed",
1523 G_CALLBACK (enable_save), de);
1524 g_signal_connect_swapped (de->dict, "variable-inserted",
1525 G_CALLBACK (enable_save), de);
1526 g_signal_connect_swapped (de->dict, "variable-deleted",
1527 G_CALLBACK (enable_save), de);
1530 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1531 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1532 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1533 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1534 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1536 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1537 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1538 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1539 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1540 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1541 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1542 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1545 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1546 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1547 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1548 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1550 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1551 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1553 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1554 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1556 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1557 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1558 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1559 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1560 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1561 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1562 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1563 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1564 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1566 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1567 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1569 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1570 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1571 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1573 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1574 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1575 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1576 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1577 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1578 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1581 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1582 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1583 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1587 GSimpleAction *save = g_simple_action_new ("save", NULL);
1588 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1589 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1593 GSimpleAction *open = g_simple_action_new ("open", NULL);
1594 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1595 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1599 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1600 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1601 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1605 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1606 g_signal_connect_swapped (rename_dataset_act, "activate",
1607 G_CALLBACK (on_rename_dataset), de);
1608 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1612 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1613 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1614 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1617 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1618 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1619 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1623 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1624 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1625 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1629 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1630 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1631 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1636 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1637 g_variant_new_string ("DATA"));
1638 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1639 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1643 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1644 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1645 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1649 GSimpleAction *act_value_labels =
1650 g_simple_action_new_stateful ("value_labels", NULL,
1651 g_variant_new_boolean (FALSE));
1652 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1653 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1657 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1658 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1659 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1663 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1664 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1668 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1669 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1670 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1674 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1675 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1676 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1680 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1681 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1682 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1686 GSimpleAction *find = g_simple_action_new ("find", NULL);
1687 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1688 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1694 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1695 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1696 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1697 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1701 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1702 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1703 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1704 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1707 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1710 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1712 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1714 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1715 G_CALLBACK (psppire_dialog_action_activate_null), a);
1717 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1718 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1719 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1723 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1725 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1727 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1728 G_CALLBACK (g_action_activate_null), a);
1730 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1731 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1732 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1736 de->ti_find = gtk_tool_button_new (NULL, "Find");
1738 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1740 g_signal_connect_swapped (de->ti_find, "clicked",
1741 G_CALLBACK (g_action_activate_null), a);
1744 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1745 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1746 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1750 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1751 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1753 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1754 G_CALLBACK (g_action_activate_null), a);
1756 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1757 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1758 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1762 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1763 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1765 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1766 G_CALLBACK (g_action_activate_null), a);
1768 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1769 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1770 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1773 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1776 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1777 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1778 "PsppireDialogActionSplit");
1780 g_signal_connect_swapped (ti, "clicked",
1781 G_CALLBACK (psppire_dialog_action_activate_null), a);
1782 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1783 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1784 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1788 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1789 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1790 "PsppireDialogActionWeight");
1792 g_signal_connect_swapped (ti, "clicked",
1793 G_CALLBACK (psppire_dialog_action_activate_null), a);
1794 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1795 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1796 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1800 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1801 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1803 g_signal_connect (de->ti_value_labels_button, "toggled",
1804 G_CALLBACK (on_labels_button_toggle), de);
1805 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1806 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1807 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1812 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1813 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1815 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1816 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1817 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1818 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1820 g_signal_connect (de->data_editor, "switch-page",
1821 G_CALLBACK (on_switch_page), de);
1823 gtk_widget_show (GTK_WIDGET (de->data_editor));
1824 gtk_widget_show_all (box);
1826 ll_push_head (&all_data_windows, &de->ll);
1831 psppire_data_window_dispose (GObject *object)
1833 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1835 if (dw->builder != NULL)
1837 g_object_unref (dw->builder);
1843 g_signal_handlers_disconnect_by_func (dw->dict,
1844 G_CALLBACK (enable_save), dw);
1845 g_signal_handlers_disconnect_by_func (dw->dict,
1846 G_CALLBACK (on_weight_change), dw);
1847 g_signal_handlers_disconnect_by_func (dw->dict,
1848 G_CALLBACK (on_filter_change), dw);
1849 g_signal_handlers_disconnect_by_func (dw->dict,
1850 G_CALLBACK (on_split_change), dw);
1852 g_object_unref (dw->dict);
1858 g_object_unref (dw->data_store);
1859 dw->data_store = NULL;
1862 if (dw->ll.next != NULL)
1864 ll_remove (&dw->ll);
1868 if (G_OBJECT_CLASS (parent_class)->dispose)
1869 G_OBJECT_CLASS (parent_class)->dispose (object);
1873 psppire_data_window_finalize (GObject *object)
1875 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1879 struct dataset *dataset = dw->dataset;
1880 struct session *session = dataset_session (dataset);
1884 dataset_set_callbacks (dataset, NULL, NULL);
1885 session_set_active_dataset (session, NULL);
1886 dataset_destroy (dataset);
1889 if (G_OBJECT_CLASS (parent_class)->finalize)
1890 G_OBJECT_CLASS (parent_class)->finalize (object);
1894 psppire_data_window_set_property (GObject *object,
1896 const GValue *value,
1899 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1904 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1907 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1913 psppire_data_window_get_property (GObject *object,
1918 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1923 g_value_set_pointer (value, window->dataset);
1926 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1934 psppire_data_window_new (struct dataset *ds)
1938 if (the_session == NULL)
1939 the_session = session_create (NULL);
1943 char *dataset_name = session_generate_dataset_name (the_session);
1944 ds = dataset_create (the_session, dataset_name);
1945 free (dataset_name);
1947 assert (dataset_session (ds) == the_session);
1951 psppire_data_window_get_type (),
1952 "description", _("Data Editor"),
1956 if (dataset_name (ds) != NULL)
1957 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1960 GApplication *app = g_application_get_default ();
1961 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1969 psppire_data_window_is_empty (PsppireDataWindow *dw)
1971 return psppire_dict_get_var_cnt (dw->dict) == 0;
1976 psppire_data_window_iface_init (PsppireWindowIface *iface)
1978 iface->save = save_file;
1979 iface->pick_filename = data_pick_filename;
1980 iface->load = load_file;
1987 psppire_default_data_window (void)
1989 if (ll_is_empty (&all_data_windows))
1990 create_data_window ();
1991 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1997 psppire_data_window_set_default (PsppireDataWindow *pdw)
1999 ll_remove (&pdw->ll);
2000 ll_push_head (&all_data_windows, &pdw->ll);
2004 psppire_data_window_undefault (PsppireDataWindow *pdw)
2006 ll_remove (&pdw->ll);
2007 ll_push_tail (&all_data_windows, &pdw->ll);
2013 psppire_data_window_for_dataset (struct dataset *ds)
2015 PsppireDataWindow *pdw;
2017 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2018 if (pdw->dataset == ds)
2025 create_data_window (void)
2027 GtkWidget *w = psppire_data_window_new (NULL);
2029 gtk_widget_show (w);
2031 return GTK_WINDOW (w);
2035 open_data_window (PsppireWindow *victim, const char *file_name,
2036 const char *encoding, gpointer hint)
2040 if (PSPPIRE_IS_DATA_WINDOW (victim)
2041 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
2043 window = GTK_WIDGET (victim);
2044 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
2047 window = psppire_data_window_new (NULL);
2049 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
2050 gtk_widget_show_all (window);
2051 return GTK_WINDOW (window);