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