45b6521255aebd5c5bb32e5ac4227556a83e5f3f
[pspp-builds.git] / 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/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 /* Callback for the File->SaveAs menuitem */
487 static void
488 syntax_save_as (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       GError *err = NULL;
519       char *filename =
520         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog) );
521
522       if ( ! save_editor_to_file (PSPPIRE_SYNTAX_WINDOW (se), filename, &err) )
523         {
524           msg ( ME, "%s", err->message );
525           g_error_free (err);
526         }
527
528       free (filename);
529     }
530
531   gtk_widget_destroy (dialog);
532 }
533
534
535 /* Callback for the File->Save menuitem */
536 static void
537 syntax_save (PsppireWindow *se)
538 {
539   const gchar *filename = psppire_window_get_filename (se);
540
541   if ( filename == NULL )
542     syntax_save_as (se);
543   else
544     {
545       GError *err = NULL;
546       save_editor_to_file (PSPPIRE_SYNTAX_WINDOW (se), filename, &err);
547       if ( err )
548         {
549           msg (ME, "%s", err->message);
550           g_error_free (err);
551         }
552     }
553 }
554
555
556 /* Callback for the File->Quit menuitem */
557 static gboolean
558 on_quit (GtkMenuItem *menuitem, gpointer    user_data)
559 {
560   psppire_quit ();
561
562   return FALSE;
563 }
564
565
566 void
567 create_syntax_window (void)
568 {
569   GtkWidget *w = psppire_syntax_window_new ();
570   gtk_widget_show (w);
571 }
572
573 void
574 open_syntax_window (const char *file_name)
575 {
576   GtkWidget *se = psppire_syntax_window_new ();
577
578   if ( psppire_window_load (PSPPIRE_WINDOW (se), file_name) )
579     gtk_widget_show (se);
580   else
581     gtk_widget_destroy (se);
582 }
583
584 static void
585 on_text_changed (GtkTextBuffer *buffer, PsppireSyntaxWindow *window)
586 {
587   gtk_statusbar_pop (GTK_STATUSBAR (window->sb), window->text_context);
588 }
589
590 static void
591 on_modified_changed (GtkTextBuffer *buffer, PsppireWindow *window)
592 {
593   if (gtk_text_buffer_get_modified (buffer))
594     psppire_window_set_unsaved (window);
595 }
596
597 static void
598 psppire_syntax_window_init (PsppireSyntaxWindow *window)
599 {
600   GtkBuilder *xml = builder_new ("syntax-editor.ui");
601   GtkWidget *box = gtk_vbox_new (FALSE, 0);
602
603   GtkWidget *menubar = get_widget_assert (xml, "menubar");
604   GtkWidget *sw = get_widget_assert (xml, "scrolledwindow8");
605
606
607   GtkWidget *text_view = get_widget_assert (xml, "syntax_text_view");
608
609   GtkClipboard *clip_selection = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
610   GtkClipboard *clip_primary =   gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_PRIMARY);
611
612   window->cliptext = NULL;
613   window->dispose_has_run = FALSE;
614
615   window->edit_delete = get_action_assert (xml, "edit_delete");
616   window->edit_copy = get_action_assert (xml, "edit_copy");
617   window->edit_cut = get_action_assert (xml, "edit_cut");
618   window->edit_paste = get_action_assert (xml, "edit_paste");
619
620   window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
621
622   window->sb = get_widget_assert (xml, "statusbar2");
623   window->text_context = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->sb), "Text Context");
624
625   g_signal_connect (window->buffer, "changed", 
626                     G_CALLBACK (on_text_changed), window);
627
628   g_signal_connect (window->buffer, "modified-changed", 
629                     G_CALLBACK (on_modified_changed), window);
630
631   window->sel_handler = g_signal_connect_swapped (clip_primary, "owner-change", 
632                                                    G_CALLBACK (selection_changed), window);
633
634   window->ps_handler = g_signal_connect (clip_selection, "owner-change", 
635                                           G_CALLBACK (set_paste_sensitivity), window);
636
637   connect_help (xml);
638
639   gtk_container_add (GTK_CONTAINER (window), box);
640
641   g_object_ref (menubar);
642
643   g_object_ref (sw);
644
645   g_object_ref (window->sb);
646
647   gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
648   gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
649   gtk_box_pack_start (GTK_BOX (box), window->sb, FALSE, TRUE, 0);
650
651   gtk_widget_show_all (box);
652
653   g_signal_connect_swapped (get_action_assert (xml,"file_new_syntax"), "activate", G_CALLBACK (create_syntax_window), NULL);
654
655 #if 0
656   g_signal_connect (get_action_assert (xml,"file_new_data"),
657                     "activate",
658                     G_CALLBACK (create_data_window),
659                     window);
660 #endif
661
662   g_signal_connect_swapped (get_action_assert (xml, "file_save"),
663                     "activate",
664                     G_CALLBACK (syntax_save),
665                     window);
666
667   g_signal_connect_swapped (get_action_assert (xml, "file_save_as"),
668                     "activate",
669                     G_CALLBACK (syntax_save_as),
670                     window);
671
672   g_signal_connect (get_action_assert (xml,"file_quit"),
673                     "activate",
674                     G_CALLBACK (on_quit),
675                     window);
676
677   g_signal_connect_swapped (window->edit_delete,
678                     "activate",
679                     G_CALLBACK (on_edit_delete),
680                     window);
681
682   g_signal_connect_swapped (window->edit_copy,
683                     "activate",
684                     G_CALLBACK (on_edit_copy),
685                     window);
686
687   g_signal_connect_swapped (window->edit_cut,
688                     "activate",
689                     G_CALLBACK (on_edit_cut),
690                     window);
691
692   g_signal_connect_swapped (window->edit_paste,
693                     "activate",
694                     G_CALLBACK (on_edit_paste),
695                     window);
696
697   g_signal_connect (get_action_assert (xml,"run_all"),
698                     "activate",
699                     G_CALLBACK (on_run_all),
700                     window);
701
702   g_signal_connect (get_action_assert (xml,"run_selection"),
703                     "activate",
704                     G_CALLBACK (on_run_selection),
705                     window);
706
707   g_signal_connect (get_action_assert (xml,"run_current_line"),
708                     "activate",
709                     G_CALLBACK (on_run_current_line),
710                     window);
711
712   g_signal_connect (get_action_assert (xml,"run_to_end"),
713                     "activate",
714                     G_CALLBACK (on_run_to_end),
715                     window);
716
717   g_signal_connect (get_action_assert (xml,"windows_minimise_all"),
718                     "activate",
719                     G_CALLBACK (psppire_window_minimise_all), NULL);
720
721
722   {
723   GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (xml, "uimanager1", GTK_TYPE_UI_MANAGER));
724
725   merge_help_menu (uim);
726
727   PSPPIRE_WINDOW (window)->menu =
728     GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
729   }
730
731   g_object_unref (xml);
732 }
733
734
735
736
737
738 GtkWidget*
739 psppire_syntax_window_new (void)
740 {
741   return GTK_WIDGET (g_object_new (psppire_syntax_window_get_type (),
742                                    /* TRANSLATORS: This will form a filename.  Please avoid whitespace. */
743                                    "filename", _("Syntax"),
744                                    "description", _("Syntax Editor"),
745                                    NULL));
746 }
747
748 static void
749 error_dialog (GtkWindow *w, const gchar *filename,  GError *err)
750 {
751   gchar *fn = g_filename_display_basename (filename);
752
753   GtkWidget *dialog =
754     gtk_message_dialog_new (w,
755                             GTK_DIALOG_DESTROY_WITH_PARENT,
756                             GTK_MESSAGE_ERROR,
757                             GTK_BUTTONS_CLOSE,
758                             _("Cannot load syntax file `%s'"),
759                             fn);
760
761   g_free (fn);
762
763   g_object_set (dialog, "icon-name", "psppicon", NULL);
764
765   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
766                                             "%s", err->message);
767
768   gtk_dialog_run (GTK_DIALOG (dialog));
769
770   gtk_widget_destroy (dialog);
771 }
772
773 /*
774   Loads the buffer from the file called FILENAME
775 */
776 gboolean
777 syntax_load (PsppireWindow *window, const gchar *filename)
778 {
779   GError *err = NULL;
780   gchar *text_locale = NULL;
781   gchar *text_utf8 = NULL;
782   gsize len_locale = -1;
783   gsize len_utf8 = -1;
784   GtkTextIter iter;
785   PsppireSyntaxWindow *sw = PSPPIRE_SYNTAX_WINDOW (window);
786
787   /* FIXME: What if it's a very big file ? */
788   if ( ! g_file_get_contents (filename, &text_locale, &len_locale, &err) )
789     {
790       error_dialog (GTK_WINDOW (window), filename, err);
791       g_clear_error (&err);
792       return FALSE;
793     }
794
795   text_utf8 = g_locale_to_utf8 (text_locale, len_locale, NULL, &len_utf8, &err);
796
797   free (text_locale);
798
799   if ( text_utf8 == NULL )
800     {
801       error_dialog (GTK_WINDOW (window), filename, err);
802       g_clear_error (&err);
803       return FALSE;
804     }
805
806   gtk_text_buffer_get_iter_at_line (sw->buffer, &iter, 0);
807
808   gtk_text_buffer_insert (sw->buffer, &iter, text_utf8, len_utf8);
809
810   gtk_text_buffer_set_modified (sw->buffer, FALSE);
811
812   free (text_utf8);
813
814   return TRUE;
815 }
816
817 \f
818
819 static void
820 psppire_syntax_window_iface_init (PsppireWindowIface *iface)
821 {
822   iface->save = syntax_save;
823   iface->load = syntax_load;
824 }
825