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