Implement DATASET commands.
[pspp-builds.git] / src / ui / gui / psppire-window.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2009, 2010, 2011  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 "psppire-window.h"
20
21 #include <gtk/gtk.h>
22
23 #include <stdlib.h>
24 #include <xalloc.h>
25
26 #include <gettext.h>
27 #define _(msgid) gettext (msgid)
28 #define N_(msgid) msgid
29
30 #include "data/any-reader.h"
31 #include "data/dataset.h"
32
33 #include "helper.h"
34 #include "psppire-conf.h"
35 #include "psppire-data-window.h"
36 #include "psppire-syntax-window.h"
37 #include "psppire-window-register.h"
38 #include "psppire.h"
39
40 static void psppire_window_base_finalize (PsppireWindowClass *, gpointer);
41 static void psppire_window_base_init     (PsppireWindowClass *class);
42 static void psppire_window_class_init    (PsppireWindowClass *class);
43 static void psppire_window_init          (PsppireWindow      *window);
44
45
46 static GObjectClass *parent_class;
47
48 GType
49 psppire_window_get_type (void)
50 {
51   static GType psppire_window_type = 0;
52
53   if (!psppire_window_type)
54     {
55       static const GTypeInfo psppire_window_info =
56       {
57         sizeof (PsppireWindowClass),
58         (GBaseInitFunc) psppire_window_base_init,
59         (GBaseFinalizeFunc) psppire_window_base_finalize,
60         (GClassInitFunc) psppire_window_class_init,
61         (GClassFinalizeFunc) NULL,
62         NULL,
63         sizeof (PsppireWindow),
64         0,
65         (GInstanceInitFunc) psppire_window_init,
66       };
67
68       psppire_window_type =
69         g_type_register_static (GTK_TYPE_WINDOW, "PsppireWindow",
70                                 &psppire_window_info, G_TYPE_FLAG_ABSTRACT);
71     }
72
73   return psppire_window_type;
74 }
75
76
77 /* Properties */
78 enum
79 {
80   PROP_0,
81   PROP_FILENAME,
82   PROP_DESCRIPTION,
83   PROP_ID
84 };
85
86
87 gchar *
88 uniquify (const gchar *str, int *x)
89 {
90   return g_strdup_printf ("%s%d", str, (*x)++);
91 }
92
93 static void
94 psppire_window_set_title (PsppireWindow *window)
95 {
96   GString *title = g_string_sized_new (80);
97
98   if (window->dirty)
99     g_string_append_c (title, '*');
100
101   if (window->basename || window->id)
102     {
103       if (window->basename)
104         g_string_append_printf (title, "%s ", window->basename);
105
106       if (window->id != '\0')
107         g_string_append_printf (title, "[%s] ", window->id);
108
109       g_string_append_unichar (title, 0x2014); /* em dash */
110       g_string_append_c (title, ' '); /* em dash */
111     }
112
113   g_string_append_printf (title, "PSPPIRE %s", window->description);
114
115   gtk_window_set_title (GTK_WINDOW (window), title->str);
116
117   g_string_free (title, TRUE);
118 }
119
120 static void
121 psppire_window_update_list_name (PsppireWindow *window)
122 {
123   PsppireWindowRegister *reg = psppire_window_register_new ();
124   GString *candidate = g_string_sized_new (80);
125   int n;
126
127   n = 1;
128   do
129     {
130       /* Compose a name. */
131       g_string_truncate (candidate, 0);
132       if (window->filename)
133         {
134           gchar *display_filename = g_filename_display_name (window->filename);
135           g_string_append (candidate, display_filename);
136           g_free (display_filename);
137
138           if (window->id)
139             g_string_append_printf (candidate, " [%s]", window->id);
140         }
141       else if (window->id)
142         g_string_append_printf (candidate, "[%s]", window->id);
143       else
144         g_string_append (candidate, window->description);
145
146       if (n++ > 1)
147         g_string_append_printf (candidate, " #%d", n);
148
149       if (window->list_name && !strcmp (candidate->str, window->list_name))
150         {
151           /* Keep the existing name. */
152           g_string_free (candidate, TRUE);
153           return;
154         }
155     }
156   while (psppire_window_register_lookup (reg, candidate->str));
157
158   if (window->list_name)
159     psppire_window_register_remove (reg, window->list_name);
160
161   g_free (window->list_name);
162   window->list_name = g_string_free (candidate, FALSE);
163
164   psppire_window_register_insert (reg, window, window->list_name);
165 }
166
167 static void
168 psppire_window_name_changed (PsppireWindow *window)
169 {
170   psppire_window_set_title (window);
171   psppire_window_update_list_name (window);
172 }
173
174 static void
175 psppire_window_set_property (GObject         *object,
176                              guint            prop_id,
177                              const GValue    *value,
178                              GParamSpec      *pspec)
179 {
180   PsppireWindow *window = PSPPIRE_WINDOW (object);
181
182   switch (prop_id)
183     {
184     case PROP_DESCRIPTION:
185       g_free (window->description);
186       window->description = g_value_dup_string (value);
187       psppire_window_set_title (window);
188       break;
189     case PROP_FILENAME:
190       g_free (window->filename);
191       window->filename = g_value_dup_string (value);
192       g_free (window->basename);
193       window->basename = (window->filename
194                           ? g_filename_display_basename (window->filename)
195                           : NULL);
196       psppire_window_name_changed (window);
197       break;
198       break;
199     case PROP_ID:
200       g_free (window->id);
201       window->id = g_value_dup_string (value);
202       psppire_window_name_changed (window);
203       break;
204     default:
205       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
206       break;
207     };
208 }
209
210
211 static void
212 psppire_window_get_property (GObject         *object,
213                              guint            prop_id,
214                              GValue          *value,
215                              GParamSpec      *pspec)
216 {
217   PsppireWindow *window = PSPPIRE_WINDOW (object);
218
219   switch (prop_id)
220     {
221     case PROP_FILENAME:
222       g_value_set_string (value, window->filename);
223       break;
224     case PROP_DESCRIPTION:
225       g_value_set_string (value, window->description);
226       break;
227     case PROP_ID:
228       g_value_set_string (value, window->id);
229       break;
230     default:
231       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
232       break;
233     };
234 }
235
236
237 static void
238 on_realize (GtkWindow *window, gpointer data)
239 {
240   PsppireConf *conf = psppire_conf_new ();
241
242   const gchar *base = G_OBJECT_TYPE_NAME (window);
243
244   psppire_conf_set_window_geometry (conf, base, window);
245 }
246
247
248 static void
249 psppire_window_finalize (GObject *object)
250 {
251   PsppireWindow *window = PSPPIRE_WINDOW (object);
252
253   PsppireWindowRegister *reg = psppire_window_register_new ();
254
255   psppire_window_register_remove (reg, window->list_name);
256   g_free (window->filename);
257   g_free (window->basename);
258   g_free (window->id);
259   g_free (window->description);
260   g_free (window->list_name);
261
262   g_signal_handler_disconnect (psppire_window_register_new (),
263                                window->remove_handler);
264
265   g_signal_handler_disconnect (psppire_window_register_new (),
266                                window->insert_handler);
267
268   g_hash_table_destroy (window->menuitem_table);
269
270   if (G_OBJECT_CLASS (parent_class)->finalize)
271     G_OBJECT_CLASS (parent_class)->finalize (object);
272 }
273
274 static GParamSpec *
275 null_if_empty_param (const gchar *name, const gchar *nick,
276                      const gchar *blurb, const gchar *default_value,
277                      GParamFlags flags)
278 {
279   GParamSpec *param;
280
281   param = g_param_spec_string (name, nick, blurb, default_value, flags);
282   ((GParamSpecString *) param)->null_fold_if_empty = TRUE;
283   return param;
284 }
285
286 static void
287 psppire_window_class_init (PsppireWindowClass *class)
288 {
289   GObjectClass *object_class = G_OBJECT_CLASS (class);
290
291   GParamSpec *description_spec =
292     null_if_empty_param ("description",
293                        "Description",
294                        "A string describing the usage of the window",
295                          NULL, /*Should be overridden by derived classes */
296                        G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
297
298   GParamSpec *filename_spec =
299     null_if_empty_param ("filename",
300                        "File name",
301                        "The name of the file associated with this window, if any",
302                          NULL,
303                          G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
304
305   GParamSpec *id_spec =
306     null_if_empty_param ("id",
307                          "Identifier",
308                          "The PSPP language identifier for the data associated "
309                          "with this window (e.g. dataset name)",
310                          NULL,
311                          G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
312
313   object_class->set_property = psppire_window_set_property;
314   object_class->get_property = psppire_window_get_property;
315
316   g_object_class_install_property (object_class,
317                                    PROP_DESCRIPTION,
318                                    description_spec);
319
320   g_object_class_install_property (object_class,
321                                    PROP_FILENAME,
322                                    filename_spec);
323
324   g_object_class_install_property (object_class,
325                                    PROP_ID,
326                                    id_spec);
327
328   parent_class = g_type_class_peek_parent (class);
329 }
330
331
332 static void
333 psppire_window_base_init (PsppireWindowClass *class)
334 {
335   GObjectClass *object_class = G_OBJECT_CLASS (class);
336
337   object_class->finalize = psppire_window_finalize;
338 }
339
340
341
342 static void
343 psppire_window_base_finalize (PsppireWindowClass *class,
344                                 gpointer class_data)
345 {
346 }
347
348 static void
349 menu_toggled (GtkCheckMenuItem *mi, gpointer data)
350 {
351   /* Prohibit changes to the state */
352   mi->active = !mi->active;
353 }
354
355
356 /* Look up the window associated with this menuitem and present it to the user */
357 static void
358 menu_activate (GtkMenuItem *mi, gpointer data)
359 {
360   const gchar *key = data;
361
362   PsppireWindowRegister *reg = psppire_window_register_new ();
363
364   PsppireWindow *window = psppire_window_register_lookup (reg, key);
365
366   gtk_window_present (GTK_WINDOW (window));
367 }
368
369 static void
370 insert_menuitem_into_menu (PsppireWindow *window, gpointer key)
371 {
372   gchar *filename;
373   GtkWidget *item;
374
375   /* Add a separator before adding the first real item.  If we add a separator
376      at any other time, sometimes GtkUIManager removes it. */
377   if (g_hash_table_size (window->menuitem_table) == 0)
378     {
379       GtkWidget *separator = gtk_separator_menu_item_new ();
380       gtk_widget_show (separator);
381       gtk_menu_shell_append (window->menu, separator);
382     }
383
384   filename = g_filename_display_name (key);
385   item = gtk_check_menu_item_new_with_label (filename);
386   g_free (filename);
387
388   g_signal_connect (item, "toggled", G_CALLBACK (menu_toggled), NULL);
389   g_signal_connect (item, "activate", G_CALLBACK (menu_activate), key);
390
391   gtk_widget_show (item);
392
393   gtk_menu_shell_append (window->menu, item);
394
395   /* Set the state without emitting a signal */
396   GTK_CHECK_MENU_ITEM (item)->active =
397    (psppire_window_register_lookup (psppire_window_register_new (), key) == window);
398
399   g_hash_table_insert (window->menuitem_table, key, item);
400 }
401
402 static void
403 insert_item (gpointer key, gpointer value, gpointer data)
404 {
405   PsppireWindow *window = PSPPIRE_WINDOW (data);
406
407   if ( NULL != g_hash_table_lookup (window->menuitem_table, key))
408     return;
409
410   insert_menuitem_into_menu (window, key);
411 }
412
413 /* Insert a new item into the window menu */
414 static void
415 insert_menuitem (GObject *reg, const gchar *key, gpointer data)
416 {
417   PsppireWindow *window = PSPPIRE_WINDOW (data);
418   
419   insert_menuitem_into_menu (window, (gpointer) key);
420 }
421
422
423 static void
424 remove_menuitem (PsppireWindowRegister *reg, const gchar *key, gpointer data)
425 {
426   PsppireWindow *window = PSPPIRE_WINDOW (data);
427   GtkWidget *item ;
428
429   item = g_hash_table_lookup (window->menuitem_table, key);
430
431   g_hash_table_remove (window->menuitem_table, key);
432
433   if (GTK_IS_CONTAINER (window->menu))
434     gtk_container_remove (GTK_CONTAINER (window->menu), item);
435 }
436
437 static void
438 insert_existing_items (PsppireWindow *window)
439 {
440   psppire_window_register_foreach (psppire_window_register_new (), insert_item, window);
441 }
442
443
444 static gboolean
445 on_delete (PsppireWindow *w, GdkEvent *event, gpointer user_data)
446 {
447   PsppireWindowRegister *reg = psppire_window_register_new ();
448
449   const gchar *base = G_OBJECT_TYPE_NAME (w);
450
451   PsppireConf *conf = psppire_conf_new ();
452
453   psppire_conf_save_window_geometry (conf, base, GTK_WINDOW (w));
454
455
456   if ( w->dirty )
457     {
458       gint response = psppire_window_query_save (w);
459
460       switch (response)
461         {
462         default:
463         case GTK_RESPONSE_CANCEL:
464           return TRUE;
465           break;
466         case GTK_RESPONSE_APPLY:
467           psppire_window_save (w);
468           if (w->dirty)
469             {
470               /* Save failed, or user exited Save As dialog with Cancel. */
471               return TRUE;
472             }
473           break;
474         case GTK_RESPONSE_REJECT:
475           break;
476         }
477     }
478
479   if ( 1 == psppire_window_register_n_items (reg))
480     gtk_main_quit ();
481
482   return FALSE;
483 }
484
485
486 static void
487 psppire_window_init (PsppireWindow *window)
488 {
489   window->menu = NULL;
490   window->filename = NULL;
491   window->basename = NULL;
492   window->id = NULL;
493   window->description = NULL;
494   window->list_name = NULL;
495
496   window->menuitem_table  = g_hash_table_new (g_str_hash, g_str_equal);
497
498
499   g_signal_connect (window,  "realize", G_CALLBACK (insert_existing_items), NULL);
500
501   window->insert_handler = g_signal_connect (psppire_window_register_new (),
502                                              "inserted",
503                                              G_CALLBACK (insert_menuitem),
504                                              window);
505
506   window->remove_handler = g_signal_connect (psppire_window_register_new (),
507                                              "removed",
508                                              G_CALLBACK (remove_menuitem),
509                                              window);
510
511   window->dirty = FALSE;
512
513   g_signal_connect_swapped (window, "delete-event", G_CALLBACK (on_delete), window);
514
515   g_object_set (window, "icon-name", "psppicon", NULL);
516
517   g_signal_connect (window, "realize",
518                     G_CALLBACK (on_realize), window);
519 }
520
521 /*
522    Ask the user if the buffer should be saved.
523    Return the response.
524 */
525 gint
526 psppire_window_query_save (PsppireWindow *se)
527 {
528   gint response;
529   GtkWidget *dialog;
530   GtkWidget *cancel_button;
531
532   gchar *description;
533
534   GTimeVal time;
535
536   g_get_current_time (&time);
537
538   if (se->filename)
539     description = g_filename_display_basename (se->filename);
540   else if (se->id)
541     description = g_strdup (se->id);
542   else
543     description = g_strdup (se->description);
544   dialog =
545     gtk_message_dialog_new (GTK_WINDOW (se),
546                             GTK_DIALOG_MODAL,
547                             GTK_MESSAGE_WARNING,
548                             GTK_BUTTONS_NONE,
549                             _("Save the changes to `%s' before closing?"),
550                             description);
551   g_free (description);
552
553   g_object_set (dialog, "icon-name", "psppicon", NULL);
554
555   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
556                                             _("If you don't save, changes from the last %ld seconds will be permanently lost."),
557                                             time.tv_sec - se->savetime.tv_sec);
558
559   gtk_dialog_add_button  (GTK_DIALOG (dialog),
560                           _("Close _without saving"),
561                           GTK_RESPONSE_REJECT);
562
563   cancel_button = gtk_dialog_add_button  (GTK_DIALOG (dialog),
564                                           GTK_STOCK_CANCEL,
565                                           GTK_RESPONSE_CANCEL);
566
567   gtk_dialog_add_button  (GTK_DIALOG (dialog),
568                           GTK_STOCK_SAVE,
569                           GTK_RESPONSE_APPLY);
570
571   gtk_widget_grab_focus (cancel_button);
572
573   response = gtk_dialog_run (GTK_DIALOG (dialog));
574
575   gtk_widget_destroy (dialog);
576
577   return response;
578 }
579
580
581 /* The return value is encoded in the glib filename encoding. */
582 const gchar *
583 psppire_window_get_filename (PsppireWindow *w)
584 {
585   return w->filename;
586 }
587
588
589 /* FILENAME must be encoded in the glib filename encoding. */
590 void
591 psppire_window_set_filename (PsppireWindow *w, const gchar *filename)
592 {
593   g_object_set (w, "filename", filename, NULL);
594 }
595
596 void
597 psppire_window_set_unsaved (PsppireWindow *w)
598 {
599   if ( w->dirty == FALSE)
600     g_get_current_time (&w->savetime);
601
602   w->dirty = TRUE;
603
604   psppire_window_set_title (w);
605 }
606
607 gboolean
608 psppire_window_get_unsaved (PsppireWindow *w)
609 {
610   return w->dirty;
611 }
612
613
614 \f
615
616
617 static void
618 minimise_window (gpointer key, gpointer value, gpointer data)
619 {
620   gtk_window_iconify (GTK_WINDOW (value));
621 }
622
623
624 void
625 psppire_window_minimise_all (void)
626 {
627   PsppireWindowRegister *reg = psppire_window_register_new ();
628
629   g_hash_table_foreach (reg->name_table, minimise_window, NULL);
630 }
631
632
633 \f
634
635 GType
636 psppire_window_model_get_type (void)
637 {
638   static GType window_model_type = 0;
639
640   if (! window_model_type)
641     {
642       static const GTypeInfo window_model_info =
643       {
644         sizeof (PsppireWindowIface), /* class_size */
645         NULL,           /* base_init */
646         NULL,           /* base_finalize */
647         NULL,
648         NULL,           /* class_finalize */
649         NULL,           /* class_data */
650         0,
651         0,              /* n_preallocs */
652         NULL
653       };
654
655       window_model_type =
656         g_type_register_static (G_TYPE_INTERFACE, "PsppireWindowModel",
657                                 &window_model_info, 0);
658
659       g_type_interface_add_prerequisite (window_model_type, G_TYPE_OBJECT);
660     }
661
662   return window_model_type;
663 }
664
665
666 void
667 psppire_window_save (PsppireWindow *w)
668 {
669   PsppireWindowIface *i = PSPPIRE_WINDOW_MODEL_GET_IFACE (w);
670
671   g_assert (i);
672   g_return_if_fail (i->save);
673
674   if (w->filename == NULL)
675     psppire_window_save_as (w);
676   else
677     {
678       i->save (w);
679       w->dirty = FALSE;
680       psppire_window_set_title (w);
681     }
682 }
683
684 void
685 psppire_window_save_as (PsppireWindow *w)
686 {
687   PsppireWindowIface *i = PSPPIRE_WINDOW_MODEL_GET_IFACE (w);
688   gchar *old_filename;
689
690   g_assert (i);
691   g_return_if_fail (i->pick_filename);
692
693   old_filename = w->filename;
694   w->filename = NULL;
695
696   i->pick_filename (w);
697   if (w->filename == NULL)
698     w->filename = old_filename;
699   else
700     {
701       g_free (old_filename);
702       psppire_window_save (w);
703     }
704 }
705
706 extern GtkRecentManager *the_recent_mgr;
707
708 static void add_most_recent (const char *file_name, GtkRecentManager *rm);
709 static void delete_recent (const char *file_name, GtkRecentManager *rm);
710
711 gboolean
712 psppire_window_load (PsppireWindow *w, const gchar *file)
713 {
714   gboolean ok;
715   PsppireWindowIface *i = PSPPIRE_WINDOW_MODEL_GET_IFACE (w);
716
717   g_assert (PSPPIRE_IS_WINDOW_MODEL (w));
718
719   g_assert (i);
720
721   g_return_val_if_fail (i->load, FALSE);
722
723   ok = i->load (w, file);
724
725   if ( ok )
726     {
727       psppire_window_set_filename (w, file);
728       add_most_recent (file, the_recent_mgr);
729       w->dirty = FALSE;
730     }
731   else
732     delete_recent (file, the_recent_mgr);
733
734   psppire_window_set_title (w);
735
736   return ok;
737 }
738
739 GtkWidget *
740 psppire_window_file_chooser_dialog (PsppireWindow *toplevel)
741 {
742   GtkWidget *dialog =
743     gtk_file_chooser_dialog_new (_("Open"),
744                                  GTK_WINDOW (toplevel),
745                                  GTK_FILE_CHOOSER_ACTION_OPEN,
746                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
747                                  GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
748                                  NULL);
749
750   GtkFileFilter *filter;
751
752   filter = gtk_file_filter_new ();
753   gtk_file_filter_set_name (filter, _("Data and Syntax Files"));
754   gtk_file_filter_add_pattern (filter, "*.sav");
755   gtk_file_filter_add_pattern (filter, "*.SAV");
756   gtk_file_filter_add_pattern (filter, "*.por");
757   gtk_file_filter_add_pattern (filter, "*.POR");
758   gtk_file_filter_add_pattern (filter, "*.sps");
759   gtk_file_filter_add_pattern (filter, "*.SPS");
760   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
761
762   filter = gtk_file_filter_new ();
763   gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
764   gtk_file_filter_add_pattern (filter, "*.sav");
765   gtk_file_filter_add_pattern (filter, "*.SAV");
766   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
767
768   filter = gtk_file_filter_new ();
769   gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
770   gtk_file_filter_add_pattern (filter, "*.por");
771   gtk_file_filter_add_pattern (filter, "*.POR");
772   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
773
774   filter = gtk_file_filter_new ();
775   gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
776   gtk_file_filter_add_pattern (filter, "*.sps");
777   gtk_file_filter_add_pattern (filter, "*.SPS");
778   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
779
780   filter = gtk_file_filter_new ();
781   gtk_file_filter_set_name (filter, _("All Files"));
782   gtk_file_filter_add_pattern (filter, "*");
783   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
784
785   if (toplevel->filename)
786     {
787       const gchar *filename = toplevel->filename;
788       gchar *dir_name;
789
790       if ( ! g_path_is_absolute (filename))
791         {
792           gchar *path =
793             g_build_filename (g_get_current_dir (), filename, NULL);
794           dir_name = g_path_get_dirname (path);
795           g_free (path);
796         }
797       else
798         {
799           dir_name = g_path_get_dirname (filename);
800         }
801       gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
802                                            dir_name);
803       free (dir_name);
804     }
805
806   return dialog;
807 }
808
809 /* Callback for the file_open action.
810    Prompts for a filename and opens it */
811 void
812 psppire_window_open (PsppireWindow *de)
813 {
814   GtkWidget *dialog = psppire_window_file_chooser_dialog (de);
815
816   switch (gtk_dialog_run (GTK_DIALOG (dialog)))
817     {
818     case GTK_RESPONSE_ACCEPT:
819       {
820         gchar *name =
821           gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
822
823         gchar *sysname = convert_glib_filename_to_system_filename (name, NULL);
824
825         if (any_reader_may_open (sysname))
826           {
827             PsppireWindow *window;
828
829 #if 0
830             if (PSPPIRE_IS_DATA_WINDOW (de)
831                 && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (de)))
832               window = de;
833             else
834               window = PSPPIRE_WINDOW (psppire_data_window_new (NULL));
835 #else
836             window = PSPPIRE_WINDOW (psppire_default_data_window ());
837 #endif
838
839             psppire_window_load (window, name);
840             gtk_widget_show (GTK_WIDGET (window));
841           }
842         else
843           open_syntax_window (name);
844
845         g_free (sysname);
846         g_free (name);
847       }
848       break;
849     default:
850       break;
851     }
852
853   gtk_widget_destroy (dialog);
854 }
855
856
857 /* Puts FILE_NAME into the recent list.
858    If it's already in the list, it moves it to the top
859 */
860 static void
861 add_most_recent (const char *file_name, GtkRecentManager *rm)
862 {
863   gchar *uri = g_filename_to_uri  (file_name, NULL, NULL);
864
865   if ( uri )
866     gtk_recent_manager_add_item (rm, uri);
867
868   g_free (uri);
869 }
870
871
872
873 /*
874    If FILE_NAME exists in the recent list, then  delete it.
875  */
876 static void
877 delete_recent (const char *file_name, GtkRecentManager *rm)
878 {
879   gchar *uri = g_filename_to_uri  (file_name, NULL, NULL);
880
881   if ( uri )
882     gtk_recent_manager_remove_item (rm, uri, NULL);
883
884   g_free (uri);
885 }
886