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