1 #include "gcin.h"
2 #include "pho.h"
3 #include "config.h"
4 #if GCIN_i18n_message
5 #include <libintl.h>
6 #endif
7 #include "lang.h"
8 #include "tsin.h"
9 #include "gtab.h"
10
11 extern char *current_tsin_fname;
12 typedef unsigned int u_int32_t;
13
14 void init_TableDir();
15 void init_gtab(int inmdno);
16 gboolean init_tsin_table_fname(INMD *p, char *fname);
17 void load_tsin_db0(char *infname, gboolean is_gtab_i);
18
19 INMD *pinmd;
20 char gtab_tsin_fname[256];
21 char is_gtab;
22
23 char *phokey2pinyin(phokey_t k);
24 gboolean b_pinyin;
25 GtkWidget *hbox_buttons;
26 char current_str[MAX_PHRASE_LEN*CH_SZ+1];
27 extern gboolean is_chs;
28
29 GtkWidget *mainwin;
30 GtkTextBuffer *buffer;
31
32 static char **phrase;
33 static int phraseN=0;
34
35
cp_ph_key(void * in,int idx,void * dest)36 void cp_ph_key(void *in, int idx, void *dest)
37 {
38 if (tsin_hand.ph_key_sz==2) {
39 phokey_t *pharr = (phokey_t *)in;
40 in = &pharr[idx];
41 } else
42 if (tsin_hand.ph_key_sz==4) {
43 u_int32_t *pharr4 = (u_int32_t *)in;
44 in = &pharr4[idx];
45 } else {
46 u_int64_t *pharr8 = (u_int64_t *)in;
47 in = &pharr8[idx];
48 }
49
50 memcpy(dest, in, tsin_hand.ph_key_sz);
51 }
52
get_ph_key_ptr(void * in,int idx)53 void *get_ph_key_ptr(void *in, int idx)
54 {
55 if (tsin_hand.ph_key_sz==2) {
56 phokey_t *pharr = (phokey_t *)in;
57 return &pharr[idx];
58 } else
59 if (tsin_hand.ph_key_sz==4) {
60 u_int32_t *pharr4 = (u_int32_t *)in;
61 return &pharr4[idx];
62 } else {
63 u_int64_t *pharr8 = (u_int64_t *)in;
64 return &pharr8[idx];
65 }
66 }
67
lookup_gtab_key(char * ch,void * out)68 int lookup_gtab_key(char *ch, void *out)
69 {
70 int outN=0;
71 INMD *tinmd = &inmd[default_input_method];
72
73 int i;
74 for(i=0; i < tinmd->DefChars; i++) {
75 char *chi = (char *)tblch2(tinmd, i);
76
77 if (!(chi[0] & 0x80))
78 continue;
79 if (!utf8_eq(chi, ch))
80 continue;
81
82 u_int64_t key = CONVT2(tinmd, i);
83 if (tsin_hand.ph_key_sz==4) {
84 u_int32_t key32 = (u_int32_t)key;
85 memcpy(get_ph_key_ptr(out, outN), &key32, tsin_hand.ph_key_sz);
86 } else
87 memcpy(get_ph_key_ptr(out, outN), &key, tsin_hand.ph_key_sz);
88 outN++;
89 }
90
91 return outN;
92 }
93
94
qcmp_str(const void * aa,const void * bb)95 static int qcmp_str(const void *aa, const void *bb)
96 {
97 char *a = * (char **)aa, *b = * (char **)bb;
98
99 return strcmp(a,b);
100 }
101
102 extern FILE *fph;
103
load_ts_phrase()104 void load_ts_phrase()
105 {
106 FILE *fp = tsin_hand.fph;
107
108 int i;
109 for(i=0; i < phraseN; i++)
110 free(phrase[i]);
111 free(phrase); phrase = NULL;
112 phraseN = 0;
113
114 dbg("fname %s\n", tsin_hand.tsin_fname);
115
116 int ofs = is_gtab ? sizeof(TSIN_GTAB_HEAD):0;
117 fseek(fp, ofs, SEEK_SET);
118
119 while (!feof(fp)) {
120 u_int64_t phbuf[MAX_PHRASE_LEN];
121 char chbuf[MAX_PHRASE_LEN * CH_SZ + 1];
122 u_char clen;
123 usecount_t usecount;
124
125 clen = 0;
126
127 int rn;
128 rn = fread(&clen,1,1,fp);
129
130 if (clen > MAX_PHRASE_LEN)
131 p_err("bad tsin db clen %d > MAX_PHRASE_LEN %d\n", clen, MAX_PHRASE_LEN);
132
133 rn = fread(&usecount,sizeof(usecount_t), 1, fp);
134 rn = fread(phbuf, tsin_hand.ph_key_sz, clen, fp);
135 int tlen = 0;
136
137 for(i=0; i < clen; i++) {
138 int n = fread(&chbuf[tlen], 1, 1, fp);
139 if (n<=0)
140 goto stop;
141 int len=utf8_sz(&chbuf[tlen]);
142 rn = fread(&chbuf[tlen+1], 1, len-1, fp);
143 tlen+=len;
144 }
145
146 if (clen < 2)
147 continue;
148
149 chbuf[tlen]=0;
150 phrase = trealloc(phrase, char *, phraseN+1);
151
152 phrase[phraseN++] = strdup(chbuf);
153 }
154
155
156 stop:
157
158 // fclose(fp);
159
160 qsort(phrase, phraseN, sizeof(char *), qcmp_str);
161
162 dbg("phraseN: %d\n", phraseN);
163 }
164
pharse_search(char * s)165 gboolean pharse_search(char *s)
166 {
167 return bsearch(&s, phrase, phraseN, sizeof(char *), qcmp_str) != NULL;
168 }
169
all_wrap()170 void all_wrap()
171 {
172 GtkTextIter mstart,mend;
173
174 gtk_text_buffer_get_bounds (buffer, &mstart, &mend);
175 gtk_text_buffer_apply_tag_by_name (buffer, "char_wrap", &mstart, &mend);
176 }
177
178
cb_button_parse(GtkButton * button,gpointer user_data)179 static void cb_button_parse(GtkButton *button, gpointer user_data)
180 {
181 int char_count = gtk_text_buffer_get_char_count (buffer);
182
183 int i;
184
185 load_ts_phrase();
186
187 char_count = gtk_text_buffer_get_char_count (buffer);
188
189 all_wrap();
190
191 dbg("parse char_count:%d\n", char_count);
192
193 for(i=0; i < char_count; ) {
194 int len;
195
196 for(len=MAX_PHRASE_LEN; len>=2 ; len--) {
197 u_char txt[MAX_PHRASE_LEN*CH_SZ + 1];
198 int txtN=0, u8chN=0;
199
200 gboolean b_ignore = FALSE;
201 int k;
202 for(k=0; k<len && i+k < char_count; k++) {
203 GtkTextIter start,end;
204 gtk_text_buffer_get_iter_at_offset (buffer, &start, i+k);
205 gtk_text_buffer_get_iter_at_offset (buffer, &end, i+k+1);
206 char *utf8 = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
207
208 if (!(utf8[0] & 128))
209 b_ignore = TRUE;
210
211 int wn = strlen(utf8);
212
213 memcpy(&txt[txtN], utf8, wn);
214
215 txtN+= wn;
216 u8chN++;
217 }
218
219 if (b_ignore || txtN < 2)
220 continue;
221
222 txt[txtN] = 0;
223 // dbg("try len:%d txtN:%d %s\n", len, txtN, txt);
224 if (!pharse_search((char *)txt))
225 continue;
226
227 // dbg("match .... %d %d\n", i, len);
228
229 GtkTextIter mstart,mend;
230
231 gtk_text_buffer_get_iter_at_offset (buffer, &mstart, i);
232 gtk_text_buffer_get_iter_at_offset (buffer, &mend, i+len);
233 gtk_text_buffer_apply_tag_by_name (buffer, "blue_background", &mstart, &mend);
234 #if 1
235 // why do I have to repeat this
236 gtk_text_buffer_get_iter_at_offset (buffer, &mstart, i);
237 gtk_text_buffer_get_iter_at_offset (buffer, &mend, i+len);
238 gtk_text_buffer_apply_tag_by_name (buffer, "blue_background", &mstart, &mend);
239 #endif
240 gdk_flush();
241 }
242
243 i+=len;
244 }
245 }
246
247 #define MAX_SAME_CHAR_PHO (16)
248
249 typedef struct {
250 u_int64_t phokeys[MAX_SAME_CHAR_PHO];
251 int phokeysN;
252 GtkWidget *opt_menu;
253 } char_pho;
254
255
256
257 static char_pho bigpho[MAX_PHRASE_LEN];
258 static int bigphoN;
259
260 static GtkWidget *hbox_pho_sel;
261
destroy_pho_sel_area()262 void destroy_pho_sel_area()
263 {
264 gtk_widget_destroy(hbox_pho_sel);
265 }
266
cb_button_ok(GtkButton * button,gpointer user_data)267 static void cb_button_ok(GtkButton *button, gpointer user_data)
268 {
269 u_int64_t pharr8[MAX_PHRASE_LEN];
270
271 int i;
272 for(i=0; i < bigphoN; i++) {
273 int idx = gtk_combo_box_get_active(GTK_COMBO_BOX(bigpho[i].opt_menu));
274 void *dest = get_ph_key_ptr(pharr8, i);
275
276 cp_ph_key(bigpho[i].phokeys, idx, dest);
277 }
278
279 save_phrase_to_db(&tsin_hand, pharr8, current_str, bigphoN, 0);
280
281 destroy_pho_sel_area();
282
283 GtkTextMark *selebound = gtk_text_buffer_get_selection_bound(buffer);
284 gtk_text_mark_set_visible(selebound, FALSE);
285
286 cb_button_parse(NULL, NULL);
287
288 }
289
cb_button_cancel(GtkButton * button,gpointer user_data)290 static void cb_button_cancel(GtkButton *button, gpointer user_data)
291 {
292 destroy_pho_sel_area();
293 }
294
295 int gtab_key2name(INMD *tinmd, u_int64_t key, char *t, int *rtlen);
create_pho_sel_area()296 GtkWidget *create_pho_sel_area()
297 {
298 hbox_pho_sel = gtk_hbox_new (FALSE, 0);
299
300 int i;
301
302 for(i=0; i < bigphoN; i++) {
303 bigpho[i].opt_menu = gtk_combo_box_new_text ();
304 #if !GTK_CHECK_VERSION(2,4,0)
305 GtkWidget *menu = gtk_menu_new ();
306 #endif
307 gtk_box_pack_start (GTK_BOX (hbox_pho_sel), bigpho[i].opt_menu, FALSE, FALSE, 0);
308
309 int j;
310 for(j=0; j < bigpho[i].phokeysN; j++) {
311 char t[128];
312 char *phostr;
313
314 if (is_gtab) {
315 int tlen;
316 u_int64_t key64;
317 if (tsin_hand.ph_key_sz == 4) {
318 u_int32_t key32;
319 cp_ph_key(bigpho[i].phokeys,j, &key32);
320 key64 = key32;
321 } else
322 cp_ph_key(bigpho[i].phokeys,j, &key64);
323
324 gtab_key2name(pinmd, key64, t, &tlen);
325 // dbg("%d,%d] %s\n", i,j, t);
326 phostr = t;
327 } else {
328 phokey_t k;
329 cp_ph_key(bigpho[i].phokeys, j, &k);
330 phostr = b_pinyin?
331 phokey2pinyin(k):phokey_to_str(k);
332 }
333
334 #if GTK_CHECK_VERSION(2,4,0)
335 gtk_combo_box_append_text (GTK_COMBO_BOX_TEXT (bigpho[i].opt_menu), phostr);
336 #else
337 GtkWidget *item = gtk_menu_item_new_with_label (phostr);
338 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
339 #endif
340 }
341
342 #if GTK_CHECK_VERSION(2,4,0)
343 gtk_combo_box_set_active (GTK_COMBO_BOX(bigpho[i].opt_menu), 0);
344 #else
345 gtk_option_menu_set_menu (GTK_OPTION_MENU (bigpho[i].opt_menu), menu);
346 #endif
347
348 }
349
350
351 GtkWidget *button_ok = gtk_button_new_with_label("OK to add");
352 gtk_box_pack_start (GTK_BOX (hbox_pho_sel), button_ok, FALSE, FALSE, 20);
353 g_signal_connect (G_OBJECT (button_ok), "clicked",
354 G_CALLBACK (cb_button_ok), NULL);
355 #if GTK_CHECK_VERSION(3,10,0)
356 GtkWidget *button_cancel = gtk_button_new_with_label ("取消");
357 #else
358 GtkWidget *button_cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
359 #endif
360 gtk_box_pack_start (GTK_BOX (hbox_pho_sel), button_cancel, FALSE, FALSE, 20);
361 g_signal_connect (G_OBJECT (button_cancel), "clicked",
362 G_CALLBACK (cb_button_cancel), NULL);
363
364
365 return hbox_pho_sel;
366 }
367
368
cb_button_add(GtkButton * button,gpointer user_data)369 static void cb_button_add(GtkButton *button, gpointer user_data)
370 {
371 GtkTextIter start, end;
372
373 if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
374 return;
375
376 char *utf8 = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
377 strcpy(current_str, utf8);
378
379 g_free(utf8);
380
381 bigphoN = 0;
382 char *p = current_str;
383 while (*p) {
384 char_pho *pbigpho = &bigpho[bigphoN++];
385
386 if (tsin_hand.ph_key_sz==2) {
387 pbigpho->phokeysN = utf8_pho_keys(p, (phokey_t*)pbigpho->phokeys);
388 } else {
389 pbigpho->phokeysN = lookup_gtab_key(p, pbigpho->phokeys);
390 }
391
392 p+=utf8_sz(p);
393
394 if (!pbigpho->phokeysN) {
395 dbg(" no mapping to pho\n");
396 return;
397 }
398 }
399
400 GtkWidget *sel = create_pho_sel_area();
401 gtk_box_pack_start (GTK_BOX (hbox_buttons), sel, FALSE, FALSE, 20);
402
403 gtk_widget_show_all(hbox_buttons);
404
405 }
406
407 Display *dpy;
408
do_exit()409 void do_exit()
410 {
411 send_gcin_message(
412 #if UNIX
413 dpy,
414 #endif
415 RELOAD_TSIN_DB);
416
417 exit(0);
418 }
419
420 void load_tsin_db();
421 void set_window_gcin_icon(GtkWidget *window);
422 #if WIN32
423 void init_gcin_program_files();
424 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
425 #endif
426
427 gboolean is_pinyin_kbm();
428
main(int argc,char ** argv)429 int main(int argc, char **argv)
430 {
431 init_TableDir();
432 set_is_chs();
433 gtk_init (&argc, &argv);
434 load_setttings();
435 load_gtab_list(TRUE);
436
437 b_pinyin = is_pinyin_kbm();
438
439
440 #if GCIN_i18n_message
441 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
442 textdomain(GETTEXT_PACKAGE);
443 #endif
444
445 pinmd = &inmd[default_input_method];
446
447 if (pinmd->method_type == method_type_TSIN) {
448 dbg("is tsin\n");
449 pho_load();
450 load_tsin_db();
451 tsin_hand.ph_key_sz = 2;
452 } else
453 if (pinmd->filename) {
454 dbg("gtab filename %s\n", pinmd->filename);
455 init_gtab(default_input_method);
456 is_gtab = TRUE;
457 init_tsin_table_fname(pinmd, gtab_tsin_fname);
458 load_tsin_db0(gtab_tsin_fname, TRUE);
459 } else
460 p_err("Your default input method %s doesn't use phrase database",
461 pinmd->cname);
462
463 dbg("ph_key_sz: %d\n", tsin_hand.ph_key_sz);
464
465 #if UNIX
466 dpy = GDK_DISPLAY();
467 #endif
468
469 mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
470 gtk_window_set_has_resize_grip(GTK_WINDOW(mainwin), FALSE);
471 gtk_window_set_default_size(GTK_WINDOW (mainwin), 640, 520);
472 set_window_gcin_icon(mainwin);
473
474 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
475 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
476 GTK_POLICY_AUTOMATIC,
477 GTK_POLICY_AUTOMATIC);
478
479 GtkWidget *vbox_top = gtk_vbox_new (FALSE, 0);
480 gtk_container_add (GTK_CONTAINER(mainwin), vbox_top);
481
482 GtkWidget *view = gtk_text_view_new ();
483 gtk_widget_set_hexpand (view, TRUE);
484 gtk_widget_set_vexpand (view, TRUE);
485 gtk_container_add (GTK_CONTAINER(sw), view);
486
487 gtk_box_pack_start (GTK_BOX (vbox_top), sw, TRUE, TRUE, 0);
488
489 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
490
491 #if UNIX
492 char *text = _(_L("按滑鼠中鍵, 貼上你要 tslearn 學習的文章。"));
493 #else
494 char *text = _(_L("按 ctrl-V, 貼上你要 tslearn 學習的文章。"));
495 #endif
496
497 gtk_text_buffer_set_text (buffer, text, -1);
498
499 gtk_text_buffer_create_tag (buffer,
500 "blue_background", "background", "blue", "foreground", "white", NULL);
501
502 gtk_text_buffer_create_tag (buffer, "char_wrap",
503 "wrap_mode", GTK_WRAP_CHAR, NULL);
504
505 hbox_buttons = gtk_hbox_new (FALSE, 0);
506 gtk_box_pack_start (GTK_BOX (vbox_top), hbox_buttons, FALSE, FALSE, 0);
507
508 GtkWidget *button_parse = gtk_button_new_with_label(_(_L("標示已知詞")));
509 gtk_box_pack_start (GTK_BOX (hbox_buttons), button_parse, FALSE, FALSE, 0);
510 g_signal_connect (G_OBJECT (button_parse), "clicked",
511 G_CALLBACK (cb_button_parse), NULL);
512
513 GtkWidget *button_add = gtk_button_new_with_label(_(_L("新增詞")));
514 gtk_box_pack_start (GTK_BOX (hbox_buttons), button_add, TRUE, TRUE, 0);
515 g_signal_connect (G_OBJECT (button_add), "clicked",
516 G_CALLBACK (cb_button_add), NULL);
517
518 #if GTK_CHECK_VERSION(3,10,0)
519 GtkWidget *button_quit = gtk_button_new_with_label ("離開");
520 #else
521 GtkWidget *button_quit = gtk_button_new_from_stock (GTK_STOCK_QUIT);
522 #endif
523 gtk_box_pack_start (GTK_BOX (hbox_buttons), button_quit, FALSE, FALSE, 0);
524 g_signal_connect (G_OBJECT (button_quit), "clicked",
525 G_CALLBACK (do_exit), NULL);
526
527
528 g_signal_connect (G_OBJECT (mainwin), "delete_event",
529 G_CALLBACK (do_exit), NULL);
530
531 all_wrap();
532
533 gtk_widget_show_all(mainwin);
534 #if WIN32
535 gtk_window_present(GTK_WINDOW(mainwin));
536 #endif
537
538 gtk_main();
539 return 0;
540 }
541