psppire-data-window: Set default filter in File|Save As to show all files.
[pspp] / src / ui / gui / psppire-data-window.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013  Free Software Foundation
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include <gtk/gtk.h>
20 #include <stdlib.h>
21
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/aggregate-dialog.h"
28 #include "ui/gui/autorecode-dialog.h"
29 #include "ui/gui/builder-wrapper.h"
30 #include "ui/gui/comments-dialog.h"
31 #include "ui/gui/entry-dialog.h"
32 #include "ui/gui/executor.h"
33 #include "ui/gui/help-menu.h"
34 #include "ui/gui/helper.h"
35 #include "ui/gui/helper.h"
36 #include "ui/gui/psppire-data-window.h"
37 #include "ui/gui/psppire-dialog-action.h"
38 #include "ui/gui/psppire-syntax-window.h"
39 #include "ui/gui/psppire-window.h"
40 #include "ui/gui/psppire.h"
41 #include "ui/gui/recode-dialog.h"
42 #include "ui/gui/select-cases-dialog.h"
43 #include "ui/gui/split-file-dialog.h"
44 #include "ui/gui/text-data-import-dialog.h"
45 #include "ui/gui/weight-cases-dialog.h"
46 #include "ui/syntax-gen.h"
47
48 #include "gl/c-strcase.h"
49 #include "gl/c-strcasestr.h"
50 #include "gl/xvasprintf.h"
51
52 #include <gettext.h>
53 #define _(msgid) gettext (msgid)
54 #define N_(msgid) msgid
55
56 struct session *the_session;
57 struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
58
59 static void psppire_data_window_class_init    (PsppireDataWindowClass *class);
60 static void psppire_data_window_init          (PsppireDataWindow      *data_editor);
61
62
63 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
64
65 static void psppire_data_window_dispose (GObject *object);
66 static void psppire_data_window_finalize (GObject *object);
67 static void psppire_data_window_set_property (GObject         *object,
68                                               guint            prop_id,
69                                               const GValue    *value,
70                                               GParamSpec      *pspec);
71 static void psppire_data_window_get_property (GObject         *object,
72                                               guint            prop_id,
73                                               GValue          *value,
74                                               GParamSpec      *pspec);
75
76 static guint psppire_data_window_add_ui (PsppireDataWindow *, GtkUIManager *);
77 static void psppire_data_window_remove_ui (PsppireDataWindow *,
78                                            GtkUIManager *, guint);
79
80 GType
81 psppire_data_window_get_type (void)
82 {
83   static GType psppire_data_window_type = 0;
84
85   if (!psppire_data_window_type)
86     {
87       static const GTypeInfo psppire_data_window_info =
88         {
89           sizeof (PsppireDataWindowClass),
90           NULL,
91           NULL,
92           (GClassInitFunc)psppire_data_window_class_init,
93           (GClassFinalizeFunc) NULL,
94           NULL,
95           sizeof (PsppireDataWindow),
96           0,
97           (GInstanceInitFunc) psppire_data_window_init,
98         };
99
100       static const GInterfaceInfo window_interface_info =
101         {
102           (GInterfaceInitFunc) psppire_data_window_iface_init,
103           NULL,
104           NULL
105         };
106
107       psppire_data_window_type =
108         g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireDataWindow",
109                                 &psppire_data_window_info, 0);
110
111
112       g_type_add_interface_static (psppire_data_window_type,
113                                    PSPPIRE_TYPE_WINDOW_MODEL,
114                                    &window_interface_info);
115     }
116
117   return psppire_data_window_type;
118 }
119
120 static GObjectClass *parent_class ;
121
122 enum {
123     PROP_DATASET = 1
124 };
125
126 static void
127 psppire_data_window_class_init (PsppireDataWindowClass *class)
128 {
129   GObjectClass *object_class = G_OBJECT_CLASS (class);
130
131   parent_class = g_type_class_peek_parent (class);
132
133   object_class->dispose = psppire_data_window_dispose;
134   object_class->finalize = psppire_data_window_finalize;
135   object_class->set_property = psppire_data_window_set_property;
136   object_class->get_property = psppire_data_window_get_property;
137
138   g_object_class_install_property (
139     object_class, PROP_DATASET,
140     g_param_spec_pointer ("dataset", "Dataset",
141                           "'struct datset *' represented by the window",
142                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
143 }
144 \f
145 /* Run the EXECUTE command. */
146 static void
147 execute (PsppireDataWindow *dw)
148 {
149   execute_const_syntax_string (dw, "EXECUTE.");
150 }
151
152 static void
153 transformation_change_callback (bool transformations_pending,
154                                 gpointer data)
155 {
156   PsppireDataWindow  *de = PSPPIRE_DATA_WINDOW (data);
157
158   GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
159
160   GtkWidget *menuitem =
161     gtk_ui_manager_get_widget (uim,"/ui/menubar/transform/transform_run-pending");
162
163   GtkWidget *status_label  =
164     get_widget_assert (de->builder, "case-counter-area");
165
166   gtk_widget_set_sensitive (menuitem, transformations_pending);
167
168
169   if ( transformations_pending)
170     gtk_label_set_text (GTK_LABEL (status_label),
171                         _("Transformations Pending"));
172   else
173     gtk_label_set_text (GTK_LABEL (status_label), "");
174 }
175
176 /* Callback for when the dictionary changes its filter variable */
177 static void
178 on_filter_change (GObject *o, gint filter_index, gpointer data)
179 {
180   PsppireDataWindow  *de = PSPPIRE_DATA_WINDOW (data);
181
182   GtkWidget *filter_status_area =
183     get_widget_assert (de->builder, "filter-use-status-area");
184
185   if ( filter_index == -1 )
186     {
187       gtk_label_set_text (GTK_LABEL (filter_status_area), _("Filter off"));
188     }
189   else
190     {
191       PsppireDict *dict = NULL;
192       struct variable *var ;
193       gchar *text ;
194
195       g_object_get (de->data_editor, "dictionary", &dict, NULL);
196
197       var = psppire_dict_get_variable (dict, filter_index);
198
199       text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
200
201       gtk_label_set_text (GTK_LABEL (filter_status_area), text);
202
203       g_free (text);
204     }
205 }
206
207 /* Callback for when the dictionary changes its split variables */
208 static void
209 on_split_change (PsppireDict *dict, gpointer data)
210 {
211   PsppireDataWindow  *de = PSPPIRE_DATA_WINDOW (data);
212
213   size_t n_split_vars = dict_get_split_cnt (dict->dict);
214
215   GtkWidget *split_status_area =
216     get_widget_assert (de->builder, "split-file-status-area");
217
218   if ( n_split_vars == 0 )
219     {
220       gtk_label_set_text (GTK_LABEL (split_status_area), _("No Split"));
221     }
222   else
223     {
224       gint i;
225       GString *text;
226       const struct variable *const * split_vars =
227         dict_get_split_vars (dict->dict);
228
229       text = g_string_new (_("Split by "));
230
231       for (i = 0 ; i < n_split_vars - 1; ++i )
232         {
233           g_string_append_printf (text, "%s, ", var_get_name (split_vars[i]));
234         }
235       g_string_append (text, var_get_name (split_vars[i]));
236
237       gtk_label_set_text (GTK_LABEL (split_status_area), text->str);
238
239       g_string_free (text, TRUE);
240     }
241 }
242
243
244
245
246 /* Callback for when the dictionary changes its weights */
247 static void
248 on_weight_change (GObject *o, gint weight_index, gpointer data)
249 {
250   PsppireDataWindow  *de = PSPPIRE_DATA_WINDOW (data);
251
252   GtkWidget *weight_status_area =
253     get_widget_assert (de->builder, "weight-status-area");
254
255   if ( weight_index == -1 )
256     {
257       gtk_label_set_text (GTK_LABEL (weight_status_area), _("Weights off"));
258     }
259   else
260     {
261       struct variable *var ;
262       PsppireDict *dict = NULL;
263       gchar *text;
264
265       g_object_get (de->data_editor, "dictionary", &dict, NULL);
266
267       var = psppire_dict_get_variable (dict, weight_index);
268
269       text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
270
271       gtk_label_set_text (GTK_LABEL (weight_status_area), text);
272
273       g_free (text);
274     }
275 }
276
277 #if 0
278 static void
279 dump_rm (GtkRecentManager *rm)
280 {
281   GList *items = gtk_recent_manager_get_items (rm);
282
283   GList *i;
284
285   g_print ("Recent Items:\n");
286   for (i = items; i; i = i->next)
287     {
288       GtkRecentInfo *ri = i->data;
289
290       g_print ("Item: %s (Mime: %s) (Desc: %s) (URI: %s)\n",
291                gtk_recent_info_get_short_name (ri),
292                gtk_recent_info_get_mime_type (ri),
293                gtk_recent_info_get_description (ri),
294                gtk_recent_info_get_uri (ri)
295                );
296
297
298       gtk_recent_info_unref (ri);
299     }
300
301   g_list_free (items);
302 }
303 #endif
304
305 static gboolean
306 has_suffix (const gchar *name, const gchar *suffix)
307 {
308   size_t name_len = strlen (name);
309   size_t suffix_len = strlen (suffix);
310   return (name_len > suffix_len
311           && !c_strcasecmp (&name[name_len - suffix_len], suffix));
312 }
313
314 static gboolean
315 name_has_por_suffix (const gchar *name)
316 {
317   return has_suffix (name, ".por");
318 }
319
320 static gboolean
321 name_has_sav_suffix (const gchar *name)
322 {
323   return has_suffix (name, ".sav") || has_suffix (name, ".zsav");
324 }
325
326 /* Returns true if NAME has a suffix which might denote a PSPP file */
327 static gboolean
328 name_has_suffix (const gchar *name)
329 {
330   return name_has_por_suffix (name) || name_has_sav_suffix (name);
331 }
332
333 static gboolean
334 load_file (PsppireWindow *de, const gchar *file_name, gpointer syn)
335 {
336   const char *mime_type = NULL;
337   gchar *syntax = NULL;
338   bool ok;
339
340   if (syn == NULL)
341     {
342       gchar *utf8_file_name;
343       struct string filename;
344       ds_init_empty (&filename);
345       
346       utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
347     
348       syntax_gen_string (&filename, ss_cstr (utf8_file_name));
349       
350       g_free (utf8_file_name);
351       
352       syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
353       ds_destroy (&filename);
354
355     }
356   else
357     {
358       syntax = syn;
359     }
360
361   ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
362                        lex_reader_for_string (syntax));
363   g_free (syntax);
364
365   if (ok && syn == NULL)
366     {
367       if (name_has_por_suffix (file_name))
368         mime_type = "application/x-spss-por";
369       else if (name_has_sav_suffix (file_name))
370         mime_type = "application/x-spss-sav";
371       
372       add_most_recent (file_name, mime_type);
373     }
374
375   return ok;
376 }
377
378 static const char *
379 psppire_data_window_format_to_string (enum PsppireDataWindowFormat format)
380 {
381   if (format == PSPPIRE_DATA_WINDOW_SAV)
382     return ".sav";
383   else if (format == PSPPIRE_DATA_WINDOW_ZSAV)
384     return ".zsav";
385   else
386     return ".por";
387 }
388
389 /* Save DE to file */
390 static void
391 save_file (PsppireWindow *w)
392 {
393   const gchar *file_name = NULL;
394   gchar *utf8_file_name = NULL;
395   GString *fnx;
396   struct string filename ;
397   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
398   gchar *syntax;
399
400   file_name = psppire_window_get_filename (w);
401
402   fnx = g_string_new (file_name);
403
404   if ( ! name_has_suffix (fnx->str))
405     g_string_append (fnx, psppire_data_window_format_to_string (de->format));
406
407   ds_init_empty (&filename);
408
409   utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
410
411   g_string_free (fnx, TRUE);
412
413   syntax_gen_string (&filename, ss_cstr (utf8_file_name));
414   g_free (utf8_file_name);
415
416   if (de->format == PSPPIRE_DATA_WINDOW_SAV)
417     syntax = g_strdup_printf ("SAVE OUTFILE=%s.", ds_cstr (&filename));
418   else if (de->format == PSPPIRE_DATA_WINDOW_ZSAV)
419     syntax = g_strdup_printf ("SAVE /ZCOMPRESSED /OUTFILE=%s.",
420                               ds_cstr (&filename));
421   else
422     syntax = g_strdup_printf ("EXPORT OUTFILE=%s.", ds_cstr (&filename));
423
424   ds_destroy (&filename);
425
426   g_free (execute_syntax_string (de, syntax));
427 }
428
429
430 static void
431 display_dict (PsppireDataWindow *de)
432 {
433   execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
434 }
435
436 static void
437 sysfile_info (PsppireDataWindow *de)
438 {
439   GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
440
441   if  ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
442     {
443       struct string filename;
444       gchar *file_name =
445         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
446
447       gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
448                                                   NULL);
449
450       gchar *syntax;
451
452       ds_init_empty (&filename);
453
454       syntax_gen_string (&filename, ss_cstr (utf8_file_name));
455
456       g_free (utf8_file_name);
457
458       syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
459       g_free (execute_syntax_string (de, syntax));
460     }
461
462   gtk_widget_destroy (dialog);
463 }
464
465
466 /* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
467 static void
468 data_pick_filename (PsppireWindow *window)
469 {
470   GtkListStore *list_store;
471   GtkWidget *combo_box;
472
473   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
474   GtkFileFilter *filter;
475   GtkWidget *dialog =
476     gtk_file_chooser_dialog_new (_("Save"),
477                                  GTK_WINDOW (de),
478                                  GTK_FILE_CHOOSER_ACTION_SAVE,
479                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
480                                  GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
481                                  NULL);
482
483   g_object_set (dialog, "local-only", FALSE, NULL);
484
485   filter = gtk_file_filter_new ();
486   gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
487   gtk_file_filter_add_mime_type (filter, "application/x-spss-sav");
488   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
489
490   filter = gtk_file_filter_new ();
491   gtk_file_filter_set_name (filter, _("Compressed System Files (*.zsav)"));
492   gtk_file_filter_add_pattern (filter, "*.zsav");
493   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
494
495   filter = gtk_file_filter_new ();
496   gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
497   gtk_file_filter_add_mime_type (filter, "application/x-spss-por");
498   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
499
500   filter = gtk_file_filter_new ();
501   gtk_file_filter_set_name (filter, _("All Files"));
502   gtk_file_filter_add_pattern (filter, "*");
503   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
504   gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
505
506   {
507     GtkCellRenderer *cell;
508     GtkWidget *label;
509     GtkTreeIter iter;
510     GtkWidget *hbox;
511
512     list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
513     combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
514
515     gtk_list_store_append (list_store, &iter);
516     gtk_list_store_set (list_store, &iter,
517                         0, PSPPIRE_DATA_WINDOW_SAV,
518                         1, _("System File"),
519                         -1);
520     gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
521
522     gtk_list_store_append (list_store, &iter);
523     gtk_list_store_set (list_store, &iter,
524                         0, PSPPIRE_DATA_WINDOW_ZSAV,
525                         1, _("Compressed System File"),
526                         -1);
527
528     gtk_list_store_append (list_store, &iter);
529     gtk_list_store_set (list_store, &iter,
530                         0, PSPPIRE_DATA_WINDOW_POR,
531                         1, _("Portable File"),
532                         -1);
533
534     label = gtk_label_new (_("Format:"));
535
536     cell = gtk_cell_renderer_text_new ();
537     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
538     gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box), cell,
539                                    "text", 1);
540
541     hbox = gtk_hbox_new (FALSE, 0);
542     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
543     gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
544     gtk_widget_show_all (hbox);
545
546     gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), hbox);
547   }
548
549   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
550                                                   TRUE);
551
552   switch (gtk_dialog_run (GTK_DIALOG (dialog)))
553     {
554     case GTK_RESPONSE_ACCEPT:
555       {
556         GString *filename =
557           g_string_new
558           (
559            gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog))
560            );
561
562         GtkTreeIter iter;
563         int format;
564
565         gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter);
566         gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter,
567                             0, &format,
568                             -1);
569         de->format = format;
570
571         if ( ! name_has_suffix (filename->str))
572           g_string_append (filename,
573                            psppire_data_window_format_to_string (format));
574
575         psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
576
577         g_string_free (filename, TRUE);
578       }
579       break;
580     default:
581       break;
582     }
583
584   gtk_widget_destroy (dialog);
585 }
586
587 static bool
588 confirm_delete_dataset (PsppireDataWindow *de,
589                         const char *old_dataset,
590                         const char *new_dataset,
591                         const char *existing_dataset)
592 {
593   GtkWidget *dialog;
594   int result;
595
596   dialog = gtk_message_dialog_new (
597     GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
598     _("Delete Existing Dataset?"));
599
600   gtk_message_dialog_format_secondary_text (
601     GTK_MESSAGE_DIALOG (dialog),
602     _("Renaming \"%s\" to \"%s\" will destroy the existing "
603       "dataset named \"%s\".  Are you sure that you want to do this?"),
604     old_dataset, new_dataset, existing_dataset);
605
606   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
607                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
608                           GTK_STOCK_DELETE, GTK_RESPONSE_OK,
609                           NULL);
610
611   g_object_set (dialog, "icon-name", "pspp", NULL);
612
613   result = gtk_dialog_run (GTK_DIALOG (dialog));
614
615   gtk_widget_destroy (dialog);
616
617   return result == GTK_RESPONSE_OK;
618 }
619
620 static void
621 on_rename_dataset (PsppireDataWindow *de)
622 {
623   struct dataset *ds = de->dataset;
624   struct session *session = dataset_session (ds);
625   const char *old_name = dataset_name (ds);
626   struct dataset *existing_dataset;
627   char *new_name;
628   char *prompt;
629
630   prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
631                       old_name);
632   new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
633                                old_name);
634   free (prompt);
635
636   if (new_name == NULL)
637     return;
638
639   existing_dataset = session_lookup_dataset (session, new_name);
640   if (existing_dataset == NULL || existing_dataset == ds
641       || confirm_delete_dataset (de, old_name, new_name,
642                                  dataset_name (existing_dataset)))
643     g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
644                                                         new_name)));
645
646   free (new_name);
647 }
648
649 static void
650 status_bar_activate (PsppireDataWindow  *de, GtkToggleAction *action)
651 {
652   GtkWidget *statusbar = get_widget_assert (de->builder, "status-bar");
653
654   if ( gtk_toggle_action_get_active (action))
655     gtk_widget_show (statusbar);
656   else
657     gtk_widget_hide (statusbar);
658 }
659
660
661 static void
662 grid_lines_activate (PsppireDataWindow  *de, GtkToggleAction *action)
663 {
664   const gboolean grid_visible = gtk_toggle_action_get_active (action);
665
666   psppire_data_editor_show_grid (de->data_editor, grid_visible);
667 }
668
669 static void
670 data_view_activate (PsppireDataWindow  *de)
671 {
672   gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
673 }
674
675
676 static void
677 variable_view_activate (PsppireDataWindow  *de)
678 {
679   gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
680 }
681
682
683 static void
684 fonts_activate (PsppireDataWindow  *de)
685 {
686   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (de));
687   PangoFontDescription *current_font;
688   gchar *font_name;
689   GtkWidget *dialog =
690     gtk_font_selection_dialog_new (_("Font Selection"));
691
692
693   current_font = GTK_WIDGET(de->data_editor)->style->font_desc;
694   font_name = pango_font_description_to_string (current_font);
695
696   gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
697
698   g_free (font_name);
699
700   gtk_window_set_transient_for (GTK_WINDOW (dialog),
701                                 GTK_WINDOW (toplevel));
702
703   if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
704     {
705       const gchar *font = gtk_font_selection_dialog_get_font_name
706         (GTK_FONT_SELECTION_DIALOG (dialog));
707
708       PangoFontDescription* font_desc =
709         pango_font_description_from_string (font);
710
711       psppire_data_editor_set_font (de->data_editor, font_desc);
712     }
713
714   gtk_widget_hide (dialog);
715 }
716
717
718
719 /* Callback for the value labels action */
720 static void
721 toggle_value_labels (PsppireDataWindow  *de, GtkToggleAction *ta)
722 {
723   g_object_set (de->data_editor, "value-labels", gtk_toggle_action_get_active (ta), NULL);
724 }
725
726 static void
727 toggle_split_window (PsppireDataWindow  *de, GtkToggleAction *ta)
728 {
729   psppire_data_editor_split_window (de->data_editor,
730                                     gtk_toggle_action_get_active (ta));
731 }
732
733
734 static void
735 file_quit (PsppireDataWindow *de)
736 {
737   /* FIXME: Need to be more intelligent here.
738      Give the user the opportunity to save any unsaved data.
739   */
740   psppire_quit ();
741 }
742
743 static void
744 on_recent_data_select (GtkMenuShell *menushell,
745                        PsppireWindow *window)
746 {
747   gchar *file;
748
749   gchar *uri =
750     gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
751
752   file = g_filename_from_uri (uri, NULL, NULL);
753
754   g_free (uri);
755
756   open_data_window (window, file, NULL);
757
758   g_free (file);
759 }
760
761 static char *
762 charset_from_mime_type (const char *mime_type)
763 {
764   const char *charset;
765   struct string s;
766   const char *p;
767
768   if (mime_type == NULL)
769     return NULL;
770
771   charset = c_strcasestr (mime_type, "charset=");
772   if (charset == NULL)
773     return NULL;
774
775   ds_init_empty (&s);
776   p = charset + 8;
777   if (*p == '"')
778     {
779       /* Parse a "quoted-string" as defined by RFC 822. */
780       for (p++; *p != '\0' && *p != '"'; p++)
781         {
782           if (*p != '\\')
783             ds_put_byte (&s, *p);
784           else if (*++p != '\0')
785             ds_put_byte (&s, *p);
786         }
787     }
788   else
789     {
790       /* Parse a "token" as defined by RFC 2045. */
791       while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
792         ds_put_byte (&s, *p++);
793     }
794   if (!ds_is_empty (&s))
795     return ds_steal_cstr (&s);
796
797   ds_destroy (&s);
798   return NULL;
799 }
800
801 static void
802 on_recent_files_select (GtkMenuShell *menushell,   gpointer user_data)
803 {
804   GtkRecentInfo *item;
805   char *encoding;
806   GtkWidget *se;
807   gchar *file;
808
809   /* Get the file name and its encoding. */
810   item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
811   file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
812   encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
813   gtk_recent_info_unref (item);
814
815   se = psppire_syntax_window_new (encoding);
816
817   free (encoding);
818
819   if ( psppire_window_load (PSPPIRE_WINDOW (se), file, NULL) ) 
820     gtk_widget_show (se);
821   else
822     gtk_widget_destroy (se);
823
824   g_free (file);
825 }
826
827 static void
828 set_unsaved (gpointer w)
829 {
830   psppire_window_set_unsaved (PSPPIRE_WINDOW (w));
831 }
832
833 static void
834 on_switch_page (PsppireDataEditor *de, gpointer p,
835                 gint pagenum, PsppireDataWindow *dw)
836 {
837   GtkWidget *page_menu_item;
838   gboolean is_ds;
839   const char *path;
840
841   is_ds = pagenum == PSPPIRE_DATA_EDITOR_DATA_VIEW;
842   path = (is_ds
843           ? "/ui/menubar/view/view_data"
844           : "/ui/menubar/view/view_variables");
845   page_menu_item = gtk_ui_manager_get_widget (dw->ui_manager, path);
846   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (page_menu_item), TRUE);
847 }
848
849 static void
850 on_ui_manager_changed (PsppireDataEditor *de,
851                        GParamSpec *pspec UNUSED,
852                        PsppireDataWindow *dw)
853 {
854   GtkUIManager *uim = psppire_data_editor_get_ui_manager (de);
855   if (uim == dw->uim)
856     return;
857
858   if (dw->uim)
859     {
860       psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
861       g_object_unref (dw->uim);
862       dw->uim = NULL;
863     }
864
865   dw->uim = uim;
866   if (dw->uim)
867     {
868       g_object_ref (dw->uim);
869       dw->merge_id = psppire_data_window_add_ui (dw, dw->uim);
870     }
871 }
872
873 /* Connects the action called ACTION_NAME to HANDLER passing DW as the auxilliary data.
874    Returns a pointer to the action
875 */
876 static GtkAction *
877 connect_action (PsppireDataWindow *dw, const char *action_name, 
878                                     GCallback handler)
879 {
880   GtkAction *action = get_action_assert (dw->builder, action_name);
881
882   g_signal_connect_swapped (action, "activate", handler, dw);
883
884   return action;
885 }
886
887 /* Only a data file with at least one variable can be saved. */
888 static void
889 enable_save (PsppireDataWindow *dw)
890 {
891   gboolean enable = psppire_dict_get_var_cnt (dw->dict) > 0;
892
893   gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save"),
894                             enable);
895   gtk_action_set_sensitive (get_action_assert (dw->builder, "file_save_as"),
896                             enable);
897 }
898
899 /* Initializes as much of a PsppireDataWindow as we can and must before the
900    dataset has been set.
901
902    In particular, the 'menu' member is required in case the "filename" property
903    is set before the "dataset" property: otherwise PsppireWindow will try to
904    modify the menu as part of the "filename" property_set() function and end up
905    with a Gtk-CRITICAL since 'menu' is NULL.  */
906 static void
907 psppire_data_window_init (PsppireDataWindow *de)
908 {
909   de->builder = builder_new ("data-editor.ui");
910
911   de->ui_manager = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
912
913   PSPPIRE_WINDOW (de)->menu =
914     GTK_MENU_SHELL (gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/windows/windows_minimise_all")->parent);
915
916   de->uim = NULL;
917   de->merge_id = 0;
918 }
919
920 static void
921 psppire_data_window_finish_init (PsppireDataWindow *de,
922                                  struct dataset *ds)
923 {
924   static const struct dataset_callbacks cbs =
925     {
926       set_unsaved,                    /* changed */
927       transformation_change_callback, /* transformations_changed */
928     };
929
930   GtkWidget *menubar;
931   GtkWidget *hb ;
932   GtkWidget *sb ;
933
934   GtkWidget *box = gtk_vbox_new (FALSE, 0);
935
936   de->dataset = ds;
937   de->dict = psppire_dict_new_from_dict (dataset_dict (ds));
938   de->data_store = psppire_data_store_new (de->dict);
939   psppire_data_store_set_reader (de->data_store, NULL);
940
941   menubar = get_widget_assert (de->builder, "menubar");
942   hb = get_widget_assert (de->builder, "handlebox1");
943   sb = get_widget_assert (de->builder, "status-bar");
944
945   de->uim = NULL;
946   de->merge_id = 0;
947
948   de->data_editor =
949     PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de->dict, de->data_store));
950   g_signal_connect (de->data_editor, "switch-page",
951                     G_CALLBACK (on_switch_page), de);
952
953   g_signal_connect_swapped (de->data_store, "case-changed",
954                             G_CALLBACK (set_unsaved), de);
955
956   g_signal_connect_swapped (de->data_store, "case-inserted",
957                             G_CALLBACK (set_unsaved), de);
958
959   g_signal_connect_swapped (de->data_store, "cases-deleted",
960                             G_CALLBACK (set_unsaved), de);
961
962   dataset_set_callbacks (de->dataset, &cbs, de);
963
964   connect_help (de->builder);
965
966   gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
967   gtk_box_pack_start (GTK_BOX (box), hb, FALSE, TRUE, 0);
968   gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (de->data_editor), TRUE, TRUE, 0);
969   gtk_box_pack_start (GTK_BOX (box), sb, FALSE, TRUE, 0);
970
971   gtk_container_add (GTK_CONTAINER (de), box);
972
973   g_signal_connect (de->dict, "weight-changed",
974                     G_CALLBACK (on_weight_change),
975                     de);
976
977   g_signal_connect (de->dict, "filter-changed",
978                     G_CALLBACK (on_filter_change),
979                     de);
980
981   g_signal_connect (de->dict, "split-changed",
982                     G_CALLBACK (on_split_change),
983                     de);
984
985   g_signal_connect_swapped (de->dict, "backend-changed",
986                             G_CALLBACK (enable_save), de);
987   g_signal_connect_swapped (de->dict, "variable-inserted",
988                             G_CALLBACK (enable_save), de);
989   g_signal_connect_swapped (de->dict, "variable-deleted",
990                             G_CALLBACK (enable_save), de);
991   enable_save (de);
992
993   connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
994   connect_action (de, "file_import", G_CALLBACK (text_data_import_assistant));
995   connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
996   connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
997   connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
998   connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
999   connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
1000   connect_action (de, "file_information_external-file", G_CALLBACK (sysfile_info));
1001
1002   g_signal_connect_swapped (get_action_assert (de->builder, "view_value-labels"), "toggled", G_CALLBACK (toggle_value_labels), de);
1003
1004   connect_action (de, "data_select-cases", G_CALLBACK (select_cases_dialog));
1005   connect_action (de, "data_aggregate", G_CALLBACK (aggregate_dialog));
1006   connect_action (de, "transform_autorecode", G_CALLBACK (autorecode_dialog));
1007   connect_action (de, "data_split-file", G_CALLBACK (split_file_dialog));
1008   connect_action (de, "data_weight-cases", G_CALLBACK (weight_cases_dialog));
1009   connect_action (de, "utilities_comments", G_CALLBACK (comments_dialog));
1010   connect_action (de, "transform_recode-same", G_CALLBACK (recode_same_dialog));
1011   connect_action (de, "transform_recode-different", G_CALLBACK (recode_different_dialog));
1012
1013   {
1014     GtkWidget *recent_data =
1015       gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-data");
1016
1017     GtkWidget *recent_files =
1018       gtk_ui_manager_get_widget (de->ui_manager, "/ui/menubar/file/file_recent-files");
1019
1020
1021     GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
1022       gtk_recent_manager_get_default ());
1023
1024     GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
1025       gtk_recent_manager_get_default ());
1026
1027     g_object_set (menu_data, "show-tips",  TRUE, NULL);
1028     g_object_set (menu_files, "show-tips",  TRUE, NULL);
1029
1030     {
1031       GtkRecentFilter *filter = gtk_recent_filter_new ();
1032
1033       gtk_recent_filter_add_mime_type (filter, "application/x-spss-sav");
1034       gtk_recent_filter_add_mime_type (filter, "application/x-spss-por");
1035
1036       gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_data), GTK_RECENT_SORT_MRU);
1037
1038       gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_data), filter);
1039     }
1040
1041     gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_data), menu_data);
1042
1043
1044     g_signal_connect (menu_data, "selection-done", G_CALLBACK (on_recent_data_select), de);
1045
1046     {
1047       GtkRecentFilter *filter = gtk_recent_filter_new ();
1048
1049       gtk_recent_filter_add_pattern (filter, "*.sps");
1050       gtk_recent_filter_add_pattern (filter, "*.SPS");
1051
1052       gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu_files), GTK_RECENT_SORT_MRU);
1053
1054       gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu_files), filter);
1055     }
1056
1057     gtk_menu_item_set_submenu (GTK_MENU_ITEM (recent_files), menu_files);
1058
1059     g_signal_connect (menu_files, "selection-done", G_CALLBACK (on_recent_files_select), de);
1060
1061   }
1062
1063   connect_action (de, "file_new_syntax", G_CALLBACK (create_syntax_window));
1064
1065
1066   gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
1067   gtk_notebook_set_current_page (GTK_NOTEBOOK (de->data_editor), PSPPIRE_DATA_EDITOR_DATA_VIEW);
1068
1069   connect_action (de, "view_statusbar", G_CALLBACK (status_bar_activate));
1070
1071   connect_action (de, "view_gridlines", G_CALLBACK (grid_lines_activate));
1072
1073   connect_action (de, "view_data", G_CALLBACK (data_view_activate));
1074
1075   connect_action (de, "view_variables", G_CALLBACK (variable_view_activate));
1076
1077   connect_action (de, "view_fonts", G_CALLBACK (fonts_activate));
1078
1079   connect_action (de, "file_quit", G_CALLBACK (file_quit));
1080
1081   connect_action (de, "transform_run-pending", G_CALLBACK (execute));
1082
1083   connect_action (de, "windows_minimise_all", G_CALLBACK (psppire_window_minimise_all));
1084
1085   g_signal_connect_swapped (get_action_assert (de->builder, "windows_split"), "toggled", G_CALLBACK (toggle_split_window), de);
1086
1087   merge_help_menu (de->ui_manager);
1088
1089   g_signal_connect (de->data_editor, "notify::ui-manager",
1090                     G_CALLBACK (on_ui_manager_changed), de);
1091   on_ui_manager_changed (de->data_editor, NULL, de);
1092
1093   gtk_widget_show (GTK_WIDGET (de->data_editor));
1094   gtk_widget_show (box);
1095
1096   ll_push_head (&all_data_windows, &de->ll);
1097 }
1098
1099 static void
1100 psppire_data_window_dispose (GObject *object)
1101 {
1102   PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1103
1104   if (dw->uim)
1105     {
1106       psppire_data_window_remove_ui (dw, dw->uim, dw->merge_id);
1107       g_object_unref (dw->uim);
1108       dw->uim = NULL;
1109     }
1110
1111   if (dw->builder != NULL)
1112     {
1113       g_object_unref (dw->builder);
1114       dw->builder = NULL;
1115     }
1116
1117   if (dw->dict)
1118     {
1119       g_signal_handlers_disconnect_by_func (dw->dict,
1120                                             G_CALLBACK (enable_save), dw);
1121       g_signal_handlers_disconnect_by_func (dw->dict,
1122                                             G_CALLBACK (on_weight_change), dw);
1123       g_signal_handlers_disconnect_by_func (dw->dict,
1124                                             G_CALLBACK (on_filter_change), dw);
1125       g_signal_handlers_disconnect_by_func (dw->dict,
1126                                             G_CALLBACK (on_split_change), dw);
1127
1128       g_object_unref (dw->dict);
1129       dw->dict = NULL;
1130     }
1131
1132   if (dw->data_store)
1133     {
1134       g_object_unref (dw->data_store);
1135       dw->data_store = NULL;
1136     }
1137
1138   if (dw->ll.next != NULL)
1139     {
1140       ll_remove (&dw->ll);
1141       dw->ll.next = NULL;
1142     }
1143
1144   if (G_OBJECT_CLASS (parent_class)->dispose)
1145     G_OBJECT_CLASS (parent_class)->dispose (object);
1146 }
1147
1148 static void
1149 psppire_data_window_finalize (GObject *object)
1150 {
1151   PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
1152
1153   if (dw->dataset)
1154     {
1155       struct dataset *dataset = dw->dataset;
1156       struct session *session = dataset_session (dataset);
1157
1158       dw->dataset = NULL;
1159
1160       dataset_set_callbacks (dataset, NULL, NULL);
1161       session_set_active_dataset (session, NULL);
1162       dataset_destroy (dataset);
1163     }
1164
1165   if (G_OBJECT_CLASS (parent_class)->finalize)
1166     G_OBJECT_CLASS (parent_class)->finalize (object);
1167 }
1168
1169 static void
1170 psppire_data_window_set_property (GObject         *object,
1171                                   guint            prop_id,
1172                                   const GValue    *value,
1173                                   GParamSpec      *pspec)
1174 {
1175   PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1176
1177   switch (prop_id)
1178     {
1179     case PROP_DATASET:
1180       psppire_data_window_finish_init (window, g_value_get_pointer (value));
1181       break;
1182     default:
1183       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1184       break;
1185     };
1186 }
1187
1188 static void
1189 psppire_data_window_get_property (GObject         *object,
1190                                   guint            prop_id,
1191                                   GValue          *value,
1192                                   GParamSpec      *pspec)
1193 {
1194   PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
1195
1196   switch (prop_id)
1197     {
1198     case PROP_DATASET:
1199       g_value_set_pointer (value, window->dataset);
1200       break;
1201     default:
1202       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1203       break;
1204     };
1205 }
1206
1207 static guint
1208 psppire_data_window_add_ui (PsppireDataWindow *pdw, GtkUIManager *uim)
1209 {
1210   gchar *ui_string;
1211   guint merge_id;
1212   GList *list;
1213
1214   ui_string = gtk_ui_manager_get_ui (uim);
1215   merge_id = gtk_ui_manager_add_ui_from_string (pdw->ui_manager, ui_string,
1216                                                 -1, NULL);
1217   g_free (ui_string);
1218
1219   g_return_val_if_fail (merge_id != 0, 0);
1220
1221   list = gtk_ui_manager_get_action_groups (uim);
1222   for (; list != NULL; list = list->next)
1223     {
1224       GtkActionGroup *action_group = list->data;
1225       GList *actions = gtk_action_group_list_actions (action_group);
1226       GList *action;
1227
1228       for (action = actions; action != NULL; action = action->next)
1229         {
1230           GtkAction *a = action->data;
1231
1232           if (PSPPIRE_IS_DIALOG_ACTION (a))
1233             g_object_set (a, "manager", pdw->ui_manager, NULL);
1234         }
1235
1236       gtk_ui_manager_insert_action_group (pdw->ui_manager, action_group, 0);
1237     }
1238
1239   gtk_window_add_accel_group (GTK_WINDOW (pdw),
1240                               gtk_ui_manager_get_accel_group (uim));
1241
1242   return merge_id;
1243 }
1244
1245 static void
1246 psppire_data_window_remove_ui (PsppireDataWindow *pdw,
1247                                GtkUIManager *uim, guint merge_id)
1248 {
1249   GList *list;
1250
1251   g_return_if_fail (merge_id != 0);
1252
1253   gtk_ui_manager_remove_ui (pdw->ui_manager, merge_id);
1254
1255   list = gtk_ui_manager_get_action_groups (uim);
1256   for (; list != NULL; list = list->next)
1257     {
1258       GtkActionGroup *action_group = list->data;
1259       gtk_ui_manager_remove_action_group (pdw->ui_manager, action_group);
1260     }
1261
1262   gtk_window_remove_accel_group (GTK_WINDOW (pdw),
1263                                  gtk_ui_manager_get_accel_group (uim));
1264 }
1265
1266 GtkWidget*
1267 psppire_data_window_new (struct dataset *ds)
1268 {
1269   GtkWidget *dw;
1270
1271   if (the_session == NULL)
1272     the_session = session_create (NULL);
1273
1274   if (ds == NULL)
1275     {
1276       char *dataset_name = session_generate_dataset_name (the_session);
1277       ds = dataset_create (the_session, dataset_name);
1278       free (dataset_name);
1279     }
1280   assert (dataset_session (ds) == the_session);
1281
1282   dw = GTK_WIDGET (
1283     g_object_new (
1284       psppire_data_window_get_type (),
1285       "description", _("Data Editor"),
1286       "dataset", ds,
1287       NULL));
1288
1289   if (dataset_name (ds) != NULL)
1290     g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
1291
1292   return dw;
1293 }
1294
1295 bool
1296 psppire_data_window_is_empty (PsppireDataWindow *dw)
1297 {
1298   return psppire_dict_get_var_cnt (dw->dict) == 0;
1299 }
1300
1301 static void
1302 psppire_data_window_iface_init (PsppireWindowIface *iface)
1303 {
1304   iface->save = save_file;
1305   iface->pick_filename = data_pick_filename;
1306   iface->load = load_file;
1307 }
1308 \f
1309 PsppireDataWindow *
1310 psppire_default_data_window (void)
1311 {
1312   if (ll_is_empty (&all_data_windows))
1313     create_data_window ();
1314   return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
1315 }
1316
1317 void
1318 psppire_data_window_set_default (PsppireDataWindow *pdw)
1319 {
1320   ll_remove (&pdw->ll);
1321   ll_push_head (&all_data_windows, &pdw->ll);
1322 }
1323
1324 void
1325 psppire_data_window_undefault (PsppireDataWindow *pdw)
1326 {
1327   ll_remove (&pdw->ll);
1328   ll_push_tail (&all_data_windows, &pdw->ll);
1329 }
1330
1331 PsppireDataWindow *
1332 psppire_data_window_for_dataset (struct dataset *ds)
1333 {
1334   PsppireDataWindow *pdw;
1335
1336   ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1337     if (pdw->dataset == ds)
1338       return pdw;
1339
1340   return NULL;
1341 }
1342
1343 PsppireDataWindow *
1344 psppire_data_window_for_data_store (PsppireDataStore *data_store)
1345 {
1346   PsppireDataWindow *pdw;
1347
1348   ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
1349     if (pdw->data_store == data_store)
1350       return pdw;
1351
1352   return NULL;
1353 }
1354
1355 void
1356 create_data_window (void)
1357 {
1358   gtk_widget_show (psppire_data_window_new (NULL));
1359 }
1360
1361 void
1362 open_data_window (PsppireWindow *victim, const char *file_name, gpointer hint)
1363 {
1364   GtkWidget *window;
1365
1366   if (PSPPIRE_IS_DATA_WINDOW (victim)
1367       && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
1368     {
1369       window = GTK_WIDGET (victim);
1370       gtk_widget_hide (GTK_WIDGET (PSPPIRE_DATA_WINDOW (window)->data_editor));
1371     }
1372   else
1373     window = psppire_data_window_new (NULL);
1374
1375   psppire_window_load (PSPPIRE_WINDOW (window), file_name, hint);
1376   gtk_widget_show_all (window);
1377 }
1378