9f75d516f49f04cc64e233b1d7aa5a6029765d6e
[slovak-l10n] / ukeyboard / ukbdcreator / ukbdcreator.c
1 /*
2  *  Copyright (c) 2008 Jiri Benc <jbenc@upir.cz>
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 version 2 as
6  *  published by the Free Software Foundation.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17
18 #include <string.h>
19 #include <glib.h>
20 #include <gtk/gtk.h>
21 #include <hildon/hildon.h>
22 #include <hildon/hildon-file-chooser-dialog.h>
23 #include <libosso.h>
24 #include <libgnomevfs/gnome-vfs.h>
25 #include <gconf/gconf.h>
26 #include <gconf/gconf-client.h>
27 #include "version.h"
28 #include "ukbdcreator.h"
29
30 static HildonWindow *window_main;
31 static GtkClipboard *clipboard;
32 static GtkTextView *view;
33 static GtkTextBuffer *buffer;
34 static gchar *filename = NULL;
35 static gboolean is_fullscreen = FALSE;
36 static gboolean is_modified = FALSE;
37
38 static int last_error_line = 0;
39 static gchar *last_error_msg = NULL;
40
41 static GConfClient *conf;
42
43
44 static void toggle_fullscreen(void)
45 {
46         if (is_fullscreen)
47                 gtk_window_unfullscreen(GTK_WINDOW(window_main));
48         else
49                 gtk_window_fullscreen(GTK_WINDOW(window_main));
50         is_fullscreen = !is_fullscreen;
51 }
52
53 static void set_modified(void)
54 {
55         is_modified = TRUE;
56 }
57
58 static void set_filename(gchar *fname)
59 {
60         if (filename)
61                 g_free(filename);
62         filename = fname;
63 }
64
65 void disp_error(gchar *msg)
66 {
67         hildon_banner_show_information(GTK_WIDGET(window_main), GTK_STOCK_DIALOG_ERROR, msg);
68 }
69
70 void disp_info(gchar *msg)
71 {
72         hildon_banner_show_information(GTK_WIDGET(window_main), GTK_STOCK_DIALOG_INFO, msg);
73 }
74
75 static void __disp_compile_error(void)
76 {
77         GtkTextIter iter;
78
79         if (!last_error_msg)
80                 return;
81         if (last_error_line > 0) {
82                 gtk_text_buffer_get_iter_at_line(buffer, &iter, last_error_line - 1);
83                 gtk_text_buffer_place_cursor(buffer, &iter);
84                 gtk_text_view_scroll_mark_onscreen(view, gtk_text_buffer_get_mark(buffer, "insert"));
85         }
86         hildon_banner_show_information(GTK_WIDGET(window_main), GTK_STOCK_DIALOG_ERROR, last_error_msg);
87 }
88
89 void disp_compile_error(int line, gchar *msg)
90 {
91         g_free(last_error_msg);
92         last_error_msg = g_strdup(msg);
93         last_error_line = line;
94         __disp_compile_error();
95 }
96
97 static gboolean read_file(gchar *fname)
98 {
99         GnomeVFSFileInfo finfo;
100         GnomeVFSHandle *handle = NULL;
101         GnomeVFSFileSize bytes;
102         gchar *buf;
103
104         if (gnome_vfs_get_file_info(fname, &finfo, GNOME_VFS_FILE_INFO_DEFAULT) != GNOME_VFS_OK ||
105                         gnome_vfs_open(&handle, fname, GNOME_VFS_OPEN_READ) != GNOME_VFS_OK) {
106                 disp_error("Error opening file");
107                 return FALSE;
108         }
109         buf = g_malloc0(finfo.size + 1);
110         if (!buf) {
111                 gnome_vfs_close(handle);
112                 disp_error("Not enough memory");
113                 return FALSE;
114         }
115         if (gnome_vfs_read(handle, buf, finfo.size, &bytes) != GNOME_VFS_OK || bytes != finfo.size) {
116                 gnome_vfs_close(handle);
117                 g_free(buf);
118                 disp_error("Error reading file");
119                 return FALSE;
120         }
121         gnome_vfs_close(handle);
122
123         gtk_text_buffer_set_text(buffer, buf, -1);
124         g_free(buf);
125         return TRUE;
126 }
127
128 static gchar *get_buffer(void)
129 {
130         GtkTextIter start, end;
131
132         gtk_text_buffer_get_bounds(buffer, &start, &end);
133         return gtk_text_buffer_get_slice(buffer, &start, &end, TRUE);
134 }
135
136 static gboolean write_file(gchar *fname)
137 {
138         GnomeVFSHandle *handle = NULL;
139         GnomeVFSFileSize bytes;
140         gchar *buf;
141         size_t size;
142
143         if (gnome_vfs_create(&handle, fname, GNOME_VFS_OPEN_WRITE, FALSE, 0644) != GNOME_VFS_OK) {
144                 disp_error("Error creating file");
145                 return FALSE;
146         }
147         buf = get_buffer();
148         size = strlen(buf);
149         if (gnome_vfs_write(handle, buf, size, &bytes) != GNOME_VFS_OK || bytes != size) {
150                 gnome_vfs_close(handle);
151                 g_free(buf);
152                 disp_error("Error writing file");
153                 return FALSE;
154         }
155         gnome_vfs_close(handle);
156         g_free(buf);
157         disp_info("Saved");
158         return TRUE;
159 }
160
161 static gchar *file_chooser(gboolean open)
162 {
163         GtkWidget *chooser;
164         GtkFileFilter *filter;
165         gchar *result = NULL;
166
167         chooser = hildon_file_chooser_dialog_new(GTK_WINDOW(window_main),
168                 open ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE);
169         filter = gtk_file_filter_new();
170         gtk_file_filter_add_pattern(filter, "*.def");
171         gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(chooser), filter);
172         gtk_widget_show_all(chooser);
173         if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK)
174                 result = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
175         gtk_widget_destroy(chooser);
176         if (!open && result && !g_str_has_suffix(result, ".def")) {
177                 gchar *tmp = result;
178
179                 result = g_strconcat(result, ".def", NULL);
180                 g_free(tmp);
181         }
182         return result;
183 }
184
185 static void file_save_as(void)
186 {
187         gchar *fname;
188
189         fname = file_chooser(FALSE);
190         if (fname) {
191                 if (write_file(fname)) {
192                         set_filename(fname);
193                         is_modified = FALSE;
194                 } else
195                         g_free(fname);
196         }
197 }
198
199 static void file_save(void)
200 {
201         if (!filename) {
202                 file_save_as();
203                 return;
204         }
205         if (write_file(filename))
206                 is_modified = FALSE;
207 }
208
209 static gboolean file_ask_save(void)
210 {
211         GtkWidget *note;
212         gint res;
213
214         if (!is_modified)
215                 return TRUE;
216         note = hildon_note_new_confirmation_add_buttons(GTK_WINDOW(window_main),
217                 "Save the file before closing?", "Yes", 1, "No", 2, "Cancel", 0, NULL);
218         res = gtk_dialog_run(GTK_DIALOG(note));
219         gtk_widget_destroy(note);
220         if (res == 1) {
221                 file_save_as();
222                 return !is_modified;
223         }
224         if (res == 2)
225                 return TRUE;
226         return FALSE;
227 }
228
229 static void file_open(void)
230 {
231         gchar *fname;
232
233         if (!file_ask_save())
234                 return;
235         fname = file_chooser(TRUE);
236         if (fname) {
237                 if (read_file(fname)) {
238                         set_filename(fname);
239                         is_modified = FALSE;
240                         g_free(last_error_msg);
241                         last_error_msg = NULL;
242                 } else
243                         g_free(fname);
244         }
245 }
246
247 static void file_new(void)
248 {
249         if (!file_ask_save())
250                 return;
251         gtk_text_buffer_set_text(buffer, "", -1);
252         set_filename(NULL);
253         is_modified = FALSE;
254         g_free(last_error_msg);
255         last_error_msg = NULL;
256 }
257
258 static gboolean file_quit(void)
259 {
260         if (!file_ask_save())
261                 return TRUE;
262         restore_layout(conf, FALSE);
263         gtk_main_quit();
264         return FALSE;
265 }
266
267 static void edit_cut(void)
268 {
269         gtk_text_buffer_cut_clipboard(buffer, clipboard, TRUE);
270 }
271
272 static void edit_copy(void)
273 {
274         gtk_text_buffer_copy_clipboard(buffer, clipboard);
275 }
276
277 static void edit_paste(void)
278 {
279         gtk_text_buffer_paste_clipboard(buffer, clipboard, NULL, TRUE);
280 }
281
282 static void run_about(void)
283 {
284         gtk_show_about_dialog(GTK_WINDOW(window_main),
285                 "version", UKBD_VERSION,
286                 "comments", "Licensed under GPLv2. Please send bug reports and feature requests to jbenc@upir.cz.",
287                 "copyright", "(c) 2008 Jiri Benc",
288                 "website", "http://upir.cz/maemo/keyboards/");
289 }
290
291 static void compile_and_test(void)
292 {
293         gchar *buf, *fname, *lang;
294         gboolean res;
295
296         buf = get_buffer();
297         res = compile_layout(buf, &fname, &lang);
298         g_free(buf);
299         if (res) {
300                 test_layout(conf, fname, lang);
301                 g_free(fname);
302                 g_free(lang);
303         }
304 }
305
306 static void untest(void)
307 {
308         restore_layout(conf, TRUE);
309 }
310
311 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event)
312 {
313         (void)widget;
314         switch (event->keyval) {
315         case GDK_F6:
316                 toggle_fullscreen();
317                 return TRUE;
318         }
319         return FALSE;
320 }
321
322 static GtkWidget *main_layout(void)
323 {
324         GtkWidget *scroll;
325
326         view = GTK_TEXT_VIEW(gtk_text_view_new());
327         gtk_text_view_set_editable(view, TRUE);
328         gtk_text_view_set_left_margin(view, 10);
329         gtk_text_view_set_right_margin(view, 10);
330
331         scroll = gtk_scrolled_window_new(NULL, NULL);
332         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
333         gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
334
335         buffer = gtk_text_view_get_buffer(view);
336         g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(set_modified), NULL);
337         g_signal_connect(G_OBJECT(buffer), "modified-changed", G_CALLBACK(set_modified), NULL);
338
339         return scroll;
340 }
341
342 static GtkMenu *main_menu(void)
343 {
344         GtkMenuShell *menu, *submenu;
345         GtkWidget *item;
346
347         menu = GTK_MENU_SHELL(gtk_menu_new());
348
349         submenu = GTK_MENU_SHELL(gtk_menu_new());
350         item = gtk_menu_item_new_with_label("File");
351         gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), GTK_WIDGET(submenu));
352         gtk_menu_shell_append(menu, item);
353
354         item = gtk_menu_item_new_with_label("New");
355         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(file_new), NULL);
356         gtk_menu_shell_append(submenu, item);
357         item = gtk_menu_item_new_with_label("Open...");
358         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(file_open), NULL);
359         gtk_menu_shell_append(submenu, item);
360         item = gtk_menu_item_new_with_label("Save");
361         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(file_save), NULL);
362         gtk_menu_shell_append(submenu, item);
363         item = gtk_menu_item_new_with_label("Save as...");
364         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(file_save_as), NULL);
365         gtk_menu_shell_append(submenu, item);
366
367         submenu = GTK_MENU_SHELL(gtk_menu_new());
368         item = gtk_menu_item_new_with_label("Edit");
369         gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), GTK_WIDGET(submenu));
370         gtk_menu_shell_append(menu, item);
371
372         item = gtk_menu_item_new_with_label("Cut");
373         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(edit_cut), NULL);
374         gtk_menu_shell_append(submenu, item);
375         item = gtk_menu_item_new_with_label("Copy");
376         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(edit_copy), NULL);
377         gtk_menu_shell_append(submenu, item);
378         item = gtk_menu_item_new_with_label("Paste");
379         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(edit_paste), NULL);
380         gtk_menu_shell_append(submenu, item);
381
382         gtk_menu_shell_append(menu, gtk_separator_menu_item_new());
383         item = gtk_menu_item_new_with_label("Test layout");
384         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(compile_and_test), NULL);
385         gtk_menu_shell_append(menu, item);
386         item = gtk_menu_item_new_with_label("Restore original layout");
387         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(untest), NULL);
388         gtk_menu_shell_append(menu, item);
389         item = gtk_menu_item_new_with_label("Show last error");
390         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(__disp_compile_error), NULL);
391         gtk_menu_shell_append(menu, item);
392
393         gtk_menu_shell_append(menu, gtk_separator_menu_item_new());
394         item = gtk_menu_item_new_with_label("Fullscreen");
395         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(toggle_fullscreen), NULL);
396         gtk_menu_shell_append(menu, item);
397         item = gtk_menu_item_new_with_label("About");
398         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(run_about), NULL);
399         gtk_menu_shell_append(menu, item);
400         item = gtk_menu_item_new_with_label("Exit");
401         g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(file_quit), NULL);
402         gtk_menu_shell_append(menu, item);
403
404         return GTK_MENU(menu);
405 }
406
407 static GtkToolbar *main_toolbar(void)
408 {
409         GtkToolbar *bar;
410         GtkToolItem *item;
411
412         bar = GTK_TOOLBAR(gtk_toolbar_new());
413         gtk_toolbar_set_orientation(bar, GTK_ORIENTATION_HORIZONTAL);
414         gtk_toolbar_set_style(bar, GTK_TOOLBAR_BOTH_HORIZ);
415
416         item = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
417         g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(file_open), NULL);
418         gtk_toolbar_insert(bar, item, -1);
419         item = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
420         g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(file_save), NULL);
421         gtk_toolbar_insert(bar, item, -1);
422         gtk_toolbar_insert(bar, gtk_separator_tool_item_new(), -1);
423         item = gtk_tool_button_new_from_stock(GTK_STOCK_CUT);
424         g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(edit_cut), NULL);
425         gtk_toolbar_insert(bar, item, -1);
426         item = gtk_tool_button_new_from_stock(GTK_STOCK_COPY);
427         g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(edit_copy), NULL);
428         gtk_toolbar_insert(bar, item, -1);
429         item = gtk_tool_button_new_from_stock(GTK_STOCK_PASTE);
430         g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(edit_paste), NULL);
431         gtk_toolbar_insert(bar, item, -1);
432         gtk_toolbar_insert(bar, gtk_separator_tool_item_new(), -1);
433         item = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
434         g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(compile_and_test), NULL);
435         gtk_toolbar_insert(bar, item, -1);
436         item = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
437         g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(untest), NULL);
438         gtk_toolbar_insert(bar, item, -1);
439
440         return bar;
441 }
442
443 int main(int argc, char **argv)
444 {
445         HildonProgram *program;
446
447         gtk_init(&argc, &argv);
448         program = hildon_program_get_instance();
449         g_set_prgname("ukbdcreator");
450         g_set_application_name("Ukeyboard Creator");
451         osso_initialize("cz.upir.ukbdcreator", UKBD_VERSION, TRUE, NULL);
452         gnome_vfs_init();
453         conf = gconf_client_get_default();
454         gconf_client_add_dir(conf, "/apps/osso/inputmethod/hildon-im-languages",
455                 GCONF_CLIENT_PRELOAD_NONE, NULL);
456
457         window_main = HILDON_WINDOW(hildon_window_new());
458         hildon_program_add_window(program, window_main);
459         clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
460         gtk_clipboard_set_can_store(clipboard, NULL, 0);
461
462         gtk_container_add(GTK_CONTAINER(window_main), main_layout());
463         hildon_window_set_menu(window_main, main_menu());
464         hildon_window_add_toolbar(window_main, main_toolbar());
465
466         g_signal_connect(G_OBJECT(window_main), "key_press_event", G_CALLBACK(key_pressed), NULL);
467         g_signal_connect(G_OBJECT(window_main), "delete_event", G_CALLBACK(file_quit), NULL);
468
469         gtk_widget_show_all(GTK_WIDGET(window_main));
470         gtk_main();
471         return 0;
472 }