1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
2 /* IM-JA Japanese Input Method Module for GTK-2.0
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Authors: Botond Botyanszki <boti@rocketmail.com>
20  *
21  */
22 
23 #include <config.h>
24 
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27 #include <math.h>
28 #include <string.h>
29 
30 #include "im-ja.h"
31 #include "symbols.h"
32 #include "error.h"
33 #include "nls.h"
34 #include "common.h"
35 
convert_line(gunichar * result,gchar ** strg,gchar * line,gint length)36 static gint convert_line(gunichar *result, gchar **strg, gchar *line, gint length) {
37   /* unichar is not changed if the input is not a 4 byte unichar string*/
38   gint i;
39   gunichar unichar = 0;
40 
41   if (length < 2) return 0;
42 
43   if (line[0] == '$') {
44     *strg = g_new0(gchar, length - 1);
45     g_strlcpy(*strg, line + 1, length - 1);
46     return 1;
47   }
48   if (line[0] == '.' && line[1] == '.') return 2;
49   if (length < 5) return 0;
50   for (i = 0; i < 4; i++) {
51     gint val = g_ascii_xdigit_value(line[i]);
52     if (val == -1) return 0;
53     unichar += val << 4 * (3 - i);
54   }
55   *strg = g_new0(gchar, 5);
56   g_unichar_to_utf8(unichar, *strg);
57   *result = unichar;
58   return 1;
59 
60 }
61 
get_symbol_table_data()62 static GSList *get_symbol_table_data() {
63 
64   GIOChannel *symbol_table;
65   GError *error = NULL;
66   static GSList *symbols = NULL;
67 
68 	if (symbols != NULL) {
69 		IM_JA_DEBUG("returning symbols from memory\n");
70 		return symbols;
71 	}
72 
73   symbol_table = g_io_channel_new_file(IM_JA_DATADIR"/im-ja-symbols.txt", "r", &error);
74 
75   if (symbol_table != NULL) {
76     GIOStatus status;
77     gchar *line;
78     gsize length;
79     gsize newline_pos;
80     GSList *symbol_group = NULL;
81     gchar *utf8_strg;
82     gint conv_result = 0, last_result = 0;
83     gunichar unichar = 0, last_unichar, i;
84 
85     while ((status = g_io_channel_read_line(symbol_table, &line, &length,
86 																						&newline_pos, &error)) == G_IO_STATUS_NORMAL) {
87 
88       /* Skip comments and empty lines */
89       if ((line[0] == '#') || (line[0] == '\n')) continue;
90       else {
91 				if ((line[0] == '%') || (line[0] == ' ')) { /* process symbol group */
92 					gchar *group_name;
93 					symbol_group = NULL;
94 					group_name = g_new0(gchar, length);
95 					g_strlcpy(group_name, line + 2, length - 2);
96 					symbol_group = g_slist_append(symbol_group, group_name);
97 					symbols = g_slist_append(symbols, symbol_group);
98 					last_result = 0;
99 				}
100 				else { /* process group entries */
101 					last_result = conv_result;
102 					last_unichar = unichar;
103 					conv_result = convert_line(&unichar, &utf8_strg, line, length);
104 					if (conv_result == 1) {
105 						if (last_result == 2) { /* We need to generate a series of entries (2 == Range) */
106 							for (i = last_unichar + 1; i <= unichar; i++) {
107 								utf8_strg = g_new0(gchar, 5);
108 								g_unichar_to_utf8(i, utf8_strg);
109 								symbol_group = g_slist_append(symbol_group, utf8_strg);
110 							}
111 						}
112 						else { /* Add only one entry */
113 							symbol_group = g_slist_append(symbol_group, utf8_strg);
114 						}
115 					}
116 				}
117       }
118       g_free(line);
119     }
120     g_io_channel_shutdown(symbol_table, FALSE, &error);
121   }
122 
123   return symbols;
124 }
125 
key_press_cb(GtkWidget * window,GdkEventKey * event,gpointer data)126 static gboolean key_press_cb(GtkWidget *window, GdkEventKey *event, gpointer data) {
127 	if (event->keyval == GDK_Escape) {
128 		gtk_widget_destroy(window);
129 		return TRUE;
130 	}
131 	return FALSE;
132 }
133 
symbol_pressed_cb(GtkWidget * button,IMJAContext * cn)134 static void symbol_pressed_cb(GtkWidget *button, IMJAContext *cn) {
135 	GtkWidget *window;
136 	gchar *symbol;
137 
138 	window = g_object_get_data(G_OBJECT(button), "im-ja-symbol-window");
139 	symbol = g_object_get_data(G_OBJECT(button), "im-ja-utf8-symbol");
140 	gtk_widget_destroy(window);
141 
142 	/* symbol = gtk_button_get_label(GTK_BUTTON(button)); */
143 	im_ja_input_utf8(cn, symbol);
144 }
145 
146 /* This makes the secondary table with the symbols */
show_symbols(GtkWidget * button,IMJAContext * cn)147 static void show_symbols(GtkWidget *button, IMJAContext *cn) {
148 	GSList *symbols_ptr;
149 	GSList *symbols;
150   gint rows = 0;
151   gint cols = 0;
152   gint col, row;
153   gint total = 0;
154 	gint cnt = 0;
155 	gdouble root;
156   GtkWidget *window;
157   GtkWidget *grp_window;
158   GtkWidget *symbol_table;
159 
160 	symbols = symbols_ptr = g_object_get_data(G_OBJECT(button), "im-ja-symbols");
161 	grp_window = g_object_get_data(G_OBJECT(button), "im-ja-symbol-grp-window");
162 	gtk_widget_destroy(grp_window);
163 
164 
165   /* count the elements in the table */
166   while (symbols_ptr != NULL) {
167     total++;
168     symbols_ptr = g_slist_next(symbols_ptr);
169   }
170 	total--; /* The group name doesn't count; */
171 
172   /* Calculate table size; */
173   root = sqrt((double) total);
174   rows = cols = (gint) root;
175 	if (((gdouble) rows) < root) {
176     rows++;
177     if (rows * cols < total) cols++;
178   }
179   IM_JA_DEBUG("Total: %d, Rows: %d, cols: %d\n", total, rows, cols);
180 
181   /* Create the table */
182   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
183   gtk_window_set_title(GTK_WINDOW(window), _("Symbols"));
184 	gtk_window_set_modal(GTK_WINDOW(window), TRUE);
185 
186 	/* FIXME */
187 #ifdef IMJA_TARGET_GTK
188   if (GTK_IS_WINDOW(cn->toplevel_gtk)) {
189 		gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(cn->toplevel_gtk));
190 	}
191 #endif
192 	g_signal_connect(GTK_OBJECT(window), "key_press_event", G_CALLBACK(key_press_cb), NULL);
193 
194   symbol_table = gtk_table_new(rows, cols, TRUE);
195   gtk_container_add(GTK_CONTAINER(window), symbol_table);
196 
197 	symbols_ptr = symbols;
198 	symbols_ptr = g_slist_next(symbols_ptr); /* skip the group name */
199 
200 	col = row = 0;
201 	while (symbols_ptr != NULL) {
202 		while (col < cols) {
203 			if (symbols_ptr->data != NULL) {
204 				GtkWidget *tmpwidget = gtk_button_new_with_label(symbols_ptr->data);
205 				g_object_set_data(G_OBJECT(tmpwidget), "im-ja-symbol-window", (gpointer) window);
206 				g_object_set_data(G_OBJECT(tmpwidget), "im-ja-utf8-symbol", symbols_ptr->data);
207 				g_signal_connect(G_OBJECT(tmpwidget), "clicked", G_CALLBACK(symbol_pressed_cb), cn);
208 
209 				gtk_table_attach(GTK_TABLE(symbol_table), tmpwidget, col, col + 1, row, row + 1,
210 												 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
211 												 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
212 
213 				symbols_ptr = g_slist_next(symbols_ptr);
214 				cnt++;
215 				col++;
216 				if (symbols_ptr == NULL) break;
217 			}
218 		}
219 		col = 0;
220 		row++;
221 	}
222 
223   gtk_widget_show_all(window);
224 
225 }
226 
227 /* This creates the main table with the symbol groups */
im_ja_symbol_table_show(IMJAContext * cn)228 void im_ja_symbol_table_show(IMJAContext *cn) {
229   GSList *symbols_ptr = NULL;
230   GSList *symbols = NULL;
231   GSList *symbol_group_ptr = NULL;
232   gint rows = 0;
233   gint cols = 0;
234   gint col, row;
235   gint total = 0;
236 	gint cnt = 0;
237   GtkWidget *window;
238   GtkWidget *symbol_grp_table;
239 
240   IM_JA_DEBUG("im_ja_symbol_table_show()\n");
241 
242   symbols = symbols_ptr = get_symbol_table_data();
243 
244   /* count the elements in the table */
245   while (symbols_ptr != NULL) {
246     total++;
247     symbols_ptr = g_slist_next(symbols_ptr);
248   }
249   /* Calculate table size; */
250 	/*
251 	//	if (total > 4) cols = 3;
252 	//	else
253 	*/
254 	cols = 2;
255 	rows = total / cols;
256 
257   /* Create the table */
258   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
259   gtk_window_set_title(GTK_WINDOW(window), _("Symbol groups"));
260   gtk_window_set_modal(GTK_WINDOW(window), TRUE);
261 
262 	/* FIXME */
263 #ifdef IMJA_TARGET_GTK
264   if (GTK_IS_WINDOW(cn->toplevel_gtk)) {
265 		gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(cn->toplevel_gtk));
266 	}
267 #endif
268 
269 	g_signal_connect(GTK_OBJECT(window), "key_press_event", G_CALLBACK(key_press_cb), NULL);
270 
271   symbol_grp_table = gtk_table_new(rows, cols, TRUE);
272   gtk_container_add(GTK_CONTAINER(window), symbol_grp_table);
273 
274   symbols_ptr = symbols;
275 	col = row = 0;
276 	while (symbols_ptr != NULL) {
277 		while (col < cols) {
278 			symbol_group_ptr = symbols_ptr->data;
279 			if (symbol_group_ptr != NULL) {
280 				GtkWidget *tmpwidget = gtk_button_new_with_label(symbol_group_ptr->data);
281 				g_object_set_data(G_OBJECT(tmpwidget), "im-ja-symbols", (gpointer) symbol_group_ptr);
282 				g_object_set_data(G_OBJECT(tmpwidget), "im-ja-symbol-grp-window", (gpointer) window);
283 				g_signal_connect(G_OBJECT(tmpwidget), "clicked", G_CALLBACK(show_symbols), cn);
284 
285 				gtk_table_attach(GTK_TABLE(symbol_grp_table), tmpwidget, col, col + 1, row, row + 1,
286 												 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
287 												 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
288 				symbols_ptr = g_slist_next(symbols_ptr);
289 				cnt++;
290 				col++;
291 				if (symbols_ptr == NULL) break;
292 			}
293 		}
294 		col = 0;
295 		row++;
296 	}
297 
298   gtk_widget_show_all(window);
299 
300 }
301 
translate_unicode_entry_cb(GtkWidget * entry,IMJAContext * cn)302 static void translate_unicode_entry_cb(GtkWidget *entry, IMJAContext *cn) {
303 	gchar *code_strg, *utf8_strg;
304 	gint length;
305 	gunichar unichar;
306 	GtkWidget *window;
307 	gboolean input_ok = TRUE;
308 	gint i;
309 
310 	code_strg = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
311 	length = strlen(code_strg);
312 
313 	window = g_object_get_data(G_OBJECT(entry), "im-ja-unicode-entry-window");
314 	gtk_widget_destroy(window);
315 
316 	if (length == 0) return;
317 
318   if (length != 4) input_ok = FALSE;
319 	else {
320 		unichar = 0;
321 		for (i = 0; i < 4; i++) {
322 			gint val = g_ascii_xdigit_value(code_strg[i]);
323 			if (val == -1) {
324 				input_ok = FALSE;
325 				break;
326 			}
327 			unichar += val << 4 * (3 - i);
328 		}
329 	}
330 
331 	if (input_ok == TRUE) {
332 		if (g_unichar_validate(unichar) == FALSE) {
333 			im_ja_print_error(_("Invalid unicode character: %s"), code_strg);
334 		}
335 		else {
336 			utf8_strg = g_new0(gchar, 5);
337 			g_unichar_to_utf8(unichar, utf8_strg);
338 			im_ja_input_utf8(cn, utf8_strg);
339 		}
340 	}
341 	else {
342 		im_ja_print_error(_("Invalid 4 byte HEX input: %s"), code_strg);
343 	}
344 	g_free(code_strg);
345 }
346 
translate_jiscode_entry_cb(GtkWidget * entry,IMJAContext * cn)347 static void translate_jiscode_entry_cb(GtkWidget *entry, IMJAContext *cn) {
348 	gchar *code_strg, *utf8_strg, *euc_str;
349 	gint length;
350 	GtkWidget *window;
351 	gboolean input_ok = TRUE;
352 	gint i;
353 	gint val = 0;
354 	wchar src_str[2];
355 	int chr = 0;
356 
357 	code_strg = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
358 	length = strlen(code_strg);
359 
360 	window = g_object_get_data(G_OBJECT(entry), "im-ja-jiscode-entry-window");
361 	gtk_widget_destroy(window);
362 
363 
364 	if (length == 0) return;
365 
366   if (length != 4) input_ok = FALSE;
367 	else {
368 		val = 0;
369 		chr = 0;
370 		for (i = 0; i < 4; i++) {
371 			gint val = g_ascii_xdigit_value(code_strg[i]);
372 			if (val == -1) {
373 				input_ok = FALSE;
374 				break;
375 			}
376 			chr = (chr << 4) + val;
377 		}
378 	}
379 	if (chr != -1) input_ok = TRUE;
380 
381 	src_str[0] = chr | 0x8080;
382 	src_str[1] = 0;
383 
384 	euc_str = wc2euc(src_str, strlen((gchar*)src_str));
385 	utf8_strg = euc2utf8(euc_str);
386 	g_free(euc_str);
387 
388 	if (input_ok == TRUE) {
389 		const gchar *end;
390 		if (g_utf8_validate(utf8_strg, -1, &end) == FALSE) {
391 			im_ja_print_error(_("Invalid unicode character: %s"), code_strg);
392 		}
393 		else {
394 			im_ja_input_utf8(cn, utf8_strg);
395 		}
396 	}
397 	else {
398 		im_ja_print_error(_("Invalid 4 byte HEX input: %s"), code_strg);
399 	}
400 	g_free(code_strg);
401 }
402 
im_ja_unicode_entry_show(IMJAContext * cn)403 void im_ja_unicode_entry_show(IMJAContext *cn) {
404   GtkWidget *window;
405 	GtkWidget *hbox;
406 	GtkWidget *label;
407 	GtkWidget *entry;
408 
409   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
410   gtk_window_set_title(GTK_WINDOW(window), _("Unicode entry"));
411   gtk_window_set_modal(GTK_WINDOW(window), TRUE);
412 
413 	/* FIXME */
414 #ifdef IMJA_TARGET_GTK
415   if (GTK_IS_WINDOW(cn->toplevel_gtk)) {
416 		gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(cn->toplevel_gtk));
417 	}
418 #endif
419 	g_signal_connect(GTK_OBJECT(window), "key_press_event", G_CALLBACK(key_press_cb), NULL);
420 
421 	hbox = gtk_vbox_new(FALSE, 5);
422 	gtk_container_add(GTK_CONTAINER(window), hbox);
423 
424 	label = gtk_label_new(_("4 Byte HEX UniCode:"));
425 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
426 
427 	entry = gtk_entry_new();
428 	gtk_entry_set_max_length(GTK_ENTRY(entry), 4);
429 	gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
430 	g_object_set_data(G_OBJECT(entry), "im-ja-unicode-entry-window", (gpointer) window);
431 	g_signal_connect(GTK_OBJECT(entry), "activate", G_CALLBACK(translate_unicode_entry_cb), cn);
432 
433 	gtk_widget_show_all(window);
434 
435 }
436 
im_ja_jiscode_entry_show(IMJAContext * cn)437 void im_ja_jiscode_entry_show(IMJAContext *cn) {
438   GtkWidget *window;
439 	GtkWidget *hbox;
440 	GtkWidget *label;
441 	GtkWidget *entry;
442 
443   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
444   gtk_window_set_title(GTK_WINDOW(window), _("JIS Code entry"));
445   gtk_window_set_modal(GTK_WINDOW(window), TRUE);
446 
447 	/* FIXME */
448 #ifdef IMJA_TARGET_GTK
449   if (GTK_IS_WINDOW(cn->toplevel_gtk)) {
450 		gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(cn->toplevel_gtk));
451 	}
452 #endif
453 	g_signal_connect(GTK_OBJECT(window), "key_press_event", G_CALLBACK(key_press_cb), NULL);
454 
455 	hbox = gtk_vbox_new(FALSE, 5);
456 	gtk_container_add(GTK_CONTAINER(window), hbox);
457 
458 	label = gtk_label_new(_("4 Byte JIS Code:"));
459 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
460 
461 	entry = gtk_entry_new();
462 	gtk_entry_set_max_length(GTK_ENTRY(entry), 4);
463 	gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
464 	g_object_set_data(G_OBJECT(entry), "im-ja-jiscode-entry-window", (gpointer) window);
465 	g_signal_connect(GTK_OBJECT(entry), "activate", G_CALLBACK(translate_jiscode_entry_cb), cn);
466 
467 	gtk_widget_show_all(window);
468 
469 }
470