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