Make the missing value code do more work, so that its callers can do
[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
32
33
34 #include <language/command.h>
35 #include <data/procedure.h>
36 #include "syntax-editor.h"
37 #include "syntax-editor-source.h"
38
39 extern struct source_stream *the_source_stream ;
40 extern struct lexer *the_lexer;
41 extern struct dataset *the_dataset;
42
43 extern GladeXML *xml;
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   if ( TRUE == gtk_text_buffer_get_modified (se->buffer))
56     {
57       gint response;
58       GtkWidget *dialog =
59         gtk_message_dialog_new (GTK_WINDOW(se->window),
60                                 GTK_DIALOG_MODAL,
61                                 GTK_MESSAGE_QUESTION,
62                                 GTK_BUTTONS_NONE,
63                                 _("Save contents of syntax editor to %s?"),
64                                 se->name ? se->name : _("Untitled")
65                                 );
66
67       gtk_dialog_add_button  (GTK_DIALOG(dialog),
68                               GTK_STOCK_YES,
69                               GTK_RESPONSE_ACCEPT);
70       gtk_dialog_add_button  (GTK_DIALOG(dialog),
71                               GTK_STOCK_NO,
72                               GTK_RESPONSE_REJECT);
73       gtk_dialog_add_button  (GTK_DIALOG(dialog),
74                               GTK_STOCK_CANCEL,
75                               GTK_RESPONSE_CANCEL);
76
77
78       response = gtk_dialog_run (GTK_DIALOG(dialog));
79
80       gtk_widget_destroy (dialog);
81
82       if ( response == GTK_RESPONSE_ACCEPT )
83         {
84           GError *err = NULL;
85
86           if ( ! save_editor_to_file (se, se->name ? se->name : _("Untitled"),
87                                       &err) )
88             {
89               msg (ME, err->message);
90               g_error_free (err);
91             }
92         }
93
94       if ( response == GTK_RESPONSE_CANCEL )
95         return ;
96     }
97
98   gtk_widget_destroy (se->window);
99 }
100
101 /* Callback for the File->SaveAs menuitem */
102 static void
103 on_syntax_save_as   (GtkMenuItem     *menuitem,
104                   gpointer         user_data)
105 {
106   GtkFileFilter *filter;
107   gint response;
108   struct syntax_editor *se = user_data;
109
110   GtkWidget *dialog =
111     gtk_file_chooser_dialog_new (_("Save Syntax"),
112                                  GTK_WINDOW(se->window),
113                                  GTK_FILE_CHOOSER_ACTION_SAVE,
114                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
115                                  GTK_STOCK_SAVE,   GTK_RESPONSE_ACCEPT,
116                                  NULL);
117
118   filter = gtk_file_filter_new ();
119   gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
120   gtk_file_filter_add_pattern (filter, "*.sps");
121   gtk_file_filter_add_pattern (filter, "*.SPS");
122   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
123
124   filter = gtk_file_filter_new ();
125   gtk_file_filter_set_name (filter, _("All Files"));
126   gtk_file_filter_add_pattern (filter, "*");
127   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
128
129   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER(dialog),
130                                                   TRUE);
131   response = gtk_dialog_run (GTK_DIALOG (dialog));
132
133   if ( response == GTK_RESPONSE_ACCEPT )
134     {
135       GError *err = NULL;
136       char *filename =
137         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog) );
138
139       if ( save_editor_to_file (se, filename, &err) )
140         {
141           g_free (se->name);
142           se->name = g_strdup (filename);
143         }
144       else
145         {
146           msg ( ME, err->message );
147           g_error_free (err);
148         }
149
150       free (filename);
151     }
152
153   gtk_widget_destroy ( dialog );
154 }
155
156 /* Callback for the File->Save menuitem */
157 void
158 on_syntax_save   (GtkMenuItem     *menuitem,
159                   gpointer         user_data)
160 {
161   struct syntax_editor *se = user_data;
162
163   if ( se->name == NULL )
164     on_syntax_save_as (menuitem, user_data);
165   else
166     {
167       GError *err;
168       save_editor_to_file (se, se->name, &err);
169       msg (ME, err->message);
170       g_error_free (err);
171     }
172 }
173
174
175 /* Callback for the "delete" action (clicking the x on the top right
176    hand corner of the window) */
177 static gboolean
178 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
179 {
180   struct syntax_editor *se = user_data;
181   save_if_modified (se);
182   return TRUE;
183 }
184
185
186 /* Callback for the File->Quit menuitem */
187 static gboolean
188 on_quit (GtkMenuItem *menuitem, gpointer    user_data)
189 {
190   struct syntax_editor *se = user_data;
191   save_if_modified (se);
192   return FALSE;
193 }
194
195 static void
196 on_run_all (GtkMenuItem *menuitem, gpointer user_data)
197 {
198   GtkTextIter begin, end;
199   struct syntax_editor *se = user_data;
200
201   gtk_text_buffer_get_iter_at_line (se->buffer, &begin, 0);
202   gtk_text_buffer_get_iter_at_line (se->buffer, &end, -1);
203
204   getl_append_source (the_source_stream,
205                       create_syntax_editor_source (se, begin, end));
206   for (;;)
207     {
208       int result = cmd_parse (the_lexer, the_dataset,
209                               proc_has_source (the_dataset)
210                               ? CMD_STATE_DATA : CMD_STATE_INITIAL);
211
212       if (result == CMD_EOF || result == CMD_FINISH)
213         break;
214     }
215 }
216
217
218 void
219 new_syntax_window (GtkMenuItem     *menuitem,
220                    gpointer         user_data);
221
222
223
224 static void open_syntax_window (GtkMenuItem *menuitem,
225                                 gpointer user_data);
226
227
228 /*
229   Create a new syntax editor with NAME.
230   If NAME is NULL, a name will be automatically assigned
231 */
232 static struct syntax_editor *
233 new_syntax_editor (const gchar *name)
234 {
235   GladeXML *new_xml ;
236   GtkWidget *text_view;
237   struct syntax_editor *se ;
238
239   new_xml = glade_xml_new  (xml->filename, "syntax_editor", NULL);
240
241   se = g_malloc (sizeof (*se));
242
243   se->window = get_widget_assert (new_xml, "syntax_editor");
244   text_view = get_widget_assert (new_xml, "syntax_text_view");
245   se->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(text_view));
246   if ( name )
247     se->name = g_strdup (name);
248   else
249     se->name = NULL;
250
251   g_signal_connect (get_widget_assert (new_xml,"file_new_syntax"),
252                     "activate",
253                     G_CALLBACK(new_syntax_window),
254                     se->window);
255
256   g_signal_connect (get_widget_assert (new_xml,"file_open_syntax"),
257                     "activate",
258                     G_CALLBACK(open_syntax_window),
259                     se->window);
260
261   g_signal_connect (get_widget_assert (new_xml,"file_quit"),
262                     "activate",
263                     G_CALLBACK(on_quit),
264                     se);
265
266   g_signal_connect (get_widget_assert (new_xml,"file_save"),
267                     "activate",
268                     G_CALLBACK(on_syntax_save),
269                     se);
270
271   g_signal_connect (get_widget_assert (new_xml,"file_save_as"),
272                     "activate",
273                     G_CALLBACK(on_syntax_save_as),
274                     se);
275
276
277   g_signal_connect (get_widget_assert (new_xml,"run_all"),
278                     "activate",
279                     G_CALLBACK(on_run_all),
280                     se);
281
282   g_object_unref (new_xml);
283
284   g_signal_connect (se->window, "delete-event",
285                     G_CALLBACK(on_delete), se);
286
287   return se;
288 }
289
290 /*
291    Callback for the File->New->Syntax menuitem
292 */
293 void
294 new_syntax_window (GtkMenuItem     *menuitem,
295                    gpointer         user_data)
296 {
297   struct syntax_editor *se =   new_syntax_editor (NULL);
298   gtk_widget_show (se->window);
299 }
300
301
302 static void
303 set_window_title_from_filename (struct syntax_editor *se,
304                                 const gchar *filename)
305 {
306   gchar *title;
307   gchar *basename ;
308   g_free (se->name);
309   se->name = strdup (filename);
310   basename = g_path_get_basename (filename);
311   title =
312     g_strdup_printf (_("%s --- PSPP Syntax Editor"), basename);
313   g_free (basename);
314   gtk_window_set_title (GTK_WINDOW(se->window), title);
315   g_free (title);
316 }
317
318
319 /*
320   Save BUFFER to the file called FILENAME.
321   If successful, clears the buffer's modified flag
322 */
323 static gboolean
324 save_editor_to_file (struct syntax_editor *se,
325                      const gchar *filename,
326                      GError **err)
327 {
328   GtkTextBuffer *buffer = se->buffer;
329   gboolean result ;
330   GtkTextIter start, stop;
331   gchar *text;
332
333   gchar *glibfilename;
334   g_assert (filename);
335
336   glibfilename = g_filename_from_utf8 (filename, -1, 0, 0, err);
337
338   if ( ! glibfilename )
339     return FALSE;
340
341   gtk_text_buffer_get_iter_at_line (buffer, &start, 0);
342   gtk_text_buffer_get_iter_at_offset (buffer, &stop, -1);
343
344   text = gtk_text_buffer_get_text (buffer, &start, &stop, FALSE);
345
346   result =  g_file_set_contents (glibfilename, text, -1, err);
347
348   if ( result )
349     {
350       set_window_title_from_filename (se, filename);
351       gtk_text_buffer_set_modified (buffer, FALSE);
352     }
353
354   return result;
355 }
356
357
358 /*
359   Loads the buffer from the file called FILENAME
360 */
361 static gboolean
362 load_editor_from_file (struct syntax_editor *se,
363                        const gchar *filename,
364                        GError **err)
365 {
366   GtkTextBuffer *buffer = se->buffer;
367   gchar *text;
368   GtkTextIter iter;
369
370   gchar *glibfilename = g_filename_from_utf8 (filename, -1, 0, 0, err);
371
372   if ( ! glibfilename )
373     return FALSE;
374
375   /* FIXME: What if it's a very big file ? */
376   if ( ! g_file_get_contents (glibfilename, &text, NULL, err) )
377     {
378       g_free (glibfilename);
379       return FALSE;
380     }
381   g_free (glibfilename);
382
383   gtk_text_buffer_get_iter_at_line (buffer, &iter, 0);
384
385   gtk_text_buffer_insert (buffer, &iter, text, -1);
386
387   set_window_title_from_filename (se, filename);
388   gtk_text_buffer_set_modified (buffer, FALSE);
389
390   return TRUE;
391 }
392
393
394 /* Callback for the File->Open->Syntax menuitem */
395 static void
396 open_syntax_window (GtkMenuItem *menuitem, gpointer parent)
397 {
398   GtkFileFilter *filter;
399   gint response;
400
401   GtkWidget *dialog =
402     gtk_file_chooser_dialog_new (_("Open Syntax"),
403                                  GTK_WINDOW(parent),
404                                  GTK_FILE_CHOOSER_ACTION_OPEN,
405                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
406                                  GTK_STOCK_OPEN,   GTK_RESPONSE_ACCEPT,
407                                  NULL);
408
409   filter = gtk_file_filter_new ();
410   gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
411   gtk_file_filter_add_pattern (filter, "*.sps");
412   gtk_file_filter_add_pattern (filter, "*.SPS");
413   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
414
415   filter = gtk_file_filter_new ();
416   gtk_file_filter_set_name (filter, _("All Files"));
417   gtk_file_filter_add_pattern (filter, "*");
418   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
419
420   response = gtk_dialog_run (GTK_DIALOG (dialog));
421
422   if (response == GTK_RESPONSE_ACCEPT)
423     {
424       const char *file_name = gtk_file_chooser_get_filename
425         (GTK_FILE_CHOOSER (dialog));
426
427       struct syntax_editor *se = new_syntax_editor (file_name);
428
429       load_editor_from_file (se, file_name, NULL);
430
431       gtk_widget_show (se->window);
432     }
433
434   gtk_widget_destroy (dialog);
435 }
436
437
438 #if 1
439 /* FIXME: get rid of these functions */
440 void
441 on_syntax4_activate   (GtkMenuItem     *menuitem,
442                        gpointer         user_data)
443 {
444   g_print ("%s\n", __FUNCTION__);
445 }
446
447
448
449 void
450 on_syntax2_activate   (GtkMenuItem     *menuitem,
451                        gpointer         user_data)
452 {
453   g_print ("%s\n", __FUNCTION__);
454 }
455
456 void
457 on_syntax1_activate   (GtkMenuItem     *menuitem,
458                        gpointer         user_data)
459 {
460   g_print ("%s\n", __FUNCTION__);
461   new_syntax_window (menuitem, user_data);
462 }
463 #endif
464
465
466
467
468