cc68cdce720dbf861fb7dc81a2f491f31397c282
[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     Written by John Darrington
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19     02110-1301, USA. */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <gettext.h>
24 #define _(msgid) gettext (msgid)
25 #define N_(msgid) msgid
26
27 #include <glade/glade.h>
28 #include <gtk/gtk.h>
29 #include <libpspp/message.h>
30
31 #include "helper.h"
32
33 extern GladeXML *xml;
34
35 struct syntax_editor
36 {
37   GtkWidget *window;      /* The top level window of the editor */
38   GtkTextBuffer *buffer;  /* The buffer which contains the text */
39   gchar *name;            /* The name of this syntax buffer/editor */
40 };
41
42 static gboolean save_editor_to_file (struct syntax_editor *se,
43                                      const gchar *filename,
44                                      GError **err);
45
46 /* If the buffer's modified flag is set, then save it, and close the window.
47    Otherwise just close the window.
48 */
49 static void
50 save_if_modified (struct syntax_editor *se)
51 {
52   if ( TRUE == gtk_text_buffer_get_modified (se->buffer))
53     {
54       gint response;
55       GtkWidget *dialog =
56         gtk_message_dialog_new (GTK_WINDOW(se->window),
57                                 GTK_DIALOG_MODAL,
58                                 GTK_MESSAGE_QUESTION,
59                                 GTK_BUTTONS_NONE,
60                                 _("Save contents of syntax editor to %s?"),
61                                 se->name ? se->name : _("Untitled")
62                                 );
63
64       gtk_dialog_add_button  (GTK_DIALOG(dialog),
65                               GTK_STOCK_YES,
66                               GTK_RESPONSE_ACCEPT);
67       gtk_dialog_add_button  (GTK_DIALOG(dialog),
68                               GTK_STOCK_NO,
69                               GTK_RESPONSE_REJECT);
70       gtk_dialog_add_button  (GTK_DIALOG(dialog),
71                               GTK_STOCK_CANCEL,
72                               GTK_RESPONSE_CANCEL);
73
74
75       response = gtk_dialog_run (GTK_DIALOG(dialog));
76
77       gtk_widget_destroy (dialog);
78
79       if ( response == GTK_RESPONSE_ACCEPT )
80         {
81           GError *err = NULL;
82
83           if ( ! save_editor_to_file (se, se->name ? se->name : _("Untitled"),
84                                       &err) )
85             {
86               msg (ME, err->message);
87               g_error_free (err);
88             }
89         }
90
91       if ( response == GTK_RESPONSE_CANCEL )
92         return ;
93     }
94
95   gtk_widget_destroy (se->window);
96 }
97
98 /* Callback for the File->SaveAs menuitem */
99 static void
100 on_syntax_save_as   (GtkMenuItem     *menuitem,
101                   gpointer         user_data)
102 {
103   GtkFileFilter *filter;
104   gint response;
105   struct syntax_editor *se = user_data;
106
107   GtkWidget *dialog =
108     gtk_file_chooser_dialog_new (_("Save Syntax"),
109                                  GTK_WINDOW(se->window),
110                                  GTK_FILE_CHOOSER_ACTION_SAVE,
111                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
112                                  GTK_STOCK_SAVE,   GTK_RESPONSE_ACCEPT,
113                                  NULL);
114
115   filter = gtk_file_filter_new ();
116   gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
117   gtk_file_filter_add_pattern (filter, "*.sps");
118   gtk_file_filter_add_pattern (filter, "*.SPS");
119   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
120
121   filter = gtk_file_filter_new ();
122   gtk_file_filter_set_name (filter, _("All Files"));
123   gtk_file_filter_add_pattern (filter, "*");
124   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
125
126   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER(dialog),
127                                                   TRUE);
128   response = gtk_dialog_run (GTK_DIALOG (dialog));
129
130   if ( response == GTK_RESPONSE_ACCEPT )
131     {
132       GError *err = NULL;
133       char *filename =
134         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog) );
135
136       if ( save_editor_to_file (se, filename, &err) )
137         {
138           g_free (se->name);
139           se->name = g_strdup (filename);
140         }
141       else
142         {
143           msg ( ME, err->message );
144           g_error_free (err);
145         }
146
147       free (filename);
148     }
149
150   gtk_widget_destroy ( dialog );
151 }
152
153 /* Callback for the File->Save menuitem */
154 void
155 on_syntax_save   (GtkMenuItem     *menuitem,
156                   gpointer         user_data)
157 {
158   struct syntax_editor *se = user_data;
159
160   if ( se->name == NULL )
161     on_syntax_save_as (menuitem, user_data);
162   else
163     {
164       GError *err;
165       save_editor_to_file (se, se->name, &err);
166       msg (ME, err->message);
167       g_error_free (err);
168     }
169 }
170
171
172 /* Callback for the "delete" action (clicking the x on the top right
173    hand corner of the window) */
174 static gboolean
175 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
176 {
177   struct syntax_editor *se = user_data;
178   save_if_modified (se);
179   return TRUE;
180 }
181
182
183 /* Callback for the File->Quit menuitem */
184 static gboolean
185 on_quit (GtkMenuItem *menuitem, gpointer    user_data)
186 {
187   struct syntax_editor *se = user_data;
188   save_if_modified (se);
189   return FALSE;
190 }
191
192 void
193 new_syntax_window (GtkMenuItem     *menuitem,
194                    gpointer         user_data);
195
196
197
198 static void open_syntax_window (GtkMenuItem *menuitem,
199                                 gpointer user_data);
200
201
202 /* Create a new syntax editor with NAME.
203    If NAME is NULL, a name will be automatically assigned
204 */
205 static struct syntax_editor *
206 new_syntax_editor (const gchar *name)
207 {
208   GladeXML *new_xml ;
209   GtkWidget *text_view;
210   struct syntax_editor *se ;
211
212   new_xml = glade_xml_new  (xml->filename, "syntax_editor", NULL);
213
214   se = g_malloc (sizeof (*se));
215
216   se->window = get_widget_assert (new_xml, "syntax_editor");
217   text_view = get_widget_assert (new_xml, "syntax_text_view");
218   se->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(text_view));
219   if ( name )
220     se->name = g_strdup (name);
221   else
222     se->name = NULL;
223
224   g_signal_connect (get_widget_assert (new_xml,"file_new_syntax"),
225                     "activate",
226                     G_CALLBACK(new_syntax_window),
227                     se->window);
228
229   g_signal_connect (get_widget_assert (new_xml,"file_open_syntax"),
230                     "activate",
231                     G_CALLBACK(open_syntax_window),
232                     se->window);
233
234   g_signal_connect (get_widget_assert (new_xml,"file_quit"),
235                     "activate",
236                     G_CALLBACK(on_quit),
237                     se);
238
239   g_signal_connect (get_widget_assert (new_xml,"file_save"),
240                     "activate",
241                     G_CALLBACK(on_syntax_save),
242                     se);
243
244   g_signal_connect (get_widget_assert (new_xml,"file_save_as"),
245                     "activate",
246                     G_CALLBACK(on_syntax_save_as),
247                     se);
248
249   g_object_unref (new_xml);
250
251   g_signal_connect (se->window, "delete-event",
252                     G_CALLBACK(on_delete), se);
253
254   return se;
255 }
256
257 /* Callback for the File->New->Syntax menuitem */
258 void
259 new_syntax_window (GtkMenuItem     *menuitem,
260                    gpointer         user_data)
261 {
262   struct syntax_editor *se =   new_syntax_editor (NULL);
263   gtk_widget_show (se->window);
264 }
265
266
267 static void
268 set_window_title_from_filename (struct syntax_editor *se,
269                                 const gchar *filename)
270 {
271   gchar *title;
272   gchar *basename ;
273   g_free (se->name);
274   se->name = strdup (filename);
275   basename = g_path_get_basename (filename);
276   title =
277     g_strdup_printf (_("%s --- PSPP Syntax Editor"), basename);
278   g_free (basename);
279   gtk_window_set_title (GTK_WINDOW(se->window), title);
280   g_free (title);
281 }
282
283
284 /* Save BUFFER to the file called FILENAME.
285    If successful, clears the buffer's modified flag */
286 static gboolean
287 save_editor_to_file (struct syntax_editor *se,
288                      const gchar *filename,
289                      GError **err)
290 {
291   GtkTextBuffer *buffer = se->buffer;
292   gboolean result ;
293   GtkTextIter start, stop;
294   gchar *text;
295
296   gchar *glibfilename;
297   g_assert (filename);
298
299   glibfilename = g_filename_from_utf8 (filename, -1, 0, 0, err);
300
301   if ( ! glibfilename )
302     return FALSE;
303
304   gtk_text_buffer_get_iter_at_line (buffer, &start, 0);
305   gtk_text_buffer_get_iter_at_offset (buffer, &stop, -1);
306
307   text = gtk_text_buffer_get_text (buffer, &start, &stop, FALSE);
308
309   result =  g_file_set_contents (glibfilename, text, -1, err);
310
311   if ( result )
312     {
313       set_window_title_from_filename (se, filename);
314       gtk_text_buffer_set_modified (buffer, FALSE);
315     }
316
317   return result;
318 }
319
320
321 /* Loads the buffer from the file called FILENAME
322 */
323 static gboolean
324 load_editor_from_file (struct syntax_editor *se,
325                        const gchar *filename,
326                        GError **err)
327 {
328   GtkTextBuffer *buffer = se->buffer;
329   gchar *text;
330   GtkTextIter iter;
331
332   gchar *glibfilename = g_filename_from_utf8 (filename, -1, 0, 0, err);
333
334   if ( ! glibfilename )
335     return FALSE;
336
337   /* FIXME: What if it's a very big file ? */
338   if ( ! g_file_get_contents (glibfilename, &text, NULL, err) )
339     {
340       g_free (glibfilename);
341       return FALSE;
342     }
343   g_free (glibfilename);
344
345   gtk_text_buffer_get_iter_at_line (buffer, &iter, 0);
346
347   gtk_text_buffer_insert (buffer, &iter, text, -1);
348
349   set_window_title_from_filename (se, filename);
350   gtk_text_buffer_set_modified (buffer, FALSE);
351
352   return TRUE;
353 }
354
355
356 /* Callback for the File->Open->Syntax menuitem */
357 static void
358 open_syntax_window (GtkMenuItem *menuitem, gpointer parent)
359 {
360   GtkFileFilter *filter;
361   gint response;
362
363   GtkWidget *dialog =
364     gtk_file_chooser_dialog_new (_("Open Syntax"),
365                                  GTK_WINDOW(parent),
366                                  GTK_FILE_CHOOSER_ACTION_OPEN,
367                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
368                                  GTK_STOCK_OPEN,   GTK_RESPONSE_ACCEPT,
369                                  NULL);
370
371   filter = gtk_file_filter_new ();
372   gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
373   gtk_file_filter_add_pattern (filter, "*.sps");
374   gtk_file_filter_add_pattern (filter, "*.SPS");
375   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
376
377   filter = gtk_file_filter_new ();
378   gtk_file_filter_set_name (filter, _("All Files"));
379   gtk_file_filter_add_pattern (filter, "*");
380   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
381
382   response = gtk_dialog_run (GTK_DIALOG (dialog));
383
384   if (response == GTK_RESPONSE_ACCEPT)
385     {
386       const char *file_name = gtk_file_chooser_get_filename
387         (GTK_FILE_CHOOSER (dialog));
388
389       struct syntax_editor *se = new_syntax_editor (file_name);
390
391       load_editor_from_file (se, file_name, NULL);
392
393       gtk_widget_show (se->window);
394     }
395
396   gtk_widget_destroy (dialog);
397 }
398
399
400 #if 1
401 /* FIXME: get rid of these functions */
402 void
403 on_syntax4_activate   (GtkMenuItem     *menuitem,
404                        gpointer         user_data)
405 {
406   g_print ("%s\n", __FUNCTION__);
407 }
408
409
410
411 void
412 on_syntax2_activate   (GtkMenuItem     *menuitem,
413                        gpointer         user_data)
414 {
415   g_print ("%s\n", __FUNCTION__);
416 }
417
418 void
419 on_syntax1_activate   (GtkMenuItem     *menuitem,
420                        gpointer         user_data)
421 {
422   g_print ("%s\n", __FUNCTION__);
423   new_syntax_window (menuitem, user_data);
424 }
425 #endif
426