Whitespace changes only.
[pspp-builds.git] / src / ui / gui / syntax-editor.c
1 /*
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2006  Free Software Foundation
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18     02110-1301, USA. */
19
20 #include <config.h>
21 #include <stdlib.h>
22 #include <gettext.h>
23 #define _(msgid) gettext (msgid)
24 #define N_(msgid) msgid
25
26 #include <glade/glade.h>
27 #include <gtk/gtk.h>
28 #include <libpspp/message.h>
29 #include <libpspp/getl.h>
30 #include "helper.h"
31 #include "data-editor.h"
32 #include "about.h"
33
34 #include "window-manager.h"
35
36 #include <language/lexer/lexer.h>
37 #include <language/command.h>
38 #include <data/procedure.h>
39 #include "syntax-editor.h"
40 #include "syntax-editor-source.h"
41
42 extern struct source_stream *the_source_stream ;
43 extern struct dataset *the_dataset;
44
45 static gboolean save_editor_to_file (struct syntax_editor *se,
46                                      const gchar *filename,
47                                      GError **err);
48
49 /* If the buffer's modified flag is set, then save it, and close the window.
50    Otherwise just close the window.
51 */
52 static void
53 save_if_modified (struct syntax_editor *se)
54 {
55   struct editor_window *e = (struct editor_window *) se;
56   if ( TRUE == gtk_text_buffer_get_modified (se->buffer))
57     {
58       gint response;
59       GtkWidget *dialog =
60         gtk_message_dialog_new (GTK_WINDOW (e->window),
61                                 GTK_DIALOG_MODAL,
62                                 GTK_MESSAGE_QUESTION,
63                                 GTK_BUTTONS_NONE,
64                                 _("Save contents of syntax editor to %s?"),
65                                 e->name ? e->name : _("Untitled")
66                                 );
67
68       gtk_dialog_add_button  (GTK_DIALOG (dialog),
69                               GTK_STOCK_YES,
70                               GTK_RESPONSE_ACCEPT);
71       gtk_dialog_add_button  (GTK_DIALOG (dialog),
72                               GTK_STOCK_NO,
73                               GTK_RESPONSE_REJECT);
74       gtk_dialog_add_button  (GTK_DIALOG (dialog),
75                               GTK_STOCK_CANCEL,
76                               GTK_RESPONSE_CANCEL);
77
78
79       response = gtk_dialog_run (GTK_DIALOG (dialog));
80
81       gtk_widget_destroy (dialog);
82
83       if ( response == GTK_RESPONSE_ACCEPT )
84         {
85           GError *err = NULL;
86
87           if ( ! save_editor_to_file (se, e->name ? e->name : _("Untitled"),
88                                       &err) )
89             {
90               msg (ME, err->message);
91               g_error_free (err);
92             }
93         }
94
95       if ( response == GTK_RESPONSE_CANCEL )
96         return ;
97     }
98
99   gtk_widget_destroy (e->window);
100 }
101
102 /* Callback for the File->SaveAs menuitem */
103 static void
104 on_syntax_save_as   (GtkMenuItem     *menuitem,
105                   gpointer         user_data)
106 {
107   GtkFileFilter *filter;
108   gint response;
109   struct syntax_editor *se = user_data;
110   struct editor_window *e = user_data;
111
112   GtkWidget *dialog =
113     gtk_file_chooser_dialog_new (_("Save Syntax"),
114                                  GTK_WINDOW (e->window),
115                                  GTK_FILE_CHOOSER_ACTION_SAVE,
116                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
117                                  GTK_STOCK_SAVE,   GTK_RESPONSE_ACCEPT,
118                                  NULL);
119
120   filter = gtk_file_filter_new ();
121   gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
122   gtk_file_filter_add_pattern (filter, "*.sps");
123   gtk_file_filter_add_pattern (filter, "*.SPS");
124   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
125
126   filter = gtk_file_filter_new ();
127   gtk_file_filter_set_name (filter, _("All Files"));
128   gtk_file_filter_add_pattern (filter, "*");
129   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
130
131   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
132                                                   TRUE);
133   response = gtk_dialog_run (GTK_DIALOG (dialog));
134
135   if ( response == GTK_RESPONSE_ACCEPT )
136     {
137       GError *err = NULL;
138       char *filename =
139         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog) );
140
141       if ( save_editor_to_file (se, filename, &err) )
142         {
143           g_free (e->name);
144           e->name = g_strdup (filename);
145         }
146       else
147         {
148           msg ( ME, err->message );
149           g_error_free (err);
150         }
151
152       free (filename);
153     }
154
155   gtk_widget_destroy ( dialog );
156 }
157
158 /* Callback for the File->Save menuitem */
159 void
160 on_syntax_save   (GtkMenuItem     *menuitem,
161                   gpointer         user_data)
162 {
163   struct syntax_editor *se = user_data;
164   struct editor_window *e = user_data;
165
166   if ( e->name == NULL )
167     on_syntax_save_as (menuitem, user_data);
168   else
169     {
170       GError *err;
171       save_editor_to_file (se, e->name, &err);
172       msg (ME, err->message);
173       g_error_free (err);
174     }
175 }
176
177
178 /* Callback for the "delete" action (clicking the x on the top right
179    hand corner of the window) */
180 static gboolean
181 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
182 {
183   struct syntax_editor *se = user_data;
184   save_if_modified (se);
185   return TRUE;
186 }
187
188
189 /* Callback for the File->Quit menuitem */
190 static gboolean
191 on_quit (GtkMenuItem *menuitem, gpointer    user_data)
192 {
193   struct syntax_editor *se = user_data;
194   save_if_modified (se);
195   return FALSE;
196 }
197
198 static void
199 execute_syntax (const struct syntax_editor *se, GtkTextIter start,
200                 GtkTextIter stop)
201 {
202   getl_append_source (the_source_stream,
203                       create_syntax_editor_source (se, start, stop));
204   for (;;)
205     {
206       int result = cmd_parse (se->lexer, the_dataset,
207                               proc_has_source (the_dataset)
208                               ? CMD_STATE_DATA : CMD_STATE_INITIAL);
209
210       if (result == CMD_EOF || result == CMD_FINISH)
211         break;
212     }
213 }
214
215 /* Parse and execute all the text in the buffer */
216 static void
217 on_run_all (GtkMenuItem *menuitem, gpointer user_data)
218 {
219   GtkTextIter begin, end;
220   struct syntax_editor *se = user_data;
221
222   gtk_text_buffer_get_iter_at_line (se->buffer, &begin, 0);
223   gtk_text_buffer_get_iter_at_line (se->buffer, &end, -1);
224
225
226   execute_syntax (se, begin, end);
227 }
228
229 /* Parse and execute the currently selected text */
230 static void
231 on_run_selection (GtkMenuItem *menuitem, gpointer user_data)
232 {
233   GtkTextIter begin, end;
234   struct syntax_editor *se = user_data;
235
236   if ( gtk_text_buffer_get_selection_bounds (se->buffer, &begin, &end) )
237     execute_syntax (se, begin, end);
238 }
239
240
241 /* Parse and execute the current line */
242 static void
243 on_run_current_line (GtkMenuItem *menuitem, gpointer user_data)
244 {
245   GtkTextIter begin, end;
246   GtkTextIter here;
247   gint line;
248
249   struct syntax_editor *se = user_data;
250
251   /* Get the current line */
252   gtk_text_buffer_get_iter_at_mark (se->buffer,
253                                     &here,
254                                     gtk_text_buffer_get_insert (se->buffer)
255                                     );
256
257   line = gtk_text_iter_get_line (&here) ;
258
259   /* Now set begin and end to the start of this line, and start of
260      following line respectively */
261   gtk_text_buffer_get_iter_at_line (se->buffer, &begin, line);
262   gtk_text_buffer_get_iter_at_line (se->buffer, &end, line + 1);
263
264   execute_syntax (se, begin, end);
265 }
266
267
268
269 /* Parse and execute the from the current line, to the end of the
270    buffer */
271 static void
272 on_run_to_end (GtkMenuItem *menuitem, gpointer user_data)
273 {
274   GtkTextIter begin, end;
275   GtkTextIter here;
276   gint line;
277
278   struct syntax_editor *se = user_data;
279
280   /* Get the current line */
281   gtk_text_buffer_get_iter_at_mark (se->buffer,
282                                     &here,
283                                     gtk_text_buffer_get_insert (se->buffer)
284                                     );
285
286   line = gtk_text_iter_get_line (&here) ;
287
288   /* Now set begin and end to the start of this line, and end of buffer
289      respectively */
290   gtk_text_buffer_get_iter_at_line (se->buffer, &begin, line);
291   gtk_text_buffer_get_iter_at_line (se->buffer, &end, -1);
292
293   execute_syntax (se, begin, end);
294 }
295
296
297
298
299 /*
300   Create a new syntax editor with NAME.
301   If NAME is NULL, a name will be automatically assigned
302 */
303 struct syntax_editor *
304 new_syntax_editor (void)
305 {
306   GladeXML *xml =
307     glade_xml_new (PKGDATADIR "/syntax-editor.glade", NULL, NULL);
308
309   GtkWidget *text_view;
310   struct syntax_editor *se ;
311   struct editor_window *e;
312
313   se = g_malloc (sizeof (*se));
314
315   e = (struct editor_window *)se;
316
317   e->window = get_widget_assert (xml, "syntax_editor");
318   text_view = get_widget_assert (xml, "syntax_text_view");
319   se->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
320   se->lexer = lex_create (the_source_stream);
321
322   g_signal_connect (get_widget_assert (xml,"file_new_syntax"),
323                     "activate",
324                     G_CALLBACK (new_syntax_window),
325                     e->window);
326
327   g_signal_connect (get_widget_assert (xml,"file_open_syntax"),
328                     "activate",
329                     G_CALLBACK (open_syntax_window),
330                     e->window);
331
332   g_signal_connect (get_widget_assert (xml,"file_new_data"),
333                     "activate",
334                     G_CALLBACK (new_data_window),
335                     e->window);
336
337   g_signal_connect (get_widget_assert (xml,"file_open_data"),
338                     "activate",
339                     G_CALLBACK (open_data_window),
340                     e->window);
341
342
343   g_signal_connect (get_widget_assert (xml,"help_about"),
344                     "activate",
345                     G_CALLBACK (about_new),
346                     e->window);
347
348
349 #if 0
350
351   g_signal_connect (get_widget_assert (xml,"file_save"),
352                     "activate",
353                     G_CALLBACK (on_syntax_save),
354                     se);
355
356   g_signal_connect (get_widget_assert (xml,"file_save_as"),
357                     "activate",
358                     G_CALLBACK (on_syntax_save_as),
359                     se);
360
361 #endif
362
363   g_signal_connect (get_widget_assert (xml,"file_quit"),
364                     "activate",
365                     G_CALLBACK (on_quit),
366                     se);
367
368
369   g_signal_connect (get_widget_assert (xml,"run_all"),
370                     "activate",
371                     G_CALLBACK (on_run_all),
372                     se);
373
374
375   g_signal_connect (get_widget_assert (xml,"run_selection"),
376                     "activate",
377                     G_CALLBACK (on_run_selection),
378                     se);
379
380   g_signal_connect (get_widget_assert (xml,"run_current_line"),
381                     "activate",
382                     G_CALLBACK (on_run_current_line),
383                     se);
384
385
386   g_signal_connect (get_widget_assert (xml,"run_to_end"),
387                     "activate",
388                     G_CALLBACK (on_run_to_end),
389                     se);
390
391
392   g_object_unref (xml);
393
394   g_signal_connect (e->window, "delete-event",
395                     G_CALLBACK (on_delete), se);
396
397
398
399   return se;
400 }
401
402 /*
403    Callback for the File->New->Syntax menuitem
404 */
405 void
406 new_syntax_window (GtkMenuItem     *menuitem,
407                    gpointer         user_data)
408 {
409   window_create (WINDOW_SYNTAX, NULL);
410 }
411
412
413 /*
414   Save BUFFER to the file called FILENAME.
415   If successful, clears the buffer's modified flag
416 */
417 static gboolean
418 save_editor_to_file (struct syntax_editor *se,
419                      const gchar *filename,
420                      GError **err)
421 {
422   GtkTextBuffer *buffer = se->buffer;
423   gboolean result ;
424   GtkTextIter start, stop;
425   gchar *text;
426
427   gchar *glibfilename;
428   g_assert (filename);
429
430   glibfilename = g_filename_from_utf8 (filename, -1, 0, 0, err);
431
432   if ( ! glibfilename )
433     return FALSE;
434
435   gtk_text_buffer_get_iter_at_line (buffer, &start, 0);
436   gtk_text_buffer_get_iter_at_offset (buffer, &stop, -1);
437
438   text = gtk_text_buffer_get_text (buffer, &start, &stop, FALSE);
439
440   result =  g_file_set_contents (glibfilename, text, -1, err);
441
442   if ( result )
443     {
444       window_set_name_from_filename ((struct editor_window *) se, filename);
445       gtk_text_buffer_set_modified (buffer, FALSE);
446     }
447
448   return result;
449 }
450
451
452 /*
453   Loads the buffer from the file called FILENAME
454 */
455 static gboolean
456 load_editor_from_file (struct syntax_editor *se,
457                        const gchar *filename,
458                        GError **err)
459 {
460   GtkTextBuffer *buffer = se->buffer;
461   gchar *text;
462   GtkTextIter iter;
463
464   gchar *glibfilename = g_filename_from_utf8 (filename, -1, 0, 0, err);
465
466   if ( ! glibfilename )
467     return FALSE;
468
469   /* FIXME: What if it's a very big file ? */
470   if ( ! g_file_get_contents (glibfilename, &text, NULL, err) )
471     {
472       g_free (glibfilename);
473       return FALSE;
474     }
475   g_free (glibfilename);
476
477   gtk_text_buffer_get_iter_at_line (buffer, &iter, 0);
478
479   gtk_text_buffer_insert (buffer, &iter, text, -1);
480
481   window_set_name_from_filename ((struct editor_window *)se, filename);
482   gtk_text_buffer_set_modified (buffer, FALSE);
483
484   return TRUE;
485 }
486
487
488 /* Callback for the File->Open->Syntax menuitem */
489 void
490 open_syntax_window (GtkMenuItem *menuitem, gpointer parent)
491 {
492   GtkFileFilter *filter;
493   gint response;
494
495   GtkWidget *dialog =
496     gtk_file_chooser_dialog_new (_("Open Syntax"),
497                                  GTK_WINDOW (parent),
498                                  GTK_FILE_CHOOSER_ACTION_OPEN,
499                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
500                                  GTK_STOCK_OPEN,   GTK_RESPONSE_ACCEPT,
501                                  NULL);
502
503   filter = gtk_file_filter_new ();
504   gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
505   gtk_file_filter_add_pattern (filter, "*.sps");
506   gtk_file_filter_add_pattern (filter, "*.SPS");
507   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
508
509   filter = gtk_file_filter_new ();
510   gtk_file_filter_set_name (filter, _("All Files"));
511   gtk_file_filter_add_pattern (filter, "*");
512   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
513
514   response = gtk_dialog_run (GTK_DIALOG (dialog));
515
516   if (response == GTK_RESPONSE_ACCEPT)
517     {
518       const char *file_name = gtk_file_chooser_get_filename
519         (GTK_FILE_CHOOSER (dialog));
520
521       struct syntax_editor *se = (struct syntax_editor *)
522         window_create (WINDOW_SYNTAX, file_name);
523
524       load_editor_from_file (se, file_name, NULL);
525     }
526
527   gtk_widget_destroy (dialog);
528 }
529