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