Implement DATASET commands.
[pspp-builds.git] / src / ui / gui / psppire-syntax-window.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008, 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 <gtk/gtk.h>
20 #include <stdlib.h>
21
22 #include "language/lexer/lexer.h"
23 #include "libpspp/message.h"
24 #include "ui/gui/executor.h"
25 #include "ui/gui/help-menu.h"
26 #include "ui/gui/helper.h"
27 #include "ui/gui/psppire-data-window.h"
28 #include "ui/gui/psppire-syntax-window.h"
29 #include "ui/gui/psppire-syntax-window.h"
30 #include "ui/gui/psppire-window-register.h"
31 #include "ui/gui/psppire.h"
32 #include "ui/gui/psppire.h"
33
34 #include "gl/xalloc.h"
35
36 #include <gettext.h>
37 #define _(msgid) gettext (msgid)
38 #define N_(msgid) msgid
39
40 static void psppire_syntax_window_base_finalize (PsppireSyntaxWindowClass *, gpointer);
41 static void psppire_syntax_window_base_init     (PsppireSyntaxWindowClass *class);
42 static void psppire_syntax_window_class_init    (PsppireSyntaxWindowClass *class);
43 static void psppire_syntax_window_init          (PsppireSyntaxWindow      *syntax_editor);
44
45
46 static void psppire_syntax_window_iface_init (PsppireWindowIface *iface);
47
48
49 GType
50 psppire_syntax_window_get_type (void)
51 {
52   static GType psppire_syntax_window_type = 0;
53
54   if (!psppire_syntax_window_type)
55     {
56       static const GTypeInfo psppire_syntax_window_info =
57       {
58         sizeof (PsppireSyntaxWindowClass),
59         (GBaseInitFunc) psppire_syntax_window_base_init,
60         (GBaseFinalizeFunc) psppire_syntax_window_base_finalize,
61         (GClassInitFunc)psppire_syntax_window_class_init,
62         (GClassFinalizeFunc) NULL,
63         NULL,
64         sizeof (PsppireSyntaxWindow),
65         0,
66         (GInstanceInitFunc) psppire_syntax_window_init,
67       };
68
69       static const GInterfaceInfo window_interface_info =
70         {
71           (GInterfaceInitFunc) psppire_syntax_window_iface_init,
72           NULL,
73           NULL
74         };
75
76       psppire_syntax_window_type =
77         g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireSyntaxWindow",
78                                 &psppire_syntax_window_info, 0);
79
80       g_type_add_interface_static (psppire_syntax_window_type,
81                                    PSPPIRE_TYPE_WINDOW_MODEL,
82                                    &window_interface_info);
83     }
84
85   return psppire_syntax_window_type;
86 }
87
88 static GObjectClass *parent_class ;
89
90 static void
91 psppire_syntax_window_finalize (GObject *object)
92 {
93   if (G_OBJECT_CLASS (parent_class)->finalize)
94     (*G_OBJECT_CLASS (parent_class)->finalize) (object);
95 }
96
97
98 static void
99 psppire_syntax_window_dispose (GObject *obj)
100 {
101   PsppireSyntaxWindow *sw = (PsppireSyntaxWindow *)obj;
102
103   GtkClipboard *clip_selection;
104   GtkClipboard *clip_primary;
105
106   if (sw->dispose_has_run)
107     return;
108
109   clip_selection = gtk_widget_get_clipboard (GTK_WIDGET (sw), GDK_SELECTION_CLIPBOARD);
110   clip_primary =   gtk_widget_get_clipboard (GTK_WIDGET (sw), GDK_SELECTION_PRIMARY);
111
112   g_signal_handler_disconnect (clip_primary, sw->sel_handler);
113
114   g_signal_handler_disconnect (clip_selection, sw->ps_handler);
115
116   /* Make sure dispose does not run twice. */
117   sw->dispose_has_run = TRUE;
118
119   /* Chain up to the parent class */
120   G_OBJECT_CLASS (parent_class)->dispose (obj);
121 }
122
123
124
125 static void
126 psppire_syntax_window_class_init (PsppireSyntaxWindowClass *class)
127 {
128   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
129
130   parent_class = g_type_class_peek_parent (class);
131
132   gobject_class->dispose = psppire_syntax_window_dispose;
133 }
134
135
136 static void
137 psppire_syntax_window_base_init (PsppireSyntaxWindowClass *class)
138 {
139   GObjectClass *object_class = G_OBJECT_CLASS (class);
140
141   object_class->finalize = psppire_syntax_window_finalize;
142 }
143
144
145
146 static void
147 psppire_syntax_window_base_finalize (PsppireSyntaxWindowClass *class,
148                                      gpointer class_data)
149 {
150 }
151
152
153 static void
154 editor_execute_syntax (const PsppireSyntaxWindow *sw, GtkTextIter start,
155                        GtkTextIter stop)
156 {
157   PsppireWindow *win = PSPPIRE_WINDOW (sw);
158   struct lex_reader *reader;
159   gchar *text;
160
161   text = gtk_text_buffer_get_text (sw->buffer, &start, &stop, FALSE);
162   reader = lex_reader_for_string (text);
163   g_free (text);
164
165   lex_reader_set_file_name (reader, psppire_window_get_filename (win));
166
167   execute_syntax (psppire_default_data_window (), reader);
168 }
169 \f
170 /* Delete the currently selected text */
171 static void
172 on_edit_delete (PsppireSyntaxWindow *sw)
173 {
174   GtkTextIter begin, end;
175   
176   if ( gtk_text_buffer_get_selection_bounds (sw->buffer, &begin, &end) )
177     gtk_text_buffer_delete (sw->buffer, &begin, &end);
178 }
179
180
181
182
183 /* The syntax editor's clipboard deals only with text */
184 enum {
185   SELECT_FMT_NULL,
186   SELECT_FMT_TEXT,
187 };
188
189
190 static void
191 selection_changed (PsppireSyntaxWindow *sw)
192 {
193   gboolean sel = gtk_text_buffer_get_has_selection (sw->buffer);
194
195   gtk_action_set_sensitive (sw->edit_copy, sel);
196   gtk_action_set_sensitive (sw->edit_cut, sel);
197   gtk_action_set_sensitive (sw->edit_delete, sel);
198 }
199
200 /* The callback which runs when something request clipboard data */
201 static void
202 clipboard_get_cb (GtkClipboard     *clipboard,
203                   GtkSelectionData *selection_data,
204                   guint             info,
205                   gpointer          data)
206 {
207   PsppireSyntaxWindow *sw = data;
208   g_assert (info == SELECT_FMT_TEXT);
209
210   gtk_selection_data_set (selection_data, selection_data->target,
211                           8,
212                           (const guchar *) sw->cliptext, strlen (sw->cliptext));
213
214 }
215
216 static void
217 clipboard_clear_cb (GtkClipboard *clipboard,
218                     gpointer data)
219 {
220   PsppireSyntaxWindow *sw = data;
221   g_free (sw->cliptext);
222   sw->cliptext = NULL;
223 }
224
225
226 static const GtkTargetEntry targets[] = {
227   { "UTF8_STRING",   0, SELECT_FMT_TEXT },
228   { "STRING",        0, SELECT_FMT_TEXT },
229   { "TEXT",          0, SELECT_FMT_TEXT },
230   { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
231   { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
232   { "text/plain",    0, SELECT_FMT_TEXT },
233 };
234
235
236 /*
237   Store a clip containing the currently selected text.
238   Returns true iff something was set.
239   As a side effect, begin and end will be set to indicate
240   the limits of the selected text.
241 */
242 static gboolean
243 set_clip (PsppireSyntaxWindow *sw, GtkTextIter *begin, GtkTextIter *end)
244 {
245   GtkClipboard *clipboard ;
246
247   if ( ! gtk_text_buffer_get_selection_bounds (sw->buffer, begin, end) )
248     return FALSE;
249
250   g_free (sw->cliptext);
251   sw->cliptext = gtk_text_buffer_get_text  (sw->buffer, begin, end, FALSE);
252
253   clipboard =
254     gtk_widget_get_clipboard (GTK_WIDGET (sw), GDK_SELECTION_CLIPBOARD);
255
256   if (!gtk_clipboard_set_with_owner (clipboard, targets,
257                                      G_N_ELEMENTS (targets),
258                                      clipboard_get_cb, clipboard_clear_cb,
259                                      G_OBJECT (sw)))
260     clipboard_clear_cb (clipboard, sw);
261
262   return TRUE;
263 }
264
265 static void
266 on_edit_cut (PsppireSyntaxWindow *sw)
267 {
268   GtkTextIter begin, end;
269   
270   if ( set_clip (sw, &begin, &end))
271     gtk_text_buffer_delete (sw->buffer, &begin, &end);
272 }
273
274 static void
275 on_edit_copy (PsppireSyntaxWindow *sw)
276 {
277   GtkTextIter begin, end;
278
279   set_clip (sw, &begin, &end);
280 }
281
282
283 /* A callback for when the clipboard contents have been received */
284 static void
285 contents_received_callback (GtkClipboard *clipboard,
286                             GtkSelectionData *sd,
287                             gpointer data)
288 {
289   gchar *c;
290   PsppireSyntaxWindow *syntax_window = data;
291
292   if ( sd->length < 0 )
293     return;
294
295   if ( sd->type != gdk_atom_intern ("UTF8_STRING", FALSE))
296     return;
297
298   c = (gchar *) sd->data;
299
300   gtk_text_buffer_insert_at_cursor (syntax_window->buffer,
301                                     (gchar *) sd->data,
302                                     sd->length);
303
304 }
305
306 static void
307 on_edit_paste (PsppireSyntaxWindow *sw)
308 {
309   GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (sw));
310   GtkClipboard *clipboard =
311     gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
312
313   gtk_clipboard_request_contents (clipboard,
314                                   gdk_atom_intern ("UTF8_STRING", TRUE),
315                                   contents_received_callback,
316                                   sw);
317 }
318
319
320 /* Check to see if CLIP holds a target which we know how to paste,
321    and set the sensitivity of the Paste action accordingly.
322  */
323 static void
324 set_paste_sensitivity (GtkClipboard *clip, GdkEventOwnerChange *event, gpointer data)
325 {
326   gint i;
327   gboolean compatible_target = FALSE;
328   PsppireSyntaxWindow *sw = PSPPIRE_SYNTAX_WINDOW (data);
329
330   for (i = 0 ; i < sizeof (targets) / sizeof (targets[0]) ; ++i)
331     {
332       GdkAtom atom = gdk_atom_intern (targets[i].target, TRUE);
333       if ( gtk_clipboard_wait_is_target_available (clip, atom))
334         {
335           compatible_target = TRUE;
336           break;
337         }
338     }
339
340   gtk_action_set_sensitive (sw->edit_paste, compatible_target);
341 }
342
343
344 \f
345
346 /* Parse and execute all the text in the buffer */
347 static void
348 on_run_all (GtkMenuItem *menuitem, gpointer user_data)
349 {
350   GtkTextIter begin, end;
351   PsppireSyntaxWindow *se = PSPPIRE_SYNTAX_WINDOW (user_data);
352
353   gtk_text_buffer_get_iter_at_offset (se->buffer, &begin, 0);
354   gtk_text_buffer_get_iter_at_offset (se->buffer, &end, -1);
355
356   editor_execute_syntax (se, begin, end);
357 }
358
359 /* Parse and execute the currently selected text */
360 static void
361 on_run_selection (GtkMenuItem *menuitem, gpointer user_data)
362 {
363   GtkTextIter begin, end;
364   PsppireSyntaxWindow *se = PSPPIRE_SYNTAX_WINDOW (user_data);
365
366   if ( gtk_text_buffer_get_selection_bounds (se->buffer, &begin, &end) )
367     editor_execute_syntax (se, begin, end);
368 }
369
370
371 /* Parse and execute the from the current line, to the end of the
372    buffer */
373 static void
374 on_run_to_end (GtkMenuItem *menuitem, gpointer user_data)
375 {
376   GtkTextIter begin, end;
377   GtkTextIter here;
378   gint line;
379
380   PsppireSyntaxWindow *se = PSPPIRE_SYNTAX_WINDOW (user_data);
381
382   /* Get the current line */
383   gtk_text_buffer_get_iter_at_mark (se->buffer,
384                                     &here,
385                                     gtk_text_buffer_get_insert (se->buffer)
386                                     );
387
388   line = gtk_text_iter_get_line (&here) ;
389
390   /* Now set begin and end to the start of this line, and end of buffer
391      respectively */
392   gtk_text_buffer_get_iter_at_line (se->buffer, &begin, line);
393   gtk_text_buffer_get_iter_at_line (se->buffer, &end, -1);
394
395   editor_execute_syntax (se, begin, end);
396 }
397
398
399
400 /* Parse and execute the current line */
401 static void
402 on_run_current_line (GtkMenuItem *menuitem, gpointer user_data)
403 {
404   GtkTextIter begin, end;
405   GtkTextIter here;
406   gint line;
407
408   PsppireSyntaxWindow *se = PSPPIRE_SYNTAX_WINDOW (user_data);
409
410   /* Get the current line */
411   gtk_text_buffer_get_iter_at_mark (se->buffer,
412                                     &here,
413                                     gtk_text_buffer_get_insert (se->buffer)
414                                     );
415
416   line = gtk_text_iter_get_line (&here) ;
417
418   /* Now set begin and end to the start of this line, and start of
419      following line respectively */
420   gtk_text_buffer_get_iter_at_line (se->buffer, &begin, line);
421   gtk_text_buffer_get_iter_at_line (se->buffer, &end, line + 1);
422
423   editor_execute_syntax (se, begin, end);
424 }
425
426
427
428 /* Append ".sps" to FILENAME if necessary.
429    The returned result must be freed when no longer required.
430  */
431 static gchar *
432 append_suffix (const gchar *filename)
433 {
434   if ( ! g_str_has_suffix (filename, ".sps" ) &&
435        ! g_str_has_suffix (filename, ".SPS" ) )
436     {
437       return g_strdup_printf ("%s.sps", filename);
438     }
439
440   return xstrdup (filename);
441 }
442
443 /*
444   Save BUFFER to the file called FILENAME.
445   FILENAME must be encoded in Glib filename encoding.
446   If successful, clears the buffer's modified flag.
447 */
448 static gboolean
449 save_editor_to_file (PsppireSyntaxWindow *se,
450                      const gchar *filename,
451                      GError **err)
452 {
453   GtkTextBuffer *buffer = se->buffer;
454   gboolean result ;
455   GtkTextIter start, stop;
456   gchar *text;
457
458   gchar *suffixedname;
459   g_assert (filename);
460
461   suffixedname = append_suffix (filename);
462
463   gtk_text_buffer_get_iter_at_line (buffer, &start, 0);
464   gtk_text_buffer_get_iter_at_offset (buffer, &stop, -1);
465
466   text = gtk_text_buffer_get_text (buffer, &start, &stop, FALSE);
467
468   result =  g_file_set_contents (suffixedname, text, -1, err);
469
470   g_free (suffixedname);
471
472   if ( result )
473     {
474       char *fn = g_filename_display_name (filename);
475       gchar *msg = g_strdup_printf (_("Saved file `%s'"), fn);
476       g_free (fn);
477       gtk_statusbar_push (GTK_STATUSBAR (se->sb), se->text_context, msg);
478       gtk_text_buffer_set_modified (buffer, FALSE);
479       g_free (msg);
480     }
481
482   return result;
483 }
484
485
486 /* PsppireWindow 'pick_Filename' callback. */
487 static void
488 syntax_pick_filename (PsppireWindow *se)
489 {
490   GtkFileFilter *filter;
491   gint response;
492
493   GtkWidget *dialog =
494     gtk_file_chooser_dialog_new (_("Save Syntax"),
495                                  GTK_WINDOW (se),
496                                  GTK_FILE_CHOOSER_ACTION_SAVE,
497                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
498                                  GTK_STOCK_SAVE,   GTK_RESPONSE_ACCEPT,
499                                  NULL);
500
501   filter = gtk_file_filter_new ();
502   gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
503   gtk_file_filter_add_pattern (filter, "*.sps");
504   gtk_file_filter_add_pattern (filter, "*.SPS");
505   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
506
507   filter = gtk_file_filter_new ();
508   gtk_file_filter_set_name (filter, _("All Files"));
509   gtk_file_filter_add_pattern (filter, "*");
510   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
511
512   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
513                                                   TRUE);
514   response = gtk_dialog_run (GTK_DIALOG (dialog));
515
516   if ( response == GTK_RESPONSE_ACCEPT )
517     {
518       char *filename =
519         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog) );
520       psppire_window_set_filename (se, filename);
521       free (filename);
522     }
523
524   gtk_widget_destroy (dialog);
525 }
526
527
528 /* PsppireWindow 'save' callback. */
529 static void
530 syntax_save (PsppireWindow *se)
531 {
532   const gchar *filename = psppire_window_get_filename (se);
533   GError *err = NULL;
534   save_editor_to_file (PSPPIRE_SYNTAX_WINDOW (se), filename, &err);
535   if ( err )
536     {
537       msg (ME, "%s", err->message);
538       g_error_free (err);
539     }
540 }
541
542
543 /* Callback for the File->Quit menuitem */
544 static gboolean
545 on_quit (GtkMenuItem *menuitem, gpointer    user_data)
546 {
547   psppire_quit ();
548
549   return FALSE;
550 }
551
552
553 void
554 create_syntax_window (void)
555 {
556   GtkWidget *w = psppire_syntax_window_new ();
557   gtk_widget_show (w);
558 }
559
560 void
561 open_syntax_window (const char *file_name)
562 {
563   GtkWidget *se = psppire_syntax_window_new ();
564
565   if ( psppire_window_load (PSPPIRE_WINDOW (se), file_name) )
566     gtk_widget_show (se);
567   else
568     gtk_widget_destroy (se);
569 }
570
571 static void
572 on_text_changed (GtkTextBuffer *buffer, PsppireSyntaxWindow *window)
573 {
574   gtk_statusbar_pop (GTK_STATUSBAR (window->sb), window->text_context);
575 }
576
577 static void
578 on_modified_changed (GtkTextBuffer *buffer, PsppireWindow *window)
579 {
580   if (gtk_text_buffer_get_modified (buffer))
581     psppire_window_set_unsaved (window);
582 }
583
584 static void
585 psppire_syntax_window_init (PsppireSyntaxWindow *window)
586 {
587   GtkBuilder *xml = builder_new ("syntax-editor.ui");
588   GtkWidget *box = gtk_vbox_new (FALSE, 0);
589
590   GtkWidget *menubar = get_widget_assert (xml, "menubar");
591   GtkWidget *sw = get_widget_assert (xml, "scrolledwindow8");
592
593
594   GtkWidget *text_view = get_widget_assert (xml, "syntax_text_view");
595
596   GtkClipboard *clip_selection = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
597   GtkClipboard *clip_primary =   gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_PRIMARY);
598
599   window->cliptext = NULL;
600   window->dispose_has_run = FALSE;
601
602   window->edit_delete = get_action_assert (xml, "edit_delete");
603   window->edit_copy = get_action_assert (xml, "edit_copy");
604   window->edit_cut = get_action_assert (xml, "edit_cut");
605   window->edit_paste = get_action_assert (xml, "edit_paste");
606
607   window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
608
609   window->sb = get_widget_assert (xml, "statusbar2");
610   window->text_context = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->sb), "Text Context");
611
612   g_signal_connect (window->buffer, "changed", 
613                     G_CALLBACK (on_text_changed), window);
614
615   g_signal_connect (window->buffer, "modified-changed", 
616                     G_CALLBACK (on_modified_changed), window);
617
618   window->sel_handler = g_signal_connect_swapped (clip_primary, "owner-change", 
619                                                    G_CALLBACK (selection_changed), window);
620
621   window->ps_handler = g_signal_connect (clip_selection, "owner-change", 
622                                           G_CALLBACK (set_paste_sensitivity), window);
623
624   connect_help (xml);
625
626   gtk_container_add (GTK_CONTAINER (window), box);
627
628   g_object_ref (menubar);
629
630   g_object_ref (sw);
631
632   g_object_ref (window->sb);
633
634   gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
635   gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
636   gtk_box_pack_start (GTK_BOX (box), window->sb, FALSE, TRUE, 0);
637
638   gtk_widget_show_all (box);
639
640   g_signal_connect_swapped (get_action_assert (xml,"file_new_syntax"), "activate", G_CALLBACK (create_syntax_window), NULL);
641
642   g_signal_connect (get_action_assert (xml,"file_new_data"),
643                     "activate",
644                     G_CALLBACK (create_data_window),
645                     window);
646
647   g_signal_connect_swapped (get_action_assert (xml, "file_open"),
648                     "activate",
649                     G_CALLBACK (psppire_window_open),
650                     window);
651
652   g_signal_connect_swapped (get_action_assert (xml, "file_save"),
653                     "activate",
654                     G_CALLBACK (psppire_window_save),
655                     window);
656
657   g_signal_connect_swapped (get_action_assert (xml, "file_save_as"),
658                     "activate",
659                     G_CALLBACK (psppire_window_save_as),
660                     window);
661
662   g_signal_connect (get_action_assert (xml,"file_quit"),
663                     "activate",
664                     G_CALLBACK (on_quit),
665                     window);
666
667   g_signal_connect_swapped (window->edit_delete,
668                     "activate",
669                     G_CALLBACK (on_edit_delete),
670                     window);
671
672   g_signal_connect_swapped (window->edit_copy,
673                     "activate",
674                     G_CALLBACK (on_edit_copy),
675                     window);
676
677   g_signal_connect_swapped (window->edit_cut,
678                     "activate",
679                     G_CALLBACK (on_edit_cut),
680                     window);
681
682   g_signal_connect_swapped (window->edit_paste,
683                     "activate",
684                     G_CALLBACK (on_edit_paste),
685                     window);
686
687   g_signal_connect (get_action_assert (xml,"run_all"),
688                     "activate",
689                     G_CALLBACK (on_run_all),
690                     window);
691
692   g_signal_connect (get_action_assert (xml,"run_selection"),
693                     "activate",
694                     G_CALLBACK (on_run_selection),
695                     window);
696
697   g_signal_connect (get_action_assert (xml,"run_current_line"),
698                     "activate",
699                     G_CALLBACK (on_run_current_line),
700                     window);
701
702   g_signal_connect (get_action_assert (xml,"run_to_end"),
703                     "activate",
704                     G_CALLBACK (on_run_to_end),
705                     window);
706
707   g_signal_connect (get_action_assert (xml,"windows_minimise_all"),
708                     "activate",
709                     G_CALLBACK (psppire_window_minimise_all), NULL);
710
711
712   {
713   GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (xml, "uimanager1", GTK_TYPE_UI_MANAGER));
714
715   merge_help_menu (uim);
716
717   PSPPIRE_WINDOW (window)->menu =
718     GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
719   }
720
721   g_object_unref (xml);
722 }
723
724
725
726
727
728 GtkWidget*
729 psppire_syntax_window_new (void)
730 {
731   return GTK_WIDGET (g_object_new (psppire_syntax_window_get_type (),
732                                    /* TRANSLATORS: This will form a filename.  Please avoid whitespace. */
733                                    "description", _("Syntax Editor"),
734                                    NULL));
735 }
736
737 static void
738 error_dialog (GtkWindow *w, const gchar *filename,  GError *err)
739 {
740   gchar *fn = g_filename_display_basename (filename);
741
742   GtkWidget *dialog =
743     gtk_message_dialog_new (w,
744                             GTK_DIALOG_DESTROY_WITH_PARENT,
745                             GTK_MESSAGE_ERROR,
746                             GTK_BUTTONS_CLOSE,
747                             _("Cannot load syntax file `%s'"),
748                             fn);
749
750   g_free (fn);
751
752   g_object_set (dialog, "icon-name", "psppicon", NULL);
753
754   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
755                                             "%s", err->message);
756
757   gtk_dialog_run (GTK_DIALOG (dialog));
758
759   gtk_widget_destroy (dialog);
760 }
761
762 /*
763   Loads the buffer from the file called FILENAME
764 */
765 gboolean
766 syntax_load (PsppireWindow *window, const gchar *filename)
767 {
768   GError *err = NULL;
769   gchar *text_locale = NULL;
770   gchar *text_utf8 = NULL;
771   gsize len_locale = -1;
772   gsize len_utf8 = -1;
773   GtkTextIter iter;
774   PsppireSyntaxWindow *sw = PSPPIRE_SYNTAX_WINDOW (window);
775
776   /* FIXME: What if it's a very big file ? */
777   if ( ! g_file_get_contents (filename, &text_locale, &len_locale, &err) )
778     {
779       error_dialog (GTK_WINDOW (window), filename, err);
780       g_clear_error (&err);
781       return FALSE;
782     }
783
784   text_utf8 = g_locale_to_utf8 (text_locale, len_locale, NULL, &len_utf8, &err);
785
786   free (text_locale);
787
788   if ( text_utf8 == NULL )
789     {
790       error_dialog (GTK_WINDOW (window), filename, err);
791       g_clear_error (&err);
792       return FALSE;
793     }
794
795   gtk_text_buffer_get_iter_at_line (sw->buffer, &iter, 0);
796
797   gtk_text_buffer_insert (sw->buffer, &iter, text_utf8, len_utf8);
798
799   gtk_text_buffer_set_modified (sw->buffer, FALSE);
800
801   free (text_utf8);
802
803   return TRUE;
804 }
805
806 \f
807
808 static void
809 psppire_syntax_window_iface_init (PsppireWindowIface *iface)
810 {
811   iface->save = syntax_save;
812   iface->pick_filename = syntax_pick_filename;
813   iface->load = syntax_load;
814 }
815