1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014,
3 2016, 2017 Free Software Foundation
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include "data/dataset.h"
24 #include "data/session.h"
25 #include "language/lexer/lexer.h"
26 #include "libpspp/message.h"
27 #include "libpspp/str.h"
28 #include "ui/gui/builder-wrapper.h"
29 #include "ui/gui/entry-dialog.h"
30 #include "ui/gui/executor.h"
31 #include "ui/gui/help-menu.h"
32 #include "ui/gui/helper.h"
33 #include "ui/gui/helper.h"
34 #include "ui/gui/psppire-import-assistant.h"
35 #include "ui/gui/psppire-data-window.h"
36 #include "ui/gui/psppire-dialog-action.h"
37 #include "ui/gui/psppire-encoding-selector.h"
38 #include "ui/gui/psppire-syntax-window.h"
39 #include "ui/gui/psppire-window.h"
40 #include "ui/gui/windows-menu.h"
41 #include "ui/gui/goto-case-dialog.h"
42 #include "ui/gui/psppire.h"
43 #include "ui/syntax-gen.h"
45 #include "gl/c-strcase.h"
46 #include "gl/c-strcasestr.h"
47 #include "gl/xvasprintf.h"
49 #include "ui/gui/efficient-sheet/jmd-sheet.h"
51 #include "find-dialog.h"
52 #include "options-dialog.h"
53 #include "psppire-dialog-action-1sks.h"
54 #include "psppire-dialog-action-aggregate.h"
55 #include "psppire-dialog-action-autorecode.h"
56 #include "psppire-dialog-action-barchart.h"
57 #include "psppire-dialog-action-binomial.h"
58 #include "psppire-dialog-action-chisquare.h"
59 #include "psppire-dialog-action-comments.h"
60 #include "psppire-dialog-action-compute.h"
61 #include "psppire-dialog-action-correlation.h"
62 #include "psppire-dialog-action-count.h"
63 #include "psppire-dialog-action-crosstabs.h"
64 #include "psppire-dialog-action-descriptives.h"
65 #include "psppire-dialog-action-examine.h"
66 #include "psppire-dialog-action-factor.h"
67 #include "psppire-dialog-action-flip.h"
68 #include "psppire-dialog-action-frequencies.h"
69 #include "psppire-dialog-action-histogram.h"
70 #include "psppire-dialog-action-indep-samps.h"
71 #include "psppire-dialog-action-k-related.h"
72 #include "psppire-dialog-action-kmeans.h"
73 #include "psppire-dialog-action-logistic.h"
74 #include "psppire-dialog-action-means.h"
75 #include "psppire-dialog-action-oneway.h"
76 #include "psppire-dialog-action-paired.h"
77 #include "psppire-dialog-action-rank.h"
78 #include "psppire-dialog-action-recode-same.h"
79 #include "psppire-dialog-action-recode-different.h"
80 #include "psppire-dialog-action-regression.h"
81 #include "psppire-dialog-action-reliability.h"
82 #include "psppire-dialog-action-roc.h"
83 #include "psppire-dialog-action-runs.h"
84 #include "psppire-dialog-action-scatterplot.h"
85 #include "psppire-dialog-action-select.h"
86 #include "psppire-dialog-action-sort.h"
87 #include "psppire-dialog-action-split.h"
88 #include "psppire-dialog-action-tt1s.h"
89 #include "psppire-dialog-action-two-sample.h"
90 #include "psppire-dialog-action-univariate.h"
91 #include "psppire-dialog-action-var-info.h"
92 #include "psppire-dialog-action-weight.h"
96 #define _(msgid) gettext (msgid)
97 #define N_(msgid) msgid
99 struct session *the_session;
100 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
102 static void psppire_data_window_class_init (PsppireDataWindowClass *class);
103 static void psppire_data_window_init (PsppireDataWindow *data_editor);
106 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
108 static void psppire_data_window_dispose (GObject *object);
109 static void psppire_data_window_finalize (GObject *object);
110 static void psppire_data_window_set_property (GObject *object,
114 static void psppire_data_window_get_property (GObject *object,
120 psppire_data_window_get_type (void)
122 static GType psppire_data_window_type = 0;
124 if (!psppire_data_window_type)
126 static const GTypeInfo psppire_data_window_info =
128 sizeof (PsppireDataWindowClass),
131 (GClassInitFunc)psppire_data_window_class_init,
132 (GClassFinalizeFunc) NULL,
134 sizeof (PsppireDataWindow),
136 (GInstanceInitFunc) psppire_data_window_init,
139 static const GInterfaceInfo window_interface_info =
141 (GInterfaceInitFunc) psppire_data_window_iface_init,
146 psppire_data_window_type =
147 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
148 &psppire_data_window_info, 0);
151 g_type_add_interface_static (psppire_data_window_type,
152 PSPPIRE_TYPE_WINDOW_MODEL,
153 &window_interface_info);
156 return psppire_data_window_type;
159 static GObjectClass *parent_class ;
166 psppire_data_window_class_init (PsppireDataWindowClass *class)
168 GObjectClass *object_class = G_OBJECT_CLASS (class);
170 parent_class = g_type_class_peek_parent (class);
172 object_class->dispose = psppire_data_window_dispose;
173 object_class->finalize = psppire_data_window_finalize;
174 object_class->set_property = psppire_data_window_set_property;
175 object_class->get_property = psppire_data_window_get_property;
177 g_object_class_install_property (
178 object_class, PROP_DATASET,
179 g_param_spec_pointer ("dataset", "Dataset",
180 "'struct datset *' represented by the window",
181 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
186 /* Run the EXECUTE command. */
188 execute (PsppireDataWindow *dw)
190 execute_const_syntax_string (dw, "EXECUTE.");
194 transformation_change_callback (bool transformations_pending,
197 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
199 GtkWidget *status_label =
200 get_widget_assert (de->builder, "case-counter-area");
203 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de),
204 "transform-pending");
206 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
207 transformations_pending);
210 if ( transformations_pending)
211 gtk_label_set_text (GTK_LABEL (status_label),
212 _("Transformations Pending"));
214 gtk_label_set_text (GTK_LABEL (status_label), "");
217 /* Callback for when the dictionary changes its filter variable */
219 on_filter_change (GObject *o, gint filter_index, gpointer data)
221 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
223 GtkWidget *filter_status_area =
224 get_widget_assert (de->builder, "filter-use-status-area");
226 if ( filter_index == -1 )
228 gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
232 PsppireDict *dict = NULL;
233 struct variable *var ;
236 g_object_get (de->data_editor, "dictionary", &dict, NULL);
238 var = psppire_dict_get_variable (dict, filter_index);
240 text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
242 gtk_label_set_text (GTK_LABEL (filter_status_area), text);
248 /* Callback for when the dictionary changes its split variables */
250 on_split_change (PsppireDict *dict, gpointer data)
252 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
254 size_t n_split_vars = dict_get_split_cnt (dict->dict);
256 GtkWidget *split_status_area =
257 get_widget_assert (de->builder, "split-file-status-area");
259 if ( n_split_vars == 0 )
261 gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
267 const struct variable *const * split_vars =
268 dict_get_split_vars (dict->dict);
270 text = g_string_new (_("Split by "));
272 for (i = 0 ; i < n_split_vars - 1; ++i )
274 g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
276 g_string_append (text, var_get_name (split_vars[i]));
278 gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
280 g_string_free (text, TRUE);
287 /* Callback for when the dictionary changes its weights */
289 on_weight_change (GObject *o, gint weight_index, gpointer data)
291 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
293 GtkWidget *weight_status_area =
294 get_widget_assert (de->builder, "weight-status-area");
296 if ( weight_index == -1 )
298 gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
302 struct variable *var ;
303 PsppireDict *dict = NULL;
306 g_object_get (de->data_editor, "dictionary", &dict, NULL);
308 var = psppire_dict_get_variable (dict, weight_index);
310 text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
312 gtk_label_set_text (GTK_LABEL (weight_status_area), text);
320 dump_rm (GtkRecentManager *rm)
322 GList *items = gtk_recent_manager_get_items (rm);
326 g_print ("Recent Items:\n");
327 for (i = items; i; i = i->next)
329 GtkRecentInfo *ri = i->data;
331 g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
332 gtk_recent_info_get_short_name (ri),
333 gtk_recent_info_get_mime_type (ri),
334 gtk_recent_info_get_description (ri),
335 gtk_recent_info_get_uri (ri)
339 gtk_recent_info_unref (ri);
347 has_suffix (const gchar *name, const gchar *suffix)
349 size_t name_len = strlen (name);
350 size_t suffix_len = strlen (suffix);
351 return (name_len > suffix_len
352 && !c_strcasecmp (&name[name_len - suffix_len], suffix));
356 name_has_por_suffix (const gchar *name)
358 return has_suffix (name, ".por");
362 name_has_sav_suffix (const gchar *name)
364 return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
367 /* Returns true if NAME has a suffix which might denote a PSPP file */
369 name_has_suffix (const gchar *name)
371 return name_has_por_suffix (name) || name_has_sav_suffix (name);
375 load_file (PsppireWindow *de, const gchar *file_name, const char *encoding,
378 const char *mime_type = NULL;
379 gchar *syntax = NULL;
384 gchar *utf8_file_name;
385 struct string filename;
387 utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
389 if (NULL == utf8_file_name)
392 ds_init_empty (&filename);
393 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
395 g_free (utf8_file_name);
397 if (encoding && encoding[0])
398 syntax = g_strdup_printf ("GET FILE=%s ENCODING='%s'.",
399 ds_cstr (&filename), encoding);
401 syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
402 ds_destroy (&filename);
409 ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
410 lex_reader_for_string (syntax, "UTF-8"));
413 if (ok && syn == NULL)
415 if (name_has_por_suffix (file_name))
416 mime_type = "application/x-spss-por";
417 else if (name_has_sav_suffix (file_name))
418 mime_type = "application/x-spss-sav";
420 add_most_recent (file_name, mime_type, encoding);
427 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
429 if (format == PSPPIRE_DATA_WINDOW_SAV)
431 else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
437 /* Save DE to file */
439 save_file (PsppireWindow *w)
441 const gchar *file_name = NULL;
442 gchar *utf8_file_name = NULL;
444 struct string filename ;
445 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
448 file_name = psppire_window_get_filename (w);
450 fnx = g_string_new (file_name);
452 if ( ! name_has_suffix (fnx->str))
453 g_string_append (fnx, psppire_data_window_format_to_string (de->format));
455 ds_init_empty (&filename);
457 utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
459 g_string_free (fnx, TRUE);
461 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
462 g_free (utf8_file_name);
464 if (de->format == PSPPIRE_DATA_WINDOW_SAV)
465 syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
466 else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
467 syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
468 ds_cstr (&filename));
470 syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
472 ds_destroy (&filename);
474 g_free (execute_syntax_string (de, syntax));
479 display_dict (PsppireDataWindow *de)
481 execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
485 sysfile_info (PsppireDataWindow *de)
487 GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
489 if ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
491 struct string filename;
493 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
494 gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
497 const gchar *encoding = psppire_encoding_selector_get_encoding (
498 gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
502 ds_init_empty (&filename);
504 syntax_gen_string (&filename, ss_cstr (utf8_file_name));
506 g_free (utf8_file_name);
509 syntax = g_strdup_printf ("SYSFILE INFO %s ENCODING='%s'.",
510 ds_cstr (&filename), encoding);
512 syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
513 g_free (execute_syntax_string (de, syntax));
516 gtk_widget_destroy (dialog);
520 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
522 data_pick_filename (PsppireWindow *window)
524 GtkListStore *list_store;
525 GtkWidget *combo_box;
527 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
528 GtkFileFilter *filter;
530 gtk_file_chooser_dialog_new (_("Save"),
532 GTK_FILE_CHOOSER_ACTION_SAVE,
533 _("Cancel"), GTK_RESPONSE_CANCEL,
534 _("Save"), GTK_RESPONSE_ACCEPT,
537 g_object_set (dialog, "local-only", FALSE, NULL);
539 filter = gtk_file_filter_new ();
540 gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
541 gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
542 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
544 filter = gtk_file_filter_new ();
545 gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
546 gtk_file_filter_add_pattern (filter, "*.zsav");
547 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
549 filter = gtk_file_filter_new ();
550 gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
551 gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
552 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
554 filter = gtk_file_filter_new ();
555 gtk_file_filter_set_name (filter, _("All Files"));
556 gtk_file_filter_add_pattern (filter, "*");
557 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
558 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
561 GtkCellRenderer *cell;
566 list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
567 combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
569 gtk_list_store_append (list_store, &iter);
570 gtk_list_store_set (list_store, &iter,
571 0, PSPPIRE_DATA_WINDOW_SAV,
574 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
576 gtk_list_store_append (list_store, &iter);
577 gtk_list_store_set (list_store, &iter,
578 0, PSPPIRE_DATA_WINDOW_ZSAV,
579 1, _("Compressed System File"),
582 gtk_list_store_append (list_store, &iter);
583 gtk_list_store_set (list_store, &iter,
584 0, PSPPIRE_DATA_WINDOW_POR,
585 1, _("Portable File"),
588 label = gtk_label_new (_("Format:"));
590 cell = gtk_cell_renderer_text_new ();
591 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
592 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
595 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
596 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
597 gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
598 gtk_widget_show_all (hbox);
600 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
603 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
606 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
608 case GTK_RESPONSE_ACCEPT:
613 gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
619 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
620 gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
625 if ( ! name_has_suffix (filename->str))
626 g_string_append (filename,
627 psppire_data_window_format_to_string (format));
629 psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
631 g_string_free (filename, TRUE);
638 gtk_widget_destroy (dialog);
642 confirm_delete_dataset (PsppireDataWindow *de,
643 const char *old_dataset,
644 const char *new_dataset,
645 const char *existing_dataset)
650 dialog = gtk_message_dialog_new (
651 GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
652 _("Delete Existing Dataset?"));
654 gtk_message_dialog_format_secondary_text (
655 GTK_MESSAGE_DIALOG (dialog),
656 _("Renaming \"%s\" to \"%s\" will destroy the existing "
657 "dataset named \"%s\". Are you sure that you want to do this?"),
658 old_dataset, new_dataset, existing_dataset);
660 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
661 _("Cancel"), GTK_RESPONSE_CANCEL,
662 _("Delete"), GTK_RESPONSE_OK,
665 g_object_set (dialog, "icon-name", "pspp", NULL);
667 result = gtk_dialog_run (GTK_DIALOG (dialog));
669 gtk_widget_destroy (dialog);
671 return result == GTK_RESPONSE_OK;
675 on_rename_dataset (PsppireDataWindow *de)
677 struct dataset *ds = de->dataset;
678 struct session *session = dataset_session (ds);
679 const char *old_name = dataset_name (ds);
680 struct dataset *existing_dataset;
684 prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
686 new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
690 if (new_name == NULL)
693 existing_dataset = session_lookup_dataset (session, new_name);
694 if (existing_dataset == NULL || existing_dataset == ds
695 || confirm_delete_dataset (de, old_name, new_name,
696 dataset_name (existing_dataset)))
697 g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
705 status_bar_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
707 GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
709 GVariant *state = g_action_get_state (action);
710 const gboolean visible = g_variant_get_boolean (state);
711 g_action_change_state (action, g_variant_new_boolean (!visible));
713 gtk_widget_set_visible (statusbar, !visible);
718 grid_lines_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
720 GVariant *state = g_action_get_state (action);
721 const gboolean grid_visible = g_variant_get_boolean (state);
722 g_action_change_state (action, g_variant_new_boolean (!grid_visible));
724 psppire_data_editor_show_grid (de->data_editor, !grid_visible);
729 on_switch_page (GtkNotebook *notebook, GtkWidget *page, guint pn, gpointer ud)
731 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (ud);
733 GAction *action = g_action_map_lookup_action (G_ACTION_MAP (de), "view_dv");
738 g_action_change_state (action, g_variant_new_string ("DATA"));
739 gtk_widget_show (GTK_WIDGET (de->ti_insert_case));
740 gtk_widget_show (GTK_WIDGET (de->ti_jump_to_case));
741 gtk_widget_show (GTK_WIDGET (de->ti_find));
743 gtk_widget_show (GTK_WIDGET (de->mi_go_to_case));
744 gtk_widget_show (GTK_WIDGET (de->mi_insert_case));
745 gtk_widget_show (GTK_WIDGET (de->mi_find));
746 gtk_widget_show (GTK_WIDGET (de->mi_find_separator));
747 gtk_widget_show (GTK_WIDGET (de->mi_clear_cases));
752 g_action_change_state (action, g_variant_new_string ("VARS"));
753 gtk_widget_hide (GTK_WIDGET (de->ti_insert_case));
754 gtk_widget_hide (GTK_WIDGET (de->ti_jump_to_case));
755 gtk_widget_hide (GTK_WIDGET (de->ti_find));
757 gtk_widget_hide (GTK_WIDGET (de->mi_go_to_case));
758 gtk_widget_hide (GTK_WIDGET (de->mi_insert_case));
759 gtk_widget_hide (GTK_WIDGET (de->mi_find));
760 gtk_widget_hide (GTK_WIDGET (de->mi_find_separator));
761 gtk_widget_hide (GTK_WIDGET (de->mi_clear_cases));
769 activate_change_view (GAction *action, GVariant *param, PsppireDataWindow *de)
771 g_action_change_state (action, param);
772 GVariant *new_state = g_action_get_state (action);
774 const gchar *what = g_variant_get_string (new_state, NULL);
775 if (0 == g_strcmp0 (what, "DATA"))
777 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
779 else if (0 == g_strcmp0 (what, "VARS"))
781 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
788 fonts_activate (PsppireDataWindow *de)
790 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
791 GtkWidget *dialog = gtk_font_chooser_dialog_new (NULL, GTK_WINDOW (toplevel));
792 GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET(de->data_editor));
793 const PangoFontDescription *current_font ;
795 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, "font", ¤t_font, NULL);
797 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (dialog), current_font);
799 gtk_window_set_transient_for (GTK_WINDOW (dialog),
800 GTK_WINDOW (toplevel));
802 if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
804 PangoFontDescription* font_desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (dialog));
806 psppire_data_editor_set_font (de->data_editor, font_desc);
809 gtk_widget_hide (dialog);
814 /* Callback for the value labels action */
817 value_labels_activate (GAction *action, GVariant *param, PsppireDataWindow *de)
819 GVariant *v = g_action_get_state (action);
820 gboolean labels_active = g_variant_get_boolean (v);
821 g_action_change_state (action, g_variant_new_boolean (!labels_active));
823 GVariant *new_state = g_action_get_state (action);
824 labels_active = g_variant_get_boolean (new_state);
825 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
827 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (de->ti_value_labels_button),
832 on_labels_button_toggle (GtkToggleToolButton *ttb, PsppireDataWindow *de)
834 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "value_labels");
836 gboolean labels_active = gtk_toggle_tool_button_get_active (ttb);
838 g_action_change_state (a, g_variant_new_boolean (labels_active));
840 GVariant *new_state = g_action_get_state (a);
841 labels_active = g_variant_get_boolean (new_state);
842 g_object_set (de->data_editor, "value-labels", labels_active, NULL);
846 on_recent_data_select (GtkMenuShell *menushell,
847 PsppireWindow *window)
852 gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
854 file = g_filename_from_uri (uri, NULL, NULL);
858 open_data_window (window, file, NULL, NULL);
864 charset_from_mime_type (const char *mime_type)
870 if (mime_type == NULL)
873 charset = c_strcasestr (mime_type, "charset=");
881 /* Parse a "quoted-string" as defined by RFC 822. */
882 for (p++; *p != '\0' && *p != '"'; p++)
885 ds_put_byte (&s, *p);
886 else if (*++p != '\0')
887 ds_put_byte (&s, *p);
892 /* Parse a "token" as defined by RFC 2045. */
893 while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
894 ds_put_byte (&s, *p++);
896 if (!ds_is_empty (&s))
897 return ds_steal_cstr (&s);
904 on_recent_files_select (GtkMenuShell *menushell, gpointer user_data)
911 /* Get the file name and its encoding. */
912 item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
913 file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
914 encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
915 gtk_recent_info_unref (item);
917 se = psppire_syntax_window_new (encoding);
921 if ( psppire_window_load (PSPPIRE_WINDOW (se), file, encoding, NULL) )
922 gtk_widget_show (se);
924 gtk_widget_destroy (se);
930 set_unsaved (gpointer w)
932 psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
936 /* Only a data file with at least one variable can be saved. */
938 enable_save (PsppireDataWindow *dw)
940 gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
942 GAction *save_as = g_action_map_lookup_action (G_ACTION_MAP (dw), "save-as");
943 GAction *save = g_action_map_lookup_action (G_ACTION_MAP (dw), "save");
946 g_object_set (save, "enabled", enable, NULL);
949 g_object_set (save_as, "enabled", enable, NULL);
952 /* Initializes as much of a PsppireDataWindow as we can and must before the
953 dataset has been set.
955 In particular, the 'menu' member is required in case the "filename" property
956 is set before the "dataset" property: otherwise PsppireWindow will try to
957 modify the menu as part of the "filename" property_set() function and end up
958 with a Gtk-CRITICAL since 'menu' is NULL. */
960 psppire_data_window_init (PsppireDataWindow *de)
962 de->builder = builder_new ("data-editor.ui");
966 file_import (PsppireDataWindow *dw)
968 GtkWidget *w = psppire_import_assistant_new (GTK_WINDOW (dw));
969 PsppireImportAssistant *asst = PSPPIRE_IMPORT_ASSISTANT (w);
970 gtk_widget_show_all (w);
972 asst->main_loop = g_main_loop_new (NULL, TRUE);
973 g_main_loop_run (asst->main_loop);
974 g_main_loop_unref (asst->main_loop);
976 if (!asst->file_name)
979 switch (asst->response)
981 case GTK_RESPONSE_APPLY:
983 gchar *fn = g_path_get_basename (asst->file_name);
984 open_data_window (PSPPIRE_WINDOW (dw), fn, NULL, psppire_import_assistant_generate_syntax (asst));
988 case PSPPIRE_RESPONSE_PASTE:
989 free (paste_syntax_to_window (psppire_import_assistant_generate_syntax (asst)));
996 gtk_widget_destroy (GTK_WIDGET (asst));
1002 connect_dialog_action (GType type, PsppireDataWindow *de)
1004 GAction *act = g_object_new (type,
1008 g_action_map_add_action (G_ACTION_MAP (de), act);
1012 g_action_activate_null (GAction *a)
1014 g_action_activate (a, NULL);
1018 connect_action_to_menuitem (GActionMap *map, const gchar *action_name, GtkWidget *w, const gchar *accel)
1020 GAction *a = g_action_map_lookup_action (map, action_name);
1023 g_error ("Action \"%s\" not found in map", action_name);
1027 GtkApplication *app = GTK_APPLICATION (g_application_get_default());
1029 /* First set the label for the accellerator so that it appears
1031 GtkWidget *child = gtk_bin_get_child (GTK_BIN (w));
1033 GdkModifierType modifier;
1034 gtk_accelerator_parse (accel, &key, &modifier);
1035 gtk_accel_label_set_accel (GTK_ACCEL_LABEL (child), key, modifier);
1037 /* Now tell the application that it must do something when that
1038 key combination is pressed */
1039 const gchar *accels[2];
1043 gchar *detailed_action_name = NULL;
1044 if (GTK_IS_WINDOW (map))
1045 detailed_action_name = g_strdup_printf ("win.%s", action_name);
1046 else if (GTK_IS_APPLICATION (map))
1047 detailed_action_name = g_strdup_printf ("app.%s", action_name);
1049 gtk_application_set_accels_for_action (app,
1050 detailed_action_name,
1052 free (detailed_action_name);
1055 g_signal_connect_swapped (w, "activate", G_CALLBACK (g_action_activate_null), a);
1060 set_data_page (PsppireDataWindow *dw)
1062 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 1);
1063 gtk_notebook_set_current_page (GTK_NOTEBOOK (dw->data_editor), 0);
1068 on_cut (PsppireDataWindow *dw)
1070 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1071 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1073 PsppireDict *dict = NULL;
1074 g_object_get (dw->data_editor, "dictionary", &dict, NULL);
1077 JmdSheet *sheet = JMD_SHEET (dw->data_editor->data_sheet);
1078 JmdRange sel = *sheet->selection;
1080 GtkClipboard *clip =
1081 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1082 GDK_SELECTION_CLIPBOARD);
1084 /* Save the selected area to a string */
1085 GString *str = g_string_new ("");
1086 for (y = sel.start_y ; y <= sel.end_y; ++y)
1088 for (x = sel.start_x ; x <= sel.end_x; ++x)
1090 const struct variable * var = psppire_dict_get_variable (dict, x);
1091 gchar *s = psppire_data_store_get_string (dw->data_editor->data_store,
1093 g_string_append (str, s);
1094 g_string_append (str, "\t");
1097 g_string_append (str, "\n");
1100 gtk_clipboard_set_text (clip, str->str, str->len);
1101 g_string_free (str, TRUE);
1103 /* Now fill the selected area with SYSMIS */
1106 for (x = sel.start_x ; x <= sel.end_x; ++x)
1108 const struct variable * var = psppire_dict_get_variable (dict, x);
1109 for (y = sel.start_y ; y <= sel.end_y; ++y)
1111 psppire_data_store_set_value (dw->data_editor->data_store,
1123 on_copy (PsppireDataWindow *dw)
1125 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1126 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1128 GtkClipboard *clip =
1129 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1130 GDK_SELECTION_CLIPBOARD);
1132 jmd_sheet_set_clip (JMD_SHEET (dw->data_editor->data_sheet), clip);
1138 trf (GtkClipboard *clip,
1144 for (i = 0; i < n_atoms; ++i)
1146 g_print ("%s\n", gdk_atom_name (atoms[i]));
1151 on_paste (PsppireDataWindow *dw)
1153 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
1154 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1156 GtkClipboard *clip =
1157 gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
1158 GDK_SELECTION_CLIPBOARD);
1160 gtk_clipboard_request_targets (clip, trf, dw);
1166 on_clear_cases (PsppireDataWindow *dw)
1168 PsppireDataEditor *de = dw->data_editor;
1169 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1170 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1172 JmdRange *range = JMD_SHEET(de->data_sheet)->selection;
1173 psppire_data_store_delete_cases (de->data_store, range->start_y,
1174 range->end_y - range->start_y + 1);
1175 gtk_widget_queue_draw (GTK_WIDGET (de->data_sheet));
1180 on_clear_variables (PsppireDataWindow *dw)
1182 PsppireDataEditor *de = dw->data_editor;
1183 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1184 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1186 data_delete_variables (de);
1190 var_delete_variables (de);
1197 insert_variable (PsppireDataWindow *dw)
1199 PsppireDataEditor *de = dw->data_editor;
1200 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1202 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1204 JmdRange *range = JMD_SHEET(de->data_sheet)->selection;
1205 insert_new_variable_at_posn (de, range->start_x);
1209 JmdRange *range = JMD_SHEET(de->var_sheet)->selection;
1210 insert_new_variable_at_posn (de, range->start_y);
1217 insert_case_at_row (PsppireDataWindow *dw)
1219 PsppireDataEditor *de = dw->data_editor;
1220 JmdRange *range = JMD_SHEET(de->data_sheet)->selection;
1221 insert_new_case_at_posn (de, range->start_y);
1226 goto_case (PsppireDataWindow *dw)
1228 PsppireDataEditor *de = dw->data_editor;
1229 int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (de));
1230 if (p == PSPPIRE_DATA_EDITOR_DATA_VIEW)
1232 goto_case_dialog (JMD_SHEET (de->data_sheet));
1238 create_file_menu (PsppireDataWindow *dw)
1240 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_File"));
1241 GtkWidget *menu = gtk_menu_new ();
1244 GtkWidget *new = gtk_menu_item_new_with_mnemonic (_("_New"));
1245 gtk_menu_attach (GTK_MENU (menu), new, 0, 1, 0, 1);
1247 GtkWidget *new_menu = gtk_menu_new ();
1249 g_object_set (new, "submenu", new_menu, NULL);
1251 GtkWidget *syntax = gtk_menu_item_new_with_mnemonic (_("_Syntax"));
1252 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-syntax", syntax, 0);
1254 GtkWidget *data = gtk_menu_item_new_with_mnemonic (_("_Data"));
1255 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()), "new-data", data, 0);
1257 gtk_menu_attach (GTK_MENU (new_menu), syntax, 0, 1, 0, 1);
1258 gtk_menu_attach (GTK_MENU (new_menu), data, 0, 1, 1, 2);
1261 GtkWidget *open = gtk_menu_item_new_with_mnemonic (_("_Open"));
1262 connect_action_to_menuitem (G_ACTION_MAP (dw), "open", open, "<Ctrl>O");
1264 GtkWidget *import = gtk_menu_item_new_with_mnemonic (_("_Import Data..."));
1265 connect_action_to_menuitem (G_ACTION_MAP (dw), "file-import", import, 0);
1267 gtk_menu_attach (GTK_MENU (menu), open, 0, 1, 1, 2);
1268 gtk_menu_attach (GTK_MENU (menu), import, 0, 1, 2, 3);
1270 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 3, 4);
1272 GtkWidget *save = gtk_menu_item_new_with_mnemonic (_("_Save..."));
1273 connect_action_to_menuitem (G_ACTION_MAP (dw), "save", save, "<Ctrl>S");
1275 GtkWidget *save_as = gtk_menu_item_new_with_mnemonic (_("Save _As..."));
1276 connect_action_to_menuitem (G_ACTION_MAP (dw), "save-as", save_as, "<Shift><Ctrl>S");
1278 GtkWidget *rename_dataset = gtk_menu_item_new_with_mnemonic (_("_Rename Dataset..."));
1279 connect_action_to_menuitem (G_ACTION_MAP (dw), "rename-dataset", rename_dataset, 0);
1282 gtk_menu_attach (GTK_MENU (menu), save, 0, 1, 4, 5);
1283 gtk_menu_attach (GTK_MENU (menu), save_as, 0, 1, 5, 6);
1284 gtk_menu_attach (GTK_MENU (menu), rename_dataset, 0, 1, 6, 7);
1286 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 7, 8);
1289 GtkWidget *display_data = gtk_menu_item_new_with_mnemonic (_("_Display Data File Information"));
1290 gtk_menu_attach (GTK_MENU (menu), display_data, 0, 1, 8, 9);
1292 GtkWidget *dd_menu = gtk_menu_new ();
1294 g_object_set (display_data, "submenu", dd_menu, NULL);
1296 GtkWidget *working_file = gtk_menu_item_new_with_mnemonic (_("Working File"));
1297 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-working", working_file, 0);
1298 GtkWidget *external_file = gtk_menu_item_new_with_mnemonic (_("_External File..."));
1299 connect_action_to_menuitem (G_ACTION_MAP (dw), "info-external", external_file, 0);
1301 gtk_menu_attach (GTK_MENU (dd_menu), working_file, 0, 1, 0, 1);
1302 gtk_menu_attach (GTK_MENU (dd_menu), external_file, 0, 1, 1, 2);
1305 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 9, 10);
1308 GtkWidget *mi_data = gtk_menu_item_new_with_mnemonic (_("_Recently Used Data"));
1309 GtkWidget *mi_files = gtk_menu_item_new_with_mnemonic (_("Recently Used _Files"));
1311 GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1312 gtk_recent_manager_get_default ());
1314 GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1315 gtk_recent_manager_get_default ());
1317 gtk_menu_attach (GTK_MENU (menu), mi_data, 0, 1, 10, 11);
1318 gtk_menu_attach (GTK_MENU (menu), mi_files, 0, 1, 11, 12);
1320 g_object_set (menu_data, "show-tips", TRUE, NULL);
1321 g_object_set (menu_files, "show-tips", TRUE, NULL);
1323 g_object_set (mi_data, "submenu", menu_data, NULL);
1324 g_object_set (mi_files, "submenu", menu_files, NULL);
1327 GtkRecentFilter *filter = gtk_recent_filter_new ();
1329 gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1330 gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1332 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1334 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1337 g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), dw);
1340 GtkRecentFilter *filter = gtk_recent_filter_new ();
1342 gtk_recent_filter_add_pattern (filter, "*.sps");
1343 gtk_recent_filter_add_pattern (filter, "*.SPS");
1345 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1347 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1350 g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), dw);
1353 gtk_menu_attach (GTK_MENU (menu), gtk_separator_menu_item_new (), 0, 1, 12, 13);
1356 GtkWidget *quit = gtk_menu_item_new_with_mnemonic (_("_Quit"));
1357 gtk_menu_attach (GTK_MENU (menu), quit, 0, 1, 13, 14);
1359 connect_action_to_menuitem (G_ACTION_MAP (g_application_get_default ()),
1360 "quit", quit, "<Ctrl>Q");
1363 g_object_set (menuitem, "submenu", menu, NULL);
1364 gtk_widget_show_all (menuitem);
1371 create_edit_menu (PsppireDataWindow *dw)
1374 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit"));
1376 GtkWidget *menu = gtk_menu_new ();
1378 dw->mi_insert_var = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
1379 dw->mi_insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
1380 GtkWidget *go_to_variable = gtk_menu_item_new_with_mnemonic (_("_Go To Variable..."));
1381 dw->mi_go_to_case = gtk_menu_item_new_with_mnemonic (_("_Go To Case..."));
1383 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_var, 0, 1, i, i + 1); ++i;
1384 gtk_menu_attach (GTK_MENU (menu), dw->mi_insert_case, 0, 1, i, i + 1); ++i;
1386 g_signal_connect_swapped (dw->mi_insert_case, "activate", G_CALLBACK (insert_case_at_row), dw);
1387 g_signal_connect_swapped (dw->mi_go_to_case, "activate", G_CALLBACK (goto_case), dw);
1388 g_signal_connect_swapped (dw->mi_insert_var, "activate", G_CALLBACK (insert_variable), dw);
1390 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (dw), "PsppireDialogActionVarInfo");
1392 g_signal_connect_swapped (go_to_variable, "activate", G_CALLBACK (psppire_dialog_action_activate_null), a);
1394 gtk_menu_attach (GTK_MENU (menu), go_to_variable, 0, 1, i, i + 1); ++i;
1395 gtk_menu_attach (GTK_MENU (menu), dw->mi_go_to_case, 0, 1, i, i + 1); ++i;
1398 GtkAccelGroup *ag = gtk_accel_group_new ();
1400 dw->mi_edit_separator = gtk_separator_menu_item_new ();
1401 gtk_menu_attach (GTK_MENU (menu), dw->mi_edit_separator, 0, 1, i, i + 1); ++i;
1403 dw->mi_cut = gtk_menu_item_new_with_mnemonic (_("Cu_t"));
1404 gtk_menu_attach (GTK_MENU (menu), dw->mi_cut, 0, 1, i, i + 1); ++i;
1405 g_signal_connect_swapped (dw->mi_cut, "activate", G_CALLBACK (on_cut), dw);
1407 gtk_window_add_accel_group (GTK_WINDOW (dw), ag);
1408 gtk_widget_add_accelerator (dw->mi_cut, "activate", ag,
1409 'X', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1411 dw->mi_copy = gtk_menu_item_new_with_mnemonic (_("_Copy"));
1412 gtk_menu_attach (GTK_MENU (menu), dw->mi_copy, 0, 1, i, i + 1); ++i;
1413 g_signal_connect_swapped (dw->mi_copy, "activate", G_CALLBACK (on_copy), dw);
1414 gtk_widget_add_accelerator (dw->mi_copy, "activate", ag,
1415 'C', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1417 dw->mi_paste = gtk_menu_item_new_with_mnemonic (_("_Paste"));
1418 gtk_menu_attach (GTK_MENU (menu), dw->mi_paste, 0, 1, i, i + 1); ++i;
1419 g_signal_connect_swapped (dw->mi_paste, "activate", G_CALLBACK (on_paste), dw);
1420 gtk_widget_add_accelerator (dw->mi_paste, "activate", ag,
1421 'V', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
1423 dw->mi_clear_variables = gtk_menu_item_new_with_mnemonic (_("Clear _Variables"));
1424 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_variables, 0, 1, i, i + 1); ++i;
1425 g_signal_connect_swapped (dw->mi_clear_variables, "activate", G_CALLBACK (on_clear_variables), dw);
1427 dw->mi_clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
1428 gtk_menu_attach (GTK_MENU (menu), dw->mi_clear_cases, 0, 1, i, i + 1); ++i;
1429 g_signal_connect_swapped (dw->mi_clear_cases, "activate", G_CALLBACK (on_clear_cases), dw);
1433 dw->mi_find_separator = gtk_separator_menu_item_new ();
1434 gtk_menu_attach (GTK_MENU (menu), dw->mi_find_separator, 0, 1, i, i + 1); ++i;
1436 dw->mi_find = gtk_menu_item_new_with_mnemonic (_("_Find..."));
1437 g_signal_connect_swapped (dw->mi_find, "activate", G_CALLBACK (find_dialog), dw);
1438 gtk_menu_attach (GTK_MENU (menu), dw->mi_find, 0, 1, i, i + 1); ++i;
1442 dw->mi_options = gtk_menu_item_new_with_mnemonic (_("_Options..."));
1443 g_signal_connect_swapped (dw->mi_options, "activate",
1444 G_CALLBACK (options_dialog), dw);
1445 gtk_menu_attach (GTK_MENU (menu), dw->mi_options, 0, 1, i, i + 1); ++i;
1448 g_object_set (menuitem, "submenu", menu, NULL);
1450 gtk_widget_show_all (menuitem);
1456 psppire_data_window_finish_init (PsppireDataWindow *de,
1459 static const struct dataset_callbacks cbs =
1461 set_unsaved, /* changed */
1462 transformation_change_callback, /* transformations_changed */
1469 GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1472 de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
1473 de->data_store = psppire_data_store_new (de->dict);
1474 psppire_data_store_set_reader (de->data_store, NULL);
1476 GObject *menu = get_object_assert (de->builder, "data-editor-menu", G_TYPE_MENU);
1477 menubar = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu));
1478 gtk_widget_show (menubar);
1480 hb = gtk_toolbar_new ();
1481 sb = get_widget_assert (de->builder, "status-bar");
1484 PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
1486 g_signal_connect (de, "realize",
1487 G_CALLBACK (set_data_page), de);
1489 g_signal_connect_swapped (de->data_store, "case-changed",
1490 G_CALLBACK (set_unsaved), de);
1492 dataset_set_callbacks (de->dataset, &cbs, de);
1494 connect_help (de->builder);
1496 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
1497 gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
1498 gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
1499 gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
1501 gtk_container_add (GTK_CONTAINER (de), box);
1503 g_signal_connect (de->dict, "weight-changed",
1504 G_CALLBACK (on_weight_change),
1507 g_signal_connect (de->dict, "filter-changed",
1508 G_CALLBACK (on_filter_change),
1511 g_signal_connect (de->dict, "split-changed",
1512 G_CALLBACK (on_split_change),
1515 g_signal_connect_swapped (de->dict, "items-changed",
1516 G_CALLBACK (enable_save), de);
1517 g_signal_connect_swapped (de->dict, "variable-inserted",
1518 G_CALLBACK (enable_save), de);
1519 g_signal_connect_swapped (de->dict, "variable-deleted",
1520 G_CALLBACK (enable_save), de);
1523 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SORT, de);
1524 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SPLIT, de);
1525 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FLIP, de);
1526 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AGGREGATE, de);
1527 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_WEIGHT, de);
1529 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMPUTE, de);
1530 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COUNT, de);
1531 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_AUTORECODE, de);
1532 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RANK, de);
1533 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SELECT, de);
1534 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, de);
1535 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, de);
1538 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_DESCRIPTIVES, de);
1539 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FREQUENCIES, de);
1540 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_EXAMINE, de);
1541 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CROSSTABS, de);
1543 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_INDEP_SAMPS, de);
1544 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_PAIRED, de);
1546 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_MEANS, de);
1547 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TT1S, de);
1549 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ONEWAY, de);
1550 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_UNIVARIATE, de);
1551 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_KMEANS, de);
1552 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_FACTOR, de);
1553 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CORRELATION, de);
1554 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RELIABILITY, de);
1555 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_REGRESSION, de);
1556 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_LOGISTIC, de);
1557 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_ROC, de);
1559 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_COMMENTS, de);
1560 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_VAR_INFO, de);
1562 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BARCHART, de);
1563 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_SCATTERPLOT, de);
1564 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_HISTOGRAM, de);
1566 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_CHISQUARE, de);
1567 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_BINOMIAL, de);
1568 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_RUNS, de);
1569 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_1SKS, de);
1570 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_TWO_SAMPLE, de);
1571 connect_dialog_action (PSPPIRE_TYPE_DIALOG_ACTION_K_RELATED, de);
1574 GSimpleAction *file_import_action = g_simple_action_new ("file-import", NULL);
1575 g_signal_connect_swapped (file_import_action, "activate", G_CALLBACK (file_import), de);
1576 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (file_import_action));
1580 GSimpleAction *save = g_simple_action_new ("save", NULL);
1581 g_signal_connect_swapped (save, "activate", G_CALLBACK (psppire_window_save), de);
1582 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save));
1586 GSimpleAction *open = g_simple_action_new ("open", NULL);
1587 g_signal_connect_swapped (open, "activate", G_CALLBACK (psppire_window_open), de);
1588 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (open));
1592 GSimpleAction *save_as = g_simple_action_new ("save-as", NULL);
1593 g_signal_connect_swapped (save_as, "activate", G_CALLBACK (psppire_window_save_as), de);
1594 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (save_as));
1598 GSimpleAction *rename_dataset_act = g_simple_action_new ("rename-dataset", NULL);
1599 g_signal_connect_swapped (rename_dataset_act, "activate",
1600 G_CALLBACK (on_rename_dataset), de);
1601 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (rename_dataset_act));
1605 GSimpleAction *info_working = g_simple_action_new ("info-working", NULL);
1606 g_signal_connect_swapped (info_working, "activate", G_CALLBACK (display_dict), de);
1607 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_working));
1610 GSimpleAction *info_external = g_simple_action_new ("info-external", NULL);
1611 g_signal_connect_swapped (info_external, "activate", G_CALLBACK (sysfile_info), de);
1612 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (info_external));
1616 GSimpleAction *act_statusbar = g_simple_action_new_stateful ("statusbar", NULL, g_variant_new_boolean (TRUE));
1617 g_signal_connect (act_statusbar, "activate", G_CALLBACK (status_bar_activate), de);
1618 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_statusbar));
1622 GSimpleAction *act_gridlines = g_simple_action_new_stateful ("gridlines", NULL, g_variant_new_boolean (TRUE));
1623 g_signal_connect (act_gridlines, "activate", G_CALLBACK (grid_lines_activate), de);
1624 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_gridlines));
1629 GSimpleAction *act_view_data = g_simple_action_new_stateful ("view_dv", G_VARIANT_TYPE_STRING,
1630 g_variant_new_string ("DATA"));
1631 g_signal_connect (act_view_data, "activate", G_CALLBACK (activate_change_view), de);
1632 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_view_data));
1636 GSimpleAction *act_fonts = g_simple_action_new ("fonts", NULL);
1637 g_signal_connect_swapped (act_fonts, "activate", G_CALLBACK (fonts_activate), de);
1638 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_fonts));
1642 GSimpleAction *act_value_labels =
1643 g_simple_action_new_stateful ("value_labels", NULL,
1644 g_variant_new_boolean (FALSE));
1645 g_signal_connect (act_value_labels, "activate", G_CALLBACK (value_labels_activate), de);
1646 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_value_labels));
1650 GSimpleAction *act_transform_pending = g_simple_action_new ("transform-pending", NULL);
1651 g_signal_connect_swapped (act_transform_pending, "activate", G_CALLBACK (execute), de);
1652 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_transform_pending));
1656 GSimpleAction *act_jump_to_variable = g_simple_action_new ("jump-to-variable", NULL);
1657 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_variable));
1661 GSimpleAction *act_insert_variable = g_simple_action_new ("insert-variable", NULL);
1662 g_signal_connect_swapped (act_insert_variable, "activate", G_CALLBACK (insert_variable), de);
1663 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_variable));
1667 GSimpleAction *act_jump_to_case = g_simple_action_new ("jump-to-case", NULL);
1668 g_signal_connect_swapped (act_jump_to_case, "activate", G_CALLBACK (goto_case), de);
1669 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_jump_to_case));
1673 GSimpleAction *act_insert_case = g_simple_action_new ("insert-case", NULL);
1674 g_signal_connect_swapped (act_insert_case, "activate", G_CALLBACK (insert_case_at_row), de);
1675 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (act_insert_case));
1679 GSimpleAction *find = g_simple_action_new ("find", NULL);
1680 g_signal_connect_swapped (find, "activate", G_CALLBACK (find_dialog), de);
1681 g_action_map_add_action (G_ACTION_MAP (de), G_ACTION (find));
1687 GtkToolItem *ti = gtk_tool_button_new (NULL, "Open");
1688 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_open), de);
1689 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1690 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-open-data");
1694 GtkToolItem *ti = gtk_tool_button_new (NULL, "Save");
1695 g_signal_connect_swapped (ti, "clicked", G_CALLBACK (psppire_window_save), de);
1696 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1697 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "file-save-data");
1700 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1703 de->ti_jump_to_variable = gtk_tool_button_new (NULL, "Goto Var");
1705 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "PsppireDialogActionVarInfo");
1707 g_signal_connect_swapped (de->ti_jump_to_variable, "clicked",
1708 G_CALLBACK (psppire_dialog_action_activate_null), a);
1710 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_variable, idx++);
1711 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_variable), "edit-go-to-variable");
1712 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_variable), _("Jump to variable"));
1716 de->ti_jump_to_case = gtk_tool_button_new (NULL, "Jump to Case");
1718 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "jump-to-case");
1720 g_signal_connect_swapped (de->ti_jump_to_case, "clicked",
1721 G_CALLBACK (g_action_activate_null), a);
1723 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_jump_to_case, idx++);
1724 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_jump_to_case), "edit-go-to-case");
1725 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_jump_to_case), _("Jump to a case in the data sheet"));
1729 de->ti_find = gtk_tool_button_new (NULL, "Find");
1731 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "find");
1733 g_signal_connect_swapped (de->ti_find, "clicked",
1734 G_CALLBACK (g_action_activate_null), a);
1737 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_find, idx++);
1738 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_find), "edit-find");
1739 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_find), _("Search for values in the data"));
1743 de->ti_insert_case = gtk_tool_button_new (NULL, "Create Case");
1744 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-case");
1746 g_signal_connect_swapped (de->ti_insert_case, "clicked",
1747 G_CALLBACK (g_action_activate_null), a);
1749 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_case, idx++);
1750 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_case), "edit-insert-case");
1751 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_case), _("Create a new case at the current position"));
1755 de->ti_insert_variable = gtk_tool_button_new (NULL, "Create Variable");
1756 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de), "insert-variable");
1758 g_signal_connect_swapped (de->ti_insert_variable, "clicked",
1759 G_CALLBACK (g_action_activate_null), a);
1761 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_insert_variable, idx++);
1762 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_insert_variable), "edit-insert-variable");
1763 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_insert_variable), _("Create a new variable at the current position"));
1766 gtk_toolbar_insert (GTK_TOOLBAR (hb), gtk_separator_tool_item_new (), idx++);
1769 GtkToolItem *ti = gtk_tool_button_new (NULL, "Split");
1770 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1771 "PsppireDialogActionSplit");
1773 g_signal_connect_swapped (ti, "clicked",
1774 G_CALLBACK (psppire_dialog_action_activate_null), a);
1775 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1776 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-split-file");
1777 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Split the active dataset"));
1781 GtkToolItem *ti = gtk_tool_button_new (NULL, "Weight");
1782 GAction *a = g_action_map_lookup_action (G_ACTION_MAP (de),
1783 "PsppireDialogActionWeight");
1785 g_signal_connect_swapped (ti, "clicked",
1786 G_CALLBACK (psppire_dialog_action_activate_null), a);
1787 gtk_toolbar_insert (GTK_TOOLBAR (hb), ti, idx++);
1788 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (ti), "data-weight-cases");
1789 gtk_widget_set_tooltip_text (GTK_WIDGET (ti), _("Weight cases by variable"));
1793 de->ti_value_labels_button = gtk_toggle_tool_button_new ();
1794 gtk_tool_button_set_label (GTK_TOOL_BUTTON (de->ti_value_labels_button),
1796 g_signal_connect (de->ti_value_labels_button, "toggled",
1797 G_CALLBACK (on_labels_button_toggle), de);
1798 gtk_toolbar_insert (GTK_TOOLBAR (hb), de->ti_value_labels_button, idx++);
1799 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (de->ti_value_labels_button), "view-value-labels");
1800 gtk_widget_set_tooltip_text (GTK_WIDGET (de->ti_value_labels_button), _("Show/hide value labels"));
1805 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1806 gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1808 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_file_menu (de), 0);
1809 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), create_edit_menu (de), 1);
1810 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_windows_menu (GTK_WINDOW (de)));
1811 gtk_menu_shell_append (GTK_MENU_SHELL (menubar), create_help_menu (GTK_WINDOW (de)));
1813 g_signal_connect (de->data_editor, "switch-page",
1814 G_CALLBACK (on_switch_page), de);
1816 gtk_widget_show (GTK_WIDGET (de->data_editor));
1817 gtk_widget_show_all (box);
1819 ll_push_head (&all_data_windows, &de->ll);
1824 psppire_data_window_dispose (GObject *object)
1826 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1828 if (dw->builder != NULL)
1830 g_object_unref (dw->builder);
1836 g_signal_handlers_disconnect_by_func (dw->dict,
1837 G_CALLBACK (enable_save), dw);
1838 g_signal_handlers_disconnect_by_func (dw->dict,
1839 G_CALLBACK (on_weight_change), dw);
1840 g_signal_handlers_disconnect_by_func (dw->dict,
1841 G_CALLBACK (on_filter_change), dw);
1842 g_signal_handlers_disconnect_by_func (dw->dict,
1843 G_CALLBACK (on_split_change), dw);
1845 g_object_unref (dw->dict);
1851 g_object_unref (dw->data_store);
1852 dw->data_store = NULL;
1855 if (dw->ll.next != NULL)
1857 ll_remove (&dw->ll);
1861 if (G_OBJECT_CLASS (parent_class)->dispose)
1862 G_OBJECT_CLASS (parent_class)->dispose (object);
1866 psppire_data_window_finalize (GObject *object)
1868 PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1872 struct dataset *dataset = dw->dataset;
1873 struct session *session = dataset_session (dataset);
1877 dataset_set_callbacks (dataset, NULL, NULL);
1878 session_set_active_dataset (session, NULL);
1879 dataset_destroy (dataset);
1882 if (G_OBJECT_CLASS (parent_class)->finalize)
1883 G_OBJECT_CLASS (parent_class)->finalize (object);
1887 psppire_data_window_set_property (GObject *object,
1889 const GValue *value,
1892 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1897 psppire_data_window_finish_init (window, g_value_get_pointer (value));
1900 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1906 psppire_data_window_get_property (GObject *object,
1911 PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1916 g_value_set_pointer (value, window->dataset);
1919 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1927 psppire_data_window_new (struct dataset *ds)
1931 if (the_session == NULL)
1932 the_session = session_create (NULL);
1936 char *dataset_name = session_generate_dataset_name (the_session);
1937 ds = dataset_create (the_session, dataset_name);
1938 free (dataset_name);
1940 assert (dataset_session (ds) == the_session);
1944 psppire_data_window_get_type (),
1945 "description", _("Data Editor"),
1949 if (dataset_name (ds) != NULL)
1950 g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1953 GApplication *app = g_application_get_default ();
1954 gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (dw));
1962 psppire_data_window_is_empty (PsppireDataWindow *dw)
1964 return psppire_dict_get_var_cnt (dw->dict) == 0;
1969 psppire_data_window_iface_init (PsppireWindowIface *iface)
1971 iface->save = save_file;
1972 iface->pick_filename = data_pick_filename;
1973 iface->load = load_file;
1980 psppire_default_data_window (void)
1982 if (ll_is_empty (&all_data_windows))
1983 create_data_window ();
1984 return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1990 psppire_data_window_set_default (PsppireDataWindow *pdw)
1992 ll_remove (&pdw->ll);
1993 ll_push_head (&all_data_windows, &pdw->ll);
1997 psppire_data_window_undefault (PsppireDataWindow *pdw)
1999 ll_remove (&pdw->ll);
2000 ll_push_tail (&all_data_windows, &pdw->ll);
2006 psppire_data_window_for_dataset (struct dataset *ds)
2008 PsppireDataWindow *pdw;
2010 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2011 if (pdw->dataset == ds)
2018 psppire_data_window_for_data_store (PsppireDataStore *data_store)
2020 PsppireDataWindow *pdw;
2022 ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
2023 if (pdw->data_store == data_store)
2030 create_data_window (void)
2032 GtkWidget *w = psppire_data_window_new (NULL);
2034 gtk_widget_show (w);
2036 return GTK_WINDOW (w);
2040 open_data_window (PsppireWindow *victim, const char *file_name,
2041 const char *encoding, gpointer hint)
2045 if (PSPPIRE_IS_DATA_WINDOW (victim)
2046 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
2048 window = GTK_WIDGET (victim);
2049 gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
2052 window = psppire_data_window_new (NULL);
2054 psppire_window_load (PSPPIRE_WINDOW (window), file_name, encoding, hint);
2055 gtk_widget_show_all (window);
2056 return GTK_WINDOW (window);